- Move target folder initialization to a dedicated function.
- Use this function in BindToObject (should be faster).
- Special handling for FolderShortcut objects in Initialize method.
- Removed a todo_wine from a no longer failing unit test.
diff --git a/dlls/shell32/shfldr_unixfs.c b/dlls/shell32/shfldr_unixfs.c
index 2288950..7c93f7e 100644
--- a/dlls/shell32/shfldr_unixfs.c
+++ b/dlls/shell32/shfldr_unixfs.c
@@ -190,8 +190,8 @@
const IPersistPropertyBagVtbl *lpIPersistPropertyBagVtbl;
const ISFHelperVtbl *lpISFHelperVtbl;
LONG m_cRef;
- CHAR *m_pszPath;
- LPITEMIDLIST m_pidlLocation;
+ CHAR *m_pszPath; /* Target path of the shell folder */
+ LPITEMIDLIST m_pidlLocation; /* Location in the shell namespace */
DWORD m_dwPathMode;
DWORD m_dwAttributes;
const CLSID *m_pCLSID;
@@ -582,6 +582,71 @@
}
/******************************************************************************
+ * UNIXFS_initialize_target_folder [Internal]
+ *
+ * Initialize the m_pszPath member of an UnixFolder, given an absolute unix
+ * base path and a relative ITEMIDLIST. Leave the m_pidlLocation member, which
+ * specifies the location in the shell namespace alone.
+ *
+ * PARAMS
+ * This [IO] The UnixFolder, whose target path is to be initialized
+ * szBasePath [I] The absolute base path
+ * pidlSubFolder [I] Relative part of the path, given as an ITEMIDLIST
+ * dwAttributes [I] Attributes to add to the Folders m_dwAttributes member
+ * (Used to pass the SFGAO_FILESYSTEM flag down the path)
+ * RETURNS
+ * Success: S_OK,
+ * Failure: E_FAIL
+ */
+static HRESULT UNIXFS_initialize_target_folder(UnixFolder *This, const char *szBasePath,
+ LPCITEMIDLIST pidlSubFolder, DWORD dwAttributes)
+{
+ LPCITEMIDLIST current = pidlSubFolder;
+ DWORD dwPathLen = strlen(szBasePath)+1;
+ struct stat statPrefix;
+ char *pNextDir;
+
+ /* Determine the path's length bytes */
+ while (current && current->mkid.cb) {
+ dwPathLen += NAME_LEN_FROM_LPSHITEMID(current) + 1; /* For the '/' */
+ current = ILGetNext(current);
+ };
+
+ /* Build the path and compute the attributes*/
+ This->m_dwAttributes =
+ dwAttributes|SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|SFGAO_CANRENAME;
+ This->m_pszPath = pNextDir = SHAlloc(dwPathLen);
+ if (!This->m_pszPath) {
+ WARN("SHAlloc failed!\n");
+ return E_FAIL;
+ }
+ current = pidlSubFolder;
+ strcpy(pNextDir, szBasePath);
+ pNextDir += strlen(szBasePath);
+ if (This->m_dwPathMode == PATHMODE_UNIX || IsEqualCLSID(&CLSID_MyDocuments, This->m_pCLSID))
+ This->m_dwAttributes |= SFGAO_FILESYSTEM;
+ if (!(This->m_dwAttributes & SFGAO_FILESYSTEM)) {
+ *pNextDir = '\0';
+ if (!stat(This->m_pszPath, &statPrefix) && UNIXFS_is_dos_device(&statPrefix))
+ This->m_dwAttributes |= SFGAO_FILESYSTEM;
+ }
+ while (current && current->mkid.cb) {
+ memcpy(pNextDir, _ILGetTextPointer(current), NAME_LEN_FROM_LPSHITEMID(current));
+ pNextDir += NAME_LEN_FROM_LPSHITEMID(current);
+ if (!(This->m_dwAttributes & SFGAO_FILESYSTEM)) {
+ *pNextDir = '\0';
+ if (!stat(This->m_pszPath, &statPrefix) && UNIXFS_is_dos_device(&statPrefix))
+ This->m_dwAttributes |= SFGAO_FILESYSTEM;
+ }
+ *pNextDir++ = '/';
+ current = ILGetNext(current);
+ }
+ *pNextDir='\0';
+
+ return S_OK;
+}
+
+/******************************************************************************
* UnixFolder
*
* Class whose heap based instances represent unix filesystem directories.
@@ -707,23 +772,33 @@
UnixFolder *This = ADJUST_THIS(UnixFolder, IShellFolder2, iface);
IPersistFolder3 *persistFolder;
HRESULT hr;
+ const CLSID *clsidChild;
TRACE("(iface=%p, pidl=%p, pbcReserver=%p, riid=%p, ppvOut=%p)\n",
iface, pidl, pbcReserved, riid, ppvOut);
if (!pidl || !pidl->mkid.cb)
return E_INVALIDARG;
-
- hr = CreateUnixFolder(NULL, &IID_IPersistFolder3, (void**)&persistFolder, This->m_pCLSID);
+
+ if (IsEqualCLSID(This->m_pCLSID, &CLSID_FolderShortcut)) {
+ /* Children of FolderShortcuts are ShellFSFolders on Windows.
+ * Unixfs' counterpart is UnixDosFolder. */
+ clsidChild = &CLSID_UnixDosFolder;
+ } else {
+ clsidChild = This->m_pCLSID;
+ }
+
+ hr = CreateUnixFolder(NULL, &IID_IPersistFolder3, (void**)&persistFolder, clsidChild);
if (!SUCCEEDED(hr)) return hr;
hr = IPersistFolder_QueryInterface(persistFolder, riid, (void**)ppvOut);
if (SUCCEEDED(hr)) {
- LPITEMIDLIST pidlSubFolder = ILCombine(This->m_pidlLocation, pidl);
- hr = IPersistFolder3_Initialize(persistFolder, pidlSubFolder);
- ILFree(pidlSubFolder);
- }
-
+ UnixFolder *subfolder = ADJUST_THIS(UnixFolder, IPersistFolder3, persistFolder);
+ subfolder->m_pidlLocation = ILCombine(This->m_pidlLocation, pidl);
+ hr = UNIXFS_initialize_target_folder(subfolder, This->m_pszPath, pidl,
+ This->m_dwAttributes & SFGAO_FILESYSTEM);
+ }
+
IPersistFolder3_Release(persistFolder);
return hr;
@@ -1221,10 +1296,8 @@
static HRESULT WINAPI UnixFolder_IPersistFolder3_Initialize(IPersistFolder3* iface, LPCITEMIDLIST pidl)
{
UnixFolder *This = ADJUST_THIS(UnixFolder, IPersistFolder3, iface);
- struct stat statPrefix;
- LPCITEMIDLIST current = pidl, root;
- DWORD dwPathLen;
- char *pNextDir, szBasePath[FILENAME_MAX] = "/";
+ LPCITEMIDLIST current = pidl;
+ char szBasePath[FILENAME_MAX] = "/";
TRACE("(iface=%p, pidl=%p)\n", iface, pidl);
@@ -1243,11 +1316,8 @@
PathAddBackslashW(wszMyDocumentsPath);
if (!UNIXFS_get_unix_path(wszMyDocumentsPath, szBasePath))
return E_FAIL;
- dwPathLen = strlen(szBasePath) + 1;
- } else {
- dwPathLen = 2; /* For the '/' prefix and the terminating '\0' */
- }
- root = current = ILGetNext(current);
+ }
+ current = ILGetNext(current);
} else if (_ILIsDesktop(pidl) || _ILIsValue(pidl) || _ILIsFolder(pidl)) {
/* Path rooted at Desktop */
WCHAR wszDesktopPath[MAX_PATH];
@@ -1256,52 +1326,21 @@
PathAddBackslashW(wszDesktopPath);
if (!UNIXFS_get_unix_path(wszDesktopPath, szBasePath))
return E_FAIL;
- dwPathLen = strlen(szBasePath) + 1;
- root = current = pidl;
+ current = pidl;
+ } else if (IsEqualCLSID(This->m_pCLSID, &CLSID_FolderShortcut)) {
+ /* FolderShortcuts' Initialize method only sets the ITEMIDLIST, which
+ * specifies the location in the shell namespace, but leaves the
+ * target folder (m_pszPath) alone. See unit tests in tests/shlfolder.c */
+ This->m_pidlLocation = ILClone(pidl);
+ return S_OK;
} else {
ERR("Unknown pidl type!\n");
pdump(pidl);
return E_INVALIDARG;
}
-
- /* Determine the path's length bytes */
- while (current && current->mkid.cb) {
- dwPathLen += NAME_LEN_FROM_LPSHITEMID(current) + 1; /* For the '/' */
- current = ILGetNext(current);
- };
-
- /* Build the path */
- This->m_dwAttributes = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|SFGAO_CANRENAME;
+
This->m_pidlLocation = ILClone(pidl);
- This->m_pszPath = pNextDir = SHAlloc(dwPathLen);
- if (!This->m_pszPath || !This->m_pidlLocation) {
- WARN("SHAlloc failed!\n");
- return E_FAIL;
- }
- current = root;
- strcpy(pNextDir, szBasePath);
- pNextDir += strlen(szBasePath);
- if (This->m_dwPathMode == PATHMODE_UNIX || IsEqualCLSID(&CLSID_MyDocuments, This->m_pCLSID))
- This->m_dwAttributes |= SFGAO_FILESYSTEM;
- if (!(This->m_dwAttributes & SFGAO_FILESYSTEM)) {
- *pNextDir = '\0';
- if (!stat(This->m_pszPath, &statPrefix) && UNIXFS_is_dos_device(&statPrefix))
- This->m_dwAttributes |= SFGAO_FILESYSTEM;
- }
- while (current && current->mkid.cb) {
- memcpy(pNextDir, _ILGetTextPointer(current), NAME_LEN_FROM_LPSHITEMID(current));
- pNextDir += NAME_LEN_FROM_LPSHITEMID(current);
- if (!(This->m_dwAttributes & SFGAO_FILESYSTEM)) {
- *pNextDir = '\0';
- if (!stat(This->m_pszPath, &statPrefix) && UNIXFS_is_dos_device(&statPrefix))
- This->m_dwAttributes |= SFGAO_FILESYSTEM;
- }
- *pNextDir++ = '/';
- current = ILGetNext(current);
- }
- *pNextDir='\0';
-
- return S_OK;
+ return UNIXFS_initialize_target_folder(This, szBasePath, current, 0);
}
static HRESULT WINAPI UnixFolder_IPersistFolder3_GetCurFolder(IPersistFolder3* iface, LPITEMIDLIST* ppidl)
@@ -1336,7 +1375,9 @@
return E_FAIL;
}
} else if (*ppfti->szTargetParsingName) {
- if (!UNIXFS_get_unix_path(ppfti->szTargetParsingName, szTargetPath)) {
+ lstrcpyW(wszTargetDosPath, ppfti->szTargetParsingName);
+ PathAddBackslashW(wszTargetDosPath);
+ if (!UNIXFS_get_unix_path(wszTargetDosPath, szTargetPath)) {
return E_FAIL;
}
} else if (ppfti->pidlTargetFolder) {
diff --git a/dlls/shell32/tests/shlfolder.c b/dlls/shell32/tests/shlfolder.c
index 4605cbb..d4f92b2 100644
--- a/dlls/shell32/tests/shlfolder.c
+++ b/dlls/shell32/tests/shlfolder.c
@@ -876,7 +876,9 @@
':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
-
+ static const GUID CLSID_UnixDosFolder =
+ {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
+
if (!pSHGetSpecialFolderPathW || !pStrRetToBufW) return;
/* These tests basically show, that CLSID_FolderShortcuts are initialized
@@ -945,7 +947,7 @@
if (FAILED(hr)) return;
hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
- todo_wine { ok (SUCCEEDED(hr), "IPersistFolder3::Initialize failed! hr = %08lx\n", hr); }
+ ok (SUCCEEDED(hr), "IPersistFolder3::Initialize failed! hr = %08lx\n", hr);
if (FAILED(hr)) {
IPersistFolder3_Release(pPersistFolder3);
ILFree(pidlWineTestFolder);
@@ -985,7 +987,7 @@
hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL,
&pidlSubFolder, NULL);
- RemoveDirectoryW(wszSomeSubFolder);
+ RemoveDirectoryW(wszDesktopPath);
ok (SUCCEEDED(hr), "IShellFolder::ParseDisplayName failed! hr = %08lx\n", hr);
if (FAILED(hr)) {
IShellFolder_Release(pShellFolder);
@@ -1000,9 +1002,12 @@
if (FAILED(hr))
return;
+ /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
+ * a little bit and also allow CLSID_UnixDosFolder. */
hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
ok(SUCCEEDED(hr), "IPersistFolder3_GetClassID failed! hr=0x%08lx\n", hr);
- ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder), "Unexpected CLSID!\n");
+ ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
+ "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
IPersistFolder3_Release(pPersistFolder3);
}