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