4 * Copyright 1998 Juergen Schmied
7 * a pidl == NULL means desktop and is legal
18 #include "interfaces.h"
25 #include "shell32_main.h"
29 void pdump (LPCITEMIDLIST pidl)
32 LPITEMIDLIST pidltemp = pidl;
34 { TRACE(pidl,"-------- pidl = NULL (Root)\n");
37 TRACE(pidl,"-------- pidl=%p \n", pidl);
38 if (pidltemp->mkid.cb)
40 { type = _ILGetDataPointer(pidltemp)->type;
41 szData = _ILGetTextPointer(type, _ILGetDataPointer(pidltemp));
43 TRACE(pidl,"---- pidl=%p size=%u type=%lx %s\n",pidltemp, pidltemp->mkid.cb,type,debugstr_a(szData));
45 pidltemp = ILGetNext(pidltemp);
46 } while (pidltemp->mkid.cb);
50 TRACE(pidl,"empty pidl (Desktop)\n");
52 /*************************************************************************
53 * ILGetDisplayName [SHELL32.15]
55 BOOL32 WINAPI ILGetDisplayName(LPCITEMIDLIST iil,LPSTR path)
56 { FIXME(pidl,"(%p,%p),stub, return e:!\n",iil,path);
60 /*************************************************************************
61 * ILFindLastID [SHELL32.16]
63 LPITEMIDLIST WINAPI ILFindLastID(LPITEMIDLIST pidl)
64 { LPITEMIDLIST pidlLast = NULL;
66 TRACE(pidl,"(pidl=%p)\n",pidl);
69 { while(pidl->mkid.cb)
70 { pidlLast = (LPITEMIDLIST)pidl;
71 pidl = ILGetNext(pidl);
76 /*************************************************************************
77 * ILRemoveLastID [SHELL32.17]
79 * Removes the last item
81 BOOL32 WINAPI ILRemoveLastID(LPCITEMIDLIST pidl)
82 { TRACE(shell,"pidl=%p\n",pidl);
83 if (!pidl || !pidl->mkid.cb)
85 ILFindLastID(pidl)->mkid.cb = 0;
89 /*************************************************************************
90 * ILClone [SHELL32.18]
95 LPITEMIDLIST WINAPI ILClone (LPCITEMIDLIST pidl)
102 len = ILGetSize(pidl);
103 newpidl = (LPITEMIDLIST)SHAlloc(len);
105 memcpy(newpidl,pidl,len);
107 TRACE(pidl,"pidl=%p newpidl=%p\n",pidl, newpidl);
112 /*************************************************************************
113 * ILCloneFirst [SHELL32.19]
116 * duplicates the first idlist of a complex pidl
118 LPITEMIDLIST WINAPI ILCloneFirst(LPCITEMIDLIST pidl)
120 LPITEMIDLIST newpidl=NULL;
123 { len = pidl->mkid.cb;
124 newpidl = (LPITEMIDLIST) SHAlloc (len+2);
126 { memcpy(newpidl,pidl,len);
127 ILGetNext(newpidl)->mkid.cb = 0x00;
130 TRACE(pidl,"pidl=%p newpidl=%p\n",pidl, newpidl);
134 /*************************************************************************
135 * ILIsEqual [SHELL32.21]
138 BOOL32 WINAPI ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
139 { FIXME(pidl,"pidl1=%p pidl2=%p stub\n",pidl1, pidl2);
144 /*************************************************************************
145 * ILFindChild [SHELL32.24]
148 DWORD WINAPI ILFindChild(LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2)
149 { FIXME(pidl,"%p %p stub\n",pidl1,pidl2);
155 /*************************************************************************
156 * ILCombine [SHELL32.25]
159 * Concatenates two complex idlists.
160 * The pidl is the first one, pidlsub the next one
161 * Does not destroy the passed in idlists!
163 LPITEMIDLIST WINAPI ILCombine(LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2)
165 LPITEMIDLIST pidlNew;
167 TRACE(pidl,"pidl=%p pidl=%p\n",pidl1,pidl2);
177 { pidlNew = ILClone(pidl2);
182 { pidlNew = ILClone(pidl1);
186 len1 = ILGetSize(pidl1)-2;
187 len2 = ILGetSize(pidl2);
188 pidlNew = SHAlloc(len1+len2);
191 { memcpy(pidlNew,pidl1,len1);
192 memcpy(((BYTE *)pidlNew)+len1,pidl2,len2);
195 /* TRACE(pidl,"--new pidl=%p\n",pidlNew);*/
198 /*************************************************************************
199 * SHLogILFromFSIL [SHELL32.95]
202 * might be the prepending of MyComputer to a filesystem pidl (?)
204 LPITEMIDLIST WINAPI SHLogILFromFSIL(LPITEMIDLIST pidl)
205 { FIXME(pidl,"(pidl=%p)\n",pidl);
207 return ILClone(pidl);
210 /*************************************************************************
211 * ILGetSize [SHELL32.152]
212 * gets the byte size of an idlist including zero terminator (pidl)
221 * exported by ordinal
223 DWORD WINAPI ILGetSize(LPITEMIDLIST pidl)
224 { LPSHITEMID si = &(pidl->mkid);
230 si = (LPSHITEMID)(((LPBYTE)si)+si->cb);
234 TRACE(pidl,"pidl=%p size=%lu\n",pidl, len);
237 /*************************************************************************
238 * ILGetNext [SHELL32.153]
239 * gets the next simple pidl of a complex pidl
245 * pointer to next element
248 LPITEMIDLIST WINAPI ILGetNext(LPITEMIDLIST pidl)
249 { LPITEMIDLIST nextpidl;
251 TRACE(pidl,"(pidl=%p)\n",pidl);
253 { nextpidl = (LPITEMIDLIST)(LPBYTE)(((LPBYTE)pidl) + pidl->mkid.cb);
260 /*************************************************************************
261 * ILAppend [SHELL32.154]
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!
269 LPITEMIDLIST WINAPI ILAppend(LPITEMIDLIST pidl,LPCITEMIDLIST item,BOOL32 bEnd)
270 { FIXME(pidl,"(pidl=%p,pidl=%p,%08u)stub\n",pidl,item,bEnd);
273 /*************************************************************************
274 * ILFree [SHELL32.155]
277 * free_check_ptr - frees memory (if not NULL)
278 * allocated by SHMalloc allocator
279 * exported by ordinal
281 DWORD WINAPI ILFree(LPVOID pidl)
282 { TRACE(pidl,"(pidl=0x%08lx)\n",(DWORD)pidl);
287 /*************************************************************************
288 * ILCreateFromPath [SHELL32.157]
291 LPITEMIDLIST WINAPI ILCreateFromPath(LPSTR path)
292 { LPSHELLFOLDER shellfolder;
293 LPITEMIDLIST pidlnew;
294 CHAR pszTemp[MAX_PATH*2];
295 LPWSTR lpszDisplayName = (LPWSTR)&pszTemp[0];
298 TRACE(pidl,"(path=%s)\n",path);
300 LocalToWideChar32(lpszDisplayName, path, MAX_PATH);
302 if (SHGetDesktopFolder(&shellfolder)==S_OK)
303 { shellfolder->lpvtbl->fnParseDisplayName(shellfolder,0, NULL,lpszDisplayName,&pchEaten,&pidlnew,NULL);
304 shellfolder->lpvtbl->fnRelease(shellfolder);
309 /**************************************************************************
313 /**************************************************************************
315 * _ILCreateMyComputer()
320 LPITEMIDLIST WINAPI _ILCreateDesktop()
321 { TRACE(pidl,"()\n");
322 return _ILCreate(PT_DESKTOP, NULL, 0);
324 LPITEMIDLIST WINAPI _ILCreateMyComputer()
325 { TRACE(pidl,"()\n");
326 return _ILCreate(PT_MYCOMP, (void *)"My Computer", strlen ("My Computer")+1);
328 LPITEMIDLIST WINAPI _ILCreateDrive( LPCSTR lpszNew)
330 strncpy (sTemp,lpszNew,4);
333 TRACE(pidl,"(%s)\n",sTemp);
334 return _ILCreate(PT_DRIVE,(LPVOID)&sTemp[0],4);
336 LPITEMIDLIST WINAPI _ILCreateFolder( LPCSTR lpszNew)
337 { TRACE(pidl,"(%s)\n",lpszNew);
338 return _ILCreate(PT_FOLDER, (LPVOID)lpszNew, strlen(lpszNew)+1);
340 LPITEMIDLIST WINAPI _ILCreateValue(LPCSTR lpszNew)
341 { TRACE(pidl,"(%s)\n",lpszNew);
342 return _ILCreate(PT_VALUE, (LPVOID)lpszNew, strlen(lpszNew)+1);
345 /**************************************************************************
350 BOOL32 WINAPI _ILGetDrive(LPCITEMIDLIST pidl,LPSTR pOut, UINT16 uSize)
351 { LPITEMIDLIST pidlTemp=NULL;
353 TRACE(pidl,"(%p,%p,%u)\n",pidl,pOut,uSize);
354 if(_ILIsMyComputer(pidl))
355 { pidlTemp = ILGetNext(pidl);
357 else if (pidlTemp && _ILIsDrive(pidlTemp))
358 { return (BOOL32)_ILGetData(PT_DRIVE, pidlTemp, (LPVOID)pOut, uSize);
362 /**************************************************************************
364 * Gets the text for only this item
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);
371 if (_ILIsDrive(pidl))
372 { return _ILGetData(PT_DRIVE, pidl, (LPVOID)lpszText, uSize);
374 if (_ILIsFolder (pidl))
375 { return _ILGetData(PT_FOLDER, pidl, (LPVOID)lpszText, uSize);
377 return _ILGetData(PT_VALUE, pidl, (LPVOID)lpszText, uSize);
379 /**************************************************************************
385 BOOL32 WINAPI _ILIsDesktop(LPCITEMIDLIST pidl)
386 { TRACE(pidl,"(%p)\n",pidl);
391 return ( pidl->mkid.cb == 0x00 );
394 BOOL32 WINAPI _ILIsMyComputer(LPCITEMIDLIST pidl)
396 TRACE(pidl,"(%p)\n",pidl);
401 pData = _ILGetDataPointer(pidl);
402 return (PT_MYCOMP == pData->type);
405 BOOL32 WINAPI _ILIsDrive(LPCITEMIDLIST pidl)
407 TRACE(pidl,"(%p)\n",pidl);
412 pData = _ILGetDataPointer(pidl);
413 return (PT_DRIVE == pData->type);
416 BOOL32 WINAPI _ILIsFolder(LPCITEMIDLIST pidl)
418 TRACE(pidl,"(%p)\n",pidl);
423 pData = _ILGetDataPointer(pidl);
424 return (PT_FOLDER == pData->type);
427 BOOL32 WINAPI _ILIsValue(LPCITEMIDLIST pidl)
429 TRACE(pidl,"(%p)\n",pidl);
434 pData = _ILGetDataPointer(pidl);
435 return (PT_VALUE == pData->type);
437 /**************************************************************************
441 BOOL32 WINAPI _ILHasFolders( LPSTR pszPath, LPCITEMIDLIST pidl)
442 { BOOL32 bResult= FALSE;
443 WIN32_FIND_DATA32A stffile;
446 TRACE(pidl,"%p %p\n", pszPath, pidl);
448 hFile = FindFirstFile32A(pszPath,&stffile);
450 { if (! (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
453 } while( FindNextFile32A(hFile,&stffile));
459 /**************************************************************************
461 * Creates a Path string from a PIDL, filtering out the special Folders
463 DWORD WINAPI _ILGetFolderText(LPCITEMIDLIST pidl,LPSTR lpszPath, DWORD dwSize)
464 { LPITEMIDLIST pidlTemp;
468 TRACE(pidl,"(%p path=%p)\n",pidl, lpszPath);
474 if(_ILIsMyComputer(pidl))
475 { pidlTemp = ILGetNext(pidl);
476 TRACE(pidl,"-- skip My Computer\n");
479 { pidlTemp = (LPITEMIDLIST)pidl;
482 //if this is NULL, return the required size of the buffer
484 { while(pidlTemp->mkid.cb)
485 { LPPIDLDATA pData = _ILGetDataPointer(pidlTemp);
486 pText = _ILGetTextPointer(pData->type,pData);
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);
494 //add one for the NULL terminator
495 TRACE(pidl,"-- (size=%lu)\n",dwCopied);
501 while(pidlTemp->mkid.cb && (dwCopied < dwSize))
502 { LPPIDLDATA pData = _ILGetDataPointer(pidlTemp);
504 //if this item is a value, then skip it and finish
505 if(PT_VALUE == pData->type)
508 pText = _ILGetTextPointer(pData->type,pData);
509 strcat(lpszPath, pText);
510 PathAddBackslash(lpszPath);
511 dwCopied += strlen(pText) + 1;
512 pidlTemp = ILGetNext(pidlTemp);
514 TRACE(pidl,"-- (size=%lu,%s)\n",dwCopied,lpszPath);
517 //remove the last backslash if necessary
519 { if(*(lpszPath + strlen(lpszPath) - 1) == '\\')
520 { *(lpszPath + strlen(lpszPath) - 1) = 0;
524 TRACE(pidl,"-- (path=%s)\n",lpszPath);
529 /**************************************************************************
531 * Gets the text for the last item in the list
533 DWORD WINAPI _ILGetValueText(
534 LPCITEMIDLIST pidl, LPSTR lpszValue, DWORD dwSize)
535 { LPITEMIDLIST pidlTemp=pidl;
536 CHAR szText[MAX_PATH];
538 TRACE(pidl,"(pidl=%p %p 0x%08lx)\n",pidl,lpszValue,dwSize);
544 while(pidlTemp->mkid.cb && !_ILIsValue(pidlTemp))
545 { pidlTemp = ILGetNext(pidlTemp);
548 if(!pidlTemp->mkid.cb)
552 _ILGetItemText( pidlTemp, szText, sizeof(szText));
555 { return strlen(szText) + 1;
557 strcpy(lpszValue, szText);
558 TRACE(pidl,"-- (pidl=%p %p=%s 0x%08lx)\n",pidl,lpszValue,lpszValue,dwSize);
559 return strlen(lpszValue);
561 /**************************************************************************
564 * used from ShellView
566 DWORD WINAPI _ILGetDataText( LPCITEMIDLIST pidlPath, LPCITEMIDLIST pidlValue, LPSTR lpszOut, DWORD dwOutSize)
571 FIXME(pidl,"(pidl=%p pidl=%p) stub\n",pidlPath,pidlValue);
573 if(!lpszOut || !pidlPath || !pidlValue)
577 /* fixme: get the driveletter*/
579 //assemble the Folder string
580 dwNameSize = _ILGetFolderText(pidlPath, NULL, 0);
581 lpszFolder = (LPSTR)HeapAlloc(GetProcessHeap(),0,dwNameSize);
585 _ILGetFolderText(pidlPath, lpszFolder, dwNameSize);
587 //assemble the value name
588 dwNameSize = _ILGetValueText(pidlValue, NULL, 0);
589 lpszValueName = (LPSTR)HeapAlloc(GetProcessHeap(),0,dwNameSize);
591 { HeapFree(GetProcessHeap(),0,lpszFolder);
594 _ILGetValueText(pidlValue, lpszValueName, dwNameSize);
596 /* fixme: we've got the path now do something with it*/
598 HeapFree(GetProcessHeap(),0,lpszFolder);
599 HeapFree(GetProcessHeap(),0,lpszValueName);
601 TRACE(pidl,"-- (%p=%s 0x%08lx)\n",lpszOut,lpszOut,dwOutSize);
606 /**************************************************************************
608 * Create a string that includes the Drive name, the folder text and
611 DWORD WINAPI _ILGetPidlPath( LPCITEMIDLIST pidl, LPSTR lpszOut, DWORD dwOutSize)
615 TRACE(pidl,"(%p,%lu)\n",lpszOut,dwOutSize);
624 dwOutSize -= _ILGetFolderText(pidl, lpszTemp, dwOutSize);
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';
634 lpszTemp = lpszOut + strlen(lpszOut);
636 //add the value string
637 _ILGetValueText(pidl, lpszTemp, dwOutSize);
639 //remove the last backslash if necessary
640 if(*(lpszOut + strlen(lpszOut) - 1) == '\\')
641 { *(lpszOut + strlen(lpszOut) - 1) = 0;
644 TRACE(pidl,"-- (%p=%s,%lu)\n",lpszOut,lpszOut,dwOutSize);
646 return strlen(lpszOut);
650 /**************************************************************************
653 * type = PT_DESKTOP | PT_DRIVE | PT_FOLDER | PT_VALUE
655 * uInSize = size of data
658 LPITEMIDLIST WINAPI _ILCreate(PIDLTYPE type, LPVOID pIn, UINT16 uInSize)
659 { LPITEMIDLIST pidlOut=NULL;
661 LPITEMIDLIST pidlTemp=NULL;
665 TRACE(pidl,"(%x %p %x)\n",type,pIn,uInSize);
667 if ( type == PT_DESKTOP)
668 { pidlOut = SHAlloc(2);
669 pidlOut->mkid.cb=0x0000;
677 /* the sizes of: cb(2), pidldata-1, szText+1, next cb(2) */
683 uSize = 4 + (sizeof(PIDLDATA)) + uInSize;
685 pidlOut = SHAlloc(uSize);
688 { pidlTemp->mkid.cb = uSize - 2;
689 pData =_ILGetDataPointer(pidlTemp);
690 pszDest = _ILGetTextPointer(type, pData);
694 memcpy(pszDest, pIn, uInSize);
695 TRACE(pidl,"- create My Computer: %s\n",debugstr_a(pszDest));
698 memcpy(pszDest, pIn, uInSize);
699 TRACE(pidl,"- create Drive: %s\n",debugstr_a(pszDest));
703 memcpy(pszDest, pIn, uInSize);
704 TRACE(pidl,"- create Value: %s\n",debugstr_a(pszDest));
707 FIXME(pidl,"-- wrong argument\n");
711 pidlTemp = ILGetNext(pidlTemp);
712 pidlTemp->mkid.cb = 0x00;
714 TRACE(pidl,"-- (pidl=%p, size=%u)\n",pidlOut,uSize-2);
717 /**************************************************************************
718 * _ILGetData(PIDLTYPE, LPCITEMIDLIST, LPVOID, UINT16)
720 DWORD WINAPI _ILGetData(PIDLTYPE type, LPCITEMIDLIST pidl, LPVOID pOut, UINT16 uOutSize)
725 TRACE(pidl,"(%x %p %p %x)\n",type,pidl,pOut,uOutSize);
733 pData = _ILGetDataPointer(pidl);
734 if ( pData->type != type)
735 { ERR(pidl,"-- wrong type\n");
738 pszSrc = _ILGetTextPointer(pData->type, pData);
744 strncpy((LPSTR)pOut, "My Computer", uOutSize);
745 dwReturn = strlen((LPSTR)pOut);
751 strncpy((LPSTR)pOut, pszSrc, uOutSize);
752 dwReturn = strlen((LPSTR)pOut);
757 strncpy((LPSTR)pOut, pszSrc, uOutSize);
758 dwReturn = strlen((LPSTR)pOut);
761 ERR(pidl,"-- unknown type\n");
764 TRACE(pidl,"-- (%p=%s 0x%08lx)\n",pOut,(char*)pOut,dwReturn);
769 /**************************************************************************
770 * _ILGetDataPointer()
772 LPPIDLDATA WINAPI _ILGetDataPointer(LPITEMIDLIST pidl)
776 /* TRACE(pidl,"(%p)\n", pidl);*/
777 return (LPPIDLDATA)(&pidl->mkid.abID);
779 /**************************************************************************
780 * _ILGetTextPointer()
781 * gets a pointer to the string stored in the pidl
783 LPSTR WINAPI _ILGetTextPointer(PIDLTYPE type, LPPIDLDATA pidldata)
784 {/* TRACE(pidl,"(type=%x data=%p)\n", type, pidldata);*/
791 return (LPSTR)&(pidldata->u.drive.szDriveName);
795 return (LPSTR)&(pidldata->u.file.szText);
800 /**************************************************************************
801 * IDLList "Item ID List List"
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);
812 static IDLList_VTable idllvt =
822 LPIDLLIST IDLList_Constructor (UINT32 uStep)
824 if (!(lpidll = (LPIDLLIST)HeapAlloc(GetProcessHeap(),0,sizeof(IDLList))))
827 lpidll->lpvtbl=&idllvt;
831 TRACE (shell,"(%p)\n",lpidll);
834 void IDLList_Destructor(LPIDLLIST this)
835 { TRACE (shell,"(%p)\n",this);
836 IDLList_CleanList(this);
839 static UINT32 WINAPI IDLList_GetState(LPIDLLIST this)
840 { TRACE (shell,"(%p)->(uStep=%u dpa=%p)\n",this, this->uStep, this->dpa);
842 if (this->uStep == 0)
845 return(State_OutOfMem);
847 return(State_UnInit);
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));
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);
857 static BOOL32 WINAPI IDLList_StoreItem(LPIDLLIST this, LPITEMIDLIST pidl)
858 { TRACE (shell,"(%p)->(pidl=%p)\n",this, pidl);
860 { if (IDLList_InitList(this) && DPA_InsertPtr(this->dpa, 0x7fff, (LPSTR)pidl)>=0)
864 IDLList_CleanList(this);
867 static BOOL32 WINAPI IDLList_AddItems(LPIDLLIST this, LPITEMIDLIST *apidl, UINT32 cidl)
869 TRACE (shell,"(%p)->(apidl=%p cidl=%u)\n",this, apidl, cidl);
871 for (i=0; i<cidl; ++i)
872 { if (!IDLList_StoreItem(this, ILClone((LPCITEMIDLIST)apidl[i])))
877 static BOOL32 WINAPI IDLList_InitList(LPIDLLIST this)
878 { TRACE (shell,"(%p)\n",this);
879 switch (IDLList_GetState(this))
888 this->dpa = DPA_Create(this->uStep);
890 return(IDLList_InitList(this));
893 static void WINAPI IDLList_CleanList(LPIDLLIST this)
895 TRACE (shell,"(%p)\n",this);
897 if (this->uStep != 0)
907 for (i=DPA_GetPtrCount(this->dpa)-1; i>=0; --i)
908 { ILFree(IDLList_GetElement(this,i));
911 DPA_Destroy(this->dpa);