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