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