xref: /reactos/dll/win32/shell32/wine/pidl.c (revision c2931ef2)
1 /*
2  *    pidl Handling
3  *
4  *    Copyright 1998    Juergen Schmied
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * NOTES
21  *  a pidl == NULL means desktop and is legal
22  *
23  */
24 
25 #include <wine/config.h>
26 
27 #define WIN32_NO_STATUS
28 #define _INC_WINDOWS
29 #define COBJMACROS
30 #define NONAMELESSUNION
31 #define NONAMELESSSTRUCT
32 
33 #include <windef.h>
34 #include <winbase.h>
35 #include <strsafe.h>
36 #include <shlobj.h>
37 #include <undocshell.h>
38 #include <shlwapi.h>
39 #include <shlguid_undoc.h>
40 #include <wine/debug.h>
41 #include <wine/unicode.h>
42 
43 #include "pidl.h"
44 #include "shell32_main.h"
45 #include "shresdef.h"
46 
47 WINE_DEFAULT_DEBUG_CHANNEL(pidl);
48 WINE_DECLARE_DEBUG_CHANNEL(shell);
49 
50 /* from comctl32.dll */
51 extern LPVOID WINAPI Alloc(INT);
52 extern BOOL WINAPI Free(LPVOID);
53 
54 static LPSTR _ILGetSTextPointer(LPCITEMIDLIST pidl);
55 static LPWSTR _ILGetTextPointerW(LPCITEMIDLIST pidl);
56 
57 EXTERN_C HWND BindCtx_GetUIWindow(_In_ IBindCtx *pBindCtx);
58 
59 EXTERN_C HRESULT
60 BindCtx_RegisterObjectParam(
61     _In_ IBindCtx *pBindCtx,
62     _In_ LPOLESTR pszKey,
63     _In_opt_ IUnknown *punk,
64     _Out_ LPBC *ppbc);
65 
66 /*************************************************************************
67  * ILGetDisplayNameExA
68  *
69  * Retrieves the display name of an ItemIDList
70  *
71  * PARAMS
72  *  psf        [I]   Shell Folder to start with, if NULL the desktop is used
73  *  pidl       [I]   ItemIDList relative to the psf to get the display name for
74  *  path       [O]   Filled in with the display name, assumed to be at least MAX_PATH long
75  *  type       [I]   Type of display name to retrieve
76  *                    0 = SHGDN_FORPARSING | SHGDN_FORADDRESSBAR uses always the desktop as root
77  *                    1 = SHGDN_NORMAL relative to the root folder
78  *                    2 = SHGDN_INFOLDER relative to the root folder, only the last name
79  *
80  * RETURNS
81  *  True if the display name could be retrieved successfully, False otherwise
82  */
83 static BOOL ILGetDisplayNameExA(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, LPSTR path, DWORD type)
84 {
85     BOOL ret = FALSE;
86     WCHAR wPath[MAX_PATH];
87 
88     TRACE("%p %p %p %d\n", psf, pidl, path, type);
89 
90     if (!pidl || !path)
91         return FALSE;
92 
93     ret = ILGetDisplayNameExW(psf, pidl, wPath, type);
94     WideCharToMultiByte(CP_ACP, 0, wPath, -1, path, MAX_PATH, NULL, NULL);
95     TRACE("%p %p %s\n", psf, pidl, debugstr_a(path));
96 
97     return ret;
98 }
99 
100 BOOL ILGetDisplayNameExW(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, LPWSTR path, DWORD type)
101 {
102     LPSHELLFOLDER psfParent, lsf = psf;
103     HRESULT ret = NO_ERROR;
104     LPCITEMIDLIST pidllast;
105     STRRET strret;
106     DWORD flag;
107 
108     TRACE("%p %p %p %x\n", psf, pidl, path, type);
109 
110     if (!pidl || !path)
111         return FALSE;
112 
113     if (!lsf)
114     {
115         ret = SHGetDesktopFolder(&lsf);
116         if (FAILED(ret))
117             return FALSE;
118     }
119 
120     switch (type)
121     {
122     case ILGDN_FORPARSING:
123         flag = SHGDN_FORPARSING | SHGDN_FORADDRESSBAR;
124         break;
125     case ILGDN_NORMAL:
126         flag = SHGDN_NORMAL;
127         break;
128     case ILGDN_INFOLDER:
129         flag = SHGDN_INFOLDER;
130         break;
131     default:
132         FIXME("Unknown type parameter = %x\n", type);
133         flag = SHGDN_FORPARSING | SHGDN_FORADDRESSBAR;
134         break;
135     }
136 
137     if (!*(const WORD*)pidl || type == ILGDN_FORPARSING)
138     {
139         ret = IShellFolder_GetDisplayNameOf(lsf, pidl, flag, &strret);
140         if (SUCCEEDED(ret))
141         {
142             if(!StrRetToStrNW(path, MAX_PATH, &strret, pidl))
143                 ret = E_FAIL;
144         }
145     }
146     else
147     {
148         ret = SHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&psfParent, &pidllast);
149         if (SUCCEEDED(ret))
150         {
151             ret = IShellFolder_GetDisplayNameOf(psfParent, pidllast, flag, &strret);
152             if (SUCCEEDED(ret))
153             {
154                 if(!StrRetToStrNW(path, MAX_PATH, &strret, pidllast))
155                     ret = E_FAIL;
156             }
157             IShellFolder_Release(psfParent);
158         }
159     }
160 
161     TRACE("%p %p %s\n", psf, pidl, debugstr_w(path));
162 
163     if (!psf)
164         IShellFolder_Release(lsf);
165     return SUCCEEDED(ret);
166 }
167 
168 /*************************************************************************
169  * ILGetDisplayNameEx        [SHELL32.186]
170  */
171 BOOL WINAPI ILGetDisplayNameEx(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, LPVOID path, DWORD type)
172 {
173     TRACE_(shell)("%p %p %p %d\n", psf, pidl, path, type);
174 
175     if (SHELL_OsIsUnicode())
176         return ILGetDisplayNameExW(psf, pidl, path, type);
177     return ILGetDisplayNameExA(psf, pidl, path, type);
178 }
179 
180 /*************************************************************************
181  * ILGetDisplayName            [SHELL32.15]
182  */
183 BOOL WINAPI ILGetDisplayName(LPCITEMIDLIST pidl, LPVOID path)
184 {
185     TRACE_(shell)("%p %p\n", pidl, path);
186 
187     if (SHELL_OsIsUnicode())
188         return ILGetDisplayNameExW(NULL, pidl, path, ILGDN_FORPARSING);
189     return ILGetDisplayNameExA(NULL, pidl, path, ILGDN_FORPARSING);
190 }
191 
192 /*************************************************************************
193  * ILFindLastID [SHELL32.16]
194  *
195  * NOTES
196  *   observed: pidl=Desktop return=pidl
197  */
198 LPITEMIDLIST WINAPI ILFindLastID(LPCITEMIDLIST pidl)
199 {
200     LPCITEMIDLIST   pidlLast = pidl;
201 
202     TRACE("(pidl=%p)\n",pidl);
203 
204     if (!pidl)
205         return NULL;
206 
207     while (pidl->mkid.cb)
208     {
209         pidlLast = pidl;
210         pidl = ILGetNext(pidl);
211     }
212     return (LPITEMIDLIST)pidlLast;
213 }
214 
215 /*************************************************************************
216  * ILRemoveLastID [SHELL32.17]
217  *
218  * NOTES
219  *   when pidl=Desktop return=FALSE
220  */
221 BOOL WINAPI ILRemoveLastID(LPITEMIDLIST pidl)
222 {
223     TRACE_(shell)("pidl=%p\n",pidl);
224 
225     if (_ILIsEmpty(pidl))
226         return FALSE;
227     ILFindLastID(pidl)->mkid.cb = 0;
228     return TRUE;
229 }
230 
231 /*************************************************************************
232  * ILClone [SHELL32.18]
233  *
234  * NOTES
235  *    duplicate an idlist
236  */
237 LPITEMIDLIST WINAPI ILClone (LPCITEMIDLIST pidl)
238 {
239     DWORD    len;
240     LPITEMIDLIST  newpidl;
241 
242     if (!pidl)
243         return NULL;
244 
245     len = ILGetSize(pidl);
246     newpidl = SHAlloc(len);
247     if (newpidl)
248         memcpy(newpidl,pidl,len);
249 
250     TRACE("pidl=%p newpidl=%p\n",pidl, newpidl);
251     pdump(pidl);
252 
253     return newpidl;
254 }
255 
256 /*************************************************************************
257  * ILCloneFirst [SHELL32.19]
258  *
259  * NOTES
260  *  duplicates the first idlist of a complex pidl
261  */
262 LPITEMIDLIST WINAPI ILCloneFirst(LPCITEMIDLIST pidl)
263 {
264     DWORD len;
265     LPITEMIDLIST pidlNew = NULL;
266 
267     TRACE("pidl=%p\n", pidl);
268     pdump(pidl);
269 
270     if (pidl)
271     {
272         len = pidl->mkid.cb;
273         pidlNew = SHAlloc(len+2);
274         if (pidlNew)
275         {
276             memcpy(pidlNew,pidl,len+2);        /* 2 -> mind a desktop pidl */
277 
278             if (len)
279                 ILGetNext(pidlNew)->mkid.cb = 0x00;
280         }
281     }
282     TRACE("-- newpidl=%p\n",pidlNew);
283 
284     return pidlNew;
285 }
286 
287 /*************************************************************************
288  * ILLoadFromStream (SHELL32.26)
289  *
290  * NOTES
291  *   the first two bytes are the len, the pidl is following then
292  */
293 HRESULT WINAPI ILLoadFromStream (IStream * pStream, LPITEMIDLIST * ppPidl)
294 {
295     WORD        wLen = 0;
296     DWORD       dwBytesRead;
297     HRESULT     ret = E_FAIL;
298 
299 
300     TRACE_(shell)("%p %p\n", pStream ,  ppPidl);
301 
302     SHFree(*ppPidl);
303     *ppPidl = NULL;
304 
305     IStream_AddRef (pStream);
306 
307     if (SUCCEEDED(IStream_Read(pStream, &wLen, 2, &dwBytesRead)))
308     {
309         TRACE("PIDL length is %d\n", wLen);
310         if (wLen != 0)
311         {
312             *ppPidl = SHAlloc (wLen);
313             if (SUCCEEDED(IStream_Read(pStream, *ppPidl , wLen, &dwBytesRead)))
314             {
315                 TRACE("Stream read OK\n");
316                 ret = S_OK;
317             }
318             else
319             {
320                 WARN("reading pidl failed\n");
321                 SHFree(*ppPidl);
322                 *ppPidl = NULL;
323             }
324         }
325         else
326         {
327             *ppPidl = NULL;
328             ret = S_OK;
329         }
330     }
331 
332     /* we are not yet fully compatible */
333     if (*ppPidl && !pcheck(*ppPidl))
334     {
335         WARN("Check failed\n");
336         SHFree(*ppPidl);
337         *ppPidl = NULL;
338     }
339 
340     IStream_Release (pStream);
341     TRACE("done\n");
342     return ret;
343 }
344 
345 /*************************************************************************
346  * ILSaveToStream (SHELL32.27)
347  *
348  * NOTES
349  *   the first two bytes are the len, the pidl is following then
350  */
351 HRESULT WINAPI ILSaveToStream (IStream * pStream, LPCITEMIDLIST pPidl)
352 {
353     WORD        wLen = 0;
354     HRESULT        ret = E_FAIL;
355 
356     TRACE_(shell)("%p %p\n", pStream, pPidl);
357 
358     IStream_AddRef (pStream);
359 
360     wLen = ILGetSize(pPidl);
361 
362     if (SUCCEEDED(IStream_Write(pStream, &wLen, 2, NULL)))
363     {
364         if (SUCCEEDED(IStream_Write(pStream, pPidl, wLen, NULL)))
365             ret = S_OK;
366     }
367     IStream_Release (pStream);
368 
369     return ret;
370 }
371 
372 /*************************************************************************
373  * SHILCreateFromPath        [SHELL32.28]
374  *
375  * Create an ItemIDList from a path
376  *
377  * PARAMS
378  *  path       [I]
379  *  ppidl      [O]
380  *  attributes [I/O] requested attributes on call and actual attributes when
381  *                   the function returns
382  *
383  * RETURNS
384  *  NO_ERROR if successful, or an OLE errer code otherwise
385  *
386  * NOTES
387  *  Wrapper for IShellFolder_ParseDisplayName().
388  */
389 HRESULT WINAPI SHILCreateFromPathA(LPCSTR path, LPITEMIDLIST * ppidl, DWORD * attributes)
390 {
391     WCHAR lpszDisplayName[MAX_PATH];
392 
393     TRACE_(shell)("%s %p 0x%08x\n", path, ppidl, attributes ? *attributes : 0);
394 
395     if (!MultiByteToWideChar(CP_ACP, 0, path, -1, lpszDisplayName, MAX_PATH))
396         lpszDisplayName[MAX_PATH-1] = 0;
397 
398     return SHILCreateFromPathW(lpszDisplayName, ppidl, attributes);
399 }
400 
401 HRESULT WINAPI SHILCreateFromPathW(LPCWSTR path, LPITEMIDLIST * ppidl, DWORD * attributes)
402 {
403     LPSHELLFOLDER sf;
404     DWORD pchEaten;
405     HRESULT ret = E_FAIL;
406 
407     TRACE_(shell)("%s %p 0x%08x\n", debugstr_w(path), ppidl, attributes ? *attributes : 0);
408 
409     if (SUCCEEDED (SHGetDesktopFolder(&sf)))
410     {
411         ret = IShellFolder_ParseDisplayName(sf, 0, NULL, (LPWSTR)path, &pchEaten, ppidl, attributes);
412         IShellFolder_Release(sf);
413     }
414     return ret;
415 }
416 
417 HRESULT WINAPI SHILCreateFromPathAW (LPCVOID path, LPITEMIDLIST * ppidl, DWORD * attributes)
418 {
419     if ( SHELL_OsIsUnicode())
420         return SHILCreateFromPathW (path, ppidl, attributes);
421     return SHILCreateFromPathA (path, ppidl, attributes);
422 }
423 
424 /*************************************************************************
425  * SHCloneSpecialIDList      [SHELL32.89]
426  *
427  * Create an ItemIDList to one of the special folders.
428 
429  * PARAMS
430  *  hwndOwner    [in]
431  *  nFolder      [in]    CSIDL_xxxxx
432  *  fCreate      [in]    Create folder if it does not exist
433  *
434  * RETURNS
435  *  Success: The newly created pidl
436  *  Failure: NULL, if inputs are invalid.
437  *
438  * NOTES
439  *  exported by ordinal.
440  *  Caller is responsible for deallocating the returned ItemIDList with the
441  *  shells IMalloc interface, aka ILFree.
442  */
443 LPITEMIDLIST WINAPI SHCloneSpecialIDList(HWND hwndOwner, int nFolder, BOOL fCreate)
444 {
445     LPITEMIDLIST ppidl;
446     TRACE_(shell)("(hwnd=%p,csidl=0x%x,%s).\n", hwndOwner, nFolder, fCreate ? "T" : "F");
447 
448     if (fCreate)
449         nFolder |= CSIDL_FLAG_CREATE;
450 
451     SHGetSpecialFolderLocation(hwndOwner, nFolder, &ppidl);
452     return ppidl;
453 }
454 
455 /*************************************************************************
456  * ILGlobalClone             [SHELL32.20]
457  *
458  * Clones an ItemIDList using Alloc.
459  *
460  * PARAMS
461  *  pidl       [I]   ItemIDList to clone
462  *
463  * RETURNS
464  *  Newly allocated ItemIDList.
465  *
466  * NOTES
467  *  exported by ordinal.
468  */
469 LPITEMIDLIST WINAPI ILGlobalClone(LPCITEMIDLIST pidl)
470 {
471     DWORD    len;
472     LPITEMIDLIST  newpidl;
473 
474     if (!pidl)
475         return NULL;
476 
477     len = ILGetSize(pidl);
478     newpidl = Alloc(len);
479     if (newpidl)
480         memcpy(newpidl,pidl,len);
481 
482     TRACE("pidl=%p newpidl=%p\n",pidl, newpidl);
483     pdump(pidl);
484 
485     return newpidl;
486 }
487 
488 BOOL _ILHACKCompareSimpleIds(LPCITEMIDLIST pidltemp1, LPCITEMIDLIST pidltemp2)
489 {
490     LPPIDLDATA pdata1 = _ILGetDataPointer(pidltemp1);
491     LPPIDLDATA pdata2 = _ILGetDataPointer(pidltemp2);
492 
493     IID *iid1 = _ILGetGUIDPointer(pidltemp1);
494     IID *iid2 = _ILGetGUIDPointer(pidltemp2);
495 
496     FileStructW* pDataW1 = _ILGetFileStructW(pidltemp1);
497     FileStructW* pDataW2 = _ILGetFileStructW(pidltemp2);
498 
499     if (_ILIsDesktop(pidltemp1) && _ILIsDesktop(pidltemp2))
500     {
501         return TRUE;
502     }
503     else if (_ILIsDesktop(pidltemp1) || _ILIsDesktop(pidltemp2))
504     {
505         return FALSE;
506     }
507     else if (iid1 || iid2)
508     {
509         if (!iid1 || !iid2 || memcmp(iid1, iid2, sizeof(GUID)))
510             return FALSE;
511     }
512     else if (pDataW1 || pDataW2)
513     {
514         if (!pDataW1 || !pDataW2 || wcsicmp(pDataW1->wszName, pDataW2->wszName))
515             return FALSE;
516     }
517     else if (_ILIsFolder(pidltemp1) || _ILIsFolder(pidltemp2))
518     {
519         if (!_ILIsFolder(pidltemp1) || !_ILIsFolder(pidltemp2) || strcmp(pdata1->u.file.szNames, pdata2->u.file.szNames))
520             return FALSE;
521     }
522     else if (_ILIsValue(pidltemp1) || _ILIsValue(pidltemp2))
523     {
524         if (!_ILIsValue(pidltemp1) || !_ILIsValue(pidltemp2) || strcmp(pdata1->u.file.szNames, pdata2->u.file.szNames))
525             return FALSE;
526     }
527     else if (_ILIsDrive(pidltemp1) || _ILIsDrive(pidltemp2))
528     {
529         if (!_ILIsDrive(pidltemp1) || !_ILIsDrive(pidltemp2) || pdata1->u.drive.szDriveName[0] != pdata2->u.drive.szDriveName[0])
530             return FALSE;
531     }
532     else
533     {
534         if ((pidltemp1->mkid.cb != pidltemp2->mkid.cb) ||
535             !RtlEqualMemory((BYTE*)&pidltemp1->mkid, (BYTE*)&pidltemp2->mkid, pidltemp1->mkid.cb))
536         {
537             return FALSE;
538         }
539     }
540 
541     return TRUE;
542 }
543 
544 /*************************************************************************
545  * ILIsEqual [SHELL32.21]
546  *
547  */
548 BOOL WINAPI ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
549 {
550     LPCITEMIDLIST pidltemp1 = pidl1;
551     LPCITEMIDLIST pidltemp2 = pidl2;
552 
553     TRACE("pidl1=%p pidl2=%p\n",pidl1, pidl2);
554 
555     /*
556      * Explorer reads from registry directly (StreamMRU),
557      * so we can only check here
558      */
559     if (!pcheck(pidl1) || !pcheck (pidl2))
560         return FALSE;
561 
562     pdump (pidl1);
563     pdump (pidl2);
564 
565     if (!pidl1 || !pidl2)
566         return FALSE;
567 
568     while (pidltemp1->mkid.cb && pidltemp2->mkid.cb)
569     {
570         if (!_ILHACKCompareSimpleIds(pidltemp1, pidltemp2))
571             return FALSE;
572 
573         pidltemp1 = ILGetNext(pidltemp1);
574         pidltemp2 = ILGetNext(pidltemp2);
575     }
576 
577     if (!pidltemp1->mkid.cb && !pidltemp2->mkid.cb)
578         return TRUE;
579 
580     return FALSE;
581 }
582 
583 /*************************************************************************
584  * ILIsParent                [SHELL32.23]
585  *
586  * Verifies that pidlParent is indeed the (immediate) parent of pidlChild.
587  *
588  * PARAMS
589  *  pidlParent [I]
590  *  pidlChild  [I]
591  *  bImmediate [I]   only return true if the parent is the direct parent
592  *                   of the child
593  *
594  * RETURNS
595  *  True if the parent ItemIDlist is a complete part of the child ItemIdList,
596  *  False otherwise.
597  *
598  * NOTES
599  *  parent = a/b, child = a/b/c -> true, c is in folder a/b
600  *  child = a/b/c/d -> false if bImmediate is true, d is not in folder a/b
601  *  child = a/b/c/d -> true if bImmediate is false, d is in a subfolder of a/b
602  *  child = a/b -> false if bImmediate is true
603  *  child = a/b -> true if bImmediate is false
604  */
605 BOOL WINAPI ILIsParent(LPCITEMIDLIST pidlParent, LPCITEMIDLIST pidlChild, BOOL bImmediate)
606 {
607     LPCITEMIDLIST pParent = pidlParent;
608     LPCITEMIDLIST pChild = pidlChild;
609 
610     TRACE("%p %p %x\n", pidlParent, pidlChild, bImmediate);
611 
612     if (!pParent || !pChild)
613         return FALSE;
614 
615     while (pParent->mkid.cb && pChild->mkid.cb)
616     {
617         if (!_ILHACKCompareSimpleIds(pParent, pChild))
618             return FALSE;
619 
620         pParent = ILGetNext(pParent);
621         pChild = ILGetNext(pChild);
622     }
623 
624     /* child has shorter name than parent */
625     if (pParent->mkid.cb)
626         return FALSE;
627 
628     /* not immediate descent */
629     if ((!pChild->mkid.cb || ILGetNext(pChild)->mkid.cb) && bImmediate)
630         return FALSE;
631 
632     return TRUE;
633 }
634 
635 /*************************************************************************
636  * ILFindChild               [SHELL32.24]
637  *
638  *  Compares elements from pidl1 and pidl2.
639  *
640  * PARAMS
641  *  pidl1      [I]
642  *  pidl2      [I]
643  *
644  * RETURNS
645  *  pidl1 is desktop      pidl2
646  *  pidl1 shorter pidl2   pointer to first different element of pidl2
647  *                        if there was at least one equal element
648  *  pidl2 shorter pidl1   0
649  *  pidl2 equal pidl1     pointer to last 0x00-element of pidl2
650  *
651  * NOTES
652  *  exported by ordinal.
653  */
654 PUIDLIST_RELATIVE WINAPI ILFindChild(PIDLIST_ABSOLUTE pidl1, PCIDLIST_ABSOLUTE pidl2)
655 {
656     LPCITEMIDLIST pidltemp1 = pidl1;
657     LPCITEMIDLIST pidltemp2 = pidl2;
658     LPCITEMIDLIST ret=NULL;
659 
660     TRACE("pidl1=%p pidl2=%p\n",pidl1, pidl2);
661 
662     /* explorer reads from registry directly (StreamMRU),
663        so we can only check here */
664     if ((!pcheck (pidl1)) || (!pcheck (pidl2)))
665         return FALSE;
666 
667     pdump (pidl1);
668     pdump (pidl2);
669 
670     if (_ILIsDesktop(pidl1))
671     {
672         ret = pidl2;
673     }
674     else
675     {
676         while (pidltemp1->mkid.cb && pidltemp2->mkid.cb)
677         {
678             if (!_ILHACKCompareSimpleIds(pidltemp1, pidltemp2))
679                 return FALSE;
680 
681             pidltemp1 = ILGetNext(pidltemp1);
682             pidltemp2 = ILGetNext(pidltemp2);
683             ret = pidltemp2;
684         }
685 
686         if (pidltemp1->mkid.cb)
687             ret = NULL; /* elements of pidl1 left*/
688     }
689     TRACE_(shell)("--- %p\n", ret);
690     return (PUIDLIST_RELATIVE)ret; /* pidl 1 is shorter */
691 }
692 
693 /*************************************************************************
694  * ILCombine                 [SHELL32.25]
695  *
696  * Concatenates two complex ItemIDLists.
697  *
698  * PARAMS
699  *  pidl1      [I]   first complex ItemIDLists
700  *  pidl2      [I]   complex ItemIDLists to append
701  *
702  * RETURNS
703  *  if both pidl's == NULL      NULL
704  *  if pidl1 == NULL            cloned pidl2
705  *  if pidl2 == NULL            cloned pidl1
706  *  otherwise new pidl with pidl2 appended to pidl1
707  *
708  * NOTES
709  *  exported by ordinal.
710  *  Does not destroy the passed in ItemIDLists!
711  */
712 LPITEMIDLIST WINAPI ILCombine(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
713 {
714     DWORD    len1,len2;
715     LPITEMIDLIST  pidlNew;
716 
717     TRACE("pidl=%p pidl=%p\n",pidl1,pidl2);
718 
719     if (!pidl1 && !pidl2) return NULL;
720 
721     pdump (pidl1);
722     pdump (pidl2);
723 
724     if (!pidl1)
725     {
726         pidlNew = ILClone(pidl2);
727         return pidlNew;
728     }
729 
730     if (!pidl2)
731     {
732         pidlNew = ILClone(pidl1);
733         return pidlNew;
734     }
735 
736     len1  = ILGetSize(pidl1)-2;
737     len2  = ILGetSize(pidl2);
738     pidlNew  = SHAlloc(len1+len2);
739 
740     if (pidlNew)
741     {
742         memcpy(pidlNew,pidl1,len1);
743         memcpy(((BYTE *)pidlNew)+len1,pidl2,len2);
744     }
745 
746     /*  TRACE(pidl,"--new pidl=%p\n",pidlNew);*/
747     return pidlNew;
748 }
749 
750 /*************************************************************************
751  *  SHGetRealIDL [SHELL32.98]
752  *
753  * NOTES
754  */
755 HRESULT WINAPI SHGetRealIDL(LPSHELLFOLDER lpsf, LPCITEMIDLIST pidlSimple, LPITEMIDLIST *pidlReal)
756 {
757     IDataObject* pDataObj;
758     HRESULT hr;
759 
760     hr = IShellFolder_GetUIObjectOf(lpsf, 0, 1, &pidlSimple,
761                              &IID_IDataObject, 0, (LPVOID*)&pDataObj);
762     if (SUCCEEDED(hr))
763     {
764         STGMEDIUM medium;
765         FORMATETC fmt;
766 
767         fmt.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
768         fmt.ptd = NULL;
769         fmt.dwAspect = DVASPECT_CONTENT;
770         fmt.lindex = -1;
771         fmt.tymed = TYMED_HGLOBAL;
772 
773         hr = IDataObject_GetData(pDataObj, &fmt, &medium);
774 
775         IDataObject_Release(pDataObj);
776 
777         if (SUCCEEDED(hr))
778         {
779             /*assert(pida->cidl==1);*/
780             LPIDA pida = GlobalLock(medium.u.hGlobal);
781 
782             LPCITEMIDLIST pidl_folder = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[0]);
783             LPCITEMIDLIST pidl_child = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[1]);
784 
785             *pidlReal = ILCombine(pidl_folder, pidl_child);
786 
787             if (!*pidlReal)
788                 hr = E_OUTOFMEMORY;
789 
790             GlobalUnlock(medium.u.hGlobal);
791             GlobalFree(medium.u.hGlobal);
792         }
793     }
794 
795     return hr;
796 }
797 
798 /*************************************************************************
799  *  SHLogILFromFSIL [SHELL32.95]
800  *
801  * NOTES
802  *  pild = CSIDL_DESKTOP    ret = 0
803  *  pild = CSIDL_DRIVES     ret = 0
804  */
805 LPITEMIDLIST WINAPI SHLogILFromFSIL(LPITEMIDLIST pidl)
806 {
807     FIXME("(pidl=%p)\n",pidl);
808 
809     pdump(pidl);
810 
811     return 0;
812 }
813 
814 /*************************************************************************
815  * ILGetSize                 [SHELL32.152]
816  *
817  * Gets the byte size of an ItemIDList including zero terminator
818  *
819  * PARAMS
820  *  pidl       [I]   ItemIDList
821  *
822  * RETURNS
823  *  size of pidl in bytes
824  *
825  * NOTES
826  *  exported by ordinal
827  */
828 UINT WINAPI ILGetSize(LPCITEMIDLIST pidl)
829 {
830     LPCSHITEMID si;
831     UINT len=0;
832 
833     if (pidl)
834     {
835         si = &(pidl->mkid);
836 
837         while (si->cb)
838         {
839             len += si->cb;
840             si  = (LPCSHITEMID)(((const BYTE*)si)+si->cb);
841         }
842         len += 2;
843     }
844     TRACE("pidl=%p size=%u\n",pidl, len);
845     return len;
846 }
847 
848 /*************************************************************************
849  * ILGetNext                 [SHELL32.153]
850  *
851  * Gets the next ItemID of an ItemIDList
852  *
853  * PARAMS
854  *  pidl       [I]   ItemIDList
855  *
856  * RETURNS
857  *  null -> null
858  *  desktop -> null
859  *  simple pidl -> pointer to 0x0000 element
860  *
861  * NOTES
862  *  exported by ordinal.
863  */
864 LPITEMIDLIST WINAPI ILGetNext(LPCITEMIDLIST pidl)
865 {
866     WORD len;
867 
868     TRACE("%p\n", pidl);
869 
870     if (pidl)
871     {
872         len =  pidl->mkid.cb;
873         if (len)
874         {
875             pidl = (LPCITEMIDLIST) (((const BYTE*)pidl)+len);
876             TRACE("-- %p\n", pidl);
877             return (LPITEMIDLIST)pidl;
878         }
879     }
880     return NULL;
881 }
882 
883 /*************************************************************************
884  * ILAppendID                [SHELL32.154]
885  *
886  * Adds the single ItemID item to the ItemIDList indicated by pidl.
887  * If bEnd is FALSE, inserts the item in the front of the list,
888  * otherwise it adds the item to the end. (???)
889  *
890  * PARAMS
891  *  pidl       [I]   ItemIDList to extend
892  *  item       [I]   ItemID to prepend/append
893  *  bEnd       [I]   Indicates if the item should be appended
894  *
895  * NOTES
896  *  Destroys the passed in idlist! (???)
897  */
898 LPITEMIDLIST WINAPI ILAppendID(LPITEMIDLIST pidl, LPCSHITEMID item, BOOL bEnd)
899 {
900     LPITEMIDLIST idlRet;
901     LPCITEMIDLIST itemid = (LPCITEMIDLIST)item;
902 
903     WARN("(pidl=%p,pidl=%p,%08u)semi-stub\n",pidl,item,bEnd);
904 
905     pdump (pidl);
906     pdump (itemid);
907 
908     if (_ILIsDesktop(pidl))
909     {
910         idlRet = ILClone(itemid);
911         SHFree (pidl);
912         return idlRet;
913     }
914 
915     if (bEnd)
916         idlRet = ILCombine(pidl, itemid);
917     else
918         idlRet = ILCombine(itemid, pidl);
919 
920     SHFree(pidl);
921     return idlRet;
922 }
923 
924 /*************************************************************************
925  * ILFree                    [SHELL32.155]
926  *
927  * Frees memory (if not NULL) allocated by SHMalloc allocator
928  *
929  * PARAMS
930  *  pidl         [I]
931  *
932  * RETURNS
933  *  Nothing
934  *
935  * NOTES
936  *  exported by ordinal
937  */
938 void WINAPI ILFree(LPITEMIDLIST pidl)
939 {
940     TRACE("(pidl=%p)\n",pidl);
941     SHFree(pidl);
942 }
943 
944 /*************************************************************************
945  * ILGlobalFree              [SHELL32.156]
946  *
947  * Frees memory (if not NULL) allocated by Alloc allocator
948  *
949  * PARAMS
950  *  pidl         [I]
951  *
952  * RETURNS
953  *  Nothing
954  *
955  * NOTES
956  *  exported by ordinal.
957  */
958 void WINAPI ILGlobalFree( LPITEMIDLIST pidl)
959 {
960     TRACE("%p\n", pidl);
961 
962     Free(pidl);
963 }
964 
965 /*************************************************************************
966  * ILCreateFromPathA         [SHELL32.189]
967  *
968  * Creates a complex ItemIDList from a path and returns it.
969  *
970  * PARAMS
971  *  path         [I]
972  *
973  * RETURNS
974  *  the newly created complex ItemIDList or NULL if failed
975  *
976  * NOTES
977  *  exported by ordinal.
978  */
979 LPITEMIDLIST WINAPI ILCreateFromPathA (LPCSTR path)
980 {
981     LPITEMIDLIST pidlnew = NULL;
982 
983     TRACE_(shell)("%s\n", debugstr_a(path));
984 
985     if (SUCCEEDED(SHILCreateFromPathA(path, &pidlnew, NULL)))
986         return pidlnew;
987     return NULL;
988 }
989 
990 /*************************************************************************
991  * ILCreateFromPathW         [SHELL32.190]
992  *
993  * See ILCreateFromPathA.
994  */
995 LPITEMIDLIST WINAPI ILCreateFromPathW (LPCWSTR path)
996 {
997     LPITEMIDLIST pidlnew = NULL;
998 
999     TRACE_(shell)("%s\n", debugstr_w(path));
1000 
1001     if (SUCCEEDED(SHILCreateFromPathW(path, &pidlnew, NULL)))
1002         return pidlnew;
1003     return NULL;
1004 }
1005 
1006 /*************************************************************************
1007  * ILCreateFromPath          [SHELL32.157]
1008  */
1009 LPITEMIDLIST WINAPI ILCreateFromPathAW (LPCVOID path)
1010 {
1011     if ( SHELL_OsIsUnicode())
1012         return ILCreateFromPathW (path);
1013     return ILCreateFromPathA (path);
1014 }
1015 
1016 /*************************************************************************
1017  * _ILParsePathW             [internal]
1018  *
1019  * Creates an ItemIDList from a path and returns it.
1020  *
1021  * PARAMS
1022  *  path         [I]   path to parse and convert into an ItemIDList
1023  *  lpFindFile   [I]   pointer to buffer to initialize the FileSystem
1024  *                     Bind Data object with
1025  *  bBindCtx     [I]   indicates to create a BindContext and assign a
1026  *                     FileSystem Bind Data object
1027  *  ppidl        [O]   the newly create ItemIDList
1028  *  prgfInOut    [I/O] requested attributes on input and actual
1029  *                     attributes on return
1030  *
1031  * RETURNS
1032  *  NO_ERROR on success or an OLE error code
1033  *
1034  * NOTES
1035  *  If either lpFindFile is non-NULL or bBindCtx is TRUE, this function
1036  *  creates a BindContext object and assigns a FileSystem Bind Data object
1037  *  to it, passing the BindContext to IShellFolder_ParseDisplayName. Each
1038  *  IShellFolder uses that FileSystem Bind Data object of the BindContext
1039  *  to pass data about the current path element to the next object. This
1040  *  is used to avoid having to verify the current path element on disk, so
1041  *  that creating an ItemIDList from a nonexistent path still can work.
1042  */
1043 static HRESULT _ILParsePathW(LPCWSTR path, LPWIN32_FIND_DATAW lpFindFile,
1044                              BOOL bBindCtx, LPITEMIDLIST *ppidl, LPDWORD prgfInOut)
1045 {
1046     LPSHELLFOLDER pSF = NULL;
1047     LPBC pBC = NULL;
1048     HRESULT ret;
1049 
1050     TRACE("%s %p %d (%p)->%p (%p)->0x%x\n", debugstr_w(path), lpFindFile, bBindCtx,
1051                                              ppidl, ppidl ? *ppidl : NULL,
1052                                              prgfInOut, prgfInOut ? *prgfInOut : 0);
1053 
1054     ret = SHGetDesktopFolder(&pSF);
1055     if (FAILED(ret))
1056         return ret;
1057 
1058     if (lpFindFile || bBindCtx)
1059         ret = IFileSystemBindData_Constructor(lpFindFile, &pBC);
1060 
1061     if (SUCCEEDED(ret))
1062     {
1063         ret = IShellFolder_ParseDisplayName(pSF, 0, pBC, (LPOLESTR)path, NULL, ppidl, prgfInOut);
1064     }
1065 
1066     if (pBC)
1067     {
1068         IBindCtx_Release(pBC);
1069         pBC = NULL;
1070     }
1071 
1072     IShellFolder_Release(pSF);
1073 
1074     if (FAILED(ret) && ppidl)
1075         *ppidl = NULL;
1076 
1077     TRACE("%s %p 0x%x\n", debugstr_w(path), ppidl ? *ppidl : NULL, prgfInOut ? *prgfInOut : 0);
1078 
1079     return ret;
1080 }
1081 
1082 /*************************************************************************
1083  * SHSimpleIDListFromPath    [SHELL32.162]
1084  *
1085  * Creates a simple ItemIDList from a path and returns it. This function
1086  * does not fail on nonexistent paths.
1087  *
1088  * PARAMS
1089  *  path         [I]   path to parse and convert into an ItemIDList
1090  *
1091  * RETURNS
1092  *  the newly created simple ItemIDList
1093  *
1094  * NOTES
1095  *  Simple in the name does not mean a relative ItemIDList but rather a
1096  *  fully qualified list, where only the file name is filled in and the
1097  *  directory flag for those ItemID elements this is known about, eg.
1098  *  it is not the last element in the ItemIDList or the actual directory
1099  *  exists on disk.
1100  *  exported by ordinal.
1101  */
1102 LPITEMIDLIST WINAPI SHSimpleIDListFromPathA(LPCSTR lpszPath)
1103 {
1104     LPITEMIDLIST pidl = NULL;
1105     LPWSTR wPath = NULL;
1106     int len;
1107 
1108     TRACE("%s\n", debugstr_a(lpszPath));
1109 
1110     if (lpszPath)
1111     {
1112         len = MultiByteToWideChar(CP_ACP, 0, lpszPath, -1, NULL, 0);
1113         wPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1114         MultiByteToWideChar(CP_ACP, 0, lpszPath, -1, wPath, len);
1115     }
1116 #ifdef __REACTOS__
1117     // FIXME: Needs folder attribute
1118     if (PathFileExistsW(wPath))
1119     {
1120         pidl = ILCreateFromPathW(wPath);
1121         HeapFree(GetProcessHeap(), 0, wPath);
1122         return pidl;
1123     }
1124 #endif
1125 
1126     _ILParsePathW(wPath, NULL, TRUE, &pidl, NULL);
1127 
1128     HeapFree(GetProcessHeap(), 0, wPath);
1129     TRACE("%s %p\n", debugstr_a(lpszPath), pidl);
1130     return pidl;
1131 }
1132 
1133 LPITEMIDLIST WINAPI SHSimpleIDListFromPathW(LPCWSTR lpszPath)
1134 {
1135     LPITEMIDLIST pidl = NULL;
1136 
1137     TRACE("%s\n", debugstr_w(lpszPath));
1138 #ifdef __REACTOS__
1139     // FIXME: Needs folder attribute
1140     if (PathFileExistsW(lpszPath))
1141         return ILCreateFromPathW(lpszPath);
1142 #endif
1143 
1144     _ILParsePathW(lpszPath, NULL, TRUE, &pidl, NULL);
1145     TRACE("%s %p\n", debugstr_w(lpszPath), pidl);
1146     return pidl;
1147 }
1148 
1149 LPITEMIDLIST WINAPI SHSimpleIDListFromPathAW(LPCVOID lpszPath)
1150 {
1151     if ( SHELL_OsIsUnicode())
1152         return SHSimpleIDListFromPathW (lpszPath);
1153     return SHSimpleIDListFromPathA (lpszPath);
1154 }
1155 
1156 /*************************************************************************
1157  * SHGetDataFromIDListA [SHELL32.247]
1158  *
1159  * NOTES
1160  *  the pidl can be a simple one. since we can't get the path out of the pidl
1161  *  we have to take all data from the pidl
1162  */
1163 HRESULT WINAPI SHGetDataFromIDListA(LPSHELLFOLDER psf, LPCITEMIDLIST pidl,
1164                                     int nFormat, LPVOID dest, int len)
1165 {
1166     LPSTR filename, shortname;
1167     WIN32_FIND_DATAA * pfd;
1168 
1169     TRACE_(shell)("sf=%p pidl=%p 0x%04x %p 0x%04x stub\n",psf,pidl,nFormat,dest,len);
1170 
1171     pdump(pidl);
1172     if (!psf || !dest)
1173         return E_INVALIDARG;
1174 
1175     switch (nFormat)
1176     {
1177     case SHGDFIL_FINDDATA:
1178         pfd = dest;
1179 
1180         if (_ILIsDrive(pidl) || _ILIsSpecialFolder(pidl))
1181             return E_INVALIDARG;
1182 
1183         if (len < sizeof(WIN32_FIND_DATAA))
1184             return E_INVALIDARG;
1185 
1186         ZeroMemory(pfd, sizeof (WIN32_FIND_DATAA));
1187         _ILGetFileDateTime( pidl, &(pfd->ftLastWriteTime));
1188         pfd->dwFileAttributes = _ILGetFileAttributes(pidl, NULL, 0);
1189         pfd->nFileSizeLow = _ILGetFileSize ( pidl, NULL, 0);
1190 
1191         filename = _ILGetTextPointer(pidl);
1192         shortname = _ILGetSTextPointer(pidl);
1193 
1194         if (filename)
1195             lstrcpynA(pfd->cFileName, filename, sizeof(pfd->cFileName));
1196         else
1197             pfd->cFileName[0] = '\0';
1198 
1199         if (shortname)
1200             lstrcpynA(pfd->cAlternateFileName, shortname, sizeof(pfd->cAlternateFileName));
1201         else
1202             pfd->cAlternateFileName[0] = '\0';
1203         return S_OK;
1204 
1205     case SHGDFIL_NETRESOURCE:
1206     case SHGDFIL_DESCRIPTIONID:
1207         FIXME_(shell)("SHGDFIL %i stub\n", nFormat);
1208         break;
1209 
1210     default:
1211         ERR_(shell)("Unknown SHGDFIL %i, please report\n", nFormat);
1212     }
1213 
1214     return E_INVALIDARG;
1215 }
1216 
1217 /*************************************************************************
1218  * SHGetDataFromIDListW [SHELL32.248]
1219  *
1220  */
1221 HRESULT WINAPI SHGetDataFromIDListW(LPSHELLFOLDER psf, LPCITEMIDLIST pidl,
1222                                     int nFormat, LPVOID dest, int len)
1223 {
1224     LPSTR filename, shortname;
1225     WIN32_FIND_DATAW * pfd = dest;
1226 
1227     TRACE_(shell)("sf=%p pidl=%p 0x%04x %p 0x%04x stub\n",psf,pidl,nFormat,dest,len);
1228 
1229     pdump(pidl);
1230 
1231     if (!psf || !dest)
1232         return E_INVALIDARG;
1233 
1234     switch (nFormat)
1235     {
1236     case SHGDFIL_FINDDATA:
1237         pfd = dest;
1238 
1239         if (_ILIsDrive(pidl))
1240             return E_INVALIDARG;
1241 
1242         if (len < sizeof(WIN32_FIND_DATAW))
1243             return E_INVALIDARG;
1244 
1245         ZeroMemory(pfd, sizeof (WIN32_FIND_DATAW));
1246         _ILGetFileDateTime( pidl, &(pfd->ftLastWriteTime));
1247         pfd->dwFileAttributes = _ILGetFileAttributes(pidl, NULL, 0);
1248         pfd->nFileSizeLow = _ILGetFileSize ( pidl, NULL, 0);
1249 
1250         filename = _ILGetTextPointer(pidl);
1251         shortname = _ILGetSTextPointer(pidl);
1252 
1253         if (!filename)
1254             pfd->cFileName[0] = '\0';
1255         else if (!MultiByteToWideChar(CP_ACP, 0, filename, -1, pfd->cFileName, MAX_PATH))
1256             pfd->cFileName[MAX_PATH-1] = 0;
1257 
1258         if (!shortname)
1259             pfd->cAlternateFileName[0] = '\0';
1260         else if (!MultiByteToWideChar(CP_ACP, 0, shortname, -1, pfd->cAlternateFileName, 14))
1261             pfd->cAlternateFileName[13] = 0;
1262         return S_OK;
1263 
1264     case SHGDFIL_NETRESOURCE:
1265     case SHGDFIL_DESCRIPTIONID:
1266         FIXME_(shell)("SHGDFIL %i stub\n", nFormat);
1267         break;
1268 
1269     default:
1270         ERR_(shell)("Unknown SHGDFIL %i, please report\n", nFormat);
1271     }
1272 
1273     return E_INVALIDARG;
1274 }
1275 
1276 /*************************************************************************
1277  * SHGetPathFromIDListA        [SHELL32.@][NT 4.0: SHELL32.220]
1278  *
1279  * PARAMETERS
1280  *  pidl,   [IN] pidl
1281  *  pszPath [OUT] path
1282  *
1283  * RETURNS
1284  *  path from a passed PIDL.
1285  *
1286  * NOTES
1287  *    NULL returns FALSE
1288  *    desktop pidl gives path to desktop directory back
1289  *    special pidls returning FALSE
1290  */
1291 BOOL WINAPI SHGetPathFromIDListA(LPCITEMIDLIST pidl, LPSTR pszPath)
1292 {
1293     WCHAR wszPath[MAX_PATH];
1294     BOOL bSuccess;
1295 
1296     bSuccess = SHGetPathFromIDListW(pidl, wszPath);
1297     WideCharToMultiByte(CP_ACP, 0, wszPath, -1, pszPath, MAX_PATH, NULL, NULL);
1298 
1299     return bSuccess;
1300 }
1301 
1302 /*************************************************************************
1303  * SHGetPathFromIDListW             [SHELL32.@]
1304  *
1305  * See SHGetPathFromIDListA.
1306  */
1307 HRESULT WINAPI
1308 SHGetPathCchFromIDListW(
1309     _In_ LPCITEMIDLIST pidl,
1310     _Out_writes_(cchPathMax) LPWSTR pszPath,
1311     _In_ SIZE_T cchPathMax)
1312 {
1313     HRESULT hr;
1314     LPCITEMIDLIST pidlLast;
1315     LPSHELLFOLDER psfFolder;
1316     DWORD dwAttributes;
1317     STRRET strret;
1318 
1319     TRACE_(shell)("(pidl=%p,%p)\n", pidl, pszPath);
1320     pdump(pidl);
1321 
1322     *pszPath = UNICODE_NULL;
1323     if (!pidl)
1324         return E_FAIL;
1325 
1326     hr = SHBindToParent(pidl, &IID_IShellFolder, (VOID**)&psfFolder, &pidlLast);
1327     if (FAILED(hr))
1328     {
1329         ERR("SHBindToParent failed: %x\n", hr);
1330         return hr;
1331     }
1332 
1333     dwAttributes = SFGAO_FILESYSTEM;
1334     hr = IShellFolder_GetAttributesOf(psfFolder, 1, &pidlLast, &dwAttributes);
1335     if (FAILED(hr) || !(dwAttributes & SFGAO_FILESYSTEM))
1336     {
1337         WARN("Wrong dwAttributes or GetAttributesOf failed: %x\n", hr);
1338         IShellFolder_Release(psfFolder);
1339         return E_FAIL;
1340     }
1341 
1342     hr = IShellFolder_GetDisplayNameOf(psfFolder, pidlLast, SHGDN_FORPARSING, &strret);
1343     IShellFolder_Release(psfFolder);
1344     if (FAILED(hr))
1345         return hr;
1346 
1347     hr = StrRetToBufW(&strret, pidlLast, pszPath, cchPathMax);
1348 
1349     TRACE_(shell)("-- %s, 0x%08x\n",debugstr_w(pszPath), hr);
1350     return hr;
1351 }
1352 
1353 BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath)
1354 {
1355     return SUCCEEDED(SHGetPathCchFromIDListW(pidl, pszPath, MAX_PATH));
1356 }
1357 
1358 /*************************************************************************
1359  *    SHBindToParent        [shell version 5.0]
1360  */
1361 HRESULT WINAPI SHBindToParent(LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppv, LPCITEMIDLIST *ppidlLast)
1362 {
1363     IShellFolder    * psfDesktop;
1364     HRESULT         hr=E_FAIL;
1365 
1366     TRACE_(shell)("pidl=%p\n", pidl);
1367     pdump(pidl);
1368 
1369     if (!pidl || !ppv)
1370         return E_INVALIDARG;
1371 
1372     *ppv = NULL;
1373     if (ppidlLast)
1374         *ppidlLast = NULL;
1375 
1376     hr = SHGetDesktopFolder(&psfDesktop);
1377     if (FAILED(hr))
1378         return hr;
1379 
1380     if (_ILIsPidlSimple(pidl))
1381     {
1382         /* we are on desktop level */
1383         hr = IShellFolder_QueryInterface(psfDesktop, riid, ppv);
1384     }
1385     else
1386     {
1387         LPITEMIDLIST pidlParent = ILClone(pidl);
1388         ILRemoveLastID(pidlParent);
1389         hr = IShellFolder_BindToObject(psfDesktop, pidlParent, NULL, riid, ppv);
1390         SHFree (pidlParent);
1391     }
1392 
1393     IShellFolder_Release(psfDesktop);
1394 
1395     if (SUCCEEDED(hr) && ppidlLast)
1396         *ppidlLast = ILFindLastID(pidl);
1397 
1398     TRACE_(shell)("-- psf=%p pidl=%p ret=0x%08x\n", *ppv, (ppidlLast)?*ppidlLast:NULL, hr);
1399     return hr;
1400 }
1401 
1402 /*************************************************************************
1403  *    SHParseDisplayName        [shell version 6.0]
1404  */
1405 HRESULT WINAPI SHParseDisplayName(LPCWSTR pszName, IBindCtx *pbc,
1406     LPITEMIDLIST *ppidl, SFGAOF sfgaoIn, SFGAOF *psfgaoOut)
1407 {
1408     HRESULT hr;
1409     LPWSTR pszNameDup;
1410     IShellFolder *psfDesktop;
1411     IBindCtx *pBindCtx = NULL;
1412 
1413     TRACE("(%s, %p, %p, 0x%X, %p)\n", pszName, pbc, ppidl, sfgaoIn, psfgaoOut);
1414 
1415     *ppidl = NULL;
1416 
1417     if (psfgaoOut)
1418         *psfgaoOut = 0;
1419 
1420     pszNameDup = StrDupW(pszName);
1421     if (!pszNameDup)
1422         return E_OUTOFMEMORY;
1423 
1424     psfDesktop = NULL;
1425     hr = SHGetDesktopFolder(&psfDesktop);
1426     if (FAILED(hr))
1427     {
1428         LocalFree(pszNameDup);
1429         return hr;
1430     }
1431 
1432     if (!pbc)
1433     {
1434         hr = BindCtx_RegisterObjectParam(NULL, STR_PARSE_TRANSLATE_ALIASES, NULL, &pBindCtx);
1435         pbc = pBindCtx;
1436     }
1437 
1438     if (SUCCEEDED(hr))
1439     {
1440         ULONG sfgao = sfgaoIn, cchEaten;
1441         HWND hwndUI = BindCtx_GetUIWindow(pbc);
1442         hr = psfDesktop->lpVtbl->ParseDisplayName(psfDesktop,
1443                                                   hwndUI,
1444                                                   pbc,
1445                                                   pszNameDup,
1446                                                   &cchEaten,
1447                                                   ppidl,
1448                                                   (psfgaoOut ? &sfgao : NULL));
1449         if (SUCCEEDED(hr) && psfgaoOut)
1450             *psfgaoOut = (sfgao & sfgaoIn);
1451     }
1452 
1453     LocalFree(pszNameDup);
1454 
1455     if (psfDesktop)
1456         psfDesktop->lpVtbl->Release(psfDesktop);
1457 
1458     if (pBindCtx)
1459         pBindCtx->lpVtbl->Release(pBindCtx);
1460 
1461     return hr;
1462 }
1463 
1464 /*************************************************************************
1465  * SHGetNameFromIDList             [SHELL32.@]
1466  */
1467 HRESULT WINAPI SHGetNameFromIDList(PCIDLIST_ABSOLUTE pidl, SIGDN sigdnName, PWSTR *ppszName)
1468 {
1469     IShellFolder *psfparent;
1470     LPCITEMIDLIST child_pidl;
1471     STRRET disp_name;
1472     HRESULT ret;
1473 
1474     TRACE("%p 0x%08x %p\n", pidl, sigdnName, ppszName);
1475 
1476     *ppszName = NULL;
1477     ret = SHBindToParent(pidl, &IID_IShellFolder, (void**)&psfparent, &child_pidl);
1478     if(SUCCEEDED(ret))
1479     {
1480         switch(sigdnName)
1481         {
1482                                                 /* sigdnName & 0xffff */
1483         case SIGDN_NORMALDISPLAY:               /* SHGDN_NORMAL */
1484         case SIGDN_PARENTRELATIVEPARSING:       /* SHGDN_INFOLDER | SHGDN_FORPARSING */
1485         case SIGDN_PARENTRELATIVEEDITING:       /* SHGDN_INFOLDER | SHGDN_FOREDITING */
1486         case SIGDN_DESKTOPABSOLUTEPARSING:      /* SHGDN_FORPARSING */
1487         case SIGDN_DESKTOPABSOLUTEEDITING:      /* SHGDN_FOREDITING | SHGDN_FORADDRESSBAR*/
1488         case SIGDN_PARENTRELATIVEFORADDRESSBAR: /* SIGDN_INFOLDER | SHGDN_FORADDRESSBAR */
1489         case SIGDN_PARENTRELATIVE:              /* SIGDN_INFOLDER */
1490 
1491             disp_name.uType = STRRET_WSTR;
1492             ret = IShellFolder_GetDisplayNameOf(psfparent, child_pidl,
1493                                                 sigdnName & 0xffff,
1494                                                 &disp_name);
1495             if(SUCCEEDED(ret))
1496                 ret = StrRetToStrW(&disp_name, pidl, ppszName);
1497 
1498             break;
1499 
1500         case SIGDN_FILESYSPATH:
1501             *ppszName = CoTaskMemAlloc(sizeof(WCHAR)*MAX_PATH);
1502             if(SHGetPathFromIDListW(pidl, *ppszName))
1503             {
1504                 TRACE("Got string %s\n", debugstr_w(*ppszName));
1505                 ret = S_OK;
1506             }
1507             else
1508             {
1509                 CoTaskMemFree(*ppszName);
1510                 ret = E_INVALIDARG;
1511             }
1512             break;
1513 
1514         case SIGDN_URL:
1515         default:
1516             FIXME("Unsupported SIGDN %x\n", sigdnName);
1517             ret = E_FAIL;
1518         }
1519 
1520         IShellFolder_Release(psfparent);
1521     }
1522     return ret;
1523 }
1524 
1525 #ifndef __REACTOS__
1526 
1527 /*************************************************************************
1528  * SHGetIDListFromObject             [SHELL32.@]
1529  */
1530 HRESULT WINAPI SHGetIDListFromObject(IUnknown *punk, PIDLIST_ABSOLUTE *ppidl)
1531 {
1532     IPersistIDList *ppersidl;
1533     IPersistFolder2 *ppf2;
1534     IDataObject *pdo;
1535     IFolderView *pfv;
1536     HRESULT ret;
1537 
1538     if(!punk)
1539         return E_NOINTERFACE;
1540 
1541     *ppidl = NULL;
1542 
1543     /* Try IPersistIDList */
1544     ret = IUnknown_QueryInterface(punk, &IID_IPersistIDList, (void**)&ppersidl);
1545     if(SUCCEEDED(ret))
1546     {
1547         TRACE("IPersistIDList (%p)\n", ppersidl);
1548         ret = IPersistIDList_GetIDList(ppersidl, ppidl);
1549         IPersistIDList_Release(ppersidl);
1550         if(SUCCEEDED(ret))
1551             return ret;
1552     }
1553 
1554     /* Try IPersistFolder2 */
1555     ret = IUnknown_QueryInterface(punk, &IID_IPersistFolder2, (void**)&ppf2);
1556     if(SUCCEEDED(ret))
1557     {
1558         TRACE("IPersistFolder2 (%p)\n", ppf2);
1559         ret = IPersistFolder2_GetCurFolder(ppf2, ppidl);
1560         IPersistFolder2_Release(ppf2);
1561         if(SUCCEEDED(ret))
1562             return ret;
1563     }
1564 
1565     /* Try IDataObject */
1566     ret = IUnknown_QueryInterface(punk, &IID_IDataObject, (void**)&pdo);
1567     if(SUCCEEDED(ret))
1568     {
1569         IShellItem *psi;
1570         TRACE("IDataObject (%p)\n", pdo);
1571         ret = SHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE,
1572                                       &IID_IShellItem, (void**)&psi);
1573         if(SUCCEEDED(ret))
1574         {
1575             ret = SHGetIDListFromObject((IUnknown*)psi, ppidl);
1576             IShellItem_Release(psi);
1577         }
1578         IDataObject_Release(pdo);
1579 
1580         if(SUCCEEDED(ret))
1581             return ret;
1582     }
1583 
1584     /* Try IFolderView */
1585     ret = IUnknown_QueryInterface(punk, &IID_IFolderView, (void**)&pfv);
1586     if(SUCCEEDED(ret))
1587     {
1588         IShellFolder *psf;
1589         TRACE("IFolderView (%p)\n", pfv);
1590         ret = IFolderView_GetFolder(pfv, &IID_IShellFolder, (void**)&psf);
1591         if(SUCCEEDED(ret))
1592         {
1593             /* We might be able to get IPersistFolder2 from a shellfolder. */
1594             ret = SHGetIDListFromObject((IUnknown*)psf, ppidl);
1595         }
1596         IFolderView_Release(pfv);
1597         return ret;
1598     }
1599 
1600     return ret;
1601 }
1602 
1603 #endif /* !__REACTOS__ */
1604 
1605 /**************************************************************************
1606  *
1607  *        internal functions
1608  *
1609  *    ### 1. section creating pidls ###
1610  *
1611  *************************************************************************
1612  */
1613 
1614 /* Basic PIDL constructor.  Allocates size + 5 bytes, where:
1615  * - two bytes are SHITEMID.cb
1616  * - one byte is PIDLDATA.type
1617  * - two bytes are the NULL PIDL terminator
1618  * Sets type of the returned PIDL to type.
1619  */
1620 static LPITEMIDLIST _ILAlloc(PIDLTYPE type, unsigned int size)
1621 {
1622     LPITEMIDLIST pidlOut = NULL;
1623 
1624     pidlOut = SHAlloc(size + 5);
1625     if(pidlOut)
1626     {
1627         LPPIDLDATA pData;
1628         LPITEMIDLIST pidlNext;
1629 
1630         ZeroMemory(pidlOut, size + 5);
1631         pidlOut->mkid.cb = size + 3;
1632 
1633         pData = _ILGetDataPointer(pidlOut);
1634         if (pData)
1635             pData->type = type;
1636 
1637         pidlNext = ILGetNext(pidlOut);
1638         if (pidlNext)
1639             pidlNext->mkid.cb = 0x00;
1640         TRACE("-- (pidl=%p, size=%u)\n", pidlOut, size);
1641     }
1642 
1643     return pidlOut;
1644 }
1645 
1646 LPITEMIDLIST _ILCreateDesktop(void)
1647 {
1648     LPITEMIDLIST ret;
1649 
1650     TRACE("()\n");
1651     ret = SHAlloc(2);
1652     if (ret)
1653         ret->mkid.cb = 0;
1654     return ret;
1655 }
1656 
1657 LPITEMIDLIST _ILCreateMyComputer(void)
1658 {
1659     TRACE("()\n");
1660     return _ILCreateGuid(PT_GUID, &CLSID_MyComputer);
1661 }
1662 
1663 LPITEMIDLIST _ILCreateMyDocuments(void)
1664 {
1665     TRACE("()\n");
1666     return _ILCreateGuid(PT_GUID, &CLSID_MyDocuments);
1667 }
1668 
1669 LPITEMIDLIST _ILCreateIExplore(void)
1670 {
1671     TRACE("()\n");
1672     return _ILCreateGuid(PT_GUID, &CLSID_Internet);
1673 }
1674 
1675 LPITEMIDLIST _ILCreateControlPanel(void)
1676 {
1677     LPITEMIDLIST parent = _ILCreateGuid(PT_GUID, &CLSID_MyComputer), ret = NULL;
1678 
1679     TRACE("()\n");
1680     if (parent)
1681     {
1682         LPITEMIDLIST cpl = _ILCreateGuid(PT_SHELLEXT, &CLSID_ControlPanel);
1683 
1684         if (cpl)
1685         {
1686             ret = ILCombine(parent, cpl);
1687             SHFree(cpl);
1688         }
1689         SHFree(parent);
1690     }
1691     return ret;
1692 }
1693 
1694 LPITEMIDLIST _ILCreatePrinters(void)
1695 {
1696     LPITEMIDLIST parent = _ILCreateGuid(PT_GUID, &CLSID_MyComputer), ret = NULL;
1697 
1698     TRACE("()\n");
1699     if (parent)
1700     {
1701         LPITEMIDLIST printers = _ILCreateGuid(PT_YAGUID, &CLSID_Printers);
1702 
1703         if (printers)
1704         {
1705             ret = ILCombine(parent, printers);
1706             SHFree(printers);
1707         }
1708         SHFree(parent);
1709     }
1710     return ret;
1711 }
1712 
1713 LPITEMIDLIST _ILCreateNetwork(void)
1714 {
1715     TRACE("()\n");
1716     return _ILCreateGuid(PT_GUID, &CLSID_NetworkPlaces);
1717 }
1718 
1719 LPITEMIDLIST _ILCreateBitBucket(void)
1720 {
1721     TRACE("()\n");
1722     return _ILCreateGuid(PT_GUID, &CLSID_RecycleBin);
1723 }
1724 
1725 LPITEMIDLIST _ILCreateAdminTools(void)
1726 {
1727     TRACE("()\n");
1728     return _ILCreateGuid(PT_GUID, &CLSID_AdminFolderShortcut); //FIXME
1729 }
1730 
1731 LPITEMIDLIST _ILCreateGuid(PIDLTYPE type, REFIID guid)
1732 {
1733     LPITEMIDLIST pidlOut;
1734 
1735     if (type == PT_SHELLEXT || type == PT_GUID || type == PT_YAGUID)
1736     {
1737         pidlOut = _ILAlloc(type, sizeof(GUIDStruct));
1738         if (pidlOut)
1739         {
1740             LPPIDLDATA pData = _ILGetDataPointer(pidlOut);
1741 
1742             pData->u.guid.guid = *guid;
1743             TRACE("-- create GUID-pidl %s\n",
1744                   debugstr_guid(&(pData->u.guid.guid)));
1745         }
1746     }
1747     else
1748     {
1749         WARN("%d: invalid type for GUID\n", type);
1750         pidlOut = NULL;
1751     }
1752     return pidlOut;
1753 }
1754 
1755 #ifndef __REACTOS__
1756 LPITEMIDLIST _ILCreateGuidFromStrA(LPCSTR szGUID)
1757 {
1758     IID iid;
1759 
1760     if (FAILED(SHCLSIDFromStringA(szGUID, &iid)))
1761     {
1762         ERR("%s is not a GUID\n", szGUID);
1763         return NULL;
1764     }
1765     return _ILCreateGuid(PT_GUID, &iid);
1766 }
1767 #endif
1768 
1769 LPITEMIDLIST _ILCreateGuidFromStrW(LPCWSTR szGUID)
1770 {
1771     IID iid;
1772 
1773 #ifndef __REACTOS__
1774     if (FAILED(SHCLSIDFromStringW(szGUID, &iid)))
1775 #else
1776     if (!GUIDFromStringW(szGUID, &iid))
1777 #endif
1778     {
1779         ERR("%s is not a GUID\n", debugstr_w(szGUID));
1780         return NULL;
1781     }
1782     return _ILCreateGuid(PT_GUID, &iid);
1783 }
1784 
1785 LPITEMIDLIST _ILCreateFromFindDataW( const WIN32_FIND_DATAW *wfd )
1786 {
1787     char    buff[MAX_PATH + 14 +1]; /* see WIN32_FIND_DATA */
1788     DWORD   len, len1, wlen, alen;
1789     LPITEMIDLIST pidl;
1790     PIDLTYPE type;
1791 
1792     if (!wfd)
1793         return NULL;
1794 
1795     TRACE("(%s, %s)\n",debugstr_w(wfd->cAlternateFileName), debugstr_w(wfd->cFileName));
1796 
1797     /* prepare buffer with both names */
1798     len = WideCharToMultiByte(CP_ACP,0,wfd->cFileName,-1,buff,MAX_PATH,NULL,NULL);
1799     len1 = WideCharToMultiByte(CP_ACP,0,wfd->cAlternateFileName,-1, buff+len, sizeof(buff)-len, NULL, NULL);
1800     alen = len + len1;
1801 
1802     type = (wfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? PT_FOLDER : PT_VALUE;
1803 
1804     wlen = lstrlenW(wfd->cFileName) + 1;
1805     pidl = _ILAlloc(type, FIELD_OFFSET(FileStruct, szNames[alen + (alen & 1)]) +
1806                     FIELD_OFFSET(FileStructW, wszName[wlen]) + sizeof(WORD));
1807     if (pidl)
1808     {
1809         LPPIDLDATA pData = _ILGetDataPointer(pidl);
1810         FileStruct *fs = &pData->u.file;
1811         FileStructW *fsw;
1812         WORD *pOffsetW;
1813 
1814         FileTimeToDosDateTime( &wfd->ftLastWriteTime, &fs->uFileDate, &fs->uFileTime);
1815         fs->dwFileSize = wfd->nFileSizeLow;
1816         fs->uFileAttribs = wfd->dwFileAttributes;
1817         memcpy(fs->szNames, buff, alen);
1818 
1819         fsw = (FileStructW*)(pData->u.file.szNames + alen + (alen & 0x1));
1820         fsw->cbLen = FIELD_OFFSET(FileStructW, wszName[wlen]) + sizeof(WORD);
1821         FileTimeToDosDateTime( &wfd->ftCreationTime, &fsw->uCreationDate, &fsw->uCreationTime);
1822         FileTimeToDosDateTime( &wfd->ftLastAccessTime, &fsw->uLastAccessDate, &fsw->uLastAccessTime);
1823         memcpy(fsw->wszName, wfd->cFileName, wlen * sizeof(WCHAR));
1824 
1825         pOffsetW = (WORD*)((LPBYTE)pidl + pidl->mkid.cb - sizeof(WORD));
1826         *pOffsetW = (LPBYTE)fsw - (LPBYTE)pidl;
1827         TRACE("-- Set Value: %s\n",debugstr_w(fsw->wszName));
1828     }
1829     return pidl;
1830 
1831 }
1832 
1833 HRESULT _ILCreateFromPathW(LPCWSTR szPath, LPITEMIDLIST* ppidl)
1834 {
1835     HANDLE hFile;
1836     WIN32_FIND_DATAW stffile;
1837 
1838     if (!ppidl)
1839         return E_INVALIDARG;
1840 
1841     hFile = FindFirstFileW(szPath, &stffile);
1842     if (hFile == INVALID_HANDLE_VALUE)
1843         return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
1844 
1845     FindClose(hFile);
1846 
1847     *ppidl = _ILCreateFromFindDataW(&stffile);
1848 
1849     return *ppidl ? S_OK : E_OUTOFMEMORY;
1850 }
1851 
1852 LPITEMIDLIST _ILCreateDrive(LPCWSTR lpszNew)
1853 {
1854     LPITEMIDLIST pidlOut;
1855 
1856     TRACE("(%s)\n",debugstr_w(lpszNew));
1857 
1858     pidlOut = _ILAlloc(PT_DRIVE, sizeof(DriveStruct));
1859     if (pidlOut)
1860     {
1861         LPSTR pszDest;
1862 
1863         pszDest = _ILGetTextPointer(pidlOut);
1864         if (pszDest)
1865         {
1866             strcpy(pszDest, "x:\\");
1867             pszDest[0]=toupperW(lpszNew[0]);
1868             TRACE("-- create Drive: %s\n", debugstr_a(pszDest));
1869         }
1870     }
1871     return pidlOut;
1872 }
1873 
1874 LPITEMIDLIST _ILCreateEntireNetwork(void)
1875 {
1876     LPITEMIDLIST pidlOut;
1877 
1878     TRACE("\n");
1879 
1880     pidlOut = _ILAlloc(PT_NETWORK, FIELD_OFFSET(PIDLDATA, u.network.szNames[sizeof("Entire Network")]));
1881     if (pidlOut)
1882     {
1883         LPPIDLDATA pData = _ILGetDataPointer(pidlOut);
1884 
1885         pData->u.network.dummy = 0;
1886         strcpy(pData->u.network.szNames, "Entire Network");
1887     }
1888     return pidlOut;
1889 }
1890 
1891 /**************************************************************************
1892  *  _ILGetDrive()
1893  *
1894  *  Gets the text for the drive eg. 'c:\'
1895  *
1896  * RETURNS
1897  *  strlen (lpszText)
1898  */
1899 DWORD _ILGetDrive(LPCITEMIDLIST pidl,LPSTR pOut, UINT uSize)
1900 {
1901     TRACE("(%p,%p,%u)\n",pidl,pOut,uSize);
1902 
1903     if(_ILIsMyComputer(pidl))
1904         pidl = ILGetNext(pidl);
1905 
1906     if (pidl && _ILIsDrive(pidl))
1907         return _ILSimpleGetText(pidl, pOut, uSize);
1908 
1909     return 0;
1910 }
1911 
1912 /**************************************************************************
1913  *
1914  *    ### 2. section testing pidls ###
1915  *
1916  **************************************************************************
1917  *  _ILIsUnicode()
1918  *  _ILIsDesktop()
1919  *  _ILIsMyComputer()
1920  *  _ILIsSpecialFolder()
1921  *  _ILIsDrive()
1922  *  _ILIsFolder()
1923  *  _ILIsValue()
1924  *  _ILIsPidlSimple()
1925  */
1926 BOOL _ILIsUnicode(LPCITEMIDLIST pidl)
1927 {
1928     LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
1929 
1930     TRACE("(%p)\n",pidl);
1931 
1932     return (pidl && lpPData && PT_VALUEW == lpPData->type);
1933 }
1934 
1935 BOOL _ILIsDesktop(LPCITEMIDLIST pidl)
1936 {
1937     TRACE("(%p)\n",pidl);
1938 
1939     return !pidl || !pidl->mkid.cb;
1940 }
1941 
1942 BOOL _ILIsMyDocuments(LPCITEMIDLIST pidl)
1943 {
1944     IID *iid = _ILGetGUIDPointer(pidl);
1945 
1946     TRACE("(%p)\n", pidl);
1947 
1948     if (iid)
1949         return IsEqualIID(iid, &CLSID_MyDocuments);
1950     return FALSE;
1951 }
1952 
1953 BOOL _ILIsNetHood(LPCITEMIDLIST pidl)
1954 {
1955     IID *iid = _ILGetGUIDPointer(pidl);
1956 
1957     TRACE("(%p)\n", pidl);
1958 
1959     if (iid)
1960         return IsEqualIID(iid, &CLSID_NetworkPlaces);
1961     return FALSE;
1962 }
1963 
1964 BOOL _ILIsControlPanel(LPCITEMIDLIST pidl)
1965 {
1966     IID *iid = _ILGetGUIDPointer(pidl);
1967 
1968     TRACE("(%p)\n", pidl);
1969 
1970     if (iid)
1971         return IsEqualIID(iid, &CLSID_ControlPanel);
1972     return FALSE;
1973 }
1974 
1975 BOOL _ILIsMyComputer(LPCITEMIDLIST pidl)
1976 {
1977     REFIID iid = _ILGetGUIDPointer(pidl);
1978 
1979     TRACE("(%p)\n",pidl);
1980 
1981     if (iid)
1982         return IsEqualIID(iid, &CLSID_MyComputer);
1983     return FALSE;
1984 }
1985 
1986 BOOL _ILIsBitBucket(LPCITEMIDLIST pidl)
1987 {
1988     IID *iid = _ILGetGUIDPointer(pidl);
1989 
1990     TRACE("(%p)\n", pidl);
1991 
1992     if (iid)
1993         return IsEqualIID(iid, &CLSID_RecycleBin);
1994     return FALSE;
1995 }
1996 
1997 BOOL _ILIsSpecialFolder (LPCITEMIDLIST pidl)
1998 {
1999     LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
2000 
2001     TRACE("(%p)\n",pidl);
2002 
2003     return (pidl && ( (lpPData && (PT_GUID== lpPData->type || PT_SHELLEXT== lpPData->type || PT_YAGUID == lpPData->type)) ||
2004               (pidl && pidl->mkid.cb == 0x00)
2005             ));
2006 }
2007 
2008 BOOL _ILIsDrive(LPCITEMIDLIST pidl)
2009 {
2010     LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
2011 
2012     TRACE("(%p)\n",pidl);
2013 
2014     return (pidl && lpPData && (PT_DRIVE == lpPData->type ||
2015                     PT_DRIVE1 == lpPData->type ||
2016                     PT_DRIVE2 == lpPData->type ||
2017                     PT_DRIVE3 == lpPData->type));
2018 }
2019 
2020 BOOL _ILIsFolder(LPCITEMIDLIST pidl)
2021 {
2022     LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
2023 
2024     TRACE("(%p)\n",pidl);
2025 
2026     return (pidl && lpPData && (PT_FOLDER == lpPData->type || PT_FOLDER1 == lpPData->type));
2027 }
2028 
2029 BOOL _ILIsValue(LPCITEMIDLIST pidl)
2030 {
2031     LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
2032 
2033     TRACE("(%p)\n",pidl);
2034 
2035     return (pidl && lpPData && PT_VALUE == lpPData->type);
2036 }
2037 
2038 BOOL _ILIsCPanelStruct(LPCITEMIDLIST pidl)
2039 {
2040     LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
2041 
2042     TRACE("(%p)\n",pidl);
2043 
2044     return (pidl && lpPData && (lpPData->type == 0));
2045 }
2046 
2047 /**************************************************************************
2048  *    _ILIsPidlSimple
2049  */
2050 BOOL _ILIsPidlSimple(LPCITEMIDLIST pidl)
2051 {
2052     BOOL ret = TRUE;
2053 
2054     if(! _ILIsDesktop(pidl))    /* pidl=NULL or mkid.cb=0 */
2055     {
2056         WORD len = pidl->mkid.cb;
2057         LPCITEMIDLIST pidlnext = (LPCITEMIDLIST) (((const BYTE*)pidl) + len );
2058 
2059         if (pidlnext->mkid.cb)
2060             ret = FALSE;
2061     }
2062 
2063     TRACE("%s\n", ret ? "Yes" : "No");
2064     return ret;
2065 }
2066 
2067 /**************************************************************************
2068  *
2069  *    ### 3. section getting values from pidls ###
2070  */
2071 
2072  /**************************************************************************
2073  *  _ILSimpleGetText
2074  *
2075  * gets the text for the first item in the pidl (eg. simple pidl)
2076  *
2077  * returns the length of the string
2078  */
2079 DWORD _ILSimpleGetText (LPCITEMIDLIST pidl, LPSTR szOut, UINT uOutSize)
2080 {
2081     DWORD        dwReturn=0;
2082     LPSTR        szSrc;
2083     LPWSTR       szSrcW;
2084     GUID const * riid;
2085     char szTemp[MAX_PATH];
2086 
2087     TRACE("(%p %p %x)\n",pidl,szOut,uOutSize);
2088 
2089     if (!pidl)
2090         return 0;
2091 
2092     if (szOut)
2093         *szOut = 0;
2094 
2095     if (_ILIsDesktop(pidl))
2096     {
2097         /* desktop */
2098         if (HCR_GetClassNameA(&CLSID_ShellDesktop, szTemp, MAX_PATH))
2099         {
2100             if (szOut)
2101                 lstrcpynA(szOut, szTemp, uOutSize);
2102 
2103             dwReturn = strlen (szTemp);
2104         }
2105     }
2106     else if (( szSrc = _ILGetTextPointer(pidl) ))
2107     {
2108         /* filesystem */
2109         if (szOut)
2110             lstrcpynA(szOut, szSrc, uOutSize);
2111 
2112         dwReturn = strlen(szSrc);
2113     }
2114     else if (( szSrcW = _ILGetTextPointerW(pidl) ))
2115     {
2116         /* unicode filesystem */
2117         WideCharToMultiByte(CP_ACP,0,szSrcW, -1, szTemp, MAX_PATH, NULL, NULL);
2118 
2119         if (szOut)
2120             lstrcpynA(szOut, szTemp, uOutSize);
2121 
2122         dwReturn = strlen (szTemp);
2123     }
2124     else if (( riid = _ILGetGUIDPointer(pidl) ))
2125     {
2126         /* special folder */
2127         if ( HCR_GetClassNameA(riid, szTemp, MAX_PATH) )
2128         {
2129             if (szOut)
2130                 lstrcpynA(szOut, szTemp, uOutSize);
2131 
2132             dwReturn = strlen (szTemp);
2133         }
2134     }
2135     else
2136     {
2137         ERR("-- no text\n");
2138     }
2139 
2140     TRACE("-- (%p=%s 0x%08x)\n",szOut,debugstr_a(szOut),dwReturn);
2141     return dwReturn;
2142 }
2143 
2144  /**************************************************************************
2145  *  _ILSimpleGetTextW
2146  *
2147  * gets the text for the first item in the pidl (eg. simple pidl)
2148  *
2149  * returns the length of the string
2150  */
2151 DWORD _ILSimpleGetTextW (LPCITEMIDLIST pidl, LPWSTR szOut, UINT uOutSize)
2152 {
2153     DWORD   dwReturn;
2154     FileStructW *pFileStructW = _ILGetFileStructW(pidl);
2155 
2156     TRACE("(%p %p %x)\n",pidl,szOut,uOutSize);
2157 
2158     if (pFileStructW) {
2159         lstrcpynW(szOut, pFileStructW->wszName, uOutSize);
2160         dwReturn = lstrlenW(pFileStructW->wszName);
2161     } else {
2162         GUID const * riid;
2163         WCHAR szTemp[MAX_PATH];
2164         LPSTR szSrc;
2165         LPWSTR szSrcW;
2166         dwReturn=0;
2167 
2168         if (!pidl)
2169             return 0;
2170 
2171         if (szOut)
2172             *szOut = 0;
2173 
2174         if (_ILIsDesktop(pidl))
2175         {
2176             /* desktop */
2177             if (HCR_GetClassNameW(&CLSID_ShellDesktop, szTemp, MAX_PATH))
2178             {
2179                 if (szOut)
2180                     lstrcpynW(szOut, szTemp, uOutSize);
2181 
2182                 dwReturn = lstrlenW (szTemp);
2183             }
2184         }
2185         else if (( szSrcW = _ILGetTextPointerW(pidl) ))
2186         {
2187             /* unicode filesystem */
2188             if (szOut)
2189                 lstrcpynW(szOut, szSrcW, uOutSize);
2190 
2191             dwReturn = lstrlenW(szSrcW);
2192         }
2193         else if (( szSrc = _ILGetTextPointer(pidl) ))
2194         {
2195             /* filesystem */
2196             MultiByteToWideChar(CP_ACP, 0, szSrc, -1, szTemp, MAX_PATH);
2197 
2198             if (szOut)
2199                 lstrcpynW(szOut, szTemp, uOutSize);
2200 
2201             dwReturn = lstrlenW (szTemp);
2202         }
2203         else if (( riid = _ILGetGUIDPointer(pidl) ))
2204         {
2205             /* special folder */
2206             if ( HCR_GetClassNameW(riid, szTemp, MAX_PATH) )
2207             {
2208                 if (szOut)
2209                     lstrcpynW(szOut, szTemp, uOutSize);
2210 
2211                 dwReturn = lstrlenW (szTemp);
2212             }
2213         }
2214         else
2215         {
2216             ERR("-- no text\n");
2217         }
2218     }
2219 
2220     TRACE("-- (%p=%s 0x%08x)\n",szOut,debugstr_w(szOut),dwReturn);
2221     return dwReturn;
2222 }
2223 
2224 /**************************************************************************
2225  *
2226  *    ### 4. getting pointers to parts of pidls ###
2227  *
2228  **************************************************************************
2229  *  _ILGetDataPointer()
2230  */
2231 LPPIDLDATA _ILGetDataPointer(LPCITEMIDLIST pidl)
2232 {
2233     if(!_ILIsEmpty(pidl))
2234         return (LPPIDLDATA)pidl->mkid.abID;
2235     return NULL;
2236 }
2237 
2238 /**************************************************************************
2239  *  _ILGetTextPointerW()
2240  * gets a pointer to the unicode long filename string stored in the pidl
2241  */
2242 static LPWSTR _ILGetTextPointerW(LPCITEMIDLIST pidl)
2243 {
2244     /* TRACE(pidl,"(pidl%p)\n", pidl);*/
2245 
2246     LPPIDLDATA pdata = _ILGetDataPointer(pidl);
2247 
2248     if (!pdata)
2249         return NULL;
2250 
2251     switch (pdata->type)
2252     {
2253     case PT_GUID:
2254     case PT_SHELLEXT:
2255     case PT_YAGUID:
2256         return NULL;
2257 
2258     case PT_DRIVE:
2259     case PT_DRIVE1:
2260     case PT_DRIVE2:
2261     case PT_DRIVE3:
2262         /*return (LPSTR)&(pdata->u.drive.szDriveName);*/
2263         return NULL;
2264 
2265     case PT_FOLDER:
2266     case PT_FOLDER1:
2267     case PT_VALUE:
2268     case PT_IESPECIAL1:
2269     case PT_IESPECIAL2:
2270         /*return (LPSTR)&(pdata->u.file.szNames);*/
2271         return NULL;
2272 
2273     case PT_WORKGRP:
2274     case PT_COMP:
2275     case PT_NETWORK:
2276     case PT_NETPROVIDER:
2277     case PT_SHARE:
2278         /*return (LPSTR)&(pdata->u.network.szNames);*/
2279         return NULL;
2280 
2281     case PT_VALUEW:
2282         return (LPWSTR)pdata->u.file.szNames;
2283 
2284 #ifdef __REACTOS__ /* r54423 */
2285     case PT_CPLAPPLET:
2286         return pdata->u.cpanel.szName;
2287 #endif
2288 
2289     }
2290     return NULL;
2291 }
2292 
2293 
2294 /**************************************************************************
2295  *  _ILGetTextPointer()
2296  * gets a pointer to the long filename string stored in the pidl
2297  */
2298 LPSTR _ILGetTextPointer(LPCITEMIDLIST pidl)
2299 {
2300     /* TRACE(pidl,"(pidl%p)\n", pidl);*/
2301 
2302     LPPIDLDATA pdata = _ILGetDataPointer(pidl);
2303 
2304     if (!pdata)
2305         return NULL;
2306 
2307     switch (pdata->type)
2308     {
2309     case PT_GUID:
2310     case PT_SHELLEXT:
2311     case PT_YAGUID:
2312         return NULL;
2313 
2314     case PT_DRIVE:
2315     case PT_DRIVE1:
2316     case PT_DRIVE2:
2317     case PT_DRIVE3:
2318         return pdata->u.drive.szDriveName;
2319 
2320     case PT_FOLDER:
2321     case PT_FOLDER1:
2322     case PT_VALUE:
2323     case PT_IESPECIAL1:
2324     case PT_IESPECIAL2:
2325         return pdata->u.file.szNames;
2326 
2327     case PT_WORKGRP:
2328     case PT_COMP:
2329     case PT_NETWORK:
2330     case PT_NETPROVIDER:
2331     case PT_SHARE:
2332         return pdata->u.network.szNames;
2333     }
2334     return NULL;
2335 }
2336 
2337 /**************************************************************************
2338  *  _ILGetSTextPointer()
2339  * gets a pointer to the short filename string stored in the pidl
2340  */
2341 static LPSTR _ILGetSTextPointer(LPCITEMIDLIST pidl)
2342 {
2343     /* TRACE(pidl,"(pidl%p)\n", pidl); */
2344 
2345     LPPIDLDATA pdata =_ILGetDataPointer(pidl);
2346 
2347     if (!pdata)
2348         return NULL;
2349 
2350     switch (pdata->type)
2351     {
2352     case PT_FOLDER:
2353     case PT_VALUE:
2354     case PT_IESPECIAL1:
2355     case PT_IESPECIAL2:
2356         return pdata->u.file.szNames + strlen (pdata->u.file.szNames) + 1;
2357 
2358     case PT_WORKGRP:
2359         return pdata->u.network.szNames + strlen (pdata->u.network.szNames) + 1;
2360     }
2361     return NULL;
2362 }
2363 
2364 /**************************************************************************
2365  * _ILGetGUIDPointer()
2366  *
2367  * returns reference to guid stored in some pidls
2368  */
2369 IID* _ILGetGUIDPointer(LPCITEMIDLIST pidl)
2370 {
2371     LPPIDLDATA pdata =_ILGetDataPointer(pidl);
2372 
2373     TRACE("%p\n", pidl);
2374 
2375     if (!pdata)
2376         return NULL;
2377 
2378     TRACE("pdata->type 0x%04x\n", pdata->type);
2379     switch (pdata->type)
2380     {
2381     case PT_SHELLEXT:
2382     case PT_GUID:
2383     case PT_YAGUID:
2384         return &(pdata->u.guid.guid);
2385 
2386     default:
2387         TRACE("Unknown pidl type 0x%04x\n", pdata->type);
2388         break;
2389     }
2390     return NULL;
2391 }
2392 
2393 /******************************************************************************
2394  * _ILGetFileStructW [Internal]
2395  *
2396  * Get pointer the a SHITEMID's FileStructW field if present
2397  *
2398  * PARAMS
2399  *  pidl [I] The SHITEMID
2400  *
2401  * RETURNS
2402  *  Success: Pointer to pidl's FileStructW field.
2403  *  Failure: NULL
2404  */
2405 FileStructW* _ILGetFileStructW(LPCITEMIDLIST pidl) {
2406     FileStructW *pFileStructW;
2407     WORD cbOffset;
2408 
2409     if (!(_ILIsValue(pidl) || _ILIsFolder(pidl)))
2410         return NULL;
2411 
2412     cbOffset = *(const WORD *)((const BYTE *)pidl + pidl->mkid.cb - sizeof(WORD));
2413     pFileStructW = (FileStructW*)((LPBYTE)pidl + cbOffset);
2414 
2415     /* Currently I don't see a fool prove way to figure out if a pidl is for sure of WinXP
2416      * style with a FileStructW member. If we switch all our shellfolder-implementations to
2417      * the new format, this won't be a problem. For now, we do as many sanity checks as possible. */
2418     if ((cbOffset & 0x1) || /* FileStructW member is word aligned in the pidl */
2419         /* FileStructW is positioned after FileStruct */
2420         cbOffset < sizeof(pidl->mkid.cb) + sizeof(PIDLTYPE) + sizeof(FileStruct) ||
2421         /* There has to be enough space at cbOffset in the pidl to hold FileStructW and cbOffset */
2422         cbOffset > pidl->mkid.cb - sizeof(cbOffset) - sizeof(FileStructW) ||
2423         pidl->mkid.cb != cbOffset + pFileStructW->cbLen)
2424     {
2425         WARN("Invalid pidl format (cbOffset = %d)!\n", cbOffset);
2426         return NULL;
2427     }
2428 
2429     return pFileStructW;
2430 }
2431 
2432 /*************************************************************************
2433  * _ILGetFileDateTime
2434  *
2435  * Given the ItemIdList, get the FileTime
2436  *
2437  * PARAMS
2438  *      pidl        [I] The ItemIDList
2439  *      pFt         [I] the resulted FILETIME of the file
2440  *
2441  * RETURNS
2442  *     True if Successful
2443  *
2444  * NOTES
2445  *
2446  */
2447 BOOL _ILGetFileDateTime(LPCITEMIDLIST pidl, FILETIME *pFt)
2448 {
2449     LPPIDLDATA pdata = _ILGetDataPointer(pidl);
2450 
2451     if (!pdata)
2452         return FALSE;
2453 
2454     switch (pdata->type)
2455     {
2456     case PT_FOLDER:
2457     case PT_VALUE:
2458         DosDateTimeToFileTime(pdata->u.file.uFileDate, pdata->u.file.uFileTime, pFt);
2459         break;
2460     default:
2461         return FALSE;
2462     }
2463     return TRUE;
2464 }
2465 
2466 BOOL _ILGetFileDate (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize)
2467 {
2468     FILETIME ft,lft;
2469     SYSTEMTIME time;
2470     BOOL ret;
2471 
2472     if (_ILGetFileDateTime( pidl, &ft ))
2473     {
2474         FileTimeToLocalFileTime(&ft, &lft);
2475         FileTimeToSystemTime (&lft, &time);
2476 
2477         ret = GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&time, NULL,  pOut, uOutSize);
2478         if (ret)
2479         {
2480             /* Append space + time without seconds */
2481             pOut[ret-1] = ' ';
2482             GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &time, NULL, &pOut[ret], uOutSize - ret);
2483         }
2484     }
2485     else
2486     {
2487         pOut[0] = '\0';
2488         ret = FALSE;
2489     }
2490     return ret;
2491 }
2492 
2493 /*************************************************************************
2494  * _ILGetFileSize
2495  *
2496  * Given the ItemIdList, get the FileSize
2497  *
2498  * PARAMS
2499  *    pidl     [I] The ItemIDList
2500  *    pOut     [I] The buffer to save the result
2501  *    uOutsize [I] The size of the buffer
2502  *
2503  * RETURNS
2504  *    The FileSize
2505  *
2506  * NOTES
2507  *    pOut can be null when no string is needed
2508  *
2509  */
2510 DWORD _ILGetFileSize (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize)
2511 {
2512     LPPIDLDATA pdata = _ILGetDataPointer(pidl);
2513     DWORD dwSize;
2514 
2515     if (!pdata)
2516         return 0;
2517 
2518     switch (pdata->type)
2519     {
2520     case PT_VALUE:
2521         dwSize = pdata->u.file.dwFileSize;
2522         if (pOut)
2523             StrFormatKBSizeA(dwSize, pOut, uOutSize);
2524         return dwSize;
2525     }
2526     if (pOut)
2527         *pOut = 0x00;
2528     return 0;
2529 }
2530 
2531 BOOL _ILGetExtension (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize)
2532 {
2533     char szTemp[MAX_PATH];
2534     const char * pPoint;
2535     LPCITEMIDLIST  pidlTemp=pidl;
2536 
2537     TRACE("pidl=%p\n",pidl);
2538 
2539     if (!pidl)
2540         return FALSE;
2541 
2542     pidlTemp = ILFindLastID(pidl);
2543 
2544     if (!_ILIsValue(pidlTemp))
2545         return FALSE;
2546     if (!_ILSimpleGetText(pidlTemp, szTemp, MAX_PATH))
2547         return FALSE;
2548 
2549     pPoint = PathFindExtensionA(szTemp);
2550 
2551     if (!*pPoint)
2552         return FALSE;
2553 
2554     pPoint++;
2555     lstrcpynA(pOut, pPoint, uOutSize);
2556     TRACE("%s\n",pOut);
2557 
2558     return TRUE;
2559 }
2560 
2561 /*************************************************************************
2562  * _ILGetFileType
2563  *
2564  * Given the ItemIdList, get the file type description
2565  *
2566  * PARAMS
2567  *      pidl        [I] The ItemIDList (simple)
2568  *      pOut        [I] The buffer to save the result
2569  *      uOutsize    [I] The size of the buffer
2570  *
2571  * RETURNS
2572  *    nothing
2573  *
2574  * NOTES
2575  *    This function copies as much as possible into the buffer.
2576  */
2577 void _ILGetFileType(LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize)
2578 {
2579 #ifdef __REACTOS__ /* r32966 */
2580     char sType[64];
2581 #endif
2582 
2583     if(_ILIsValue(pidl))
2584     {
2585         char sTemp[64];
2586 
2587         if(uOutSize > 0)
2588             pOut[0] = 0;
2589 #ifdef __REACTOS__ /* r32966 */
2590         if (_ILGetExtension (pidl, sType, 64))
2591         {
2592             if (HCR_MapTypeToValueA(sType, sTemp, 64, TRUE))
2593             {
2594                 /* retrieve description */
2595                 if(HCR_MapTypeToValueA(sTemp, pOut, uOutSize, FALSE ))
2596                     return;
2597             }
2598             /* display Ext-file as description */
2599             _strupr(sType);
2600             /* load localized file string */
2601             sTemp[0] = '\0';
2602             if(LoadStringA(shell32_hInstance, IDS_ANY_FILE, sTemp, 64))
2603             {
2604                 sTemp[63] = '\0';
2605                 StringCchPrintfA(pOut, uOutSize, sTemp, sType);
2606             }
2607         }
2608 #else
2609         if (_ILGetExtension (pidl, sTemp, 64))
2610         {
2611             if (!( HCR_MapTypeToValueA(sTemp, sTemp, 64, TRUE)
2612                 && HCR_MapTypeToValueA(sTemp, pOut, uOutSize, FALSE )))
2613             {
2614                 lstrcpynA (pOut, sTemp, uOutSize - 6);
2615                 strcat (pOut, "-file");
2616             }
2617         }
2618 #endif
2619     }
2620     else
2621 #ifdef __REACTOS__ /* r32966 */
2622     {
2623         pOut[0] = '\0';
2624         LoadStringA(shell32_hInstance, IDS_DIRECTORY, pOut, uOutSize);
2625         /* make sure its null terminated */
2626         pOut[uOutSize-1] = '\0';
2627     }
2628 #else
2629         lstrcpynA(pOut, "Folder", uOutSize);
2630 #endif
2631 }
2632 
2633 /*************************************************************************
2634  * _ILGetFileAttributes
2635  *
2636  * Given the ItemIdList, get the Attrib string format
2637  *
2638  * PARAMS
2639  *      pidl        [I] The ItemIDList
2640  *      pOut        [I] The buffer to save the result
2641  *      uOutsize    [I] The size of the Buffer
2642  *
2643  * RETURNS
2644  *     Attributes
2645  *
2646  * FIXME
2647  *  return value 0 in case of error is a valid return value
2648  *
2649  */
2650 DWORD _ILGetFileAttributes(LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize)
2651 {
2652     LPPIDLDATA pData = _ILGetDataPointer(pidl);
2653     WORD wAttrib = 0;
2654     int i;
2655 
2656     if (!pData)
2657         return 0;
2658 
2659     switch(pData->type)
2660     {
2661     case PT_FOLDER:
2662     case PT_VALUE:
2663         wAttrib = pData->u.file.uFileAttribs;
2664         break;
2665     }
2666 
2667     if(uOutSize >= 6)
2668     {
2669         i=0;
2670         if(wAttrib & FILE_ATTRIBUTE_READONLY)
2671             pOut[i++] = 'R';
2672         if(wAttrib & FILE_ATTRIBUTE_HIDDEN)
2673             pOut[i++] = 'H';
2674         if(wAttrib & FILE_ATTRIBUTE_SYSTEM)
2675             pOut[i++] = 'S';
2676         if(wAttrib & FILE_ATTRIBUTE_ARCHIVE)
2677             pOut[i++] = 'A';
2678         if(wAttrib & FILE_ATTRIBUTE_COMPRESSED)
2679             pOut[i++] = 'C';
2680         pOut[i] = 0x00;
2681     }
2682     return wAttrib;
2683 }
2684 
2685 /*************************************************************************
2686  * ILFreeaPidl
2687  *
2688  * frees an aPidl struct
2689  */
2690 void _ILFreeaPidl(LPITEMIDLIST * apidl, UINT cidl)
2691 {
2692     UINT   i;
2693 
2694     if (apidl)
2695     {
2696         for (i = 0; i < cidl; i++)
2697             SHFree(apidl[i]);
2698         SHFree(apidl);
2699     }
2700 }
2701 
2702 /*************************************************************************
2703  * ILCopyaPidl
2704  *
2705  * copies an aPidl struct
2706  */
2707 PITEMID_CHILD* _ILCopyaPidl(PCUITEMID_CHILD_ARRAY apidlsrc, UINT cidl)
2708 {
2709     UINT i;
2710     PITEMID_CHILD *apidldest;
2711 
2712     if (!apidlsrc)
2713         return NULL;
2714 
2715     apidldest = SHAlloc(cidl * sizeof(PITEMID_CHILD));
2716 
2717     for (i = 0; i < cidl; i++)
2718         apidldest[i] = ILClone(apidlsrc[i]);
2719 
2720     return apidldest;
2721 }
2722 
2723 /*************************************************************************
2724  * _ILCopyCidaToaPidl
2725  *
2726  * creates aPidl from CIDA
2727  */
2728 LPITEMIDLIST* _ILCopyCidaToaPidl(LPITEMIDLIST* pidl, const CIDA * cida)
2729 {
2730     UINT i;
2731     LPITEMIDLIST *dst;
2732 
2733     dst = SHAlloc(cida->cidl * sizeof(LPITEMIDLIST));
2734     if (!dst)
2735         return NULL;
2736 
2737     if (pidl)
2738         *pidl = ILClone((LPCITEMIDLIST)(&((const BYTE*)cida)[cida->aoffset[0]]));
2739 
2740     for (i = 0; i < cida->cidl; i++)
2741         dst[i] = ILClone((LPCITEMIDLIST)(&((const BYTE*)cida)[cida->aoffset[i + 1]]));
2742 
2743     return dst;
2744 }
2745