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