[PATCH] shell32: Implement Application() property for Folder and FolderItems

Nikolay Sivov nsivov at codeweavers.com
Wed Sep 13 05:58:32 CDT 2017


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/shell32/shelldispatch.c       | 64 +++++++++++++++++------------------
 dlls/shell32/tests/shelldispatch.c | 68 +++++++++++++++++++++++++++++++++-----
 2 files changed, 91 insertions(+), 41 deletions(-)

diff --git a/dlls/shell32/shelldispatch.c b/dlls/shell32/shelldispatch.c
index ec52c6d613..a225f45eb3 100644
--- a/dlls/shell32/shelldispatch.c
+++ b/dlls/shell32/shelldispatch.c
@@ -63,12 +63,13 @@ typedef struct {
     Folder3 Folder3_iface;
     LONG ref;
     VARIANT dir;
+    IDispatch *application;
 } FolderImpl;
 
 typedef struct {
     FolderItems3 FolderItems3_iface;
     LONG ref;
-    VARIANT dir;
+    FolderImpl *folder;
     WCHAR **item_filenames;
     LONG item_count;
 } FolderItemsImpl;
@@ -998,7 +999,7 @@ static ULONG WINAPI FolderItemsImpl_Release(FolderItems3 *iface)
 
     if (!ref)
     {
-        VariantClear(&This->dir);
+        Folder3_Release(&This->folder->Folder3_iface);
         for (i = 0; i < This->item_count; i++)
             HeapFree(GetProcessHeap(), 0, This->item_filenames[i]);
         HeapFree(GetProcessHeap(), 0, This->item_filenames);
@@ -1065,19 +1066,17 @@ static HRESULT WINAPI FolderItemsImpl_get_Count(FolderItems3 *iface, LONG *count
 
     TRACE("(%p,%p)\n", iface, count);
 
-    *count = PathIsDirectoryW(V_BSTR(&This->dir)) ? This->item_count : 0;
+    *count = PathIsDirectoryW(V_BSTR(&This->folder->dir)) ? This->item_count : 0;
     return S_OK;
 }
 
-static HRESULT WINAPI FolderItemsImpl_get_Application(FolderItems3 *iface, IDispatch **ppid)
+static HRESULT WINAPI FolderItemsImpl_get_Application(FolderItems3 *iface, IDispatch **disp)
 {
-    FIXME("(%p,%p)\n", iface, ppid);
+    FolderItemsImpl *This = impl_from_FolderItems(iface);
 
-    if (!ppid)
-        return E_INVALIDARG;
+    TRACE("(%p,%p)\n", iface, disp);
 
-    *ppid = NULL;
-    return E_NOTIMPL;
+    return Folder3_get_Application(&This->folder->Folder3_iface, disp);
 }
 
 static HRESULT WINAPI FolderItemsImpl_get_Parent(FolderItems3 *iface, IDispatch **ppid)
@@ -1101,7 +1100,7 @@ static HRESULT WINAPI FolderItemsImpl_Item(FolderItems3 *iface, VARIANT index, F
 
     *ppid = NULL;
 
-    if (!PathIsDirectoryW(V_BSTR(&This->dir)))
+    if (!PathIsDirectoryW(V_BSTR(&This->folder->dir)))
         return S_FALSE;
 
     switch (V_VT(&index))
@@ -1114,7 +1113,7 @@ static HRESULT WINAPI FolderItemsImpl_Item(FolderItems3 *iface, VARIANT index, F
             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)]))
+            if (!PathCombineW(path_str, V_BSTR(&This->folder->dir), This->item_filenames[V_I4(&index)]))
                 return S_FALSE;
 
             break;
