ICOMization of remaining interfaces.
[wine] / dlls / shell32 / pidl.c
1 /*
2  *      pidl Handling
3  *
4  *      Copyright 1998  Juergen Schmied
5  *
6  * NOTES
7  *  a pidl == NULL means desktop and is legal
8  *
9  */
10
11 #include <ctype.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include "ole2.h"
15 #include "debug.h"
16 #include "shlobj.h"
17 #include "shell.h"
18 #include "winerror.h"
19 #include "winnls.h"
20 #include "winproc.h"
21 #include "commctrl.h"
22 #include "winversion.h"
23 #include "shell32_main.h"
24
25 #include "pidl.h"
26
27 DECLARE_DEBUG_CHANNEL(pidl)
28 DECLARE_DEBUG_CHANNEL(shell)
29
30 void pdump (LPCITEMIDLIST pidl)
31 {       DWORD type;
32         CHAR * szData;
33         CHAR * szShortName;
34         LPITEMIDLIST pidltemp = pidl;
35         if (! pidltemp)
36         { TRACE(pidl,"-------- pidl = NULL (Root)\n");
37           return;
38         }
39         TRACE(pidl,"-------- pidl=%p \n", pidl);
40         if (pidltemp->mkid.cb)
41         { do
42           { type   = _ILGetDataPointer(pidltemp)->type;
43             szData = _ILGetTextPointer(type, _ILGetDataPointer(pidltemp));
44             szShortName = _ILGetSTextPointer(type, _ILGetDataPointer(pidltemp));
45
46             TRACE(pidl,"---- pidl=%p size=%u type=%lx %s, (%s)\n",
47                        pidltemp, pidltemp->mkid.cb,type,debugstr_a(szData), debugstr_a(szShortName));
48
49             pidltemp = ILGetNext(pidltemp);
50           } while (pidltemp->mkid.cb);
51           return;
52         }
53         else
54           TRACE(pidl,"empty pidl (Desktop)\n"); 
55 }
56
57 BOOL pcheck (LPCITEMIDLIST pidl)
58 {       DWORD type, ret=TRUE;
59
60         LPITEMIDLIST pidltemp = pidl;
61
62         if (pidltemp && pidltemp->mkid.cb)
63         { do
64           { type   = _ILGetDataPointer(pidltemp)->type;
65             switch (type)
66             { case PT_DESKTOP:
67               case PT_MYCOMP:
68               case PT_SPECIAL:
69               case PT_DRIVE:
70               case PT_FOLDER:
71               case PT_VALUE:
72                 break;
73               default:
74               {
75                 char szTemp[100];      /* 3*32 + 3 + 1 */
76                 int i;
77                 for ( i = 0; i < pidltemp->mkid.cb; i++)
78                 {
79                   sprintf (&(szTemp[i*3]),"%02x ", ((LPBYTE)pidltemp)[i]);
80                   if (i>=31)
81                   {
82                     sprintf (&(szTemp[i*3+3]),"...");
83                     break;
84                   }
85                 }
86                 ERR (pidl,"unknown IDLIST type size=%u type=%lx\n%s\n",pidltemp->mkid.cb,type, szTemp);
87                 ret = FALSE;
88               }
89             }
90             pidltemp = ILGetNext(pidltemp);
91           } while (pidltemp->mkid.cb);
92         }
93         return ret;
94 }
95
96 /*************************************************************************
97  * ILGetDisplayName                     [SHELL32.15]
98  */
99 BOOL WINAPI ILGetDisplayName(LPCITEMIDLIST pidl,LPSTR path)
100 {       FIXME(shell,"pidl=%p %p semi-stub\n",pidl,path);
101         return SHGetPathFromIDListA(pidl, path);
102 }
103 /*************************************************************************
104  * ILFindLastID [SHELL32.16]
105  */
106 LPITEMIDLIST WINAPI ILFindLastID(LPITEMIDLIST pidl) 
107 {       LPITEMIDLIST   pidlLast = NULL;
108
109         TRACE(pidl,"(pidl=%p)\n",pidl);
110
111         if(pidl)
112         { while(pidl->mkid.cb)
113           { pidlLast = (LPITEMIDLIST)pidl;
114             pidl = ILGetNext(pidl);
115           }  
116         }
117         return pidlLast;                
118 }
119 /*************************************************************************
120  * ILRemoveLastID [SHELL32.17]
121  * NOTES
122  *  Removes the last item 
123  */
124 BOOL WINAPI ILRemoveLastID(LPCITEMIDLIST pidl)
125 {       TRACE(shell,"pidl=%p\n",pidl);
126         if (!pidl || !pidl->mkid.cb)
127           return 0;
128         ILFindLastID(pidl)->mkid.cb = 0;
129         return 1;
130 }
131
132 /*************************************************************************
133  * ILClone [SHELL32.18]
134  *
135  * NOTES
136  *    dupicate an idlist
137  */
138 LPITEMIDLIST WINAPI ILClone (LPCITEMIDLIST pidl)
139 { DWORD    len;
140   LPITEMIDLIST  newpidl;
141
142   if (!pidl)
143     return NULL;
144     
145   len = ILGetSize(pidl);
146   newpidl = (LPITEMIDLIST)SHAlloc(len);
147   if (newpidl)
148     memcpy(newpidl,pidl,len);
149
150   TRACE(pidl,"pidl=%p newpidl=%p\n",pidl, newpidl);
151   pdump(pidl);
152
153   return newpidl;
154 }
155 /*************************************************************************
156  * ILCloneFirst [SHELL32.19]
157  *
158  * NOTES
159  *  duplicates the first idlist of a complex pidl
160  */
161 LPITEMIDLIST WINAPI ILCloneFirst(LPCITEMIDLIST pidl)
162 {       DWORD len;
163         LPITEMIDLIST newpidl=NULL;
164         
165         TRACE(pidl,"pidl=%p \n",pidl);
166         pdump(pidl);
167         
168         if (pidl)
169         { len = pidl->mkid.cb;  
170           newpidl = (LPITEMIDLIST) SHAlloc (len+2);
171           if (newpidl)
172           { memcpy(newpidl,pidl,len);
173             ILGetNext(newpidl)->mkid.cb = 0x00;
174           }
175         }
176         TRACE(pidl,"-- newpidl=%p\n",newpidl);
177
178         return newpidl;
179 }
180 /*************************************************************************
181  * ILLoadFromStream
182  *
183  * NOTES
184  *   the first two bytes are the len, the pidl is following then
185  */
186 HRESULT WINAPI ILLoadFromStream (IStream * pStream, LPITEMIDLIST * ppPidl)
187 {       WORD            wLen = 0;
188         DWORD           dwBytesRead;
189         HRESULT         ret = E_FAIL;
190         
191
192         TRACE(shell,"%p %p\n", pStream ,  ppPidl);
193
194         if (*ppPidl)
195         { SHFree(*ppPidl);
196           *ppPidl = NULL;
197         }
198         
199         IStream_AddRef (pStream);
200
201         if (SUCCEEDED(IStream_Read(pStream, (LPVOID)&wLen, 2, &dwBytesRead)))
202         { *ppPidl = SHAlloc (wLen);
203           if (SUCCEEDED(IStream_Read(pStream, *ppPidl , wLen, &dwBytesRead)))
204           { ret = S_OK;
205           }
206           else
207           { SHFree(*ppPidl);
208             *ppPidl = NULL;
209           }
210         }
211         
212         /* we are not jet fully compatible */
213         if (!pcheck(*ppPidl))
214         { SHFree(*ppPidl);
215           *ppPidl = NULL;
216         }
217         
218
219         IStream_Release (pStream);
220
221         return ret;
222 }
223 /*************************************************************************
224  * SHILCreateFromPath   [SHELL32.28]
225  *
226  * NOTES
227  *   wraper for IShellFolder::ParseDisplayName()
228  */
229 HRESULT WINAPI SHILCreateFromPathA (LPSTR path, LPITEMIDLIST * ppidl, DWORD attributes)
230 {       LPSHELLFOLDER sf;
231         WCHAR lpszDisplayName[MAX_PATH];
232         DWORD pchEaten;
233         HRESULT ret = E_FAIL;
234         
235         TRACE(shell, "%s %p 0x%08lx\n",path,ppidl,attributes);
236
237         LocalToWideChar(lpszDisplayName, path, MAX_PATH);
238
239         if (SUCCEEDED (SHGetDesktopFolder(&sf)))
240         { ret = sf->lpvtbl->fnParseDisplayName(sf,0, NULL,lpszDisplayName,&pchEaten,ppidl,&attributes);
241           sf->lpvtbl->fnRelease(sf);
242         }
243         return ret;     
244 }
245 HRESULT WINAPI SHILCreateFromPathW (LPWSTR 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);
251
252         if (SUCCEEDED (SHGetDesktopFolder(&sf)))
253         { ret = sf->lpvtbl->fnParseDisplayName(sf,0, NULL, path, &pchEaten, ppidl, &attributes);
254           sf->lpvtbl->fnRelease(sf);
255         }
256         return ret;
257 }
258 HRESULT WINAPI SHILCreateFromPathAW (LPVOID path, LPITEMIDLIST * ppidl, DWORD attributes)
259 {
260         if ( VERSION_OsIsUnicode())
261           return SHILCreateFromPathW (path, ppidl, attributes);
262         return SHILCreateFromPathA (path, ppidl, attributes);
263 }
264
265 /*************************************************************************
266  * SHCloneSpecialIDList [SHELL32.89]
267  * 
268  * PARAMETERS
269  *  hwndOwner   [in] 
270  *  nFolder     [in]    CSIDL_xxxxx ??
271  *
272  * RETURNS
273  *  pidl ??
274  * NOTES
275  *     exported by ordinal
276  */
277 LPITEMIDLIST WINAPI SHCloneSpecialIDList(HWND hwndOwner,DWORD nFolder,DWORD x3)
278 {       LPITEMIDLIST ppidl;
279         WARN(shell,"(hwnd=0x%x,csidl=0x%lx,0x%lx):semi-stub.\n",
280                                          hwndOwner,nFolder,x3);
281
282         SHGetSpecialFolderLocation(hwndOwner, nFolder, &ppidl);
283
284         return ppidl;
285 }
286
287 /*************************************************************************
288  * ILGlobalClone [SHELL32.97]
289  *
290  */
291 LPITEMIDLIST WINAPI ILGlobalClone(LPCITEMIDLIST pidl)
292 {       DWORD    len;
293         LPITEMIDLIST  newpidl;
294
295         if (!pidl)
296           return NULL;
297     
298         len = ILGetSize(pidl);
299         newpidl = (LPITEMIDLIST)pCOMCTL32_Alloc(len);
300         if (newpidl)
301           memcpy(newpidl,pidl,len);
302
303         TRACE(pidl,"pidl=%p newpidl=%p\n",pidl, newpidl);
304         pdump(pidl);
305
306         return newpidl;
307 }
308
309 /*************************************************************************
310  * ILIsEqual [SHELL32.21]
311  *
312  */
313 BOOL WINAPI ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
314 {       LPPIDLDATA ppidldata;
315         CHAR * szData1;
316         CHAR * szData2;
317
318         LPITEMIDLIST pidltemp1 = pidl1;
319         LPITEMIDLIST pidltemp2 = pidl2;
320
321         TRACE(pidl,"pidl1=%p pidl2=%p\n",pidl1, pidl2);
322
323         /* explorer reads from registry directly (StreamMRU),
324            so we can only check here */
325         if ((!pcheck (pidl1)) || (!pcheck (pidl2)))
326           return FALSE;
327
328         pdump (pidl1);
329         pdump (pidl2);
330
331         if ( (!pidl1) || (!pidl2) )
332         { return FALSE;
333         }
334
335         if (pidltemp1->mkid.cb && pidltemp2->mkid.cb)
336         { do
337           { ppidldata = _ILGetDataPointer(pidltemp1);
338             szData1 = _ILGetTextPointer(ppidldata->type, ppidldata);
339             
340             ppidldata = _ILGetDataPointer(pidltemp2);    
341             szData2 = _ILGetTextPointer(ppidldata->type, ppidldata);
342
343             if (strcmp ( szData1, szData2 )!=0 )
344               return FALSE;
345
346             pidltemp1 = ILGetNext(pidltemp1);
347             pidltemp2 = ILGetNext(pidltemp2);
348
349           } while (pidltemp1->mkid.cb && pidltemp2->mkid.cb);
350         }       
351         if (!pidltemp1->mkid.cb && !pidltemp2->mkid.cb)
352         { TRACE(shell, "--- equal\n");
353           return TRUE;
354         }
355
356         return FALSE;
357 }
358 /*************************************************************************
359  * ILIsParent [SHELL32.23]
360  *
361  */
362 DWORD WINAPI ILIsParent( DWORD x, DWORD y, DWORD z)
363 {       FIXME(pidl,"0x%08lx 0x%08lx 0x%08lx stub\n",x,y,z);
364         return 0;
365 }
366
367 /*************************************************************************
368  * ILFindChild [SHELL32.24]
369  *
370  * NOTES
371  *  Compares elements from pidl1 and pidl2.
372  *  When at least the first element is equal, it gives a pointer
373  *  to the first different element of pidl 2 back.
374  *  Returns 0 if pidl 2 is shorter.
375  */
376 LPITEMIDLIST WINAPI ILFindChild(LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2)
377 {       LPPIDLDATA ppidldata;
378         CHAR * szData1;
379         CHAR * szData2;
380
381         LPITEMIDLIST pidltemp1 = pidl1;
382         LPITEMIDLIST pidltemp2 = pidl2;
383         LPITEMIDLIST ret=NULL;
384
385         TRACE(pidl,"pidl1=%p pidl2=%p\n",pidl1, pidl2);
386
387         pdump (pidl1);
388         pdump (pidl2);
389
390         if ( !pidl1 || !pidl1->mkid.cb)         /* pidl 1 is desktop (root) */
391         { TRACE(shell, "--- %p\n", pidl2);
392           return pidl2;
393         }
394
395         if (pidltemp1->mkid.cb && pidltemp2->mkid.cb)
396         { do
397           { ppidldata = _ILGetDataPointer(pidltemp1);
398             szData1 = _ILGetTextPointer(ppidldata->type, ppidldata);
399             
400             ppidldata = _ILGetDataPointer(pidltemp2);    
401             szData2 = _ILGetTextPointer(ppidldata->type, ppidldata);
402
403             pidltemp2 = ILGetNext(pidltemp2);   /* points behind the pidl2 */
404
405             if (strcmp(szData1,szData2) == 0)
406             { ret = pidltemp2;  /* found equal element */
407             }
408             else
409             { if (ret)          /* different element after equal -> break */
410               { ret = NULL;
411                 break;
412               }
413             }
414             pidltemp1 = ILGetNext(pidltemp1);
415           } while (pidltemp1->mkid.cb && pidltemp2->mkid.cb);
416         }       
417
418         if (!pidltemp2->mkid.cb)
419         { return NULL; /* complete equal or pidl 2 is shorter */
420         }
421
422         TRACE(shell, "--- %p\n", ret);
423         return ret; /* pidl 1 is shorter */
424 }
425
426 /*************************************************************************
427  * ILCombine [SHELL32.25]
428  *
429  * NOTES
430  *  Concatenates two complex idlists.
431  *  The pidl is the first one, pidlsub the next one
432  *  Does not destroy the passed in idlists!
433  */
434 LPITEMIDLIST WINAPI ILCombine(LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2)
435 { DWORD    len1,len2;
436   LPITEMIDLIST  pidlNew;
437   
438   TRACE(pidl,"pidl=%p pidl=%p\n",pidl1,pidl2);
439
440   if(!pidl1 && !pidl2)
441   {  return NULL;
442   }
443
444   pdump (pidl1);
445   pdump (pidl2);
446  
447   if(!pidl1)
448   { pidlNew = ILClone(pidl2);
449     return pidlNew;
450   }
451
452   if(!pidl2)
453   { pidlNew = ILClone(pidl1);
454     return pidlNew;
455   }
456
457   len1  = ILGetSize(pidl1)-2;
458   len2  = ILGetSize(pidl2);
459   pidlNew  = SHAlloc(len1+len2);
460   
461   if (pidlNew)
462   { memcpy(pidlNew,pidl1,len1);
463     memcpy(((BYTE *)pidlNew)+len1,pidl2,len2);
464   }
465
466 /*  TRACE(pidl,"--new pidl=%p\n",pidlNew);*/
467   return pidlNew;
468 }
469 /*************************************************************************
470  *  SHGetRealIDL [SHELL32.98]
471  *
472  * NOTES
473  */
474 LPITEMIDLIST WINAPI SHGetRealIDL(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl, DWORD z)
475 {       FIXME(pidl,"sf=%p pidl=%p 0x%04lx\n",lpsf,pidl,z);
476         pdump (pidl);
477         return 0;
478 }
479
480 /*************************************************************************
481  *  SHLogILFromFSIL [SHELL32.95]
482  *
483  * NOTES
484  */
485 LPITEMIDLIST WINAPI SHLogILFromFSIL(LPITEMIDLIST pidl)
486 {       FIXME(pidl,"(pidl=%p)\n",pidl);
487         pdump(pidl);
488         return 0;
489 }
490
491 /*************************************************************************
492  * ILGetSize [SHELL32.152]
493  *  gets the byte size of an idlist including zero terminator (pidl)
494  *
495  * PARAMETERS
496  *  pidl ITEMIDLIST
497  *
498  * RETURNS
499  *  size of pidl
500  *
501  * NOTES
502  *  exported by ordinal
503  */
504 DWORD WINAPI ILGetSize(LPITEMIDLIST pidl)
505 {       LPSHITEMID si = &(pidl->mkid);
506         DWORD  len=0;
507
508         if (pidl)
509         { while (si->cb) 
510           { len += si->cb;
511             si  = (LPSHITEMID)(((LPBYTE)si)+si->cb);
512           }
513           len += 2;
514         }
515         TRACE(pidl,"pidl=%p size=%lu\n",pidl, len);
516         return len;
517 }
518 /*************************************************************************
519  * ILGetNext [SHELL32.153]
520  *  gets the next simple pidl of a complex pidl
521  *
522  * PARAMETERS
523  *  pidl ITEMIDLIST
524  *
525  * RETURNS
526  *  pointer to next element
527  *
528  */
529 LPITEMIDLIST WINAPI ILGetNext(LPITEMIDLIST pidl)
530 {       LPITEMIDLIST nextpidl;
531
532         /* TRACE(pidl,"(pidl=%p)\n",pidl);*/
533         if(pidl)
534         { nextpidl = (LPITEMIDLIST)(LPBYTE)(((LPBYTE)pidl) + pidl->mkid.cb);
535           return nextpidl;
536         }
537         else
538         {  return (NULL);
539         }
540 }
541 /*************************************************************************
542  * ILAppend [SHELL32.154]
543  *
544  * NOTES
545  *  Adds the single item to the idlist indicated by pidl.
546  *  if bEnd is 0, adds the item to the front of the list,
547  *  otherwise adds the item to the end. (???)
548  *  Destroys the passed in idlist! (???)
549  */
550 LPITEMIDLIST WINAPI ILAppend(LPITEMIDLIST pidl,LPCITEMIDLIST item,BOOL bEnd)
551 {       LPITEMIDLIST idlRet;
552         WARN(pidl,"(pidl=%p,pidl=%p,%08u)semi-stub\n",pidl,item,bEnd);
553         pdump (pidl);
554         pdump (item);
555         
556         if (_ILIsDesktop(pidl))
557         {  idlRet = ILClone(item);
558            if (pidl)
559              SHFree (pidl);
560            return idlRet;
561         }  
562         if (bEnd)
563         { idlRet=ILCombine(pidl,item);
564         }
565         else
566         { idlRet=ILCombine(item,pidl);
567         }
568         SHFree(pidl);
569         return idlRet;
570 }
571 /*************************************************************************
572  * ILFree [SHELL32.155]
573  *
574  * NOTES
575  *     free_check_ptr - frees memory (if not NULL)
576  *     allocated by SHMalloc allocator
577  *     exported by ordinal
578  */
579 DWORD WINAPI ILFree(LPITEMIDLIST pidl) 
580 {       TRACE(pidl,"(pidl=0x%08lx)\n",(DWORD)pidl);
581
582         if (!pidl)
583           return FALSE;
584
585         return SHFree(pidl);
586 }
587 /*************************************************************************
588  * ILGlobalFree [SHELL32.156]
589  *
590  */
591 DWORD WINAPI ILGlobalFree( LPITEMIDLIST pidl)
592 {       TRACE(pidl,"%p\n",pidl);
593
594         if (!pidl)
595           return FALSE;
596
597         return pCOMCTL32_Free (pidl);
598 }
599 /*************************************************************************
600  * ILCreateFromPath [SHELL32.157]
601  *
602  */
603 LPITEMIDLIST WINAPI ILCreateFromPathA (LPSTR path) 
604 {       LPITEMIDLIST pidlnew;
605
606         TRACE(shell,"%s\n",path);
607         if (SUCCEEDED (SHILCreateFromPathA (path, &pidlnew, 0)))
608           return pidlnew;
609         return FALSE;
610 }
611 LPITEMIDLIST WINAPI ILCreateFromPathW (LPWSTR path) 
612 {       LPITEMIDLIST pidlnew;
613
614         TRACE(shell,"%s\n",debugstr_w(path));
615
616         if (SUCCEEDED (SHILCreateFromPathW (path, &pidlnew, 0)))
617           return pidlnew;
618         return FALSE;
619 }
620 LPITEMIDLIST WINAPI ILCreateFromPathAW (LPVOID path) 
621 {
622         if ( VERSION_OsIsUnicode())
623           return ILCreateFromPathW (path);
624         return ILCreateFromPathA (path);
625 }
626 /*************************************************************************
627  *  SHSimpleIDListFromPath [SHELL32.162]
628  *
629  */
630 LPITEMIDLIST WINAPI SHSimpleIDListFromPathAW (LPVOID lpszPath)
631 {       LPCSTR  lpszElement;
632         char    lpszTemp[MAX_PATH];
633
634         if (!lpszPath)
635           return 0;
636
637         if ( VERSION_OsIsUnicode())
638         { TRACE(pidl,"(path=L%s)\n",debugstr_w((LPWSTR)lpszPath));
639           WideCharToLocal(lpszTemp, lpszPath, MAX_PATH);
640         }
641         else
642         { TRACE(pidl,"(path=%s)\n",(LPSTR)lpszPath);
643           strcpy(lpszTemp, lpszPath);
644         }
645                 
646         lpszElement = PathFindFilenameA(lpszTemp);
647         if( GetFileAttributesA(lpszTemp) & FILE_ATTRIBUTE_DIRECTORY )
648         { return _ILCreateFolder(NULL, lpszElement);    /*FIXME: fill shortname */
649         }
650         return _ILCreateValue(NULL, lpszElement);       /*FIXME: fill shortname */
651 }
652 /*************************************************************************
653  * SHGetDataFromIDListA [SHELL32.247]
654  *
655  */
656 HRESULT WINAPI SHGetDataFromIDListA(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, int nFormat, LPVOID dest, int len)
657 {       TRACE(shell,"sf=%p pidl=%p 0x%04x %p 0x%04x stub\n",psf,pidl,nFormat,dest,len);
658         
659         if (! psf || !dest )
660           return E_INVALIDARG;
661
662         switch (nFormat)
663         { case SHGDFIL_FINDDATA:
664             {  WIN32_FIND_DATAA * pfd = dest;
665                STRRET   lpName;
666                CHAR     pszPath[MAX_PATH];
667                HANDLE handle;
668
669                if ( len < sizeof (WIN32_FIND_DATAA))
670                  return E_INVALIDARG;
671
672                psf->lpvtbl->fnAddRef(psf);
673                psf->lpvtbl->fnGetDisplayNameOf( psf, pidl, SHGDN_FORPARSING, &lpName);
674                psf->lpvtbl->fnRelease(psf);
675
676                strcpy(pszPath,lpName.u.cStr);
677                if ((handle  = FindFirstFileA ( pszPath, pfd)))
678                  FindClose (handle);
679             }
680             break;
681           case SHGDFIL_NETRESOURCE:
682           case SHGDFIL_DESCRIPTIONID:
683             FIXME(shell, "SHGDFIL %i stub\n", nFormat);
684             break;
685           default:
686             ERR(shell,"Unknown SHGDFIL %i, please report\n", nFormat);
687         }
688         return E_INVALIDARG;
689 }
690 /*************************************************************************
691  * SHGetDataFromIDListW [SHELL32.247]
692  *
693  */
694 HRESULT WINAPI SHGetDataFromIDListW(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, int nFormat, LPVOID dest, int len)
695 {       FIXME(shell,"sf=%p pidl=%p 0x%04x %p 0x%04x stub\n",psf,pidl,nFormat,dest,len);
696         return SHGetDataFromIDListA( psf, pidl, nFormat, dest, len);
697 }
698
699 /**************************************************************************
700 * internal functions
701 */
702
703 /**************************************************************************
704  *  _ILCreateDesktop()
705  *  _ILCreateMyComputer()
706  *  _ILCreateDrive()
707  *  _ILCreateFolder() 
708  *  _ILCreateValue()
709  */
710 LPITEMIDLIST WINAPI _ILCreateDesktop()
711 {       TRACE(pidl,"()\n");
712         return _ILCreate(PT_DESKTOP, NULL, 0);
713 }
714 LPITEMIDLIST WINAPI _ILCreateMyComputer()
715 {       TRACE(pidl,"()\n");
716         return _ILCreate(PT_MYCOMP, (void *)"My Computer", strlen ("My Computer")+1);
717 }
718 LPITEMIDLIST WINAPI _ILCreateDrive( LPCSTR lpszNew)
719 {       char sTemp[4];
720         strncpy (sTemp,lpszNew,4);
721         sTemp[2]='\\';
722         sTemp[3]=0x00;
723         TRACE(pidl,"(%s)\n",sTemp);
724         return _ILCreate(PT_DRIVE,(LPVOID)&sTemp[0],4);
725 }
726 LPITEMIDLIST WINAPI _ILCreateFolder( LPCSTR lpszShortName, LPCSTR lpszName)
727 {       char    buff[MAX_PATH];
728         char *  pbuff = buff;
729         ULONG   len, len1;
730         
731         TRACE(pidl,"(%s, %s)\n",lpszShortName, lpszName);
732
733         len = strlen (lpszName)+1;
734         memcpy (pbuff, lpszName, len);
735         pbuff += len;
736
737         if (lpszShortName)
738         { len1 = strlen (lpszShortName)+1;
739           memcpy (pbuff, lpszShortName, len1);
740         }
741         else
742         { len1 = 1;
743           *pbuff = 0x00;
744         }
745         return _ILCreate(PT_FOLDER, (LPVOID)buff, len + len1);
746 }
747 LPITEMIDLIST WINAPI _ILCreateValue(LPCSTR lpszShortName, LPCSTR lpszName)
748 {       char    buff[MAX_PATH];
749         char *  pbuff = buff;
750         ULONG   len, len1;
751         
752         TRACE(pidl,"(%s, %s)\n", lpszShortName, lpszName);
753
754         len = strlen (lpszName)+1;
755         memcpy (pbuff, lpszName, len);
756         pbuff += len;
757
758         if (lpszShortName)
759         { len1 = strlen (lpszShortName)+1;
760           memcpy (pbuff, lpszShortName, len1);
761         }
762         else
763         { len1 = 1;
764           *pbuff = 0x00;
765         }
766         return _ILCreate(PT_VALUE, (LPVOID)buff, len + len1);
767 }
768
769 /**************************************************************************
770  *  _ILGetDrive()
771  *
772  *  Gets the text for the drive eg. 'c:\'
773  *
774  * RETURNS
775  *  strlen (lpszText)
776  */
777 DWORD WINAPI _ILGetDrive(LPCITEMIDLIST pidl,LPSTR pOut, UINT16 uSize)
778 {       TRACE(pidl,"(%p,%p,%u)\n",pidl,pOut,uSize);
779
780         if(_ILIsMyComputer(pidl))
781           pidl = ILGetNext(pidl);
782
783         if (pidl && _ILIsDrive(pidl))
784           return _ILGetData(PT_DRIVE, pidl, (LPVOID)pOut, uSize)-1;
785
786         return 0;
787 }
788 /**************************************************************************
789  *  _ILGetItemText()
790  *  Gets the text for only the first item
791  *
792  * RETURNS
793  *  strlen (lpszText)
794  */
795 DWORD WINAPI _ILGetItemText(LPCITEMIDLIST pidl, LPSTR lpszText, UINT16 uSize)
796 {       DWORD ret = 0;
797
798         TRACE(pidl,"(pidl=%p %p %d)\n",pidl,lpszText,uSize);
799         if (_ILIsMyComputer(pidl))
800         { ret = _ILGetData(PT_MYCOMP, pidl, (LPVOID)lpszText, uSize)-1;
801         }
802         else if (_ILIsDrive(pidl))
803         { ret = _ILGetData(PT_DRIVE, pidl, (LPVOID)lpszText, uSize)-1;
804         }
805         else if (_ILIsFolder (pidl))
806         { ret = _ILGetData(PT_FOLDER, pidl, (LPVOID)lpszText, uSize)-1;
807         }
808         else if (_ILIsValue (pidl))
809         { ret = _ILGetData(PT_VALUE, pidl, (LPVOID)lpszText, uSize)-1;
810         }
811         TRACE(pidl,"(-- %s)\n",debugstr_a(lpszText));
812         return ret;
813 }
814 /**************************************************************************
815  *  _ILIsDesktop()
816  *  _ILIsDrive()
817  *  _ILIsFolder()
818  *  _ILIsValue()
819  */
820 BOOL WINAPI _ILIsDesktop(LPCITEMIDLIST pidl)
821 {       TRACE(pidl,"(%p)\n",pidl);
822         return ( !pidl || (pidl && pidl->mkid.cb == 0x00) );
823 }
824
825 BOOL WINAPI _ILIsMyComputer(LPCITEMIDLIST pidl)
826 {       LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
827         TRACE(pidl,"(%p)\n",pidl);
828         return (pidl && lpPData && PT_MYCOMP == lpPData->type);
829 }
830
831 BOOL WINAPI _ILIsDrive(LPCITEMIDLIST pidl)
832 {       LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
833         TRACE(pidl,"(%p)\n",pidl);
834         return (pidl && lpPData && PT_DRIVE == lpPData->type);
835 }
836
837 BOOL WINAPI _ILIsFolder(LPCITEMIDLIST pidl)
838 {       LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
839         TRACE(pidl,"(%p)\n",pidl);
840         return (pidl && lpPData && PT_FOLDER == lpPData->type);
841 }
842
843 BOOL WINAPI _ILIsValue(LPCITEMIDLIST pidl)
844 {       LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
845         TRACE(pidl,"(%p)\n",pidl);
846         return (pidl && lpPData && PT_VALUE == lpPData->type);
847 }
848
849 /**************************************************************************
850  *  _ILGetFolderText()
851  *  Creates a Path string from a PIDL, filtering out the special Folders and values
852  *  There is no trailing backslash
853  *  When lpszPath is NULL the needed size is returned
854  * 
855  * RETURNS
856  *  strlen(lpszPath)
857  */
858 DWORD WINAPI _ILGetFolderText(LPCITEMIDLIST pidl,LPSTR lpszPath, DWORD dwSize)
859 {       LPITEMIDLIST    pidlTemp;
860         LPPIDLDATA      pData;
861         DWORD           dwCopied = 0;
862         LPSTR           pText;
863  
864         TRACE(pidl,"(%p path=%p)\n",pidl, lpszPath);
865  
866         if(!pidl)
867           return 0;
868
869         if(_ILIsMyComputer(pidl))
870         { pidlTemp = ILGetNext(pidl);
871           TRACE(pidl,"-- skip My Computer\n");
872         }
873         else
874         { pidlTemp = (LPITEMIDLIST)pidl;
875         }
876
877         if(lpszPath)
878           *lpszPath = 0;
879
880         pData = _ILGetDataPointer(pidlTemp);
881
882         while(pidlTemp->mkid.cb && !(PT_VALUE == pData->type))
883         { 
884           if (!(pText = _ILGetTextPointer(pData->type,pData)))
885             return 0;                           /* foreign pidl */
886                   
887           dwCopied += strlen(pText);
888
889           pidlTemp = ILGetNext(pidlTemp);
890           pData = _ILGetDataPointer(pidlTemp);
891
892           if (lpszPath)
893           { strcat(lpszPath, pText);
894
895             if (pidlTemp->mkid.cb               /* last element ? */
896                 && (pText[2] != '\\')           /* drive has own '\' */
897                 && (PT_VALUE != pData->type))   /* next element is value */
898             { lpszPath[dwCopied] = '\\';
899               lpszPath[dwCopied+1] = '\0';
900               dwCopied++;
901             }
902           }
903           else                                          /* only length */
904           { if (pidlTemp->mkid.cb 
905                 && (pText[2] != '\\')
906                 && (PT_VALUE != pData->type))
907               dwCopied++;                               /* backslash between elements */
908           }
909         }
910
911         TRACE(pidl,"-- (size=%lu path=%s)\n",dwCopied, debugstr_a(lpszPath));
912         return dwCopied;
913 }
914
915
916 /**************************************************************************
917  *  _ILGetValueText()
918  *  Gets the text for the last item in the list
919  */
920 DWORD WINAPI _ILGetValueText(LPCITEMIDLIST pidl, LPSTR lpszValue, DWORD dwSize)
921 {       LPITEMIDLIST  pidlTemp=pidl;
922         CHAR          szText[MAX_PATH];
923
924         TRACE(pidl,"(pidl=%p %p 0x%08lx)\n",pidl,lpszValue,dwSize);
925
926         if(!pidl)
927         { return 0;
928         }
929                 
930         while(pidlTemp->mkid.cb && !_ILIsValue(pidlTemp))
931         { pidlTemp = ILGetNext(pidlTemp);
932         }
933
934         if(!pidlTemp->mkid.cb)
935         { return 0;
936         }
937
938         _ILGetItemText( pidlTemp, szText, sizeof(szText));
939
940         if(!lpszValue)
941         { return strlen(szText);
942         }
943         
944         strcpy(lpszValue, szText);
945
946         TRACE(pidl,"-- (pidl=%p %p=%s 0x%08lx)\n",pidl,lpszValue,lpszValue,dwSize);
947         return strlen(lpszValue);
948 }
949
950 /**************************************************************************
951  *  _ILGetPidlPath()
952  *  Create a string that includes the Drive name, the folder text and 
953  *  the value text.
954  *
955  * RETURNS
956  *  strlen(lpszOut)
957  */
958 DWORD WINAPI _ILGetPidlPath( LPCITEMIDLIST pidl, LPSTR lpszOut, DWORD dwOutSize)
959 {       int     len = 0;
960         LPSTR   lpszTemp = lpszOut;
961         
962         TRACE(pidl,"(%p,%lu)\n",lpszOut,dwOutSize);
963
964         if(!lpszOut)
965         { return 0;
966         }
967
968         *lpszOut = 0;
969
970         len = _ILGetFolderText(pidl, lpszOut, dwOutSize);
971
972         lpszOut += len;
973         strcpy (lpszOut,"\\");
974         len++; lpszOut++; dwOutSize -= len;
975
976         len += _ILGetValueText(pidl, lpszOut, dwOutSize );
977
978         /*remove the last backslash if necessary */
979         if( lpszTemp[len-1]=='\\')
980         { lpszTemp[len-1] = 0;
981           len--;
982         }
983
984         TRACE(pidl,"-- (%p=%s,%u)\n",lpszTemp,lpszTemp,len);
985
986         return len;
987 }
988
989 /**************************************************************************
990  *  _ILCreate()
991  *  Creates a new PIDL
992  *  type = PT_DESKTOP | PT_DRIVE | PT_FOLDER | PT_VALUE
993  *  pIn = data
994  *  uInSize = size of data (raw)
995  */
996
997 LPITEMIDLIST WINAPI _ILCreate(PIDLTYPE type, LPVOID pIn, UINT16 uInSize)
998 {       LPITEMIDLIST   pidlOut=NULL;
999         UINT16         uSize;
1000         LPITEMIDLIST   pidlTemp=NULL;
1001         LPPIDLDATA     pData;
1002         LPSTR   pszDest;
1003         
1004         TRACE(pidl,"(0x%02x %p %i)\n",type,pIn,uInSize);
1005
1006         if ( type == PT_DESKTOP)
1007         { pidlOut = SHAlloc(2);
1008           pidlOut->mkid.cb=0x0000;
1009           return pidlOut;
1010         }
1011
1012         if (! pIn)
1013         { return NULL;
1014         }       
1015
1016         /* the sizes of: cb(2), pidldata-1(26), szText+1, next cb(2) */
1017         switch (type)
1018         { case PT_DRIVE:
1019             uSize = 4 + 9;
1020             break;
1021           default:
1022             uSize = 4 + (sizeof(PIDLDATA)) + uInSize; 
1023          }   
1024         pidlOut = SHAlloc(uSize);
1025         pidlTemp = pidlOut;
1026         if(pidlOut)
1027         { pidlTemp->mkid.cb = uSize - 2;
1028           pData =_ILGetDataPointer(pidlTemp);
1029           pszDest =  _ILGetTextPointer(type, pData);
1030           pData->type = type;
1031           switch(type)
1032           { case PT_MYCOMP:
1033               memcpy(pszDest, pIn, uInSize);
1034               TRACE(pidl,"- create My Computer: %s\n",debugstr_a(pszDest));
1035               break;
1036             case PT_DRIVE:
1037               memcpy(pszDest, pIn, uInSize);
1038               TRACE(pidl,"- create Drive: %s\n",debugstr_a(pszDest));
1039               break;
1040             case PT_FOLDER:
1041             case PT_VALUE:   
1042               memcpy(pszDest, pIn, uInSize);
1043               TRACE(pidl,"- create Value: %s\n",debugstr_a(pszDest));
1044               break;
1045             default: 
1046               FIXME(pidl,"-- wrong argument\n");
1047               break;
1048           }
1049    
1050           pidlTemp = ILGetNext(pidlTemp);
1051           pidlTemp->mkid.cb = 0x00;
1052         }
1053         TRACE(pidl,"-- (pidl=%p, size=%u)\n",pidlOut,uSize-2);
1054         return pidlOut;
1055 }
1056 /**************************************************************************
1057  *  _ILGetData(PIDLTYPE, LPCITEMIDLIST, LPVOID, UINT16)
1058  *
1059  * RETURNS
1060  *  length of data (raw)
1061  */
1062 DWORD WINAPI _ILGetData(PIDLTYPE type, LPCITEMIDLIST pidl, LPVOID pOut, UINT uOutSize)
1063 {       LPPIDLDATA  pData;
1064         DWORD       dwReturn=0; 
1065         LPSTR       pszSrc;
1066         
1067         TRACE(pidl,"(%x %p %p %x)\n",type,pidl,pOut,uOutSize);
1068         
1069         if(!pidl)
1070         {  return 0;
1071         }
1072
1073         *(LPSTR)pOut = 0;        
1074
1075         pData = _ILGetDataPointer(pidl);
1076         if ( pData->type != type)
1077         { ERR(pidl,"-- wrong type\n");
1078           return 0;
1079         }
1080         pszSrc = _ILGetTextPointer(pData->type, pData);
1081
1082         switch(type)
1083         { case PT_MYCOMP:
1084             if(uOutSize < 1)
1085               return 0;
1086             strncpy((LPSTR)pOut, "My Computer", uOutSize);
1087             dwReturn = strlen((LPSTR)pOut)+1;
1088             break;
1089
1090           case PT_DRIVE:
1091             if(uOutSize < 1)
1092               return 0;
1093             strncpy((LPSTR)pOut, pszSrc, uOutSize);
1094             dwReturn = strlen((LPSTR)pOut)+1;
1095             break;
1096
1097           case PT_FOLDER:
1098           case PT_VALUE: 
1099              strncpy((LPSTR)pOut, pszSrc, uOutSize);
1100              dwReturn = strlen((LPSTR)pOut)+1;
1101              break;
1102           default:
1103             ERR(pidl,"-- unknown type\n");
1104             break;                                                                               
1105         }
1106         TRACE(pidl,"-- (%p=%s 0x%08lx)\n",pOut,(char*)pOut,dwReturn);
1107         return dwReturn;
1108 }
1109
1110
1111 /**************************************************************************
1112  *  _ILGetDataPointer()
1113  */
1114 LPPIDLDATA WINAPI _ILGetDataPointer(LPITEMIDLIST pidl)
1115 {       if(pidl && pidl->mkid.cb != 0x00)
1116           return (LPPIDLDATA)(&pidl->mkid.abID);
1117         return NULL;
1118 }
1119 /**************************************************************************
1120  *  _ILGetTextPointer()
1121  * gets a pointer to the long filename string stored in the pidl
1122  */
1123 LPSTR WINAPI _ILGetTextPointer(PIDLTYPE type, LPPIDLDATA pidldata)
1124 {/*     TRACE(pidl,"(type=%x data=%p)\n", type, pidldata);*/
1125
1126         if(!pidldata)
1127         { return NULL;
1128         }
1129         switch (type)
1130         { case PT_DRIVE:
1131             return (LPSTR)&(pidldata->u.drive.szDriveName);
1132           case PT_MYCOMP:
1133           case PT_FOLDER:
1134           case PT_VALUE:
1135             return (LPSTR)&(pidldata->u.file.szNames);
1136         }
1137         return NULL;
1138 }
1139 /**************************************************************************
1140  *  _ILGetSTextPointer()
1141  * gets a pointer to the long filename string stored in the pidl
1142  */
1143 LPSTR WINAPI _ILGetSTextPointer(PIDLTYPE type, LPPIDLDATA pidldata)
1144 {/*     TRACE(pidl,"(type=%x data=%p)\n", type, pidldata);*/
1145
1146         if(!pidldata)
1147         { return NULL;
1148         }
1149         switch (type)
1150         { case PT_MYCOMP:
1151           case PT_DRIVE:
1152             return NULL;
1153           case PT_FOLDER:
1154           case PT_VALUE:
1155             return (LPSTR)(pidldata->u.file.szNames + strlen (pidldata->u.file.szNames) + 1);
1156         }
1157         return NULL;
1158 }
1159 BOOL WINAPI _ILGetFileDate (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize)
1160 {       LPPIDLDATA pdata =_ILGetDataPointer(pidl);
1161         FILETIME ft;
1162         SYSTEMTIME time;
1163
1164         switch (pdata->type)
1165         { case PT_DRIVE:
1166           case PT_MYCOMP:
1167             return FALSE;
1168           case PT_FOLDER:
1169             DosDateTimeToFileTime(pdata->u.folder.uFileDate, pdata->u.folder.uFileTime, &ft);
1170             break;          
1171           case PT_VALUE:
1172             DosDateTimeToFileTime(pdata->u.file.uFileDate, pdata->u.file.uFileTime, &ft);
1173             break;
1174           default:
1175             return FALSE;
1176         }
1177         FileTimeToSystemTime (&ft, &time);
1178         return GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&time, NULL,  pOut, uOutSize);
1179 }
1180 BOOL WINAPI _ILGetFileSize (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize)
1181 {       LPPIDLDATA pdata =_ILGetDataPointer(pidl);
1182         char stemp[20]; /* for filesize */
1183         
1184         switch (pdata->type)
1185         { case PT_DRIVE:
1186           case PT_MYCOMP:
1187           case PT_FOLDER:
1188             return FALSE;
1189           case PT_VALUE:
1190             break;
1191           default:
1192             return FALSE;
1193         }
1194         StrFormatByteSizeA(pdata->u.file.dwFileSize, stemp, 20);
1195         strncpy( pOut, stemp, 20);
1196         return TRUE;
1197 }
1198
1199 BOOL WINAPI _ILGetExtension (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize)
1200 {       char pTemp[MAX_PATH];
1201         int i;
1202
1203         TRACE(pidl,"pidl=%p\n",pidl);
1204
1205         if ( ! _ILGetValueText(pidl, pTemp, MAX_PATH))
1206         { return FALSE;
1207         }
1208
1209         for (i=0; pTemp[i]!='.' && pTemp[i];i++);
1210
1211         if (!pTemp[i])
1212           return FALSE;
1213           
1214         strncpy(pOut, &pTemp[i], uOutSize);
1215         TRACE(pidl,"%s\n",pOut);
1216
1217         return TRUE;
1218 }