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