Implement ResetDC and PHYSICALOFFSET[X|Y] devcaps.
[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 "wine/debug.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(pidl);
42 WINE_DECLARE_DEBUG_CHANNEL(shell);
43
44 void pdump (LPCITEMIDLIST pidl)
45 {
46         LPITEMIDLIST pidltemp = pidl;
47         if (!TRACE_ON(pidl))
48           return;
49
50         if (! pidltemp)
51         {
52           MESSAGE ("-------- pidl=NULL (Desktop)\n");
53         }
54         else
55         {
56           MESSAGE ("-------- pidl=%p\n", pidl);
57           if (pidltemp->mkid.cb)
58           { 
59             do
60             {
61               DWORD dwAttrib = 0;
62               LPPIDLDATA pData   = _ILGetDataPointer(pidltemp);
63               DWORD type         = pData->type;
64               LPSTR szLongName   = _ILGetTextPointer(pidltemp);
65               LPSTR szShortName  = _ILGetSTextPointer(pidltemp);
66               char szName[MAX_PATH];
67
68               _ILSimpleGetText(pidltemp, szName, MAX_PATH);
69               if( PT_FOLDER == type)
70                 dwAttrib = pData->u.folder.uFileAttribs;
71               else if( PT_VALUE == type)
72                 dwAttrib = pData->u.file.uFileAttribs;
73
74               MESSAGE ("-- pidl=%p size=%u type=%lx attr=0x%08lx name=%s (%s,%s)\n",
75                        pidltemp, pidltemp->mkid.cb,type,dwAttrib,szName,debugstr_a(szLongName), debugstr_a(szShortName));
76
77               pidltemp = ILGetNext(pidltemp);
78
79             } while (pidltemp->mkid.cb);
80           }
81           else
82           {
83             MESSAGE ("empty pidl (Desktop)\n");
84           }
85           pcheck(pidl);
86         }
87 }
88 #define BYTES_PRINTED 32
89 BOOL pcheck (LPCITEMIDLIST pidl)
90 {
91         DWORD type, ret=TRUE;
92         LPITEMIDLIST pidltemp = pidl;
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         return ret;
140 }
141
142 /*************************************************************************
143  * ILGetDisplayName                     [SHELL32.15]
144  */
145 BOOL WINAPI ILGetDisplayName(LPCITEMIDLIST pidl,LPSTR path)
146 {
147         TRACE_(shell)("pidl=%p %p semi-stub\n",pidl,path);
148         return SHGetPathFromIDListA(pidl, path);
149 }
150 /*************************************************************************
151  * ILFindLastID [SHELL32.16]
152  *
153  * NOTES
154  *   observed: pidl=Desktop return=pidl
155  */
156 LPITEMIDLIST WINAPI ILFindLastID(LPITEMIDLIST pidl) 
157 {       LPITEMIDLIST   pidlLast = pidl;
158
159         TRACE("(pidl=%p)\n",pidl);
160
161         while (pidl->mkid.cb)
162         {
163           pidlLast = pidl;
164           pidl = ILGetNext(pidl);
165         }
166         return pidlLast;                
167 }
168 /*************************************************************************
169  * ILRemoveLastID [SHELL32.17]
170  *
171  * NOTES
172  *   when pidl=Desktop return=FALSE
173  */
174 BOOL WINAPI ILRemoveLastID(LPCITEMIDLIST pidl)
175 {
176         TRACE_(shell)("pidl=%p\n",pidl);
177
178         if (!pidl || !pidl->mkid.cb)
179           return 0;
180         ILFindLastID(pidl)->mkid.cb = 0;
181         return 1;
182 }
183
184 /*************************************************************************
185  * ILClone [SHELL32.18]
186  *
187  * NOTES
188  *    duplicate an idlist
189  */
190 LPITEMIDLIST WINAPI ILClone (LPCITEMIDLIST pidl)
191 { DWORD    len;
192   LPITEMIDLIST  newpidl;
193
194   if (!pidl)
195     return NULL;
196     
197   len = ILGetSize(pidl);
198   newpidl = (LPITEMIDLIST)SHAlloc(len);
199   if (newpidl)
200     memcpy(newpidl,pidl,len);
201
202   TRACE("pidl=%p newpidl=%p\n",pidl, newpidl);
203   pdump(pidl);
204
205   return newpidl;
206 }
207 /*************************************************************************
208  * ILCloneFirst [SHELL32.19]
209  *
210  * NOTES
211  *  duplicates the first idlist of a complex pidl
212  */
213 LPITEMIDLIST WINAPI ILCloneFirst(LPCITEMIDLIST pidl)
214 {       DWORD len;
215         LPITEMIDLIST pidlNew = NULL;
216         
217         TRACE("pidl=%p \n",pidl);
218         pdump(pidl);
219         
220         if (pidl)
221         {
222           len = pidl->mkid.cb;  
223           pidlNew = (LPITEMIDLIST) SHAlloc (len+2);
224           if (pidlNew)
225           {
226             memcpy(pidlNew,pidl,len+2);         /* 2 -> mind a desktop pidl */
227
228             if (len)
229               ILGetNext(pidlNew)->mkid.cb = 0x00;
230           }
231         }
232         TRACE("-- newpidl=%p\n",pidlNew);
233
234         return pidlNew;
235 }
236
237 /*************************************************************************
238  * ILLoadFromStream (SHELL32.26)
239  *
240  * NOTES
241  *   the first two bytes are the len, the pidl is following then
242  */
243 HRESULT WINAPI ILLoadFromStream (IStream * pStream, LPITEMIDLIST * ppPidl)
244 {       WORD            wLen = 0;
245         DWORD           dwBytesRead;
246         HRESULT         ret = E_FAIL;
247         
248
249         TRACE_(shell)("%p %p\n", pStream ,  ppPidl);
250
251         if (*ppPidl)
252         { SHFree(*ppPidl);
253           *ppPidl = NULL;
254         }
255         
256         IStream_AddRef (pStream);
257
258         if (SUCCEEDED(IStream_Read(pStream, (LPVOID)&wLen, 2, &dwBytesRead)))
259         { *ppPidl = SHAlloc (wLen);
260           if (SUCCEEDED(IStream_Read(pStream, *ppPidl , wLen, &dwBytesRead)))
261           { ret = S_OK;
262           }
263           else
264           { SHFree(*ppPidl);
265             *ppPidl = NULL;
266           }
267         }
268         
269         /* we are not yet fully compatible */
270         if (!pcheck(*ppPidl))
271         { SHFree(*ppPidl);
272           *ppPidl = NULL;
273         }
274         
275
276         IStream_Release (pStream);
277
278         return ret;
279 }
280
281 /*************************************************************************
282  * ILSaveToStream (SHELL32.27)
283  *
284  * NOTES
285  *   the first two bytes are the len, the pidl is following then
286  */
287 HRESULT WINAPI ILSaveToStream (IStream * pStream, LPCITEMIDLIST pPidl)
288 {
289         LPITEMIDLIST    pidl;
290         WORD            wLen = 0;
291         HRESULT         ret = E_FAIL;
292         
293         TRACE_(shell)("%p %p\n", pStream, pPidl);
294
295         IStream_AddRef (pStream);
296
297         pidl = pPidl;
298         while (pidl->mkid.cb)
299         {
300           wLen += sizeof(WORD) + pidl->mkid.cb;
301           pidl = ILGetNext(pidl);
302         }
303
304         if (SUCCEEDED(IStream_Write(pStream, (LPVOID)&wLen, 2, NULL)))
305         {
306           if (SUCCEEDED(IStream_Write(pStream, pPidl, wLen, NULL)))
307           { ret = S_OK;
308           }
309         }
310         
311
312         IStream_Release (pStream);
313
314         return ret;
315 }
316
317 /*************************************************************************
318  * SHILCreateFromPath   [SHELL32.28]
319  *
320  * NOTES
321  *   wraper for IShellFolder::ParseDisplayName()
322  */
323 HRESULT WINAPI SHILCreateFromPathA (LPCSTR path, LPITEMIDLIST * ppidl, DWORD * attributes)
324 {       LPSHELLFOLDER sf;
325         WCHAR lpszDisplayName[MAX_PATH];
326         DWORD pchEaten;
327         HRESULT ret = E_FAIL;
328         
329         TRACE_(shell)("%s %p 0x%08lx\n",path,ppidl,attributes?*attributes:0);
330
331         if (!MultiByteToWideChar( CP_ACP, 0, path, -1, lpszDisplayName, MAX_PATH ))
332             lpszDisplayName[MAX_PATH-1] = 0;
333
334         if (SUCCEEDED (SHGetDesktopFolder(&sf)))
335         {
336           ret = IShellFolder_ParseDisplayName(sf,0, NULL,lpszDisplayName,&pchEaten,ppidl,attributes);
337           IShellFolder_Release(sf);
338         }
339         return ret;
340 }
341 HRESULT WINAPI SHILCreateFromPathW (LPCWSTR path, LPITEMIDLIST * ppidl, DWORD * attributes)
342 {       LPSHELLFOLDER sf;
343         DWORD pchEaten;
344         HRESULT ret = E_FAIL;
345         
346         TRACE_(shell)("%s %p 0x%08lx\n",debugstr_w(path),ppidl,attributes?*attributes:0);
347
348         if (SUCCEEDED (SHGetDesktopFolder(&sf)))
349         {
350           ret = IShellFolder_ParseDisplayName(sf,0, NULL, (LPWSTR) path, &pchEaten, ppidl, attributes);
351           IShellFolder_Release(sf);
352         }
353         return ret;
354 }
355 HRESULT WINAPI SHILCreateFromPathAW (LPCVOID path, LPITEMIDLIST * ppidl, DWORD * attributes)
356 {
357         if ( SHELL_OsIsUnicode())
358           return SHILCreateFromPathW (path, ppidl, attributes);
359         return SHILCreateFromPathA (path, ppidl, attributes);
360 }
361
362 /*************************************************************************
363  * SHCloneSpecialIDList [SHELL32.89]
364  * 
365  * PARAMETERS
366  *  hwndOwner   [in] 
367  *  nFolder     [in]    CSIDL_xxxxx ??
368  *
369  * RETURNS
370  *  pidl ??
371  * NOTES
372  *     exported by ordinal
373  */
374 LPITEMIDLIST WINAPI SHCloneSpecialIDList(HWND hwndOwner,DWORD nFolder,DWORD x3)
375 {       LPITEMIDLIST ppidl;
376         WARN_(shell)("(hwnd=0x%x,csidl=0x%lx,0x%lx):semi-stub.\n",
377                                          hwndOwner,nFolder,x3);
378
379         SHGetSpecialFolderLocation(hwndOwner, nFolder, &ppidl);
380
381         return ppidl;
382 }
383
384 /*************************************************************************
385  * ILGlobalClone [SHELL32.20]
386  *
387  */
388 LPITEMIDLIST WINAPI ILGlobalClone(LPCITEMIDLIST pidl)
389 {       DWORD    len;
390         LPITEMIDLIST  newpidl;
391
392         if (!pidl)
393           return NULL;
394     
395         len = ILGetSize(pidl);
396         newpidl = (LPITEMIDLIST)pCOMCTL32_Alloc(len);
397         if (newpidl)
398           memcpy(newpidl,pidl,len);
399
400         TRACE("pidl=%p newpidl=%p\n",pidl, newpidl);
401         pdump(pidl);
402
403         return newpidl;
404 }
405
406 /*************************************************************************
407  * ILIsEqual [SHELL32.21]
408  *
409  */
410 BOOL WINAPI ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
411 {
412         char    szData1[MAX_PATH];
413         char    szData2[MAX_PATH];
414
415         LPITEMIDLIST pidltemp1 = pidl1;
416         LPITEMIDLIST pidltemp2 = pidl2;
417
418         TRACE("pidl1=%p pidl2=%p\n",pidl1, pidl2);
419
420         /* explorer reads from registry directly (StreamMRU),
421            so we can only check here */
422         if ((!pcheck (pidl1)) || (!pcheck (pidl2))) return FALSE;
423
424         pdump (pidl1);
425         pdump (pidl2);
426
427         if ( (!pidl1) || (!pidl2) ) return FALSE;
428         
429         while (pidltemp1->mkid.cb && pidltemp2->mkid.cb)
430         {
431             _ILSimpleGetText(pidltemp1, szData1, MAX_PATH);
432             _ILSimpleGetText(pidltemp2, szData2, MAX_PATH);
433
434             if (strcasecmp ( szData1, szData2 )!=0 )
435               return FALSE;
436
437             pidltemp1 = ILGetNext(pidltemp1);
438             pidltemp2 = ILGetNext(pidltemp2);
439         }       
440
441         if (!pidltemp1->mkid.cb && !pidltemp2->mkid.cb)
442         {
443           return TRUE;
444         }
445
446         return FALSE;
447 }
448 /*************************************************************************
449  * ILIsParent [SHELL32.23]
450  *
451  * parent=a/b   child=a/b/c -> true, c is in folder a/b
452  *              child=a/b/c/d -> false if bImmediate is true, d is not in folder a/b
453  *              child=a/b/c/d -> true if bImmediate is false, d is in a subfolder of a/b
454  */
455 BOOL WINAPI ILIsParent( LPCITEMIDLIST pidlParent, LPCITEMIDLIST pidlChild, BOOL bImmediate)
456 {
457         char    szData1[MAX_PATH];
458         char    szData2[MAX_PATH];
459
460         LPITEMIDLIST pParent = pidlParent;
461         LPITEMIDLIST pChild = pidlChild;
462         
463         TRACE("%p %p %x\n", pidlParent, pidlChild, bImmediate);
464
465         while (pParent->mkid.cb && pChild->mkid.cb)
466         {
467           _ILSimpleGetText(pParent, szData1, MAX_PATH);
468           _ILSimpleGetText(pChild, szData2, MAX_PATH);
469
470           if (strcasecmp ( szData1, szData2 )!=0 )
471             return FALSE;
472
473           pParent = ILGetNext(pParent);
474           pChild = ILGetNext(pChild);
475         }       
476         
477         if ( pParent->mkid.cb || ! pChild->mkid.cb)     /* child shorter or has equal length to parent */
478           return FALSE;
479         
480         if ( ILGetNext(pChild)->mkid.cb && bImmediate)  /* not immediate descent */
481           return FALSE;
482         
483         return TRUE;
484 }
485
486 /*************************************************************************
487  * ILFindChild [SHELL32.24]
488  *
489  * NOTES
490  *  Compares elements from pidl1 and pidl2.
491  *
492  *  pidl1 is desktop            pidl2
493  *  pidl1 shorter pidl2         pointer to first different element of pidl2
494  *                              if there was at least one equal element
495  *  pidl2 shorter pidl1         0
496  *  pidl2 equal pidl1           pointer to last 0x00-element of pidl2
497  */
498 LPITEMIDLIST WINAPI ILFindChild(LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2)
499 {
500         char    szData1[MAX_PATH];
501         char    szData2[MAX_PATH];
502
503         LPITEMIDLIST pidltemp1 = pidl1;
504         LPITEMIDLIST pidltemp2 = pidl2;
505         LPITEMIDLIST ret=NULL;
506
507         TRACE("pidl1=%p pidl2=%p\n",pidl1, pidl2);
508
509         /* explorer reads from registry directly (StreamMRU),
510            so we can only check here */
511         if ((!pcheck (pidl1)) || (!pcheck (pidl2)))
512           return FALSE;
513
514         pdump (pidl1);
515         pdump (pidl2);
516
517         if ( _ILIsDesktop(pidl1) )
518         {
519           ret = pidl2;
520         }
521         else
522         {
523           while (pidltemp1->mkid.cb && pidltemp2->mkid.cb)
524           {
525             _ILSimpleGetText(pidltemp1, szData1, MAX_PATH);
526             _ILSimpleGetText(pidltemp2, szData2, MAX_PATH);
527
528             if (strcasecmp(szData1,szData2))
529               break;
530
531             pidltemp1 = ILGetNext(pidltemp1);
532             pidltemp2 = ILGetNext(pidltemp2);
533             ret = pidltemp2;    
534           }
535
536           if (pidltemp1->mkid.cb)
537           {
538             ret = NULL; /* elements of pidl1 left*/
539           }
540         }
541         TRACE_(shell)("--- %p\n", ret);
542         return ret; /* pidl 1 is shorter */
543 }
544
545 /*************************************************************************
546  * ILCombine [SHELL32.25]
547  *
548  * NOTES
549  *  Concatenates two complex idlists.
550  *  The pidl is the first one, pidlsub the next one
551  *  Does not destroy the passed in idlists!
552  */
553 LPITEMIDLIST WINAPI ILCombine(LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2)
554 {
555         DWORD    len1,len2;
556         LPITEMIDLIST  pidlNew;
557         
558         TRACE("pidl=%p pidl=%p\n",pidl1,pidl2);
559
560         if(!pidl1 && !pidl2) return NULL;
561
562         pdump (pidl1);
563         pdump (pidl2);
564
565         if(!pidl1)
566         {
567           pidlNew = ILClone(pidl2);
568           return pidlNew;
569         }
570
571         if(!pidl2)
572         {
573           pidlNew = ILClone(pidl1);
574           return pidlNew;
575         }
576
577         len1  = ILGetSize(pidl1)-2;
578         len2  = ILGetSize(pidl2);
579         pidlNew  = SHAlloc(len1+len2);
580
581         if (pidlNew)
582         {
583           memcpy(pidlNew,pidl1,len1);
584           memcpy(((BYTE *)pidlNew)+len1,pidl2,len2);
585         }
586
587         /*  TRACE(pidl,"--new pidl=%p\n",pidlNew);*/
588         return pidlNew;
589 }
590 /*************************************************************************
591  *  SHGetRealIDL [SHELL32.98]
592  *
593  * NOTES
594  */
595 LPITEMIDLIST WINAPI SHGetRealIDL(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl, DWORD z)
596 {
597         FIXME("sf=%p pidl=%p 0x%04lx\n",lpsf,pidl,z);
598
599         pdump (pidl);
600         return 0;
601 }
602
603 /*************************************************************************
604  *  SHLogILFromFSIL [SHELL32.95]
605  *
606  * NOTES
607  *  pild = CSIDL_DESKTOP        ret = 0
608  *  pild = CSIDL_DRIVES         ret = 0
609  */
610 LPITEMIDLIST WINAPI SHLogILFromFSIL(LPITEMIDLIST pidl)
611 {
612         FIXME("(pidl=%p)\n",pidl);
613
614         pdump(pidl);
615
616         return 0;
617 }
618
619 /*************************************************************************
620  * ILGetSize [SHELL32.152]
621  *  gets the byte size of an idlist including zero terminator (pidl)
622  *
623  * PARAMETERS
624  *  pidl ITEMIDLIST
625  *
626  * RETURNS
627  *  size of pidl
628  *
629  * NOTES
630  *  exported by ordinal
631  */
632 DWORD WINAPI ILGetSize(LPITEMIDLIST pidl)
633 {
634         LPSHITEMID si = &(pidl->mkid);
635         DWORD  len=0;
636
637         if (pidl)
638         { while (si->cb) 
639           { len += si->cb;
640             si  = (LPSHITEMID)(((LPBYTE)si)+si->cb);
641           }
642           len += 2;
643         }
644         TRACE("pidl=%p size=%lu\n",pidl, len);
645         return len;
646 }
647
648 /*************************************************************************
649  * ILGetNext [SHELL32.153]
650  *  gets the next simple pidl of a complex pidl
651  *
652  * observed return values:
653  *  null -> null
654  *  desktop -> null
655  *  simple pidl -> pointer to 0x0000 element
656  *
657  */
658 LPITEMIDLIST WINAPI ILGetNext(LPITEMIDLIST pidl)
659 {
660         WORD len;
661
662         if(pidl)
663         {
664           len =  pidl->mkid.cb;
665           if (len)
666           {
667             pidl = (LPITEMIDLIST) (((LPBYTE)pidl)+len);
668             return pidl;
669           }
670         }
671         return NULL;
672 }
673 /*************************************************************************
674  * ILAppend [SHELL32.154]
675  *
676  * NOTES
677  *  Adds the single item to the idlist indicated by pidl.
678  *  if bEnd is 0, adds the item to the front of the list,
679  *  otherwise adds the item to the end. (???)
680  *  Destroys the passed in idlist! (???)
681  */
682 LPITEMIDLIST WINAPI ILAppend(LPITEMIDLIST pidl,LPCITEMIDLIST item,BOOL bEnd)
683 {
684         LPITEMIDLIST idlRet;
685
686         WARN("(pidl=%p,pidl=%p,%08u)semi-stub\n",pidl,item,bEnd);
687
688         pdump (pidl);
689         pdump (item);
690         
691         if (_ILIsDesktop(pidl))
692         {
693            idlRet = ILClone(item);
694            if (pidl)
695              SHFree (pidl);
696            return idlRet;
697         }
698
699         if (bEnd)
700         {
701           idlRet=ILCombine(pidl,item);
702         }
703         else
704         {
705           idlRet=ILCombine(item,pidl);
706         }
707
708         SHFree(pidl);
709         return idlRet;
710 }
711 /*************************************************************************
712  * ILFree [SHELL32.155]
713  *
714  * NOTES
715  *     free_check_ptr - frees memory (if not NULL)
716  *     allocated by SHMalloc allocator
717  *     exported by ordinal
718  */
719 DWORD WINAPI ILFree(LPITEMIDLIST pidl) 
720 {
721         TRACE("(pidl=0x%08lx)\n",(DWORD)pidl);
722
723         if(!pidl) return FALSE;
724         SHFree(pidl);
725         return TRUE;
726 }
727 /*************************************************************************
728  * ILGlobalFree [SHELL32.156]
729  *
730  */
731 void WINAPI ILGlobalFree( LPCITEMIDLIST pidl)
732 {
733         TRACE("%p\n",pidl);
734
735         if(!pidl) return;
736         pCOMCTL32_Free(pidl);
737 }
738 /*************************************************************************
739  * ILCreateFromPath [SHELL32.157]
740  *
741  */
742 LPITEMIDLIST WINAPI ILCreateFromPathA (LPCSTR path) 
743 {
744         LPITEMIDLIST pidlnew;
745         DWORD attributes = 0;
746
747         TRACE_(shell)("%s\n",path);
748
749         if (SUCCEEDED (SHILCreateFromPathA (path, &pidlnew, &attributes)))
750           return pidlnew;
751         return FALSE;
752 }
753 LPITEMIDLIST WINAPI ILCreateFromPathW (LPCWSTR path) 
754 {
755         LPITEMIDLIST pidlnew;
756         DWORD attributes = 0;
757
758         TRACE_(shell)("%s\n",debugstr_w(path));
759
760         if (SUCCEEDED (SHILCreateFromPathW (path, &pidlnew, &attributes)))
761           return pidlnew;
762         return FALSE;
763 }
764 LPITEMIDLIST WINAPI ILCreateFromPathAW (LPCVOID path) 
765 {
766         if ( SHELL_OsIsUnicode())
767           return ILCreateFromPathW (path);
768         return ILCreateFromPathA (path);
769 }
770 /*************************************************************************
771  *  SHSimpleIDListFromPath [SHELL32.162]
772  */
773 LPITEMIDLIST WINAPI SHSimpleIDListFromPathA (LPCSTR lpszPath)
774 {
775         LPITEMIDLIST    pidl=NULL;
776         HANDLE  hFile;
777         WIN32_FIND_DATAA        stffile;
778
779         TRACE("path=%s\n", lpszPath);
780
781         if (!lpszPath) return NULL;
782
783         hFile = FindFirstFileA(lpszPath, &stffile);
784
785         if ( hFile != INVALID_HANDLE_VALUE )
786         {
787           if (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
788           {
789             pidl = _ILCreateFolder (&stffile);
790           }
791           else
792           {
793             pidl = _ILCreateValue (&stffile);
794           }
795           FindClose (hFile);
796         }
797         return pidl;
798 }
799 LPITEMIDLIST WINAPI SHSimpleIDListFromPathW (LPCWSTR lpszPath)
800 {
801         char    lpszTemp[MAX_PATH];
802         TRACE("path=%s\n",debugstr_w(lpszPath));
803
804         if (!WideCharToMultiByte( CP_ACP, 0, lpszPath, -1, lpszTemp, sizeof(lpszTemp), NULL, NULL ))
805             lpszTemp[sizeof(lpszTemp)-1] = 0;
806
807         return SHSimpleIDListFromPathA (lpszTemp);
808 }
809
810 LPITEMIDLIST WINAPI SHSimpleIDListFromPathAW (LPCVOID lpszPath)
811 {
812         if ( SHELL_OsIsUnicode())
813           return SHSimpleIDListFromPathW (lpszPath);
814         return SHSimpleIDListFromPathA (lpszPath);
815 }
816
817 /*************************************************************************
818  * SHGetSpecialFolderLocation           [SHELL32.@]
819  *
820  * gets the folder locations from the registry and creates a pidl
821  * creates missing reg keys and directories
822  * 
823  * PARAMS
824  *   hwndOwner [I]
825  *   nFolder   [I] CSIDL_xxxxx
826  *   ppidl     [O] PIDL of a special folder
827  *
828  */
829 HRESULT WINAPI SHGetSpecialFolderLocation(
830         HWND hwndOwner,
831         INT nFolder,
832         LPITEMIDLIST * ppidl)
833 {
834         CHAR            szPath[MAX_PATH];
835         HRESULT         hr = E_INVALIDARG;
836
837         TRACE_(shell)("(%04x,0x%x,%p)\n", hwndOwner,nFolder,ppidl);
838
839         if (ppidl)
840         {
841           *ppidl = NULL;
842           switch (nFolder)
843           {
844             case CSIDL_DESKTOP:
845               *ppidl = _ILCreateDesktop();
846               break;
847
848             case CSIDL_DRIVES:
849               *ppidl = _ILCreateMyComputer();
850               break;
851
852             case CSIDL_NETWORK:
853               *ppidl = _ILCreateNetwork ();
854               break;
855
856             case CSIDL_CONTROLS:
857               *ppidl = _ILCreateControl ();
858               break;
859
860             case CSIDL_PRINTERS:
861               *ppidl = _ILCreatePrinter ();
862               break;
863
864             case CSIDL_BITBUCKET:
865               *ppidl = _ILCreateBitBucket ();
866               break;
867
868             default:
869               if (SHGetSpecialFolderPathA(hwndOwner, szPath, nFolder, TRUE))
870               {
871                 DWORD attributes=0;
872                 TRACE_(shell)("Value=%s\n",szPath);
873                 hr = SHILCreateFromPathA(szPath, ppidl, &attributes);
874               }
875           }
876           if(*ppidl) hr = NOERROR;
877         }
878
879         TRACE_(shell)("-- (new pidl %p)\n",*ppidl);
880         return hr;
881 }
882
883 /*************************************************************************
884  * SHGetFolderLocation [SHELL32.@]
885  *
886  * NOTES
887  *  the pidl can be a simple one. since we cant get the path out of the pidl
888  *  we have to take all data from the pidl
889  */
890 HRESULT WINAPI SHGetFolderLocation(
891         HWND hwnd,
892         int csidl,
893         HANDLE hToken,
894         DWORD dwFlags,
895         LPITEMIDLIST *ppidl)
896 {
897         FIXME("0x%04x 0x%08x 0x%08x 0x%08lx %p\n",
898          hwnd, csidl, hToken, dwFlags, ppidl);
899         return SHGetSpecialFolderLocation(hwnd, csidl, ppidl);
900 }
901
902 /*************************************************************************
903  * SHGetDataFromIDListA [SHELL32.247]
904  *
905  * NOTES
906  *  the pidl can be a simple one. since we cant get the path out of the pidl
907  *  we have to take all data from the pidl
908  */
909 HRESULT WINAPI SHGetDataFromIDListA(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, int nFormat, LPVOID dest, int len)
910 {
911         TRACE_(shell)("sf=%p pidl=%p 0x%04x %p 0x%04x stub\n",psf,pidl,nFormat,dest,len);
912         
913         pdump(pidl);
914         if (!psf || !dest )  return E_INVALIDARG;
915
916         switch (nFormat)
917         {
918           case SHGDFIL_FINDDATA:
919             {
920                WIN32_FIND_DATAA * pfd = dest;
921
922                if ( len < sizeof (WIN32_FIND_DATAA)) return E_INVALIDARG;
923
924                ZeroMemory(pfd, sizeof (WIN32_FIND_DATAA));
925                _ILGetFileDateTime( pidl, &(pfd->ftLastWriteTime));
926                pfd->dwFileAttributes = _ILGetFileAttributes(pidl, NULL, 0);
927                pfd->nFileSizeLow = _ILGetFileSize ( pidl, NULL, 0);
928                lstrcpynA(pfd->cFileName,_ILGetTextPointer(pidl), MAX_PATH);
929                lstrcpynA(pfd->cAlternateFileName,_ILGetSTextPointer(pidl), 14);
930             }
931             return NOERROR;
932
933           case SHGDFIL_NETRESOURCE:
934           case SHGDFIL_DESCRIPTIONID:
935             FIXME_(shell)("SHGDFIL %i stub\n", nFormat);
936             break;
937
938           default:
939             ERR_(shell)("Unknown SHGDFIL %i, please report\n", nFormat);
940         }
941
942         return E_INVALIDARG;
943 }
944 /*************************************************************************
945  * SHGetDataFromIDListW [SHELL32.248]
946  *
947  */
948 HRESULT WINAPI SHGetDataFromIDListW(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, int nFormat, LPVOID dest, int len)
949 {
950         TRACE_(shell)("sf=%p pidl=%p 0x%04x %p 0x%04x stub\n",psf,pidl,nFormat,dest,len);
951
952         pdump(pidl);
953
954         if (! psf || !dest )  return E_INVALIDARG;
955
956         switch (nFormat)
957         {
958           case SHGDFIL_FINDDATA:
959             {
960                WIN32_FIND_DATAW * pfd = dest;
961
962                if ( len < sizeof (WIN32_FIND_DATAW)) return E_INVALIDARG;
963
964                ZeroMemory(pfd, sizeof (WIN32_FIND_DATAA));
965                _ILGetFileDateTime( pidl, &(pfd->ftLastWriteTime));
966                pfd->dwFileAttributes = _ILGetFileAttributes(pidl, NULL, 0);
967                pfd->nFileSizeLow = _ILGetFileSize ( pidl, NULL, 0);
968                if (!MultiByteToWideChar( CP_ACP, 0, _ILGetTextPointer(pidl), -1,
969                                          pfd->cFileName, MAX_PATH ))
970                    pfd->cFileName[MAX_PATH-1] = 0;
971                if (!MultiByteToWideChar( CP_ACP, 0, _ILGetSTextPointer(pidl), -1,
972                                          pfd->cAlternateFileName, 14 ))
973                    pfd->cFileName[13] = 0;
974             }
975             return NOERROR;
976           case SHGDFIL_NETRESOURCE:
977           case SHGDFIL_DESCRIPTIONID:
978             FIXME_(shell)("SHGDFIL %i stub\n", nFormat);
979             break;
980
981           default:
982             ERR_(shell)("Unknown SHGDFIL %i, please report\n", nFormat);
983         }
984
985         return E_INVALIDARG;
986 }
987
988 /*************************************************************************
989  * SHGetPathFromIDListA         [SHELL32.@][NT 4.0: SHELL32.220]
990  *
991  * PARAMETERS
992  *  pidl,   [IN] pidl 
993  *  pszPath [OUT] path
994  *
995  * RETURNS 
996  *  path from a passed PIDL.
997  *
998  * NOTES
999  *      NULL returns FALSE
1000  *      desktop pidl gives path to desktopdirectory back
1001  *      special pidls returning FALSE
1002  *
1003  * FIXME
1004  *  fnGetDisplayNameOf can return different types of OLEString
1005  */
1006 BOOL WINAPI SHGetPathFromIDListA (LPCITEMIDLIST pidl,LPSTR pszPath)
1007 {       STRRET str;
1008         LPSHELLFOLDER shellfolder;
1009
1010         TRACE_(shell)("(pidl=%p,%p)\n",pidl,pszPath);
1011
1012         if (!pidl) return FALSE;
1013
1014         pdump(pidl);
1015
1016         if(_ILIsDesktop(pidl))
1017         {
1018            SHGetSpecialFolderPathA(0, pszPath, CSIDL_DESKTOPDIRECTORY, FALSE);  
1019         }
1020         else if (_ILIsSpecialFolder(ILFindLastID(pidl)))
1021         {
1022           /* we are somewhere in a special folder */
1023           return FALSE;
1024         }
1025         else
1026         {
1027           if (SHGetDesktopFolder(&shellfolder)==S_OK)
1028           {
1029             if(!SUCCEEDED(IShellFolder_GetDisplayNameOf(shellfolder,pidl,SHGDN_FORPARSING,&str))) {
1030               IShellFolder_Release(shellfolder);
1031               return FALSE;
1032             }
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         TRACE("%p\n", pidl);
1600
1601         if (pdata)
1602         {
1603           TRACE("pdata->type 0x%04x\n", pdata->type);
1604           switch (pdata->type)
1605           {
1606             case PT_SPECIAL:
1607             case PT_MYCOMP:
1608               return (REFIID) &(pdata->u.mycomp.guid);
1609
1610             default:
1611                 TRACE("Unknown pidl type 0x%04x\n", pdata->type);
1612                 break;
1613           }
1614         }
1615         return NULL;
1616 }
1617
1618 /*************************************************************************
1619  * _ILGetFileDateTime
1620  *
1621  * Given the ItemIdList, get the FileTime
1622  *
1623  * PARAMS
1624  *      pidl        [I] The ItemIDList
1625  *      pFt         [I] the resulted FILETIME of the file
1626  *
1627  * RETURNS
1628  *     True if Successful
1629  *
1630  * NOTES
1631  *     
1632  */
1633 BOOL _ILGetFileDateTime(LPCITEMIDLIST pidl, FILETIME *pFt)
1634 {
1635     LPPIDLDATA pdata =_ILGetDataPointer(pidl);
1636
1637     if(! pdata) return FALSE;
1638
1639     switch (pdata->type)
1640     { 
1641         case PT_FOLDER:
1642             DosDateTimeToFileTime(pdata->u.folder.uFileDate, pdata->u.folder.uFileTime, pFt);
1643             break;          
1644         case PT_VALUE:
1645             DosDateTimeToFileTime(pdata->u.file.uFileDate, pdata->u.file.uFileTime, pFt);
1646             break;
1647         default:
1648             return FALSE;
1649     }
1650     return TRUE;
1651 }
1652
1653 BOOL _ILGetFileDate (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize)
1654 {       
1655         FILETIME ft,lft;
1656         SYSTEMTIME time;
1657
1658         if (! _ILGetFileDateTime( pidl, &ft )) return FALSE;
1659         
1660         FileTimeToLocalFileTime(&ft, &lft);
1661         FileTimeToSystemTime (&lft, &time);
1662         return GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&time, NULL,  pOut, uOutSize);
1663 }
1664
1665 /*************************************************************************
1666  * _ILGetFileSize
1667  *
1668  * Given the ItemIdList, get the FileSize
1669  *
1670  * PARAMS
1671  *      pidl    [I] The ItemIDList
1672  *      pOut    [I] The buffer to save the result
1673  *      uOutsize [I] The size of the buffer
1674  *
1675  * RETURNS
1676  *     The FileSize
1677  *
1678  * NOTES
1679  *      pOut can be null when no string is needed
1680  *     
1681  */
1682 DWORD _ILGetFileSize (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize)
1683 {
1684         LPPIDLDATA pdata =_ILGetDataPointer(pidl);
1685         DWORD dwSize;
1686         
1687         if(! pdata) return 0;
1688
1689         switch (pdata->type)
1690         {
1691           case PT_VALUE:
1692             dwSize = pdata->u.file.dwFileSize;
1693             if (pOut) StrFormatByteSizeA(dwSize, pOut, uOutSize);
1694             return dwSize;
1695         }
1696         if (pOut) *pOut = 0x00;
1697         return 0;
1698 }
1699
1700 BOOL _ILGetExtension (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize)
1701 {
1702         char szTemp[MAX_PATH];
1703         const char * pPoint;
1704         LPITEMIDLIST  pidlTemp=pidl;
1705         
1706         TRACE("pidl=%p\n",pidl);
1707
1708         if (!pidl) return FALSE;
1709         
1710         pidlTemp = ILFindLastID(pidl);
1711         
1712         if (!_ILIsValue(pidlTemp)) return FALSE;
1713         if (!_ILSimpleGetText(pidlTemp, szTemp, MAX_PATH)) return FALSE;
1714
1715         pPoint = PathFindExtensionA(szTemp);
1716
1717         if (! *pPoint) return FALSE;
1718
1719         pPoint++;
1720         lstrcpynA(pOut, pPoint, uOutSize);
1721         TRACE("%s\n",pOut);
1722
1723         return TRUE;
1724 }
1725
1726 /*************************************************************************
1727  * _ILGetFileType
1728  *
1729  * Given the ItemIdList, get the file type description
1730  *
1731  * PARAMS
1732  *      pidl        [I] The ItemIDList (simple)
1733  *      pOut        [I] The buffer to save the result
1734  *      uOutsize    [I] The size of the buffer
1735  *
1736  * RETURNS
1737  *      nothing
1738  *
1739  * NOTES
1740  *      This function copies as much as possible into the buffer. 
1741  */
1742 void _ILGetFileType(LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize)
1743 {
1744         if(_ILIsValue(pidl))
1745         {
1746           char sTemp[64];
1747           if(uOutSize > 0)
1748           {
1749             pOut[0] = 0;
1750           }
1751           if (_ILGetExtension (pidl, sTemp, 64))
1752           {
1753             if (!( HCR_MapTypeToValue(sTemp, sTemp, 64, TRUE)
1754                 && HCR_MapTypeToValue(sTemp, pOut, uOutSize, FALSE )))
1755             {
1756               lstrcpynA (pOut, sTemp, uOutSize - 6);
1757               strcat (pOut, "-file");
1758             }
1759           }
1760         }
1761         else
1762         {
1763           lstrcpynA(pOut, "Folder", uOutSize);
1764         }
1765 }
1766
1767 /*************************************************************************
1768  * _ILGetFileAttributes
1769  *
1770  * Given the ItemIdList, get the Attrib string format
1771  *
1772  * PARAMS
1773  *      pidl        [I] The ItemIDList
1774  *      pOut        [I] The buffer to save the result
1775  *      uOutsize    [I] The size of the Buffer
1776  *
1777  * RETURNS
1778  *     Attributes
1779  *
1780  * FIXME
1781  *  return value 0 in case of error is a valid return value
1782  *     
1783  */
1784 DWORD _ILGetFileAttributes(LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize)
1785 {
1786         LPPIDLDATA pData =_ILGetDataPointer(pidl);
1787         WORD wAttrib = 0;
1788         int i;
1789
1790         if(! pData) return 0;
1791
1792         switch(pData->type)
1793         {
1794           case PT_FOLDER:
1795             wAttrib = pData->u.folder.uFileAttribs;
1796             break;
1797           case PT_VALUE:
1798             wAttrib = pData->u.file.uFileAttribs;
1799             break;
1800         }
1801         
1802         if(uOutSize >= 6)
1803         {
1804           i=0;
1805           if(wAttrib & FILE_ATTRIBUTE_READONLY)
1806           {
1807             pOut[i++] = 'R';
1808           }
1809           if(wAttrib & FILE_ATTRIBUTE_HIDDEN)
1810           {
1811             pOut[i++] = 'H';
1812           }
1813           if(wAttrib & FILE_ATTRIBUTE_SYSTEM)
1814           {
1815             pOut[i++] = 'S';
1816           }
1817           if(wAttrib & FILE_ATTRIBUTE_ARCHIVE)
1818           {
1819             pOut[i++] = 'A';
1820           }
1821           if(wAttrib & FILE_ATTRIBUTE_COMPRESSED)
1822           {
1823             pOut[i++] = 'C';
1824           }
1825           pOut[i] = 0x00;
1826         }
1827         return wAttrib;
1828 }
1829
1830 /*************************************************************************
1831 * ILFreeaPidl
1832 *
1833 * free a aPidl struct
1834 */
1835 void _ILFreeaPidl(LPITEMIDLIST * apidl, UINT cidl)
1836 {
1837         int   i;
1838
1839         if(apidl)
1840         {
1841           for(i = 0; i < cidl; i++) SHFree(apidl[i]);
1842           SHFree(apidl);
1843         }
1844 }
1845
1846 /*************************************************************************
1847 * ILCopyaPidl
1848 *
1849 * copies an aPidl struct
1850 */
1851 LPITEMIDLIST *  _ILCopyaPidl(LPITEMIDLIST * apidlsrc, UINT cidl)
1852 {
1853         int i;
1854         LPITEMIDLIST * apidldest = (LPITEMIDLIST*)SHAlloc(cidl * sizeof(LPITEMIDLIST));
1855         if(!apidlsrc) return NULL;
1856
1857         for(i = 0; i < cidl; i++)
1858           apidldest[i] = ILClone(apidlsrc[i]);
1859
1860         return apidldest;
1861 }
1862
1863 /*************************************************************************
1864 * _ILCopyCidaToaPidl
1865 *
1866 * creates aPidl from CIDA
1867 */
1868 LPITEMIDLIST * _ILCopyCidaToaPidl(LPITEMIDLIST* pidl, LPCIDA cida)
1869 {
1870         int i;
1871         LPITEMIDLIST * dst = (LPITEMIDLIST*)SHAlloc(cida->cidl * sizeof(LPITEMIDLIST));
1872
1873         if(!dst) return NULL;
1874
1875         if (pidl)
1876           *pidl = ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[0]]));
1877
1878         for(i = 0; i < cida->cidl; i++)
1879           dst[i] = ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[i + 1]]));
1880
1881         return dst;
1882 }