Fixes for FreeBSD.
[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 "ole.h"
15 #include "ole2.h"
16 #include "debug.h"
17 #include "compobj.h"
18 #include "interfaces.h"
19 #include "shlobj.h"
20 #include "shell.h"
21 #include "winerror.h"
22 #include "winnls.h"
23 #include "winproc.h"
24 #include "commctrl.h"
25 #include "shell32_main.h"
26
27 #include "pidl.h"
28
29 void pdump (LPCITEMIDLIST pidl)
30 {       DWORD type;
31         CHAR * szData;
32         LPITEMIDLIST pidltemp = pidl;
33         if (! pidltemp)
34         { TRACE(pidl,"-------- pidl = NULL (Root)\n");
35           return;
36         }
37         TRACE(pidl,"-------- pidl=%p \n", pidl);
38         if (pidltemp->mkid.cb)
39         { do
40           { type   = _ILGetDataPointer(pidltemp)->type;
41             szData = _ILGetTextPointer(type, _ILGetDataPointer(pidltemp));
42
43             TRACE(pidl,"---- pidl=%p size=%u type=%lx %s\n",pidltemp, pidltemp->mkid.cb,type,debugstr_a(szData));
44
45             pidltemp = ILGetNext(pidltemp);
46           } while (pidltemp->mkid.cb);
47           return;
48         }
49         else
50           TRACE(pidl,"empty pidl (Desktop)\n"); 
51 }
52 /*************************************************************************
53  * ILGetDisplayName                     [SHELL32.15]
54  */
55 BOOL32 WINAPI ILGetDisplayName(LPCITEMIDLIST iil,LPSTR path)
56 {       FIXME(pidl,"(%p,%p),stub, return e:!\n",iil,path);
57         strcpy(path,"e:\\");
58         return TRUE;
59 }
60 /*************************************************************************
61  * ILFindLastID [SHELL32.16]
62  */
63 LPITEMIDLIST WINAPI ILFindLastID(LPITEMIDLIST pidl) 
64 {       LPITEMIDLIST   pidlLast = NULL;
65
66         TRACE(pidl,"(pidl=%p)\n",pidl);
67
68         if(pidl)
69         { while(pidl->mkid.cb)
70           { pidlLast = (LPITEMIDLIST)pidl;
71             pidl = ILGetNext(pidl);
72           }  
73         }
74         return pidlLast;                
75 }
76 /*************************************************************************
77  * ILRemoveLastID [SHELL32.17]
78  * NOTES
79  *  Removes the last item 
80  */
81 BOOL32 WINAPI ILRemoveLastID(LPCITEMIDLIST pidl)
82 {       TRACE(shell,"pidl=%p\n",pidl);
83         if (!pidl || !pidl->mkid.cb)
84           return 0;
85         ILFindLastID(pidl)->mkid.cb = 0;
86         return 1;
87 }
88
89 /*************************************************************************
90  * ILClone [SHELL32.18]
91  *
92  * NOTES
93  *    dupicate an idlist
94  */
95 LPITEMIDLIST WINAPI ILClone (LPCITEMIDLIST pidl)
96 { DWORD    len;
97   LPITEMIDLIST  newpidl;
98
99   if (!pidl)
100     return NULL;
101     
102   len = ILGetSize(pidl);
103   newpidl = (LPITEMIDLIST)SHAlloc(len);
104   if (newpidl)
105     memcpy(newpidl,pidl,len);
106
107   TRACE(pidl,"pidl=%p newpidl=%p\n",pidl, newpidl);
108   pdump(pidl);
109
110   return newpidl;
111 }
112 /*************************************************************************
113  * ILCloneFirst [SHELL32.19]
114  *
115  * NOTES
116  *  duplicates the first idlist of a complex pidl
117  */
118 LPITEMIDLIST WINAPI ILCloneFirst(LPCITEMIDLIST pidl)
119 {       DWORD len;
120         LPITEMIDLIST newpidl=NULL;
121         
122         TRACE(pidl,"pidl=%p \n",pidl);
123         pdump(pidl);
124         
125         if (pidl)
126         { len = pidl->mkid.cb;  
127           newpidl = (LPITEMIDLIST) SHAlloc (len+2);
128           if (newpidl)
129           { memcpy(newpidl,pidl,len);
130             ILGetNext(newpidl)->mkid.cb = 0x00;
131           }
132         }
133         TRACE(pidl,"-- newpidl=%p\n",newpidl);
134
135         return newpidl;
136 }
137 /*************************************************************************
138  * ILIsEqual [SHELL32.21]
139  *
140  */
141 BOOL32 WINAPI ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
142 {       FIXME(pidl,"pidl1=%p pidl2=%p stub\n",pidl1, pidl2);
143         pdump (pidl1);
144         pdump (pidl2);
145         return FALSE;
146 }
147 /*************************************************************************
148  * ILFindChild [SHELL32.24]
149  *
150  */
151 DWORD WINAPI ILFindChild(LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2)
152 {       FIXME(pidl,"%p %p stub\n",pidl1,pidl2);
153         pdump (pidl1);
154         pdump (pidl2);
155         return 0;
156 }
157
158 /*************************************************************************
159  * ILCombine [SHELL32.25]
160  *
161  * NOTES
162  *  Concatenates two complex idlists.
163  *  The pidl is the first one, pidlsub the next one
164  *  Does not destroy the passed in idlists!
165  */
166 LPITEMIDLIST WINAPI ILCombine(LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2)
167 { DWORD    len1,len2;
168   LPITEMIDLIST  pidlNew;
169   
170   TRACE(pidl,"pidl=%p pidl=%p\n",pidl1,pidl2);
171
172   if(!pidl1 && !pidl2)
173   {  return NULL;
174   }
175
176   pdump (pidl1);
177   pdump (pidl2);
178  
179   if(!pidl1)
180   { pidlNew = ILClone(pidl2);
181     return pidlNew;
182   }
183
184   if(!pidl2)
185   { pidlNew = ILClone(pidl1);
186     return pidlNew;
187   }
188
189   len1  = ILGetSize(pidl1)-2;
190   len2  = ILGetSize(pidl2);
191   pidlNew  = SHAlloc(len1+len2);
192   
193   if (pidlNew)
194   { memcpy(pidlNew,pidl1,len1);
195     memcpy(((BYTE *)pidlNew)+len1,pidl2,len2);
196   }
197
198 /*  TRACE(pidl,"--new pidl=%p\n",pidlNew);*/
199   return pidlNew;
200 }
201 /*************************************************************************
202  *  SHGetRealIDL [SHELL32.98]
203  *
204  * NOTES
205  */
206 LPITEMIDLIST WINAPI SHGetRealIDL(DWORD x, DWORD y, DWORD z)
207 {       FIXME(pidl,"0x%04lx 0x%04lx 0x%04lx\n",x,y,z);
208         return 0;
209 }
210
211 /*************************************************************************
212  *  SHLogILFromFSIL [SHELL32.95]
213  *
214  * NOTES
215  *  might be the prepending of MyComputer to a filesystem pidl (?)
216  */
217 LPITEMIDLIST WINAPI SHLogILFromFSIL(LPITEMIDLIST pidl)
218 {       FIXME(pidl,"(pidl=%p)\n",pidl);
219         pdump(pidl);
220         return ILClone(pidl);
221 }
222
223 /*************************************************************************
224  * ILGetSize [SHELL32.152]
225  *  gets the byte size of an idlist including zero terminator (pidl)
226  *
227  * PARAMETERS
228  *  pidl ITEMIDLIST
229  *
230  * RETURNS
231  *  size of pidl
232  *
233  * NOTES
234  *  exported by ordinal
235  */
236 DWORD WINAPI ILGetSize(LPITEMIDLIST pidl)
237 {       LPSHITEMID si = &(pidl->mkid);
238         DWORD  len=0;
239
240         if (pidl)
241         { while (si->cb) 
242           { len += si->cb;
243             si  = (LPSHITEMID)(((LPBYTE)si)+si->cb);
244           }
245           len += 2;
246         }
247         TRACE(pidl,"pidl=%p size=%lu\n",pidl, len);
248         return len;
249 }
250 /*************************************************************************
251  * ILGetNext [SHELL32.153]
252  *  gets the next simple pidl of a complex pidl
253  *
254  * PARAMETERS
255  *  pidl ITEMIDLIST
256  *
257  * RETURNS
258  *  pointer to next element
259  *
260  */
261 LPITEMIDLIST WINAPI ILGetNext(LPITEMIDLIST pidl)
262 {       LPITEMIDLIST nextpidl;
263
264         TRACE(pidl,"(pidl=%p)\n",pidl);
265         if(pidl)
266         { nextpidl = (LPITEMIDLIST)(LPBYTE)(((LPBYTE)pidl) + pidl->mkid.cb);
267           return nextpidl;
268         }
269         else
270         {  return (NULL);
271         }
272 }
273 /*************************************************************************
274  * ILAppend [SHELL32.154]
275  *
276  * NOTES
277  *  Adds the single item to the idlist indicated by pidl.
278  *  if bEnd is 0, adds the item to the front of the list,
279  *  otherwise adds the item to the end. (???)
280  *  Destroys the passed in idlist! (???)
281  */
282 LPITEMIDLIST WINAPI ILAppend(LPITEMIDLIST pidl,LPCITEMIDLIST item,BOOL32 bEnd)
283 {       LPITEMIDLIST idlRet;
284         WARN(pidl,"(pidl=%p,pidl=%p,%08u)semi-stub\n",pidl,item,bEnd);
285         pdump (pidl);
286         pdump (item);
287         
288         if (_ILIsDesktop(pidl))
289         {  idlRet = ILClone(item);
290            if (pidl)
291              SHFree (pidl);
292            return idlRet;
293         }  
294         idlRet=ILCombine(pidl,item);
295         SHFree(pidl);
296         return idlRet;
297 }
298 /*************************************************************************
299  * ILFree [SHELL32.155]
300  *
301  * NOTES
302  *     free_check_ptr - frees memory (if not NULL)
303  *     allocated by SHMalloc allocator
304  *     exported by ordinal
305  */
306 DWORD WINAPI ILFree(LPVOID pidl) 
307 {       TRACE(pidl,"(pidl=0x%08lx)\n",(DWORD)pidl);
308         if (!pidl)
309           return 0;
310         return SHFree(pidl);
311 }
312 /*************************************************************************
313  * ILCreateFromPath [SHELL32.157]
314  *
315  */
316 LPITEMIDLIST WINAPI ILCreateFromPath(LPSTR path) 
317 {       LPSHELLFOLDER shellfolder;
318         LPITEMIDLIST pidlnew;
319         CHAR pszTemp[MAX_PATH*2];
320         LPWSTR lpszDisplayName = (LPWSTR)&pszTemp[0];
321         DWORD pchEaten;
322         
323         TRACE(pidl,"(path=%s)\n",path);
324         
325         LocalToWideChar32(lpszDisplayName, path, MAX_PATH);
326   
327         if (SHGetDesktopFolder(&shellfolder)==S_OK)
328         { shellfolder->lpvtbl->fnParseDisplayName(shellfolder,0, NULL,lpszDisplayName,&pchEaten,&pidlnew,NULL);
329           shellfolder->lpvtbl->fnRelease(shellfolder);
330         }
331         return pidlnew;
332 }
333
334 /**************************************************************************
335 * internal functions
336 */
337
338 /**************************************************************************
339  *  _ILCreateDesktop()
340  *  _ILCreateMyComputer()
341  *  _ILCreateDrive()
342  *  _ILCreateFolder() 
343  *  _ILCreateValue()
344  */
345 LPITEMIDLIST WINAPI _ILCreateDesktop()
346 {       TRACE(pidl,"()\n");
347         return _ILCreate(PT_DESKTOP, NULL, 0);
348 }
349 LPITEMIDLIST WINAPI _ILCreateMyComputer()
350 { TRACE(pidl,"()\n");
351   return _ILCreate(PT_MYCOMP, (void *)"My Computer", strlen ("My Computer")+1);
352 }
353 LPITEMIDLIST WINAPI _ILCreateDrive( LPCSTR lpszNew)
354 {       char sTemp[4];
355         strncpy (sTemp,lpszNew,4);
356         sTemp[2]='\\';
357         sTemp[3]=0x00;
358         TRACE(pidl,"(%s)\n",sTemp);
359         return _ILCreate(PT_DRIVE,(LPVOID)&sTemp[0],4);
360 }
361 LPITEMIDLIST WINAPI _ILCreateFolder( LPCSTR lpszNew)
362 { TRACE(pidl,"(%s)\n",lpszNew);
363   return _ILCreate(PT_FOLDER, (LPVOID)lpszNew, strlen(lpszNew)+1);
364 }
365 LPITEMIDLIST WINAPI _ILCreateValue(LPCSTR lpszNew)
366 { TRACE(pidl,"(%s)\n",lpszNew);
367   return _ILCreate(PT_VALUE, (LPVOID)lpszNew, strlen(lpszNew)+1);
368 }
369
370 /**************************************************************************
371  *  _ILGetDrive()
372  *
373  *  FIXME: quick hack
374  */
375 BOOL32 WINAPI _ILGetDrive(LPCITEMIDLIST pidl,LPSTR pOut, UINT16 uSize)
376 {       LPITEMIDLIST   pidlTemp=NULL;
377
378         TRACE(pidl,"(%p,%p,%u)\n",pidl,pOut,uSize);
379         if(_ILIsMyComputer(pidl))
380         { pidlTemp = ILGetNext(pidl);
381         }
382         else if (pidlTemp && _ILIsDrive(pidlTemp))
383         { return (BOOL32)_ILGetData(PT_DRIVE, pidlTemp, (LPVOID)pOut, uSize);
384         }
385         return FALSE;
386 }
387 /**************************************************************************
388  *  _ILGetItemText()
389  *  Gets the text for only this item
390  */
391 DWORD WINAPI _ILGetItemText(LPCITEMIDLIST pidl, LPSTR lpszText, UINT16 uSize)
392 {       TRACE(pidl,"(pidl=%p %p %x)\n",pidl,lpszText,uSize);
393         if (_ILIsMyComputer(pidl))
394         { return _ILGetData(PT_MYCOMP, pidl, (LPVOID)lpszText, uSize);
395         }
396         if (_ILIsDrive(pidl))
397         { return _ILGetData(PT_DRIVE, pidl, (LPVOID)lpszText, uSize);
398         }
399         if (_ILIsFolder (pidl))
400         { return _ILGetData(PT_FOLDER, pidl, (LPVOID)lpszText, uSize);
401         }
402         return _ILGetData(PT_VALUE, pidl, (LPVOID)lpszText, uSize);     
403 }
404 /**************************************************************************
405  *  _ILIsDesktop()
406  *  _ILIsDrive()
407  *  _ILIsFolder()
408  *  _ILIsValue()
409  */
410 BOOL32 WINAPI _ILIsDesktop(LPCITEMIDLIST pidl)
411 { TRACE(pidl,"(%p)\n",pidl);
412
413   if (! pidl)
414     return TRUE;
415
416   return (  pidl->mkid.cb == 0x00 );
417 }
418
419 BOOL32 WINAPI _ILIsMyComputer(LPCITEMIDLIST pidl)
420 { LPPIDLDATA  pData;
421   TRACE(pidl,"(%p)\n",pidl);
422
423   if (! pidl)
424     return FALSE;
425
426   pData = _ILGetDataPointer(pidl);
427   return (PT_MYCOMP == pData->type);
428 }
429
430 BOOL32 WINAPI _ILIsDrive(LPCITEMIDLIST pidl)
431 { LPPIDLDATA  pData;
432   TRACE(pidl,"(%p)\n",pidl);
433
434   if (! pidl)
435     return FALSE;
436
437   pData = _ILGetDataPointer(pidl);
438   return (PT_DRIVE == pData->type);
439 }
440
441 BOOL32 WINAPI _ILIsFolder(LPCITEMIDLIST pidl)
442 { LPPIDLDATA  pData;
443   TRACE(pidl,"(%p)\n",pidl);
444
445   if (! pidl)
446     return FALSE;
447
448   pData = _ILGetDataPointer(pidl);
449   return (PT_FOLDER == pData->type);
450 }
451
452 BOOL32 WINAPI _ILIsValue(LPCITEMIDLIST pidl)
453 { LPPIDLDATA  pData;
454   TRACE(pidl,"(%p)\n",pidl);
455
456   if (! pidl)
457     return FALSE;
458
459   pData = _ILGetDataPointer(pidl);
460   return (PT_VALUE == pData->type);
461 }
462 /**************************************************************************
463  * _ILHasFolders()
464  * fixme: quick hack
465  */
466 BOOL32 WINAPI _ILHasFolders( LPSTR pszPath, LPCITEMIDLIST pidl)
467 {       BOOL32 bResult= FALSE;
468         WIN32_FIND_DATA32A stffile;     
469         HANDLE32 hFile;
470
471         TRACE(pidl,"%p %p\n", pszPath, pidl);
472         
473         hFile = FindFirstFile32A(pszPath,&stffile);
474         do
475         { if (! (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
476           {  bResult= TRUE;       
477           }
478         } while( FindNextFile32A(hFile,&stffile));
479         FindClose32 (hFile);
480         
481         return bResult;
482 }
483
484 /**************************************************************************
485  *  _ILGetFolderText()
486  *  Creates a Path string from a PIDL, filtering out the special Folders 
487  */
488 DWORD WINAPI _ILGetFolderText(LPCITEMIDLIST pidl,LPSTR lpszPath, DWORD dwSize)
489 {       LPITEMIDLIST    pidlTemp;
490         DWORD           dwCopied = 0;
491         LPSTR           pText;
492  
493         TRACE(pidl,"(%p path=%p)\n",pidl, lpszPath);
494  
495         if(!pidl)
496         { return 0;
497         }
498
499         if(_ILIsMyComputer(pidl))
500         { pidlTemp = ILGetNext(pidl);
501           TRACE(pidl,"-- skip My Computer\n");
502         }
503         else
504         { pidlTemp = (LPITEMIDLIST)pidl;
505         }
506
507         //if this is NULL, return the required size of the buffer
508         if(!lpszPath)
509         { while(pidlTemp->mkid.cb)
510           { LPPIDLDATA  pData = _ILGetDataPointer(pidlTemp);
511             pText = _ILGetTextPointer(pData->type,pData);         
512
513             /*add the length of this item plus one for the backslash
514             fixme: is one to much, drive has its own backslash*/
515             dwCopied += strlen(pText) + 1;          
516             pidlTemp = ILGetNext(pidlTemp);
517           }
518
519           //add one for the NULL terminator
520           TRACE(pidl,"-- (size=%lu)\n",dwCopied);
521           return dwCopied + 1;
522         }
523
524         *lpszPath = 0;
525
526         while(pidlTemp->mkid.cb && (dwCopied < dwSize))
527         { LPPIDLDATA  pData = _ILGetDataPointer(pidlTemp);
528
529           //if this item is a value, then skip it and finish
530           if(PT_VALUE == pData->type)
531           { break;
532           }
533           pText = _ILGetTextPointer(pData->type,pData);   
534           strcat(lpszPath, pText);
535           PathAddBackslash(lpszPath);
536           dwCopied += strlen(pText) + 1;
537           pidlTemp = ILGetNext(pidlTemp);
538
539           TRACE(pidl,"-- (size=%lu,%s)\n",dwCopied,lpszPath);
540         }
541
542         //remove the last backslash if necessary
543         if(dwCopied)
544         { if(*(lpszPath + strlen(lpszPath) - 1) == '\\')
545           { *(lpszPath + strlen(lpszPath) - 1) = 0;
546             dwCopied--;
547           }
548         }
549         TRACE(pidl,"-- (path=%s)\n",lpszPath);
550         return dwCopied;
551 }
552
553
554 /**************************************************************************
555  *  _ILGetValueText()
556  *  Gets the text for the last item in the list
557  */
558 DWORD WINAPI _ILGetValueText(
559     LPCITEMIDLIST pidl, LPSTR lpszValue, DWORD dwSize)
560 {       LPITEMIDLIST  pidlTemp=pidl;
561         CHAR          szText[MAX_PATH];
562
563         TRACE(pidl,"(pidl=%p %p 0x%08lx)\n",pidl,lpszValue,dwSize);
564
565         if(!pidl)
566         { return 0;
567         }
568                 
569         while(pidlTemp->mkid.cb && !_ILIsValue(pidlTemp))
570         { pidlTemp = ILGetNext(pidlTemp);
571         }
572
573         if(!pidlTemp->mkid.cb)
574         { return 0;
575         }
576
577         _ILGetItemText( pidlTemp, szText, sizeof(szText));
578
579         if(!lpszValue)
580         { return strlen(szText) + 1;
581         }
582         strcpy(lpszValue, szText);
583         TRACE(pidl,"-- (pidl=%p %p=%s 0x%08lx)\n",pidl,lpszValue,lpszValue,dwSize);
584         return strlen(lpszValue);
585 }
586 /**************************************************************************
587  *  _ILGetDataText()
588  * NOTES
589  *  used from ShellView
590  */
591 DWORD WINAPI _ILGetDataText( LPCITEMIDLIST pidlPath, LPCITEMIDLIST pidlValue, LPSTR lpszOut, DWORD dwOutSize)
592 { LPSTR    lpszFolder,
593            lpszValueName;
594   DWORD    dwNameSize;
595
596   FIXME(pidl,"(pidl=%p pidl=%p) stub\n",pidlPath,pidlValue);
597
598   if(!lpszOut || !pidlPath || !pidlValue)
599   { return FALSE;
600         }
601
602   /* fixme: get the driveletter*/
603
604   //assemble the Folder string
605   dwNameSize = _ILGetFolderText(pidlPath, NULL, 0);
606   lpszFolder = (LPSTR)HeapAlloc(GetProcessHeap(),0,dwNameSize);
607   if(!lpszFolder)
608   {  return FALSE;
609         }
610   _ILGetFolderText(pidlPath, lpszFolder, dwNameSize);
611
612   //assemble the value name
613   dwNameSize = _ILGetValueText(pidlValue, NULL, 0);
614   lpszValueName = (LPSTR)HeapAlloc(GetProcessHeap(),0,dwNameSize);
615   if(!lpszValueName)
616   { HeapFree(GetProcessHeap(),0,lpszFolder);
617     return FALSE;
618   }
619   _ILGetValueText(pidlValue, lpszValueName, dwNameSize);
620
621   /* fixme: we've got the path now do something with it*/
622         
623   HeapFree(GetProcessHeap(),0,lpszFolder);
624   HeapFree(GetProcessHeap(),0,lpszValueName);
625
626   TRACE(pidl,"-- (%p=%s 0x%08lx)\n",lpszOut,lpszOut,dwOutSize);
627
628         return TRUE;
629 }
630
631 /**************************************************************************
632  *  _ILGetPidlPath()
633  *  Create a string that includes the Drive name, the folder text and 
634  *  the value text.
635  */
636 DWORD WINAPI _ILGetPidlPath( LPCITEMIDLIST pidl, LPSTR lpszOut, DWORD dwOutSize)
637 { LPSTR lpszTemp;
638   WORD  len;
639
640   TRACE(pidl,"(%p,%lu)\n",lpszOut,dwOutSize);
641
642   if(!lpszOut)
643   { return 0;
644         }
645
646   *lpszOut = 0;
647   lpszTemp = lpszOut;
648
649   dwOutSize -= _ILGetFolderText(pidl, lpszTemp, dwOutSize);
650
651   //add a backslash if necessary
652   len = strlen(lpszTemp);
653   if (len && lpszTemp[len-1]!='\\')
654         { lpszTemp[len+0]='\\';
655     lpszTemp[len+1]='\0';
656                 dwOutSize--;
657   }
658
659   lpszTemp = lpszOut + strlen(lpszOut);
660
661   //add the value string
662   _ILGetValueText(pidl, lpszTemp, dwOutSize);
663
664   //remove the last backslash if necessary
665   if(*(lpszOut + strlen(lpszOut) - 1) == '\\')
666   { *(lpszOut + strlen(lpszOut) - 1) = 0;
667   }
668
669   TRACE(pidl,"-- (%p=%s,%lu)\n",lpszOut,lpszOut,dwOutSize);
670
671   return strlen(lpszOut);
672
673 }
674
675 /**************************************************************************
676  *  _ILCreate()
677  *  Creates a new PIDL
678  *  type = PT_DESKTOP | PT_DRIVE | PT_FOLDER | PT_VALUE
679  *  pIn = data
680  *  uInSize = size of data
681  */
682
683 LPITEMIDLIST WINAPI _ILCreate(PIDLTYPE type, LPVOID pIn, UINT16 uInSize)
684 {       LPITEMIDLIST   pidlOut=NULL;
685         UINT16         uSize;
686         LPITEMIDLIST   pidlTemp=NULL;
687         LPPIDLDATA     pData;
688         LPSTR   pszDest;
689         
690         TRACE(pidl,"(%x %p %x)\n",type,pIn,uInSize);
691
692         if ( type == PT_DESKTOP)
693         { pidlOut = SHAlloc(2);
694           pidlOut->mkid.cb=0x0000;
695           return pidlOut;
696         }
697
698         if (! pIn)
699         { return NULL;
700         }       
701
702         /* the sizes of: cb(2), pidldata-1, szText+1, next cb(2) */
703         switch (type)
704         { case PT_DRIVE:
705             uSize = 4 + 9;
706             break;
707           default:
708             uSize = 4 + (sizeof(PIDLDATA)) + uInSize; 
709          }   
710         pidlOut = SHAlloc(uSize);
711         pidlTemp = pidlOut;
712         if(pidlOut)
713         { pidlTemp->mkid.cb = uSize - 2;
714           pData =_ILGetDataPointer(pidlTemp);
715           pszDest =  _ILGetTextPointer(type, pData);
716           pData->type = type;
717           switch(type)
718           { case PT_MYCOMP:
719               memcpy(pszDest, pIn, uInSize);
720               TRACE(pidl,"- create My Computer: %s\n",debugstr_a(pszDest));
721               break;
722             case PT_DRIVE:
723               memcpy(pszDest, pIn, uInSize);
724               TRACE(pidl,"- create Drive: %s\n",debugstr_a(pszDest));
725               break;
726             case PT_FOLDER:
727             case PT_VALUE:   
728               memcpy(pszDest, pIn, uInSize);
729               TRACE(pidl,"- create Value: %s\n",debugstr_a(pszDest));
730               break;
731             default: 
732               FIXME(pidl,"-- wrong argument\n");
733               break;
734           }
735    
736           pidlTemp = ILGetNext(pidlTemp);
737           pidlTemp->mkid.cb = 0x00;
738         }
739         TRACE(pidl,"-- (pidl=%p, size=%u)\n",pidlOut,uSize-2);
740         return pidlOut;
741 }
742 /**************************************************************************
743  *  _ILGetData(PIDLTYPE, LPCITEMIDLIST, LPVOID, UINT16)
744  */
745 DWORD WINAPI _ILGetData(PIDLTYPE type, LPCITEMIDLIST pidl, LPVOID pOut, UINT16 uOutSize)
746 {       LPPIDLDATA  pData;
747         DWORD       dwReturn=0; 
748         LPSTR       pszSrc;
749         
750         TRACE(pidl,"(%x %p %p %x)\n",type,pidl,pOut,uOutSize);
751         
752         if(!pidl)
753         {  return 0;
754         }
755
756         *(LPSTR)pOut = 0;        
757
758         pData = _ILGetDataPointer(pidl);
759         if ( pData->type != type)
760         { ERR(pidl,"-- wrong type\n");
761           return 0;
762         }
763         pszSrc = _ILGetTextPointer(pData->type, pData);
764
765         switch(type)
766         { case PT_MYCOMP:
767             if(uOutSize < 1)
768               return 0;
769             strncpy((LPSTR)pOut, "My Computer", uOutSize);
770             dwReturn = strlen((LPSTR)pOut);
771             break;
772
773           case PT_DRIVE:
774             if(uOutSize < 1)
775               return 0;
776             strncpy((LPSTR)pOut, pszSrc, uOutSize);
777             dwReturn = strlen((LPSTR)pOut);
778             break;
779
780           case PT_FOLDER:
781           case PT_VALUE: 
782              strncpy((LPSTR)pOut, pszSrc, uOutSize);
783              dwReturn = strlen((LPSTR)pOut);
784              break;
785           default:
786             ERR(pidl,"-- unknown type\n");
787             break;                                                                               
788         }
789         TRACE(pidl,"-- (%p=%s 0x%08lx)\n",pOut,(char*)pOut,dwReturn);
790         return dwReturn;
791 }
792
793
794 /**************************************************************************
795  *  _ILGetDataPointer()
796  */
797 LPPIDLDATA WINAPI _ILGetDataPointer(LPITEMIDLIST pidl)
798 {       if(!pidl)
799         { return NULL;
800         }
801 /*      TRACE(pidl,"(%p)\n",  pidl);*/
802         return (LPPIDLDATA)(&pidl->mkid.abID);
803 }
804 /**************************************************************************
805  *  _ILGetTextPointer()
806  * gets a pointer to the string stored in the pidl
807  */
808 LPSTR WINAPI _ILGetTextPointer(PIDLTYPE type, LPPIDLDATA pidldata)
809 {/*     TRACE(pidl,"(type=%x data=%p)\n", type, pidldata);*/
810
811         if(!pidldata)
812         { return NULL;
813         }
814         switch (type)
815         { case PT_DRIVE:
816             return (LPSTR)&(pidldata->u.drive.szDriveName);
817           case PT_MYCOMP:
818           case PT_FOLDER:
819           case PT_VALUE:
820             return (LPSTR)&(pidldata->u.file.szText);
821         }
822         return NULL;
823 }
824
825 /**************************************************************************
826  *  IDLList "Item ID List List"
827  * 
828  */
829 static UINT32 WINAPI IDLList_GetState(LPIDLLIST this);
830 static LPITEMIDLIST WINAPI IDLList_GetElement(LPIDLLIST this, UINT32 nIndex);
831 static UINT32 WINAPI IDLList_GetCount(LPIDLLIST this);
832 static BOOL32 WINAPI IDLList_StoreItem(LPIDLLIST this, LPITEMIDLIST pidl);
833 static BOOL32 WINAPI IDLList_AddItems(LPIDLLIST this, LPITEMIDLIST *apidl, UINT32 cidl);
834 static BOOL32 WINAPI IDLList_InitList(LPIDLLIST this);
835 static void WINAPI IDLList_CleanList(LPIDLLIST this);
836
837 static IDLList_VTable idllvt = 
838 {       IDLList_GetState,
839         IDLList_GetElement,
840         IDLList_GetCount,
841         IDLList_StoreItem,
842         IDLList_AddItems,
843         IDLList_InitList,
844         IDLList_CleanList
845 };
846
847 LPIDLLIST IDLList_Constructor (UINT32 uStep)
848 {       LPIDLLIST lpidll;
849         if (!(lpidll = (LPIDLLIST)HeapAlloc(GetProcessHeap(),0,sizeof(IDLList))))
850           return NULL;
851
852         lpidll->lpvtbl=&idllvt;
853         lpidll->uStep=uStep;
854         lpidll->dpa=NULL;
855
856         TRACE (shell,"(%p)\n",lpidll);
857         return lpidll;
858 }
859 void IDLList_Destructor(LPIDLLIST this)
860 {       TRACE (shell,"(%p)\n",this);
861         IDLList_CleanList(this);
862 }
863  
864 static UINT32 WINAPI IDLList_GetState(LPIDLLIST this)
865 {       TRACE (shell,"(%p)->(uStep=%u dpa=%p)\n",this, this->uStep, this->dpa);
866
867         if (this->uStep == 0)
868         { if (this->dpa)
869             return(State_Init);
870           return(State_OutOfMem);
871         }
872         return(State_UnInit);
873 }
874 static LPITEMIDLIST WINAPI IDLList_GetElement(LPIDLLIST this, UINT32 nIndex)
875 {       TRACE (shell,"(%p)->(index=%u)\n",this, nIndex);
876         return((LPITEMIDLIST)DPA_GetPtr(this->dpa, nIndex));
877 }
878 static UINT32 WINAPI IDLList_GetCount(LPIDLLIST this)
879 {       TRACE (shell,"(%p)\n",this);
880         return(IDLList_GetState(this)==State_Init ? DPA_GetPtrCount(this->dpa) : 0);
881 }
882 static BOOL32 WINAPI IDLList_StoreItem(LPIDLLIST this, LPITEMIDLIST pidl)
883 {       TRACE (shell,"(%p)->(pidl=%p)\n",this, pidl);
884         if (pidl)
885         { if (IDLList_InitList(this) && DPA_InsertPtr(this->dpa, 0x7fff, (LPSTR)pidl)>=0)
886             return(TRUE);
887           ILFree(pidl);
888         }
889         IDLList_CleanList(this);
890         return(FALSE);
891 }
892 static BOOL32 WINAPI IDLList_AddItems(LPIDLLIST this, LPITEMIDLIST *apidl, UINT32 cidl)
893 {       INT32 i;
894         TRACE (shell,"(%p)->(apidl=%p cidl=%u)\n",this, apidl, cidl);
895
896         for (i=0; i<cidl; ++i)
897         { if (!IDLList_StoreItem(this, ILClone((LPCITEMIDLIST)apidl[i])))
898             return(FALSE);
899         }
900         return(TRUE);
901 }
902 static BOOL32 WINAPI IDLList_InitList(LPIDLLIST this)
903 {       TRACE (shell,"(%p)\n",this);
904         switch (IDLList_GetState(this))
905         { case State_Init:
906             return(TRUE);
907
908           case State_OutOfMem:
909             return(FALSE);
910
911           case State_UnInit:
912           default:
913             this->dpa = DPA_Create(this->uStep);
914             this->uStep = 0;
915             return(IDLList_InitList(this));
916         }
917 }
918 static void WINAPI IDLList_CleanList(LPIDLLIST this)
919 {       INT32 i;
920         TRACE (shell,"(%p)\n",this);
921
922         if (this->uStep != 0)
923         { this->dpa = NULL;
924           this->uStep = 0;
925           return;
926         }
927
928         if (!this->dpa)
929         { return;
930         }
931
932         for (i=DPA_GetPtrCount(this->dpa)-1; i>=0; --i)
933         { ILFree(IDLList_GetElement(this,i));
934         }
935
936         DPA_Destroy(this->dpa);
937         this->dpa=NULL;
938 }