From: Alex Henrie Subject: [PATCH v12 2/3] shell32: Implement FolderItems_Item. Message-Id: <20160909060254.6294-2-alexhenrie24@gmail.com> Date: Fri, 9 Sep 2016 00:02:23 -0600 In-Reply-To: <20160909060254.6294-1-alexhenrie24@gmail.com> References: <20160909060254.6294-1-alexhenrie24@gmail.com> Cc: Sebastian Lackner v12 fixes a compilation error that I somehow missed. Signed-off-by: Alex Henrie --- dlls/shell32/shell32_main.h | 9 +++ dlls/shell32/shelldispatch.c | 140 +++++++++++++++++++++++++++++++++++-- dlls/shell32/shelllink.c | 10 --- dlls/shell32/tests/shelldispatch.c | 21 ------ 4 files changed, 143 insertions(+), 37 deletions(-) diff --git a/dlls/shell32/shell32_main.h b/dlls/shell32/shell32_main.h index 8cd1318..d1ad0cd 100644 --- a/dlls/shell32/shell32_main.h +++ b/dlls/shell32/shell32_main.h @@ -164,6 +164,15 @@ static inline WCHAR * __SHCloneStrAtoW(WCHAR ** target, const char * source) return *target; } +static inline WCHAR * strdupW( const WCHAR *src ) +{ + WCHAR *dst; + if (!src) return NULL; + dst = HeapAlloc(GetProcessHeap(), 0, (strlenW(src)+1)*sizeof(WCHAR)); + if (dst) strcpyW(dst, src); + return dst; +} + extern WCHAR swShell32Name[MAX_PATH] DECLSPEC_HIDDEN; diff --git a/dlls/shell32/shelldispatch.c b/dlls/shell32/shelldispatch.c index ac79302..0aa9bf0 100644 --- a/dlls/shell32/shelldispatch.c +++ b/dlls/shell32/shelldispatch.c @@ -68,6 +68,9 @@ typedef struct { typedef struct { FolderItems3 FolderItems3_iface; LONG ref; + VARIANT dir; + WCHAR **item_filenames; + LONG item_count; } FolderItemsImpl; typedef struct { @@ -989,11 +992,18 @@ static ULONG WINAPI FolderItemsImpl_Release(FolderItems3 *iface) { FolderItemsImpl *This = impl_from_FolderItems(iface); ULONG ref = InterlockedDecrement(&This->ref); + LONG i; TRACE("(%p), new refcount=%i\n", iface, ref); if (!ref) + { + VariantClear(&This->dir); + for (i = 0; i < This->item_count; i++) + HeapFree(GetProcessHeap(), 0, This->item_filenames[i]); + HeapFree(GetProcessHeap(), 0, This->item_filenames); HeapFree(GetProcessHeap(), 0, This); + } return ref; } @@ -1079,10 +1089,57 @@ static HRESULT WINAPI FolderItemsImpl_get_Parent(FolderItems3 *iface, IDispatch static HRESULT WINAPI FolderItemsImpl_Item(FolderItems3 *iface, VARIANT index, FolderItem **ppid) { - FIXME("(%p,%s,%p)\n", iface, debugstr_variant(&index), ppid); + FolderItemsImpl *This = impl_from_FolderItems(iface); + WCHAR path_str[MAX_PATH]; + VARIANT path_var; + HRESULT ret; + + TRACE("(%p,%s,%p)\n", iface, debugstr_variant(&index), ppid); *ppid = NULL; - return E_NOTIMPL; + + if (!PathIsDirectoryW(V_BSTR(&This->dir))) + return S_FALSE; + + switch (V_VT(&index)) + { + case VT_I2: + VariantChangeType(&index, &index, 0, VT_I4); + /* fall through */ + + case VT_I4: + if (V_I4(&index) >= This->item_count || V_I4(&index) < 0) + return S_FALSE; + + if (!PathCombineW(path_str, V_BSTR(&This->dir), This->item_filenames[V_I4(&index)])) + return E_OUTOFMEMORY; + + break; + + case VT_BSTR: + if (!V_BSTR(&index)) + return S_FALSE; + + if (!PathCombineW(path_str, V_BSTR(&This->dir), V_BSTR(&index))) + return E_OUTOFMEMORY; + + if (!PathFileExistsW(path_str)) + return S_FALSE; + + break; + + case VT_ERROR: + return FolderItem_Constructor(&This->dir, ppid); + + default: + return E_NOTIMPL; + } + + V_VT(&path_var) = VT_BSTR; + V_BSTR(&path_var) = SysAllocString(path_str); + ret = FolderItem_Constructor(&path_var, ppid); + VariantClear(&path_var); + return ret; } static HRESULT WINAPI FolderItemsImpl__NewEnum(FolderItems3 *iface, IUnknown **ppunk) @@ -1139,21 +1196,90 @@ static const FolderItems3Vtbl FolderItemsImpl_Vtbl = { FolderItemsImpl_get_Verbs }; -static HRESULT FolderItems_Constructor(FolderItems **ppfi) +static HRESULT FolderItems_Constructor(VARIANT *dir, FolderItems **ppfi) { + static const WCHAR backslash_star[] = {'\\','*',0}; + static const WCHAR dot[] = {'.',0}; + static const WCHAR dot_dot[] = {'.','.',0}; FolderItemsImpl *This; + LONG item_size; + WCHAR glob[MAX_PATH + 2]; + HANDLE first_file; + WIN32_FIND_DATAW file_info; + WCHAR **filenames; + HRESULT ret; - TRACE("\n"); + TRACE("(%s,%p)\n", debugstr_variant(dir), ppfi); *ppfi = NULL; + if (V_VT(dir) == VT_I4) + { + FIXME("special folder constants are not supported\n"); + return E_NOTIMPL; + } + This = HeapAlloc(GetProcessHeap(), 0, sizeof(FolderItemsImpl)); if (!This) return E_OUTOFMEMORY; This->FolderItems3_iface.lpVtbl = &FolderItemsImpl_Vtbl; This->ref = 1; + VariantInit(&This->dir); + ret = VariantCopy(&This->dir, dir); + if (FAILED(ret)) + { + HeapFree(GetProcessHeap(), 0, This); + return ret; + } + + This->item_count = 0; + lstrcpyW(glob, V_BSTR(dir)); + lstrcatW(glob, backslash_star); + first_file = FindFirstFileW(glob, &file_info); + if (first_file != INVALID_HANDLE_VALUE) + { + item_size = 128; + This->item_filenames = HeapAlloc(GetProcessHeap(), 0, item_size * sizeof(WCHAR*)); + if (!This->item_filenames) + goto fail; + + do + { + if (!strcmpW(file_info.cFileName, dot) || !strcmpW(file_info.cFileName, dot_dot)) + continue; + + if (This->item_count >= item_size) + { + item_size *= 2; + filenames = HeapReAlloc(GetProcessHeap(), 0, This->item_filenames, item_size * sizeof(WCHAR*)); + if (!filenames) + goto fail; + This->item_filenames = filenames; + } + + This->item_filenames[This->item_count] = strdupW(file_info.cFileName); + if (!This->item_filenames[This->item_count]) + goto fail; + This->item_count++; + } + while (FindNextFileW(first_file, &file_info)); + + FindClose(first_file); + HeapReAlloc(GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, + This->item_filenames, This->item_count * sizeof(WCHAR*)); + } + else + { + This->item_filenames = NULL; + } + *ppfi = (FolderItems*)&This->FolderItems3_iface; return S_OK; + +fail: + FindClose(first_file); + FolderItems3_Release(&This->FolderItems3_iface); + return E_OUTOFMEMORY; } static HRESULT WINAPI FolderImpl_QueryInterface(Folder3 *iface, REFIID riid, @@ -1308,9 +1434,11 @@ static HRESULT WINAPI FolderImpl_get_ParentFolder(Folder3 *iface, Folder **ppsf) static HRESULT WINAPI FolderImpl_Items(Folder3 *iface, FolderItems **ppid) { - FIXME("(%p,%p)\n", iface, ppid); + FolderImpl *This = impl_from_Folder(iface); + + TRACE("(%p,%p)\n", iface, ppid); - return FolderItems_Constructor(ppid); + return FolderItems_Constructor(&This->dir, ppid); } static HRESULT WINAPI FolderImpl_ParseName(Folder3 *iface, BSTR name, FolderItem **item) diff --git a/dlls/shell32/shelllink.c b/dlls/shell32/shelllink.c index bd3507e..3ac6364 100644 --- a/dlls/shell32/shelllink.c +++ b/dlls/shell32/shelllink.c @@ -215,16 +215,6 @@ static inline LPWSTR heap_strdupAtoW( LPCSTR str) return p; } -static inline LPWSTR strdupW( LPCWSTR src ) -{ - LPWSTR dest; - if (!src) return NULL; - dest = HeapAlloc( GetProcessHeap(), 0, (lstrlenW(src)+1)*sizeof(WCHAR) ); - if (dest) - lstrcpyW(dest, src); - return dest; -} - /************************************************************************** * IPersistFile_QueryInterface */ diff --git a/dlls/shell32/tests/shelldispatch.c b/dlls/shell32/tests/shelldispatch.c index 149f3b9..e18bb6a 100644 --- a/dlls/shell32/tests/shelldispatch.c +++ b/dlls/shell32/tests/shelldispatch.c @@ -390,7 +390,6 @@ todo_wine r = FolderItems_Item(items, var, NULL); r = FolderItems_Item(items, var, &item); -todo_wine ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r); ok(!item, "item is not null\n"); @@ -446,9 +445,7 @@ todo_wine V_BSTR(&var) = SysAllocString(wstr); item = (FolderItem*)0xdeadbeef; r = FolderItems_Item(items, var, &item); -todo_wine ok(r == S_OK, "FolderItems::Item failed: %08x\n", r); -todo_wine ok(!!item, "item is null\n"); VariantClear(&var); @@ -483,24 +480,19 @@ todo_wine V_I2(&var) = 0; item = NULL; r = FolderItems_Item(items, var, &item); -todo_wine ok(r == S_OK, "FolderItems::Item failed: %08x\n", r); -todo_wine ok(!!item, "item is null\n"); V_VT(&var) = VT_I4; V_I4(&var) = 0; item = NULL; r = FolderItems_Item(items, var, &item); -todo_wine ok(r == S_OK, "FolderItems::Item failed: %08x\n", r); -todo_wine ok(!!item, "item is null\n"); V_I4(&var) = -1; item = (FolderItem*)0xdeadbeef; r = FolderItems_Item(items, var, &item); -todo_wine ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r); ok(!item, "item is not null\n"); @@ -510,11 +502,8 @@ todo_wine V_ERROR(&var) = i; item = NULL; r = FolderItems_Item(items, var, &item); -todo_wine ok(r == S_OK, "expected S_OK, got %08x\n", r); -todo_wine ok(!!item, "item is null\n"); - if (!item) continue; bstr = NULL; r = FolderItem_get_Path(item, &bstr); @@ -539,11 +528,8 @@ todo_wine item = NULL; r = FolderItems_Item(items, int_index, &item); -todo_wine ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08x\n", i, r); -todo_wine ok(!!item, "file_defs[%d]: item is null\n", i); - if (!item) goto cleanup; item2 = NULL; r = FolderItems_Item(items, int_index, &item2); @@ -576,7 +562,6 @@ todo_wine FolderItem_Release(item); -cleanup: if (file_defs[i].type == DIRECTORY) { PathCombineA(buf, file_defs[i].name, "foo.txt"); @@ -585,9 +570,7 @@ cleanup: V_BSTR(&var) = SysAllocString(wstr2); item2 = NULL; r = FolderItems_Item(items, var, &item2); -todo_wine ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08x\n", i, r); -todo_wine ok(!!item2, "file_defs[%d]: item is null\n", i); if (item2) FolderItem_Release(item2); VariantClear(&var); @@ -599,7 +582,6 @@ todo_wine { ok(DeleteFileW(wstr), "file_defs[%d]: DeleteFile failed: %08x\n", i, GetLastError()); } - if (!item) continue; item = NULL; r = FolderItems_Item(items, int_index, &item); @@ -629,7 +611,6 @@ todo_wine V_I4(&var) = sizeof(file_defs)/sizeof(file_defs[0]); item = (FolderItem*)0xdeadbeef; r = FolderItems_Item(items, var, &item); -todo_wine ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r); ok(!item, "item is not null\n"); @@ -705,7 +686,6 @@ todo_wine V_I4(&var) = 0; item = (FolderItem*)0xdeadbeef; r = FolderItems_Item(items, var, &item); -todo_wine ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r); ok(!item, "item is not null\n"); @@ -714,7 +694,6 @@ todo_wine V_BSTR(&var) = SysAllocString(wstr); item = (FolderItem*)0xdeadbeef; r = FolderItems_Item(items, var, &item); -todo_wine ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r); ok(!item, "item is not null\n"); VariantClear(&var); -- 2.9.3