[SHELL32]
[reactos.git] / dll / win32 / shell32 / shlfolder.cpp
1 /*
2 * Shell Folder stuff
3 *
4 * Copyright 1997 Marcus Meissner
5 * Copyright 1998, 1999, 2002 Juergen Schmied
6 *
7 * IShellFolder2 and related interfaces
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24 #include "precomp.h"
25
26 WINE_DEFAULT_DEBUG_CHANNEL(shell);
27
28 static const WCHAR wszDotShellClassInfo[] = {
29 '.','S','h','e','l','l','C','l','a','s','s','I','n','f','o',0};
30
31 /***************************************************************************
32 * SHELL32_GetCustomFolderAttribute (internal function)
33 *
34 * Gets a value from the folder's desktop.ini file, if one exists.
35 *
36 * PARAMETERS
37 * pidl [I] Folder containing the desktop.ini file.
38 * pwszHeading [I] Heading in .ini file.
39 * pwszAttribute [I] Attribute in .ini file.
40 * pwszValue [O] Buffer to store value into.
41 * cchValue [I] Size in characters including NULL of buffer pointed to
42 * by pwszValue.
43 *
44 * RETURNS
45 * TRUE if returned non-NULL value.
46 * FALSE otherwise.
47 */
48 static BOOL __inline SHELL32_GetCustomFolderAttributeFromPath(
49 LPWSTR pwszFolderPath, LPCWSTR pwszHeading, LPCWSTR pwszAttribute,
50 LPWSTR pwszValue, DWORD cchValue)
51 {
52 static const WCHAR wszDesktopIni[] =
53 {'d','e','s','k','t','o','p','.','i','n','i',0};
54 static const WCHAR wszDefault[] = {0};
55
56 PathAddBackslashW(pwszFolderPath);
57 PathAppendW(pwszFolderPath, wszDesktopIni);
58 return GetPrivateProfileStringW(pwszHeading, pwszAttribute, wszDefault,
59 pwszValue, cchValue, pwszFolderPath);
60 }
61
62 BOOL SHELL32_GetCustomFolderAttribute(
63 LPCITEMIDLIST pidl, LPCWSTR pwszHeading, LPCWSTR pwszAttribute,
64 LPWSTR pwszValue, DWORD cchValue)
65 {
66 DWORD dwAttrib = FILE_ATTRIBUTE_SYSTEM;
67 WCHAR wszFolderPath[MAX_PATH];
68
69 /* Hack around not having system attribute on non-Windows file systems */
70 if (0)
71 dwAttrib = _ILGetFileAttributes(pidl, NULL, 0);
72
73 if (dwAttrib & FILE_ATTRIBUTE_SYSTEM)
74 {
75 if (!SHGetPathFromIDListW(pidl, wszFolderPath))
76 return FALSE;
77
78 return SHELL32_GetCustomFolderAttributeFromPath(wszFolderPath, pwszHeading,
79 pwszAttribute, pwszValue, cchValue);
80 }
81 return FALSE;
82 }
83
84 BOOL SHELL32_GetCustomFolderAttributes(
85 LPCITEMIDLIST pidl, LPCWSTR pwszHeading,
86 LPWSTR pwszValue, DWORD cchValue)
87 {
88 DWORD dwAttrib = FILE_ATTRIBUTE_SYSTEM;
89 WCHAR wszFolderPath[MAX_PATH];
90
91 /* Hack around not having system attribute on non-Windows file systems */
92 if (0)
93 dwAttrib = _ILGetFileAttributes(pidl, NULL, 0);
94
95 if (dwAttrib & FILE_ATTRIBUTE_SYSTEM)
96 {
97 if (!SHGetPathFromIDListW(pidl, wszFolderPath))
98 return FALSE;
99
100 static const WCHAR wszDesktopIni[] =
101 {'d','e','s','k','t','o','p','.','i','n','i',0};
102
103 PathAddBackslashW(wszFolderPath);
104 PathAppendW(wszFolderPath, wszDesktopIni);
105 return GetPrivateProfileSectionW(pwszHeading, pwszValue, cchValue, wszFolderPath);
106 }
107 return FALSE;
108 }
109
110
111 /***************************************************************************
112 * GetNextElement (internal function)
113 *
114 * Gets a part of a string till the first backslash.
115 *
116 * PARAMETERS
117 * pszNext [IN] string to get the element from
118 * pszOut [IN] pointer to buffer which receives string
119 * dwOut [IN] length of pszOut
120 *
121 * RETURNS
122 * LPSTR pointer to first, not yet parsed char
123 */
124
125 LPCWSTR GetNextElementW (LPCWSTR pszNext, LPWSTR pszOut, DWORD dwOut)
126 {
127 LPCWSTR pszTail = pszNext;
128 DWORD dwCopy;
129
130 TRACE ("(%s %p 0x%08x)\n", debugstr_w (pszNext), pszOut, dwOut);
131
132 *pszOut = 0x0000;
133
134 if (!pszNext || !*pszNext)
135 return NULL;
136
137 while (*pszTail && (*pszTail != (WCHAR) '\\'))
138 pszTail++;
139
140 dwCopy = pszTail - pszNext + 1;
141 lstrcpynW (pszOut, pszNext, (dwOut < dwCopy) ? dwOut : dwCopy);
142
143 if (*pszTail)
144 pszTail++;
145 else
146 pszTail = NULL;
147
148 TRACE ("--(%s %s 0x%08x %p)\n", debugstr_w (pszNext), debugstr_w (pszOut), dwOut, pszTail);
149 return pszTail;
150 }
151
152 HRESULT SHELL32_ParseNextElement (IShellFolder2 * psf, HWND hwndOwner, LPBC pbc,
153 LPITEMIDLIST * pidlInOut, LPOLESTR szNext, DWORD * pEaten, DWORD * pdwAttributes)
154 {
155 HRESULT hr = E_INVALIDARG;
156 LPITEMIDLIST pidlIn = pidlInOut ? *pidlInOut : NULL;
157 LPITEMIDLIST pidlOut = NULL;
158 LPITEMIDLIST pidlTemp = NULL;
159 CComPtr<IShellFolder> psfChild;
160
161 TRACE ("(%p, %p, %p, %s)\n", psf, pbc, pidlIn, debugstr_w (szNext));
162
163 /* get the shellfolder for the child pidl and let it analyse further */
164 hr = psf->BindToObject(pidlIn, pbc, IID_PPV_ARG(IShellFolder, &psfChild));
165 if (FAILED(hr))
166 return hr;
167
168 hr = psfChild->ParseDisplayName(hwndOwner, pbc, szNext, pEaten, &pidlOut, pdwAttributes);
169 if (FAILED(hr))
170 return hr;
171
172 pidlTemp = ILCombine (pidlIn, pidlOut);
173 if (!pidlTemp)
174 {
175 hr = E_OUTOFMEMORY;
176 if (pidlOut)
177 ILFree(pidlOut);
178 return hr;
179 }
180
181 if (pidlOut)
182 ILFree (pidlOut);
183
184 if (pidlIn)
185 ILFree (pidlIn);
186
187 *pidlInOut = pidlTemp;
188
189 TRACE ("-- pidl=%p ret=0x%08x\n", pidlInOut ? *pidlInOut : NULL, hr);
190 return S_OK;
191 }
192
193 /***********************************************************************
194 * SHELL32_CoCreateInitSF
195 *
196 * Creates a shell folder and initializes it with a pidl and a root folder
197 * via IPersistFolder3 or IPersistFolder.
198 *
199 * NOTES
200 * pathRoot can be NULL for Folders being a drive.
201 * In this case the absolute path is built from pidlChild (eg. C:)
202 */
203 static HRESULT SHELL32_CoCreateInitSF (LPCITEMIDLIST pidlRoot, LPCWSTR pathRoot,
204 LPCITEMIDLIST pidlChild, REFCLSID clsid, LPVOID * ppvOut)
205 {
206 HRESULT hr;
207 CComPtr<IShellFolder> pShellFolder;
208
209 TRACE ("%p %s %p\n", pidlRoot, debugstr_w(pathRoot), pidlChild);
210
211 hr = SHCoCreateInstance(NULL, &clsid, NULL, IID_PPV_ARG(IShellFolder, &pShellFolder));
212 if (SUCCEEDED (hr))
213 {
214 LPITEMIDLIST pidlAbsolute = ILCombine (pidlRoot, pidlChild);
215 CComPtr<IPersistFolder> ppf;
216 CComPtr<IPersistFolder3> ppf3;
217
218 if (_ILIsFolder(pidlChild) &&
219 SUCCEEDED(pShellFolder->QueryInterface(IID_PPV_ARG(IPersistFolder3, &ppf3))))
220 {
221 PERSIST_FOLDER_TARGET_INFO ppfti;
222
223 ZeroMemory (&ppfti, sizeof (ppfti));
224
225 /* fill the PERSIST_FOLDER_TARGET_INFO */
226 ppfti.dwAttributes = -1;
227 ppfti.csidl = -1;
228
229 /* build path */
230 if (pathRoot)
231 {
232 lstrcpynW (ppfti.szTargetParsingName, pathRoot, MAX_PATH - 1);
233 PathAddBackslashW(ppfti.szTargetParsingName); /* FIXME: why have drives a backslash here ? */
234 }
235
236 if (pidlChild)
237 {
238 int len = wcslen(ppfti.szTargetParsingName);
239
240 if (!_ILSimpleGetTextW(pidlChild, ppfti.szTargetParsingName + len, MAX_PATH - len))
241 hr = E_INVALIDARG;
242 }
243
244 ppf3->InitializeEx(NULL, pidlAbsolute, &ppfti);
245 }
246 else if (SUCCEEDED((hr = pShellFolder->QueryInterface(IID_PPV_ARG(IPersistFolder, &ppf)))))
247 {
248 ppf->Initialize(pidlAbsolute);
249 }
250 ILFree (pidlAbsolute);
251 }
252
253 *ppvOut = pShellFolder.Detach();
254
255 TRACE ("-- (%p) ret=0x%08x\n", *ppvOut, hr);
256
257 return hr;
258 }
259
260 /***********************************************************************
261 * SHELL32_BindToChild [Internal]
262 *
263 * Common code for IShellFolder_BindToObject.
264 *
265 * PARAMS
266 * pidlRoot [I] The parent shell folder's absolute pidl.
267 * pathRoot [I] Absolute dos path of the parent shell folder.
268 * pidlComplete [I] PIDL of the child. Relative to pidlRoot.
269 * riid [I] GUID of the interface, which ppvOut shall be bound to.
270 * ppvOut [O] A reference to the child's interface (riid).
271 *
272 * NOTES
273 * pidlComplete has to contain at least one non empty SHITEMID.
274 * This function makes special assumptions on the shell namespace, which
275 * means you probably can't use it for your IShellFolder implementation.
276 */
277 HRESULT SHELL32_BindToChild (LPCITEMIDLIST pidlRoot,
278 LPCWSTR pathRoot, LPCITEMIDLIST pidlComplete, REFIID riid, LPVOID * ppvOut)
279 {
280 GUID const *clsid;
281 CComPtr<IShellFolder> pSF;
282 HRESULT hr;
283 LPITEMIDLIST pidlChild;
284
285 if (!pidlRoot || !ppvOut || !pidlComplete || !pidlComplete->mkid.cb)
286 return E_INVALIDARG;
287
288 *ppvOut = NULL;
289
290 pidlChild = ILCloneFirst (pidlComplete);
291
292 if ((clsid = _ILGetGUIDPointer (pidlChild))) {
293 /* virtual folder */
294 hr = SHELL32_CoCreateInitSF (pidlRoot, pathRoot, pidlChild, *clsid, (LPVOID *)&pSF);
295 } else {
296 /* file system folder */
297 CLSID clsidFolder = CLSID_ShellFSFolder;
298 static const WCHAR wszCLSID[] = {'C','L','S','I','D',0};
299 WCHAR wszCLSIDValue[CHARS_IN_GUID], wszFolderPath[MAX_PATH], *pwszPathTail = wszFolderPath;
300
301 /* see if folder CLSID should be overridden by desktop.ini file */
302 if (pathRoot) {
303 lstrcpynW(wszFolderPath, pathRoot, MAX_PATH);
304 pwszPathTail = PathAddBackslashW(wszFolderPath);
305 }
306
307 _ILSimpleGetTextW(pidlChild,pwszPathTail,MAX_PATH - (int)(pwszPathTail - wszFolderPath));
308
309 if (SHELL32_GetCustomFolderAttributeFromPath (wszFolderPath,
310 wszDotShellClassInfo, wszCLSID, wszCLSIDValue, CHARS_IN_GUID))
311 CLSIDFromString (wszCLSIDValue, &clsidFolder);
312
313 hr = SHELL32_CoCreateInitSF (pidlRoot, pathRoot, pidlChild,
314 clsidFolder, (LPVOID *)&pSF);
315 }
316 ILFree (pidlChild);
317
318 if (SUCCEEDED (hr)) {
319 if (_ILIsPidlSimple (pidlComplete)) {
320 /* no sub folders */
321 hr = pSF->QueryInterface(riid, ppvOut);
322 } else {
323 /* go deeper */
324 hr = pSF->BindToObject(ILGetNext (pidlComplete), NULL, riid, ppvOut);
325 }
326 }
327
328 TRACE ("-- returning (%p) %08x\n", *ppvOut, hr);
329
330 return hr;
331 }
332
333 /***********************************************************************
334 * SHELL32_GetDisplayNameOfChild
335 *
336 * Retrieves the display name of a child object of a shellfolder.
337 *
338 * For a pidl eg. [subpidl1][subpidl2][subpidl3]:
339 * - it binds to the child shellfolder [subpidl1]
340 * - asks it for the displayname of [subpidl2][subpidl3]
341 *
342 * Is possible the pidl is a simple pidl. In this case it asks the
343 * subfolder for the displayname of an empty pidl. The subfolder
344 * returns the own displayname eg. "::{guid}". This is used for
345 * virtual folders with the registry key WantsFORPARSING set.
346 */
347 HRESULT SHELL32_GetDisplayNameOfChild (IShellFolder2 * psf,
348 LPCITEMIDLIST pidl, DWORD dwFlags, LPWSTR szOut, DWORD dwOutLen)
349 {
350 LPITEMIDLIST pidlFirst;
351 HRESULT hr = E_INVALIDARG;
352
353 TRACE ("(%p)->(pidl=%p 0x%08x %p 0x%08x)\n", psf, pidl, dwFlags, szOut, dwOutLen);
354 pdump (pidl);
355
356 pidlFirst = ILCloneFirst(pidl);
357 if (pidlFirst)
358 {
359 CComPtr<IShellFolder> psfChild;
360
361 hr = psf->BindToObject(pidlFirst, NULL, IID_PPV_ARG(IShellFolder, &psfChild));
362 if (SUCCEEDED (hr))
363 {
364 STRRET strTemp;
365 LPITEMIDLIST pidlNext = ILGetNext (pidl);
366
367 hr = psfChild->GetDisplayNameOf(pidlNext, dwFlags, &strTemp);
368 if (SUCCEEDED (hr))
369 {
370 if(!StrRetToStrNW (szOut, dwOutLen, &strTemp, pidlNext))
371 hr = E_FAIL;
372 }
373 }
374 ILFree (pidlFirst);
375 } else
376 hr = E_OUTOFMEMORY;
377
378 TRACE ("-- ret=0x%08x %s\n", hr, debugstr_w(szOut));
379
380 return hr;
381 }
382
383 /***********************************************************************
384 * SHELL32_GetItemAttributes
385 *
386 * NOTES
387 * Observed values:
388 * folder: 0xE0000177 FILESYSTEM | HASSUBFOLDER | FOLDER
389 * file: 0x40000177 FILESYSTEM
390 * drive: 0xf0000144 FILESYSTEM | HASSUBFOLDER | FOLDER | FILESYSANCESTOR
391 * mycomputer: 0xb0000154 HASSUBFOLDER | FOLDER | FILESYSANCESTOR
392 * (seems to be default for shell extensions if no registry entry exists)
393 *
394 * win2k:
395 * folder: 0xF0400177 FILESYSTEM | HASSUBFOLDER | FOLDER | FILESYSANCESTOR | CANMONIKER
396 * file: 0x40400177 FILESYSTEM | CANMONIKER
397 * drive 0xF0400154 FILESYSTEM | HASSUBFOLDER | FOLDER | FILESYSANCESTOR | CANMONIKER | CANRENAME (LABEL)
398 *
399 * According to the MSDN documentation this function should not set flags. It claims only to reset flags when necessary.
400 * However it turns out the native shell32.dll _sets_ flags in several cases - so do we.
401 */
402 HRESULT SHELL32_GetItemAttributes (IShellFolder * psf, LPCITEMIDLIST pidl, LPDWORD pdwAttributes)
403 {
404 DWORD dwAttributes;
405 BOOL has_guid;
406 static const DWORD dwSupportedAttr=
407 SFGAO_CANCOPY | /*0x00000001 */
408 SFGAO_CANMOVE | /*0x00000002 */
409 SFGAO_CANLINK | /*0x00000004 */
410 SFGAO_CANRENAME | /*0x00000010 */
411 SFGAO_CANDELETE | /*0x00000020 */
412 SFGAO_HASPROPSHEET | /*0x00000040 */
413 SFGAO_DROPTARGET | /*0x00000100 */
414 SFGAO_LINK | /*0x00010000 */
415 SFGAO_READONLY | /*0x00040000 */
416 SFGAO_HIDDEN | /*0x00080000 */
417 SFGAO_FILESYSANCESTOR | /*0x10000000 */
418 SFGAO_FOLDER | /*0x20000000 */
419 SFGAO_FILESYSTEM | /*0x40000000 */
420 SFGAO_HASSUBFOLDER; /*0x80000000 */
421
422 TRACE ("0x%08x\n", *pdwAttributes);
423
424 if (*pdwAttributes & ~dwSupportedAttr)
425 {
426 WARN ("attributes 0x%08x not implemented\n", (*pdwAttributes & ~dwSupportedAttr));
427 *pdwAttributes &= dwSupportedAttr;
428 }
429
430 has_guid = _ILGetGUIDPointer(pidl) != NULL;
431
432 dwAttributes = *pdwAttributes;
433
434 if (has_guid && HCR_GetFolderAttributes(pidl, &dwAttributes))
435 *pdwAttributes = dwAttributes;
436 else if (_ILGetDataPointer(pidl))
437 {
438 dwAttributes = _ILGetFileAttributes(pidl, NULL, 0);
439
440 if (!dwAttributes && has_guid)
441 {
442 WCHAR path[MAX_PATH];
443 STRRET strret;
444
445 /* File attributes are not present in the internal PIDL structure, so get them from the file system. */
446
447 HRESULT hr = psf->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strret);
448
449 if (SUCCEEDED(hr))
450 {
451 hr = StrRetToBufW(&strret, pidl, path, MAX_PATH);
452
453 /* call GetFileAttributes() only for file system paths, not for parsing names like "::{...}" */
454 if (SUCCEEDED(hr) && path[0]!=':')
455 dwAttributes = GetFileAttributesW(path);
456 }
457 }
458
459 /* Set common attributes */
460 *pdwAttributes |= SFGAO_FILESYSTEM | SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_CANDELETE |
461 SFGAO_CANRENAME | SFGAO_CANLINK | SFGAO_CANMOVE | SFGAO_CANCOPY;
462
463 if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY)
464 {
465 *pdwAttributes |= (SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_FILESYSANCESTOR);
466 }
467 else
468 *pdwAttributes &= ~(SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_FILESYSANCESTOR);
469
470 if (dwAttributes & FILE_ATTRIBUTE_HIDDEN)
471 *pdwAttributes |= SFGAO_HIDDEN;
472 else
473 *pdwAttributes &= ~SFGAO_HIDDEN;
474
475 if (dwAttributes & FILE_ATTRIBUTE_READONLY)
476 *pdwAttributes |= SFGAO_READONLY;
477 else
478 *pdwAttributes &= ~SFGAO_READONLY;
479
480 if (SFGAO_LINK & *pdwAttributes)
481 {
482 char ext[MAX_PATH];
483
484 if (!_ILGetExtension(pidl, ext, MAX_PATH) || lstrcmpiA(ext, "lnk"))
485 *pdwAttributes &= ~SFGAO_LINK;
486 }
487
488 if (SFGAO_HASSUBFOLDER & *pdwAttributes)
489 {
490 CComPtr<IShellFolder> psf2;
491 if (SUCCEEDED(psf->BindToObject(pidl, 0, IID_PPV_ARG(IShellFolder, &psf2))))
492 {
493 CComPtr<IEnumIDList> pEnumIL;
494 if (SUCCEEDED(psf2->EnumObjects(0, SHCONTF_FOLDERS, &pEnumIL)))
495 {
496 if (pEnumIL->Skip(1) != S_OK)
497 *pdwAttributes &= ~SFGAO_HASSUBFOLDER;
498 }
499 }
500 }
501 } else
502 *pdwAttributes &= SFGAO_HASSUBFOLDER|SFGAO_FOLDER|SFGAO_FILESYSANCESTOR|SFGAO_DROPTARGET|SFGAO_HASPROPSHEET|SFGAO_CANRENAME|SFGAO_CANLINK;
503
504 TRACE ("-- 0x%08x\n", *pdwAttributes);
505 return S_OK;
506 }
507
508 /***********************************************************************
509 * SHELL32_CompareIDs
510 */
511 HRESULT SHELL32_CompareIDs(IShellFolder * iface, LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
512 {
513 int type1,
514 type2;
515 char szTemp1[MAX_PATH];
516 char szTemp2[MAX_PATH];
517 HRESULT nReturn;
518 LPITEMIDLIST firstpidl;
519 LPITEMIDLIST nextpidl1;
520 LPITEMIDLIST nextpidl2;
521 CComPtr<IShellFolder> psf;
522
523 /* test for empty pidls */
524 BOOL isEmpty1 = _ILIsDesktop(pidl1);
525 BOOL isEmpty2 = _ILIsDesktop(pidl2);
526
527 if (isEmpty1 && isEmpty2)
528 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);
529 if (isEmpty1)
530 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (WORD) -1);
531 if (isEmpty2)
532 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 1);
533
534 /* test for different types. Sort order is the PT_* constant */
535 type1 = _ILGetDataPointer(pidl1)->type;
536 type2 = _ILGetDataPointer(pidl2)->type;
537 if (type1 < type2)
538 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (WORD) -1);
539 else if (type1 > type2)
540 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 1);
541
542 /* test for name of pidl */
543 _ILSimpleGetText(pidl1, szTemp1, MAX_PATH);
544 _ILSimpleGetText(pidl2, szTemp2, MAX_PATH);
545 nReturn = lstrcmpiA(szTemp1, szTemp2);
546 if (nReturn < 0)
547 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (WORD) -1);
548 else if (nReturn > 0)
549 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 1);
550
551 /* test of complex pidls */
552 firstpidl = ILCloneFirst(pidl1);
553 nextpidl1 = ILGetNext(pidl1);
554 nextpidl2 = ILGetNext(pidl2);
555
556 /* optimizing: test special cases and bind not deeper */
557 /* the deeper shellfolder would do the same */
558 isEmpty1 = _ILIsDesktop(nextpidl1);
559 isEmpty2 = _ILIsDesktop(nextpidl2);
560
561 if (isEmpty1 && isEmpty2)
562 {
563 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);
564 }
565 else if (isEmpty1)
566 {
567 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (WORD) -1);
568 }
569 else if (isEmpty2)
570 {
571 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 1);
572 /* optimizing end */
573 }
574 else if (SUCCEEDED(iface->BindToObject(firstpidl, NULL, IID_PPV_ARG(IShellFolder, &psf)))) {
575 nReturn = psf->CompareIDs(lParam, nextpidl1, nextpidl2);
576 }
577 ILFree(firstpidl);
578 return nReturn;
579 }
580
581 /***********************************************************************
582 * SHCreateLinks
583 *
584 * Undocumented.
585 */
586 HRESULT WINAPI SHCreateLinks( HWND hWnd, LPCSTR lpszDir, IDataObject * lpDataObject,
587 UINT uFlags, LPITEMIDLIST *lppidlLinks)
588 {
589 FIXME("%p %s %p %08x %p\n", hWnd, lpszDir, lpDataObject, uFlags, lppidlLinks);
590 return E_NOTIMPL;
591 }
592
593 /***********************************************************************
594 * SHOpenFolderAndSelectItems
595 *
596 * Unimplemented.
597 */
598 EXTERN_C HRESULT
599 WINAPI
600 SHOpenFolderAndSelectItems(LPITEMIDLIST pidlFolder,
601 UINT cidl,
602 PCUITEMID_CHILD_ARRAY apidl,
603 DWORD dwFlags)
604 {
605 FIXME("SHOpenFolderAndSelectItems() stub\n");
606 return E_NOTIMPL;
607 }