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