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