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