[PATCH v3 0/6] MR10661: scrrun: Implement some folder stubs
Implement several stub methods on Scripting.FileSystemObject's IFolder and IFile interfaces (ParentFolder, IsRootFolder, Attributes, date getters), and fix a latent BSTR length off-by-one in create_folder that the ParentFolder root-path case depends on. -- v3: scrrun: Implement IFolder and IFile date getters. scrrun: Implement IFolder::get_Attributes and IFolder::put_Attributes. scrrun: Implement IFolder::get_IsRootFolder. scrrun: Implement IFile::get_ParentFolder. https://gitlab.winehq.org/wine/wine/-/merge_requests/10661
From: Francis De Brabandere <francisdb@gmail.com> GetFullPathNameW returns the required buffer size including the terminating NUL character, but the result was passed directly to SysAllocStringLen, which expects the string length excluding the NUL. As a result, the BSTR stored in struct folder's path field had a length prefix one greater than the actual string content. The bug was not observable via folder_get_Path or folder_get_Name because both use the NUL-terminated view of the buffer, but it misdirects any internal code that uses SysStringLen on the stored path. --- dlls/scrrun/filesystem.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/scrrun/filesystem.c b/dlls/scrrun/filesystem.c index ae6c583fd06..6af73acbd79 100644 --- a/dlls/scrrun/filesystem.c +++ b/dlls/scrrun/filesystem.c @@ -2740,7 +2740,9 @@ HRESULT create_folder(const WCHAR *path, IFolder **folder) return E_FAIL; } - object->path = SysAllocStringLen(NULL, len); + /* GetFullPathNameW returns the required size including the NUL terminator, + * so the BSTR length prefix must be one less. */ + object->path = SysAllocStringLen(NULL, len - 1); if(!object->path) { free(object); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10661
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
From: Francis De Brabandere <francisdb@gmail.com> Return a new IFolder for the parent directory of This->path, mirroring the IFolder::get_ParentFolder implementation. The struct file path is a plain WCHAR* (not a BSTR), so the string length is taken via lstrlenW. --- dlls/scrrun/filesystem.c | 25 ++++++++++++++++-- dlls/scrrun/tests/filesystem.c | 46 ++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/dlls/scrrun/filesystem.c b/dlls/scrrun/filesystem.c index 184a562ae16..4fcbd23c97d 100644 --- a/dlls/scrrun/filesystem.c +++ b/dlls/scrrun/filesystem.c @@ -2961,8 +2961,29 @@ static HRESULT WINAPI file_get_Drive(IFile *iface, IDrive **ppdrive) static HRESULT WINAPI file_get_ParentFolder(IFile *iface, IFolder **ppfolder) { struct file *This = impl_from_IFile(iface); - FIXME("(%p)->(%p)\n", This, ppfolder); - return E_NOTIMPL; + WCHAR *parent_path; + DWORD len; + HRESULT hr; + + TRACE("(%p)->(%p)\n", This, ppfolder); + + if(!ppfolder) + return E_POINTER; + + *ppfolder = NULL; + + len = get_parent_folder_name(This->path, lstrlenW(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, ppfolder); + free(parent_path); + return hr; } static HRESULT WINAPI file_get_Attributes(IFile *iface, FileAttribute *pfa) diff --git a/dlls/scrrun/tests/filesystem.c b/dlls/scrrun/tests/filesystem.c index 3911e910b4a..aa3c37fea4f 100644 --- a/dlls/scrrun/tests/filesystem.c +++ b/dlls/scrrun/tests/filesystem.c @@ -769,6 +769,51 @@ static void test_GetFile(void) RemoveDirectoryW(pathW); } +static void test_File_ParentFolder(void) +{ + WCHAR pathW[MAX_PATH]; + IFile *file; + IFolder *parent; + BSTR path, expected, str; + HRESULT hr; + HANDLE hf; + + get_temp_path(NULL, pathW); + hf = CreateFileW(pathW, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); + if(hf == INVALID_HANDLE_VALUE) { + skip("Can't create temporary file\n"); + return; + } + CloseHandle(hf); + + path = SysAllocString(pathW); + hr = IFileSystem3_GetFile(fs3, path, &file); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IFile_get_ParentFolder(file, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + parent = (void*)0xdeadbeef; + hr = IFile_get_ParentFolder(file, &parent); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(parent != NULL && parent != (void*)0xdeadbeef, "got parent %p\n", parent); + + hr = IFileSystem3_GetParentFolderName(fs3, path, &expected); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + 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(parent); + IFile_Release(file); + SysFreeString(path); + DeleteFileW(pathW); +} + static inline BOOL create_file(const WCHAR *name) { HANDLE f = CreateFileW(name, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL); @@ -2995,6 +3040,7 @@ START_TEST(filesystem) test_GetBaseName(); test_GetAbsolutePathName(); test_GetFile(); + test_File_ParentFolder(); test_GetTempName(); test_CopyFolder(); test_BuildPath(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10661
From: Francis De Brabandere <francisdb@gmail.com> Return VARIANT_TRUE when the folder has no parent (its path is a drive root), and VARIANT_FALSE otherwise, using the existing get_parent_folder_name() helper. --- dlls/scrrun/filesystem.c | 11 +++++++++-- dlls/scrrun/tests/filesystem.c | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/dlls/scrrun/filesystem.c b/dlls/scrrun/filesystem.c index 4fcbd23c97d..b523daaa1e2 100644 --- a/dlls/scrrun/filesystem.c +++ b/dlls/scrrun/filesystem.c @@ -2654,8 +2654,15 @@ static HRESULT WINAPI folder_Move(IFolder *iface, BSTR dest) static HRESULT WINAPI folder_get_IsRootFolder(IFolder *iface, VARIANT_BOOL *isroot) { struct folder *This = impl_from_IFolder(iface); - FIXME("(%p)->(%p): stub\n", This, isroot); - return E_NOTIMPL; + + TRACE("(%p)->(%p)\n", This, isroot); + + if(!isroot) + return E_POINTER; + + *isroot = get_parent_folder_name(This->path, SysStringLen(This->path)) + ? VARIANT_FALSE : VARIANT_TRUE; + return S_OK; } static HRESULT WINAPI folder_get_Size(IFolder *iface, VARIANT *size) diff --git a/dlls/scrrun/tests/filesystem.c b/dlls/scrrun/tests/filesystem.c index aa3c37fea4f..7e9dab74987 100644 --- a/dlls/scrrun/tests/filesystem.c +++ b/dlls/scrrun/tests/filesystem.c @@ -1082,6 +1082,7 @@ static void test_Folder_ParentFolder(void) WCHAR windir[MAX_PATH]; IFolder *folder, *parent, *grandparent; BSTR str, expected; + VARIANT_BOOL isroot; HRESULT hr; GetWindowsDirectoryW(windir, MAX_PATH); @@ -1110,6 +1111,15 @@ static void test_Folder_ParentFolder(void) SysFreeString(str); SysFreeString(expected); + /* Non-root folder: IsRootFolder is FALSE. */ + hr = IFolder_get_IsRootFolder(folder, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + isroot = VARIANT_TRUE; + hr = IFolder_get_IsRootFolder(folder, &isroot); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(isroot == VARIANT_FALSE, "got %d\n", isroot); + IFolder_Release(folder); /* Root folder: ParentFolder returns NULL. */ @@ -1118,6 +1128,12 @@ static void test_Folder_ParentFolder(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(grandparent == NULL, "got %p, expected NULL\n", grandparent); + /* Root folder: IsRootFolder is TRUE. */ + isroot = VARIANT_FALSE; + hr = IFolder_get_IsRootFolder(parent, &isroot); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(isroot == VARIANT_TRUE, "got %d\n", isroot); + IFolder_Release(parent); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10661
From: Francis De Brabandere <francisdb@gmail.com> Delegate to GetFileAttributesW and SetFileAttributesW, mirroring the existing IFile implementations of these methods. The returned value is masked to the same FileAttribute subset that IFile::get_Attributes exposes. --- dlls/scrrun/filesystem.c | 23 ++++++++++++--- dlls/scrrun/tests/filesystem.c | 52 ++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 4 deletions(-) diff --git a/dlls/scrrun/filesystem.c b/dlls/scrrun/filesystem.c index b523daaa1e2..75f52501b6c 100644 --- a/dlls/scrrun/filesystem.c +++ b/dlls/scrrun/filesystem.c @@ -2591,15 +2591,30 @@ static HRESULT WINAPI folder_get_ParentFolder(IFolder *iface, IFolder **parent) static HRESULT WINAPI folder_get_Attributes(IFolder *iface, FileAttribute *attr) { struct folder *This = impl_from_IFolder(iface); - FIXME("(%p)->(%p): stub\n", This, attr); - return E_NOTIMPL; + DWORD fa; + + TRACE("(%p)->(%p)\n", This, attr); + + if(!attr) + return E_POINTER; + + fa = GetFileAttributesW(This->path); + if(fa == INVALID_FILE_ATTRIBUTES) + return create_error(GetLastError()); + + *attr = fa & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | + FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE | + FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_COMPRESSED); + return S_OK; } static HRESULT WINAPI folder_put_Attributes(IFolder *iface, FileAttribute attr) { struct folder *This = impl_from_IFolder(iface); - FIXME("(%p)->(0x%x): stub\n", This, attr); - return E_NOTIMPL; + + TRACE("(%p)->(0x%x)\n", This, attr); + + return SetFileAttributesW(This->path, attr) ? S_OK : create_error(GetLastError()); } static HRESULT WINAPI folder_get_DateCreated(IFolder *iface, DATE *date) diff --git a/dlls/scrrun/tests/filesystem.c b/dlls/scrrun/tests/filesystem.c index 7e9dab74987..14db34b8d02 100644 --- a/dlls/scrrun/tests/filesystem.c +++ b/dlls/scrrun/tests/filesystem.c @@ -1077,6 +1077,57 @@ static void test_GetFolder(void) SetCurrentDirectoryW(prev_path); } +static void test_Folder_Attributes(void) +{ + static const DWORD attr_mask = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | + FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE | + FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_COMPRESSED; + + WCHAR temp_path[MAX_PATH], dir_path[MAX_PATH]; + IFolder *folder; + FileAttribute fa; + DWORD gfa, new_gfa; + BSTR path; + HRESULT hr; + + GetTempPathW(MAX_PATH, temp_path); + lstrcpyW(dir_path, temp_path); + lstrcatW(dir_path, L"scrrun_attr_test"); + ok(CreateDirectoryW(dir_path, NULL), "CreateDirectory failed, error %ld\n", GetLastError()); + + path = SysAllocString(dir_path); + hr = IFileSystem3_GetFolder(fs3, path, &folder); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IFolder_get_Attributes(folder, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + hr = IFolder_get_Attributes(folder, &fa); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + gfa = GetFileAttributesW(dir_path) & attr_mask; + ok(fa == gfa, "Unexpected flags %#x, expected %lx.\n", fa, gfa); + ok(fa & FILE_ATTRIBUTE_DIRECTORY, "directory bit not set, got %#x.\n", fa); + + /* FILE_ATTRIBUTE_READONLY is silently ignored on directories by Windows + * (it has a different meaning for folders), so exercise HIDDEN instead. */ + hr = IFolder_put_Attributes(folder, gfa | FILE_ATTRIBUTE_HIDDEN); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + new_gfa = GetFileAttributesW(dir_path) & attr_mask; + ok(new_gfa == (gfa | FILE_ATTRIBUTE_HIDDEN), "got %#lx, expected %lx\n", + new_gfa, gfa | FILE_ATTRIBUTE_HIDDEN); + + hr = IFolder_get_Attributes(folder, &fa); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(fa == new_gfa, "got %#x, expected %lx.\n", fa, new_gfa); + + hr = IFolder_put_Attributes(folder, gfa); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + IFolder_Release(folder); + SysFreeString(path); + RemoveDirectoryW(dir_path); +} + static void test_Folder_ParentFolder(void) { WCHAR windir[MAX_PATH]; @@ -3061,6 +3112,7 @@ START_TEST(filesystem) test_CopyFolder(); test_BuildPath(); test_GetFolder(); + test_Folder_Attributes(); test_Folder_ParentFolder(); test_FolderCollection(); test_FileCollection(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10661
From: Francis De Brabandere <francisdb@gmail.com> Implement IFolder::get_DateCreated, IFolder::get_DateLastModified, IFolder::get_DateLastAccessed, and the previously-stubbed IFile::get_DateLastAccessed, all delegating to GetFileAttributesExW and the existing get_date_from_filetime helper. --- dlls/scrrun/filesystem.c | 41 +++++++++++++++++++++------ dlls/scrrun/tests/filesystem.c | 52 ++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 8 deletions(-) diff --git a/dlls/scrrun/filesystem.c b/dlls/scrrun/filesystem.c index 75f52501b6c..af76f0cf4d8 100644 --- a/dlls/scrrun/filesystem.c +++ b/dlls/scrrun/filesystem.c @@ -199,6 +199,7 @@ 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 HRESULT get_date_from_filetime(const FILETIME *ft, DATE *date); static inline BOOL is_dir_data(const WIN32_FIND_DATAW *data) { @@ -2620,22 +2621,40 @@ static HRESULT WINAPI folder_put_Attributes(IFolder *iface, FileAttribute attr) static HRESULT WINAPI folder_get_DateCreated(IFolder *iface, DATE *date) { struct folder *This = impl_from_IFolder(iface); - FIXME("(%p)->(%p): stub\n", This, date); - return E_NOTIMPL; + WIN32_FILE_ATTRIBUTE_DATA attrs; + + TRACE("(%p)->(%p)\n", This, date); + + if (GetFileAttributesExW(This->path, GetFileExInfoStandard, &attrs)) + return get_date_from_filetime(&attrs.ftCreationTime, date); + + return E_FAIL; } static HRESULT WINAPI folder_get_DateLastModified(IFolder *iface, DATE *date) { struct folder *This = impl_from_IFolder(iface); - FIXME("(%p)->(%p): stub\n", This, date); - return E_NOTIMPL; + WIN32_FILE_ATTRIBUTE_DATA attrs; + + TRACE("(%p)->(%p)\n", This, date); + + if (GetFileAttributesExW(This->path, GetFileExInfoStandard, &attrs)) + return get_date_from_filetime(&attrs.ftLastWriteTime, date); + + return E_FAIL; } static HRESULT WINAPI folder_get_DateLastAccessed(IFolder *iface, DATE *date) { struct folder *This = impl_from_IFolder(iface); - FIXME("(%p)->(%p): stub\n", This, date); - return E_NOTIMPL; + WIN32_FILE_ATTRIBUTE_DATA attrs; + + TRACE("(%p)->(%p)\n", This, date); + + if (GetFileAttributesExW(This->path, GetFileExInfoStandard, &attrs)) + return get_date_from_filetime(&attrs.ftLastAccessTime, date); + + return E_FAIL; } static HRESULT WINAPI folder_get_Type(IFolder *iface, BSTR *type) @@ -3081,8 +3100,14 @@ static HRESULT WINAPI file_get_DateLastModified(IFile *iface, DATE *date) static HRESULT WINAPI file_get_DateLastAccessed(IFile *iface, DATE *pdate) { struct file *This = impl_from_IFile(iface); - FIXME("(%p)->(%p)\n", This, pdate); - return E_NOTIMPL; + WIN32_FILE_ATTRIBUTE_DATA attrs; + + TRACE("(%p)->(%p)\n", This, pdate); + + if (GetFileAttributesExW(This->path, GetFileExInfoStandard, &attrs)) + return get_date_from_filetime(&attrs.ftLastAccessTime, pdate); + + return E_FAIL; } static HRESULT WINAPI file_get_Size(IFile *iface, VARIANT *pvarSize) diff --git a/dlls/scrrun/tests/filesystem.c b/dlls/scrrun/tests/filesystem.c index 14db34b8d02..9b5abdf5c97 100644 --- a/dlls/scrrun/tests/filesystem.c +++ b/dlls/scrrun/tests/filesystem.c @@ -704,6 +704,14 @@ static void test_GetFile(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(date > 0.0, "got %f\n", date); + hr = IFile_get_DateLastAccessed(file, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + date = 0.0; + hr = IFile_get_DateLastAccessed(file, &date); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(date > 0.0, "got %f\n", date); + hr = IFile_get_Path(file, NULL); ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); @@ -1077,6 +1085,49 @@ static void test_GetFolder(void) SetCurrentDirectoryW(prev_path); } +static void test_Folder_Dates(void) +{ + WCHAR temp_path[MAX_PATH], dir_path[MAX_PATH]; + IFolder *folder; + BSTR path; + DATE date; + HRESULT hr; + + GetTempPathW(MAX_PATH, temp_path); + lstrcpyW(dir_path, temp_path); + lstrcatW(dir_path, L"scrrun_dates_test"); + ok(CreateDirectoryW(dir_path, NULL), "CreateDirectory failed, error %ld\n", GetLastError()); + + path = SysAllocString(dir_path); + hr = IFileSystem3_GetFolder(fs3, path, &folder); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IFolder_get_DateCreated(folder, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + date = 0.0; + hr = IFolder_get_DateCreated(folder, &date); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(date > 0.0, "got %f\n", date); + + hr = IFolder_get_DateLastModified(folder, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + date = 0.0; + hr = IFolder_get_DateLastModified(folder, &date); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(date > 0.0, "got %f\n", date); + + hr = IFolder_get_DateLastAccessed(folder, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + date = 0.0; + hr = IFolder_get_DateLastAccessed(folder, &date); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(date > 0.0, "got %f\n", date); + + IFolder_Release(folder); + SysFreeString(path); + RemoveDirectoryW(dir_path); +} + static void test_Folder_Attributes(void) { static const DWORD attr_mask = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | @@ -3113,6 +3164,7 @@ START_TEST(filesystem) test_BuildPath(); test_GetFolder(); test_Folder_Attributes(); + test_Folder_Dates(); test_Folder_ParentFolder(); test_FolderCollection(); test_FileCollection(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10661
@nsivov should I add more or stop here and work on a next MR once this is merged? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10661#note_136147
This merge request was approved by Nikolay Sivov. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10661
On Wed Apr 15 12:15:35 2026 +0000, Francis De Brabandere wrote:
@nsivov should I add more or stop here and work on a next MR once this is merged? Depending on amount of changes, 5-8 commits is fine I'd say.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10661#note_136285
On Wed Apr 15 12:15:35 2026 +0000, Nikolay Sivov wrote:
Depending on amount of changes, 5-8 commits is fine I'd say. So let's wait for this one to get in first.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10661#note_136286
On Wed Apr 15 19:29:53 2026 +0000, Nikolay Sivov wrote:
So let's wait for this one to get in first. Ok
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10661#note_136342
On Wed Apr 15 19:29:53 2026 +0000, Francis De Brabandere wrote:
Ok Thanks for the quick review!
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10661#note_136344
participants (3)
-
Francis De Brabandere -
Francis De Brabandere (@francisdb) -
Nikolay Sivov (@nsivov)