|  | /* | 
|  | *    pidl Handling | 
|  | * | 
|  | *    Copyright 1998    Juergen Schmied | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | * | 
|  | * NOTES | 
|  | *  a pidl == NULL means desktop and is legal | 
|  | * | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  | #include "wine/port.h" | 
|  |  | 
|  | #include <ctype.h> | 
|  | #include <stdarg.h> | 
|  | #include <stdlib.h> | 
|  | #include <string.h> | 
|  |  | 
|  | #define COBJMACROS | 
|  | #define NONAMELESSUNION | 
|  |  | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "winreg.h" | 
|  | #include "objbase.h" | 
|  | #include "shlguid.h" | 
|  | #include "winerror.h" | 
|  | #include "winnls.h" | 
|  | #include "undocshell.h" | 
|  | #include "shell32_main.h" | 
|  | #include "shlwapi.h" | 
|  |  | 
|  | #include "pidl.h" | 
|  | #include "wine/debug.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(pidl); | 
|  | WINE_DECLARE_DEBUG_CHANNEL(shell); | 
|  |  | 
|  | /* from comctl32.dll */ | 
|  | extern LPVOID WINAPI Alloc(INT); | 
|  | extern BOOL WINAPI Free(LPVOID); | 
|  |  | 
|  | static LPSTR _ILGetSTextPointer(LPCITEMIDLIST pidl); | 
|  | static LPWSTR _ILGetTextPointerW(LPCITEMIDLIST pidl); | 
|  |  | 
|  | /************************************************************************* | 
|  | * ILGetDisplayNameExA | 
|  | * | 
|  | * Retrieves the display name of an ItemIDList | 
|  | * | 
|  | * PARAMS | 
|  | *  psf        [I]   Shell Folder to start with, if NULL the desktop is used | 
|  | *  pidl       [I]   ItemIDList relative to the psf to get the display name for | 
|  | *  path       [O]   Filled in with the display name, assumed to be at least MAX_PATH long | 
|  | *  type       [I]   Type of display name to retrieve | 
|  | *                    0 = SHGDN_FORPARSING | SHGDN_FORADDRESSBAR uses always the desktop as root | 
|  | *                    1 = SHGDN_NORMAL relative to the root folder | 
|  | *                    2 = SHGDN_INFOLDER relative to the root folder, only the last name | 
|  | * | 
|  | * RETURNS | 
|  | *  True if the display name could be retrieved successfully, False otherwise | 
|  | */ | 
|  | static BOOL ILGetDisplayNameExA(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, LPSTR path, DWORD type) | 
|  | { | 
|  | BOOL ret = FALSE; | 
|  | WCHAR wPath[MAX_PATH]; | 
|  |  | 
|  | TRACE("%p %p %p %d\n", psf, pidl, path, type); | 
|  |  | 
|  | if (!pidl || !path) | 
|  | return FALSE; | 
|  |  | 
|  | ret = ILGetDisplayNameExW(psf, pidl, wPath, type); | 
|  | WideCharToMultiByte(CP_ACP, 0, wPath, -1, path, MAX_PATH, NULL, NULL); | 
|  | TRACE("%p %p %s\n", psf, pidl, debugstr_a(path)); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | BOOL ILGetDisplayNameExW(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, LPWSTR path, DWORD type) | 
|  | { | 
|  | LPSHELLFOLDER psfParent, lsf = psf; | 
|  | HRESULT ret = NO_ERROR; | 
|  | LPCITEMIDLIST pidllast; | 
|  | STRRET strret; | 
|  | DWORD flag; | 
|  |  | 
|  | TRACE("%p %p %p %x\n", psf, pidl, path, type); | 
|  |  | 
|  | if (!pidl || !path) | 
|  | return FALSE; | 
|  |  | 
|  | if (!lsf) | 
|  | { | 
|  | ret = SHGetDesktopFolder(&lsf); | 
|  | if (FAILED(ret)) | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | switch (type) | 
|  | { | 
|  | case ILGDN_FORPARSING: | 
|  | flag = SHGDN_FORPARSING | SHGDN_FORADDRESSBAR; | 
|  | break; | 
|  | case ILGDN_NORMAL: | 
|  | flag = SHGDN_NORMAL; | 
|  | break; | 
|  | case ILGDN_INFOLDER: | 
|  | flag = SHGDN_INFOLDER; | 
|  | break; | 
|  | default: | 
|  | FIXME("Unknown type parameter = %x\n", type); | 
|  | flag = SHGDN_FORPARSING | SHGDN_FORADDRESSBAR; | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (!*(const WORD*)pidl || type == ILGDN_FORPARSING) | 
|  | { | 
|  | ret = IShellFolder_GetDisplayNameOf(lsf, pidl, flag, &strret); | 
|  | if (SUCCEEDED(ret)) | 
|  | { | 
|  | if(!StrRetToStrNW(path, MAX_PATH, &strret, pidl)) | 
|  | ret = E_FAIL; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | ret = SHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&psfParent, &pidllast); | 
|  | if (SUCCEEDED(ret)) | 
|  | { | 
|  | ret = IShellFolder_GetDisplayNameOf(psfParent, pidllast, flag, &strret); | 
|  | if (SUCCEEDED(ret)) | 
|  | { | 
|  | if(!StrRetToStrNW(path, MAX_PATH, &strret, pidllast)) | 
|  | ret = E_FAIL; | 
|  | } | 
|  | IShellFolder_Release(psfParent); | 
|  | } | 
|  | } | 
|  |  | 
|  | TRACE("%p %p %s\n", psf, pidl, debugstr_w(path)); | 
|  |  | 
|  | if (!psf) | 
|  | IShellFolder_Release(lsf); | 
|  | return SUCCEEDED(ret); | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * ILGetDisplayNameEx        [SHELL32.186] | 
|  | */ | 
|  | BOOL WINAPI ILGetDisplayNameEx(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, LPVOID path, DWORD type) | 
|  | { | 
|  | TRACE_(shell)("%p %p %p %d\n", psf, pidl, path, type); | 
|  |  | 
|  | if (SHELL_OsIsUnicode()) | 
|  | return ILGetDisplayNameExW(psf, pidl, path, type); | 
|  | return ILGetDisplayNameExA(psf, pidl, path, type); | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * ILGetDisplayName            [SHELL32.15] | 
|  | */ | 
|  | BOOL WINAPI ILGetDisplayName(LPCITEMIDLIST pidl, LPVOID path) | 
|  | { | 
|  | TRACE_(shell)("%p %p\n", pidl, path); | 
|  |  | 
|  | if (SHELL_OsIsUnicode()) | 
|  | return ILGetDisplayNameExW(NULL, pidl, path, ILGDN_FORPARSING); | 
|  | return ILGetDisplayNameExA(NULL, pidl, path, ILGDN_FORPARSING); | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * ILFindLastID [SHELL32.16] | 
|  | * | 
|  | * NOTES | 
|  | *   observed: pidl=Desktop return=pidl | 
|  | */ | 
|  | LPITEMIDLIST WINAPI ILFindLastID(LPCITEMIDLIST pidl) | 
|  | { | 
|  | LPCITEMIDLIST   pidlLast = pidl; | 
|  |  | 
|  | TRACE("(pidl=%p)\n",pidl); | 
|  |  | 
|  | if (!pidl) | 
|  | return NULL; | 
|  |  | 
|  | while (pidl->mkid.cb) | 
|  | { | 
|  | pidlLast = pidl; | 
|  | pidl = ILGetNext(pidl); | 
|  | } | 
|  | return (LPITEMIDLIST)pidlLast; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * ILRemoveLastID [SHELL32.17] | 
|  | * | 
|  | * NOTES | 
|  | *   when pidl=Desktop return=FALSE | 
|  | */ | 
|  | BOOL WINAPI ILRemoveLastID(LPITEMIDLIST pidl) | 
|  | { | 
|  | TRACE_(shell)("pidl=%p\n",pidl); | 
|  |  | 
|  | if (_ILIsEmpty(pidl)) | 
|  | return FALSE; | 
|  | ILFindLastID(pidl)->mkid.cb = 0; | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * ILClone [SHELL32.18] | 
|  | * | 
|  | * NOTES | 
|  | *    duplicate an idlist | 
|  | */ | 
|  | LPITEMIDLIST WINAPI ILClone (LPCITEMIDLIST pidl) | 
|  | { | 
|  | DWORD    len; | 
|  | LPITEMIDLIST  newpidl; | 
|  |  | 
|  | if (!pidl) | 
|  | return NULL; | 
|  |  | 
|  | len = ILGetSize(pidl); | 
|  | newpidl = SHAlloc(len); | 
|  | if (newpidl) | 
|  | memcpy(newpidl,pidl,len); | 
|  |  | 
|  | TRACE("pidl=%p newpidl=%p\n",pidl, newpidl); | 
|  | pdump(pidl); | 
|  |  | 
|  | return newpidl; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * ILCloneFirst [SHELL32.19] | 
|  | * | 
|  | * NOTES | 
|  | *  duplicates the first idlist of a complex pidl | 
|  | */ | 
|  | LPITEMIDLIST WINAPI ILCloneFirst(LPCITEMIDLIST pidl) | 
|  | { | 
|  | DWORD len; | 
|  | LPITEMIDLIST pidlNew = NULL; | 
|  |  | 
|  | TRACE("pidl=%p\n", pidl); | 
|  | pdump(pidl); | 
|  |  | 
|  | if (pidl) | 
|  | { | 
|  | len = pidl->mkid.cb; | 
|  | pidlNew = SHAlloc(len+2); | 
|  | if (pidlNew) | 
|  | { | 
|  | memcpy(pidlNew,pidl,len+2);        /* 2 -> mind a desktop pidl */ | 
|  |  | 
|  | if (len) | 
|  | ILGetNext(pidlNew)->mkid.cb = 0x00; | 
|  | } | 
|  | } | 
|  | TRACE("-- newpidl=%p\n",pidlNew); | 
|  |  | 
|  | return pidlNew; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * ILLoadFromStream (SHELL32.26) | 
|  | * | 
|  | * NOTES | 
|  | *   the first two bytes are the len, the pidl is following then | 
|  | */ | 
|  | HRESULT WINAPI ILLoadFromStream (IStream * pStream, LPITEMIDLIST * ppPidl) | 
|  | { | 
|  | WORD        wLen = 0; | 
|  | DWORD       dwBytesRead; | 
|  | HRESULT     ret = E_FAIL; | 
|  |  | 
|  |  | 
|  | TRACE_(shell)("%p %p\n", pStream ,  ppPidl); | 
|  |  | 
|  | SHFree(*ppPidl); | 
|  | *ppPidl = NULL; | 
|  |  | 
|  | IStream_AddRef (pStream); | 
|  |  | 
|  | if (SUCCEEDED(IStream_Read(pStream, &wLen, 2, &dwBytesRead))) | 
|  | { | 
|  | TRACE("PIDL length is %d\n", wLen); | 
|  | if (wLen != 0) | 
|  | { | 
|  | *ppPidl = SHAlloc (wLen); | 
|  | if (SUCCEEDED(IStream_Read(pStream, *ppPidl , wLen, &dwBytesRead))) | 
|  | { | 
|  | TRACE("Stream read OK\n"); | 
|  | ret = S_OK; | 
|  | } | 
|  | else | 
|  | { | 
|  | WARN("reading pidl failed\n"); | 
|  | SHFree(*ppPidl); | 
|  | *ppPidl = NULL; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | *ppPidl = NULL; | 
|  | ret = S_OK; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* we are not yet fully compatible */ | 
|  | if (*ppPidl && !pcheck(*ppPidl)) | 
|  | { | 
|  | WARN("Check failed\n"); | 
|  | SHFree(*ppPidl); | 
|  | *ppPidl = NULL; | 
|  | } | 
|  |  | 
|  | IStream_Release (pStream); | 
|  | TRACE("done\n"); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * ILSaveToStream (SHELL32.27) | 
|  | * | 
|  | * NOTES | 
|  | *   the first two bytes are the len, the pidl is following then | 
|  | */ | 
|  | HRESULT WINAPI ILSaveToStream (IStream * pStream, LPCITEMIDLIST pPidl) | 
|  | { | 
|  | WORD        wLen = 0; | 
|  | HRESULT        ret = E_FAIL; | 
|  |  | 
|  | TRACE_(shell)("%p %p\n", pStream, pPidl); | 
|  |  | 
|  | IStream_AddRef (pStream); | 
|  |  | 
|  | wLen = ILGetSize(pPidl); | 
|  |  | 
|  | if (SUCCEEDED(IStream_Write(pStream, &wLen, 2, NULL))) | 
|  | { | 
|  | if (SUCCEEDED(IStream_Write(pStream, pPidl, wLen, NULL))) | 
|  | ret = S_OK; | 
|  | } | 
|  | IStream_Release (pStream); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * SHILCreateFromPath        [SHELL32.28] | 
|  | * | 
|  | * Create an ItemIDList from a path | 
|  | * | 
|  | * PARAMS | 
|  | *  path       [I] | 
|  | *  ppidl      [O] | 
|  | *  attributes [I/O] requested attributes on call and actual attributes when | 
|  | *                   the function returns | 
|  | * | 
|  | * RETURNS | 
|  | *  NO_ERROR if successful, or an OLE errer code otherwise | 
|  | * | 
|  | * NOTES | 
|  | *  Wrapper for IShellFolder_ParseDisplayName(). | 
|  | */ | 
|  | static HRESULT SHILCreateFromPathA(LPCSTR path, LPITEMIDLIST * ppidl, DWORD * attributes) | 
|  | { | 
|  | WCHAR lpszDisplayName[MAX_PATH]; | 
|  |  | 
|  | TRACE_(shell)("%s %p 0x%08x\n", path, ppidl, attributes ? *attributes : 0); | 
|  |  | 
|  | if (!MultiByteToWideChar(CP_ACP, 0, path, -1, lpszDisplayName, MAX_PATH)) | 
|  | lpszDisplayName[MAX_PATH-1] = 0; | 
|  |  | 
|  | return SHILCreateFromPathW(lpszDisplayName, ppidl, attributes); | 
|  | } | 
|  |  | 
|  | HRESULT SHILCreateFromPathW(LPCWSTR path, LPITEMIDLIST * ppidl, DWORD * attributes) | 
|  | { | 
|  | LPSHELLFOLDER sf; | 
|  | DWORD pchEaten; | 
|  | HRESULT ret = E_FAIL; | 
|  |  | 
|  | TRACE_(shell)("%s %p 0x%08x\n", debugstr_w(path), ppidl, attributes ? *attributes : 0); | 
|  |  | 
|  | if (SUCCEEDED (SHGetDesktopFolder(&sf))) | 
|  | { | 
|  | ret = IShellFolder_ParseDisplayName(sf, 0, NULL, (LPWSTR)path, &pchEaten, ppidl, attributes); | 
|  | IShellFolder_Release(sf); | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI SHILCreateFromPathAW (LPCVOID path, LPITEMIDLIST * ppidl, DWORD * attributes) | 
|  | { | 
|  | if ( SHELL_OsIsUnicode()) | 
|  | return SHILCreateFromPathW (path, ppidl, attributes); | 
|  | return SHILCreateFromPathA (path, ppidl, attributes); | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * SHCloneSpecialIDList      [SHELL32.89] | 
|  | * | 
|  | * Create an ItemIDList to one of the special folders. | 
|  |  | 
|  | * PARAMS | 
|  | *  hwndOwner    [in] | 
|  | *  nFolder      [in]    CSIDL_xxxxx | 
|  | *  fCreate      [in]    Create folder if it does not exist | 
|  | * | 
|  | * RETURNS | 
|  | *  Success: The newly created pidl | 
|  | *  Failure: NULL, if inputs are invalid. | 
|  | * | 
|  | * NOTES | 
|  | *  exported by ordinal. | 
|  | *  Caller is responsible for deallocating the returned ItemIDList with the | 
|  | *  shells IMalloc interface, aka ILFree. | 
|  | */ | 
|  | LPITEMIDLIST WINAPI SHCloneSpecialIDList(HWND hwndOwner, DWORD nFolder, BOOL fCreate) | 
|  | { | 
|  | LPITEMIDLIST ppidl; | 
|  | TRACE_(shell)("(hwnd=%p,csidl=0x%x,%s).\n", hwndOwner, nFolder, fCreate ? "T" : "F"); | 
|  |  | 
|  | if (fCreate) | 
|  | nFolder |= CSIDL_FLAG_CREATE; | 
|  |  | 
|  | SHGetSpecialFolderLocation(hwndOwner, nFolder, &ppidl); | 
|  | return ppidl; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * ILGlobalClone             [SHELL32.20] | 
|  | * | 
|  | * Clones an ItemIDList using Alloc. | 
|  | * | 
|  | * PARAMS | 
|  | *  pidl       [I]   ItemIDList to clone | 
|  | * | 
|  | * RETURNS | 
|  | *  Newly allocated ItemIDList. | 
|  | * | 
|  | * NOTES | 
|  | *  exported by ordinal. | 
|  | */ | 
|  | LPITEMIDLIST WINAPI ILGlobalClone(LPCITEMIDLIST pidl) | 
|  | { | 
|  | DWORD    len; | 
|  | LPITEMIDLIST  newpidl; | 
|  |  | 
|  | if (!pidl) | 
|  | return NULL; | 
|  |  | 
|  | len = ILGetSize(pidl); | 
|  | newpidl = Alloc(len); | 
|  | if (newpidl) | 
|  | memcpy(newpidl,pidl,len); | 
|  |  | 
|  | TRACE("pidl=%p newpidl=%p\n",pidl, newpidl); | 
|  | pdump(pidl); | 
|  |  | 
|  | return newpidl; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * ILIsEqual [SHELL32.21] | 
|  | * | 
|  | */ | 
|  | BOOL WINAPI ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) | 
|  | { | 
|  | char    szData1[MAX_PATH]; | 
|  | char    szData2[MAX_PATH]; | 
|  |  | 
|  | LPCITEMIDLIST pidltemp1 = pidl1; | 
|  | LPCITEMIDLIST pidltemp2 = pidl2; | 
|  |  | 
|  | TRACE("pidl1=%p pidl2=%p\n",pidl1, pidl2); | 
|  |  | 
|  | /* | 
|  | * Explorer reads from registry directly (StreamMRU), | 
|  | * so we can only check here | 
|  | */ | 
|  | if (!pcheck(pidl1) || !pcheck (pidl2)) | 
|  | return FALSE; | 
|  |  | 
|  | pdump (pidl1); | 
|  | pdump (pidl2); | 
|  |  | 
|  | if (!pidl1 || !pidl2) | 
|  | return FALSE; | 
|  |  | 
|  | while (pidltemp1->mkid.cb && pidltemp2->mkid.cb) | 
|  | { | 
|  | _ILSimpleGetText(pidltemp1, szData1, MAX_PATH); | 
|  | _ILSimpleGetText(pidltemp2, szData2, MAX_PATH); | 
|  |  | 
|  | if (strcasecmp( szData1, szData2 )) | 
|  | return FALSE; | 
|  |  | 
|  | pidltemp1 = ILGetNext(pidltemp1); | 
|  | pidltemp2 = ILGetNext(pidltemp2); | 
|  | } | 
|  |  | 
|  | if (!pidltemp1->mkid.cb && !pidltemp2->mkid.cb) | 
|  | return TRUE; | 
|  |  | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * ILIsParent                [SHELL32.23] | 
|  | * | 
|  | * Verifies that pidlParent is indeed the (immediate) parent of pidlChild. | 
|  | * | 
|  | * PARAMS | 
|  | *  pidlParent [I] | 
|  | *  pidlChild  [I] | 
|  | *  bImmediate [I]   only return true if the parent is the direct parent | 
|  | *                   of the child | 
|  | * | 
|  | * RETURNS | 
|  | *  True if the parent ItemIDlist is a complete part of the child ItemIdList, | 
|  | *  False otherwise. | 
|  | * | 
|  | * NOTES | 
|  | *  parent = a/b, child = a/b/c -> true, c is in folder a/b | 
|  | *  child = a/b/c/d -> false if bImmediate is true, d is not in folder a/b | 
|  | *  child = a/b/c/d -> true if bImmediate is false, d is in a subfolder of a/b | 
|  | *  child = a/b -> false if bImmediate is true | 
|  | *  child = a/b -> true if bImmediate is false | 
|  | */ | 
|  | BOOL WINAPI ILIsParent(LPCITEMIDLIST pidlParent, LPCITEMIDLIST pidlChild, BOOL bImmediate) | 
|  | { | 
|  | char    szData1[MAX_PATH]; | 
|  | char    szData2[MAX_PATH]; | 
|  | LPCITEMIDLIST pParent = pidlParent; | 
|  | LPCITEMIDLIST pChild = pidlChild; | 
|  |  | 
|  | TRACE("%p %p %x\n", pidlParent, pidlChild, bImmediate); | 
|  |  | 
|  | if (!pParent || !pChild) | 
|  | return FALSE; | 
|  |  | 
|  | while (pParent->mkid.cb && pChild->mkid.cb) | 
|  | { | 
|  | _ILSimpleGetText(pParent, szData1, MAX_PATH); | 
|  | _ILSimpleGetText(pChild, szData2, MAX_PATH); | 
|  |  | 
|  | if (strcasecmp( szData1, szData2 )) | 
|  | return FALSE; | 
|  |  | 
|  | pParent = ILGetNext(pParent); | 
|  | pChild = ILGetNext(pChild); | 
|  | } | 
|  |  | 
|  | /* child has shorter name than parent */ | 
|  | if (pParent->mkid.cb) | 
|  | return FALSE; | 
|  |  | 
|  | /* not immediate descent */ | 
|  | if ((!pChild->mkid.cb || ILGetNext(pChild)->mkid.cb) && bImmediate) | 
|  | return FALSE; | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * ILFindChild               [SHELL32.24] | 
|  | * | 
|  | *  Compares elements from pidl1 and pidl2. | 
|  | * | 
|  | * PARAMS | 
|  | *  pidl1      [I] | 
|  | *  pidl2      [I] | 
|  | * | 
|  | * RETURNS | 
|  | *  pidl1 is desktop      pidl2 | 
|  | *  pidl1 shorter pidl2   pointer to first different element of pidl2 | 
|  | *                        if there was at least one equal element | 
|  | *  pidl2 shorter pidl1   0 | 
|  | *  pidl2 equal pidl1     pointer to last 0x00-element of pidl2 | 
|  | * | 
|  | * NOTES | 
|  | *  exported by ordinal. | 
|  | */ | 
|  | LPITEMIDLIST WINAPI ILFindChild(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) | 
|  | { | 
|  | char    szData1[MAX_PATH]; | 
|  | char    szData2[MAX_PATH]; | 
|  |  | 
|  | LPCITEMIDLIST pidltemp1 = pidl1; | 
|  | LPCITEMIDLIST pidltemp2 = pidl2; | 
|  | LPCITEMIDLIST ret=NULL; | 
|  |  | 
|  | TRACE("pidl1=%p pidl2=%p\n",pidl1, pidl2); | 
|  |  | 
|  | /* explorer reads from registry directly (StreamMRU), | 
|  | so we can only check here */ | 
|  | if ((!pcheck (pidl1)) || (!pcheck (pidl2))) | 
|  | return FALSE; | 
|  |  | 
|  | pdump (pidl1); | 
|  | pdump (pidl2); | 
|  |  | 
|  | if (_ILIsDesktop(pidl1)) | 
|  | { | 
|  | ret = pidl2; | 
|  | } | 
|  | else | 
|  | { | 
|  | while (pidltemp1->mkid.cb && pidltemp2->mkid.cb) | 
|  | { | 
|  | _ILSimpleGetText(pidltemp1, szData1, MAX_PATH); | 
|  | _ILSimpleGetText(pidltemp2, szData2, MAX_PATH); | 
|  |  | 
|  | if (strcasecmp(szData1,szData2)) | 
|  | break; | 
|  |  | 
|  | pidltemp1 = ILGetNext(pidltemp1); | 
|  | pidltemp2 = ILGetNext(pidltemp2); | 
|  | ret = pidltemp2; | 
|  | } | 
|  |  | 
|  | if (pidltemp1->mkid.cb) | 
|  | ret = NULL; /* elements of pidl1 left*/ | 
|  | } | 
|  | TRACE_(shell)("--- %p\n", ret); | 
|  | return (LPITEMIDLIST)ret; /* pidl 1 is shorter */ | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * ILCombine                 [SHELL32.25] | 
|  | * | 
|  | * Concatenates two complex ItemIDLists. | 
|  | * | 
|  | * PARAMS | 
|  | *  pidl1      [I]   first complex ItemIDLists | 
|  | *  pidl2      [I]   complex ItemIDLists to append | 
|  | * | 
|  | * RETURNS | 
|  | *  if both pidl's == NULL      NULL | 
|  | *  if pidl1 == NULL            cloned pidl2 | 
|  | *  if pidl2 == NULL            cloned pidl1 | 
|  | *  otherwise new pidl with pidl2 appended to pidl1 | 
|  | * | 
|  | * NOTES | 
|  | *  exported by ordinal. | 
|  | *  Does not destroy the passed in ItemIDLists! | 
|  | */ | 
|  | LPITEMIDLIST WINAPI ILCombine(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) | 
|  | { | 
|  | DWORD    len1,len2; | 
|  | LPITEMIDLIST  pidlNew; | 
|  |  | 
|  | TRACE("pidl=%p pidl=%p\n",pidl1,pidl2); | 
|  |  | 
|  | if (!pidl1 && !pidl2) return NULL; | 
|  |  | 
|  | pdump (pidl1); | 
|  | pdump (pidl2); | 
|  |  | 
|  | if (!pidl1) | 
|  | { | 
|  | pidlNew = ILClone(pidl2); | 
|  | return pidlNew; | 
|  | } | 
|  |  | 
|  | if (!pidl2) | 
|  | { | 
|  | pidlNew = ILClone(pidl1); | 
|  | return pidlNew; | 
|  | } | 
|  |  | 
|  | len1  = ILGetSize(pidl1)-2; | 
|  | len2  = ILGetSize(pidl2); | 
|  | pidlNew  = SHAlloc(len1+len2); | 
|  |  | 
|  | if (pidlNew) | 
|  | { | 
|  | memcpy(pidlNew,pidl1,len1); | 
|  | memcpy(((BYTE *)pidlNew)+len1,pidl2,len2); | 
|  | } | 
|  |  | 
|  | /*  TRACE(pidl,"--new pidl=%p\n",pidlNew);*/ | 
|  | return pidlNew; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | *  SHGetRealIDL [SHELL32.98] | 
|  | * | 
|  | * NOTES | 
|  | */ | 
|  | HRESULT WINAPI SHGetRealIDL(LPSHELLFOLDER lpsf, LPCITEMIDLIST pidlSimple, LPITEMIDLIST *pidlReal) | 
|  | { | 
|  | IDataObject* pDataObj; | 
|  | HRESULT hr; | 
|  |  | 
|  | hr = IShellFolder_GetUIObjectOf(lpsf, 0, 1, &pidlSimple, | 
|  | &IID_IDataObject, 0, (LPVOID*)&pDataObj); | 
|  | if (SUCCEEDED(hr)) | 
|  | { | 
|  | STGMEDIUM medium; | 
|  | FORMATETC fmt; | 
|  |  | 
|  | fmt.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW); | 
|  | fmt.ptd = NULL; | 
|  | fmt.dwAspect = DVASPECT_CONTENT; | 
|  | fmt.lindex = -1; | 
|  | fmt.tymed = TYMED_HGLOBAL; | 
|  |  | 
|  | hr = IDataObject_GetData(pDataObj, &fmt, &medium); | 
|  |  | 
|  | IDataObject_Release(pDataObj); | 
|  |  | 
|  | if (SUCCEEDED(hr)) | 
|  | { | 
|  | /*assert(pida->cidl==1);*/ | 
|  | LPIDA pida = GlobalLock(medium.u.hGlobal); | 
|  |  | 
|  | LPCITEMIDLIST pidl_folder = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[0]); | 
|  | LPCITEMIDLIST pidl_child = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[1]); | 
|  |  | 
|  | *pidlReal = ILCombine(pidl_folder, pidl_child); | 
|  |  | 
|  | if (!*pidlReal) | 
|  | hr = E_OUTOFMEMORY; | 
|  |  | 
|  | GlobalUnlock(medium.u.hGlobal); | 
|  | GlobalFree(medium.u.hGlobal); | 
|  | } | 
|  | } | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | *  SHLogILFromFSIL [SHELL32.95] | 
|  | * | 
|  | * NOTES | 
|  | *  pild = CSIDL_DESKTOP    ret = 0 | 
|  | *  pild = CSIDL_DRIVES     ret = 0 | 
|  | */ | 
|  | LPITEMIDLIST WINAPI SHLogILFromFSIL(LPITEMIDLIST pidl) | 
|  | { | 
|  | FIXME("(pidl=%p)\n",pidl); | 
|  |  | 
|  | pdump(pidl); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * ILGetSize                 [SHELL32.152] | 
|  | * | 
|  | * Gets the byte size of an ItemIDList including zero terminator | 
|  | * | 
|  | * PARAMS | 
|  | *  pidl       [I]   ItemIDList | 
|  | * | 
|  | * RETURNS | 
|  | *  size of pidl in bytes | 
|  | * | 
|  | * NOTES | 
|  | *  exported by ordinal | 
|  | */ | 
|  | UINT WINAPI ILGetSize(LPCITEMIDLIST pidl) | 
|  | { | 
|  | LPCSHITEMID si = &(pidl->mkid); | 
|  | UINT len=0; | 
|  |  | 
|  | if (pidl) | 
|  | { | 
|  | while (si->cb) | 
|  | { | 
|  | len += si->cb; | 
|  | si  = (LPCSHITEMID)(((const BYTE*)si)+si->cb); | 
|  | } | 
|  | len += 2; | 
|  | } | 
|  | TRACE("pidl=%p size=%u\n",pidl, len); | 
|  | return len; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * ILGetNext                 [SHELL32.153] | 
|  | * | 
|  | * Gets the next ItemID of an ItemIDList | 
|  | * | 
|  | * PARAMS | 
|  | *  pidl       [I]   ItemIDList | 
|  | * | 
|  | * RETURNS | 
|  | *  null -> null | 
|  | *  desktop -> null | 
|  | *  simple pidl -> pointer to 0x0000 element | 
|  | * | 
|  | * NOTES | 
|  | *  exported by ordinal. | 
|  | */ | 
|  | LPITEMIDLIST WINAPI ILGetNext(LPCITEMIDLIST pidl) | 
|  | { | 
|  | WORD len; | 
|  |  | 
|  | TRACE("%p\n", pidl); | 
|  |  | 
|  | if (pidl) | 
|  | { | 
|  | len =  pidl->mkid.cb; | 
|  | if (len) | 
|  | { | 
|  | pidl = (LPCITEMIDLIST) (((const BYTE*)pidl)+len); | 
|  | TRACE("-- %p\n", pidl); | 
|  | return (LPITEMIDLIST)pidl; | 
|  | } | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * ILAppendID                [SHELL32.154] | 
|  | * | 
|  | * Adds the single ItemID item to the ItemIDList indicated by pidl. | 
|  | * If bEnd is FALSE, inserts the item in the front of the list, | 
|  | * otherwise it adds the item to the end. (???) | 
|  | * | 
|  | * PARAMS | 
|  | *  pidl       [I]   ItemIDList to extend | 
|  | *  item       [I]   ItemID to prepend/append | 
|  | *  bEnd       [I]   Indicates if the item should be appended | 
|  | * | 
|  | * NOTES | 
|  | *  Destroys the passed in idlist! (???) | 
|  | */ | 
|  | LPITEMIDLIST WINAPI ILAppendID(LPITEMIDLIST pidl, LPCSHITEMID item, BOOL bEnd) | 
|  | { | 
|  | LPITEMIDLIST idlRet; | 
|  | LPCITEMIDLIST itemid = (LPCITEMIDLIST)item; | 
|  |  | 
|  | WARN("(pidl=%p,pidl=%p,%08u)semi-stub\n",pidl,item,bEnd); | 
|  |  | 
|  | pdump (pidl); | 
|  | pdump (itemid); | 
|  |  | 
|  | if (_ILIsDesktop(pidl)) | 
|  | { | 
|  | idlRet = ILClone(itemid); | 
|  | SHFree (pidl); | 
|  | return idlRet; | 
|  | } | 
|  |  | 
|  | if (bEnd) | 
|  | idlRet = ILCombine(pidl, itemid); | 
|  | else | 
|  | idlRet = ILCombine(itemid, pidl); | 
|  |  | 
|  | SHFree(pidl); | 
|  | return idlRet; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * ILFree                    [SHELL32.155] | 
|  | * | 
|  | * Frees memory (if not NULL) allocated by SHMalloc allocator | 
|  | * | 
|  | * PARAMS | 
|  | *  pidl         [I] | 
|  | * | 
|  | * RETURNS | 
|  | *  Nothing | 
|  | * | 
|  | * NOTES | 
|  | *  exported by ordinal | 
|  | */ | 
|  | void WINAPI ILFree(LPITEMIDLIST pidl) | 
|  | { | 
|  | TRACE("(pidl=%p)\n",pidl); | 
|  | SHFree(pidl); | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * ILGlobalFree              [SHELL32.156] | 
|  | * | 
|  | * Frees memory (if not NULL) allocated by Alloc allocator | 
|  | * | 
|  | * PARAMS | 
|  | *  pidl         [I] | 
|  | * | 
|  | * RETURNS | 
|  | *  Nothing | 
|  | * | 
|  | * NOTES | 
|  | *  exported by ordinal. | 
|  | */ | 
|  | void WINAPI ILGlobalFree( LPITEMIDLIST pidl) | 
|  | { | 
|  | TRACE("%p\n", pidl); | 
|  |  | 
|  | Free(pidl); | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * ILCreateFromPathA         [SHELL32.189] | 
|  | * | 
|  | * Creates a complex ItemIDList from a path and returns it. | 
|  | * | 
|  | * PARAMS | 
|  | *  path         [I] | 
|  | * | 
|  | * RETURNS | 
|  | *  the newly created complex ItemIDList or NULL if failed | 
|  | * | 
|  | * NOTES | 
|  | *  exported by ordinal. | 
|  | */ | 
|  | LPITEMIDLIST WINAPI ILCreateFromPathA (LPCSTR path) | 
|  | { | 
|  | LPITEMIDLIST pidlnew = NULL; | 
|  |  | 
|  | TRACE_(shell)("%s\n", debugstr_a(path)); | 
|  |  | 
|  | if (SUCCEEDED(SHILCreateFromPathA(path, &pidlnew, NULL))) | 
|  | return pidlnew; | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * ILCreateFromPathW         [SHELL32.190] | 
|  | * | 
|  | * See ILCreateFromPathA. | 
|  | */ | 
|  | LPITEMIDLIST WINAPI ILCreateFromPathW (LPCWSTR path) | 
|  | { | 
|  | LPITEMIDLIST pidlnew = NULL; | 
|  |  | 
|  | TRACE_(shell)("%s\n", debugstr_w(path)); | 
|  |  | 
|  | if (SUCCEEDED(SHILCreateFromPathW(path, &pidlnew, NULL))) | 
|  | return pidlnew; | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * ILCreateFromPath          [SHELL32.157] | 
|  | */ | 
|  | LPITEMIDLIST WINAPI ILCreateFromPathAW (LPCVOID path) | 
|  | { | 
|  | if ( SHELL_OsIsUnicode()) | 
|  | return ILCreateFromPathW (path); | 
|  | return ILCreateFromPathA (path); | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * _ILParsePathW             [internal] | 
|  | * | 
|  | * Creates an ItemIDList from a path and returns it. | 
|  | * | 
|  | * PARAMS | 
|  | *  path         [I]   path to parse and convert into an ItemIDList | 
|  | *  lpFindFile   [I]   pointer to buffer to initialize the FileSystem | 
|  | *                     Bind Data object with | 
|  | *  bBindCtx     [I]   indicates to create a BindContext and assign a | 
|  | *                     FileSystem Bind Data object | 
|  | *  ppidl        [O]   the newly create ItemIDList | 
|  | *  prgfInOut    [I/O] requested attributes on input and actual | 
|  | *                     attributes on return | 
|  | * | 
|  | * RETURNS | 
|  | *  NO_ERROR on success or an OLE error code | 
|  | * | 
|  | * NOTES | 
|  | *  If either lpFindFile is non-NULL or bBindCtx is TRUE, this function | 
|  | *  creates a BindContext object and assigns a FileSystem Bind Data object | 
|  | *  to it, passing the BindContext to IShellFolder_ParseDisplayName. Each | 
|  | *  IShellFolder uses that FileSystem Bind Data object of the BindContext | 
|  | *  to pass data about the current path element to the next object. This | 
|  | *  is used to avoid having to verify the current path element on disk, so | 
|  | *  that creating an ItemIDList from a nonexistent path still can work. | 
|  | */ | 
|  | static HRESULT _ILParsePathW(LPCWSTR path, LPWIN32_FIND_DATAW lpFindFile, | 
|  | BOOL bBindCtx, LPITEMIDLIST *ppidl, LPDWORD prgfInOut) | 
|  | { | 
|  | LPSHELLFOLDER pSF = NULL; | 
|  | LPBC pBC = NULL; | 
|  | HRESULT ret; | 
|  |  | 
|  | TRACE("%s %p %d (%p)->%p (%p)->0x%x\n", debugstr_w(path), lpFindFile, bBindCtx, | 
|  | ppidl, ppidl ? *ppidl : NULL, | 
|  | prgfInOut, prgfInOut ? *prgfInOut : 0); | 
|  |  | 
|  | ret = SHGetDesktopFolder(&pSF); | 
|  | if (FAILED(ret)) | 
|  | return ret; | 
|  |  | 
|  | if (lpFindFile || bBindCtx) | 
|  | ret = IFileSystemBindData_Constructor(lpFindFile, &pBC); | 
|  |  | 
|  | if (SUCCEEDED(ret)) | 
|  | { | 
|  | ret = IShellFolder_ParseDisplayName(pSF, 0, pBC, (LPOLESTR)path, NULL, ppidl, prgfInOut); | 
|  | } | 
|  |  | 
|  | if (pBC) | 
|  | { | 
|  | IBindCtx_Release(pBC); | 
|  | pBC = NULL; | 
|  | } | 
|  |  | 
|  | IShellFolder_Release(pSF); | 
|  |  | 
|  | if (FAILED(ret) && ppidl) | 
|  | *ppidl = NULL; | 
|  |  | 
|  | TRACE("%s %p 0x%x\n", debugstr_w(path), ppidl ? *ppidl : NULL, prgfInOut ? *prgfInOut : 0); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * SHSimpleIDListFromPath    [SHELL32.162] | 
|  | * | 
|  | * Creates a simple ItemIDList from a path and returns it. This function | 
|  | * does not fail on nonexistent paths. | 
|  | * | 
|  | * PARAMS | 
|  | *  path         [I]   path to parse and convert into an ItemIDList | 
|  | * | 
|  | * RETURNS | 
|  | *  the newly created simple ItemIDList | 
|  | * | 
|  | * NOTES | 
|  | *  Simple in the name does not mean a relative ItemIDList but rather a | 
|  | *  fully qualified list, where only the file name is filled in and the | 
|  | *  directory flag for those ItemID elements this is known about, eg. | 
|  | *  it is not the last element in the ItemIDList or the actual directory | 
|  | *  exists on disk. | 
|  | *  exported by ordinal. | 
|  | */ | 
|  | LPITEMIDLIST SHSimpleIDListFromPathA(LPCSTR lpszPath) | 
|  | { | 
|  | LPITEMIDLIST pidl = NULL; | 
|  | LPWSTR wPath = NULL; | 
|  | int len; | 
|  |  | 
|  | TRACE("%s\n", debugstr_a(lpszPath)); | 
|  |  | 
|  | if (lpszPath) | 
|  | { | 
|  | len = MultiByteToWideChar(CP_ACP, 0, lpszPath, -1, NULL, 0); | 
|  | wPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); | 
|  | MultiByteToWideChar(CP_ACP, 0, lpszPath, -1, wPath, len); | 
|  | } | 
|  |  | 
|  | _ILParsePathW(wPath, NULL, TRUE, &pidl, NULL); | 
|  |  | 
|  | HeapFree(GetProcessHeap(), 0, wPath); | 
|  | TRACE("%s %p\n", debugstr_a(lpszPath), pidl); | 
|  | return pidl; | 
|  | } | 
|  |  | 
|  | LPITEMIDLIST SHSimpleIDListFromPathW(LPCWSTR lpszPath) | 
|  | { | 
|  | LPITEMIDLIST pidl = NULL; | 
|  |  | 
|  | TRACE("%s\n", debugstr_w(lpszPath)); | 
|  |  | 
|  | _ILParsePathW(lpszPath, NULL, TRUE, &pidl, NULL); | 
|  | TRACE("%s %p\n", debugstr_w(lpszPath), pidl); | 
|  | return pidl; | 
|  | } | 
|  |  | 
|  | LPITEMIDLIST WINAPI SHSimpleIDListFromPathAW(LPCVOID lpszPath) | 
|  | { | 
|  | if ( SHELL_OsIsUnicode()) | 
|  | return SHSimpleIDListFromPathW (lpszPath); | 
|  | return SHSimpleIDListFromPathA (lpszPath); | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * SHGetDataFromIDListA [SHELL32.247] | 
|  | * | 
|  | * NOTES | 
|  | *  the pidl can be a simple one. since we can't get the path out of the pidl | 
|  | *  we have to take all data from the pidl | 
|  | */ | 
|  | HRESULT WINAPI SHGetDataFromIDListA(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, | 
|  | int nFormat, LPVOID dest, int len) | 
|  | { | 
|  | LPSTR filename, shortname; | 
|  | WIN32_FIND_DATAA * pfd; | 
|  |  | 
|  | TRACE_(shell)("sf=%p pidl=%p 0x%04x %p 0x%04x stub\n",psf,pidl,nFormat,dest,len); | 
|  |  | 
|  | pdump(pidl); | 
|  | if (!psf || !dest) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | switch (nFormat) | 
|  | { | 
|  | case SHGDFIL_FINDDATA: | 
|  | pfd = dest; | 
|  |  | 
|  | if (_ILIsDrive(pidl) || _ILIsSpecialFolder(pidl)) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | if (len < sizeof(WIN32_FIND_DATAA)) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | ZeroMemory(pfd, sizeof (WIN32_FIND_DATAA)); | 
|  | _ILGetFileDateTime( pidl, &(pfd->ftLastWriteTime)); | 
|  | pfd->dwFileAttributes = _ILGetFileAttributes(pidl, NULL, 0); | 
|  | pfd->nFileSizeLow = _ILGetFileSize ( pidl, NULL, 0); | 
|  |  | 
|  | filename = _ILGetTextPointer(pidl); | 
|  | shortname = _ILGetSTextPointer(pidl); | 
|  |  | 
|  | if (filename) | 
|  | lstrcpynA(pfd->cFileName, filename, sizeof(pfd->cFileName)); | 
|  | else | 
|  | pfd->cFileName[0] = '\0'; | 
|  |  | 
|  | if (shortname) | 
|  | lstrcpynA(pfd->cAlternateFileName, shortname, sizeof(pfd->cAlternateFileName)); | 
|  | else | 
|  | pfd->cAlternateFileName[0] = '\0'; | 
|  | return S_OK; | 
|  |  | 
|  | case SHGDFIL_NETRESOURCE: | 
|  | case SHGDFIL_DESCRIPTIONID: | 
|  | FIXME_(shell)("SHGDFIL %i stub\n", nFormat); | 
|  | break; | 
|  |  | 
|  | default: | 
|  | ERR_(shell)("Unknown SHGDFIL %i, please report\n", nFormat); | 
|  | } | 
|  |  | 
|  | return E_INVALIDARG; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * SHGetDataFromIDListW [SHELL32.248] | 
|  | * | 
|  | */ | 
|  | HRESULT WINAPI SHGetDataFromIDListW(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, | 
|  | int nFormat, LPVOID dest, int len) | 
|  | { | 
|  | LPSTR filename, shortname; | 
|  | WIN32_FIND_DATAW * pfd = dest; | 
|  |  | 
|  | TRACE_(shell)("sf=%p pidl=%p 0x%04x %p 0x%04x stub\n",psf,pidl,nFormat,dest,len); | 
|  |  | 
|  | pdump(pidl); | 
|  |  | 
|  | if (!psf || !dest) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | switch (nFormat) | 
|  | { | 
|  | case SHGDFIL_FINDDATA: | 
|  | pfd = dest; | 
|  |  | 
|  | if (_ILIsDrive(pidl)) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | if (len < sizeof(WIN32_FIND_DATAW)) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | ZeroMemory(pfd, sizeof (WIN32_FIND_DATAW)); | 
|  | _ILGetFileDateTime( pidl, &(pfd->ftLastWriteTime)); | 
|  | pfd->dwFileAttributes = _ILGetFileAttributes(pidl, NULL, 0); | 
|  | pfd->nFileSizeLow = _ILGetFileSize ( pidl, NULL, 0); | 
|  |  | 
|  | filename = _ILGetTextPointer(pidl); | 
|  | shortname = _ILGetSTextPointer(pidl); | 
|  |  | 
|  | if (!filename) | 
|  | pfd->cFileName[0] = '\0'; | 
|  | else if (!MultiByteToWideChar(CP_ACP, 0, filename, -1, pfd->cFileName, MAX_PATH)) | 
|  | pfd->cFileName[MAX_PATH-1] = 0; | 
|  |  | 
|  | if (!shortname) | 
|  | pfd->cAlternateFileName[0] = '\0'; | 
|  | else if (!MultiByteToWideChar(CP_ACP, 0, shortname, -1, pfd->cAlternateFileName, 14)) | 
|  | pfd->cAlternateFileName[13] = 0; | 
|  | return S_OK; | 
|  |  | 
|  | case SHGDFIL_NETRESOURCE: | 
|  | case SHGDFIL_DESCRIPTIONID: | 
|  | FIXME_(shell)("SHGDFIL %i stub\n", nFormat); | 
|  | break; | 
|  |  | 
|  | default: | 
|  | ERR_(shell)("Unknown SHGDFIL %i, please report\n", nFormat); | 
|  | } | 
|  |  | 
|  | return E_INVALIDARG; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * SHGetPathFromIDListA        [SHELL32.@][NT 4.0: SHELL32.220] | 
|  | * | 
|  | * PARAMETERS | 
|  | *  pidl,   [IN] pidl | 
|  | *  pszPath [OUT] path | 
|  | * | 
|  | * RETURNS | 
|  | *  path from a passed PIDL. | 
|  | * | 
|  | * NOTES | 
|  | *    NULL returns FALSE | 
|  | *    desktop pidl gives path to desktop directory back | 
|  | *    special pidls returning FALSE | 
|  | */ | 
|  | BOOL WINAPI SHGetPathFromIDListA(LPCITEMIDLIST pidl, LPSTR pszPath) | 
|  | { | 
|  | WCHAR wszPath[MAX_PATH]; | 
|  | BOOL bSuccess; | 
|  |  | 
|  | bSuccess = SHGetPathFromIDListW(pidl, wszPath); | 
|  | WideCharToMultiByte(CP_ACP, 0, wszPath, -1, pszPath, MAX_PATH, NULL, NULL); | 
|  |  | 
|  | return bSuccess; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * SHGetPathFromIDListW             [SHELL32.@] | 
|  | * | 
|  | * See SHGetPathFromIDListA. | 
|  | */ | 
|  | BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath) | 
|  | { | 
|  | HRESULT hr; | 
|  | LPCITEMIDLIST pidlLast; | 
|  | LPSHELLFOLDER psfFolder; | 
|  | DWORD dwAttributes; | 
|  | STRRET strret; | 
|  |  | 
|  | TRACE_(shell)("(pidl=%p,%p)\n", pidl, pszPath); | 
|  | pdump(pidl); | 
|  |  | 
|  | *pszPath = '\0'; | 
|  | if (!pidl) | 
|  | return FALSE; | 
|  |  | 
|  | hr = SHBindToParent(pidl, &IID_IShellFolder, (VOID**)&psfFolder, &pidlLast); | 
|  | if (FAILED(hr)) return FALSE; | 
|  |  | 
|  | dwAttributes = SFGAO_FILESYSTEM; | 
|  | hr = IShellFolder_GetAttributesOf(psfFolder, 1, &pidlLast, &dwAttributes); | 
|  | if (FAILED(hr) || !(dwAttributes & SFGAO_FILESYSTEM)) { | 
|  | IShellFolder_Release(psfFolder); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | hr = IShellFolder_GetDisplayNameOf(psfFolder, pidlLast, SHGDN_FORPARSING, &strret); | 
|  | IShellFolder_Release(psfFolder); | 
|  | if (FAILED(hr)) return FALSE; | 
|  |  | 
|  | hr = StrRetToBufW(&strret, pidlLast, pszPath, MAX_PATH); | 
|  |  | 
|  | TRACE_(shell)("-- %s, 0x%08x\n",debugstr_w(pszPath), hr); | 
|  | return SUCCEEDED(hr); | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | *    SHBindToParent        [shell version 5.0] | 
|  | */ | 
|  | HRESULT WINAPI SHBindToParent(LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppv, LPCITEMIDLIST *ppidlLast) | 
|  | { | 
|  | IShellFolder    * psfDesktop; | 
|  | HRESULT         hr=E_FAIL; | 
|  |  | 
|  | TRACE_(shell)("pidl=%p\n", pidl); | 
|  | pdump(pidl); | 
|  |  | 
|  | if (!pidl || !ppv) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | *ppv = NULL; | 
|  | if (ppidlLast) | 
|  | *ppidlLast = NULL; | 
|  |  | 
|  | hr = SHGetDesktopFolder(&psfDesktop); | 
|  | if (FAILED(hr)) | 
|  | return hr; | 
|  |  | 
|  | if (_ILIsPidlSimple(pidl)) | 
|  | { | 
|  | /* we are on desktop level */ | 
|  | hr = IShellFolder_QueryInterface(psfDesktop, riid, ppv); | 
|  | } | 
|  | else | 
|  | { | 
|  | LPITEMIDLIST pidlParent = ILClone(pidl); | 
|  | ILRemoveLastID(pidlParent); | 
|  | hr = IShellFolder_BindToObject(psfDesktop, pidlParent, NULL, riid, ppv); | 
|  | SHFree (pidlParent); | 
|  | } | 
|  |  | 
|  | IShellFolder_Release(psfDesktop); | 
|  |  | 
|  | if (SUCCEEDED(hr) && ppidlLast) | 
|  | *ppidlLast = ILFindLastID(pidl); | 
|  |  | 
|  | TRACE_(shell)("-- psf=%p pidl=%p ret=0x%08x\n", *ppv, (ppidlLast)?*ppidlLast:NULL, hr); | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * SHParseDisplayName             [SHELL32.@] | 
|  | */ | 
|  | HRESULT WINAPI SHParseDisplayName(LPCWSTR name, IBindCtx *bindctx, LPITEMIDLIST *pidlist, | 
|  | SFGAOF attr_in, SFGAOF *attr_out) | 
|  | { | 
|  | IShellFolder *desktop; | 
|  | HRESULT hr; | 
|  |  | 
|  | TRACE("%s %p %p %d %p\n", debugstr_w(name), bindctx, pidlist, attr_in, attr_out); | 
|  |  | 
|  | *pidlist = NULL; | 
|  |  | 
|  | if (!name) return E_INVALIDARG; | 
|  |  | 
|  | hr = SHGetDesktopFolder(&desktop); | 
|  | if (hr != S_OK) return hr; | 
|  |  | 
|  | hr = IShellFolder_ParseDisplayName(desktop, NULL, bindctx, (LPWSTR)name, NULL, pidlist, &attr_in); | 
|  | if (attr_out) *attr_out = attr_in; | 
|  |  | 
|  | IShellFolder_Release(desktop); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * SHGetNameFromIDList             [SHELL32.@] | 
|  | */ | 
|  | HRESULT WINAPI SHGetNameFromIDList(PCIDLIST_ABSOLUTE pidl, SIGDN sigdnName, PWSTR *ppszName) | 
|  | { | 
|  | IShellFolder *psfparent; | 
|  | LPCITEMIDLIST child_pidl; | 
|  | STRRET disp_name; | 
|  | HRESULT ret; | 
|  |  | 
|  | TRACE("%p 0x%08x %p\n", pidl, sigdnName, ppszName); | 
|  |  | 
|  | *ppszName = NULL; | 
|  | ret = SHBindToParent(pidl, &IID_IShellFolder, (void**)&psfparent, &child_pidl); | 
|  | if(SUCCEEDED(ret)) | 
|  | { | 
|  | switch(sigdnName) | 
|  | { | 
|  | /* sigdnName & 0xffff */ | 
|  | case SIGDN_NORMALDISPLAY:               /* SHGDN_NORMAL */ | 
|  | case SIGDN_PARENTRELATIVEPARSING:       /* SHGDN_INFOLDER | SHGDN_FORPARSING */ | 
|  | case SIGDN_PARENTRELATIVEEDITING:       /* SHGDN_INFOLDER | SHGDN_FOREDITING */ | 
|  | case SIGDN_DESKTOPABSOLUTEPARSING:      /* SHGDN_FORPARSING */ | 
|  | case SIGDN_DESKTOPABSOLUTEEDITING:      /* SHGDN_FOREDITING | SHGDN_FORADDRESSBAR*/ | 
|  | case SIGDN_PARENTRELATIVEFORADDRESSBAR: /* SIGDN_INFOLDER | SHGDN_FORADDRESSBAR */ | 
|  | case SIGDN_PARENTRELATIVE:              /* SIGDN_INFOLDER */ | 
|  |  | 
|  | disp_name.uType = STRRET_WSTR; | 
|  | ret = IShellFolder_GetDisplayNameOf(psfparent, child_pidl, | 
|  | sigdnName & 0xffff, | 
|  | &disp_name); | 
|  | if(SUCCEEDED(ret)) | 
|  | ret = StrRetToStrW(&disp_name, pidl, ppszName); | 
|  |  | 
|  | break; | 
|  |  | 
|  | case SIGDN_FILESYSPATH: | 
|  | *ppszName = CoTaskMemAlloc(sizeof(WCHAR)*MAX_PATH); | 
|  | if(SHGetPathFromIDListW(pidl, *ppszName)) | 
|  | { | 
|  | TRACE("Got string %s\n", debugstr_w(*ppszName)); | 
|  | ret = S_OK; | 
|  | } | 
|  | else | 
|  | { | 
|  | CoTaskMemFree(*ppszName); | 
|  | ret = E_INVALIDARG; | 
|  | } | 
|  | break; | 
|  |  | 
|  | case SIGDN_URL: | 
|  | default: | 
|  | FIXME("Unsupported SIGDN %x\n", sigdnName); | 
|  | ret = E_FAIL; | 
|  | } | 
|  |  | 
|  | IShellFolder_Release(psfparent); | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * SHGetIDListFromObject             [SHELL32.@] | 
|  | */ | 
|  | HRESULT WINAPI SHGetIDListFromObject(IUnknown *punk, PIDLIST_ABSOLUTE *ppidl) | 
|  | { | 
|  | IPersistIDList *ppersidl; | 
|  | IPersistFolder2 *ppf2; | 
|  | IDataObject *pdo; | 
|  | IFolderView *pfv; | 
|  | HRESULT ret; | 
|  |  | 
|  | if(!punk) | 
|  | return E_NOINTERFACE; | 
|  |  | 
|  | *ppidl = NULL; | 
|  |  | 
|  | /* Try IPersistIDList */ | 
|  | ret = IUnknown_QueryInterface(punk, &IID_IPersistIDList, (void**)&ppersidl); | 
|  | if(SUCCEEDED(ret)) | 
|  | { | 
|  | TRACE("IPersistIDList (%p)\n", ppersidl); | 
|  | ret = IPersistIDList_GetIDList(ppersidl, ppidl); | 
|  | IPersistIDList_Release(ppersidl); | 
|  | if(SUCCEEDED(ret)) | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* Try IPersistFolder2 */ | 
|  | ret = IUnknown_QueryInterface(punk, &IID_IPersistFolder2, (void**)&ppf2); | 
|  | if(SUCCEEDED(ret)) | 
|  | { | 
|  | TRACE("IPersistFolder2 (%p)\n", ppf2); | 
|  | ret = IPersistFolder2_GetCurFolder(ppf2, ppidl); | 
|  | IPersistFolder2_Release(ppf2); | 
|  | if(SUCCEEDED(ret)) | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* Try IDataObject */ | 
|  | ret = IUnknown_QueryInterface(punk, &IID_IDataObject, (void**)&pdo); | 
|  | if(SUCCEEDED(ret)) | 
|  | { | 
|  | IShellItem *psi; | 
|  | TRACE("IDataObject (%p)\n", pdo); | 
|  | ret = SHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, | 
|  | &IID_IShellItem, (void**)&psi); | 
|  | if(SUCCEEDED(ret)) | 
|  | { | 
|  | ret = SHGetIDListFromObject((IUnknown*)psi, ppidl); | 
|  | IShellItem_Release(psi); | 
|  | } | 
|  | IDataObject_Release(pdo); | 
|  |  | 
|  | if(SUCCEEDED(ret)) | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* Try IFolderView */ | 
|  | ret = IUnknown_QueryInterface(punk, &IID_IFolderView, (void**)&pfv); | 
|  | if(SUCCEEDED(ret)) | 
|  | { | 
|  | IShellFolder *psf; | 
|  | TRACE("IFolderView (%p)\n", pfv); | 
|  | ret = IFolderView_GetFolder(pfv, &IID_IShellFolder, (void**)&psf); | 
|  | if(SUCCEEDED(ret)) | 
|  | { | 
|  | /* We might be able to get IPersistFolder2 from a shellfolder. */ | 
|  | ret = SHGetIDListFromObject((IUnknown*)psf, ppidl); | 
|  | IShellFolder_Release(psf); | 
|  | } | 
|  | IFolderView_Release(pfv); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | * | 
|  | *        internal functions | 
|  | * | 
|  | *    ### 1. section creating pidls ### | 
|  | * | 
|  | ************************************************************************* | 
|  | */ | 
|  |  | 
|  | /* Basic PIDL constructor.  Allocates size + 5 bytes, where: | 
|  | * - two bytes are SHITEMID.cb | 
|  | * - one byte is PIDLDATA.type | 
|  | * - two bytes are the NULL PIDL terminator | 
|  | * Sets type of the returned PIDL to type. | 
|  | */ | 
|  | static LPITEMIDLIST _ILAlloc(PIDLTYPE type, unsigned int size) | 
|  | { | 
|  | LPITEMIDLIST pidlOut = NULL; | 
|  |  | 
|  | pidlOut = SHAlloc(size + 5); | 
|  | if(pidlOut) | 
|  | { | 
|  | LPPIDLDATA pData; | 
|  | LPITEMIDLIST pidlNext; | 
|  |  | 
|  | ZeroMemory(pidlOut, size + 5); | 
|  | pidlOut->mkid.cb = size + 3; | 
|  |  | 
|  | pData = _ILGetDataPointer(pidlOut); | 
|  | if (pData) | 
|  | pData->type = type; | 
|  |  | 
|  | pidlNext = ILGetNext(pidlOut); | 
|  | if (pidlNext) | 
|  | pidlNext->mkid.cb = 0x00; | 
|  | TRACE("-- (pidl=%p, size=%u)\n", pidlOut, size); | 
|  | } | 
|  |  | 
|  | return pidlOut; | 
|  | } | 
|  |  | 
|  | LPITEMIDLIST _ILCreateDesktop(void) | 
|  | { | 
|  | LPITEMIDLIST ret; | 
|  |  | 
|  | TRACE("()\n"); | 
|  | ret = SHAlloc(2); | 
|  | if (ret) | 
|  | ret->mkid.cb = 0; | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | LPITEMIDLIST _ILCreateMyComputer(void) | 
|  | { | 
|  | TRACE("()\n"); | 
|  | return _ILCreateGuid(PT_GUID, &CLSID_MyComputer); | 
|  | } | 
|  |  | 
|  | LPITEMIDLIST _ILCreateMyDocuments(void) | 
|  | { | 
|  | TRACE("()\n"); | 
|  | return _ILCreateGuid(PT_GUID, &CLSID_MyDocuments); | 
|  | } | 
|  |  | 
|  | LPITEMIDLIST _ILCreateIExplore(void) | 
|  | { | 
|  | TRACE("()\n"); | 
|  | return _ILCreateGuid(PT_GUID, &CLSID_Internet); | 
|  | } | 
|  |  | 
|  | LPITEMIDLIST _ILCreateControlPanel(void) | 
|  | { | 
|  | LPITEMIDLIST parent = _ILCreateGuid(PT_GUID, &CLSID_MyComputer), ret = NULL; | 
|  |  | 
|  | TRACE("()\n"); | 
|  | if (parent) | 
|  | { | 
|  | LPITEMIDLIST cpl = _ILCreateGuid(PT_SHELLEXT, &CLSID_ControlPanel); | 
|  |  | 
|  | if (cpl) | 
|  | { | 
|  | ret = ILCombine(parent, cpl); | 
|  | SHFree(cpl); | 
|  | } | 
|  | SHFree(parent); | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | LPITEMIDLIST _ILCreatePrinters(void) | 
|  | { | 
|  | LPITEMIDLIST parent = _ILCreateGuid(PT_GUID, &CLSID_MyComputer), ret = NULL; | 
|  |  | 
|  | TRACE("()\n"); | 
|  | if (parent) | 
|  | { | 
|  | LPITEMIDLIST printers = _ILCreateGuid(PT_YAGUID, &CLSID_Printers); | 
|  |  | 
|  | if (printers) | 
|  | { | 
|  | ret = ILCombine(parent, printers); | 
|  | SHFree(printers); | 
|  | } | 
|  | SHFree(parent); | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | LPITEMIDLIST _ILCreateNetwork(void) | 
|  | { | 
|  | TRACE("()\n"); | 
|  | return _ILCreateGuid(PT_GUID, &CLSID_NetworkPlaces); | 
|  | } | 
|  |  | 
|  | LPITEMIDLIST _ILCreateBitBucket(void) | 
|  | { | 
|  | TRACE("()\n"); | 
|  | return _ILCreateGuid(PT_GUID, &CLSID_RecycleBin); | 
|  | } | 
|  |  | 
|  | LPITEMIDLIST _ILCreateNetHood(void) | 
|  | { | 
|  | TRACE("()\n"); | 
|  | return _ILCreateGuid(PT_GUID, &CLSID_NetworkPlaces); | 
|  | } | 
|  |  | 
|  | LPITEMIDLIST _ILCreateGuid(PIDLTYPE type, REFIID guid) | 
|  | { | 
|  | LPITEMIDLIST pidlOut; | 
|  |  | 
|  | if (type == PT_SHELLEXT || type == PT_GUID || type == PT_YAGUID) | 
|  | { | 
|  | pidlOut = _ILAlloc(type, sizeof(GUIDStruct)); | 
|  | if (pidlOut) | 
|  | { | 
|  | LPPIDLDATA pData = _ILGetDataPointer(pidlOut); | 
|  |  | 
|  | pData->u.guid.guid = *guid; | 
|  | TRACE("-- create GUID-pidl %s\n", | 
|  | debugstr_guid(&(pData->u.guid.guid))); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | WARN("%d: invalid type for GUID\n", type); | 
|  | pidlOut = NULL; | 
|  | } | 
|  | return pidlOut; | 
|  | } | 
|  |  | 
|  | LPITEMIDLIST _ILCreateGuidFromStrA(LPCSTR szGUID) | 
|  | { | 
|  | IID iid; | 
|  |  | 
|  | if (FAILED(SHCLSIDFromStringA(szGUID, &iid))) | 
|  | { | 
|  | ERR("%s is not a GUID\n", szGUID); | 
|  | return NULL; | 
|  | } | 
|  | return _ILCreateGuid(PT_GUID, &iid); | 
|  | } | 
|  |  | 
|  | LPITEMIDLIST _ILCreateGuidFromStrW(LPCWSTR szGUID) | 
|  | { | 
|  | IID iid; | 
|  |  | 
|  | if (FAILED(SHCLSIDFromStringW(szGUID, &iid))) | 
|  | { | 
|  | ERR("%s is not a GUID\n", debugstr_w(szGUID)); | 
|  | return NULL; | 
|  | } | 
|  | return _ILCreateGuid(PT_GUID, &iid); | 
|  | } | 
|  |  | 
|  | LPITEMIDLIST _ILCreateFromFindDataW( const WIN32_FIND_DATAW *wfd ) | 
|  | { | 
|  | char    buff[MAX_PATH + 14 +1]; /* see WIN32_FIND_DATA */ | 
|  | DWORD   len, len1, wlen, alen; | 
|  | LPITEMIDLIST pidl; | 
|  | PIDLTYPE type; | 
|  |  | 
|  | if (!wfd) | 
|  | return NULL; | 
|  |  | 
|  | TRACE("(%s, %s)\n",debugstr_w(wfd->cAlternateFileName), debugstr_w(wfd->cFileName)); | 
|  |  | 
|  | /* prepare buffer with both names */ | 
|  | len = WideCharToMultiByte(CP_ACP,0,wfd->cFileName,-1,buff,MAX_PATH,NULL,NULL); | 
|  | len1 = WideCharToMultiByte(CP_ACP,0,wfd->cAlternateFileName,-1, buff+len, sizeof(buff)-len, NULL, NULL); | 
|  | alen = len + len1; | 
|  |  | 
|  | type = (wfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? PT_FOLDER : PT_VALUE; | 
|  |  | 
|  | wlen = lstrlenW(wfd->cFileName) + 1; | 
|  | pidl = _ILAlloc(type, FIELD_OFFSET(FileStruct, szNames[alen + (alen & 1)]) + | 
|  | FIELD_OFFSET(FileStructW, wszName[wlen]) + sizeof(WORD)); | 
|  | if (pidl) | 
|  | { | 
|  | LPPIDLDATA pData = _ILGetDataPointer(pidl); | 
|  | FileStruct *fs = &pData->u.file; | 
|  | FileStructW *fsw; | 
|  | WORD *pOffsetW; | 
|  |  | 
|  | FileTimeToDosDateTime( &wfd->ftLastWriteTime, &fs->uFileDate, &fs->uFileTime); | 
|  | fs->dwFileSize = wfd->nFileSizeLow; | 
|  | fs->uFileAttribs = wfd->dwFileAttributes; | 
|  | memcpy(fs->szNames, buff, alen); | 
|  |  | 
|  | fsw = (FileStructW*)(pData->u.file.szNames + alen + (alen & 0x1)); | 
|  | fsw->cbLen = FIELD_OFFSET(FileStructW, wszName[wlen]) + sizeof(WORD); | 
|  | FileTimeToDosDateTime( &wfd->ftCreationTime, &fsw->uCreationDate, &fsw->uCreationTime); | 
|  | FileTimeToDosDateTime( &wfd->ftLastAccessTime, &fsw->uLastAccessDate, &fsw->uLastAccessTime); | 
|  | memcpy(fsw->wszName, wfd->cFileName, wlen * sizeof(WCHAR)); | 
|  |  | 
|  | pOffsetW = (WORD*)((LPBYTE)pidl + pidl->mkid.cb - sizeof(WORD)); | 
|  | *pOffsetW = (LPBYTE)fsw - (LPBYTE)pidl; | 
|  | TRACE("-- Set Value: %s\n",debugstr_w(fsw->wszName)); | 
|  | } | 
|  | return pidl; | 
|  |  | 
|  | } | 
|  |  | 
|  | HRESULT _ILCreateFromPathW(LPCWSTR szPath, LPITEMIDLIST* ppidl) | 
|  | { | 
|  | HANDLE hFile; | 
|  | WIN32_FIND_DATAW stffile; | 
|  |  | 
|  | if (!ppidl) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | hFile = FindFirstFileW(szPath, &stffile); | 
|  | if (hFile == INVALID_HANDLE_VALUE) | 
|  | return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); | 
|  |  | 
|  | FindClose(hFile); | 
|  |  | 
|  | *ppidl = _ILCreateFromFindDataW(&stffile); | 
|  |  | 
|  | return *ppidl ? S_OK : E_OUTOFMEMORY; | 
|  | } | 
|  |  | 
|  | LPITEMIDLIST _ILCreateDrive(LPCWSTR lpszNew) | 
|  | { | 
|  | LPITEMIDLIST pidlOut; | 
|  |  | 
|  | TRACE("(%s)\n",debugstr_w(lpszNew)); | 
|  |  | 
|  | pidlOut = _ILAlloc(PT_DRIVE, sizeof(DriveStruct)); | 
|  | if (pidlOut) | 
|  | { | 
|  | LPSTR pszDest; | 
|  |  | 
|  | pszDest = _ILGetTextPointer(pidlOut); | 
|  | if (pszDest) | 
|  | { | 
|  | strcpy(pszDest, "x:\\"); | 
|  | pszDest[0]=toupperW(lpszNew[0]); | 
|  | TRACE("-- create Drive: %s\n", debugstr_a(pszDest)); | 
|  | } | 
|  | } | 
|  | return pidlOut; | 
|  | } | 
|  |  | 
|  | LPITEMIDLIST _ILCreateEntireNetwork(void) | 
|  | { | 
|  | LPITEMIDLIST pidlOut; | 
|  |  | 
|  | TRACE("\n"); | 
|  |  | 
|  | pidlOut = _ILAlloc(PT_NETWORK, FIELD_OFFSET(PIDLDATA, u.network.szNames[sizeof("Entire Network")])); | 
|  | if (pidlOut) | 
|  | { | 
|  | LPPIDLDATA pData = _ILGetDataPointer(pidlOut); | 
|  |  | 
|  | pData->u.network.dummy = 0; | 
|  | strcpy(pData->u.network.szNames, "Entire Network"); | 
|  | } | 
|  | return pidlOut; | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | *  _ILGetDrive() | 
|  | * | 
|  | *  Gets the text for the drive eg. 'c:\' | 
|  | * | 
|  | * RETURNS | 
|  | *  strlen (lpszText) | 
|  | */ | 
|  | DWORD _ILGetDrive(LPCITEMIDLIST pidl,LPSTR pOut, UINT uSize) | 
|  | { | 
|  | TRACE("(%p,%p,%u)\n",pidl,pOut,uSize); | 
|  |  | 
|  | if(_ILIsMyComputer(pidl)) | 
|  | pidl = ILGetNext(pidl); | 
|  |  | 
|  | if (pidl && _ILIsDrive(pidl)) | 
|  | return _ILSimpleGetText(pidl, pOut, uSize); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | * | 
|  | *    ### 2. section testing pidls ### | 
|  | * | 
|  | ************************************************************************** | 
|  | *  _ILIsUnicode() | 
|  | *  _ILIsDesktop() | 
|  | *  _ILIsMyComputer() | 
|  | *  _ILIsSpecialFolder() | 
|  | *  _ILIsDrive() | 
|  | *  _ILIsFolder() | 
|  | *  _ILIsValue() | 
|  | *  _ILIsPidlSimple() | 
|  | */ | 
|  | BOOL _ILIsUnicode(LPCITEMIDLIST pidl) | 
|  | { | 
|  | LPPIDLDATA lpPData = _ILGetDataPointer(pidl); | 
|  |  | 
|  | TRACE("(%p)\n",pidl); | 
|  |  | 
|  | return (pidl && lpPData && PT_VALUEW == lpPData->type); | 
|  | } | 
|  |  | 
|  | BOOL _ILIsDesktop(LPCITEMIDLIST pidl) | 
|  | { | 
|  | TRACE("(%p)\n",pidl); | 
|  |  | 
|  | return !pidl || !pidl->mkid.cb; | 
|  | } | 
|  |  | 
|  | BOOL _ILIsMyComputer(LPCITEMIDLIST pidl) | 
|  | { | 
|  | REFIID iid = _ILGetGUIDPointer(pidl); | 
|  |  | 
|  | TRACE("(%p)\n",pidl); | 
|  |  | 
|  | if (iid) | 
|  | return IsEqualIID(iid, &CLSID_MyComputer); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | BOOL _ILIsSpecialFolder (LPCITEMIDLIST pidl) | 
|  | { | 
|  | LPPIDLDATA lpPData = _ILGetDataPointer(pidl); | 
|  |  | 
|  | TRACE("(%p)\n",pidl); | 
|  |  | 
|  | return (pidl && ( (lpPData && (PT_GUID== lpPData->type || PT_SHELLEXT== lpPData->type || PT_YAGUID == lpPData->type)) || | 
|  | (pidl && pidl->mkid.cb == 0x00) | 
|  | )); | 
|  | } | 
|  |  | 
|  | BOOL _ILIsDrive(LPCITEMIDLIST pidl) | 
|  | { | 
|  | LPPIDLDATA lpPData = _ILGetDataPointer(pidl); | 
|  |  | 
|  | TRACE("(%p)\n",pidl); | 
|  |  | 
|  | return (pidl && lpPData && (PT_DRIVE == lpPData->type || | 
|  | PT_DRIVE1 == lpPData->type || | 
|  | PT_DRIVE2 == lpPData->type || | 
|  | PT_DRIVE3 == lpPData->type)); | 
|  | } | 
|  |  | 
|  | BOOL _ILIsFolder(LPCITEMIDLIST pidl) | 
|  | { | 
|  | LPPIDLDATA lpPData = _ILGetDataPointer(pidl); | 
|  |  | 
|  | TRACE("(%p)\n",pidl); | 
|  |  | 
|  | return (pidl && lpPData && (PT_FOLDER == lpPData->type || PT_FOLDER1 == lpPData->type)); | 
|  | } | 
|  |  | 
|  | BOOL _ILIsValue(LPCITEMIDLIST pidl) | 
|  | { | 
|  | LPPIDLDATA lpPData = _ILGetDataPointer(pidl); | 
|  |  | 
|  | TRACE("(%p)\n",pidl); | 
|  |  | 
|  | return (pidl && lpPData && PT_VALUE == lpPData->type); | 
|  | } | 
|  |  | 
|  | BOOL _ILIsCPanelStruct(LPCITEMIDLIST pidl) | 
|  | { | 
|  | LPPIDLDATA lpPData = _ILGetDataPointer(pidl); | 
|  |  | 
|  | TRACE("(%p)\n",pidl); | 
|  |  | 
|  | return (pidl && lpPData && (lpPData->type == 0)); | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | *    _ILIsPidlSimple | 
|  | */ | 
|  | BOOL _ILIsPidlSimple(LPCITEMIDLIST pidl) | 
|  | { | 
|  | BOOL ret = TRUE; | 
|  |  | 
|  | if(! _ILIsDesktop(pidl))    /* pidl=NULL or mkid.cb=0 */ | 
|  | { | 
|  | WORD len = pidl->mkid.cb; | 
|  | LPCITEMIDLIST pidlnext = (LPCITEMIDLIST) (((const BYTE*)pidl) + len ); | 
|  |  | 
|  | if (pidlnext->mkid.cb) | 
|  | ret = FALSE; | 
|  | } | 
|  |  | 
|  | TRACE("%s\n", ret ? "Yes" : "No"); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | * | 
|  | *    ### 3. section getting values from pidls ### | 
|  | */ | 
|  |  | 
|  | /************************************************************************** | 
|  | *  _ILSimpleGetText | 
|  | * | 
|  | * gets the text for the first item in the pidl (eg. simple pidl) | 
|  | * | 
|  | * returns the length of the string | 
|  | */ | 
|  | DWORD _ILSimpleGetText (LPCITEMIDLIST pidl, LPSTR szOut, UINT uOutSize) | 
|  | { | 
|  | DWORD        dwReturn=0; | 
|  | LPSTR        szSrc; | 
|  | LPWSTR       szSrcW; | 
|  | GUID const * riid; | 
|  | char szTemp[MAX_PATH]; | 
|  |  | 
|  | TRACE("(%p %p %x)\n",pidl,szOut,uOutSize); | 
|  |  | 
|  | if (!pidl) | 
|  | return 0; | 
|  |  | 
|  | if (szOut) | 
|  | *szOut = 0; | 
|  |  | 
|  | if (_ILIsDesktop(pidl)) | 
|  | { | 
|  | /* desktop */ | 
|  | if (HCR_GetClassNameA(&CLSID_ShellDesktop, szTemp, MAX_PATH)) | 
|  | { | 
|  | if (szOut) | 
|  | lstrcpynA(szOut, szTemp, uOutSize); | 
|  |  | 
|  | dwReturn = strlen (szTemp); | 
|  | } | 
|  | } | 
|  | else if (( szSrc = _ILGetTextPointer(pidl) )) | 
|  | { | 
|  | /* filesystem */ | 
|  | if (szOut) | 
|  | lstrcpynA(szOut, szSrc, uOutSize); | 
|  |  | 
|  | dwReturn = strlen(szSrc); | 
|  | } | 
|  | else if (( szSrcW = _ILGetTextPointerW(pidl) )) | 
|  | { | 
|  | /* unicode filesystem */ | 
|  | WideCharToMultiByte(CP_ACP,0,szSrcW, -1, szTemp, MAX_PATH, NULL, NULL); | 
|  |  | 
|  | if (szOut) | 
|  | lstrcpynA(szOut, szTemp, uOutSize); | 
|  |  | 
|  | dwReturn = strlen (szTemp); | 
|  | } | 
|  | else if (( riid = _ILGetGUIDPointer(pidl) )) | 
|  | { | 
|  | /* special folder */ | 
|  | if ( HCR_GetClassNameA(riid, szTemp, MAX_PATH) ) | 
|  | { | 
|  | if (szOut) | 
|  | lstrcpynA(szOut, szTemp, uOutSize); | 
|  |  | 
|  | dwReturn = strlen (szTemp); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | ERR("-- no text\n"); | 
|  | } | 
|  |  | 
|  | TRACE("-- (%p=%s 0x%08x)\n",szOut,debugstr_a(szOut),dwReturn); | 
|  | return dwReturn; | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | *  _ILSimpleGetTextW | 
|  | * | 
|  | * gets the text for the first item in the pidl (eg. simple pidl) | 
|  | * | 
|  | * returns the length of the string | 
|  | */ | 
|  | DWORD _ILSimpleGetTextW (LPCITEMIDLIST pidl, LPWSTR szOut, UINT uOutSize) | 
|  | { | 
|  | DWORD   dwReturn; | 
|  | FileStructW *pFileStructW = _ILGetFileStructW(pidl); | 
|  |  | 
|  | TRACE("(%p %p %x)\n",pidl,szOut,uOutSize); | 
|  |  | 
|  | if (pFileStructW) { | 
|  | lstrcpynW(szOut, pFileStructW->wszName, uOutSize); | 
|  | dwReturn = lstrlenW(pFileStructW->wszName); | 
|  | } else { | 
|  | GUID const * riid; | 
|  | WCHAR szTemp[MAX_PATH]; | 
|  | LPSTR szSrc; | 
|  | LPWSTR szSrcW; | 
|  | dwReturn=0; | 
|  |  | 
|  | if (!pidl) | 
|  | return 0; | 
|  |  | 
|  | if (szOut) | 
|  | *szOut = 0; | 
|  |  | 
|  | if (_ILIsDesktop(pidl)) | 
|  | { | 
|  | /* desktop */ | 
|  | if (HCR_GetClassNameW(&CLSID_ShellDesktop, szTemp, MAX_PATH)) | 
|  | { | 
|  | if (szOut) | 
|  | lstrcpynW(szOut, szTemp, uOutSize); | 
|  |  | 
|  | dwReturn = lstrlenW (szTemp); | 
|  | } | 
|  | } | 
|  | else if (( szSrcW = _ILGetTextPointerW(pidl) )) | 
|  | { | 
|  | /* unicode filesystem */ | 
|  | if (szOut) | 
|  | lstrcpynW(szOut, szSrcW, uOutSize); | 
|  |  | 
|  | dwReturn = lstrlenW(szSrcW); | 
|  | } | 
|  | else if (( szSrc = _ILGetTextPointer(pidl) )) | 
|  | { | 
|  | /* filesystem */ | 
|  | MultiByteToWideChar(CP_ACP, 0, szSrc, -1, szTemp, MAX_PATH); | 
|  |  | 
|  | if (szOut) | 
|  | lstrcpynW(szOut, szTemp, uOutSize); | 
|  |  | 
|  | dwReturn = lstrlenW (szTemp); | 
|  | } | 
|  | else if (( riid = _ILGetGUIDPointer(pidl) )) | 
|  | { | 
|  | /* special folder */ | 
|  | if ( HCR_GetClassNameW(riid, szTemp, MAX_PATH) ) | 
|  | { | 
|  | if (szOut) | 
|  | lstrcpynW(szOut, szTemp, uOutSize); | 
|  |  | 
|  | dwReturn = lstrlenW (szTemp); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | ERR("-- no text\n"); | 
|  | } | 
|  | } | 
|  |  | 
|  | TRACE("-- (%p=%s 0x%08x)\n",szOut,debugstr_w(szOut),dwReturn); | 
|  | return dwReturn; | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | * | 
|  | *    ### 4. getting pointers to parts of pidls ### | 
|  | * | 
|  | ************************************************************************** | 
|  | *  _ILGetDataPointer() | 
|  | */ | 
|  | LPPIDLDATA _ILGetDataPointer(LPCITEMIDLIST pidl) | 
|  | { | 
|  | if(!_ILIsEmpty(pidl)) | 
|  | return (LPPIDLDATA)pidl->mkid.abID; | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | *  _ILGetTextPointerW() | 
|  | * gets a pointer to the unicode long filename string stored in the pidl | 
|  | */ | 
|  | static LPWSTR _ILGetTextPointerW(LPCITEMIDLIST pidl) | 
|  | { | 
|  | /* TRACE(pidl,"(pidl%p)\n", pidl);*/ | 
|  |  | 
|  | LPPIDLDATA pdata = _ILGetDataPointer(pidl); | 
|  |  | 
|  | if (!pdata) | 
|  | return NULL; | 
|  |  | 
|  | switch (pdata->type) | 
|  | { | 
|  | case PT_GUID: | 
|  | case PT_SHELLEXT: | 
|  | case PT_YAGUID: | 
|  | return NULL; | 
|  |  | 
|  | case PT_DRIVE: | 
|  | case PT_DRIVE1: | 
|  | case PT_DRIVE2: | 
|  | case PT_DRIVE3: | 
|  | /*return (LPSTR)&(pdata->u.drive.szDriveName);*/ | 
|  | return NULL; | 
|  |  | 
|  | case PT_FOLDER: | 
|  | case PT_FOLDER1: | 
|  | case PT_VALUE: | 
|  | case PT_IESPECIAL1: | 
|  | case PT_IESPECIAL2: | 
|  | /*return (LPSTR)&(pdata->u.file.szNames);*/ | 
|  | return NULL; | 
|  |  | 
|  | case PT_WORKGRP: | 
|  | case PT_COMP: | 
|  | case PT_NETWORK: | 
|  | case PT_NETPROVIDER: | 
|  | case PT_SHARE: | 
|  | /*return (LPSTR)&(pdata->u.network.szNames);*/ | 
|  | return NULL; | 
|  |  | 
|  | case PT_VALUEW: | 
|  | return (LPWSTR)pdata->u.file.szNames; | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  |  | 
|  | /************************************************************************** | 
|  | *  _ILGetTextPointer() | 
|  | * gets a pointer to the long filename string stored in the pidl | 
|  | */ | 
|  | LPSTR _ILGetTextPointer(LPCITEMIDLIST pidl) | 
|  | { | 
|  | /* TRACE(pidl,"(pidl%p)\n", pidl);*/ | 
|  |  | 
|  | LPPIDLDATA pdata = _ILGetDataPointer(pidl); | 
|  |  | 
|  | if (!pdata) | 
|  | return NULL; | 
|  |  | 
|  | switch (pdata->type) | 
|  | { | 
|  | case PT_GUID: | 
|  | case PT_SHELLEXT: | 
|  | case PT_YAGUID: | 
|  | return NULL; | 
|  |  | 
|  | case PT_DRIVE: | 
|  | case PT_DRIVE1: | 
|  | case PT_DRIVE2: | 
|  | case PT_DRIVE3: | 
|  | return pdata->u.drive.szDriveName; | 
|  |  | 
|  | case PT_FOLDER: | 
|  | case PT_FOLDER1: | 
|  | case PT_VALUE: | 
|  | case PT_IESPECIAL1: | 
|  | case PT_IESPECIAL2: | 
|  | return pdata->u.file.szNames; | 
|  |  | 
|  | case PT_WORKGRP: | 
|  | case PT_COMP: | 
|  | case PT_NETWORK: | 
|  | case PT_NETPROVIDER: | 
|  | case PT_SHARE: | 
|  | return pdata->u.network.szNames; | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | *  _ILGetSTextPointer() | 
|  | * gets a pointer to the short filename string stored in the pidl | 
|  | */ | 
|  | static LPSTR _ILGetSTextPointer(LPCITEMIDLIST pidl) | 
|  | { | 
|  | /* TRACE(pidl,"(pidl%p)\n", pidl); */ | 
|  |  | 
|  | LPPIDLDATA pdata =_ILGetDataPointer(pidl); | 
|  |  | 
|  | if (!pdata) | 
|  | return NULL; | 
|  |  | 
|  | switch (pdata->type) | 
|  | { | 
|  | case PT_FOLDER: | 
|  | case PT_VALUE: | 
|  | case PT_IESPECIAL1: | 
|  | case PT_IESPECIAL2: | 
|  | return pdata->u.file.szNames + strlen (pdata->u.file.szNames) + 1; | 
|  |  | 
|  | case PT_WORKGRP: | 
|  | return pdata->u.network.szNames + strlen (pdata->u.network.szNames) + 1; | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | * _ILGetGUIDPointer() | 
|  | * | 
|  | * returns reference to guid stored in some pidls | 
|  | */ | 
|  | IID* _ILGetGUIDPointer(LPCITEMIDLIST pidl) | 
|  | { | 
|  | LPPIDLDATA pdata =_ILGetDataPointer(pidl); | 
|  |  | 
|  | TRACE("%p\n", pidl); | 
|  |  | 
|  | if (!pdata) | 
|  | return NULL; | 
|  |  | 
|  | TRACE("pdata->type 0x%04x\n", pdata->type); | 
|  | switch (pdata->type) | 
|  | { | 
|  | case PT_SHELLEXT: | 
|  | case PT_GUID: | 
|  | case PT_YAGUID: | 
|  | return &(pdata->u.guid.guid); | 
|  |  | 
|  | default: | 
|  | TRACE("Unknown pidl type 0x%04x\n", pdata->type); | 
|  | break; | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | * _ILGetFileStructW [Internal] | 
|  | * | 
|  | * Get pointer the a SHITEMID's FileStructW field if present | 
|  | * | 
|  | * PARAMS | 
|  | *  pidl [I] The SHITEMID | 
|  | * | 
|  | * RETURNS | 
|  | *  Success: Pointer to pidl's FileStructW field. | 
|  | *  Failure: NULL | 
|  | */ | 
|  | FileStructW* _ILGetFileStructW(LPCITEMIDLIST pidl) { | 
|  | FileStructW *pFileStructW; | 
|  | WORD cbOffset; | 
|  |  | 
|  | if (!(_ILIsValue(pidl) || _ILIsFolder(pidl))) | 
|  | return NULL; | 
|  |  | 
|  | cbOffset = *(const WORD *)((const BYTE *)pidl + pidl->mkid.cb - sizeof(WORD)); | 
|  | pFileStructW = (FileStructW*)((LPBYTE)pidl + cbOffset); | 
|  |  | 
|  | /* Currently I don't see a fool prove way to figure out if a pidl is for sure of WinXP | 
|  | * style with a FileStructW member. If we switch all our shellfolder-implementations to | 
|  | * the new format, this won't be a problem. For now, we do as many sanity checks as possible. */ | 
|  | if ((cbOffset & 0x1) || /* FileStructW member is word aligned in the pidl */ | 
|  | /* FileStructW is positioned after FileStruct */ | 
|  | cbOffset < sizeof(pidl->mkid.cb) + sizeof(PIDLTYPE) + sizeof(FileStruct) || | 
|  | /* There has to be enough space at cbOffset in the pidl to hold FileStructW and cbOffset */ | 
|  | cbOffset > pidl->mkid.cb - sizeof(cbOffset) - sizeof(FileStructW) || | 
|  | pidl->mkid.cb != cbOffset + pFileStructW->cbLen) | 
|  | { | 
|  | WARN("Invalid pidl format (cbOffset = %d)!\n", cbOffset); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | return pFileStructW; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * _ILGetFileDateTime | 
|  | * | 
|  | * Given the ItemIdList, get the FileTime | 
|  | * | 
|  | * PARAMS | 
|  | *      pidl        [I] The ItemIDList | 
|  | *      pFt         [I] the resulted FILETIME of the file | 
|  | * | 
|  | * RETURNS | 
|  | *     True if Successful | 
|  | * | 
|  | * NOTES | 
|  | * | 
|  | */ | 
|  | BOOL _ILGetFileDateTime(LPCITEMIDLIST pidl, FILETIME *pFt) | 
|  | { | 
|  | LPPIDLDATA pdata = _ILGetDataPointer(pidl); | 
|  |  | 
|  | if (!pdata) | 
|  | return FALSE; | 
|  |  | 
|  | switch (pdata->type) | 
|  | { | 
|  | case PT_FOLDER: | 
|  | case PT_VALUE: | 
|  | DosDateTimeToFileTime(pdata->u.file.uFileDate, pdata->u.file.uFileTime, pFt); | 
|  | break; | 
|  | default: | 
|  | return FALSE; | 
|  | } | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | BOOL _ILGetFileDate (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) | 
|  | { | 
|  | FILETIME ft,lft; | 
|  | SYSTEMTIME time; | 
|  | BOOL ret; | 
|  |  | 
|  | if (_ILGetFileDateTime( pidl, &ft )) | 
|  | { | 
|  | FileTimeToLocalFileTime(&ft, &lft); | 
|  | FileTimeToSystemTime (&lft, &time); | 
|  |  | 
|  | ret = GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&time, NULL,  pOut, uOutSize); | 
|  | if (ret) | 
|  | { | 
|  | /* Append space + time without seconds */ | 
|  | pOut[ret-1] = ' '; | 
|  | GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &time, NULL, &pOut[ret], uOutSize - ret); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | pOut[0] = '\0'; | 
|  | ret = FALSE; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * _ILGetFileSize | 
|  | * | 
|  | * Given the ItemIdList, get the FileSize | 
|  | * | 
|  | * PARAMS | 
|  | *    pidl     [I] The ItemIDList | 
|  | *    pOut     [I] The buffer to save the result | 
|  | *    uOutsize [I] The size of the buffer | 
|  | * | 
|  | * RETURNS | 
|  | *    The FileSize | 
|  | * | 
|  | * NOTES | 
|  | *    pOut can be null when no string is needed | 
|  | * | 
|  | */ | 
|  | DWORD _ILGetFileSize (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) | 
|  | { | 
|  | LPPIDLDATA pdata = _ILGetDataPointer(pidl); | 
|  | DWORD dwSize; | 
|  |  | 
|  | if (!pdata) | 
|  | return 0; | 
|  |  | 
|  | switch (pdata->type) | 
|  | { | 
|  | case PT_VALUE: | 
|  | dwSize = pdata->u.file.dwFileSize; | 
|  | if (pOut) | 
|  | StrFormatKBSizeA(dwSize, pOut, uOutSize); | 
|  | return dwSize; | 
|  | } | 
|  | if (pOut) | 
|  | *pOut = 0x00; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | BOOL _ILGetExtension (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) | 
|  | { | 
|  | char szTemp[MAX_PATH]; | 
|  | const char * pPoint; | 
|  | LPCITEMIDLIST  pidlTemp=pidl; | 
|  |  | 
|  | TRACE("pidl=%p\n",pidl); | 
|  |  | 
|  | if (!pidl) | 
|  | return FALSE; | 
|  |  | 
|  | pidlTemp = ILFindLastID(pidl); | 
|  |  | 
|  | if (!_ILIsValue(pidlTemp)) | 
|  | return FALSE; | 
|  | if (!_ILSimpleGetText(pidlTemp, szTemp, MAX_PATH)) | 
|  | return FALSE; | 
|  |  | 
|  | pPoint = PathFindExtensionA(szTemp); | 
|  |  | 
|  | if (!*pPoint) | 
|  | return FALSE; | 
|  |  | 
|  | pPoint++; | 
|  | lstrcpynA(pOut, pPoint, uOutSize); | 
|  | TRACE("%s\n",pOut); | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * _ILGetFileType | 
|  | * | 
|  | * Given the ItemIdList, get the file type description | 
|  | * | 
|  | * PARAMS | 
|  | *      pidl        [I] The ItemIDList (simple) | 
|  | *      pOut        [I] The buffer to save the result | 
|  | *      uOutsize    [I] The size of the buffer | 
|  | * | 
|  | * RETURNS | 
|  | *    nothing | 
|  | * | 
|  | * NOTES | 
|  | *    This function copies as much as possible into the buffer. | 
|  | */ | 
|  | void _ILGetFileType(LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) | 
|  | { | 
|  | if(_ILIsValue(pidl)) | 
|  | { | 
|  | char sTemp[64]; | 
|  |  | 
|  | if(uOutSize > 0) | 
|  | pOut[0] = 0; | 
|  | if (_ILGetExtension (pidl, sTemp, 64)) | 
|  | { | 
|  | if (!( HCR_MapTypeToValueA(sTemp, sTemp, 64, TRUE) | 
|  | && HCR_MapTypeToValueA(sTemp, pOut, uOutSize, FALSE ))) | 
|  | { | 
|  | lstrcpynA (pOut, sTemp, uOutSize - 6); | 
|  | strcat (pOut, "-file"); | 
|  | } | 
|  | } | 
|  | } | 
|  | else | 
|  | lstrcpynA(pOut, "Folder", uOutSize); | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * _ILGetFileAttributes | 
|  | * | 
|  | * Given the ItemIdList, get the Attrib string format | 
|  | * | 
|  | * PARAMS | 
|  | *      pidl        [I] The ItemIDList | 
|  | *      pOut        [I] The buffer to save the result | 
|  | *      uOutsize    [I] The size of the Buffer | 
|  | * | 
|  | * RETURNS | 
|  | *     Attributes | 
|  | * | 
|  | * FIXME | 
|  | *  return value 0 in case of error is a valid return value | 
|  | * | 
|  | */ | 
|  | DWORD _ILGetFileAttributes(LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) | 
|  | { | 
|  | LPPIDLDATA pData = _ILGetDataPointer(pidl); | 
|  | WORD wAttrib = 0; | 
|  | int i; | 
|  |  | 
|  | if (!pData) | 
|  | return 0; | 
|  |  | 
|  | switch(pData->type) | 
|  | { | 
|  | case PT_FOLDER: | 
|  | case PT_VALUE: | 
|  | wAttrib = pData->u.file.uFileAttribs; | 
|  | break; | 
|  | } | 
|  |  | 
|  | if(uOutSize >= 6) | 
|  | { | 
|  | i=0; | 
|  | if(wAttrib & FILE_ATTRIBUTE_READONLY) | 
|  | pOut[i++] = 'R'; | 
|  | if(wAttrib & FILE_ATTRIBUTE_HIDDEN) | 
|  | pOut[i++] = 'H'; | 
|  | if(wAttrib & FILE_ATTRIBUTE_SYSTEM) | 
|  | pOut[i++] = 'S'; | 
|  | if(wAttrib & FILE_ATTRIBUTE_ARCHIVE) | 
|  | pOut[i++] = 'A'; | 
|  | if(wAttrib & FILE_ATTRIBUTE_COMPRESSED) | 
|  | pOut[i++] = 'C'; | 
|  | pOut[i] = 0x00; | 
|  | } | 
|  | return wAttrib; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * ILFreeaPidl | 
|  | * | 
|  | * frees an aPidl struct | 
|  | */ | 
|  | void _ILFreeaPidl(LPITEMIDLIST * apidl, UINT cidl) | 
|  | { | 
|  | UINT   i; | 
|  |  | 
|  | if (apidl) | 
|  | { | 
|  | for (i = 0; i < cidl; i++) | 
|  | SHFree(apidl[i]); | 
|  | SHFree(apidl); | 
|  | } | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * ILCopyaPidl | 
|  | * | 
|  | * copies an aPidl struct | 
|  | */ | 
|  | LPITEMIDLIST* _ILCopyaPidl(const LPCITEMIDLIST * apidlsrc, UINT cidl) | 
|  | { | 
|  | UINT i; | 
|  | LPITEMIDLIST *apidldest; | 
|  |  | 
|  | if (!apidlsrc) | 
|  | return NULL; | 
|  |  | 
|  | apidldest = SHAlloc(cidl * sizeof(LPITEMIDLIST)); | 
|  |  | 
|  | for (i = 0; i < cidl; i++) | 
|  | apidldest[i] = ILClone(apidlsrc[i]); | 
|  |  | 
|  | return apidldest; | 
|  | } | 
|  |  | 
|  | /************************************************************************* | 
|  | * _ILCopyCidaToaPidl | 
|  | * | 
|  | * creates aPidl from CIDA | 
|  | */ | 
|  | LPITEMIDLIST* _ILCopyCidaToaPidl(LPITEMIDLIST* pidl, const CIDA * cida) | 
|  | { | 
|  | UINT i; | 
|  | LPITEMIDLIST *dst; | 
|  |  | 
|  | dst = SHAlloc(cida->cidl * sizeof(LPITEMIDLIST)); | 
|  | if (!dst) | 
|  | return NULL; | 
|  |  | 
|  | if (pidl) | 
|  | *pidl = ILClone((LPCITEMIDLIST)(&((const BYTE*)cida)[cida->aoffset[0]])); | 
|  |  | 
|  | for (i = 0; i < cida->cidl; i++) | 
|  | dst[i] = ILClone((LPCITEMIDLIST)(&((const BYTE*)cida)[cida->aoffset[i + 1]])); | 
|  |  | 
|  | return dst; | 
|  | } |