Use OBJREF on the wire for generic marshaling functions.
[wine] / dlls / shell32 / pidl.c
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * NOTES
21  *  a pidl == NULL means desktop and is legal
22  *
23  */
24
25 #include "config.h"
26 #include "wine/port.h"
27
28 #include <ctype.h>
29 #include <stdarg.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #define COBJMACROS
34 #define NONAMELESSUNION
35 #define NONAMELESSSTRUCT
36
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winreg.h"
40 #include "objbase.h"
41 #include "shlguid.h"
42 #include "winerror.h"
43 #include "winnls.h"
44 #include "undocshell.h"
45 #include "shell32_main.h"
46 #include "shellapi.h"
47 #include "shlwapi.h"
48
49 #include "pidl.h"
50 #include "debughlp.h"
51 #include "wine/debug.h"
52
53 WINE_DEFAULT_DEBUG_CHANNEL(pidl);
54 WINE_DECLARE_DEBUG_CHANNEL(shell);
55
56 /* from comctl32.dll */
57 extern LPVOID WINAPI Alloc(INT);
58 extern BOOL WINAPI Free(LPVOID);
59
60 /*************************************************************************
61  * ILGetDisplayNameEx           [SHELL32.186]
62  *
63  * Retrieves the display name of an ItemIDList
64  *
65  * PARAMS
66  *  psf        [I]   Shell Folder to start with, if NULL the desktop is used
67  *  pidl       [I]   ItemIDList relativ to the psf to get the display name for
68  *  path       [O]   Filled in with the display name, assumed to be at least MAX_PATH long
69  *  type       [I]   Type of display name to retrieve
70  *                    0 = SHGDN_FORPARSING | SHGDN_FORADDRESSBAR uses always the desktop as root
71  *                    1 = SHGDN_NORMAL relative to the root folder
72  *                    2 = SHGDN_INFOLDER relative to the root folder, only the last name
73  *
74  * RETURNS
75  *  True if the display name could be retrieved successfully, False otherwise
76  */
77 BOOL WINAPI ILGetDisplayNameExA(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, LPSTR path, DWORD type)
78 {
79         BOOL ret = FALSE;
80         WCHAR wPath[MAX_PATH];
81
82         TRACE("%p %p %p %ld\n", psf, pidl, path, type);
83
84         if (!pidl || !path)
85           return FALSE;
86
87         ret = ILGetDisplayNameExW(psf, pidl, wPath, type);
88         WideCharToMultiByte(CP_ACP, 0, wPath, -1, path, MAX_PATH, NULL, NULL);
89         TRACE("%p %p %s\n", psf, pidl, debugstr_a(path));
90
91         return ret;
92 }
93
94 BOOL WINAPI ILGetDisplayNameExW(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, LPWSTR path, DWORD type)
95 {
96         LPSHELLFOLDER psfParent, lsf = psf;
97         HRESULT ret = NO_ERROR;
98         LPCITEMIDLIST pidllast;
99         STRRET strret;
100         DWORD flag;
101
102         TRACE("%p %p %p %ld\n", psf, pidl, path, type);
103
104         if (!pidl || !path)
105           return FALSE;
106
107         if (!lsf)
108         {
109           ret = SHGetDesktopFolder(&lsf);
110           if (FAILED(ret))
111             return FALSE;
112         }
113
114         if (type >= 0 && type <= 2)
115         {
116           switch (type)
117           {
118             case ILGDN_FORPARSING:
119               flag = SHGDN_FORPARSING | SHGDN_FORADDRESSBAR;
120               break;
121             case ILGDN_NORMAL:
122               flag = SHGDN_NORMAL;
123               break;
124             case ILGDN_INFOLDER:
125               flag = SHGDN_INFOLDER;
126               break;
127             default:
128               FIXME("Unknown type parameter = %lx\n", type);
129               flag = SHGDN_FORPARSING | SHGDN_FORADDRESSBAR;
130               break;
131           }
132           if (!*(const WORD*)pidl || type == ILGDN_FORPARSING)
133           {
134             ret = IShellFolder_GetDisplayNameOf(lsf, pidl, flag, &strret);
135             if (SUCCEEDED(ret))
136             {
137               ret = StrRetToStrNW(path, MAX_PATH, &strret, pidl);
138             }
139           }
140           else
141           {
142             ret = SHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&psfParent, &pidllast);
143             if (SUCCEEDED(ret))
144             {
145               ret = IShellFolder_GetDisplayNameOf(psfParent, pidllast, flag, &strret);
146               if (SUCCEEDED(ret))
147               {
148                 ret = StrRetToStrNW(path, MAX_PATH, &strret, pidllast);
149               }
150               IShellFolder_Release(psfParent);
151             }
152           }
153         }
154
155         TRACE("%p %p %s\n", psf, pidl, debugstr_w(path));
156
157         if (!psf)
158           IShellFolder_Release(lsf);
159         return SUCCEEDED(ret);
160 }
161
162 BOOL WINAPI ILGetDisplayNameEx(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, LPVOID path, DWORD type)
163 {
164         TRACE_(shell)("%p %p %p %ld\n", psf, pidl, path, type);
165         if (SHELL_OsIsUnicode())
166           return ILGetDisplayNameExW(psf, pidl, path, type);
167         return ILGetDisplayNameExA(psf, pidl, path, type);
168 }
169
170 /*************************************************************************
171  * ILGetDisplayName                     [SHELL32.15]
172  */
173 BOOL WINAPI ILGetDisplayName(LPCITEMIDLIST pidl, LPVOID path)
174 {
175         TRACE_(shell)("%p %p\n", pidl, path);
176         if (SHELL_OsIsUnicode())
177           return ILGetDisplayNameExW(NULL, pidl, path, ILGDN_FORPARSING);
178         return ILGetDisplayNameExA(NULL, pidl, path, ILGDN_FORPARSING);
179 }
180
181 /*************************************************************************
182  * ILFindLastID [SHELL32.16]
183  *
184  * NOTES
185  *   observed: pidl=Desktop return=pidl
186  */
187 LPITEMIDLIST WINAPI ILFindLastID(LPCITEMIDLIST pidl)
188 {
189         LPCITEMIDLIST   pidlLast = pidl;
190
191         TRACE("(pidl=%p)\n",pidl);
192
193         if (!pidl)
194           return NULL;
195
196         while (pidl->mkid.cb)
197         {
198           pidlLast = pidl;
199           pidl = ILGetNext(pidl);
200         }
201         return (LPITEMIDLIST)pidlLast;
202 }
203 /*************************************************************************
204  * ILRemoveLastID [SHELL32.17]
205  *
206  * NOTES
207  *   when pidl=Desktop return=FALSE
208  */
209 BOOL WINAPI ILRemoveLastID(LPITEMIDLIST pidl)
210 {
211         TRACE_(shell)("pidl=%p\n",pidl);
212
213         if (!pidl || !pidl->mkid.cb)
214           return 0;
215         ILFindLastID(pidl)->mkid.cb = 0;
216         return 1;
217 }
218
219 /*************************************************************************
220  * ILClone [SHELL32.18]
221  *
222  * NOTES
223  *    duplicate an idlist
224  */
225 LPITEMIDLIST WINAPI ILClone (LPCITEMIDLIST pidl)
226 { DWORD    len;
227   LPITEMIDLIST  newpidl;
228
229   if (!pidl)
230     return NULL;
231
232   len = ILGetSize(pidl);
233   newpidl = (LPITEMIDLIST)SHAlloc(len);
234   if (newpidl)
235     memcpy(newpidl,pidl,len);
236
237   TRACE("pidl=%p newpidl=%p\n",pidl, newpidl);
238   pdump(pidl);
239
240   return newpidl;
241 }
242 /*************************************************************************
243  * ILCloneFirst [SHELL32.19]
244  *
245  * NOTES
246  *  duplicates the first idlist of a complex pidl
247  */
248 LPITEMIDLIST WINAPI ILCloneFirst(LPCITEMIDLIST pidl)
249 {       DWORD len;
250         LPITEMIDLIST pidlNew = NULL;
251
252         TRACE("pidl=%p \n",pidl);
253         pdump(pidl);
254
255         if (pidl)
256         {
257           len = pidl->mkid.cb;
258           pidlNew = (LPITEMIDLIST) SHAlloc (len+2);
259           if (pidlNew)
260           {
261             memcpy(pidlNew,pidl,len+2);         /* 2 -> mind a desktop pidl */
262
263             if (len)
264               ILGetNext(pidlNew)->mkid.cb = 0x00;
265           }
266         }
267         TRACE("-- newpidl=%p\n",pidlNew);
268
269         return pidlNew;
270 }
271
272 /*************************************************************************
273  * ILLoadFromStream (SHELL32.26)
274  *
275  * NOTES
276  *   the first two bytes are the len, the pidl is following then
277  */
278 HRESULT WINAPI ILLoadFromStream (IStream * pStream, LPITEMIDLIST * ppPidl)
279 {       WORD            wLen = 0;
280         DWORD           dwBytesRead;
281         HRESULT         ret = E_FAIL;
282
283
284         TRACE_(shell)("%p %p\n", pStream ,  ppPidl);
285
286         if (*ppPidl)
287         { SHFree(*ppPidl);
288           *ppPidl = NULL;
289         }
290
291         IStream_AddRef (pStream);
292
293         if (SUCCEEDED(IStream_Read(pStream, (LPVOID)&wLen, 2, &dwBytesRead)))
294         {
295           TRACE("PIDL length is %d\n", wLen);
296           if (wLen != 0) {
297             *ppPidl = SHAlloc (wLen);
298             if (SUCCEEDED(IStream_Read(pStream, *ppPidl , wLen, &dwBytesRead))) {
299                 TRACE("Stream read OK\n");
300                 ret = S_OK;
301             } else {
302                 WARN("reading pidl failed\n");
303                 SHFree(*ppPidl);
304                 *ppPidl = NULL;
305             }
306           } else {
307             *ppPidl = NULL;
308             ret = S_OK;
309           }
310         }
311
312         /* we are not yet fully compatible */
313         if (*ppPidl && !pcheck(*ppPidl))
314         {
315           WARN("Check failed\n");
316           SHFree(*ppPidl);
317           *ppPidl = NULL;
318         }
319
320         
321         IStream_Release (pStream);
322         TRACE("done\n");
323         return ret;
324 }
325
326 /*************************************************************************
327  * ILSaveToStream (SHELL32.27)
328  *
329  * NOTES
330  *   the first two bytes are the len, the pidl is following then
331  */
332 HRESULT WINAPI ILSaveToStream (IStream * pStream, LPCITEMIDLIST pPidl)
333 {
334         LPCITEMIDLIST   pidl;
335         WORD            wLen = 0;
336         HRESULT         ret = E_FAIL;
337
338         TRACE_(shell)("%p %p\n", pStream, pPidl);
339
340         IStream_AddRef (pStream);
341
342         pidl = pPidl;
343         while (pidl->mkid.cb)
344         {
345           wLen += sizeof(WORD) + pidl->mkid.cb;
346           pidl = ILGetNext(pidl);
347         }
348
349         if (SUCCEEDED(IStream_Write(pStream, (LPVOID)&wLen, 2, NULL)))
350         {
351           if (SUCCEEDED(IStream_Write(pStream, pPidl, wLen, NULL)))
352           { ret = S_OK;
353           }
354         }
355         IStream_Release (pStream);
356
357         return ret;
358 }
359
360 /*************************************************************************
361  * SHILCreateFromPath        [SHELL32.28]
362  *
363  * Create an ItemIDList from a path
364  *
365  * PARAMS
366  *  path       [I]
367  *  ppidl      [O]
368  *  attributes [I/O] requested attributes on call and actual attributes when
369  *                   the function returns
370  *
371  * RETURNS
372  *  NO_ERROR if successful, or an OLE errer code otherwise
373  *
374  * NOTES
375  *  Wrapper for IShellFolder_ParseDisplayName().
376  */
377 HRESULT WINAPI SHILCreateFromPathA(LPCSTR path, LPITEMIDLIST * ppidl, DWORD * attributes)
378 {
379         LPSHELLFOLDER sf;
380         WCHAR lpszDisplayName[MAX_PATH];
381         DWORD pchEaten;
382         HRESULT ret = E_FAIL;
383
384         TRACE_(shell)("%s %p 0x%08lx\n", path, ppidl, attributes ? *attributes : 0);
385
386         if (!MultiByteToWideChar(CP_ACP, 0, path, -1, lpszDisplayName, MAX_PATH))
387           lpszDisplayName[MAX_PATH-1] = 0;
388
389         if (SUCCEEDED (SHGetDesktopFolder(&sf)))
390         {
391           ret = IShellFolder_ParseDisplayName(sf, 0, NULL, lpszDisplayName, &pchEaten, ppidl, attributes);
392           IShellFolder_Release(sf);
393         }
394         return ret;
395 }
396
397 HRESULT WINAPI SHILCreateFromPathW(LPCWSTR path, LPITEMIDLIST * ppidl, DWORD * attributes)
398 {
399         LPSHELLFOLDER sf;
400         DWORD pchEaten;
401         HRESULT ret = E_FAIL;
402
403         TRACE_(shell)("%s %p 0x%08lx\n", debugstr_w(path), ppidl, attributes ? *attributes : 0);
404
405         if (SUCCEEDED (SHGetDesktopFolder(&sf)))
406         {
407           ret = IShellFolder_ParseDisplayName(sf, 0, NULL, (LPWSTR)path, &pchEaten, ppidl, attributes);
408           IShellFolder_Release(sf);
409         }
410         return ret;
411 }
412
413 HRESULT WINAPI SHILCreateFromPathAW (LPCVOID path, LPITEMIDLIST * ppidl, DWORD * attributes)
414 {
415         if ( SHELL_OsIsUnicode())
416           return SHILCreateFromPathW (path, ppidl, attributes);
417         return SHILCreateFromPathA (path, ppidl, attributes);
418 }
419
420 /*************************************************************************
421  * SHCloneSpecialIDList      [SHELL32.89]
422  *
423  * Create an ItemIDList to one of the special folders.
424
425  * PARAMS
426  *  hwndOwner   [in]
427  *  nFolder             [in]    CSIDL_xxxxx
428  *  fCreate             [in]    Create folder if it does not exist
429  *
430  * RETURNS
431  *  Success: The newly created pidl
432  *  Failure: NULL, if inputs are invalid.
433  *
434  * NOTES
435  *  exported by ordinal.
436  *  Caller is responsible for deallocating the returned ItemIDList with the
437  *  shells IMalloc interface, aka ILFree.
438  */
439 LPITEMIDLIST WINAPI SHCloneSpecialIDList(HWND hwndOwner, DWORD nFolder, BOOL fCreate)
440 {       LPITEMIDLIST ppidl;
441         TRACE_(shell)("(hwnd=%p,csidl=0x%lx,%s).\n", hwndOwner, nFolder, fCreate ? "T" : "F");
442
443         if (fCreate)
444           nFolder |= CSIDL_FLAG_CREATE;
445
446         SHGetSpecialFolderLocation(hwndOwner, nFolder, &ppidl);
447         return ppidl;
448 }
449
450 /*************************************************************************
451  * ILGlobalClone             [SHELL32.20]
452  *
453  * Clones an ItemIDList using Alloc.
454  *
455  * PARAMS
456  *  pidl       [I]   ItemIDList to clone
457  *
458  * RETURNS
459  *  Newly allocated ItemIDList.
460  *
461  * NOTES
462  *  exported by ordinal.
463  */
464 LPITEMIDLIST WINAPI ILGlobalClone(LPCITEMIDLIST pidl)
465 {       DWORD    len;
466         LPITEMIDLIST  newpidl;
467
468         if (!pidl)
469           return NULL;
470
471         len = ILGetSize(pidl);
472         newpidl = (LPITEMIDLIST)Alloc(len);
473         if (newpidl)
474           memcpy(newpidl,pidl,len);
475
476         TRACE("pidl=%p newpidl=%p\n",pidl, newpidl);
477         pdump(pidl);
478
479         return newpidl;
480 }
481
482 /*************************************************************************
483  * ILIsEqual [SHELL32.21]
484  *
485  */
486 BOOL WINAPI ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
487 {
488         char    szData1[MAX_PATH];
489         char    szData2[MAX_PATH];
490
491         LPCITEMIDLIST pidltemp1 = pidl1;
492         LPCITEMIDLIST pidltemp2 = pidl2;
493
494         TRACE("pidl1=%p pidl2=%p\n",pidl1, pidl2);
495
496         /* explorer reads from registry directly (StreamMRU),
497            so we can only check here */
498         if ((!pcheck (pidl1)) || (!pcheck (pidl2))) return FALSE;
499
500         pdump (pidl1);
501         pdump (pidl2);
502
503         if ( (!pidl1) || (!pidl2) ) return FALSE;
504
505         while (pidltemp1->mkid.cb && pidltemp2->mkid.cb)
506         {
507             _ILSimpleGetText(pidltemp1, szData1, MAX_PATH);
508             _ILSimpleGetText(pidltemp2, szData2, MAX_PATH);
509
510             if (strcasecmp ( szData1, szData2 )!=0 )
511               return FALSE;
512
513             pidltemp1 = ILGetNext(pidltemp1);
514             pidltemp2 = ILGetNext(pidltemp2);
515         }
516
517         if (!pidltemp1->mkid.cb && !pidltemp2->mkid.cb)
518         {
519           return TRUE;
520         }
521
522         return FALSE;
523 }
524 /*************************************************************************
525  * ILIsParent                [SHELL32.23]
526  *
527  * Verifies that pidlParent is indeed the (immediate) parent of pidlChild.
528  *
529  * PARAMS
530  *  pidlParent [I]
531  *  pidlChild  [I]
532  *  bImmediate [I]   only return true if the parent is the direct parent
533  *                   of the child
534  *
535  * RETURNS
536  *  True if the parent ItemIDlist is a complete part of the child ItemIdList,
537  *  False otherwise.
538  *
539  * NOTES
540  *  parent = a/b, child = a/b/c -> true, c is in folder a/b
541  *  child = a/b/c/d -> false if bImmediate is true, d is not in folder a/b
542  *  child = a/b/c/d -> true if bImmediate is false, d is in a subfolder of a/b
543  */
544 BOOL WINAPI ILIsParent(LPCITEMIDLIST pidlParent, LPCITEMIDLIST pidlChild, BOOL bImmediate)
545 {
546         char    szData1[MAX_PATH];
547         char    szData2[MAX_PATH];
548
549         LPCITEMIDLIST pParent = pidlParent;
550         LPCITEMIDLIST pChild = pidlChild;
551
552         TRACE("%p %p %x\n", pidlParent, pidlChild, bImmediate);
553
554         if (!pParent || !pChild) return FALSE;
555
556         while (pParent->mkid.cb && pChild->mkid.cb)
557         {
558           _ILSimpleGetText(pParent, szData1, MAX_PATH);
559           _ILSimpleGetText(pChild, szData2, MAX_PATH);
560
561           if (strcasecmp ( szData1, szData2 )!=0 )
562             return FALSE;
563
564           pParent = ILGetNext(pParent);
565           pChild = ILGetNext(pChild);
566         }
567
568         if ( pParent->mkid.cb || ! pChild->mkid.cb) /* child shorter or has equal length to parent */
569           return FALSE;
570
571         if ( ILGetNext(pChild)->mkid.cb && bImmediate) /* not immediate descent */
572           return FALSE;
573
574         return TRUE;
575 }
576
577 /*************************************************************************
578  * ILFindChild               [SHELL32.24]
579  *
580  *  Compares elements from pidl1 and pidl2.
581  *
582  * PARAMS
583  *  pidl1      [I]
584  *  pidl2      [I]
585  *
586  * RETURNS
587  *  pidl1 is desktop      pidl2
588  *  pidl1 shorter pidl2   pointer to first different element of pidl2
589  *                        if there was at least one equal element
590  *  pidl2 shorter pidl1   0
591  *  pidl2 equal pidl1     pointer to last 0x00-element of pidl2
592  *
593  * NOTES
594  *  exported by ordinal.
595  */
596 LPITEMIDLIST WINAPI ILFindChild(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
597 {
598         char    szData1[MAX_PATH];
599         char    szData2[MAX_PATH];
600
601         LPCITEMIDLIST pidltemp1 = pidl1;
602         LPCITEMIDLIST pidltemp2 = pidl2;
603         LPCITEMIDLIST ret=NULL;
604
605         TRACE("pidl1=%p pidl2=%p\n",pidl1, pidl2);
606
607         /* explorer reads from registry directly (StreamMRU),
608            so we can only check here */
609         if ((!pcheck (pidl1)) || (!pcheck (pidl2)))
610           return FALSE;
611
612         pdump (pidl1);
613         pdump (pidl2);
614
615         if ( _ILIsDesktop(pidl1) )
616         {
617           ret = pidl2;
618         }
619         else
620         {
621           while (pidltemp1->mkid.cb && pidltemp2->mkid.cb)
622           {
623             _ILSimpleGetText(pidltemp1, szData1, MAX_PATH);
624             _ILSimpleGetText(pidltemp2, szData2, MAX_PATH);
625
626             if (strcasecmp(szData1,szData2))
627               break;
628
629             pidltemp1 = ILGetNext(pidltemp1);
630             pidltemp2 = ILGetNext(pidltemp2);
631             ret = pidltemp2;
632           }
633
634           if (pidltemp1->mkid.cb)
635           {
636             ret = NULL; /* elements of pidl1 left*/
637           }
638         }
639         TRACE_(shell)("--- %p\n", ret);
640         return (LPITEMIDLIST)ret; /* pidl 1 is shorter */
641 }
642
643 /*************************************************************************
644  * ILCombine                 [SHELL32.25]
645  *
646  * Concatenates two complex ItemIDLists.
647  *
648  * PARAMS
649  *  pidl1      [I]   first complex ItemIDLists
650  *  pidl2      [I]   complex ItemIDLists to append
651  *
652  * RETURNS
653  *  if both pidl's == NULL      NULL
654  *  if pidl1 == NULL            cloned pidl2
655  *  if pidl2 == NULL            cloned pidl1
656  *  otherwise new pidl with pidl2 appended to pidl1
657  *
658  * NOTES
659  *  exported by ordinal.
660  *  Does not destroy the passed in ItemIDLists!
661  */
662 LPITEMIDLIST WINAPI ILCombine(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
663 {
664         DWORD    len1,len2;
665         LPITEMIDLIST  pidlNew;
666
667         TRACE("pidl=%p pidl=%p\n",pidl1,pidl2);
668
669         if(!pidl1 && !pidl2) return NULL;
670
671         pdump (pidl1);
672         pdump (pidl2);
673
674         if(!pidl1)
675         {
676           pidlNew = ILClone(pidl2);
677           return pidlNew;
678         }
679
680         if(!pidl2)
681         {
682           pidlNew = ILClone(pidl1);
683           return pidlNew;
684         }
685
686         len1  = ILGetSize(pidl1)-2;
687         len2  = ILGetSize(pidl2);
688         pidlNew  = SHAlloc(len1+len2);
689
690         if (pidlNew)
691         {
692           memcpy(pidlNew,pidl1,len1);
693           memcpy(((BYTE *)pidlNew)+len1,pidl2,len2);
694         }
695
696         /*  TRACE(pidl,"--new pidl=%p\n",pidlNew);*/
697         return pidlNew;
698 }
699
700 /*************************************************************************
701  *  SHGetRealIDL [SHELL32.98]
702  *
703  * NOTES
704  */
705 HRESULT WINAPI SHGetRealIDL(LPSHELLFOLDER lpsf, LPCITEMIDLIST pidlSimple, LPITEMIDLIST *pidlReal)
706 {
707         IDataObject* pDataObj;
708         HRESULT hr = IShellFolder_GetUIObjectOf(lpsf, 0, 1, &pidlSimple, &IID_IDataObject, 0, (LPVOID*)&pDataObj);
709
710         if (SUCCEEDED(hr)) {
711             STGMEDIUM medium;
712             FORMATETC fmt;
713
714             fmt.cfFormat = RegisterClipboardFormatA(CFSTR_SHELLIDLIST);
715             fmt.ptd = NULL;
716             fmt.dwAspect = DVASPECT_CONTENT;
717             fmt.lindex = -1;
718             fmt.tymed = TYMED_HGLOBAL;
719
720             hr = IDataObject_GetData(pDataObj, &fmt, &medium);
721
722             IDataObject_Release(pDataObj);
723
724             if (SUCCEEDED(hr)) {
725                 /*assert(pida->cidl==1);*/
726                 LPIDA pida = (LPIDA)GlobalLock(medium.u.hGlobal);
727
728                 LPCITEMIDLIST pidl_folder = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[0]);
729                 LPCITEMIDLIST pidl_child = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[1]);
730
731                 *pidlReal = ILCombine(pidl_folder, pidl_child);
732
733                 if (!*pidlReal)
734                         hr = E_OUTOFMEMORY;
735
736                 GlobalUnlock(medium.u.hGlobal);
737                 GlobalFree(medium.u.hGlobal);
738             }
739         }
740
741         return hr;
742 }
743
744 /*************************************************************************
745  *  SHLogILFromFSIL [SHELL32.95]
746  *
747  * NOTES
748  *  pild = CSIDL_DESKTOP        ret = 0
749  *  pild = CSIDL_DRIVES         ret = 0
750  */
751 LPITEMIDLIST WINAPI SHLogILFromFSIL(LPITEMIDLIST pidl)
752 {
753         FIXME("(pidl=%p)\n",pidl);
754
755         pdump(pidl);
756
757         return 0;
758 }
759
760 /*************************************************************************
761  * ILGetSize                 [SHELL32.152]
762  *
763  * Gets the byte size of an ItemIDList including zero terminator
764  *
765  * PARAMS
766  *  pidl       [I]   ItemIDList
767  *
768  * RETURNS
769  *  size of pidl in bytes
770  *
771  * NOTES
772  *  exported by ordinal
773  */
774 UINT WINAPI ILGetSize(LPCITEMIDLIST pidl)
775 {
776         LPCSHITEMID si = &(pidl->mkid);
777         UINT len=0;
778
779         if (pidl)
780         { while (si->cb)
781           { len += si->cb;
782             si  = (LPCSHITEMID)(((const BYTE*)si)+si->cb);
783           }
784           len += 2;
785         }
786         TRACE("pidl=%p size=%u\n",pidl, len);
787         return len;
788 }
789
790 /*************************************************************************
791  * ILGetNext                 [SHELL32.153]
792  *
793  * Gets the next ItemID of an ItemIDList
794  *
795  * PARAMS
796  *  pidl       [I]   ItemIDList
797  *
798  * RETURNS
799  *  null -> null
800  *  desktop -> null
801  *  simple pidl -> pointer to 0x0000 element
802  *
803  * NOTES
804  *  exported by ordinal.
805  */
806 LPITEMIDLIST WINAPI ILGetNext(LPCITEMIDLIST pidl)
807 {
808         WORD len;
809
810         TRACE("%p\n", pidl);
811
812         if(pidl)
813         {
814           len =  pidl->mkid.cb;
815           if (len)
816           {
817             pidl = (LPCITEMIDLIST) (((const BYTE*)pidl)+len);
818             TRACE("-- %p\n", pidl);
819             return (LPITEMIDLIST)pidl;
820           }
821         }
822         return NULL;
823 }
824
825 /*************************************************************************
826  * ILAppend                  [SHELL32.154]
827  *
828  * Adds the single ItemID item to the ItemIDList indicated by pidl.
829  * If bEnd is FALSE, inserts the item in the front of the list,
830  * otherwise it adds the item to the end. (???)
831  *
832  * PARAMS
833  *  pidl       [I]   ItemIDList to extend
834  *  item       [I]   ItemID to prepend/append
835  *  bEnd       [I]   Indicates if the item should be appended
836  *
837  * NOTES
838  *  Destroys the passed in idlist! (???)
839  */
840 LPITEMIDLIST WINAPI ILAppend(LPITEMIDLIST pidl, LPCITEMIDLIST item, BOOL bEnd)
841 {
842         LPITEMIDLIST idlRet;
843
844         WARN("(pidl=%p,pidl=%p,%08u)semi-stub\n",pidl,item,bEnd);
845
846         pdump (pidl);
847         pdump (item);
848
849         if (_ILIsDesktop(pidl))
850         {
851            idlRet = ILClone(item);
852            if (pidl)
853              SHFree (pidl);
854            return idlRet;
855         }
856
857         if (bEnd)
858         {
859           idlRet = ILCombine(pidl, item);
860         }
861         else
862         {
863           idlRet = ILCombine(item, pidl);
864         }
865
866         SHFree(pidl);
867         return idlRet;
868 }
869
870 /*************************************************************************
871  * ILFree                    [SHELL32.155]
872  *
873  * Frees memory (if not NULL) allocated by SHMalloc allocator
874  *
875  * PARAMS
876  *  pidl         [I]
877  *
878  * NOTES
879  *  exported by ordinal
880  */
881 void WINAPI ILFree(LPITEMIDLIST pidl)
882 {
883         TRACE("(pidl=%p)\n",pidl);
884         if(pidl) SHFree(pidl);
885 }
886
887 /*************************************************************************
888  * ILGlobalFree              [SHELL32.156]
889  *
890  * Frees memory (if not NULL) allocated by Alloc allocator
891  *
892  * PARAMS
893  *  pidl         [I]
894  *
895  * NOTES
896  *  exported by ordinal.
897  */
898 void WINAPI ILGlobalFree( LPITEMIDLIST pidl)
899 {
900         TRACE("%p\n", pidl);
901
902         if(!pidl) return;
903         Free(pidl);
904 }
905
906 /*************************************************************************
907  * ILCreateFromPathA         [SHELL32.189]
908  *
909  * Creates a complex ItemIDList from a path and returns it.
910  *
911  * PARAMS
912  *  path         [I]
913  *
914  * RETURNS
915  *  the newly created complex ItemIDList or NULL if failed
916  *
917  * NOTES
918  *  exported by ordinal.
919  */
920
921 LPITEMIDLIST WINAPI ILCreateFromPathA (LPCSTR path)
922 {
923         LPITEMIDLIST pidlnew = NULL;
924
925         TRACE_(shell)("%s\n", debugstr_a(path));
926
927         if (SUCCEEDED(SHILCreateFromPathA(path, &pidlnew, NULL)))
928           return pidlnew;
929         return NULL;
930 }
931
932 /*************************************************************************
933  * ILCreateFromPathW         [SHELL32.190]
934  */
935 LPITEMIDLIST WINAPI ILCreateFromPathW (LPCWSTR path)
936 {
937         LPITEMIDLIST pidlnew = NULL;
938
939         TRACE_(shell)("%s\n", debugstr_w(path));
940
941         if (SUCCEEDED(SHILCreateFromPathW(path, &pidlnew, NULL)))
942           return pidlnew;
943         return NULL;
944 }
945
946 /*************************************************************************
947  * ILCreateFromPath          [SHELL32.157]
948  */
949 LPITEMIDLIST WINAPI ILCreateFromPathAW (LPCVOID path)
950 {
951         if ( SHELL_OsIsUnicode())
952           return ILCreateFromPathW (path);
953         return ILCreateFromPathA (path);
954 }
955
956 /*************************************************************************
957  * _ILParsePathW             [internal]
958  *
959  * Creates an ItemIDList from a path and returns it.
960  *
961  * PARAMS
962  *  path         [I]   path to parse and convert into an ItemIDList
963  *  lpFindFile   [I]   pointer to buffer to initialize the FileSystem
964  *                     Bind Data object with
965  *  bBindCtx     [I]   indicates to create a BindContext and assign a
966  *                     FileSystem Bind Data object
967  *  ppidl        [O]   the newly create ItemIDList
968  *  prgfInOut    [I/O] requested attributes on input and actual
969  *                     attributes on return
970  *
971  * RETURNS
972  *  NO_ERROR on success or an OLE error code
973  *
974  * NOTES
975  *  If either lpFindFile is non-NULL or bBindCtx is TRUE, this function
976  *  creates a BindContext object and assigns a FileSystem Bind Data object
977  *  to it, passing the BindContext to IShellFolder_ParseDisplayName. Each
978  *  IShellFolder uses that FileSystem Bind Data object of the BindContext
979  *  to pass data about the current path element to the next object. This
980  *  is used to avoid having to verify the current path element on disk, so
981  *  that creating an ItemIDList from a non-existent path still can work.
982  */
983 static HRESULT WINAPI _ILParsePathW(LPCWSTR path, LPWIN32_FIND_DATAW lpFindFile,
984                              BOOL bBindCtx, LPITEMIDLIST *ppidl, LPDWORD prgfInOut)
985 {
986         LPSHELLFOLDER pSF = NULL;
987         LPBC pBC = NULL;
988         HRESULT ret;
989
990         TRACE("%s %p %d (%p)->%p (%p)->0x%lx\n", debugstr_w(path), lpFindFile, bBindCtx,
991                                                  ppidl, ppidl ? *ppidl : NULL,
992                                                  prgfInOut, prgfInOut ? *prgfInOut : 0);
993
994         ret = SHGetDesktopFolder(&pSF);
995         if (FAILED(ret))
996         {
997           return ret;
998         }
999
1000         if (lpFindFile || bBindCtx)
1001           ret = IFileSystemBindData_Constructor(lpFindFile, &pBC);
1002
1003         if (SUCCEEDED(ret))
1004         {
1005           ret = IShellFolder_ParseDisplayName(pSF, 0, pBC, (LPOLESTR)path, NULL, ppidl, prgfInOut);
1006         }
1007
1008         if (pBC)
1009         {
1010           IBindCtx_Release(pBC);
1011           pBC = NULL;
1012         }
1013
1014         IShellFolder_Release(pSF);
1015
1016         if (!SUCCEEDED(ret) && ppidl)
1017           *ppidl = NULL;
1018
1019         TRACE("%s %p 0x%lx\n", debugstr_w(path), ppidl ? *ppidl : NULL, prgfInOut ? *prgfInOut : 0);
1020
1021         return ret;
1022 }
1023
1024 /*************************************************************************
1025  * SHSimpleIDListFromPath    [SHELL32.162]
1026  *
1027  * Creates a simple ItemIDList from a path and returns it. This function
1028  * does not fail on non-existent paths.
1029  *
1030  * PARAMS
1031  *  path         [I]   path to parse and convert into an ItemIDList
1032  *
1033  * RETURNS
1034  *  the newly created simple ItemIDList
1035  *
1036  * NOTES
1037  *  Simple in the name does not mean a relative ItemIDList but rather a
1038  *  fully qualified list, where only the file name is filled in and the
1039  *  directory flag for those ItemID elements this is known about, eg.
1040  *  it is not the last element in the ItemIDList or the actual directory
1041  *  exists on disk.
1042  *  exported by ordinal.
1043  */
1044 LPITEMIDLIST WINAPI SHSimpleIDListFromPathA(LPCSTR lpszPath)
1045 {
1046     LPITEMIDLIST pidl = NULL;
1047     LPWSTR wPath = NULL;
1048     int len;
1049
1050     TRACE("%s\n", debugstr_a(lpszPath));
1051
1052     if (lpszPath)
1053     {
1054         len = MultiByteToWideChar(CP_ACP, 0, lpszPath, -1, NULL, 0);
1055         wPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1056         MultiByteToWideChar(CP_ACP, 0, lpszPath, -1, wPath, len);
1057     }
1058
1059     _ILParsePathW(wPath, NULL, TRUE, &pidl, NULL);
1060
1061     if (wPath) HeapFree(GetProcessHeap(), 0, wPath);
1062     TRACE("%s %p\n", debugstr_a(lpszPath), pidl);
1063     return pidl;
1064 }
1065
1066 LPITEMIDLIST WINAPI SHSimpleIDListFromPathW(LPCWSTR lpszPath)
1067 {
1068         LPITEMIDLIST pidl = NULL;
1069
1070         TRACE("%s\n", debugstr_w(lpszPath));
1071
1072         _ILParsePathW(lpszPath, NULL, TRUE, &pidl, NULL);
1073         TRACE("%s %p\n", debugstr_w(lpszPath), pidl);
1074         return pidl;
1075 }
1076
1077 LPITEMIDLIST WINAPI SHSimpleIDListFromPathAW(LPCVOID lpszPath)
1078 {
1079         if ( SHELL_OsIsUnicode())
1080           return SHSimpleIDListFromPathW (lpszPath);
1081         return SHSimpleIDListFromPathA (lpszPath);
1082 }
1083
1084 /*************************************************************************
1085  * SHGetDataFromIDListA [SHELL32.247]
1086  *
1087  * NOTES
1088  *  the pidl can be a simple one. since we can't get the path out of the pidl
1089  *  we have to take all data from the pidl
1090  */
1091 HRESULT WINAPI SHGetDataFromIDListA(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, int nFormat, LPVOID dest, int len)
1092 {
1093         TRACE_(shell)("sf=%p pidl=%p 0x%04x %p 0x%04x stub\n",psf,pidl,nFormat,dest,len);
1094
1095         pdump(pidl);
1096         if (!psf || !dest )  return E_INVALIDARG;
1097
1098         switch (nFormat)
1099         {
1100           case SHGDFIL_FINDDATA:
1101             {
1102                LPSTR filename, shortname;
1103                WIN32_FIND_DATAA * pfd = dest;
1104
1105                if (_ILIsDrive(pidl))
1106                    return E_INVALIDARG;
1107
1108                if (len < (int)sizeof(WIN32_FIND_DATAA)) return E_INVALIDARG;
1109
1110                ZeroMemory(pfd, sizeof (WIN32_FIND_DATAA));
1111                _ILGetFileDateTime( pidl, &(pfd->ftLastWriteTime));
1112                pfd->dwFileAttributes = _ILGetFileAttributes(pidl, NULL, 0);
1113                pfd->nFileSizeLow = _ILGetFileSize ( pidl, NULL, 0);
1114
1115                filename = _ILGetTextPointer(pidl);
1116                shortname = _ILGetSTextPointer(pidl);
1117
1118                if (filename)
1119                    lstrcpynA(pfd->cFileName, filename, MAX_PATH);
1120                else
1121                    pfd->cFileName[0] = '\0';
1122
1123                if (shortname)
1124                    lstrcpynA(pfd->cAlternateFileName, shortname, MAX_PATH);
1125                else
1126                    pfd->cAlternateFileName[0] = '\0';
1127             }
1128             return NOERROR;
1129
1130           case SHGDFIL_NETRESOURCE:
1131           case SHGDFIL_DESCRIPTIONID:
1132             FIXME_(shell)("SHGDFIL %i stub\n", nFormat);
1133             break;
1134
1135           default:
1136             ERR_(shell)("Unknown SHGDFIL %i, please report\n", nFormat);
1137         }
1138
1139         return E_INVALIDARG;
1140 }
1141
1142 /*************************************************************************
1143  * SHGetDataFromIDListW [SHELL32.248]
1144  *
1145  */
1146 HRESULT WINAPI SHGetDataFromIDListW(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, int nFormat, LPVOID dest, int len)
1147 {
1148         TRACE_(shell)("sf=%p pidl=%p 0x%04x %p 0x%04x stub\n",psf,pidl,nFormat,dest,len);
1149
1150         pdump(pidl);
1151
1152         if (! psf || !dest )  return E_INVALIDARG;
1153
1154         switch (nFormat)
1155         {
1156           case SHGDFIL_FINDDATA:
1157             {
1158                LPSTR filename, shortname;
1159                WIN32_FIND_DATAW * pfd = dest;
1160
1161                if (_ILIsDrive(pidl))
1162                    return E_INVALIDARG;
1163
1164                if (len < (int)sizeof(WIN32_FIND_DATAW)) return E_INVALIDARG;
1165
1166                ZeroMemory(pfd, sizeof (WIN32_FIND_DATAA));
1167                _ILGetFileDateTime( pidl, &(pfd->ftLastWriteTime));
1168                pfd->dwFileAttributes = _ILGetFileAttributes(pidl, NULL, 0);
1169                pfd->nFileSizeLow = _ILGetFileSize ( pidl, NULL, 0);
1170
1171                filename = _ILGetTextPointer(pidl);
1172                shortname = _ILGetSTextPointer(pidl);
1173
1174                if (!filename)
1175                    pfd->cFileName[0] = '\0';
1176                else if (!MultiByteToWideChar(CP_ACP, 0, filename, -1, pfd->cFileName, MAX_PATH))
1177                    pfd->cFileName[MAX_PATH-1] = 0;
1178
1179                if (!shortname)
1180                    pfd->cAlternateFileName[0] = '\0';
1181                else if (!MultiByteToWideChar(CP_ACP, 0, shortname, -1, pfd->cAlternateFileName, 14))
1182                    pfd->cAlternateFileName[13] = 0;
1183             }
1184             return NOERROR;
1185           case SHGDFIL_NETRESOURCE:
1186           case SHGDFIL_DESCRIPTIONID:
1187             FIXME_(shell)("SHGDFIL %i stub\n", nFormat);
1188             break;
1189
1190           default:
1191             ERR_(shell)("Unknown SHGDFIL %i, please report\n", nFormat);
1192         }
1193
1194         return E_INVALIDARG;
1195 }
1196
1197 /*************************************************************************
1198  * SHELL_GetPathFromIDListA
1199  */
1200 HRESULT SHELL_GetPathFromIDListA(LPCITEMIDLIST pidl, LPSTR pszPath, UINT uOutSize)
1201 {
1202         HRESULT hr = S_OK;
1203
1204         pszPath[0]=0;
1205
1206         /* One case is a PIDL rooted at desktop level */
1207         if (_ILIsValue(pidl) || _ILIsFolder(pidl)) {
1208             hr = SHGetSpecialFolderPathA(0, pszPath, CSIDL_DESKTOP, FALSE);
1209
1210             if (SUCCEEDED(hr))
1211                 PathAddBackslashA(pszPath);
1212         }
1213         /* The only other valid case is a item ID list beginning at "My Computer" */
1214         else if (_ILIsMyComputer(pidl))
1215             pidl = ILGetNext(pidl);
1216
1217         if (SUCCEEDED(hr)) {
1218             LPSTR txt;
1219
1220             while(pidl && pidl->mkid.cb) {
1221                 if (_ILIsSpecialFolder(pidl))
1222                     {hr = E_INVALIDARG; break;}
1223
1224                 txt = _ILGetTextPointer(pidl);
1225                 if (!txt)
1226                     {hr = E_INVALIDARG; break;}
1227
1228                 if (lstrlenA(txt) > pidl->mkid.cb)
1229                     ERR("pidl %p is borked\n",pidl);
1230
1231                 /* make sure there's enough space for the next segment */
1232                 if ( (lstrlenA(txt) + lstrlenA(pszPath)) > uOutSize)
1233                     {hr = E_INVALIDARG; break;}
1234                 lstrcatA( pszPath, txt );
1235
1236                 pidl = ILGetNext(pidl);
1237                 if (!pidl)
1238                     {hr = E_INVALIDARG; break;}
1239
1240                 if (!pidl->mkid.cb) {
1241                     /* We are at the end and successfully converted the complete PIDL. */
1242                     break;
1243                 }
1244
1245                 if( (lstrlenA(pszPath) + 1) > uOutSize)
1246                     {hr = E_INVALIDARG; break;}
1247                 if (!PathAddBackslashA(pszPath))
1248                     {hr = E_INVALIDARG; break;}
1249             }
1250         } else
1251             hr = E_INVALIDARG;
1252
1253         TRACE_(shell)("-- %s, 0x%08lx\n", pszPath, hr);
1254         return hr;
1255 }
1256
1257 /*************************************************************************
1258  * SHGetPathFromIDListA         [SHELL32.@][NT 4.0: SHELL32.220]
1259  *
1260  * PARAMETERS
1261  *  pidl,   [IN] pidl
1262  *  pszPath [OUT] path
1263  *
1264  * RETURNS
1265  *  path from a passed PIDL.
1266  *
1267  * NOTES
1268  *      NULL returns FALSE
1269  *      desktop pidl gives path to desktop directory back
1270  *      special pidls returning FALSE
1271  */
1272 BOOL WINAPI SHGetPathFromIDListA(LPCITEMIDLIST pidl, LPSTR pszPath)
1273 {
1274         HRESULT hr;
1275
1276         TRACE_(shell)("(pidl=%p,%p)\n",pidl,pszPath);
1277         pdump(pidl);
1278
1279         if (!pidl)
1280             return FALSE;
1281
1282         hr = SHELL_GetPathFromIDListA(pidl, pszPath, MAX_PATH);
1283
1284         return SUCCEEDED(hr);
1285 }
1286
1287 /*************************************************************************
1288  * SHELL_GetPathFromIDListW
1289  */
1290 HRESULT SHELL_GetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath, UINT uOutSize)
1291 {
1292         HRESULT hr = S_OK;
1293         UINT len;
1294
1295         pszPath[0]=0;
1296
1297         /* One case is a PIDL rooted at desktop level */
1298         if (_ILIsValue(pidl) || _ILIsFolder(pidl)) {
1299             hr = SHGetSpecialFolderPathW(0, pszPath, CSIDL_DESKTOP, FALSE);
1300
1301             if (SUCCEEDED(hr))
1302                 PathAddBackslashW(pszPath);
1303         }
1304         /* The only other valid case is a item ID list beginning at "My Computer" */
1305         else if (_ILIsMyComputer(pidl))
1306             pidl = ILGetNext(pidl);
1307
1308         if (SUCCEEDED(hr)) {
1309             LPSTR txt;
1310
1311             while(pidl && pidl->mkid.cb) {
1312                 if (_ILIsSpecialFolder(pidl))
1313                     {hr = E_INVALIDARG; break;}
1314
1315                 txt = _ILGetTextPointer(pidl);
1316                 if (!txt)
1317                     {hr = E_INVALIDARG; break;}
1318
1319                 if (lstrlenA(txt) > pidl->mkid.cb)
1320                     ERR("pidl %p is borked\n",pidl);
1321                 len = MultiByteToWideChar(CP_ACP, 0, txt, -1, NULL, 0);
1322                 if ( (lstrlenW(pszPath) + len) > uOutSize )
1323                     {hr = E_INVALIDARG; break;}
1324
1325                 MultiByteToWideChar(CP_ACP, 0, txt, -1, 
1326                                     &pszPath[lstrlenW(pszPath)], len);
1327
1328                 pidl = ILGetNext(pidl);
1329                 if (!pidl)
1330                     {hr = E_INVALIDARG; break;}
1331
1332                 if (!pidl->mkid.cb) {
1333                     /* We are at the end and successfully converted the complete PIDL. */
1334                     break;
1335                 }
1336
1337                 if ( (lstrlenW(pszPath) + 1) > uOutSize )
1338                     {hr = E_INVALIDARG; break;}
1339                 if (!PathAddBackslashW(pszPath))
1340                     {hr = E_INVALIDARG; break;}
1341             }
1342         } else
1343             hr = E_INVALIDARG;
1344
1345     TRACE_(shell)("-- %s, 0x%08lx\n", debugstr_w(pszPath), hr);
1346     return hr;
1347 }
1348
1349 /*************************************************************************
1350  * SHGetPathFromIDListW                         [SHELL32.@]
1351  */
1352 BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath)
1353 {
1354         HRESULT hr;
1355
1356         TRACE_(shell)("(pidl=%p,%p)\n", pidl, debugstr_w(pszPath));
1357         pdump(pidl);
1358
1359         if (!pidl)
1360             return FALSE;
1361
1362         hr = SHELL_GetPathFromIDListW(pidl, pszPath, MAX_PATH);
1363
1364         TRACE_(shell)("-- %s, 0x%08lx\n",debugstr_w(pszPath), hr);
1365         return SUCCEEDED(hr);
1366 }
1367
1368 /*************************************************************************
1369  * SHGetPathFromIDList          [SHELL32.@][NT 4.0: SHELL32.219]
1370  */
1371 BOOL WINAPI SHGetPathFromIDListAW(LPCITEMIDLIST pidl,LPVOID pszPath)
1372 {
1373         TRACE_(shell)("(pidl=%p,%p)\n",pidl,pszPath);
1374
1375         if (SHELL_OsIsUnicode())
1376           return SHGetPathFromIDListW(pidl,pszPath);
1377         return SHGetPathFromIDListA(pidl,pszPath);
1378 }
1379
1380 /*************************************************************************
1381  *      SHBindToParent          [shell version 5.0]
1382  */
1383 HRESULT WINAPI SHBindToParent(LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppv, LPCITEMIDLIST *ppidlLast)
1384 {
1385         IShellFolder    * psf;
1386         LPITEMIDLIST    pidlChild, pidlParent;
1387         HRESULT         hr=E_FAIL;
1388
1389         TRACE_(shell)("pidl=%p\n", pidl);
1390         pdump(pidl);
1391
1392         *ppv = NULL;
1393         if (ppidlLast) *ppidlLast = NULL;
1394
1395         if (_ILIsPidlSimple(pidl))
1396         {
1397           IShellFolder* desktop;
1398
1399           /* we are on desktop level */
1400           hr = SHGetDesktopFolder(&desktop);
1401
1402           if (SUCCEEDED(hr))
1403           {
1404             hr = IShellFolder_QueryInterface(desktop, riid, ppv);
1405
1406             if (SUCCEEDED(hr) && ppidlLast)
1407               *ppidlLast = ILClone(pidl);
1408
1409             IShellFolder_Release(desktop);
1410           }
1411         }
1412         else
1413         {
1414           pidlChild =  ILClone(ILFindLastID(pidl));
1415           pidlParent = ILClone(pidl);
1416           ILRemoveLastID(pidlParent);
1417
1418           hr = SHGetDesktopFolder(&psf);
1419
1420           if (SUCCEEDED(hr))
1421             hr = IShellFolder_BindToObject(psf, pidlParent, NULL, riid, ppv);
1422
1423           if (SUCCEEDED(hr) && ppidlLast)
1424             *ppidlLast = pidlChild;
1425           else
1426             ILFree (pidlChild);
1427
1428           SHFree (pidlParent);
1429           if (psf) IShellFolder_Release(psf);
1430         }
1431
1432
1433         TRACE_(shell)("-- psf=%p pidl=%p ret=0x%08lx\n", *ppv, (ppidlLast)?*ppidlLast:NULL, hr);
1434         return hr;
1435 }
1436
1437 /**************************************************************************
1438  *
1439  *              internal functions
1440  *
1441  *      ### 1. section creating pidls ###
1442  *
1443  *************************************************************************
1444  */
1445 LPITEMIDLIST _ILAlloc(PIDLTYPE type, size_t size)
1446 {
1447     LPITEMIDLIST pidlOut = NULL;
1448
1449     if((pidlOut = SHAlloc(size + 5)))
1450     {
1451         LPPIDLDATA pData;
1452         LPITEMIDLIST pidlNext;
1453
1454         ZeroMemory(pidlOut, size + 5);
1455         pidlOut->mkid.cb = size + 3;
1456
1457         if ((pData = _ILGetDataPointer(pidlOut)))
1458             pData->type = type;
1459
1460         if ((pidlNext = ILGetNext(pidlOut)))
1461             pidlNext->mkid.cb = 0x00;
1462         TRACE("-- (pidl=%p, size=%u)\n", pidlOut, size);
1463     }
1464
1465     return pidlOut;
1466 }
1467
1468 LPITEMIDLIST _ILCreateDesktop()
1469 {
1470     LPITEMIDLIST ret;
1471
1472     TRACE("()\n");
1473     ret = SHAlloc(2);
1474     if (ret)
1475         ret->mkid.cb = 0;
1476     return ret;
1477 }
1478
1479 LPITEMIDLIST _ILCreateMyComputer()
1480 {       TRACE("()\n");
1481         return _ILCreateGuid(PT_GUID, &CLSID_MyComputer);
1482 }
1483
1484 LPITEMIDLIST _ILCreateIExplore()
1485 {       TRACE("()\n");
1486         return _ILCreateGuid(PT_GUID, &CLSID_Internet);
1487 }
1488
1489 LPITEMIDLIST _ILCreateControlPanel()
1490 {
1491     LPITEMIDLIST parent = _ILCreateGuid(PT_GUID, &CLSID_MyComputer), ret = NULL;
1492
1493     TRACE("()\n");
1494     if (parent)
1495     {
1496         LPITEMIDLIST cpl = _ILCreateGuid(PT_SHELLEXT, &CLSID_ControlPanel);
1497
1498         if (cpl)
1499         {
1500             ret = ILCombine(parent, cpl);
1501             SHFree(cpl);
1502         }
1503         SHFree(parent);
1504     }
1505     return ret;
1506 }
1507
1508 LPITEMIDLIST _ILCreatePrinters()
1509 {
1510     LPITEMIDLIST parent = _ILCreateGuid(PT_GUID, &CLSID_MyComputer), ret = NULL;
1511
1512     TRACE("()\n");
1513     if (parent)
1514     {
1515         LPITEMIDLIST printers = _ILCreateGuid(PT_YAGUID, &CLSID_Printers);
1516
1517         if (printers)
1518         {
1519             ret = ILCombine(parent, printers);
1520             SHFree(printers);
1521         }
1522         SHFree(parent);
1523     }
1524     return ret;
1525 }
1526
1527 LPITEMIDLIST _ILCreateNetwork()
1528 {       TRACE("()\n");
1529         return _ILCreateGuid(PT_GUID, &CLSID_NetworkPlaces);
1530 }
1531
1532 LPITEMIDLIST _ILCreateBitBucket()
1533 {       TRACE("()\n");
1534         return _ILCreateGuid(PT_GUID, &CLSID_RecycleBin);
1535 }
1536
1537 LPITEMIDLIST _ILCreateGuid(PIDLTYPE type, REFIID guid)
1538 {
1539     LPITEMIDLIST pidlOut;
1540
1541     if (type == PT_SHELLEXT || type == PT_GUID || type == PT_YAGUID)
1542     {
1543         pidlOut = _ILAlloc(type, sizeof(GUIDStruct));
1544         if (pidlOut)
1545         {
1546             LPPIDLDATA pData = _ILGetDataPointer(pidlOut);
1547
1548             memcpy(&(pData->u.guid.guid), guid, sizeof(GUID));
1549             TRACE("-- create GUID-pidl %s\n",
1550              debugstr_guid(&(pData->u.guid.guid)));
1551         }
1552     }
1553     else
1554     {
1555         WARN("%d: invalid type for GUID\n", type);
1556         pidlOut = NULL;
1557     }
1558     return pidlOut;
1559 }
1560
1561 LPITEMIDLIST _ILCreateGuidFromStrA(LPCSTR szGUID)
1562 {
1563         IID iid;
1564
1565         if (!SUCCEEDED(SHCLSIDFromStringA(szGUID, &iid)))
1566         {
1567           ERR("%s is not a GUID\n", szGUID);
1568           return NULL;
1569         }
1570         return _ILCreateGuid(PT_GUID, &iid);
1571 }
1572
1573 LPITEMIDLIST _ILCreateFromFindDataA(WIN32_FIND_DATAA * stffile )
1574 {
1575     char        buff[MAX_PATH + 14 +1]; /* see WIN32_FIND_DATA */
1576     char *      pbuff = buff;
1577     size_t      len, len1;
1578     LPITEMIDLIST pidl;
1579     PIDLTYPE type;
1580
1581     if (!stffile)
1582         return NULL;
1583
1584     TRACE("(%s, %s)\n",stffile->cAlternateFileName, stffile->cFileName);
1585
1586     /* prepare buffer with both names */
1587     len = strlen (stffile->cFileName) + 1;
1588     memcpy (pbuff, stffile->cFileName, len);
1589     pbuff += len;
1590
1591     len1 = strlen (stffile->cAlternateFileName)+1;
1592     memcpy (pbuff, stffile->cAlternateFileName, len1);
1593
1594     type = (stffile->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? PT_FOLDER : 
1595      PT_VALUE;
1596     /* FileStruct already has one byte for the first name, so use len - 1 in
1597      * size calculation
1598      */
1599     if ((pidl = _ILAlloc(type, sizeof(FileStruct) + (len - 1) + len1)))
1600     {
1601         LPPIDLDATA pData;
1602         LPSTR pszDest;
1603
1604         /* set attributes */
1605         if ((pData = _ILGetDataPointer(pidl)))
1606         {
1607             pData->type = type;
1608             FileTimeToDosDateTime(&(stffile->ftLastWriteTime),&pData->u.file.uFileDate,&pData->u.file.uFileTime);
1609             pData->u.file.dwFileSize = stffile->nFileSizeLow;
1610             pData->u.file.uFileAttribs = (WORD)stffile->dwFileAttributes;
1611         }
1612         if ((pszDest = _ILGetTextPointer(pidl)))
1613         {
1614             memcpy(pszDest, buff, len + len1);
1615             TRACE("-- create Value: %s\n",debugstr_a(pszDest));
1616         }
1617     }
1618     return pidl;
1619 }
1620
1621 HRESULT _ILCreateFromPathA(LPCSTR szPath, LPITEMIDLIST* ppidl)
1622 {
1623         HANDLE hFile;
1624         WIN32_FIND_DATAA stffile;
1625
1626     if (!ppidl)
1627         return E_INVALIDARG;
1628
1629         hFile = FindFirstFileA(szPath, &stffile);
1630
1631         if (hFile == INVALID_HANDLE_VALUE)
1632                 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
1633
1634         FindClose(hFile);
1635
1636         *ppidl = _ILCreateFromFindDataA(&stffile);
1637
1638         return *ppidl ? S_OK : E_OUTOFMEMORY;
1639 }
1640
1641 LPITEMIDLIST _ILCreateDrive(LPCWSTR lpszNew)
1642 {
1643     WCHAR sTemp[4];
1644     LPITEMIDLIST pidlOut;
1645
1646     sTemp[0]=toupperW(lpszNew[0]);
1647     sTemp[1]=':';
1648     sTemp[2]='\\';
1649     sTemp[3]=0x00;
1650     TRACE("(%s)\n",debugstr_w(sTemp));
1651
1652     if ((pidlOut = _ILAlloc(PT_DRIVE, sizeof(DriveStruct))))
1653     {
1654         LPSTR pszDest;
1655
1656         if ((pszDest = _ILGetTextPointer(pidlOut)))
1657         {
1658             WideCharToMultiByte(CP_ACP, 0, sTemp, sizeof(sTemp)/sizeof(WCHAR), pszDest, sizeof(sTemp)/sizeof(WCHAR), NULL, NULL);
1659             TRACE("-- create Drive: %s\n", debugstr_a(pszDest));
1660         }
1661     }
1662     return pidlOut;
1663 }
1664
1665 /**************************************************************************
1666  *  _ILGetDrive()
1667  *
1668  *  Gets the text for the drive eg. 'c:\'
1669  *
1670  * RETURNS
1671  *  strlen (lpszText)
1672  */
1673 DWORD _ILGetDrive(LPCITEMIDLIST pidl,LPSTR pOut, UINT uSize)
1674 {       TRACE("(%p,%p,%u)\n",pidl,pOut,uSize);
1675
1676         if(_ILIsMyComputer(pidl))
1677           pidl = ILGetNext(pidl);
1678
1679         if (pidl && _ILIsDrive(pidl))
1680           return _ILSimpleGetText(pidl, pOut, uSize);
1681
1682         return 0;
1683 }
1684
1685 /**************************************************************************
1686  *
1687  *      ### 2. section testing pidls ###
1688  *
1689  **************************************************************************
1690  *  _ILIsDesktop()
1691  *  _ILIsMyComputer()
1692  *  _ILIsSpecialFolder()
1693  *  _ILIsDrive()
1694  *  _ILIsFolder()
1695  *  _ILIsValue()
1696  *  _ILIsPidlSimple()
1697  */
1698 BOOL _ILIsDesktop(LPCITEMIDLIST pidl)
1699 {       TRACE("(%p)\n",pidl);
1700         return pidl && pidl->mkid.cb  ? 0 : 1;
1701 }
1702
1703 BOOL _ILIsMyComputer(LPCITEMIDLIST pidl)
1704 {
1705         REFIID iid = _ILGetGUIDPointer(pidl);
1706
1707         TRACE("(%p)\n",pidl);
1708
1709         if (iid)
1710           return IsEqualIID(iid, &CLSID_MyComputer);
1711         return FALSE;
1712 }
1713
1714 BOOL _ILIsSpecialFolder (LPCITEMIDLIST pidl)
1715 {
1716         LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
1717         TRACE("(%p)\n",pidl);
1718         return (pidl && ( (lpPData && (PT_GUID== lpPData->type || PT_SHELLEXT== lpPData->type)) ||
1719                           (pidl && pidl->mkid.cb == 0x00)
1720                         ));
1721 }
1722
1723 BOOL _ILIsDrive(LPCITEMIDLIST pidl)
1724 {       LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
1725         TRACE("(%p)\n",pidl);
1726         return (pidl && lpPData && (PT_DRIVE == lpPData->type ||
1727                                     PT_DRIVE1 == lpPData->type ||
1728                                     PT_DRIVE2 == lpPData->type ||
1729                                     PT_DRIVE3 == lpPData->type));
1730 }
1731
1732 BOOL _ILIsFolder(LPCITEMIDLIST pidl)
1733 {       LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
1734         TRACE("(%p)\n",pidl);
1735         return (pidl && lpPData && (PT_FOLDER == lpPData->type || PT_FOLDER1 == lpPData->type));
1736 }
1737
1738 BOOL _ILIsValue(LPCITEMIDLIST pidl)
1739 {       LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
1740         TRACE("(%p)\n",pidl);
1741         return (pidl && lpPData && PT_VALUE == lpPData->type);
1742 }
1743
1744 BOOL _ILIsCPanelStruct(LPCITEMIDLIST pidl)
1745 {       LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
1746         TRACE("(%p)\n",pidl);
1747         return (pidl && lpPData && (lpPData->type == 0));
1748 }
1749
1750 /**************************************************************************
1751  *      _ILIsPidlSimple
1752  */
1753 BOOL _ILIsPidlSimple ( LPCITEMIDLIST pidl)
1754 {
1755         BOOL ret = TRUE;
1756
1757         if(! _ILIsDesktop(pidl))        /* pidl=NULL or mkid.cb=0 */
1758         {
1759           WORD len = pidl->mkid.cb;
1760           LPCITEMIDLIST pidlnext = (LPCITEMIDLIST) (((const BYTE*)pidl) + len );
1761           if (pidlnext->mkid.cb)
1762             ret = FALSE;
1763         }
1764
1765         TRACE("%s\n", ret ? "Yes" : "No");
1766         return ret;
1767 }
1768
1769 /**************************************************************************
1770  *
1771  *      ### 3. section getting values from pidls ###
1772  */
1773
1774  /**************************************************************************
1775  *  _ILSimpleGetText
1776  *
1777  * gets the text for the first item in the pidl (eg. simple pidl)
1778  *
1779  * returns the length of the string
1780  */
1781 DWORD _ILSimpleGetText (LPCITEMIDLIST pidl, LPSTR szOut, UINT uOutSize)
1782 {
1783         DWORD           dwReturn=0;
1784         LPSTR           szSrc;
1785         GUID const *    riid;
1786         char szTemp[MAX_PATH];
1787
1788         TRACE("(%p %p %x)\n",pidl,szOut,uOutSize);
1789
1790         if (!pidl) return 0;
1791
1792         if (szOut)
1793           *szOut = 0;
1794
1795         if (_ILIsDesktop(pidl))
1796         {
1797          /* desktop */
1798           if (HCR_GetClassNameA(&CLSID_ShellDesktop, szTemp, MAX_PATH))
1799           {
1800             if (szOut)
1801               lstrcpynA(szOut, szTemp, uOutSize);
1802
1803             dwReturn = strlen (szTemp);
1804           }
1805         }
1806         else if (( szSrc = _ILGetTextPointer(pidl) ))
1807         {
1808           /* filesystem */
1809           if (szOut)
1810             lstrcpynA(szOut, szSrc, uOutSize);
1811
1812           dwReturn = strlen(szSrc);
1813         }
1814         else if (( riid = _ILGetGUIDPointer(pidl) ))
1815         {
1816           /* special folder */
1817           if ( HCR_GetClassNameA(riid, szTemp, MAX_PATH) )
1818           {
1819             if (szOut)
1820               lstrcpynA(szOut, szTemp, uOutSize);
1821
1822             dwReturn = strlen (szTemp);
1823           }
1824         }
1825         else
1826         {
1827           ERR("-- no text\n");
1828         }
1829
1830         TRACE("-- (%p=%s 0x%08lx)\n",szOut,debugstr_a(szOut),dwReturn);
1831         return dwReturn;
1832 }
1833
1834  /**************************************************************************
1835  *  _ILSimpleGetTextW
1836  *
1837  * gets the text for the first item in the pidl (eg. simple pidl)
1838  *
1839  * returns the length of the string
1840  */
1841 DWORD _ILSimpleGetTextW (LPCITEMIDLIST pidl, LPWSTR szOut, UINT uOutSize)
1842 {
1843         DWORD   dwReturn;
1844         char    szTemp[MAX_PATH];
1845
1846         TRACE("(%p %p %x)\n",pidl,szOut,uOutSize);
1847
1848         dwReturn = _ILSimpleGetText(pidl, szTemp, uOutSize);
1849
1850         if (!MultiByteToWideChar(CP_ACP, 0, szTemp, -1, szOut, MAX_PATH))
1851                 *szOut = 0;
1852
1853         TRACE("-- (%p=%s 0x%08lx)\n",szOut,debugstr_w(szOut),dwReturn);
1854         return dwReturn;
1855 }
1856
1857 /**************************************************************************
1858  *
1859  *      ### 4. getting pointers to parts of pidls ###
1860  *
1861  **************************************************************************
1862  *  _ILGetDataPointer()
1863  */
1864 LPPIDLDATA _ILGetDataPointer(LPCITEMIDLIST pidl)
1865 {
1866         if(pidl && pidl->mkid.cb != 0x00)
1867           return (LPPIDLDATA) &(pidl->mkid.abID);
1868         return NULL;
1869 }
1870
1871 /**************************************************************************
1872  *  _ILGetTextPointer()
1873  * gets a pointer to the long filename string stored in the pidl
1874  */
1875 LPSTR _ILGetTextPointer(LPCITEMIDLIST pidl)
1876 {/*     TRACE(pidl,"(pidl%p)\n", pidl);*/
1877
1878         LPPIDLDATA pdata = _ILGetDataPointer(pidl);
1879
1880         if (pdata)
1881         {
1882           switch (pdata->type)
1883           {
1884             case PT_GUID:
1885             case PT_SHELLEXT:
1886             case PT_YAGUID:
1887               return NULL;
1888
1889             case PT_DRIVE:
1890             case PT_DRIVE1:
1891             case PT_DRIVE2:
1892             case PT_DRIVE3:
1893               return (LPSTR)&(pdata->u.drive.szDriveName);
1894
1895             case PT_FOLDER:
1896             case PT_FOLDER1:
1897             case PT_VALUE:
1898             case PT_IESPECIAL1:
1899             case PT_IESPECIAL2:
1900               return (LPSTR)&(pdata->u.file.szNames);
1901
1902             case PT_WORKGRP:
1903             case PT_COMP:
1904             case PT_NETWORK:
1905             case PT_NETPROVIDER:
1906             case PT_SHARE:
1907               return (LPSTR)&(pdata->u.network.szNames);
1908           }
1909         }
1910         return NULL;
1911 }
1912
1913 /**************************************************************************
1914  *  _ILGetSTextPointer()
1915  * gets a pointer to the short filename string stored in the pidl
1916  */
1917 LPSTR _ILGetSTextPointer(LPCITEMIDLIST pidl)
1918 {/*     TRACE(pidl,"(pidl%p)\n", pidl);*/
1919
1920         LPPIDLDATA pdata =_ILGetDataPointer(pidl);
1921
1922         if (pdata)
1923         {
1924           switch (pdata->type)
1925           {
1926             case PT_FOLDER:
1927             case PT_VALUE:
1928             case PT_IESPECIAL1:
1929             case PT_IESPECIAL2:
1930               return (LPSTR)(pdata->u.file.szNames + strlen (pdata->u.file.szNames) + 1);
1931
1932             case PT_WORKGRP:
1933               return (LPSTR)(pdata->u.network.szNames + strlen (pdata->u.network.szNames) + 1);
1934           }
1935         }
1936         return NULL;
1937 }
1938
1939 /**************************************************************************
1940  * _ILGetGUIDPointer()
1941  *
1942  * returns reference to guid stored in some pidls
1943  */
1944 IID* _ILGetGUIDPointer(LPCITEMIDLIST pidl)
1945 {
1946         LPPIDLDATA pdata =_ILGetDataPointer(pidl);
1947
1948         TRACE("%p\n", pidl);
1949
1950         if (pdata)
1951         {
1952           TRACE("pdata->type 0x%04x\n", pdata->type);
1953           switch (pdata->type)
1954           {
1955             case PT_SHELLEXT:
1956             case PT_GUID:
1957               return &(pdata->u.guid.guid);
1958
1959             default:
1960                 TRACE("Unknown pidl type 0x%04x\n", pdata->type);
1961                 break;
1962           }
1963         }
1964         return NULL;
1965 }
1966
1967 /*************************************************************************
1968  * _ILGetFileDateTime
1969  *
1970  * Given the ItemIdList, get the FileTime
1971  *
1972  * PARAMS
1973  *      pidl        [I] The ItemIDList
1974  *      pFt         [I] the resulted FILETIME of the file
1975  *
1976  * RETURNS
1977  *     True if Successful
1978  *
1979  * NOTES
1980  *
1981  */
1982 BOOL _ILGetFileDateTime(LPCITEMIDLIST pidl, FILETIME *pFt)
1983 {
1984     LPPIDLDATA pdata = _ILGetDataPointer(pidl);
1985
1986     if(! pdata) return FALSE;
1987
1988     switch (pdata->type)
1989     {
1990         case PT_FOLDER:
1991         case PT_VALUE:
1992             DosDateTimeToFileTime(pdata->u.file.uFileDate, pdata->u.file.uFileTime, pFt);
1993             break;
1994         default:
1995             return FALSE;
1996     }
1997     return TRUE;
1998 }
1999
2000 BOOL _ILGetFileDate (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize)
2001 {
2002         FILETIME ft,lft;
2003         SYSTEMTIME time;
2004         BOOL ret;
2005
2006         if (_ILGetFileDateTime( pidl, &ft )) {
2007             FileTimeToLocalFileTime(&ft, &lft);
2008             FileTimeToSystemTime (&lft, &time);
2009             ret = GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&time, NULL,  pOut, uOutSize);
2010         } else {
2011             pOut[0] = '\0';
2012             ret = FALSE;
2013         }
2014         return ret;
2015
2016 }
2017
2018 /*************************************************************************
2019  * _ILGetFileSize
2020  *
2021  * Given the ItemIdList, get the FileSize
2022  *
2023  * PARAMS
2024  *      pidl    [I] The ItemIDList
2025  *      pOut    [I] The buffer to save the result
2026  *      uOutsize [I] The size of the buffer
2027  *
2028  * RETURNS
2029  *     The FileSize
2030  *
2031  * NOTES
2032  *      pOut can be null when no string is needed
2033  *
2034  */
2035 DWORD _ILGetFileSize (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize)
2036 {
2037         LPPIDLDATA pdata = _ILGetDataPointer(pidl);
2038         DWORD dwSize;
2039
2040         if(! pdata) return 0;
2041
2042         switch (pdata->type)
2043         {
2044           case PT_VALUE:
2045             dwSize = pdata->u.file.dwFileSize;
2046             if (pOut) StrFormatByteSizeA(dwSize, pOut, uOutSize);
2047             return dwSize;
2048         }
2049         if (pOut) *pOut = 0x00;
2050         return 0;
2051 }
2052
2053 BOOL _ILGetExtension (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize)
2054 {
2055         char szTemp[MAX_PATH];
2056         const char * pPoint;
2057         LPCITEMIDLIST  pidlTemp=pidl;
2058
2059         TRACE("pidl=%p\n",pidl);
2060
2061         if (!pidl) return FALSE;
2062
2063         pidlTemp = ILFindLastID(pidl);
2064
2065         if (!_ILIsValue(pidlTemp)) return FALSE;
2066         if (!_ILSimpleGetText(pidlTemp, szTemp, MAX_PATH)) return FALSE;
2067
2068         pPoint = PathFindExtensionA(szTemp);
2069
2070         if (! *pPoint) return FALSE;
2071
2072         pPoint++;
2073         lstrcpynA(pOut, pPoint, uOutSize);
2074         TRACE("%s\n",pOut);
2075
2076         return TRUE;
2077 }
2078
2079 /*************************************************************************
2080  * _ILGetFileType
2081  *
2082  * Given the ItemIdList, get the file type description
2083  *
2084  * PARAMS
2085  *      pidl        [I] The ItemIDList (simple)
2086  *      pOut        [I] The buffer to save the result
2087  *      uOutsize    [I] The size of the buffer
2088  *
2089  * RETURNS
2090  *      nothing
2091  *
2092  * NOTES
2093  *      This function copies as much as possible into the buffer.
2094  */
2095 void _ILGetFileType(LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize)
2096 {
2097         if(_ILIsValue(pidl))
2098         {
2099           char sTemp[64];
2100           if(uOutSize > 0)
2101           {
2102             pOut[0] = 0;
2103           }
2104           if (_ILGetExtension (pidl, sTemp, 64))
2105           {
2106             if (!( HCR_MapTypeToValueA(sTemp, sTemp, 64, TRUE)
2107                 && HCR_MapTypeToValueA(sTemp, pOut, uOutSize, FALSE )))
2108             {
2109               lstrcpynA (pOut, sTemp, uOutSize - 6);
2110               strcat (pOut, "-file");
2111             }
2112           }
2113         }
2114         else
2115         {
2116           lstrcpynA(pOut, "Folder", uOutSize);
2117         }
2118 }
2119
2120 /*************************************************************************
2121  * _ILGetFileAttributes
2122  *
2123  * Given the ItemIdList, get the Attrib string format
2124  *
2125  * PARAMS
2126  *      pidl        [I] The ItemIDList
2127  *      pOut        [I] The buffer to save the result
2128  *      uOutsize    [I] The size of the Buffer
2129  *
2130  * RETURNS
2131  *     Attributes
2132  *
2133  * FIXME
2134  *  return value 0 in case of error is a valid return value
2135  *
2136  */
2137 DWORD _ILGetFileAttributes(LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize)
2138 {
2139         LPPIDLDATA pData = _ILGetDataPointer(pidl);
2140         WORD wAttrib = 0;
2141         int i;
2142
2143         if(! pData) return 0;
2144
2145         switch(pData->type)
2146         {
2147           case PT_FOLDER:
2148           case PT_VALUE:
2149             wAttrib = pData->u.file.uFileAttribs;
2150             break;
2151         }
2152
2153         if(uOutSize >= 6)
2154         {
2155           i=0;
2156           if(wAttrib & FILE_ATTRIBUTE_READONLY)
2157           {
2158             pOut[i++] = 'R';
2159           }
2160           if(wAttrib & FILE_ATTRIBUTE_HIDDEN)
2161           {
2162             pOut[i++] = 'H';
2163           }
2164           if(wAttrib & FILE_ATTRIBUTE_SYSTEM)
2165           {
2166             pOut[i++] = 'S';
2167           }
2168           if(wAttrib & FILE_ATTRIBUTE_ARCHIVE)
2169           {
2170             pOut[i++] = 'A';
2171           }
2172           if(wAttrib & FILE_ATTRIBUTE_COMPRESSED)
2173           {
2174             pOut[i++] = 'C';
2175           }
2176           pOut[i] = 0x00;
2177         }
2178         return wAttrib;
2179 }
2180
2181 /*************************************************************************
2182 * ILFreeaPidl
2183 *
2184 * free a aPidl struct
2185 */
2186 void _ILFreeaPidl(LPITEMIDLIST * apidl, UINT cidl)
2187 {
2188         UINT   i;
2189
2190         if (apidl)
2191         {
2192           for (i = 0; i < cidl; i++) SHFree(apidl[i]);
2193           SHFree(apidl);
2194         }
2195 }
2196
2197 /*************************************************************************
2198 * ILCopyaPidl
2199 *
2200 * copies an aPidl struct
2201 */
2202 LPITEMIDLIST* _ILCopyaPidl(LPCITEMIDLIST * apidlsrc, UINT cidl)
2203 {
2204         UINT i;
2205         LPITEMIDLIST * apidldest = (LPITEMIDLIST*)SHAlloc(cidl * sizeof(LPITEMIDLIST));
2206         if(!apidlsrc) return NULL;
2207
2208         for (i = 0; i < cidl; i++)
2209           apidldest[i] = ILClone(apidlsrc[i]);
2210
2211         return apidldest;
2212 }
2213
2214 /*************************************************************************
2215 * _ILCopyCidaToaPidl
2216 *
2217 * creates aPidl from CIDA
2218 */
2219 LPITEMIDLIST* _ILCopyCidaToaPidl(LPITEMIDLIST* pidl, LPIDA cida)
2220 {
2221         UINT i;
2222         LPITEMIDLIST * dst = (LPITEMIDLIST*)SHAlloc(cida->cidl * sizeof(LPITEMIDLIST));
2223
2224         if(!dst) return NULL;
2225
2226         if (pidl)
2227           *pidl = ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[0]]));
2228
2229         for (i = 0; i < cida->cidl; i++)
2230           dst[i] = ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[i + 1]]));
2231
2232         return dst;
2233 }