xref: /reactos/dll/win32/shell32/wine/pidl.c (revision 6ae11ba0)
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  */
ILGetDisplayNameExA(LPSHELLFOLDER psf,LPCITEMIDLIST pidl,LPSTR path,DWORD type)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 
ILGetDisplayNameExW(LPSHELLFOLDER psf,LPCITEMIDLIST pidl,LPWSTR path,DWORD type)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  */
ILGetDisplayNameEx(LPSHELLFOLDER psf,LPCITEMIDLIST pidl,LPVOID path,DWORD type)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  */
ILGetDisplayName(LPCITEMIDLIST pidl,LPVOID path)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  */
ILFindLastID(LPCITEMIDLIST pidl)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  */
ILRemoveLastID(LPITEMIDLIST pidl)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  */
ILClone(LPCITEMIDLIST pidl)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  */
ILCloneFirst(LPCITEMIDLIST pidl)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  */
ILLoadFromStream(IStream * pStream,LPITEMIDLIST * ppPidl)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  */
ILSaveToStream(IStream * pStream,LPCITEMIDLIST pPidl)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  */
SHILCreateFromPathA(LPCSTR path,LPITEMIDLIST * ppidl,DWORD * attributes)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 
SHILCreateFromPathW(LPCWSTR path,LPITEMIDLIST * ppidl,DWORD * attributes)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 
SHILCreateFromPathAW(LPCVOID path,LPITEMIDLIST * ppidl,DWORD * attributes)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  */
SHCloneSpecialIDList(HWND hwndOwner,int nFolder,BOOL fCreate)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  */
ILGlobalClone(LPCITEMIDLIST pidl)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 
_ILHACKCompareSimpleIds(LPCITEMIDLIST pidltemp1,LPCITEMIDLIST pidltemp2)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  */
ILIsEqual(LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2)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 #ifdef __REACTOS__
561     {
562         /* We don't understand the PIDL content but that does not mean it's invalid */
563     }
564 #else
565         return FALSE;
566 #endif
567 
568     pdump (pidl1);
569     pdump (pidl2);
570 
571     if (!pidl1 || !pidl2)
572         return FALSE;
573 
574     while (pidltemp1->mkid.cb && pidltemp2->mkid.cb)
575     {
576         if (!_ILHACKCompareSimpleIds(pidltemp1, pidltemp2))
577             return FALSE;
578 
579         pidltemp1 = ILGetNext(pidltemp1);
580         pidltemp2 = ILGetNext(pidltemp2);
581     }
582 
583     if (!pidltemp1->mkid.cb && !pidltemp2->mkid.cb)
584         return TRUE;
585 
586     return FALSE;
587 }
588 
589 /*************************************************************************
590  * ILIsParent                [SHELL32.23]
591  *
592  * Verifies that pidlParent is indeed the (immediate) parent of pidlChild.
593  *
594  * PARAMS
595  *  pidlParent [I]
596  *  pidlChild  [I]
597  *  bImmediate [I]   only return true if the parent is the direct parent
598  *                   of the child
599  *
600  * RETURNS
601  *  True if the parent ItemIDlist is a complete part of the child ItemIdList,
602  *  False otherwise.
603  *
604  * NOTES
605  *  parent = a/b, child = a/b/c -> true, c is in folder a/b
606  *  child = a/b/c/d -> false if bImmediate is true, d is not in folder a/b
607  *  child = a/b/c/d -> true if bImmediate is false, d is in a subfolder of a/b
608  *  child = a/b -> false if bImmediate is true
609  *  child = a/b -> true if bImmediate is false
610  */
ILIsParent(LPCITEMIDLIST pidlParent,LPCITEMIDLIST pidlChild,BOOL bImmediate)611 BOOL WINAPI ILIsParent(LPCITEMIDLIST pidlParent, LPCITEMIDLIST pidlChild, BOOL bImmediate)
612 {
613     LPCITEMIDLIST pParent = pidlParent;
614     LPCITEMIDLIST pChild = pidlChild;
615 
616     TRACE("%p %p %x\n", pidlParent, pidlChild, bImmediate);
617 
618     if (!pParent || !pChild)
619         return FALSE;
620 
621     while (pParent->mkid.cb && pChild->mkid.cb)
622     {
623         if (!_ILHACKCompareSimpleIds(pParent, pChild))
624             return FALSE;
625 
626         pParent = ILGetNext(pParent);
627         pChild = ILGetNext(pChild);
628     }
629 
630     /* child has shorter name than parent */
631     if (pParent->mkid.cb)
632         return FALSE;
633 
634     /* not immediate descent */
635     if ((!pChild->mkid.cb || ILGetNext(pChild)->mkid.cb) && bImmediate)
636         return FALSE;
637 
638     return TRUE;
639 }
640 
641 /*************************************************************************
642  * ILFindChild               [SHELL32.24]
643  *
644  *  Compares elements from pidl1 and pidl2.
645  *
646  * PARAMS
647  *  pidl1      [I]
648  *  pidl2      [I]
649  *
650  * RETURNS
651  *  pidl1 is desktop      pidl2
652  *  pidl1 shorter pidl2   pointer to first different element of pidl2
653  *                        if there was at least one equal element
654  *  pidl2 shorter pidl1   0
655  *  pidl2 equal pidl1     pointer to last 0x00-element of pidl2
656  *
657  * NOTES
658  *  exported by ordinal.
659  */
ILFindChild(PIDLIST_ABSOLUTE pidl1,PCIDLIST_ABSOLUTE pidl2)660 PUIDLIST_RELATIVE WINAPI ILFindChild(PIDLIST_ABSOLUTE pidl1, PCIDLIST_ABSOLUTE pidl2)
661 {
662     LPCITEMIDLIST pidltemp1 = pidl1;
663     LPCITEMIDLIST pidltemp2 = pidl2;
664     LPCITEMIDLIST ret=NULL;
665 
666     TRACE("pidl1=%p pidl2=%p\n",pidl1, pidl2);
667 
668     /* explorer reads from registry directly (StreamMRU),
669        so we can only check here */
670     if ((!pcheck (pidl1)) || (!pcheck (pidl2)))
671         return FALSE;
672 
673     pdump (pidl1);
674     pdump (pidl2);
675 
676     if (_ILIsDesktop(pidl1))
677     {
678         ret = pidl2;
679     }
680     else
681     {
682         while (pidltemp1->mkid.cb && pidltemp2->mkid.cb)
683         {
684             if (!_ILHACKCompareSimpleIds(pidltemp1, pidltemp2))
685                 return FALSE;
686 
687             pidltemp1 = ILGetNext(pidltemp1);
688             pidltemp2 = ILGetNext(pidltemp2);
689             ret = pidltemp2;
690         }
691 
692         if (pidltemp1->mkid.cb)
693             ret = NULL; /* elements of pidl1 left*/
694     }
695     TRACE_(shell)("--- %p\n", ret);
696     return (PUIDLIST_RELATIVE)ret; /* pidl 1 is shorter */
697 }
698 
699 /*************************************************************************
700  * ILCombine                 [SHELL32.25]
701  *
702  * Concatenates two complex ItemIDLists.
703  *
704  * PARAMS
705  *  pidl1      [I]   first complex ItemIDLists
706  *  pidl2      [I]   complex ItemIDLists to append
707  *
708  * RETURNS
709  *  if both pidl's == NULL      NULL
710  *  if pidl1 == NULL            cloned pidl2
711  *  if pidl2 == NULL            cloned pidl1
712  *  otherwise new pidl with pidl2 appended to pidl1
713  *
714  * NOTES
715  *  exported by ordinal.
716  *  Does not destroy the passed in ItemIDLists!
717  */
ILCombine(LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2)718 LPITEMIDLIST WINAPI ILCombine(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
719 {
720     DWORD    len1,len2;
721     LPITEMIDLIST  pidlNew;
722 
723     TRACE("pidl=%p pidl=%p\n",pidl1,pidl2);
724 
725     if (!pidl1 && !pidl2) return NULL;
726 
727     pdump (pidl1);
728     pdump (pidl2);
729 
730     if (!pidl1)
731     {
732         pidlNew = ILClone(pidl2);
733         return pidlNew;
734     }
735 
736     if (!pidl2)
737     {
738         pidlNew = ILClone(pidl1);
739         return pidlNew;
740     }
741 
742     len1  = ILGetSize(pidl1)-2;
743     len2  = ILGetSize(pidl2);
744     pidlNew  = SHAlloc(len1+len2);
745 
746     if (pidlNew)
747     {
748         memcpy(pidlNew,pidl1,len1);
749         memcpy(((BYTE *)pidlNew)+len1,pidl2,len2);
750     }
751 
752     /*  TRACE(pidl,"--new pidl=%p\n",pidlNew);*/
753     return pidlNew;
754 }
755 
756 #ifndef __REACTOS__ /* See ..\utils.cpp */
757 /*************************************************************************
758  *  SHGetRealIDL [SHELL32.98]
759  *
760  * NOTES
761  */
SHGetRealIDL(LPSHELLFOLDER lpsf,LPCITEMIDLIST pidlSimple,LPITEMIDLIST * pidlReal)762 HRESULT WINAPI SHGetRealIDL(LPSHELLFOLDER lpsf, LPCITEMIDLIST pidlSimple, LPITEMIDLIST *pidlReal)
763 {
764     IDataObject* pDataObj;
765     HRESULT hr;
766 
767     hr = IShellFolder_GetUIObjectOf(lpsf, 0, 1, &pidlSimple,
768                              &IID_IDataObject, 0, (LPVOID*)&pDataObj);
769     if (SUCCEEDED(hr))
770     {
771         STGMEDIUM medium;
772         FORMATETC fmt;
773 
774         fmt.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
775         fmt.ptd = NULL;
776         fmt.dwAspect = DVASPECT_CONTENT;
777         fmt.lindex = -1;
778         fmt.tymed = TYMED_HGLOBAL;
779 
780         hr = IDataObject_GetData(pDataObj, &fmt, &medium);
781 
782         IDataObject_Release(pDataObj);
783 
784         if (SUCCEEDED(hr))
785         {
786             /*assert(pida->cidl==1);*/
787             LPIDA pida = GlobalLock(medium.u.hGlobal);
788 
789             LPCITEMIDLIST pidl_folder = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[0]);
790             LPCITEMIDLIST pidl_child = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[1]);
791 
792             *pidlReal = ILCombine(pidl_folder, pidl_child);
793 
794             if (!*pidlReal)
795                 hr = E_OUTOFMEMORY;
796 
797             GlobalUnlock(medium.u.hGlobal);
798             GlobalFree(medium.u.hGlobal);
799         }
800     }
801 
802     return hr;
803 }
804 #endif
805 
806 /*************************************************************************
807  *  SHLogILFromFSIL [SHELL32.95]
808  *
809  * NOTES
810  *  pild = CSIDL_DESKTOP    ret = 0
811  *  pild = CSIDL_DRIVES     ret = 0
812  */
SHLogILFromFSIL(LPITEMIDLIST pidl)813 LPITEMIDLIST WINAPI SHLogILFromFSIL(LPITEMIDLIST pidl)
814 {
815     FIXME("(pidl=%p)\n",pidl);
816 
817     pdump(pidl);
818 
819     return 0;
820 }
821 
822 /*************************************************************************
823  * ILGetSize                 [SHELL32.152]
824  *
825  * Gets the byte size of an ItemIDList including zero terminator
826  *
827  * PARAMS
828  *  pidl       [I]   ItemIDList
829  *
830  * RETURNS
831  *  size of pidl in bytes
832  *
833  * NOTES
834  *  exported by ordinal
835  */
ILGetSize(LPCITEMIDLIST pidl)836 UINT WINAPI ILGetSize(LPCITEMIDLIST pidl)
837 {
838     LPCSHITEMID si;
839     UINT len=0;
840 
841     if (pidl)
842     {
843         si = &(pidl->mkid);
844 
845         while (si->cb)
846         {
847             len += si->cb;
848             si  = (LPCSHITEMID)(((const BYTE*)si)+si->cb);
849         }
850         len += 2;
851     }
852     TRACE("pidl=%p size=%u\n",pidl, len);
853     return len;
854 }
855 
856 /*************************************************************************
857  * ILGetNext                 [SHELL32.153]
858  *
859  * Gets the next ItemID of an ItemIDList
860  *
861  * PARAMS
862  *  pidl       [I]   ItemIDList
863  *
864  * RETURNS
865  *  null -> null
866  *  desktop -> null
867  *  simple pidl -> pointer to 0x0000 element
868  *
869  * NOTES
870  *  exported by ordinal.
871  */
ILGetNext(LPCITEMIDLIST pidl)872 LPITEMIDLIST WINAPI ILGetNext(LPCITEMIDLIST pidl)
873 {
874     WORD len;
875 
876     TRACE("%p\n", pidl);
877 
878     if (pidl)
879     {
880         len =  pidl->mkid.cb;
881         if (len)
882         {
883             pidl = (LPCITEMIDLIST) (((const BYTE*)pidl)+len);
884             TRACE("-- %p\n", pidl);
885             return (LPITEMIDLIST)pidl;
886         }
887     }
888     return NULL;
889 }
890 
891 /*************************************************************************
892  * ILAppendID                [SHELL32.154]
893  *
894  * Adds the single ItemID item to the ItemIDList indicated by pidl.
895  * If bEnd is FALSE, inserts the item in the front of the list,
896  * otherwise it adds the item to the end. (???)
897  *
898  * PARAMS
899  *  pidl       [I]   ItemIDList to extend
900  *  item       [I]   ItemID to prepend/append
901  *  bEnd       [I]   Indicates if the item should be appended
902  *
903  * NOTES
904  *  Destroys the passed in idlist! (???)
905  */
ILAppendID(LPITEMIDLIST pidl,LPCSHITEMID item,BOOL bEnd)906 LPITEMIDLIST WINAPI ILAppendID(LPITEMIDLIST pidl, LPCSHITEMID item, BOOL bEnd)
907 {
908     LPITEMIDLIST idlRet;
909     LPCITEMIDLIST itemid = (LPCITEMIDLIST)item;
910 
911     WARN("(pidl=%p,pidl=%p,%08u)semi-stub\n",pidl,item,bEnd);
912 
913     pdump (pidl);
914     pdump (itemid);
915 
916     if (_ILIsDesktop(pidl))
917     {
918         idlRet = ILClone(itemid);
919         SHFree (pidl);
920         return idlRet;
921     }
922 
923     if (bEnd)
924         idlRet = ILCombine(pidl, itemid);
925     else
926         idlRet = ILCombine(itemid, pidl);
927 
928     SHFree(pidl);
929     return idlRet;
930 }
931 
932 /*************************************************************************
933  * ILFree                    [SHELL32.155]
934  *
935  * Frees memory (if not NULL) allocated by SHMalloc allocator
936  *
937  * PARAMS
938  *  pidl         [I]
939  *
940  * RETURNS
941  *  Nothing
942  *
943  * NOTES
944  *  exported by ordinal
945  */
ILFree(LPITEMIDLIST pidl)946 void WINAPI ILFree(LPITEMIDLIST pidl)
947 {
948     TRACE("(pidl=%p)\n",pidl);
949     SHFree(pidl);
950 }
951 
952 /*************************************************************************
953  * ILGlobalFree              [SHELL32.156]
954  *
955  * Frees memory (if not NULL) allocated by Alloc allocator
956  *
957  * PARAMS
958  *  pidl         [I]
959  *
960  * RETURNS
961  *  Nothing
962  *
963  * NOTES
964  *  exported by ordinal.
965  */
ILGlobalFree(LPITEMIDLIST pidl)966 void WINAPI ILGlobalFree( LPITEMIDLIST pidl)
967 {
968     TRACE("%p\n", pidl);
969 
970     Free(pidl);
971 }
972 
973 /*************************************************************************
974  * ILCreateFromPathA         [SHELL32.189]
975  *
976  * Creates a complex ItemIDList from a path and returns it.
977  *
978  * PARAMS
979  *  path         [I]
980  *
981  * RETURNS
982  *  the newly created complex ItemIDList or NULL if failed
983  *
984  * NOTES
985  *  exported by ordinal.
986  */
ILCreateFromPathA(LPCSTR path)987 LPITEMIDLIST WINAPI ILCreateFromPathA (LPCSTR path)
988 {
989     LPITEMIDLIST pidlnew = NULL;
990 
991     TRACE_(shell)("%s\n", debugstr_a(path));
992 
993     if (SUCCEEDED(SHILCreateFromPathA(path, &pidlnew, NULL)))
994         return pidlnew;
995     return NULL;
996 }
997 
998 /*************************************************************************
999  * ILCreateFromPathW         [SHELL32.190]
1000  *
1001  * See ILCreateFromPathA.
1002  */
ILCreateFromPathW(LPCWSTR path)1003 LPITEMIDLIST WINAPI ILCreateFromPathW (LPCWSTR path)
1004 {
1005     LPITEMIDLIST pidlnew = NULL;
1006 
1007     TRACE_(shell)("%s\n", debugstr_w(path));
1008 
1009     if (SUCCEEDED(SHILCreateFromPathW(path, &pidlnew, NULL)))
1010         return pidlnew;
1011     return NULL;
1012 }
1013 
1014 /*************************************************************************
1015  * ILCreateFromPath          [SHELL32.157]
1016  */
ILCreateFromPathAW(LPCVOID path)1017 LPITEMIDLIST WINAPI ILCreateFromPathAW (LPCVOID path)
1018 {
1019     if ( SHELL_OsIsUnicode())
1020         return ILCreateFromPathW (path);
1021     return ILCreateFromPathA (path);
1022 }
1023 
1024 /*************************************************************************
1025  * _ILParsePathW             [internal]
1026  *
1027  * Creates an ItemIDList from a path and returns it.
1028  *
1029  * PARAMS
1030  *  path         [I]   path to parse and convert into an ItemIDList
1031  *  lpFindFile   [I]   pointer to buffer to initialize the FileSystem
1032  *                     Bind Data object with
1033  *  bBindCtx     [I]   indicates to create a BindContext and assign a
1034  *                     FileSystem Bind Data object
1035  *  ppidl        [O]   the newly create ItemIDList
1036  *  prgfInOut    [I/O] requested attributes on input and actual
1037  *                     attributes on return
1038  *
1039  * RETURNS
1040  *  NO_ERROR on success or an OLE error code
1041  *
1042  * NOTES
1043  *  If either lpFindFile is non-NULL or bBindCtx is TRUE, this function
1044  *  creates a BindContext object and assigns a FileSystem Bind Data object
1045  *  to it, passing the BindContext to IShellFolder_ParseDisplayName. Each
1046  *  IShellFolder uses that FileSystem Bind Data object of the BindContext
1047  *  to pass data about the current path element to the next object. This
1048  *  is used to avoid having to verify the current path element on disk, so
1049  *  that creating an ItemIDList from a nonexistent path still can work.
1050  */
_ILParsePathW(LPCWSTR path,LPWIN32_FIND_DATAW lpFindFile,BOOL bBindCtx,LPITEMIDLIST * ppidl,LPDWORD prgfInOut)1051 static HRESULT _ILParsePathW(LPCWSTR path, LPWIN32_FIND_DATAW lpFindFile,
1052                              BOOL bBindCtx, LPITEMIDLIST *ppidl, LPDWORD prgfInOut)
1053 {
1054     LPSHELLFOLDER pSF = NULL;
1055     LPBC pBC = NULL;
1056     HRESULT ret;
1057 
1058     TRACE("%s %p %d (%p)->%p (%p)->0x%x\n", debugstr_w(path), lpFindFile, bBindCtx,
1059                                              ppidl, ppidl ? *ppidl : NULL,
1060                                              prgfInOut, prgfInOut ? *prgfInOut : 0);
1061 
1062     ret = SHGetDesktopFolder(&pSF);
1063     if (FAILED(ret))
1064         return ret;
1065 
1066     if (lpFindFile || bBindCtx)
1067         ret = IFileSystemBindData_Constructor(lpFindFile, &pBC);
1068 
1069     if (SUCCEEDED(ret))
1070     {
1071         ret = IShellFolder_ParseDisplayName(pSF, 0, pBC, (LPOLESTR)path, NULL, ppidl, prgfInOut);
1072     }
1073 
1074     if (pBC)
1075     {
1076         IBindCtx_Release(pBC);
1077         pBC = NULL;
1078     }
1079 
1080     IShellFolder_Release(pSF);
1081 
1082     if (FAILED(ret) && ppidl)
1083         *ppidl = NULL;
1084 
1085     TRACE("%s %p 0x%x\n", debugstr_w(path), ppidl ? *ppidl : NULL, prgfInOut ? *prgfInOut : 0);
1086 
1087     return ret;
1088 }
1089 
1090 /*************************************************************************
1091  * SHSimpleIDListFromPath    [SHELL32.162]
1092  *
1093  * Creates a simple ItemIDList from a path and returns it. This function
1094  * does not fail on nonexistent paths.
1095  *
1096  * PARAMS
1097  *  path         [I]   path to parse and convert into an ItemIDList
1098  *
1099  * RETURNS
1100  *  the newly created simple ItemIDList
1101  *
1102  * NOTES
1103  *  Simple in the name does not mean a relative ItemIDList but rather a
1104  *  fully qualified list, where only the file name is filled in and the
1105  *  directory flag for those ItemID elements this is known about, eg.
1106  *  it is not the last element in the ItemIDList or the actual directory
1107  *  exists on disk.
1108  *  exported by ordinal.
1109  */
SHSimpleIDListFromPathA(LPCSTR lpszPath)1110 LPITEMIDLIST WINAPI SHSimpleIDListFromPathA(LPCSTR lpszPath)
1111 {
1112     LPITEMIDLIST pidl = NULL;
1113     LPWSTR wPath = NULL;
1114     int len;
1115 
1116     TRACE("%s\n", debugstr_a(lpszPath));
1117 
1118     if (lpszPath)
1119     {
1120         len = MultiByteToWideChar(CP_ACP, 0, lpszPath, -1, NULL, 0);
1121         wPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1122         MultiByteToWideChar(CP_ACP, 0, lpszPath, -1, wPath, len);
1123     }
1124 
1125     _ILParsePathW(wPath, NULL, TRUE, &pidl, NULL);
1126 
1127     HeapFree(GetProcessHeap(), 0, wPath);
1128     TRACE("%s %p\n", debugstr_a(lpszPath), pidl);
1129     return pidl;
1130 }
1131 
SHSimpleIDListFromPathW(LPCWSTR lpszPath)1132 LPITEMIDLIST WINAPI SHSimpleIDListFromPathW(LPCWSTR lpszPath)
1133 {
1134     LPITEMIDLIST pidl = NULL;
1135 
1136     TRACE("%s\n", debugstr_w(lpszPath));
1137 
1138     _ILParsePathW(lpszPath, NULL, TRUE, &pidl, NULL);
1139 
1140     TRACE("%s %p\n", debugstr_w(lpszPath), pidl);
1141     return pidl;
1142 }
1143 
SHSimpleIDListFromPathAW(LPCVOID lpszPath)1144 LPITEMIDLIST WINAPI SHSimpleIDListFromPathAW(LPCVOID lpszPath)
1145 {
1146     if ( SHELL_OsIsUnicode())
1147         return SHSimpleIDListFromPathW (lpszPath);
1148     return SHSimpleIDListFromPathA (lpszPath);
1149 }
1150 
1151 /*************************************************************************
1152  * SHGetDataFromIDListA [SHELL32.247]
1153  *
1154  * NOTES
1155  *  the pidl can be a simple one. since we can't get the path out of the pidl
1156  *  we have to take all data from the pidl
1157  */
SHGetDataFromIDListA(LPSHELLFOLDER psf,LPCITEMIDLIST pidl,int nFormat,LPVOID dest,int len)1158 HRESULT WINAPI SHGetDataFromIDListA(LPSHELLFOLDER psf, LPCITEMIDLIST pidl,
1159                                     int nFormat, LPVOID dest, int len)
1160 {
1161     LPSTR filename, shortname;
1162     WIN32_FIND_DATAA * pfd;
1163 
1164     TRACE_(shell)("sf=%p pidl=%p 0x%04x %p 0x%04x stub\n",psf,pidl,nFormat,dest,len);
1165 
1166     pdump(pidl);
1167     if (!psf || !dest)
1168         return E_INVALIDARG;
1169 
1170     switch (nFormat)
1171     {
1172     case SHGDFIL_FINDDATA:
1173         pfd = dest;
1174 
1175         if (_ILIsDrive(pidl) || _ILIsSpecialFolder(pidl))
1176             return E_INVALIDARG;
1177 
1178         if (len < sizeof(WIN32_FIND_DATAA))
1179             return E_INVALIDARG;
1180 
1181         ZeroMemory(pfd, sizeof (WIN32_FIND_DATAA));
1182         _ILGetFileDateTime( pidl, &(pfd->ftLastWriteTime));
1183         pfd->dwFileAttributes = _ILGetFileAttributes(pidl, NULL, 0);
1184         pfd->nFileSizeLow = _ILGetFileSize ( pidl, NULL, 0);
1185 
1186         filename = _ILGetTextPointer(pidl);
1187         shortname = _ILGetSTextPointer(pidl);
1188 
1189         if (filename)
1190             lstrcpynA(pfd->cFileName, filename, sizeof(pfd->cFileName));
1191         else
1192             pfd->cFileName[0] = '\0';
1193 
1194         if (shortname)
1195             lstrcpynA(pfd->cAlternateFileName, shortname, sizeof(pfd->cAlternateFileName));
1196         else
1197             pfd->cAlternateFileName[0] = '\0';
1198         return S_OK;
1199 
1200     case SHGDFIL_NETRESOURCE:
1201     case SHGDFIL_DESCRIPTIONID:
1202         FIXME_(shell)("SHGDFIL %i stub\n", nFormat);
1203         break;
1204 
1205     default:
1206         ERR_(shell)("Unknown SHGDFIL %i, please report\n", nFormat);
1207     }
1208 
1209     return E_INVALIDARG;
1210 }
1211 
1212 /*************************************************************************
1213  * SHGetDataFromIDListW [SHELL32.248]
1214  *
1215  */
SHGetDataFromIDListW(LPSHELLFOLDER psf,LPCITEMIDLIST pidl,int nFormat,LPVOID dest,int len)1216 HRESULT WINAPI SHGetDataFromIDListW(LPSHELLFOLDER psf, LPCITEMIDLIST pidl,
1217                                     int nFormat, LPVOID dest, int len)
1218 {
1219     LPSTR filename, shortname;
1220     WIN32_FIND_DATAW * pfd = dest;
1221 
1222     TRACE_(shell)("sf=%p pidl=%p 0x%04x %p 0x%04x stub\n",psf,pidl,nFormat,dest,len);
1223 
1224     pdump(pidl);
1225 
1226     if (!psf || !dest)
1227         return E_INVALIDARG;
1228 
1229     switch (nFormat)
1230     {
1231     case SHGDFIL_FINDDATA:
1232         pfd = dest;
1233 
1234         if (_ILIsDrive(pidl))
1235             return E_INVALIDARG;
1236 
1237         if (len < sizeof(WIN32_FIND_DATAW))
1238             return E_INVALIDARG;
1239 
1240         ZeroMemory(pfd, sizeof (WIN32_FIND_DATAW));
1241         _ILGetFileDateTime( pidl, &(pfd->ftLastWriteTime));
1242         pfd->dwFileAttributes = _ILGetFileAttributes(pidl, NULL, 0);
1243         pfd->nFileSizeLow = _ILGetFileSize ( pidl, NULL, 0);
1244 
1245         filename = _ILGetTextPointer(pidl);
1246         shortname = _ILGetSTextPointer(pidl);
1247 
1248         if (!filename)
1249             pfd->cFileName[0] = '\0';
1250         else if (!MultiByteToWideChar(CP_ACP, 0, filename, -1, pfd->cFileName, MAX_PATH))
1251             pfd->cFileName[MAX_PATH-1] = 0;
1252 
1253         if (!shortname)
1254             pfd->cAlternateFileName[0] = '\0';
1255         else if (!MultiByteToWideChar(CP_ACP, 0, shortname, -1, pfd->cAlternateFileName, 14))
1256             pfd->cAlternateFileName[13] = 0;
1257         return S_OK;
1258 
1259     case SHGDFIL_NETRESOURCE:
1260     case SHGDFIL_DESCRIPTIONID:
1261         FIXME_(shell)("SHGDFIL %i stub\n", nFormat);
1262         break;
1263 
1264     default:
1265         ERR_(shell)("Unknown SHGDFIL %i, please report\n", nFormat);
1266     }
1267 
1268     return E_INVALIDARG;
1269 }
1270 
1271 /*************************************************************************
1272  * SHGetPathFromIDListA        [SHELL32.@][NT 4.0: SHELL32.220]
1273  *
1274  * PARAMETERS
1275  *  pidl,   [IN] pidl
1276  *  pszPath [OUT] path
1277  *
1278  * RETURNS
1279  *  path from a passed PIDL.
1280  *
1281  * NOTES
1282  *    NULL returns FALSE
1283  *    desktop pidl gives path to desktop directory back
1284  *    special pidls returning FALSE
1285  */
SHGetPathFromIDListA(LPCITEMIDLIST pidl,LPSTR pszPath)1286 BOOL WINAPI SHGetPathFromIDListA(LPCITEMIDLIST pidl, LPSTR pszPath)
1287 {
1288     WCHAR wszPath[MAX_PATH];
1289     BOOL bSuccess;
1290 
1291     bSuccess = SHGetPathFromIDListW(pidl, wszPath);
1292     WideCharToMultiByte(CP_ACP, 0, wszPath, -1, pszPath, MAX_PATH, NULL, NULL);
1293 
1294     return bSuccess;
1295 }
1296 
1297 /*************************************************************************
1298  * SHGetPathFromIDListW             [SHELL32.@]
1299  *
1300  * See SHGetPathFromIDListA.
1301  */
1302 HRESULT WINAPI
SHGetPathCchFromIDListW(_In_ LPCITEMIDLIST pidl,_Out_writes_ (cchPathMax)LPWSTR pszPath,_In_ SIZE_T cchPathMax)1303 SHGetPathCchFromIDListW(
1304     _In_ LPCITEMIDLIST pidl,
1305     _Out_writes_(cchPathMax) LPWSTR pszPath,
1306     _In_ SIZE_T cchPathMax)
1307 {
1308     HRESULT hr;
1309     LPCITEMIDLIST pidlLast;
1310     LPSHELLFOLDER psfFolder;
1311     DWORD dwAttributes;
1312     STRRET strret;
1313 
1314     TRACE_(shell)("(pidl=%p,%p)\n", pidl, pszPath);
1315     pdump(pidl);
1316 
1317     *pszPath = UNICODE_NULL;
1318     if (!pidl)
1319         return E_FAIL;
1320 
1321     hr = SHBindToParent(pidl, &IID_IShellFolder, (VOID**)&psfFolder, &pidlLast);
1322     if (FAILED(hr))
1323     {
1324         ERR("SHBindToParent failed: %x\n", hr);
1325         return hr;
1326     }
1327 
1328     dwAttributes = SFGAO_FILESYSTEM;
1329     hr = IShellFolder_GetAttributesOf(psfFolder, 1, &pidlLast, &dwAttributes);
1330     if (FAILED(hr) || !(dwAttributes & SFGAO_FILESYSTEM))
1331     {
1332         WARN("Wrong dwAttributes or GetAttributesOf failed: %x\n", hr);
1333         IShellFolder_Release(psfFolder);
1334         return E_FAIL;
1335     }
1336 
1337     hr = IShellFolder_GetDisplayNameOf(psfFolder, pidlLast, SHGDN_FORPARSING, &strret);
1338     IShellFolder_Release(psfFolder);
1339     if (FAILED(hr))
1340         return hr;
1341 
1342     hr = StrRetToBufW(&strret, pidlLast, pszPath, cchPathMax);
1343 
1344     TRACE_(shell)("-- %s, 0x%08x\n",debugstr_w(pszPath), hr);
1345     return hr;
1346 }
1347 
SHGetPathFromIDListW(LPCITEMIDLIST pidl,LPWSTR pszPath)1348 BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath)
1349 {
1350     return SUCCEEDED(SHGetPathCchFromIDListW(pidl, pszPath, MAX_PATH));
1351 }
1352 
1353 /*************************************************************************
1354  *    SHBindToParent        [shell version 5.0]
1355  */
SHBindToParent(LPCITEMIDLIST pidl,REFIID riid,LPVOID * ppv,LPCITEMIDLIST * ppidlLast)1356 HRESULT WINAPI SHBindToParent(LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppv, LPCITEMIDLIST *ppidlLast)
1357 {
1358     IShellFolder    * psfDesktop;
1359     HRESULT         hr=E_FAIL;
1360 
1361     TRACE_(shell)("pidl=%p\n", pidl);
1362     pdump(pidl);
1363 
1364     if (!pidl || !ppv)
1365         return E_INVALIDARG;
1366 
1367     *ppv = NULL;
1368     if (ppidlLast)
1369         *ppidlLast = NULL;
1370 
1371     hr = SHGetDesktopFolder(&psfDesktop);
1372     if (FAILED(hr))
1373         return hr;
1374 
1375     if (_ILIsPidlSimple(pidl))
1376     {
1377         /* we are on desktop level */
1378         hr = IShellFolder_QueryInterface(psfDesktop, riid, ppv);
1379     }
1380     else
1381     {
1382         LPITEMIDLIST pidlParent = ILClone(pidl);
1383         ILRemoveLastID(pidlParent);
1384         hr = IShellFolder_BindToObject(psfDesktop, pidlParent, NULL, riid, ppv);
1385         SHFree (pidlParent);
1386     }
1387 
1388     IShellFolder_Release(psfDesktop);
1389 
1390     if (SUCCEEDED(hr) && ppidlLast)
1391         *ppidlLast = ILFindLastID(pidl);
1392 
1393     TRACE_(shell)("-- psf=%p pidl=%p ret=0x%08x\n", *ppv, (ppidlLast)?*ppidlLast:NULL, hr);
1394     return hr;
1395 }
1396 
1397 /*************************************************************************
1398  *    SHParseDisplayName        [shell version 6.0]
1399  */
SHParseDisplayName(LPCWSTR pszName,IBindCtx * pbc,LPITEMIDLIST * ppidl,SFGAOF sfgaoIn,SFGAOF * psfgaoOut)1400 HRESULT WINAPI SHParseDisplayName(LPCWSTR pszName, IBindCtx *pbc,
1401     LPITEMIDLIST *ppidl, SFGAOF sfgaoIn, SFGAOF *psfgaoOut)
1402 {
1403     HRESULT hr;
1404     LPWSTR pszNameDup;
1405     IShellFolder *psfDesktop;
1406     IBindCtx *pBindCtx = NULL;
1407 
1408     TRACE("(%s, %p, %p, 0x%X, %p)\n", pszName, pbc, ppidl, sfgaoIn, psfgaoOut);
1409 
1410     *ppidl = NULL;
1411 
1412     if (psfgaoOut)
1413         *psfgaoOut = 0;
1414 
1415     pszNameDup = StrDupW(pszName);
1416     if (!pszNameDup)
1417         return E_OUTOFMEMORY;
1418 
1419     psfDesktop = NULL;
1420     hr = SHGetDesktopFolder(&psfDesktop);
1421     if (FAILED(hr))
1422     {
1423         LocalFree(pszNameDup);
1424         return hr;
1425     }
1426 
1427     if (!pbc)
1428     {
1429         hr = BindCtx_RegisterObjectParam(NULL, STR_PARSE_TRANSLATE_ALIASES, NULL, &pBindCtx);
1430         pbc = pBindCtx;
1431     }
1432 
1433     if (SUCCEEDED(hr))
1434     {
1435         ULONG sfgao = sfgaoIn, cchEaten;
1436         HWND hwndUI = BindCtx_GetUIWindow(pbc);
1437         hr = psfDesktop->lpVtbl->ParseDisplayName(psfDesktop,
1438                                                   hwndUI,
1439                                                   pbc,
1440                                                   pszNameDup,
1441                                                   &cchEaten,
1442                                                   ppidl,
1443                                                   (psfgaoOut ? &sfgao : NULL));
1444         if (SUCCEEDED(hr) && psfgaoOut)
1445             *psfgaoOut = (sfgao & sfgaoIn);
1446     }
1447 
1448     LocalFree(pszNameDup);
1449 
1450     if (psfDesktop)
1451         psfDesktop->lpVtbl->Release(psfDesktop);
1452 
1453     if (pBindCtx)
1454         pBindCtx->lpVtbl->Release(pBindCtx);
1455 
1456     return hr;
1457 }
1458 
1459 /*************************************************************************
1460  * SHGetNameFromIDList             [SHELL32.@]
1461  */
SHGetNameFromIDList(PCIDLIST_ABSOLUTE pidl,SIGDN sigdnName,PWSTR * ppszName)1462 HRESULT WINAPI SHGetNameFromIDList(PCIDLIST_ABSOLUTE pidl, SIGDN sigdnName, PWSTR *ppszName)
1463 {
1464     IShellFolder *psfparent;
1465     LPCITEMIDLIST child_pidl;
1466     STRRET disp_name;
1467     HRESULT ret;
1468 
1469     TRACE("%p 0x%08x %p\n", pidl, sigdnName, ppszName);
1470 
1471     *ppszName = NULL;
1472     ret = SHBindToParent(pidl, &IID_IShellFolder, (void**)&psfparent, &child_pidl);
1473     if(SUCCEEDED(ret))
1474     {
1475         switch(sigdnName)
1476         {
1477                                                 /* sigdnName & 0xffff */
1478         case SIGDN_NORMALDISPLAY:               /* SHGDN_NORMAL */
1479         case SIGDN_PARENTRELATIVEPARSING:       /* SHGDN_INFOLDER | SHGDN_FORPARSING */
1480         case SIGDN_PARENTRELATIVEEDITING:       /* SHGDN_INFOLDER | SHGDN_FOREDITING */
1481         case SIGDN_DESKTOPABSOLUTEPARSING:      /* SHGDN_FORPARSING */
1482         case SIGDN_DESKTOPABSOLUTEEDITING:      /* SHGDN_FOREDITING | SHGDN_FORADDRESSBAR*/
1483         case SIGDN_PARENTRELATIVEFORADDRESSBAR: /* SIGDN_INFOLDER | SHGDN_FORADDRESSBAR */
1484         case SIGDN_PARENTRELATIVE:              /* SIGDN_INFOLDER */
1485 
1486             disp_name.uType = STRRET_WSTR;
1487             ret = IShellFolder_GetDisplayNameOf(psfparent, child_pidl,
1488                                                 sigdnName & 0xffff,
1489                                                 &disp_name);
1490             if(SUCCEEDED(ret))
1491                 ret = StrRetToStrW(&disp_name, pidl, ppszName);
1492 
1493             break;
1494 
1495         case SIGDN_FILESYSPATH:
1496             *ppszName = CoTaskMemAlloc(sizeof(WCHAR)*MAX_PATH);
1497             if(SHGetPathFromIDListW(pidl, *ppszName))
1498             {
1499                 TRACE("Got string %s\n", debugstr_w(*ppszName));
1500                 ret = S_OK;
1501             }
1502             else
1503             {
1504                 CoTaskMemFree(*ppszName);
1505                 ret = E_INVALIDARG;
1506             }
1507             break;
1508 
1509         case SIGDN_URL:
1510         default:
1511             FIXME("Unsupported SIGDN %x\n", sigdnName);
1512             ret = E_FAIL;
1513         }
1514 
1515         IShellFolder_Release(psfparent);
1516     }
1517     return ret;
1518 }
1519 
1520 #ifndef __REACTOS__
1521 
1522 /*************************************************************************
1523  * SHGetIDListFromObject             [SHELL32.@]
1524  */
SHGetIDListFromObject(IUnknown * punk,PIDLIST_ABSOLUTE * ppidl)1525 HRESULT WINAPI SHGetIDListFromObject(IUnknown *punk, PIDLIST_ABSOLUTE *ppidl)
1526 {
1527     IPersistIDList *ppersidl;
1528     IPersistFolder2 *ppf2;
1529     IDataObject *pdo;
1530     IFolderView *pfv;
1531     HRESULT ret;
1532 
1533     if(!punk)
1534         return E_NOINTERFACE;
1535 
1536     *ppidl = NULL;
1537 
1538     /* Try IPersistIDList */
1539     ret = IUnknown_QueryInterface(punk, &IID_IPersistIDList, (void**)&ppersidl);
1540     if(SUCCEEDED(ret))
1541     {
1542         TRACE("IPersistIDList (%p)\n", ppersidl);
1543         ret = IPersistIDList_GetIDList(ppersidl, ppidl);
1544         IPersistIDList_Release(ppersidl);
1545         if(SUCCEEDED(ret))
1546             return ret;
1547     }
1548 
1549     /* Try IPersistFolder2 */
1550     ret = IUnknown_QueryInterface(punk, &IID_IPersistFolder2, (void**)&ppf2);
1551     if(SUCCEEDED(ret))
1552     {
1553         TRACE("IPersistFolder2 (%p)\n", ppf2);
1554         ret = IPersistFolder2_GetCurFolder(ppf2, ppidl);
1555         IPersistFolder2_Release(ppf2);
1556         if(SUCCEEDED(ret))
1557             return ret;
1558     }
1559 
1560     /* Try IDataObject */
1561     ret = IUnknown_QueryInterface(punk, &IID_IDataObject, (void**)&pdo);
1562     if(SUCCEEDED(ret))
1563     {
1564         IShellItem *psi;
1565         TRACE("IDataObject (%p)\n", pdo);
1566         ret = SHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE,
1567                                       &IID_IShellItem, (void**)&psi);
1568         if(SUCCEEDED(ret))
1569         {
1570             ret = SHGetIDListFromObject((IUnknown*)psi, ppidl);
1571             IShellItem_Release(psi);
1572         }
1573         IDataObject_Release(pdo);
1574 
1575         if(SUCCEEDED(ret))
1576             return ret;
1577     }
1578 
1579     /* Try IFolderView */
1580     ret = IUnknown_QueryInterface(punk, &IID_IFolderView, (void**)&pfv);
1581     if(SUCCEEDED(ret))
1582     {
1583         IShellFolder *psf;
1584         TRACE("IFolderView (%p)\n", pfv);
1585         ret = IFolderView_GetFolder(pfv, &IID_IShellFolder, (void**)&psf);
1586         if(SUCCEEDED(ret))
1587         {
1588             /* We might be able to get IPersistFolder2 from a shellfolder. */
1589             ret = SHGetIDListFromObject((IUnknown*)psf, ppidl);
1590         }
1591         IFolderView_Release(pfv);
1592         return ret;
1593     }
1594 
1595     return ret;
1596 }
1597 
1598 #endif /* !__REACTOS__ */
1599 
1600 /**************************************************************************
1601  *
1602  *        internal functions
1603  *
1604  *    ### 1. section creating pidls ###
1605  *
1606  *************************************************************************
1607  */
1608 
1609 /* Basic PIDL constructor.  Allocates size + 5 bytes, where:
1610  * - two bytes are SHITEMID.cb
1611  * - one byte is PIDLDATA.type
1612  * - two bytes are the NULL PIDL terminator
1613  * Sets type of the returned PIDL to type.
1614  */
_ILAlloc(PIDLTYPE type,unsigned int size)1615 static LPITEMIDLIST _ILAlloc(PIDLTYPE type, unsigned int size)
1616 {
1617     LPITEMIDLIST pidlOut = NULL;
1618 
1619     pidlOut = SHAlloc(size + 5);
1620     if(pidlOut)
1621     {
1622         LPPIDLDATA pData;
1623         LPITEMIDLIST pidlNext;
1624 
1625         ZeroMemory(pidlOut, size + 5);
1626         pidlOut->mkid.cb = size + 3;
1627 
1628         pData = _ILGetDataPointer(pidlOut);
1629         if (pData)
1630             pData->type = type;
1631 
1632         pidlNext = ILGetNext(pidlOut);
1633         if (pidlNext)
1634             pidlNext->mkid.cb = 0x00;
1635         TRACE("-- (pidl=%p, size=%u)\n", pidlOut, size);
1636     }
1637 
1638     return pidlOut;
1639 }
1640 
_ILCreateDesktop(void)1641 LPITEMIDLIST _ILCreateDesktop(void)
1642 {
1643     LPITEMIDLIST ret;
1644 
1645     TRACE("()\n");
1646     ret = SHAlloc(2);
1647     if (ret)
1648         ret->mkid.cb = 0;
1649     return ret;
1650 }
1651 
_ILCreateMyComputer(void)1652 LPITEMIDLIST _ILCreateMyComputer(void)
1653 {
1654     TRACE("()\n");
1655     return _ILCreateGuid(PT_GUID, &CLSID_MyComputer);
1656 }
1657 
_ILCreateMyDocuments(void)1658 LPITEMIDLIST _ILCreateMyDocuments(void)
1659 {
1660     TRACE("()\n");
1661     return _ILCreateGuid(PT_GUID, &CLSID_MyDocuments);
1662 }
1663 
_ILCreateIExplore(void)1664 LPITEMIDLIST _ILCreateIExplore(void)
1665 {
1666     TRACE("()\n");
1667     return _ILCreateGuid(PT_GUID, &CLSID_Internet);
1668 }
1669 
_ILCreateControlPanel(void)1670 LPITEMIDLIST _ILCreateControlPanel(void)
1671 {
1672     LPITEMIDLIST parent = _ILCreateGuid(PT_GUID, &CLSID_MyComputer), ret = NULL;
1673 
1674     TRACE("()\n");
1675     if (parent)
1676     {
1677         LPITEMIDLIST cpl = _ILCreateGuid(PT_SHELLEXT, &CLSID_ControlPanel);
1678 
1679         if (cpl)
1680         {
1681             ret = ILCombine(parent, cpl);
1682             SHFree(cpl);
1683         }
1684         SHFree(parent);
1685     }
1686     return ret;
1687 }
1688 
_ILCreatePrinters(void)1689 LPITEMIDLIST _ILCreatePrinters(void)
1690 {
1691 #ifdef __REACTOS__
1692     // Note: Wine returns the PIDL as it was in Windows 95, NT5 moved it into CSIDL_CONTROLS
1693     extern HRESULT SHGetFolderLocationHelper(HWND hwnd, int nFolder, REFCLSID clsid, LPITEMIDLIST *ppidl);
1694     LPITEMIDLIST pidl;
1695     SHGetFolderLocationHelper(NULL, CSIDL_CONTROLS, &CLSID_Printers, &pidl);
1696     return pidl;
1697 #else
1698     LPITEMIDLIST parent = _ILCreateGuid(PT_GUID, &CLSID_MyComputer), ret = NULL;
1699 
1700     TRACE("()\n");
1701     if (parent)
1702     {
1703         LPITEMIDLIST printers = _ILCreateGuid(PT_YAGUID, &CLSID_Printers);
1704 
1705         if (printers)
1706         {
1707             ret = ILCombine(parent, printers);
1708             SHFree(printers);
1709         }
1710         SHFree(parent);
1711     }
1712     return ret;
1713 #endif
1714 }
1715 
_ILCreateNetwork(void)1716 LPITEMIDLIST _ILCreateNetwork(void)
1717 {
1718     TRACE("()\n");
1719     return _ILCreateGuid(PT_GUID, &CLSID_NetworkPlaces);
1720 }
1721 
_ILCreateBitBucket(void)1722 LPITEMIDLIST _ILCreateBitBucket(void)
1723 {
1724     TRACE("()\n");
1725     return _ILCreateGuid(PT_GUID, &CLSID_RecycleBin);
1726 }
1727 
_ILCreateAdminTools(void)1728 LPITEMIDLIST _ILCreateAdminTools(void)
1729 {
1730     TRACE("()\n");
1731     return _ILCreateGuid(PT_GUID, &CLSID_AdminFolderShortcut); //FIXME
1732 }
1733 
_ILCreateGuid(PIDLTYPE type,REFIID guid)1734 LPITEMIDLIST _ILCreateGuid(PIDLTYPE type, REFIID guid)
1735 {
1736     LPITEMIDLIST pidlOut;
1737 
1738     if (type == PT_SHELLEXT || type == PT_GUID || type == PT_YAGUID)
1739     {
1740         pidlOut = _ILAlloc(type, sizeof(GUIDStruct));
1741         if (pidlOut)
1742         {
1743             LPPIDLDATA pData = _ILGetDataPointer(pidlOut);
1744 
1745             pData->u.guid.guid = *guid;
1746             TRACE("-- create GUID-pidl %s\n",
1747                   debugstr_guid(&(pData->u.guid.guid)));
1748         }
1749     }
1750     else
1751     {
1752         WARN("%d: invalid type for GUID\n", type);
1753         pidlOut = NULL;
1754     }
1755     return pidlOut;
1756 }
1757 
1758 #ifndef __REACTOS__
_ILCreateGuidFromStrA(LPCSTR szGUID)1759 LPITEMIDLIST _ILCreateGuidFromStrA(LPCSTR szGUID)
1760 {
1761     IID iid;
1762 
1763     if (FAILED(SHCLSIDFromStringA(szGUID, &iid)))
1764     {
1765         ERR("%s is not a GUID\n", szGUID);
1766         return NULL;
1767     }
1768     return _ILCreateGuid(PT_GUID, &iid);
1769 }
1770 
_ILCreateGuidFromStrW(LPCWSTR szGUID)1771 LPITEMIDLIST _ILCreateGuidFromStrW(LPCWSTR szGUID)
1772 {
1773     IID iid;
1774 
1775 #ifndef __REACTOS__
1776     if (FAILED(SHCLSIDFromStringW(szGUID, &iid)))
1777 #else
1778     if (!GUIDFromStringW(szGUID, &iid))
1779 #endif
1780     {
1781         ERR("%s is not a GUID\n", debugstr_w(szGUID));
1782         return NULL;
1783     }
1784     return _ILCreateGuid(PT_GUID, &iid);
1785 }
1786 #endif /* __REACTOS__ */
1787 
_ILCreateFromFindDataW(const WIN32_FIND_DATAW * wfd)1788 LPITEMIDLIST _ILCreateFromFindDataW( const WIN32_FIND_DATAW *wfd )
1789 {
1790     char    buff[MAX_PATH + 14 +1]; /* see WIN32_FIND_DATA */
1791     DWORD   len, len1, wlen, alen;
1792     LPITEMIDLIST pidl;
1793     PIDLTYPE type;
1794 
1795     if (!wfd)
1796         return NULL;
1797 
1798     TRACE("(%s, %s)\n",debugstr_w(wfd->cAlternateFileName), debugstr_w(wfd->cFileName));
1799 
1800     /* prepare buffer with both names */
1801     len = WideCharToMultiByte(CP_ACP,0,wfd->cFileName,-1,buff,MAX_PATH,NULL,NULL);
1802     len1 = WideCharToMultiByte(CP_ACP,0,wfd->cAlternateFileName,-1, buff+len, sizeof(buff)-len, NULL, NULL);
1803     alen = len + len1;
1804 
1805     type = (wfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? PT_FOLDER : PT_VALUE;
1806 
1807     wlen = lstrlenW(wfd->cFileName) + 1;
1808     pidl = _ILAlloc(type, FIELD_OFFSET(FileStruct, szNames[alen + (alen & 1)]) +
1809                     FIELD_OFFSET(FileStructW, wszName[wlen]) + sizeof(WORD));
1810     if (pidl)
1811     {
1812         LPPIDLDATA pData = _ILGetDataPointer(pidl);
1813         FileStruct *fs = &pData->u.file;
1814         FileStructW *fsw;
1815         WORD *pOffsetW;
1816 
1817         FileTimeToDosDateTime( &wfd->ftLastWriteTime, &fs->uFileDate, &fs->uFileTime);
1818         fs->dwFileSize = wfd->nFileSizeLow;
1819         fs->uFileAttribs = wfd->dwFileAttributes;
1820         memcpy(fs->szNames, buff, alen);
1821 
1822         fsw = (FileStructW*)(pData->u.file.szNames + alen + (alen & 0x1));
1823         fsw->cbLen = FIELD_OFFSET(FileStructW, wszName[wlen]) + sizeof(WORD);
1824         FileTimeToDosDateTime( &wfd->ftCreationTime, &fsw->uCreationDate, &fsw->uCreationTime);
1825         FileTimeToDosDateTime( &wfd->ftLastAccessTime, &fsw->uLastAccessDate, &fsw->uLastAccessTime);
1826         memcpy(fsw->wszName, wfd->cFileName, wlen * sizeof(WCHAR));
1827 
1828         pOffsetW = (WORD*)((LPBYTE)pidl + pidl->mkid.cb - sizeof(WORD));
1829         *pOffsetW = (LPBYTE)fsw - (LPBYTE)pidl;
1830         TRACE("-- Set Value: %s\n",debugstr_w(fsw->wszName));
1831     }
1832     return pidl;
1833 
1834 }
1835 
_ILCreateFromPathW(LPCWSTR szPath,LPITEMIDLIST * ppidl)1836 HRESULT _ILCreateFromPathW(LPCWSTR szPath, LPITEMIDLIST* ppidl)
1837 {
1838     HANDLE hFile;
1839     WIN32_FIND_DATAW stffile;
1840 
1841     if (!ppidl)
1842         return E_INVALIDARG;
1843 
1844     hFile = FindFirstFileW(szPath, &stffile);
1845     if (hFile == INVALID_HANDLE_VALUE)
1846         return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
1847 
1848     FindClose(hFile);
1849 
1850     *ppidl = _ILCreateFromFindDataW(&stffile);
1851 
1852     return *ppidl ? S_OK : E_OUTOFMEMORY;
1853 }
1854 
_ILCreateDrive(LPCWSTR lpszNew)1855 LPITEMIDLIST _ILCreateDrive(LPCWSTR lpszNew)
1856 {
1857     LPITEMIDLIST pidlOut;
1858 
1859     TRACE("(%s)\n",debugstr_w(lpszNew));
1860 
1861     pidlOut = _ILAlloc(PT_DRIVE, sizeof(DriveStruct));
1862     if (pidlOut)
1863     {
1864         LPSTR pszDest = _ILGetTextPointer(pidlOut);
1865         if (pszDest)
1866         {
1867             lstrcpyA(pszDest, "x:\\");
1868             pszDest[0] = toupper(lpszNew[0]);
1869             TRACE("-- create Drive: %s\n", debugstr_a(pszDest));
1870         }
1871     }
1872     return pidlOut;
1873 }
1874 
_ILCreateEntireNetwork(void)1875 LPITEMIDLIST _ILCreateEntireNetwork(void)
1876 {
1877     LPITEMIDLIST pidlOut;
1878 
1879     TRACE("\n");
1880 
1881     pidlOut = _ILAlloc(PT_NETWORK, FIELD_OFFSET(PIDLDATA, u.network.szNames[sizeof("Entire Network")]));
1882     if (pidlOut)
1883     {
1884         LPPIDLDATA pData = _ILGetDataPointer(pidlOut);
1885 
1886         pData->u.network.dummy = 0;
1887         strcpy(pData->u.network.szNames, "Entire Network");
1888     }
1889     return pidlOut;
1890 }
1891 
1892 /**************************************************************************
1893  *  _ILGetDrive()
1894  *
1895  *  Gets the text for the drive eg. 'c:\'
1896  *
1897  * RETURNS
1898  *  strlen (lpszText)
1899  */
_ILGetDrive(LPCITEMIDLIST pidl,LPWSTR pOut,UINT uSize)1900 DWORD _ILGetDrive(LPCITEMIDLIST pidl, LPWSTR pOut, UINT uSize)
1901 {
1902     TRACE("(%p,%p,%u)\n",pidl,pOut,uSize);
1903 
1904     if(_ILIsMyComputer(pidl))
1905         pidl = ILGetNext(pidl);
1906 
1907     if (pidl && _ILIsDrive(pidl))
1908         return _ILSimpleGetTextW(pidl, pOut, uSize);
1909 
1910     return 0;
1911 }
1912 
1913 /**************************************************************************
1914  *
1915  *    ### 2. section testing pidls ###
1916  *
1917  **************************************************************************
1918  *  _ILIsUnicode()
1919  *  _ILIsDesktop()
1920  *  _ILIsMyComputer()
1921  *  _ILIsSpecialFolder()
1922  *  _ILIsDrive()
1923  *  _ILIsFolder()
1924  *  _ILIsValue()
1925  *  _ILIsPidlSimple()
1926  */
_ILIsUnicode(LPCITEMIDLIST pidl)1927 BOOL _ILIsUnicode(LPCITEMIDLIST pidl)
1928 {
1929     LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
1930 
1931     TRACE("(%p)\n",pidl);
1932 
1933     return (pidl && lpPData && PT_VALUEW == lpPData->type);
1934 }
1935 
_ILIsDesktop(LPCITEMIDLIST pidl)1936 BOOL _ILIsDesktop(LPCITEMIDLIST pidl)
1937 {
1938     TRACE("(%p)\n",pidl);
1939 
1940     return !pidl || !pidl->mkid.cb;
1941 }
1942 
_ILIsMyDocuments(LPCITEMIDLIST pidl)1943 BOOL _ILIsMyDocuments(LPCITEMIDLIST pidl)
1944 {
1945     IID *iid = _ILGetGUIDPointer(pidl);
1946 
1947     TRACE("(%p)\n", pidl);
1948 
1949     if (iid)
1950         return IsEqualIID(iid, &CLSID_MyDocuments);
1951     return FALSE;
1952 }
1953 
_ILIsNetHood(LPCITEMIDLIST pidl)1954 BOOL _ILIsNetHood(LPCITEMIDLIST pidl)
1955 {
1956     IID *iid = _ILGetGUIDPointer(pidl);
1957 
1958     TRACE("(%p)\n", pidl);
1959 
1960     if (iid)
1961         return IsEqualIID(iid, &CLSID_NetworkPlaces);
1962     return FALSE;
1963 }
1964 
_ILIsControlPanel(LPCITEMIDLIST pidl)1965 BOOL _ILIsControlPanel(LPCITEMIDLIST pidl)
1966 {
1967     IID *iid = _ILGetGUIDPointer(pidl);
1968 
1969     TRACE("(%p)\n", pidl);
1970 
1971     if (iid)
1972         return IsEqualIID(iid, &CLSID_ControlPanel);
1973     return FALSE;
1974 }
1975 
_ILIsMyComputer(LPCITEMIDLIST pidl)1976 BOOL _ILIsMyComputer(LPCITEMIDLIST pidl)
1977 {
1978     REFIID iid = _ILGetGUIDPointer(pidl);
1979 
1980     TRACE("(%p)\n",pidl);
1981 
1982     if (iid)
1983         return IsEqualIID(iid, &CLSID_MyComputer);
1984     return FALSE;
1985 }
1986 
_ILIsBitBucket(LPCITEMIDLIST pidl)1987 BOOL _ILIsBitBucket(LPCITEMIDLIST pidl)
1988 {
1989     IID *iid = _ILGetGUIDPointer(pidl);
1990 
1991     TRACE("(%p)\n", pidl);
1992 
1993     if (iid)
1994         return IsEqualIID(iid, &CLSID_RecycleBin);
1995     return FALSE;
1996 }
1997 
_ILIsSpecialFolder(LPCITEMIDLIST pidl)1998 BOOL _ILIsSpecialFolder (LPCITEMIDLIST pidl)
1999 {
2000     LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
2001 
2002     TRACE("(%p)\n",pidl);
2003 
2004     return (pidl && ( (lpPData && (PT_GUID== lpPData->type || PT_SHELLEXT== lpPData->type || PT_YAGUID == lpPData->type)) ||
2005               (pidl && pidl->mkid.cb == 0x00)
2006             ));
2007 }
2008 
_ILIsDrive(LPCITEMIDLIST pidl)2009 BOOL _ILIsDrive(LPCITEMIDLIST pidl)
2010 {
2011     LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
2012 
2013     TRACE("(%p)\n",pidl);
2014 
2015     return (pidl && lpPData && (PT_DRIVE == lpPData->type ||
2016                     PT_DRIVE1 == lpPData->type ||
2017                     PT_DRIVE2 == lpPData->type ||
2018                     PT_DRIVE3 == lpPData->type));
2019 }
2020 
_ILIsFolder(LPCITEMIDLIST pidl)2021 BOOL _ILIsFolder(LPCITEMIDLIST pidl)
2022 {
2023     LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
2024 
2025     TRACE("(%p)\n",pidl);
2026 
2027     return (pidl && lpPData && (PT_FOLDER == lpPData->type || PT_FOLDER1 == lpPData->type));
2028 }
2029 
_ILIsValue(LPCITEMIDLIST pidl)2030 BOOL _ILIsValue(LPCITEMIDLIST pidl)
2031 {
2032     LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
2033 
2034     TRACE("(%p)\n",pidl);
2035 
2036     return (pidl && lpPData && PT_VALUE == lpPData->type);
2037 }
2038 
_ILIsCPanelStruct(LPCITEMIDLIST pidl)2039 BOOL _ILIsCPanelStruct(LPCITEMIDLIST pidl)
2040 {
2041     LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
2042 
2043     TRACE("(%p)\n",pidl);
2044 
2045     return (pidl && lpPData && (lpPData->type == 0));
2046 }
2047 
2048 /**************************************************************************
2049  *    _ILIsPidlSimple
2050  */
_ILIsPidlSimple(LPCITEMIDLIST pidl)2051 BOOL _ILIsPidlSimple(LPCITEMIDLIST pidl)
2052 {
2053     BOOL ret = TRUE;
2054 
2055     if(! _ILIsDesktop(pidl))    /* pidl=NULL or mkid.cb=0 */
2056     {
2057         WORD len = pidl->mkid.cb;
2058         LPCITEMIDLIST pidlnext = (LPCITEMIDLIST) (((const BYTE*)pidl) + len );
2059 
2060         if (pidlnext->mkid.cb)
2061             ret = FALSE;
2062     }
2063 
2064     TRACE("%s\n", ret ? "Yes" : "No");
2065     return ret;
2066 }
2067 
2068 /**************************************************************************
2069  *
2070  *    ### 3. section getting values from pidls ###
2071  */
2072 
2073 /**************************************************************************
2074  *  _ILSimpleGetTextW
2075  *
2076  * gets the text for the first item in the pidl (eg. simple pidl)
2077  *
2078  * returns the length of the string
2079  */
_ILSimpleGetTextW(LPCITEMIDLIST pidl,LPWSTR szOut,UINT uOutSize)2080 DWORD _ILSimpleGetTextW (LPCITEMIDLIST pidl, LPWSTR szOut, UINT uOutSize)
2081 {
2082     DWORD   dwReturn;
2083     FileStructW *pFileStructW = _ILGetFileStructW(pidl);
2084 
2085     TRACE("(%p %p %x)\n",pidl,szOut,uOutSize);
2086 
2087     if (pFileStructW) {
2088         lstrcpynW(szOut, pFileStructW->wszName, uOutSize);
2089         dwReturn = lstrlenW(pFileStructW->wszName);
2090     } else {
2091         GUID const * riid;
2092         WCHAR szTemp[MAX_PATH];
2093         LPSTR szSrc;
2094         LPWSTR szSrcW;
2095         dwReturn=0;
2096 
2097         if (!pidl)
2098             return 0;
2099 
2100         if (szOut)
2101             *szOut = 0;
2102 
2103         if (_ILIsDesktop(pidl))
2104         {
2105             /* desktop */
2106             if (HCR_GetClassNameW(&CLSID_ShellDesktop, szTemp, _countof(szTemp)))
2107             {
2108                 if (szOut)
2109                     lstrcpynW(szOut, szTemp, uOutSize);
2110 
2111                 dwReturn = lstrlenW (szTemp);
2112             }
2113         }
2114         else if (( szSrcW = _ILGetTextPointerW(pidl) ))
2115         {
2116             /* unicode filesystem */
2117             if (szOut)
2118                 lstrcpynW(szOut, szSrcW, uOutSize);
2119 
2120             dwReturn = lstrlenW(szSrcW);
2121         }
2122         else if (( szSrc = _ILGetTextPointer(pidl) ))
2123         {
2124             /* filesystem */
2125             MultiByteToWideChar(CP_ACP, 0, szSrc, -1, szTemp, _countof(szTemp));
2126 
2127             if (szOut)
2128                 lstrcpynW(szOut, szTemp, uOutSize);
2129 
2130             dwReturn = lstrlenW (szTemp);
2131         }
2132         else if (( riid = _ILGetGUIDPointer(pidl) ))
2133         {
2134             /* special folder */
2135             if ( HCR_GetClassNameW(riid, szTemp, _countof(szTemp)))
2136             {
2137                 if (szOut)
2138                     lstrcpynW(szOut, szTemp, uOutSize);
2139 
2140                 dwReturn = lstrlenW (szTemp);
2141             }
2142         }
2143         else
2144         {
2145             ERR("-- no text\n");
2146         }
2147     }
2148 
2149     TRACE("-- (%p=%s 0x%08x)\n",szOut,debugstr_w(szOut),dwReturn);
2150     return dwReturn;
2151 }
2152 
2153 /**************************************************************************
2154  *
2155  *    ### 4. getting pointers to parts of pidls ###
2156  *
2157  **************************************************************************
2158  *  _ILGetDataPointer()
2159  */
_ILGetDataPointer(LPCITEMIDLIST pidl)2160 LPPIDLDATA _ILGetDataPointer(LPCITEMIDLIST pidl)
2161 {
2162     if(!_ILIsEmpty(pidl))
2163         return (LPPIDLDATA)pidl->mkid.abID;
2164     return NULL;
2165 }
2166 
2167 /**************************************************************************
2168  *  _ILGetTextPointerW()
2169  * gets a pointer to the unicode long filename string stored in the pidl
2170  */
_ILGetTextPointerW(LPCITEMIDLIST pidl)2171 static LPWSTR _ILGetTextPointerW(LPCITEMIDLIST pidl)
2172 {
2173     /* TRACE(pidl,"(pidl%p)\n", pidl);*/
2174 
2175     LPPIDLDATA pdata = _ILGetDataPointer(pidl);
2176 
2177     if (!pdata)
2178         return NULL;
2179 
2180     switch (pdata->type)
2181     {
2182     case PT_GUID:
2183     case PT_SHELLEXT:
2184     case PT_YAGUID:
2185         return NULL;
2186 
2187     case PT_DRIVE:
2188     case PT_DRIVE1:
2189     case PT_DRIVE2:
2190     case PT_DRIVE3:
2191         /*return (LPSTR)&(pdata->u.drive.szDriveName);*/
2192         return NULL;
2193 
2194     case PT_FOLDER:
2195     case PT_FOLDER1:
2196     case PT_VALUE:
2197     case PT_IESPECIAL1:
2198     case PT_IESPECIAL2:
2199         /*return (LPSTR)&(pdata->u.file.szNames);*/
2200         return NULL;
2201 
2202     case PT_WORKGRP:
2203     case PT_COMP:
2204     case PT_NETWORK:
2205     case PT_NETPROVIDER:
2206     case PT_SHARE:
2207         /*return (LPSTR)&(pdata->u.network.szNames);*/
2208         return NULL;
2209 
2210     case PT_VALUEW:
2211         return (LPWSTR)pdata->u.file.szNames;
2212 
2213 #ifdef __REACTOS__ /* r54423 */
2214     case PT_CPLAPPLET:
2215         return pdata->u.cpanel.szName;
2216 #endif
2217 
2218     }
2219     return NULL;
2220 }
2221 
2222 
2223 /**************************************************************************
2224  *  _ILGetTextPointer()
2225  * gets a pointer to the long filename string stored in the pidl
2226  */
_ILGetTextPointer(LPCITEMIDLIST pidl)2227 LPSTR _ILGetTextPointer(LPCITEMIDLIST pidl)
2228 {
2229     /* TRACE(pidl,"(pidl%p)\n", pidl);*/
2230 
2231     LPPIDLDATA pdata = _ILGetDataPointer(pidl);
2232 
2233     if (!pdata)
2234         return NULL;
2235 
2236     switch (pdata->type)
2237     {
2238     case PT_GUID:
2239     case PT_SHELLEXT:
2240     case PT_YAGUID:
2241         return NULL;
2242 
2243     case PT_DRIVE:
2244     case PT_DRIVE1:
2245     case PT_DRIVE2:
2246     case PT_DRIVE3:
2247         return pdata->u.drive.szDriveName;
2248 
2249     case PT_FOLDER:
2250     case PT_FOLDER1:
2251     case PT_VALUE:
2252     case PT_IESPECIAL1:
2253     case PT_IESPECIAL2:
2254         return pdata->u.file.szNames;
2255 
2256     case PT_WORKGRP:
2257     case PT_COMP:
2258     case PT_NETWORK:
2259     case PT_NETPROVIDER:
2260     case PT_SHARE:
2261         return pdata->u.network.szNames;
2262     }
2263     return NULL;
2264 }
2265 
2266 /**************************************************************************
2267  *  _ILGetSTextPointer()
2268  * gets a pointer to the short filename string stored in the pidl
2269  */
_ILGetSTextPointer(LPCITEMIDLIST pidl)2270 static LPSTR _ILGetSTextPointer(LPCITEMIDLIST pidl)
2271 {
2272     /* TRACE(pidl,"(pidl%p)\n", pidl); */
2273 
2274     LPPIDLDATA pdata =_ILGetDataPointer(pidl);
2275 
2276     if (!pdata)
2277         return NULL;
2278 
2279     switch (pdata->type)
2280     {
2281     case PT_FOLDER:
2282     case PT_VALUE:
2283     case PT_IESPECIAL1:
2284     case PT_IESPECIAL2:
2285         return pdata->u.file.szNames + strlen (pdata->u.file.szNames) + 1;
2286 
2287     case PT_WORKGRP:
2288         return pdata->u.network.szNames + strlen (pdata->u.network.szNames) + 1;
2289     }
2290     return NULL;
2291 }
2292 
2293 /**************************************************************************
2294  * _ILGetGUIDPointer()
2295  *
2296  * returns reference to guid stored in some pidls
2297  */
_ILGetGUIDPointer(LPCITEMIDLIST pidl)2298 IID* _ILGetGUIDPointer(LPCITEMIDLIST pidl)
2299 {
2300     LPPIDLDATA pdata =_ILGetDataPointer(pidl);
2301 
2302     TRACE("%p\n", pidl);
2303 
2304     if (!pdata)
2305         return NULL;
2306 
2307     TRACE("pdata->type 0x%04x\n", pdata->type);
2308     switch (pdata->type)
2309     {
2310     case PT_SHELLEXT:
2311     case PT_GUID:
2312     case PT_YAGUID:
2313         return &(pdata->u.guid.guid);
2314 
2315     default:
2316         TRACE("Unknown pidl type 0x%04x\n", pdata->type);
2317         break;
2318     }
2319     return NULL;
2320 }
2321 
2322 /******************************************************************************
2323  * _ILGetFileStructW [Internal]
2324  *
2325  * Get pointer the a SHITEMID's FileStructW field if present
2326  *
2327  * PARAMS
2328  *  pidl [I] The SHITEMID
2329  *
2330  * RETURNS
2331  *  Success: Pointer to pidl's FileStructW field.
2332  *  Failure: NULL
2333  */
_ILGetFileStructW(LPCITEMIDLIST pidl)2334 FileStructW* _ILGetFileStructW(LPCITEMIDLIST pidl) {
2335     FileStructW *pFileStructW;
2336     WORD cbOffset;
2337 
2338     if (!(_ILIsValue(pidl) || _ILIsFolder(pidl)))
2339         return NULL;
2340 
2341     cbOffset = *(const WORD *)((const BYTE *)pidl + pidl->mkid.cb - sizeof(WORD));
2342     pFileStructW = (FileStructW*)((LPBYTE)pidl + cbOffset);
2343 
2344     /* Currently I don't see a fool prove way to figure out if a pidl is for sure of WinXP
2345      * style with a FileStructW member. If we switch all our shellfolder-implementations to
2346      * the new format, this won't be a problem. For now, we do as many sanity checks as possible. */
2347     if ((cbOffset & 0x1) || /* FileStructW member is word aligned in the pidl */
2348         /* FileStructW is positioned after FileStruct */
2349         cbOffset < sizeof(pidl->mkid.cb) + sizeof(PIDLTYPE) + sizeof(FileStruct) ||
2350         /* There has to be enough space at cbOffset in the pidl to hold FileStructW and cbOffset */
2351         cbOffset > pidl->mkid.cb - sizeof(cbOffset) - sizeof(FileStructW) ||
2352         pidl->mkid.cb != cbOffset + pFileStructW->cbLen)
2353     {
2354         WARN("Invalid pidl format (cbOffset = %d)!\n", cbOffset);
2355         return NULL;
2356     }
2357 
2358     return pFileStructW;
2359 }
2360 
2361 /*************************************************************************
2362  * _ILGetFileDateTime
2363  *
2364  * Given the ItemIdList, get the FileTime
2365  *
2366  * PARAMS
2367  *      pidl        [I] The ItemIDList
2368  *      pFt         [I] the resulted FILETIME of the file
2369  *
2370  * RETURNS
2371  *     True if Successful
2372  *
2373  * NOTES
2374  *
2375  */
_ILGetFileDateTime(LPCITEMIDLIST pidl,FILETIME * pFt)2376 BOOL _ILGetFileDateTime(LPCITEMIDLIST pidl, FILETIME *pFt)
2377 {
2378     LPPIDLDATA pdata = _ILGetDataPointer(pidl);
2379 
2380     if (!pdata)
2381         return FALSE;
2382 
2383     switch (pdata->type)
2384     {
2385     case PT_FOLDER:
2386     case PT_VALUE:
2387         DosDateTimeToFileTime(pdata->u.file.uFileDate, pdata->u.file.uFileTime, pFt);
2388         break;
2389     default:
2390         return FALSE;
2391     }
2392     return TRUE;
2393 }
2394 
_ILGetFileDate(LPCITEMIDLIST pidl,LPWSTR pOut,UINT uOutSize)2395 BOOL _ILGetFileDate(LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize)
2396 {
2397     FILETIME ft,lft;
2398     SYSTEMTIME time;
2399     BOOL ret;
2400 
2401     if (_ILGetFileDateTime( pidl, &ft ))
2402     {
2403         FileTimeToLocalFileTime(&ft, &lft);
2404         FileTimeToSystemTime (&lft, &time);
2405 
2406         ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &time, NULL, pOut, uOutSize);
2407         if (ret)
2408         {
2409             /* Append space + time without seconds */
2410             pOut[ret - 1] = L' ';
2411             GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &time, NULL, &pOut[ret], uOutSize - ret);
2412         }
2413     }
2414     else
2415     {
2416         pOut[0] = UNICODE_NULL;
2417         ret = FALSE;
2418     }
2419     return ret;
2420 }
2421 
2422 /*************************************************************************
2423  * _ILGetFileSize
2424  *
2425  * Given the ItemIdList, get the FileSize
2426  *
2427  * PARAMS
2428  *    pidl     [I] The ItemIDList
2429  *    pOut     [I] The buffer to save the result
2430  *    uOutsize [I] The size of the buffer
2431  *
2432  * RETURNS
2433  *    The FileSize
2434  *
2435  * NOTES
2436  *    pOut can be null when no string is needed
2437  *
2438  */
_ILGetFileSize(LPCITEMIDLIST pidl,LPWSTR pOut,UINT uOutSize)2439 DWORD _ILGetFileSize(LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize)
2440 {
2441     LPPIDLDATA pdata = _ILGetDataPointer(pidl);
2442     DWORD dwSize;
2443 
2444     if (!pdata)
2445         return 0;
2446 
2447     switch (pdata->type)
2448     {
2449     case PT_VALUE:
2450         dwSize = pdata->u.file.dwFileSize;
2451         if (pOut)
2452             StrFormatKBSizeW(dwSize, pOut, uOutSize);
2453         return dwSize;
2454     }
2455     if (pOut)
2456         *pOut = UNICODE_NULL;
2457     return 0;
2458 }
2459 
_ILGetExtension(LPCITEMIDLIST pidl,LPWSTR pOut,UINT uOutSize)2460 BOOL _ILGetExtension(LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize)
2461 {
2462     WCHAR szTemp[MAX_PATH];
2463     LPCWSTR pPoint;
2464     LPCITEMIDLIST pidlTemp = pidl;
2465 
2466     TRACE("pidl=%p\n",pidl);
2467 
2468     if (!pidl)
2469         return FALSE;
2470 
2471     pidlTemp = ILFindLastID(pidl);
2472 
2473     if (!_ILIsValue(pidlTemp))
2474         return FALSE;
2475     if (!_ILSimpleGetTextW(pidlTemp, szTemp, _countof(szTemp)))
2476         return FALSE;
2477 
2478     pPoint = PathFindExtensionW(szTemp);
2479 
2480     if (!*pPoint)
2481         return FALSE;
2482 
2483     pPoint++;
2484     lstrcpynW(pOut, pPoint, uOutSize);
2485     TRACE("%s\n", debugstr_w(pOut));
2486 
2487     return TRUE;
2488 }
2489 
2490 /*************************************************************************
2491  * _ILGetFileType
2492  *
2493  * Given the ItemIdList, get the file type description
2494  *
2495  * PARAMS
2496  *      pidl        [I] The ItemIDList (simple)
2497  *      pOut        [I] The buffer to save the result
2498  *      uOutsize    [I] The size of the buffer
2499  *
2500  * RETURNS
2501  *    nothing
2502  *
2503  * NOTES
2504  *    This function copies as much as possible into the buffer.
2505  */
_ILGetFileType(LPCITEMIDLIST pidl,LPWSTR pOut,UINT uOutSize)2506 void _ILGetFileType(LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize)
2507 {
2508     WCHAR sType[64], sTemp[64];
2509 
2510     if(_ILIsValue(pidl))
2511     {
2512         if(uOutSize > 0)
2513             pOut[0] = 0;
2514         if (_ILGetExtension(pidl, sType, _countof(sType)))
2515         {
2516             if (HCR_MapTypeToValueW(sType, sTemp, _countof(sTemp), TRUE))
2517             {
2518                 /* retrieve description */
2519                 if (HCR_MapTypeToValueW(sTemp, pOut, uOutSize, FALSE))
2520                     return;
2521             }
2522 
2523             /* display Ext-file as description */
2524             CharUpperW(sType);
2525             /* load localized file string */
2526             sTemp[0] = UNICODE_NULL;
2527             if (LoadStringW(shell32_hInstance, IDS_ANY_FILE, sTemp, _countof(sTemp)))
2528             {
2529                 sTemp[_countof(sTemp) - 1] = UNICODE_NULL;
2530                 StringCchPrintfW(pOut, uOutSize, sTemp, sType);
2531             }
2532         }
2533     }
2534     else
2535     {
2536         pOut[0] = UNICODE_NULL;
2537         LoadStringW(shell32_hInstance, IDS_DIRECTORY, pOut, uOutSize);
2538         /* make sure its null terminated */
2539         pOut[uOutSize - 1] = UNICODE_NULL;
2540     }
2541 }
2542 
2543 /*************************************************************************
2544  * _ILGetFileAttributes
2545  *
2546  * Given the ItemIdList, get the Attrib string format
2547  *
2548  * PARAMS
2549  *      pidl        [I] The ItemIDList
2550  *      pOut        [I] The buffer to save the result
2551  *      uOutsize    [I] The size of the Buffer
2552  *
2553  * RETURNS
2554  *     Attributes
2555  *
2556  * FIXME
2557  *  return value 0 in case of error is a valid return value
2558  *
2559  */
_ILGetFileAttributes(LPCITEMIDLIST pidl,LPWSTR pOut,UINT uOutSize)2560 DWORD _ILGetFileAttributes(LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize)
2561 {
2562     LPPIDLDATA pData = _ILGetDataPointer(pidl);
2563     WORD wAttrib = 0;
2564     int i;
2565 
2566     if (!pData)
2567         return 0;
2568 
2569     switch(pData->type)
2570     {
2571     case PT_FOLDER:
2572     case PT_VALUE:
2573         wAttrib = pData->u.file.uFileAttribs;
2574         break;
2575     }
2576 
2577     if(uOutSize >= 6)
2578     {
2579         i=0;
2580         if(wAttrib & FILE_ATTRIBUTE_READONLY)
2581             pOut[i++] = L'R';
2582         if(wAttrib & FILE_ATTRIBUTE_HIDDEN)
2583             pOut[i++] = L'H';
2584         if(wAttrib & FILE_ATTRIBUTE_SYSTEM)
2585             pOut[i++] = L'S';
2586         if(wAttrib & FILE_ATTRIBUTE_ARCHIVE)
2587             pOut[i++] = L'A';
2588         if(wAttrib & FILE_ATTRIBUTE_COMPRESSED)
2589             pOut[i++] = L'C';
2590         pOut[i] = UNICODE_NULL;
2591     }
2592     return wAttrib;
2593 }
2594 
2595 /*************************************************************************
2596  * ILFreeaPidl
2597  *
2598  * frees an aPidl struct
2599  */
_ILFreeaPidl(LPITEMIDLIST * apidl,UINT cidl)2600 void _ILFreeaPidl(LPITEMIDLIST * apidl, UINT cidl)
2601 {
2602     UINT   i;
2603 
2604     if (apidl)
2605     {
2606         for (i = 0; i < cidl; i++)
2607             SHFree(apidl[i]);
2608         SHFree(apidl);
2609     }
2610 }
2611 
2612 /*************************************************************************
2613  * ILCopyaPidl
2614  *
2615  * copies an aPidl struct
2616  */
_ILCopyaPidl(PCUITEMID_CHILD_ARRAY apidlsrc,UINT cidl)2617 PITEMID_CHILD* _ILCopyaPidl(PCUITEMID_CHILD_ARRAY apidlsrc, UINT cidl)
2618 {
2619     UINT i;
2620     PITEMID_CHILD *apidldest;
2621 
2622     if (!apidlsrc)
2623         return NULL;
2624 
2625     apidldest = SHAlloc(cidl * sizeof(PITEMID_CHILD));
2626 
2627     for (i = 0; i < cidl; i++)
2628         apidldest[i] = ILClone(apidlsrc[i]);
2629 
2630     return apidldest;
2631 }
2632 
2633 /*************************************************************************
2634  * _ILCopyCidaToaPidl
2635  *
2636  * creates aPidl from CIDA
2637  */
_ILCopyCidaToaPidl(LPITEMIDLIST * pidl,const CIDA * cida)2638 LPITEMIDLIST* _ILCopyCidaToaPidl(LPITEMIDLIST* pidl, const CIDA * cida)
2639 {
2640     UINT i;
2641     LPITEMIDLIST *dst;
2642 
2643     dst = SHAlloc(cida->cidl * sizeof(LPITEMIDLIST));
2644     if (!dst)
2645         return NULL;
2646 
2647     if (pidl)
2648         *pidl = ILClone((LPCITEMIDLIST)(&((const BYTE*)cida)[cida->aoffset[0]]));
2649 
2650     for (i = 0; i < cida->cidl; i++)
2651         dst[i] = ILClone((LPCITEMIDLIST)(&((const BYTE*)cida)[cida->aoffset[i + 1]]));
2652 
2653     return dst;
2654 }
2655