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