From: Francis De Brabandere <francisdb@gmail.com> Return a new IFolder for the parent directory of This->path, reusing the existing get_parent_folder_name() helper. Return a NULL IFolder (Nothing in VBScript) for root paths. This fixes VBScript expressions such as `folder.ParentFolder & "\sub"` that previously failed with error 445 ("Object doesn't support this action") because the getter was a stub returning E_NOTIMPL. --- dlls/scrrun/filesystem.c | 26 ++++++++++++++++++-- dlls/scrrun/tests/filesystem.c | 45 ++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/dlls/scrrun/filesystem.c b/dlls/scrrun/filesystem.c index 6af73acbd79..184a562ae16 100644 --- a/dlls/scrrun/filesystem.c +++ b/dlls/scrrun/filesystem.c @@ -198,6 +198,7 @@ static HRESULT create_file(BSTR, IFile**); static HRESULT create_foldercoll_enum(struct foldercollection*, IUnknown**); static HRESULT create_filecoll_enum(struct filecollection*, IUnknown**); static HRESULT create_drivecoll_enum(struct drivecollection*, IUnknown**); +static inline DWORD get_parent_folder_name(const WCHAR *path, DWORD len); static inline BOOL is_dir_data(const WIN32_FIND_DATAW *data) { @@ -2562,8 +2563,29 @@ static HRESULT WINAPI folder_get_Drive(IFolder *iface, IDrive **drive) static HRESULT WINAPI folder_get_ParentFolder(IFolder *iface, IFolder **parent) { struct folder *This = impl_from_IFolder(iface); - FIXME("(%p)->(%p): stub\n", This, parent); - return E_NOTIMPL; + WCHAR *parent_path; + DWORD len; + HRESULT hr; + + TRACE("(%p)->(%p)\n", This, parent); + + if(!parent) + return E_POINTER; + + *parent = NULL; + + len = get_parent_folder_name(This->path, SysStringLen(This->path)); + if(!len) + return S_OK; + + if(!(parent_path = malloc((len + 1) * sizeof(WCHAR)))) + return E_OUTOFMEMORY; + memcpy(parent_path, This->path, len * sizeof(WCHAR)); + parent_path[len] = 0; + + hr = create_folder(parent_path, parent); + free(parent_path); + return hr; } static HRESULT WINAPI folder_get_Attributes(IFolder *iface, FileAttribute *attr) diff --git a/dlls/scrrun/tests/filesystem.c b/dlls/scrrun/tests/filesystem.c index 5edf11824e0..3911e910b4a 100644 --- a/dlls/scrrun/tests/filesystem.c +++ b/dlls/scrrun/tests/filesystem.c @@ -1032,6 +1032,50 @@ static void test_GetFolder(void) SetCurrentDirectoryW(prev_path); } +static void test_Folder_ParentFolder(void) +{ + WCHAR windir[MAX_PATH]; + IFolder *folder, *parent, *grandparent; + BSTR str, expected; + HRESULT hr; + + GetWindowsDirectoryW(windir, MAX_PATH); + str = SysAllocString(windir); + hr = IFileSystem3_GetFolder(fs3, str, &folder); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + SysFreeString(str); + + hr = IFolder_get_ParentFolder(folder, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + parent = (void*)0xdeadbeef; + hr = IFolder_get_ParentFolder(folder, &parent); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(parent != NULL && parent != (void*)0xdeadbeef, "got parent %p\n", parent); + + str = SysAllocString(windir); + hr = IFileSystem3_GetParentFolderName(fs3, str, &expected); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + SysFreeString(str); + + hr = IFolder_get_Path(parent, &str); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!lstrcmpiW(str, expected), "got %s, expected %s\n", + wine_dbgstr_w(str), wine_dbgstr_w(expected)); + SysFreeString(str); + SysFreeString(expected); + + IFolder_Release(folder); + + /* Root folder: ParentFolder returns NULL. */ + grandparent = (void*)0xdeadbeef; + hr = IFolder_get_ParentFolder(parent, &grandparent); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(grandparent == NULL, "got %p, expected NULL\n", grandparent); + + IFolder_Release(parent); +} + static void _test_clone(IEnumVARIANT *enumvar, BOOL position_inherited, LONG count, int line) { HRESULT hr; @@ -2955,6 +2999,7 @@ START_TEST(filesystem) test_CopyFolder(); test_BuildPath(); test_GetFolder(); + test_Folder_ParentFolder(); test_FolderCollection(); test_FileCollection(); test_DriveCollection(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10661