4 * Copyright 1998 Juergen Schmied
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * a pidl == NULL means desktop and is legal
26 #include "wine/port.h"
36 #include "undocshell.h"
37 #include "shell32_main.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(pidl);
46 WINE_DECLARE_DEBUG_CHANNEL(shell);
48 /* from comctl32.dll */
49 extern LPVOID WINAPI Alloc(INT);
50 extern BOOL WINAPI Free(LPVOID);
52 /*************************************************************************
53 * ILGetDisplayName [SHELL32.15]
55 BOOL WINAPI ILGetDisplayName(LPCITEMIDLIST pidl,LPSTR path)
57 TRACE_(shell)("pidl=%p %p semi-stub\n",pidl,path);
58 return SHGetPathFromIDListA(pidl, path);
60 /*************************************************************************
61 * ILFindLastID [SHELL32.16]
64 * observed: pidl=Desktop return=pidl
66 LPITEMIDLIST WINAPI ILFindLastID(LPITEMIDLIST pidl)
67 { LPITEMIDLIST pidlLast = pidl;
69 TRACE("(pidl=%p)\n",pidl);
74 pidl = ILGetNext(pidl);
78 /*************************************************************************
79 * ILRemoveLastID [SHELL32.17]
82 * when pidl=Desktop return=FALSE
84 BOOL WINAPI ILRemoveLastID(LPCITEMIDLIST pidl)
86 TRACE_(shell)("pidl=%p\n",pidl);
88 if (!pidl || !pidl->mkid.cb)
90 ILFindLastID(pidl)->mkid.cb = 0;
94 /*************************************************************************
95 * ILClone [SHELL32.18]
100 LPITEMIDLIST WINAPI ILClone (LPCITEMIDLIST pidl)
102 LPITEMIDLIST newpidl;
107 len = ILGetSize(pidl);
108 newpidl = (LPITEMIDLIST)SHAlloc(len);
110 memcpy(newpidl,pidl,len);
112 TRACE("pidl=%p newpidl=%p\n",pidl, newpidl);
117 /*************************************************************************
118 * ILCloneFirst [SHELL32.19]
121 * duplicates the first idlist of a complex pidl
123 LPITEMIDLIST WINAPI ILCloneFirst(LPCITEMIDLIST pidl)
125 LPITEMIDLIST pidlNew = NULL;
127 TRACE("pidl=%p \n",pidl);
133 pidlNew = (LPITEMIDLIST) SHAlloc (len+2);
136 memcpy(pidlNew,pidl,len+2); /* 2 -> mind a desktop pidl */
139 ILGetNext(pidlNew)->mkid.cb = 0x00;
142 TRACE("-- newpidl=%p\n",pidlNew);
147 /*************************************************************************
148 * ILLoadFromStream (SHELL32.26)
151 * the first two bytes are the len, the pidl is following then
153 HRESULT WINAPI ILLoadFromStream (IStream * pStream, LPITEMIDLIST * ppPidl)
156 HRESULT ret = E_FAIL;
159 TRACE_(shell)("%p %p\n", pStream , ppPidl);
166 IStream_AddRef (pStream);
168 if (SUCCEEDED(IStream_Read(pStream, (LPVOID)&wLen, 2, &dwBytesRead)))
169 { *ppPidl = SHAlloc (wLen);
170 if (SUCCEEDED(IStream_Read(pStream, *ppPidl , wLen, &dwBytesRead)))
179 /* we are not yet fully compatible */
180 if (!pcheck(*ppPidl))
186 IStream_Release (pStream);
191 /*************************************************************************
192 * ILSaveToStream (SHELL32.27)
195 * the first two bytes are the len, the pidl is following then
197 HRESULT WINAPI ILSaveToStream (IStream * pStream, LPCITEMIDLIST pPidl)
201 HRESULT ret = E_FAIL;
203 TRACE_(shell)("%p %p\n", pStream, pPidl);
205 IStream_AddRef (pStream);
208 while (pidl->mkid.cb)
210 wLen += sizeof(WORD) + pidl->mkid.cb;
211 pidl = ILGetNext(pidl);
214 if (SUCCEEDED(IStream_Write(pStream, (LPVOID)&wLen, 2, NULL)))
216 if (SUCCEEDED(IStream_Write(pStream, pPidl, wLen, NULL)))
222 IStream_Release (pStream);
227 HRESULT WINAPI SHILCreateFromPathA (LPCSTR path, LPITEMIDLIST * ppidl, DWORD * attributes)
229 WCHAR lpszDisplayName[MAX_PATH];
231 HRESULT ret = E_FAIL;
233 TRACE_(shell)("%s %p 0x%08lx\n",path,ppidl,attributes?*attributes:0);
235 if (!MultiByteToWideChar( CP_ACP, 0, path, -1, lpszDisplayName, MAX_PATH ))
236 lpszDisplayName[MAX_PATH-1] = 0;
238 if (SUCCEEDED (SHGetDesktopFolder(&sf)))
240 ret = IShellFolder_ParseDisplayName(sf,0, NULL,lpszDisplayName,&pchEaten,ppidl,attributes);
241 IShellFolder_Release(sf);
246 HRESULT WINAPI SHILCreateFromPathW (LPCWSTR path, LPITEMIDLIST * ppidl, DWORD * attributes)
249 HRESULT ret = E_FAIL;
251 TRACE_(shell)("%s %p 0x%08lx\n",debugstr_w(path),ppidl,attributes?*attributes:0);
253 if (SUCCEEDED (SHGetDesktopFolder(&sf)))
255 ret = IShellFolder_ParseDisplayName(sf,0, NULL, (LPWSTR) path, &pchEaten, ppidl, attributes);
256 IShellFolder_Release(sf);
261 /*************************************************************************
262 * SHILCreateFromPath [SHELL32.28]
265 * Wrapper for IShellFolder_ParseDisplayName().
267 HRESULT WINAPI SHILCreateFromPathAW (LPCVOID path, LPITEMIDLIST * ppidl, DWORD * attributes)
269 if ( SHELL_OsIsUnicode())
270 return SHILCreateFromPathW (path, ppidl, attributes);
271 return SHILCreateFromPathA (path, ppidl, attributes);
274 /*************************************************************************
275 * SHCloneSpecialIDList [SHELL32.89]
279 * nFolder [in] CSIDL_xxxxx ??
284 * exported by ordinal
286 LPITEMIDLIST WINAPI SHCloneSpecialIDList(HWND hwndOwner,DWORD nFolder,DWORD x3)
287 { LPITEMIDLIST ppidl;
288 WARN_(shell)("(hwnd=%p,csidl=0x%lx,0x%lx):semi-stub.\n",
289 hwndOwner,nFolder,x3);
291 SHGetSpecialFolderLocation(hwndOwner, nFolder, &ppidl);
296 /*************************************************************************
297 * ILGlobalClone [SHELL32.20]
300 LPITEMIDLIST WINAPI ILGlobalClone(LPCITEMIDLIST pidl)
302 LPITEMIDLIST newpidl;
307 len = ILGetSize(pidl);
308 newpidl = (LPITEMIDLIST)Alloc(len);
310 memcpy(newpidl,pidl,len);
312 TRACE("pidl=%p newpidl=%p\n",pidl, newpidl);
318 /*************************************************************************
319 * ILIsEqual [SHELL32.21]
322 BOOL WINAPI ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
324 char szData1[MAX_PATH];
325 char szData2[MAX_PATH];
327 LPITEMIDLIST pidltemp1 = pidl1;
328 LPITEMIDLIST pidltemp2 = pidl2;
330 TRACE("pidl1=%p pidl2=%p\n",pidl1, pidl2);
332 /* explorer reads from registry directly (StreamMRU),
333 so we can only check here */
334 if ((!pcheck (pidl1)) || (!pcheck (pidl2))) return FALSE;
339 if ( (!pidl1) || (!pidl2) ) return FALSE;
341 while (pidltemp1->mkid.cb && pidltemp2->mkid.cb)
343 _ILSimpleGetText(pidltemp1, szData1, MAX_PATH);
344 _ILSimpleGetText(pidltemp2, szData2, MAX_PATH);
346 if (strcasecmp ( szData1, szData2 )!=0 )
349 pidltemp1 = ILGetNext(pidltemp1);
350 pidltemp2 = ILGetNext(pidltemp2);
353 if (!pidltemp1->mkid.cb && !pidltemp2->mkid.cb)
360 /*************************************************************************
361 * ILIsParent [SHELL32.23]
363 * parent=a/b child=a/b/c -> true, c is in folder a/b
364 * child=a/b/c/d -> false if bImmediate is true, d is not in folder a/b
365 * child=a/b/c/d -> true if bImmediate is false, d is in a subfolder of a/b
367 BOOL WINAPI ILIsParent( LPCITEMIDLIST pidlParent, LPCITEMIDLIST pidlChild, BOOL bImmediate)
369 char szData1[MAX_PATH];
370 char szData2[MAX_PATH];
372 LPITEMIDLIST pParent = pidlParent;
373 LPITEMIDLIST pChild = pidlChild;
375 TRACE("%p %p %x\n", pidlParent, pidlChild, bImmediate);
377 while (pParent->mkid.cb && pChild->mkid.cb)
379 _ILSimpleGetText(pParent, szData1, MAX_PATH);
380 _ILSimpleGetText(pChild, szData2, MAX_PATH);
382 if (strcasecmp ( szData1, szData2 )!=0 )
385 pParent = ILGetNext(pParent);
386 pChild = ILGetNext(pChild);
389 if ( pParent->mkid.cb || ! pChild->mkid.cb) /* child shorter or has equal length to parent */
392 if ( ILGetNext(pChild)->mkid.cb && bImmediate) /* not immediate descent */
398 /*************************************************************************
399 * ILFindChild [SHELL32.24]
402 * Compares elements from pidl1 and pidl2.
404 * pidl1 is desktop pidl2
405 * pidl1 shorter pidl2 pointer to first different element of pidl2
406 * if there was at least one equal element
407 * pidl2 shorter pidl1 0
408 * pidl2 equal pidl1 pointer to last 0x00-element of pidl2
410 LPITEMIDLIST WINAPI ILFindChild(LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2)
412 char szData1[MAX_PATH];
413 char szData2[MAX_PATH];
415 LPITEMIDLIST pidltemp1 = pidl1;
416 LPITEMIDLIST pidltemp2 = pidl2;
417 LPITEMIDLIST ret=NULL;
419 TRACE("pidl1=%p pidl2=%p\n",pidl1, pidl2);
421 /* explorer reads from registry directly (StreamMRU),
422 so we can only check here */
423 if ((!pcheck (pidl1)) || (!pcheck (pidl2)))
429 if ( _ILIsDesktop(pidl1) )
435 while (pidltemp1->mkid.cb && pidltemp2->mkid.cb)
437 _ILSimpleGetText(pidltemp1, szData1, MAX_PATH);
438 _ILSimpleGetText(pidltemp2, szData2, MAX_PATH);
440 if (strcasecmp(szData1,szData2))
443 pidltemp1 = ILGetNext(pidltemp1);
444 pidltemp2 = ILGetNext(pidltemp2);
448 if (pidltemp1->mkid.cb)
450 ret = NULL; /* elements of pidl1 left*/
453 TRACE_(shell)("--- %p\n", ret);
454 return ret; /* pidl 1 is shorter */
457 /*************************************************************************
458 * ILCombine [SHELL32.25]
461 * Concatenates two complex idlists.
462 * The pidl is the first one, pidlsub the next one
463 * Does not destroy the passed in idlists!
465 LPITEMIDLIST WINAPI ILCombine(LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2)
468 LPITEMIDLIST pidlNew;
470 TRACE("pidl=%p pidl=%p\n",pidl1,pidl2);
472 if(!pidl1 && !pidl2) return NULL;
479 pidlNew = ILClone(pidl2);
485 pidlNew = ILClone(pidl1);
489 len1 = ILGetSize(pidl1)-2;
490 len2 = ILGetSize(pidl2);
491 pidlNew = SHAlloc(len1+len2);
495 memcpy(pidlNew,pidl1,len1);
496 memcpy(((BYTE *)pidlNew)+len1,pidl2,len2);
499 /* TRACE(pidl,"--new pidl=%p\n",pidlNew);*/
502 /*************************************************************************
503 * SHGetRealIDL [SHELL32.98]
507 LPITEMIDLIST WINAPI SHGetRealIDL(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl, DWORD z)
509 FIXME("sf=%p pidl=%p 0x%04lx\n",lpsf,pidl,z);
515 /*************************************************************************
516 * SHLogILFromFSIL [SHELL32.95]
519 * pild = CSIDL_DESKTOP ret = 0
520 * pild = CSIDL_DRIVES ret = 0
522 LPITEMIDLIST WINAPI SHLogILFromFSIL(LPITEMIDLIST pidl)
524 FIXME("(pidl=%p)\n",pidl);
531 /*************************************************************************
532 * ILGetSize [SHELL32.152]
533 * gets the byte size of an idlist including zero terminator (pidl)
542 * exported by ordinal
544 DWORD WINAPI ILGetSize(LPITEMIDLIST pidl)
546 LPSHITEMID si = &(pidl->mkid);
552 si = (LPSHITEMID)(((LPBYTE)si)+si->cb);
556 TRACE("pidl=%p size=%lu\n",pidl, len);
560 /*************************************************************************
561 * ILGetNext [SHELL32.153]
562 * gets the next simple pidl of a complex pidl
564 * observed return values:
567 * simple pidl -> pointer to 0x0000 element
570 LPITEMIDLIST WINAPI ILGetNext(LPITEMIDLIST pidl)
581 pidl = (LPITEMIDLIST) (((LPBYTE)pidl)+len);
582 TRACE("-- %p\n", pidl);
588 /*************************************************************************
589 * ILAppend [SHELL32.154]
592 * Adds the single item to the idlist indicated by pidl.
593 * if bEnd is 0, adds the item to the front of the list,
594 * otherwise adds the item to the end. (???)
595 * Destroys the passed in idlist! (???)
597 LPITEMIDLIST WINAPI ILAppend(LPITEMIDLIST pidl,LPCITEMIDLIST item,BOOL bEnd)
601 WARN("(pidl=%p,pidl=%p,%08u)semi-stub\n",pidl,item,bEnd);
606 if (_ILIsDesktop(pidl))
608 idlRet = ILClone(item);
616 idlRet=ILCombine(pidl,item);
620 idlRet=ILCombine(item,pidl);
626 /*************************************************************************
627 * ILFree [SHELL32.155]
630 * free_check_ptr - frees memory (if not NULL)
631 * allocated by SHMalloc allocator
632 * exported by ordinal
634 DWORD WINAPI ILFree(LPITEMIDLIST pidl)
636 TRACE("(pidl=0x%08lx)\n",(DWORD)pidl);
638 if(!pidl) return FALSE;
642 /*************************************************************************
643 * ILGlobalFree [SHELL32.156]
646 void WINAPI ILGlobalFree( LPCITEMIDLIST pidl)
653 /*************************************************************************
654 * ILCreateFromPath [SHELL32.157]
657 LPITEMIDLIST WINAPI ILCreateFromPathA (LPCSTR path)
659 LPITEMIDLIST pidlnew;
660 DWORD attributes = 0;
662 TRACE_(shell)("%s\n",path);
664 if (SUCCEEDED (SHILCreateFromPathA (path, &pidlnew, &attributes)))
668 LPITEMIDLIST WINAPI ILCreateFromPathW (LPCWSTR path)
670 LPITEMIDLIST pidlnew;
671 DWORD attributes = 0;
673 TRACE_(shell)("%s\n",debugstr_w(path));
675 if (SUCCEEDED (SHILCreateFromPathW (path, &pidlnew, &attributes)))
679 LPITEMIDLIST WINAPI ILCreateFromPathAW (LPCVOID path)
681 if ( SHELL_OsIsUnicode())
682 return ILCreateFromPathW (path);
683 return ILCreateFromPathA (path);
685 /*************************************************************************
686 * SHSimpleIDListFromPath [SHELL32.162]
688 LPITEMIDLIST WINAPI SHSimpleIDListFromPathA (LPCSTR lpszPath)
690 LPITEMIDLIST pidl=NULL;
692 WIN32_FIND_DATAA stffile;
694 TRACE("path=%s\n", lpszPath);
696 if (!lpszPath) return NULL;
698 hFile = FindFirstFileA(lpszPath, &stffile);
700 if ( hFile != INVALID_HANDLE_VALUE )
702 if (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
704 pidl = _ILCreateFolder (&stffile);
708 pidl = _ILCreateValue (&stffile);
714 LPITEMIDLIST WINAPI SHSimpleIDListFromPathW (LPCWSTR lpszPath)
716 char lpszTemp[MAX_PATH];
717 TRACE("path=%s\n",debugstr_w(lpszPath));
719 if (!WideCharToMultiByte( CP_ACP, 0, lpszPath, -1, lpszTemp, sizeof(lpszTemp), NULL, NULL ))
720 lpszTemp[sizeof(lpszTemp)-1] = 0;
722 return SHSimpleIDListFromPathA (lpszTemp);
725 LPITEMIDLIST WINAPI SHSimpleIDListFromPathAW (LPCVOID lpszPath)
727 if ( SHELL_OsIsUnicode())
728 return SHSimpleIDListFromPathW (lpszPath);
729 return SHSimpleIDListFromPathA (lpszPath);
732 /*************************************************************************
733 * SHGetSpecialFolderLocation [SHELL32.@]
735 * gets the folder locations from the registry and creates a pidl
736 * creates missing reg keys and directories
740 * nFolder [I] CSIDL_xxxxx
741 * ppidl [O] PIDL of a special folder
744 HRESULT WINAPI SHGetSpecialFolderLocation(
747 LPITEMIDLIST * ppidl)
749 CHAR szPath[MAX_PATH];
750 HRESULT hr = E_INVALIDARG;
752 TRACE_(shell)("(%p,0x%x,%p)\n", hwndOwner,nFolder,ppidl);
760 *ppidl = _ILCreateDesktop();
764 *ppidl = _ILCreateMyComputer();
768 *ppidl = _ILCreateNetwork ();
772 *ppidl = _ILCreateControl ();
776 *ppidl = _ILCreatePrinter ();
779 case CSIDL_BITBUCKET:
780 *ppidl = _ILCreateBitBucket ();
784 if (SHGetSpecialFolderPathA(hwndOwner, szPath, nFolder, TRUE))
787 TRACE_(shell)("Value=%s\n",szPath);
788 hr = SHILCreateFromPathA(szPath, ppidl, &attributes);
791 if(*ppidl) hr = NOERROR;
794 TRACE_(shell)("-- (new pidl %p)\n",*ppidl);
798 /*************************************************************************
799 * SHGetFolderLocation [SHELL32.@]
802 * the pidl can be a simple one. since we cant get the path out of the pidl
803 * we have to take all data from the pidl
805 HRESULT WINAPI SHGetFolderLocation(
812 FIXME("%p 0x%08x %p 0x%08lx %p\n",
813 hwnd, csidl, hToken, dwFlags, ppidl);
814 return SHGetSpecialFolderLocation(hwnd, csidl, ppidl);
817 /*************************************************************************
818 * SHGetDataFromIDListA [SHELL32.247]
821 * the pidl can be a simple one. since we cant get the path out of the pidl
822 * we have to take all data from the pidl
824 HRESULT WINAPI SHGetDataFromIDListA(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, int nFormat, LPVOID dest, int len)
826 TRACE_(shell)("sf=%p pidl=%p 0x%04x %p 0x%04x stub\n",psf,pidl,nFormat,dest,len);
829 if (!psf || !dest ) return E_INVALIDARG;
833 case SHGDFIL_FINDDATA:
835 WIN32_FIND_DATAA * pfd = dest;
837 if ( len < sizeof (WIN32_FIND_DATAA)) return E_INVALIDARG;
839 ZeroMemory(pfd, sizeof (WIN32_FIND_DATAA));
840 _ILGetFileDateTime( pidl, &(pfd->ftLastWriteTime));
841 pfd->dwFileAttributes = _ILGetFileAttributes(pidl, NULL, 0);
842 pfd->nFileSizeLow = _ILGetFileSize ( pidl, NULL, 0);
843 lstrcpynA(pfd->cFileName,_ILGetTextPointer(pidl), MAX_PATH);
844 lstrcpynA(pfd->cAlternateFileName,_ILGetSTextPointer(pidl), 14);
848 case SHGDFIL_NETRESOURCE:
849 case SHGDFIL_DESCRIPTIONID:
850 FIXME_(shell)("SHGDFIL %i stub\n", nFormat);
854 ERR_(shell)("Unknown SHGDFIL %i, please report\n", nFormat);
859 /*************************************************************************
860 * SHGetDataFromIDListW [SHELL32.248]
863 HRESULT WINAPI SHGetDataFromIDListW(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, int nFormat, LPVOID dest, int len)
865 TRACE_(shell)("sf=%p pidl=%p 0x%04x %p 0x%04x stub\n",psf,pidl,nFormat,dest,len);
869 if (! psf || !dest ) return E_INVALIDARG;
873 case SHGDFIL_FINDDATA:
875 WIN32_FIND_DATAW * pfd = dest;
877 if ( len < sizeof (WIN32_FIND_DATAW)) return E_INVALIDARG;
879 ZeroMemory(pfd, sizeof (WIN32_FIND_DATAA));
880 _ILGetFileDateTime( pidl, &(pfd->ftLastWriteTime));
881 pfd->dwFileAttributes = _ILGetFileAttributes(pidl, NULL, 0);
882 pfd->nFileSizeLow = _ILGetFileSize ( pidl, NULL, 0);
883 if (!MultiByteToWideChar( CP_ACP, 0, _ILGetTextPointer(pidl), -1,
884 pfd->cFileName, MAX_PATH ))
885 pfd->cFileName[MAX_PATH-1] = 0;
886 if (!MultiByteToWideChar( CP_ACP, 0, _ILGetSTextPointer(pidl), -1,
887 pfd->cAlternateFileName, 14 ))
888 pfd->cFileName[13] = 0;
891 case SHGDFIL_NETRESOURCE:
892 case SHGDFIL_DESCRIPTIONID:
893 FIXME_(shell)("SHGDFIL %i stub\n", nFormat);
897 ERR_(shell)("Unknown SHGDFIL %i, please report\n", nFormat);
903 /*************************************************************************
904 * SHGetPathFromIDListA [SHELL32.@][NT 4.0: SHELL32.220]
911 * path from a passed PIDL.
915 * desktop pidl gives path to desktopdirectory back
916 * special pidls returning FALSE
918 BOOL WINAPI SHGetPathFromIDListA(LPCITEMIDLIST pidl, LPSTR pszPath)
922 LPSHELLFOLDER shellfolder;
924 TRACE_(shell)("(pidl=%p,%p)\n",pidl,pszPath);
927 if (!pidl) return FALSE;
929 hr = SHGetDesktopFolder(&shellfolder);
930 if (SUCCEEDED (hr)) {
931 hr = IShellFolder_GetDisplayNameOf(shellfolder,pidl,SHGDN_FORPARSING,&str);
933 StrRetToStrNA (pszPath, MAX_PATH, &str, pidl);
935 IShellFolder_Release(shellfolder);
938 TRACE_(shell)("-- %s, 0x%08lx\n",pszPath, hr);
939 return SUCCEEDED(hr);
941 /*************************************************************************
942 * SHGetPathFromIDListW [SHELL32.@]
944 BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath)
948 LPSHELLFOLDER shellfolder;
950 TRACE_(shell)("(pidl=%p,%p)\n", pidl, debugstr_w(pszPath));
953 if (!pidl) return FALSE;
955 hr = SHGetDesktopFolder(&shellfolder);
957 hr = IShellFolder_GetDisplayNameOf(shellfolder, pidl, SHGDN_FORPARSING, &str);
959 StrRetToStrNW(pszPath, MAX_PATH, &str, pidl);
961 IShellFolder_Release(shellfolder);
964 TRACE_(shell)("-- %s, 0x%08lx\n",debugstr_w(pszPath), hr);
965 return SUCCEEDED(hr);
968 /*************************************************************************
969 * SHBindToParent [shell version 5.0]
971 HRESULT WINAPI SHBindToParent(LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppv, LPCITEMIDLIST *ppidlLast)
974 LPITEMIDLIST pidlChild, pidlParent;
977 TRACE_(shell)("pidl=%p\n", pidl);
981 if (ppidlLast) *ppidlLast = NULL;
983 if (_ILIsPidlSimple(pidl))
985 /* we are on desktop level */
987 *ppidlLast = ILClone(pidl);
988 hr = SHGetDesktopFolder((IShellFolder**)ppv);
992 pidlChild = ILClone(ILFindLastID(pidl));
993 pidlParent = ILClone(pidl);
994 ILRemoveLastID(pidlParent);
996 hr = SHGetDesktopFolder(&psf);
999 hr = IShellFolder_BindToObject(psf, pidlParent, NULL, riid, ppv);
1001 if (SUCCEEDED(hr) && ppidlLast)
1002 *ppidlLast = pidlChild;
1006 SHFree (pidlParent);
1007 if (psf) IShellFolder_Release(psf);
1011 TRACE_(shell)("-- psf=%p pidl=%p ret=0x%08lx\n", *ppv, (ppidlLast)?*ppidlLast:NULL, hr);
1015 /*************************************************************************
1016 * SHGetPathFromIDList [SHELL32.@][NT 4.0: SHELL32.219]
1018 BOOL WINAPI SHGetPathFromIDListAW(LPCITEMIDLIST pidl,LPVOID pszPath)
1020 TRACE_(shell)("(pidl=%p,%p)\n",pidl,pszPath);
1022 if (SHELL_OsIsUnicode())
1023 return SHGetPathFromIDListW(pidl,pszPath);
1024 return SHGetPathFromIDListA(pidl,pszPath);
1027 /**************************************************************************
1029 * internal functions
1031 * ### 1. section creating pidls ###
1033 *************************************************************************
1034 * _ILCreateDesktop()
1035 * _ILCreateIExplore()
1036 * _ILCreateMyComputer()
1041 LPITEMIDLIST _ILCreateDesktop()
1043 return _ILCreate(PT_DESKTOP, NULL, 0);
1046 LPITEMIDLIST _ILCreateMyComputer()
1048 return _ILCreate(PT_MYCOMP, &CLSID_MyComputer, sizeof(GUID));
1051 LPITEMIDLIST _ILCreateIExplore()
1053 return _ILCreate(PT_MYCOMP, &CLSID_Internet, sizeof(GUID));
1056 LPITEMIDLIST _ILCreateControl()
1058 return _ILCreate(PT_SPECIAL, &CLSID_ControlPanel, sizeof(GUID));
1061 LPITEMIDLIST _ILCreatePrinter()
1063 return _ILCreate(PT_SPECIAL, &CLSID_Printers, sizeof(GUID));
1066 LPITEMIDLIST _ILCreateNetwork()
1068 return _ILCreate(PT_MYCOMP, &CLSID_NetworkPlaces, sizeof(GUID));
1071 LPITEMIDLIST _ILCreateBitBucket()
1073 return _ILCreate(PT_MYCOMP, &CLSID_RecycleBin, sizeof(GUID));
1076 LPITEMIDLIST _ILCreateDrive( LPCSTR lpszNew)
1078 lstrcpynA (sTemp,lpszNew,4);
1081 TRACE("(%s)\n",sTemp);
1082 return _ILCreate(PT_DRIVE,(LPVOID)&sTemp[0],4);
1085 LPITEMIDLIST _ILCreateFolder( WIN32_FIND_DATAA * stffile )
1087 char buff[MAX_PATH + 14 +1]; /* see WIN32_FIND_DATA */
1088 char * pbuff = buff;
1092 TRACE("(%s, %s)\n",stffile->cAlternateFileName, stffile->cFileName);
1094 /* prepare buffer with both names */
1095 len = strlen (stffile->cFileName) + 1;
1096 memcpy (pbuff, stffile->cFileName, len);
1099 if (stffile->cAlternateFileName)
1101 len1 = strlen (stffile->cAlternateFileName)+1;
1102 memcpy (pbuff, stffile->cAlternateFileName, len1);
1110 pidl = _ILCreate(PT_FOLDER, (LPVOID)buff, len + len1);
1112 /* set attributes */
1116 pData = _ILGetDataPointer(pidl);
1117 FileTimeToDosDateTime(&(stffile->ftLastWriteTime),&pData->u.folder.uFileDate,&pData->u.folder.uFileTime);
1118 pData->u.folder.dwFileSize = stffile->nFileSizeLow;
1119 pData->u.folder.uFileAttribs=stffile->dwFileAttributes;
1125 LPITEMIDLIST _ILCreateValue(WIN32_FIND_DATAA * stffile)
1127 char buff[MAX_PATH + 14 +1]; /* see WIN32_FIND_DATA */
1128 char * pbuff = buff;
1132 TRACE("(%s, %s)\n",stffile->cAlternateFileName, stffile->cFileName);
1134 /* prepare buffer with both names */
1135 len = strlen (stffile->cFileName) + 1;
1136 memcpy (pbuff, stffile->cFileName, len);
1139 if (stffile->cAlternateFileName)
1141 len1 = strlen (stffile->cAlternateFileName)+1;
1142 memcpy (pbuff, stffile->cAlternateFileName, len1);
1150 pidl = _ILCreate(PT_VALUE, (LPVOID)buff, len + len1);
1152 /* set attributes */
1156 pData = _ILGetDataPointer(pidl);
1157 FileTimeToDosDateTime(&(stffile->ftLastWriteTime),&pData->u.folder.uFileDate,&pData->u.folder.uFileTime);
1158 pData->u.folder.dwFileSize = stffile->nFileSizeLow;
1159 pData->u.folder.uFileAttribs=stffile->dwFileAttributes;
1165 LPITEMIDLIST _ILCreateSpecial(LPCSTR szGUID)
1169 if (!SUCCEEDED(SHCLSIDFromStringA(szGUID, &iid)))
1171 ERR("%s is not a GUID\n", szGUID);
1174 return _ILCreate(PT_MYCOMP, &iid, sizeof(IID));
1177 /**************************************************************************
1179 * Creates a new PIDL
1180 * type = PT_DESKTOP | PT_DRIVE | PT_FOLDER | PT_VALUE
1182 * uInSize = size of data (raw)
1185 LPITEMIDLIST _ILCreate(PIDLTYPE type, LPCVOID pIn, UINT uInSize)
1187 LPITEMIDLIST pidlOut = NULL, pidlTemp = NULL;
1192 TRACE("(0x%02x %p %i)\n",type,pIn,uInSize);
1201 uSize = 2 + 2 + sizeof(GUID);
1208 uSize = 2 + 12 + uInSize;
1211 FIXME("can't create type: 0x%08x\n",type);
1215 if(!(pidlOut = SHAlloc(uSize + 2))) return NULL;
1216 ZeroMemory(pidlOut, uSize + 2);
1217 pidlOut->mkid.cb = uSize;
1222 TRACE("- create Desktop\n");
1227 pData =_ILGetDataPointer(pidlOut);
1229 memcpy(&(pData->u.mycomp.guid), pIn, uInSize);
1230 TRACE("-- create GUID-pidl %s\n", debugstr_guid(&(pData->u.mycomp.guid)));
1234 pData =_ILGetDataPointer(pidlOut);
1236 pszDest = _ILGetTextPointer(pidlOut);
1237 memcpy(pszDest, pIn, uInSize);
1238 TRACE("-- create Drive: %s\n",debugstr_a(pszDest));
1243 pData =_ILGetDataPointer(pidlOut);
1245 pszDest = _ILGetTextPointer(pidlOut);
1246 memcpy(pszDest, pIn, uInSize);
1247 TRACE("-- create Value: %s\n",debugstr_a(pszDest));
1251 pidlTemp = ILGetNext(pidlOut);
1253 pidlTemp->mkid.cb = 0x00;
1255 TRACE("-- (pidl=%p, size=%u)\n", pidlOut, uSize);
1259 /**************************************************************************
1262 * Gets the text for the drive eg. 'c:\'
1267 DWORD _ILGetDrive(LPCITEMIDLIST pidl,LPSTR pOut, UINT uSize)
1268 { TRACE("(%p,%p,%u)\n",pidl,pOut,uSize);
1270 if(_ILIsMyComputer(pidl))
1271 pidl = ILGetNext(pidl);
1273 if (pidl && _ILIsDrive(pidl))
1274 return _ILSimpleGetText(pidl, pOut, uSize);
1279 /**************************************************************************
1281 * ### 2. section testing pidls ###
1283 **************************************************************************
1286 * _ILIsSpecialFolder()
1292 BOOL _ILIsDesktop(LPCITEMIDLIST pidl)
1293 { TRACE("(%p)\n",pidl);
1294 return pidl && pidl->mkid.cb ? 0 : 1;
1297 BOOL _ILIsMyComputer(LPCITEMIDLIST pidl)
1299 REFIID iid = _ILGetGUIDPointer(pidl);
1301 TRACE("(%p)\n",pidl);
1304 return IsEqualIID(iid, &CLSID_MyComputer);
1308 BOOL _ILIsSpecialFolder (LPCITEMIDLIST pidl)
1310 LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
1311 TRACE("(%p)\n",pidl);
1312 return (pidl && ( (lpPData && (PT_MYCOMP== lpPData->type || PT_SPECIAL== lpPData->type)) ||
1313 (pidl && pidl->mkid.cb == 0x00)
1317 BOOL _ILIsDrive(LPCITEMIDLIST pidl)
1318 { LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
1319 TRACE("(%p)\n",pidl);
1320 return (pidl && lpPData && (PT_DRIVE == lpPData->type ||
1321 PT_DRIVE1 == lpPData->type ||
1322 PT_DRIVE2 == lpPData->type ||
1323 PT_DRIVE3 == lpPData->type));
1326 BOOL _ILIsFolder(LPCITEMIDLIST pidl)
1327 { LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
1328 TRACE("(%p)\n",pidl);
1329 return (pidl && lpPData && (PT_FOLDER == lpPData->type || PT_FOLDER1 == lpPData->type));
1332 BOOL _ILIsValue(LPCITEMIDLIST pidl)
1333 { LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
1334 TRACE("(%p)\n",pidl);
1335 return (pidl && lpPData && PT_VALUE == lpPData->type);
1338 /**************************************************************************
1341 BOOL _ILIsPidlSimple ( LPCITEMIDLIST pidl)
1345 if(! _ILIsDesktop(pidl)) /* pidl=NULL or mkid.cb=0 */
1347 WORD len = pidl->mkid.cb;
1348 LPCITEMIDLIST pidlnext = (LPCITEMIDLIST) (((LPBYTE)pidl) + len );
1349 if (pidlnext->mkid.cb)
1353 TRACE("%s\n", ret ? "Yes" : "No");
1357 /**************************************************************************
1359 * ### 3. section getting values from pidls ###
1362 /**************************************************************************
1365 * gets the text for the first item in the pidl (eg. simple pidl)
1367 * returns the length of the string
1369 DWORD _ILSimpleGetText (LPCITEMIDLIST pidl, LPSTR szOut, UINT uOutSize)
1374 char szTemp[MAX_PATH];
1376 TRACE("(%p %p %x)\n",pidl,szOut,uOutSize);
1378 if (!pidl) return 0;
1383 if (_ILIsDesktop(pidl))
1386 if (HCR_GetClassNameA(&CLSID_ShellDesktop, szTemp, MAX_PATH))
1389 lstrcpynA(szOut, szTemp, uOutSize);
1391 dwReturn = strlen (szTemp);
1394 else if (( szSrc = _ILGetTextPointer(pidl) ))
1398 lstrcpynA(szOut, szSrc, uOutSize);
1400 dwReturn = strlen(szSrc);
1402 else if (( riid = _ILGetGUIDPointer(pidl) ))
1404 /* special folder */
1405 if ( HCR_GetClassNameA(riid, szTemp, MAX_PATH) )
1408 lstrcpynA(szOut, szTemp, uOutSize);
1410 dwReturn = strlen (szTemp);
1415 ERR("-- no text\n");
1418 TRACE("-- (%p=%s 0x%08lx)\n",szOut,debugstr_a(szOut),dwReturn);
1422 /**************************************************************************
1424 * ### 4. getting pointers to parts of pidls ###
1426 **************************************************************************
1427 * _ILGetDataPointer()
1429 LPPIDLDATA _ILGetDataPointer(LPITEMIDLIST pidl)
1431 if(pidl && pidl->mkid.cb != 0x00)
1432 return (LPPIDLDATA) &(pidl->mkid.abID);
1436 /**************************************************************************
1437 * _ILGetTextPointer()
1438 * gets a pointer to the long filename string stored in the pidl
1440 LPSTR _ILGetTextPointer(LPCITEMIDLIST pidl)
1441 {/* TRACE(pidl,"(pidl%p)\n", pidl);*/
1443 LPPIDLDATA pdata =_ILGetDataPointer(pidl);
1447 switch (pdata->type)
1457 return (LPSTR)&(pdata->u.drive.szDriveName);
1464 return (LPSTR)&(pdata->u.file.szNames);
1470 return (LPSTR)&(pdata->u.network.szNames);
1476 /**************************************************************************
1477 * _ILGetSTextPointer()
1478 * gets a pointer to the short filename string stored in the pidl
1480 LPSTR _ILGetSTextPointer(LPCITEMIDLIST pidl)
1481 {/* TRACE(pidl,"(pidl%p)\n", pidl);*/
1483 LPPIDLDATA pdata =_ILGetDataPointer(pidl);
1487 switch (pdata->type)
1493 return (LPSTR)(pdata->u.file.szNames + strlen (pdata->u.file.szNames) + 1);
1496 return (LPSTR)(pdata->u.network.szNames + strlen (pdata->u.network.szNames) + 1);
1502 /**************************************************************************
1503 * _ILGetGUIDPointer()
1505 * returns reference to guid stored in some pidls
1507 REFIID _ILGetGUIDPointer(LPCITEMIDLIST pidl)
1509 LPPIDLDATA pdata =_ILGetDataPointer(pidl);
1511 TRACE("%p\n", pidl);
1515 TRACE("pdata->type 0x%04x\n", pdata->type);
1516 switch (pdata->type)
1520 return (REFIID) &(pdata->u.mycomp.guid);
1523 TRACE("Unknown pidl type 0x%04x\n", pdata->type);
1530 /*************************************************************************
1531 * _ILGetFileDateTime
1533 * Given the ItemIdList, get the FileTime
1536 * pidl [I] The ItemIDList
1537 * pFt [I] the resulted FILETIME of the file
1540 * True if Successful
1545 BOOL _ILGetFileDateTime(LPCITEMIDLIST pidl, FILETIME *pFt)
1547 LPPIDLDATA pdata =_ILGetDataPointer(pidl);
1549 if(! pdata) return FALSE;
1551 switch (pdata->type)
1554 DosDateTimeToFileTime(pdata->u.folder.uFileDate, pdata->u.folder.uFileTime, pFt);
1557 DosDateTimeToFileTime(pdata->u.file.uFileDate, pdata->u.file.uFileTime, pFt);
1565 BOOL _ILGetFileDate (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize)
1571 if (_ILGetFileDateTime( pidl, &ft )) {
1572 FileTimeToLocalFileTime(&ft, &lft);
1573 FileTimeToSystemTime (&lft, &time);
1574 ret = GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&time, NULL, pOut, uOutSize);
1583 /*************************************************************************
1586 * Given the ItemIdList, get the FileSize
1589 * pidl [I] The ItemIDList
1590 * pOut [I] The buffer to save the result
1591 * uOutsize [I] The size of the buffer
1597 * pOut can be null when no string is needed
1600 DWORD _ILGetFileSize (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize)
1602 LPPIDLDATA pdata =_ILGetDataPointer(pidl);
1605 if(! pdata) return 0;
1607 switch (pdata->type)
1610 dwSize = pdata->u.file.dwFileSize;
1611 if (pOut) StrFormatByteSizeA(dwSize, pOut, uOutSize);
1614 if (pOut) *pOut = 0x00;
1618 BOOL _ILGetExtension (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize)
1620 char szTemp[MAX_PATH];
1621 const char * pPoint;
1622 LPITEMIDLIST pidlTemp=pidl;
1624 TRACE("pidl=%p\n",pidl);
1626 if (!pidl) return FALSE;
1628 pidlTemp = ILFindLastID(pidl);
1630 if (!_ILIsValue(pidlTemp)) return FALSE;
1631 if (!_ILSimpleGetText(pidlTemp, szTemp, MAX_PATH)) return FALSE;
1633 pPoint = PathFindExtensionA(szTemp);
1635 if (! *pPoint) return FALSE;
1638 lstrcpynA(pOut, pPoint, uOutSize);
1644 /*************************************************************************
1647 * Given the ItemIdList, get the file type description
1650 * pidl [I] The ItemIDList (simple)
1651 * pOut [I] The buffer to save the result
1652 * uOutsize [I] The size of the buffer
1658 * This function copies as much as possible into the buffer.
1660 void _ILGetFileType(LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize)
1662 if(_ILIsValue(pidl))
1669 if (_ILGetExtension (pidl, sTemp, 64))
1671 if (!( HCR_MapTypeToValueA(sTemp, sTemp, 64, TRUE)
1672 && HCR_MapTypeToValueA(sTemp, pOut, uOutSize, FALSE )))
1674 lstrcpynA (pOut, sTemp, uOutSize - 6);
1675 strcat (pOut, "-file");
1681 lstrcpynA(pOut, "Folder", uOutSize);
1685 /*************************************************************************
1686 * _ILGetFileAttributes
1688 * Given the ItemIdList, get the Attrib string format
1691 * pidl [I] The ItemIDList
1692 * pOut [I] The buffer to save the result
1693 * uOutsize [I] The size of the Buffer
1699 * return value 0 in case of error is a valid return value
1702 DWORD _ILGetFileAttributes(LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize)
1704 LPPIDLDATA pData =_ILGetDataPointer(pidl);
1708 if(! pData) return 0;
1713 wAttrib = pData->u.folder.uFileAttribs;
1716 wAttrib = pData->u.file.uFileAttribs;
1723 if(wAttrib & FILE_ATTRIBUTE_READONLY)
1727 if(wAttrib & FILE_ATTRIBUTE_HIDDEN)
1731 if(wAttrib & FILE_ATTRIBUTE_SYSTEM)
1735 if(wAttrib & FILE_ATTRIBUTE_ARCHIVE)
1739 if(wAttrib & FILE_ATTRIBUTE_COMPRESSED)
1748 /*************************************************************************
1751 * free a aPidl struct
1753 void _ILFreeaPidl(LPITEMIDLIST * apidl, UINT cidl)
1759 for (i = 0; i < cidl; i++) SHFree(apidl[i]);
1764 /*************************************************************************
1767 * copies an aPidl struct
1769 LPITEMIDLIST * _ILCopyaPidl(LPITEMIDLIST * apidlsrc, UINT cidl)
1772 LPITEMIDLIST * apidldest = (LPITEMIDLIST*)SHAlloc(cidl * sizeof(LPITEMIDLIST));
1773 if(!apidlsrc) return NULL;
1775 for (i = 0; i < cidl; i++)
1776 apidldest[i] = ILClone(apidlsrc[i]);
1781 /*************************************************************************
1782 * _ILCopyCidaToaPidl
1784 * creates aPidl from CIDA
1786 LPITEMIDLIST * _ILCopyCidaToaPidl(LPITEMIDLIST* pidl, LPIDA cida)
1789 LPITEMIDLIST * dst = (LPITEMIDLIST*)SHAlloc(cida->cidl * sizeof(LPITEMIDLIST));
1791 if(!dst) return NULL;
1794 *pidl = ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[0]]));
1796 for (i = 0; i < cida->cidl; i++)
1797 dst[i] = ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[i + 1]]));