| /* | |
| * UNIXFS - Shell namespace extension for the unix filesystem | |
| * | |
| * Copyright (C) 2005 Michael Jung | |
| * | |
| * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| */ | |
| #include <stdio.h> | |
| #include <stdarg.h> | |
| #include <dirent.h> | |
| #define COBJMACROS | |
| #define NONAMELESSUNION | |
| #define NONAMELESSSTRUCT | |
| #include "windef.h" | |
| #include "winbase.h" | |
| #include "winuser.h" | |
| #include "objbase.h" | |
| #include "wine/debug.h" | |
| #include "shell32_main.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(shell); | |
| const GUID CLSID_UnixFolder = {0xcc702eb2, 0x7dc5, 0x11d9, {0xc6, 0x87, 0x00, 0x04, 0x23, 0x8a, 0x01, 0xcd}}; | |
| #define ADJUST_THIS(c,m,p) ((c*)(((long)p)-(long)&(((c*)0)->lp##m##Vtbl))) | |
| #define STATIC_CAST(i,p) ((i*)&p->lp##i##Vtbl) | |
| /****************************************************************************** | |
| * UNIXFS_path_to_pidl [Internal] | |
| * | |
| * PARAMS | |
| * path [I] An absolute unix path | |
| * ppidl [O] The corresponding ITEMIDLIST. Release with SHFree/ILFree | |
| * | |
| * RETURNS | |
| * Success: TRUE | |
| * Failure: FALSE, invalid params, path not absolute or out of memory | |
| * | |
| * NOTES | |
| * 'path' has to be an absolute unix filesystem path starting and | |
| * ending with a slash ('/'). Currently, only directories (no files) | |
| * are accepted. | |
| */ | |
| static BOOL UNIXFS_path_to_pidl(char *path, LPITEMIDLIST *ppidl) { | |
| LPITEMIDLIST pidl; | |
| int cSubDirs, cPidlLen; | |
| char *pSlash, *pSubDir; | |
| /* Fail, if no absolute path given */ | |
| if (!ppidl || !path || path[0] != '/') return FALSE; | |
| /* Count the number of sub-directories in the path */ | |
| cSubDirs = 0; | |
| pSlash = strchr(path, '/'); | |
| while (pSlash) { | |
| cSubDirs++; | |
| pSlash = strchr(pSlash+1, '/'); | |
| } | |
| /* Allocate enough memory to hold the path */ | |
| cPidlLen = strlen(path) + cSubDirs * sizeof(USHORT) + sizeof(USHORT); | |
| *ppidl = pidl = (LPITEMIDLIST)SHAlloc(cPidlLen); | |
| if (!pidl) return FALSE; | |
| /* Start with a SHITEMID for the root directory */ | |
| pidl->mkid.cb = 3; | |
| pidl->mkid.abID[0] = '/'; | |
| pidl = ILGetNext(pidl); | |
| /* Append SHITEMIDs for the sub-directories */ | |
| pSubDir = path + 1; | |
| pSlash = strchr(pSubDir, '/'); | |
| while (pSlash) { | |
| pidl->mkid.cb = (USHORT)(pSlash+3-pSubDir); | |
| memcpy(pidl->mkid.abID, pSubDir, pidl->mkid.cb); | |
| pSubDir = pSlash + 1; | |
| pSlash = strchr(pSubDir, '/'); | |
| pidl = ILGetNext(pidl); | |
| } | |
| pidl->mkid.cb = 0; /* Terminate the ITEMIDLIST */ | |
| /* Path doesn't end with a '/' */ | |
| if (*pSubDir) | |
| WARN("Path '%s' not in canonical form.\n", path); | |
| return TRUE; | |
| } | |
| /****************************************************************************** | |
| * UNIXFS_pidl_to_path [Internal] | |
| * | |
| * Construct the unix path that corresponds to a fully qualified ITEMIDLIST | |
| * | |
| * PARAMS | |
| * pidl [I] ITEMIDLIST that specifies the absolute location of the folder | |
| * path [O] The corresponding unix path as a zero terminated ascii string | |
| * | |
| * RETURNS | |
| * Success: TRUE | |
| * Failure: FALSE, pidl doesn't specify a unix path or out of memory | |
| */ | |
| static BOOL UNIXFS_pidl_to_path(LPCITEMIDLIST pidl, PSZ *path) { | |
| LPCITEMIDLIST current = pidl, root; | |
| DWORD dwPathLen; | |
| char *pNextDir; | |
| *path = NULL; | |
| /* Find the UnixFolderClass root */ | |
| while (current->mkid.cb) { | |
| if (current->mkid.cb < sizeof(GUID)+4) return FALSE; | |
| if (IsEqualIID(&CLSID_UnixFolder, ¤t->mkid.abID[2])) break; | |
| current = ILGetNext(current); | |
| } | |
| if (!current->mkid.cb) return FALSE; | |
| root = ILGetNext(current); | |
| /* Determine the path's length bytes */ | |
| dwPathLen = 1; /* For the terminating '\0' */ | |
| current = root; | |
| while (current->mkid.cb) { | |
| dwPathLen += current->mkid.cb - sizeof(USHORT); | |
| current = ILGetNext(current); | |
| }; | |
| /* Build the path */ | |
| *path = pNextDir = SHAlloc(dwPathLen); | |
| if (!path) { | |
| WARN("SHAlloc failed!\n"); | |
| return FALSE; | |
| } | |
| current = root; | |
| while (current->mkid.cb) { | |
| memcpy(pNextDir, current->mkid.abID, current->mkid.cb - sizeof(USHORT)); | |
| pNextDir += current->mkid.cb - sizeof(USHORT); | |
| current = ILGetNext(current); | |
| } | |
| *pNextDir='\0'; | |
| TRACE("resulting path: %s\n", *path); | |
| return TRUE; | |
| } | |
| /****************************************************************************** | |
| * UNIXFS_build_subfolder_pidls [Internal] | |
| * | |
| * Builds an array of subfolder PIDLs relativ to an unix directory | |
| * | |
| * PARAMS | |
| * path [I] Name of an unix directory as an zero terminated ascii string | |
| * apidl [O] The array of PIDLs | |
| * pCount [O] Size of apidl | |
| * | |
| * RETURNS | |
| * Success: TRUE | |
| * Failure: FALSE, path is not a valid unix directory or out of memory | |
| * | |
| * NOTES | |
| * The array of PIDLs and each PIDL are allocated with SHAlloc. You'll have | |
| * to release each PIDL as well as the array itself with SHFree. | |
| */ | |
| static BOOL UNIXFS_build_subfolder_pidls(const char *path, LPITEMIDLIST **apidl, DWORD *pCount) | |
| { | |
| DIR *dir; | |
| struct dirent *pSubDir; | |
| DWORD cSubDirs, i; | |
| USHORT sLen; | |
| *apidl = NULL; | |
| *pCount = 0; | |
| /* Special case for 'My UNIX Filesystem' shell folder: | |
| * The unix root directory is the only child of 'My UNIX Filesystem'. | |
| */ | |
| if (!strlen(path)) { | |
| LPSHITEMID pid; | |
| pid = (LPSHITEMID)SHAlloc(1 + 2 * sizeof(USHORT)); | |
| pid->cb = 3; | |
| pid->abID[0] = '/'; | |
| memset(((PBYTE)pid)+pid->cb, 0, sizeof(USHORT)); | |
| *apidl = SHAlloc(sizeof(LPITEMIDLIST)); | |
| (*apidl)[0] = (LPITEMIDLIST)pid; | |
| *pCount = 1; | |
| return TRUE; | |
| } | |
| dir = opendir(path); | |
| if (!dir) { | |
| WARN("Failed to open directory '%s'.\n", path); | |
| return FALSE; | |
| } | |
| /* Count number of sub directories. | |
| */ | |
| for (cSubDirs = 0, pSubDir = readdir(dir); pSubDir; pSubDir = readdir(dir)) { | |
| if (strcmp(pSubDir->d_name, ".") && | |
| strcmp(pSubDir->d_name, "..") && | |
| pSubDir->d_type == DT_DIR) | |
| { | |
| cSubDirs++; | |
| } | |
| } | |
| /* If there are no subdirectories, we are done. */ | |
| if (cSubDirs == 0) { | |
| closedir(dir); | |
| return TRUE; | |
| } | |
| /* Allocate the array of PIDLs */ | |
| *apidl = SHAlloc(cSubDirs * sizeof(LPITEMIDLIST)); | |
| if (!apidl) { | |
| WARN("SHAlloc failed!\n"); | |
| return FALSE; | |
| } | |
| /* Allocate and initialize one SHITEMID per sub-directory. */ | |
| for (rewinddir(dir), pSubDir = readdir(dir), i = 0; pSubDir; pSubDir = readdir(dir)) { | |
| LPSHITEMID pid; | |
| if (!strcmp(pSubDir->d_name, ".") || | |
| !strcmp(pSubDir->d_name, "..") || | |
| pSubDir->d_type != DT_DIR) | |
| { | |
| continue; | |
| } | |
| sLen = strlen(pSubDir->d_name)+1; /* For the trailing '/' */ | |
| pid = (LPSHITEMID)SHAlloc(sLen + 2 * sizeof(USHORT)); | |
| if (!pid) { | |
| WARN("SHAlloc failed!\n"); | |
| return FALSE; | |
| } | |
| pid->cb = (USHORT)(sLen + sizeof(USHORT)); | |
| memcpy(pid->abID, pSubDir->d_name, sLen-1); | |
| pid->abID[sLen-1] = '/'; | |
| memset(((PBYTE)pid)+pid->cb, 0, sizeof(USHORT)); | |
| (*apidl)[i++] = (LPITEMIDLIST)pid; | |
| } | |
| *pCount = i; | |
| closedir(dir); | |
| return TRUE; | |
| } | |
| /****************************************************************************** | |
| * UnixFolderIcon | |
| * | |
| * Singleton class, which is used by the shell to extract icons to represent | |
| * folders in tree- and listviews. Currently, all this singleton does is to | |
| * provide the shell with the absolute path to "shell32.dll" and with the | |
| * indices of the closed and opened folder icons in the resources of this dll. | |
| */ | |
| /* UnixFolderIcon object layout and typedef. | |
| */ | |
| typedef struct _UnixFolderIcon { | |
| const IExtractIconWVtbl *lpIExtractIconWVtbl; | |
| } UnixFolderIcon; | |
| static HRESULT WINAPI UnixFolderIcon_IExtractIconW_QueryInterface(IExtractIconW *iface, REFIID riid, | |
| void **ppv) | |
| { | |
| TRACE("(iface=%p, riid=%p, ppv=%p)\n", iface, riid, ppv); | |
| if (!ppv) return E_INVALIDARG; | |
| if (IsEqualIID(&IID_IUnknown, riid) || | |
| IsEqualIID(&IID_IExtractIconW, riid)) | |
| { | |
| *ppv = iface; | |
| } else { | |
| *ppv = NULL; | |
| return E_NOINTERFACE; | |
| } | |
| IExtractIconW_AddRef(iface); | |
| return S_OK; | |
| } | |
| static ULONG WINAPI UnixFolderIcon_IExtractIconW_AddRef(IExtractIconW *iface) { | |
| TRACE("(iface=%p)\n", iface); | |
| return 2; | |
| } | |
| static ULONG WINAPI UnixFolderIcon_IExtractIconW_Release(IExtractIconW *iface) { | |
| TRACE("(iface=%p)\n", iface); | |
| return 1; | |
| } | |
| static HRESULT WINAPI UnixFolderIcon_IExtractIconW_GetIconLocation(IExtractIconW *iface, | |
| UINT uFlags, LPWSTR szIconFile, UINT cchMax, INT* piIndex, UINT* pwFlags) | |
| { | |
| TRACE("(iface=%p, uFlags=%u, szIconFile=%s, cchMax=%u, piIndex=%p, pwFlags=%p)\n", | |
| iface, uFlags, debugstr_w(szIconFile), cchMax, piIndex, pwFlags); | |
| lstrcpynW(szIconFile, swShell32Name, cchMax); | |
| *piIndex = (uFlags & GIL_OPENICON) ? 4 : 3; | |
| *pwFlags = 0; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI UnixFolderIcon_IExtractIconW_Extract( | |
| IExtractIconW *iface, LPCWSTR pszFile, UINT nIconIndex, HICON* phiconLarge, HICON* phiconSmall, | |
| UINT nIconSize) | |
| { | |
| TRACE("(iface=%p, pszFile=%s, nIconIndex=%u, phiconLarge=%p, phiconSmall=%p, nIconSize=%u)" | |
| "stub\n", iface, debugstr_w(pszFile), nIconIndex, phiconLarge, phiconSmall, nIconSize); | |
| return E_NOTIMPL; | |
| } | |
| /* VTable for the IExtractIconW interface of the UnixFolderIcon class. | |
| */ | |
| static const IExtractIconWVtbl UnixFolderIcon_IExtractIconW_Vtbl = { | |
| UnixFolderIcon_IExtractIconW_QueryInterface, | |
| UnixFolderIcon_IExtractIconW_AddRef, | |
| UnixFolderIcon_IExtractIconW_Release, | |
| UnixFolderIcon_IExtractIconW_GetIconLocation, | |
| UnixFolderIcon_IExtractIconW_Extract | |
| }; | |
| /* The singleton instance | |
| */ | |
| UnixFolderIcon UnixFolderIconSingleton = { &UnixFolderIcon_IExtractIconW_Vtbl }; | |
| /****************************************************************************** | |
| * UnixFolder | |
| * | |
| * Class whose heap based instances represent unix filesystem directories. | |
| */ | |
| /* UnixFolder object layout and typedef. | |
| */ | |
| typedef struct _UnixFolder { | |
| const IShellFolderVtbl *lpIShellFolderVtbl; | |
| const IPersistFolderVtbl *lpIPersistFolderVtbl; | |
| ULONG m_cRef; | |
| CHAR *m_pszPath; | |
| LPITEMIDLIST m_pidlLocation; | |
| LPITEMIDLIST *m_apidlSubDirs; | |
| DWORD m_cSubDirs; | |
| } UnixFolder; | |
| static void UnixFolder_Destroy(UnixFolder *pUnixFolder) { | |
| DWORD i; | |
| TRACE("(pUnixFolder=%p)\n", pUnixFolder); | |
| if (pUnixFolder->m_apidlSubDirs) | |
| for (i=0; i < pUnixFolder->m_cSubDirs; i++) | |
| SHFree(pUnixFolder->m_apidlSubDirs[i]); | |
| SHFree(pUnixFolder->m_apidlSubDirs); | |
| SHFree(pUnixFolder->m_pszPath); | |
| ILFree(pUnixFolder->m_pidlLocation); | |
| SHFree(pUnixFolder); | |
| } | |
| static HRESULT WINAPI UnixFolder_IShellFolder_QueryInterface(IShellFolder *iface, REFIID riid, | |
| void **ppv) | |
| { | |
| UnixFolder *This = ADJUST_THIS(UnixFolder, IShellFolder, iface); | |
| TRACE("(iface=%p, riid=%p, ppv=%p)\n", iface, riid, ppv); | |
| if (!ppv) return E_INVALIDARG; | |
| if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IShellFolder, riid)) { | |
| *ppv = &This->lpIShellFolderVtbl; | |
| } else if (IsEqualIID(&IID_IPersistFolder, riid) || IsEqualIID(&IID_IPersist, riid)) { | |
| *ppv = &This->lpIPersistFolderVtbl; | |
| } else { | |
| *ppv = NULL; | |
| return E_NOINTERFACE; | |
| } | |
| IUnknown_AddRef((IUnknown*)*ppv); | |
| return S_OK; | |
| } | |
| static ULONG WINAPI UnixFolder_IShellFolder_AddRef(IShellFolder *iface) { | |
| UnixFolder *This = ADJUST_THIS(UnixFolder, IShellFolder, iface); | |
| TRACE("(iface=%p)\n", iface); | |
| return InterlockedIncrement(&This->m_cRef); | |
| } | |
| static ULONG WINAPI UnixFolder_IShellFolder_Release(IShellFolder *iface) { | |
| UnixFolder *This = ADJUST_THIS(UnixFolder, IShellFolder, iface); | |
| ULONG cRef; | |
| TRACE("(iface=%p)\n", iface); | |
| cRef = InterlockedDecrement(&This->m_cRef); | |
| if (!cRef) | |
| UnixFolder_Destroy(This); | |
| return cRef; | |
| } | |
| static HRESULT WINAPI UnixFolder_IShellFolder_ParseDisplayName(IShellFolder* iface, HWND hwndOwner, | |
| LPBC pbcReserved, LPOLESTR lpszDisplayName, ULONG* pchEaten, LPITEMIDLIST* ppidl, | |
| ULONG* pdwAttributes) | |
| { | |
| int cPathLen; | |
| char *pszAnsiPath; | |
| BOOL result; | |
| TRACE("(iface=%p, hwndOwner=%p, pbcReserved=%p, lpszDisplayName=%s, pchEaten=%p, ppidl=%p, " | |
| "pdwAttributes=%p) stub\n", iface, hwndOwner, pbcReserved, debugstr_w(lpszDisplayName), | |
| pchEaten, ppidl, pdwAttributes); | |
| cPathLen = lstrlenW(lpszDisplayName); | |
| pszAnsiPath = (char*)SHAlloc(cPathLen+1); | |
| WideCharToMultiByte(CP_ACP, 0, lpszDisplayName, -1, pszAnsiPath, cPathLen+1, NULL, NULL); | |
| result = UNIXFS_path_to_pidl(pszAnsiPath, ppidl); | |
| SHFree(pszAnsiPath); | |
| return result ? S_OK : E_FAIL; | |
| } | |
| static IUnknown *UnixSubFolderIterator_Construct(UnixFolder *pUnixFolder); | |
| static HRESULT WINAPI UnixFolder_IShellFolder_EnumObjects(IShellFolder* iface, HWND hwndOwner, | |
| SHCONTF grfFlags, IEnumIDList** ppEnumIDList) | |
| { | |
| UnixFolder *This = ADJUST_THIS(UnixFolder, IShellFolder, iface); | |
| IUnknown *newIterator; | |
| HRESULT hr; | |
| TRACE("(iface=%p, hwndOwner=%p, grfFlags=%08lx, ppEnumIDList=%p)\n", | |
| iface, hwndOwner, grfFlags, ppEnumIDList); | |
| newIterator = UnixSubFolderIterator_Construct(This); | |
| hr = IUnknown_QueryInterface(newIterator, &IID_IEnumIDList, (void**)ppEnumIDList); | |
| IUnknown_Release(newIterator); | |
| return hr; | |
| } | |
| static HRESULT WINAPI UnixFolder_IShellFolder_BindToObject(IShellFolder* iface, LPCITEMIDLIST pidl, | |
| LPBC pbcReserved, REFIID riid, void** ppvOut) | |
| { | |
| UnixFolder *This = ADJUST_THIS(UnixFolder, IShellFolder, iface); | |
| IPersistFolder *persistFolder; | |
| LPITEMIDLIST pidlSubFolder; | |
| HRESULT hr; | |
| TRACE("(iface=%p, pidl=%p, pbcReserver=%p, riid=%p, ppvOut=%p)\n", | |
| iface, pidl, pbcReserved, riid, ppvOut); | |
| hr = UnixFolder_Constructor(NULL, &IID_IPersistFolder, (void**)&persistFolder); | |
| if (!SUCCEEDED(hr)) return hr; | |
| hr = IPersistFolder_QueryInterface(persistFolder, riid, (void**)ppvOut); | |
| pidlSubFolder = ILCombine(This->m_pidlLocation, pidl); | |
| IPersistFolder_Initialize(persistFolder, pidlSubFolder); | |
| IPersistFolder_Release(persistFolder); | |
| ILFree(pidlSubFolder); | |
| return hr; | |
| } | |
| static HRESULT WINAPI UnixFolder_IShellFolder_BindToStorage(IShellFolder* This, LPCITEMIDLIST pidl, | |
| LPBC pbcReserved, REFIID riid, void** ppvObj) | |
| { | |
| TRACE("stub\n"); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI UnixFolder_IShellFolder_CompareIDs(IShellFolder* This, LPARAM lParam, | |
| LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) | |
| { | |
| TRACE("stub\n"); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI UnixFolder_IShellFolder_CreateViewObject(IShellFolder* This, HWND hwndOwner, | |
| REFIID riid, void** ppvOut) | |
| { | |
| TRACE("stub\n"); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI UnixFolder_IShellFolder_GetAttributesOf(IShellFolder* iface, UINT cidl, | |
| LPCITEMIDLIST* apidl, SFGAOF* rgfInOut) | |
| { | |
| TRACE("(iface=%p, cidl=%u, apidl=%p, rgfInOut=%p) semi-stub\n", iface, cidl, apidl, rgfInOut); | |
| *rgfInOut = *rgfInOut & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER); | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI UnixFolder_IShellFolder_GetUIObjectOf(IShellFolder* iface, HWND hwndOwner, | |
| UINT cidl, LPCITEMIDLIST* apidl, REFIID riid, UINT* prgfInOut, void** ppvOut) | |
| { | |
| TRACE("(iface=%p, hwndOwner=%p, cidl=%d, apidl=%p, riid=%s, prgfInOut=%p, ppv=%p)\n", | |
| iface, hwndOwner, cidl, apidl, debugstr_guid(riid), prgfInOut, ppvOut); | |
| if (IsEqualIID(&IID_IExtractIconW, riid)) { | |
| *ppvOut = &UnixFolderIconSingleton; | |
| return S_OK; | |
| } | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI UnixFolder_IShellFolder_GetDisplayNameOf(IShellFolder* iface, | |
| LPCITEMIDLIST pidl, SHGDNF uFlags, STRRET* lpName) | |
| { | |
| LPCSHITEMID pSHItem = (LPCSHITEMID)pidl; | |
| char szName[MAX_PATH]; | |
| lpName->uType = STRRET_CSTR; | |
| if (!pidl->mkid.cb) { | |
| strcpy(lpName->u.cStr, ""); | |
| return S_OK; | |
| } | |
| memcpy(szName, pSHItem->abID, pSHItem->cb-sizeof(USHORT)); | |
| szName[pSHItem->cb-sizeof(USHORT)] = '\0'; | |
| TRACE("(iface=%p, pidl=%p, uFlags=%lx, lpName=%p)\n", iface, pidl, uFlags, lpName); | |
| if ((uFlags & SHGDN_FORPARSING) && !(uFlags & SHGDN_INFOLDER)) { | |
| STRRET strSubfolderName; | |
| IShellFolder *pSubFolder; | |
| HRESULT hr; | |
| LPITEMIDLIST pidlFirst; | |
| pidlFirst = ILCloneFirst(pidl); | |
| if (!pidlFirst) { | |
| WARN("ILCloneFirst failed!\n"); | |
| return E_FAIL; | |
| } | |
| hr = IShellFolder_BindToObject(iface, pidlFirst, NULL, &IID_IShellFolder, | |
| (void**)&pSubFolder); | |
| if (!SUCCEEDED(hr)) { | |
| WARN("BindToObject failed!\n"); | |
| ILFree(pidlFirst); | |
| return hr; | |
| } | |
| ILFree(pidlFirst); | |
| hr = IShellFolder_GetDisplayNameOf(pSubFolder, ILGetNext(pidl), uFlags, &strSubfolderName); | |
| if (!SUCCEEDED(hr)) { | |
| WARN("GetDisplayNameOf failed!\n"); | |
| return hr; | |
| } | |
| snprintf(lpName->u.cStr, MAX_PATH, "%s%s", szName, strSubfolderName.u.cStr); | |
| IShellFolder_Release(pSubFolder); | |
| } else { | |
| size_t len; | |
| strcpy(lpName->u.cStr, szName); | |
| len = strlen(lpName->u.cStr); | |
| if (len > 1) lpName->u.cStr[len-1] = '\0'; | |
| } | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI UnixFolder_IShellFolder_SetNameOf(IShellFolder* This, HWND hwnd, | |
| LPCITEMIDLIST pidl, LPCOLESTR lpszName, SHGDNF uFlags, LPITEMIDLIST* ppidlOut) | |
| { | |
| TRACE("stub\n"); | |
| return E_NOTIMPL; | |
| } | |
| /* VTable for UnixFolder's IShellFolder interface. | |
| */ | |
| static const IShellFolderVtbl UnixFolder_IShellFolder_Vtbl = { | |
| UnixFolder_IShellFolder_QueryInterface, | |
| UnixFolder_IShellFolder_AddRef, | |
| UnixFolder_IShellFolder_Release, | |
| UnixFolder_IShellFolder_ParseDisplayName, | |
| UnixFolder_IShellFolder_EnumObjects, | |
| UnixFolder_IShellFolder_BindToObject, | |
| UnixFolder_IShellFolder_BindToStorage, | |
| UnixFolder_IShellFolder_CompareIDs, | |
| UnixFolder_IShellFolder_CreateViewObject, | |
| UnixFolder_IShellFolder_GetAttributesOf, | |
| UnixFolder_IShellFolder_GetUIObjectOf, | |
| UnixFolder_IShellFolder_GetDisplayNameOf, | |
| UnixFolder_IShellFolder_SetNameOf | |
| }; | |
| static HRESULT WINAPI UnixFolder_IPersistFolder_QueryInterface(IPersistFolder* This, REFIID riid, | |
| void** ppvObject) | |
| { | |
| return UnixFolder_IShellFolder_QueryInterface( | |
| (IShellFolder*)ADJUST_THIS(UnixFolder, IPersistFolder, This), riid, ppvObject); | |
| } | |
| static ULONG WINAPI UnixFolder_IPersistFolder_AddRef(IPersistFolder* This) | |
| { | |
| return UnixFolder_IShellFolder_AddRef( | |
| (IShellFolder*)ADJUST_THIS(UnixFolder, IPersistFolder, This)); | |
| } | |
| static ULONG WINAPI UnixFolder_IPersistFolder_Release(IPersistFolder* This) | |
| { | |
| return UnixFolder_IShellFolder_Release( | |
| (IShellFolder*)ADJUST_THIS(UnixFolder, IPersistFolder, This)); | |
| } | |
| static HRESULT WINAPI UnixFolder_IPersistFolder_GetClassID(IPersistFolder* This, CLSID* pClassID) | |
| { | |
| TRACE("stub\n"); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI UnixFolder_IPersistFolder_Initialize(IPersistFolder* iface, LPCITEMIDLIST pidl) | |
| { | |
| UnixFolder *This = ADJUST_THIS(UnixFolder, IPersistFolder, iface); | |
| TRACE("(iface=%p, pidl=%p)\n", iface, pidl); | |
| This->m_pidlLocation = ILClone(pidl); | |
| UNIXFS_pidl_to_path(pidl, &This->m_pszPath); | |
| UNIXFS_build_subfolder_pidls(This->m_pszPath, &This->m_apidlSubDirs, &This->m_cSubDirs); | |
| return S_OK; | |
| } | |
| /* VTable for UnixFolder's IPersistFolder interface. | |
| */ | |
| static const IPersistFolderVtbl UnixFolder_IPersistFolder_Vtbl = { | |
| UnixFolder_IPersistFolder_QueryInterface, | |
| UnixFolder_IPersistFolder_AddRef, | |
| UnixFolder_IPersistFolder_Release, | |
| UnixFolder_IPersistFolder_GetClassID, | |
| UnixFolder_IPersistFolder_Initialize | |
| }; | |
| /****************************************************************************** | |
| * UnixFolder_Constructor [Internal] | |
| * | |
| * PARAMS | |
| * pUnkOuter [I] Outer class for aggregation. Currently ignored. | |
| * riid [I] Interface asked for by the client. | |
| * ppv [O] Pointer to an riid interface to the UnixFolder object. | |
| * | |
| * NOTES | |
| * This is the only function exported from shfldr_unixfs.c. It's called from | |
| * shellole.c's default class factory and thus has to exhibit a LPFNCREATEINSTANCE | |
| * compatible signature. | |
| */ | |
| HRESULT WINAPI UnixFolder_Constructor(IUnknown *pUnkOuter, REFIID riid, LPVOID *ppv) { | |
| HRESULT hr; | |
| UnixFolder *pUnixFolder; | |
| TRACE("(pUnkOuter=%p, riid=%p, ppv=%p)\n", pUnkOuter, riid, ppv); | |
| pUnixFolder = SHAlloc((ULONG)sizeof(UnixFolder)); | |
| pUnixFolder->lpIShellFolderVtbl = &UnixFolder_IShellFolder_Vtbl; | |
| pUnixFolder->lpIPersistFolderVtbl = &UnixFolder_IPersistFolder_Vtbl; | |
| pUnixFolder->m_cRef = 0; | |
| pUnixFolder->m_pszPath = NULL; | |
| pUnixFolder->m_apidlSubDirs = NULL; | |
| pUnixFolder->m_cSubDirs = 0; | |
| UnixFolder_IShellFolder_AddRef(STATIC_CAST(IShellFolder, pUnixFolder)); | |
| hr = UnixFolder_IShellFolder_QueryInterface(STATIC_CAST(IShellFolder, pUnixFolder), riid, ppv); | |
| UnixFolder_IShellFolder_Release(STATIC_CAST(IShellFolder, pUnixFolder)); | |
| return hr; | |
| } | |
| /****************************************************************************** | |
| * UnixSubFolderIterator | |
| * | |
| * Class whose heap based objects represent iterators over the sub-directories | |
| * of a given UnixFolder object. | |
| */ | |
| /* UnixSubFolderIterator object layout and typedef. | |
| */ | |
| typedef struct _UnixSubFolderIterator { | |
| const IEnumIDListVtbl *lpIEnumIDListVtbl; | |
| ULONG m_cRef; | |
| UnixFolder *m_pUnixFolder; | |
| ULONG m_cIdx; | |
| } UnixSubFolderIterator; | |
| static void UnixSubFolderIterator_Destroy(UnixSubFolderIterator *iterator) { | |
| TRACE("(iterator=%p)\n", iterator); | |
| UnixFolder_IShellFolder_Release((IShellFolder*)iterator->m_pUnixFolder); | |
| SHFree(iterator); | |
| } | |
| static HRESULT WINAPI UnixSubFolderIterator_IEnumIDList_QueryInterface(IEnumIDList* iface, | |
| REFIID riid, void** ppv) | |
| { | |
| TRACE("(iface=%p, riid=%p, ppv=%p)\n", iface, riid, ppv); | |
| if (!ppv) return E_INVALIDARG; | |
| if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IEnumIDList, riid)) { | |
| *ppv = iface; | |
| } else { | |
| *ppv = NULL; | |
| return E_NOINTERFACE; | |
| } | |
| IEnumIDList_AddRef(iface); | |
| return S_OK; | |
| } | |
| static ULONG WINAPI UnixSubFolderIterator_IEnumIDList_AddRef(IEnumIDList* iface) | |
| { | |
| UnixSubFolderIterator *This = ADJUST_THIS(UnixSubFolderIterator, IEnumIDList, iface); | |
| TRACE("(iface=%p)\n", iface); | |
| return InterlockedIncrement(&This->m_cRef); | |
| } | |
| static ULONG WINAPI UnixSubFolderIterator_IEnumIDList_Release(IEnumIDList* iface) | |
| { | |
| UnixSubFolderIterator *This = ADJUST_THIS(UnixSubFolderIterator, IEnumIDList, iface); | |
| ULONG cRef; | |
| TRACE("(iface=%p)\n", iface); | |
| cRef = InterlockedDecrement(&This->m_cRef); | |
| if (!cRef) | |
| UnixSubFolderIterator_Destroy(This); | |
| return cRef; | |
| } | |
| static HRESULT WINAPI UnixSubFolderIterator_IEnumIDList_Next(IEnumIDList* iface, ULONG celt, | |
| LPITEMIDLIST* rgelt, ULONG* pceltFetched) | |
| { | |
| UnixSubFolderIterator *This = ADJUST_THIS(UnixSubFolderIterator, IEnumIDList, iface); | |
| ULONG i; | |
| TRACE("(iface=%p, celt=%ld, rgelt=%p, pceltFetched=%p)\n", iface, celt, rgelt, pceltFetched); | |
| for (i=0; (i < celt) && (This->m_cIdx < This->m_pUnixFolder->m_cSubDirs); i++, This->m_cIdx++) { | |
| rgelt[i] = ILClone(This->m_pUnixFolder->m_apidlSubDirs[This->m_cIdx]); | |
| } | |
| if (pceltFetched) | |
| *pceltFetched = i; | |
| return i == celt ? S_OK : S_FALSE; | |
| } | |
| static HRESULT WINAPI UnixSubFolderIterator_IEnumIDList_Skip(IEnumIDList* iface, ULONG celt) | |
| { | |
| UnixSubFolderIterator *This = ADJUST_THIS(UnixSubFolderIterator, IEnumIDList, iface); | |
| TRACE("(iface=%p, celt=%ld)\n", iface, celt); | |
| if (This->m_cIdx + celt > This->m_pUnixFolder->m_cSubDirs) { | |
| This->m_cIdx = This->m_pUnixFolder->m_cSubDirs; | |
| return S_FALSE; | |
| } else { | |
| This->m_cIdx += celt; | |
| return S_OK; | |
| } | |
| } | |
| static HRESULT WINAPI UnixSubFolderIterator_IEnumIDList_Reset(IEnumIDList* iface) | |
| { | |
| UnixSubFolderIterator *This = ADJUST_THIS(UnixSubFolderIterator, IEnumIDList, iface); | |
| TRACE("(iface=%p)\n", iface); | |
| This->m_cIdx = 0; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI UnixSubFolderIterator_IEnumIDList_Clone(IEnumIDList* This, | |
| IEnumIDList** ppenum) | |
| { | |
| TRACE("stub\n"); | |
| return E_NOTIMPL; | |
| } | |
| /* VTable for UnixSubFolderIterator's IEnumIDList interface. | |
| */ | |
| static const IEnumIDListVtbl UnixSubFolderIterator_IEnumIDList_Vtbl = { | |
| UnixSubFolderIterator_IEnumIDList_QueryInterface, | |
| UnixSubFolderIterator_IEnumIDList_AddRef, | |
| UnixSubFolderIterator_IEnumIDList_Release, | |
| UnixSubFolderIterator_IEnumIDList_Next, | |
| UnixSubFolderIterator_IEnumIDList_Skip, | |
| UnixSubFolderIterator_IEnumIDList_Reset, | |
| UnixSubFolderIterator_IEnumIDList_Clone | |
| }; | |
| static IUnknown *UnixSubFolderIterator_Construct(UnixFolder *pUnixFolder) { | |
| UnixSubFolderIterator *iterator; | |
| TRACE("(pUnixFolder=%p)\n", pUnixFolder); | |
| iterator = SHAlloc((ULONG)sizeof(UnixSubFolderIterator)); | |
| iterator->lpIEnumIDListVtbl = &UnixSubFolderIterator_IEnumIDList_Vtbl; | |
| iterator->m_cRef = 0; | |
| iterator->m_cIdx = 0; | |
| iterator->m_pUnixFolder = pUnixFolder; | |
| UnixSubFolderIterator_IEnumIDList_AddRef((IEnumIDList*)iterator); | |
| UnixFolder_IShellFolder_AddRef((IShellFolder*)pUnixFolder); | |
| return (IUnknown*)iterator; | |
| } |