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