@@ -1129,7 +1128,7 @@ static HRESULT WINAPI FolderItemsImpl_Item(FolderItems3 *iface, VARIANT index, F
             if (strcmpW(V_BSTR(&index), canonicalized_index) != 0)
                 return S_FALSE;
 
-            if (!PathCombineW(path_str, V_BSTR(&This->dir), V_BSTR(&index)))
+            if (!PathCombineW(path_str, V_BSTR(&This->folder->dir), V_BSTR(&index)))
                 return S_FALSE;
 
             if (!PathFileExistsW(path_str))
@@ -1138,7 +1137,7 @@ static HRESULT WINAPI FolderItemsImpl_Item(FolderItems3 *iface, VARIANT index, F
             break;
 
         case VT_ERROR:
-            return FolderItem_Constructor(&This->dir, ppid);
+            return FolderItem_Constructor(&This->folder->dir, ppid);
 
         default:
             return E_NOTIMPL;
@@ -1205,7 +1204,7 @@ static const FolderItems3Vtbl FolderItemsImpl_Vtbl = {
     FolderItemsImpl_get_Verbs
 };
 
-static HRESULT FolderItems_Constructor(VARIANT *dir, FolderItems **ppfi)
+static HRESULT FolderItems_Constructor(FolderImpl *folder, FolderItems **ppfi)
 {
     static const WCHAR backslash_star[] = {'\\','*',0};
     static const WCHAR dot[] = {'.',0};
@@ -1216,13 +1215,12 @@ static HRESULT FolderItems_Constructor(VARIANT *dir, FolderItems **ppfi)
     HANDLE first_file;
     WIN32_FIND_DATAW file_info;
     WCHAR **filenames;
-    HRESULT ret;
 
-    TRACE("(%s,%p)\n", debugstr_variant(dir), ppfi);
+    TRACE("(%s,%p)\n", debugstr_variant(&folder->dir), ppfi);
 
     *ppfi = NULL;
 
-    if (V_VT(dir) == VT_I4)
+    if (V_VT(&folder->dir) == VT_I4)
     {
         FIXME("special folder constants are not supported\n");
         return E_NOTIMPL;
@@ -1232,17 +1230,11 @@ static HRESULT FolderItems_Constructor(VARIANT *dir, FolderItems **ppfi)
     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->folder = folder;
+    Folder3_AddRef(&folder->Folder3_iface);
 
     This->item_count = 0;
-    lstrcpyW(glob, V_BSTR(dir));
+    lstrcpyW(glob, V_BSTR(&folder->dir));
     lstrcatW(glob, backslash_star);
     first_file = FindFirstFileW(glob, &file_info);
     if (first_file != INVALID_HANDLE_VALUE)
@@ -1335,6 +1327,7 @@ static ULONG WINAPI FolderImpl_Release(Folder3 *iface)
 
     if (!ref)
     {
+        IDispatch_Release(This->application);
         VariantClear(&This->dir);
         HeapFree(GetProcessHeap(), 0, This);
     }
@@ -1416,13 +1409,19 @@ static HRESULT WINAPI FolderImpl_get_Title(Folder3 *iface, BSTR *pbs)
     return *pbs ? S_OK : E_OUTOFMEMORY;
 }
 
-static HRESULT WINAPI FolderImpl_get_Application(Folder3 *iface,
-        IDispatch **ppid)
+static HRESULT WINAPI FolderImpl_get_Application(Folder3 *iface, IDispatch **disp)
 {
-    FIXME("(%p,%p)\n", iface, ppid);
+    FolderImpl *This = impl_from_Folder(iface);
 
-    *ppid = NULL;
-    return E_NOTIMPL;
+    TRACE("(%p,%p)\n", iface, disp);
+
+    if (!disp)
+        return E_INVALIDARG;
+
+    *disp = This->application;
+    IDispatch_AddRef(*disp);
+
+    return S_OK;
 }
 
 static HRESULT WINAPI FolderImpl_get_Parent(Folder3 *iface, IDispatch **ppid)
@@ -1447,7 +1446,7 @@ static HRESULT WINAPI FolderImpl_Items(Folder3 *iface, FolderItems **ppid)
 
     TRACE("(%p,%p)\n", iface, ppid);
 
-    return FolderItems_Constructor(&This->dir, ppid);
+    return FolderItems_Constructor(This, ppid);
 }
 
 static HRESULT WINAPI FolderImpl_ParseName(Folder3 *iface, BSTR name, FolderItem **item)
@@ -1624,6 +1623,7 @@ static HRESULT Folder_Constructor(VARIANT *dir, Folder **ppsdf)
     if (!This) return E_OUTOFMEMORY;
     This->Folder3_iface.lpVtbl = &FolderImpl_Vtbl;
     This->ref = 1;
+    IShellDispatch_Constructor(NULL, &IID_IDispatch, (void **)&This->application);
 
     VariantInit(&This->dir);
     ret = VariantCopy(&This->dir, dir);
diff --git a/dlls/shell32/tests/shelldispatch.c b/dlls/shell32/tests/shelldispatch.c
index 0529bb2d10..1d22b06779 100644
--- a/dlls/shell32/tests/shelldispatch.c
+++ b/dlls/shell32/tests/shelldispatch.c
@@ -33,6 +33,15 @@
 #define EXPECT_HR(hr,hr_exp) \
     ok(hr == hr_exp, "got 0x%08x, expected 0x%08x\n", hr, hr_exp)
 
+#define EXPECT_REF(obj,ref) _expect_ref((IUnknown *)obj, ref, __LINE__)
+static void _expect_ref(IUnknown *obj, ULONG ref, int line)
+{
+    ULONG rc;
+    IUnknown_AddRef(obj);
+    rc = IUnknown_Release(obj);
+    ok_(__FILE__,line)(rc == ref, "Unexpected refcount %d, expected %d\n", rc, ref);
+}
+
 static const WCHAR winetestW[] = {'w','i','n','e','t','e','s','t',0};
 
 static HRESULT (WINAPI *pSHGetFolderPathW)(HWND, int, HANDLE, DWORD, LPWSTR);
@@ -401,15 +410,15 @@ static void test_items(void)
     HRESULT r;
     IShellDispatch *sd = NULL;
     Folder *folder = NULL;
-    FolderItems *items = NULL;
+    FolderItems *items;
     FolderItems2 *items2 = NULL;
     FolderItems3 *items3 = NULL;
     FolderItem *item = (FolderItem*)0xdeadbeef, *item2;
-    IDispatch *disp = NULL;
-    IUnknown *unk = NULL;
     FolderItemVerbs *verbs = (FolderItemVerbs*)0xdeadbeef;
     VARIANT var, int_index, str_index, str_index2;
+    IDispatch *disp, *disp2;
     LONG count = -1;
+    IUnknown *unk;
     HANDLE file;
     BSTR bstr;
     char cstr[64];
@@ -427,18 +436,56 @@ static void test_items(void)
     GetFullPathNameW(winetestW, MAX_PATH, path, NULL);
     V_VT(&var) = VT_BSTR;
     V_BSTR(&var) = SysAllocString(path);
+
+    EXPECT_REF(sd, 1);
     r = IShellDispatch_NameSpace(sd, var, &folder);
     ok(r == S_OK, "IShellDispatch::NameSpace failed: %08x\n", r);
     ok(!!folder, "folder is null\n");
+    EXPECT_REF(folder, 1);
+    EXPECT_REF(sd, 1);
+
     VariantClear(&var);
-    IShellDispatch_Release(sd);
     SetCurrentDirectoryW(winetestW);
     GetCurrentDirectoryW(MAX_PATH, path);
     GetLongPathNameW(path, cur_dir, MAX_PATH);
 
+    /* FolderItems grabs its Folder reference */
+    items = NULL;
     r = Folder_Items(folder, &items);
     ok(r == S_OK, "Folder::Items failed: %08x\n", r);
     ok(!!items, "items is null\n");
+    EXPECT_REF(folder, 2);
+    EXPECT_REF(items, 1);
+
+    unk = NULL;
+    r = Folder_Items(folder, (FolderItems **)&unk);
+    ok(r == S_OK, "Folder::Items failed: %08x\n", r);
+    EXPECT_REF(folder, 3);
+    IUnknown_Release(unk);
+    EXPECT_REF(folder, 2);
+
+    FolderItems_AddRef(items);
+    EXPECT_REF(folder, 2);
+    FolderItems_Release(items);
+
+    /* Application property */
+    disp = NULL;
+    EXPECT_REF(sd, 1);
+    r = Folder_get_Application(folder, &disp);
+    ok(r == S_OK, "Failed to get application %#x.\n", r);
+    ok(disp != (IDispatch *)sd, "Unexpected application pointer\n");
+    EXPECT_REF(sd, 1);
+
+    disp2 = NULL;
+    r = Folder_get_Application(folder, &disp2);
+    ok(r == S_OK, "Failed to get application %#x.\n", r);
+    ok(disp2 == disp, "Unexpected application pointer\n");
+    IDispatch_Release(disp2);
+
+    r = IDispatch_QueryInterface(disp, &IID_IShellDispatch, (void **)&disp2);
+    ok(r == S_OK, "Wrong instance, hr %#x.\n", r);
+    IDispatch_Release(disp2);
+    IDispatch_Release(disp);
 
     if (0) /* crashes on all versions of Windows */
         r = FolderItems_get_Count(items, NULL);
@@ -506,7 +553,6 @@ static void test_items(void)
     r = FolderItems_QueryInterface(items, &IID_FolderItems3, (void**)&items3);
     ok(r == S_OK, "FolderItems::QueryInterface failed: %08x\n", r);
     ok(!!items3, "items3 is null\n");
-    Folder_Release(folder);
 
     count = -1;
     r = FolderItems_get_Count(items, &count);
@@ -674,11 +720,13 @@ static void test_items(void)
     }
 
     r = FolderItems_get_Application(items, &disp);
-todo_wine
     ok(r == S_OK, "FolderItems::get_Application failed: %08x\n", r);
-todo_wine
-    ok(!!disp, "disp is null\n");
-    if (disp) IDispatch_Release(disp);
+
+    r = Folder_get_Application(folder, &disp2);
+    ok(r == S_OK, "Failed to get application pointer, hr %#x.\n", r);
+    ok(disp == disp2, "Unexpected application pointer.\n");
+    IDispatch_Release(disp2);
+    IDispatch_Release(disp);
 
     if (0) /* crashes on xp */
     {
@@ -749,8 +797,10 @@ todo_wine
     VariantClear(&str_index);
 
     FolderItems_Release(items);
+    Folder_Release(folder);
     if (items2) FolderItems2_Release(items2);
     if (items3) FolderItems3_Release(items3);
+    IShellDispatch_Release(sd);
 }
 
 static void test_service(void)
-- 
2.14.1




More information about the wine-patches mailing list