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