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