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