[PATCH v3 2/3] shell32: Implement FolderItems_Item.

Alex Henrie alexhenrie24 at gmail.com
Mon Jul 25 01:32:29 CDT 2016


Signed-off-by: Alex Henrie <alexhenrie24 at gmail.com>
---
 dlls/shell32/shelldispatch.c       | 116 +++++++++++++++++++++++++++++++++++--
 dlls/shell32/tests/shelldispatch.c |  62 +++++++++++---------
 2 files changed, 146 insertions(+), 32 deletions(-)

diff --git a/dlls/shell32/shelldispatch.c b/dlls/shell32/shelldispatch.c
index ac79302..d9b0527 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;
+    BSTR *item_paths;
+    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);
+    int i;
 
     TRACE("(%p), new refcount=%i\n", iface, ref);
 
     if (!ref)
+    {
+        VariantClear(&This->dir);
+        for (i = 0; i < This->item_count; i++)
+            SysFreeString(This->item_paths[i]);
+        HeapFree(GetProcessHeap(), 0, This->item_paths);
         HeapFree(GetProcessHeap(), 0, This);
+    }
     return ref;
 }
 
@@ -1079,10 +1089,36 @@ 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);
+    VARIANT path;
+
+    TRACE("(%p,%s,%p)\n", iface, debugstr_variant(&index), ppid);
 
     *ppid = NULL;
-    return E_NOTIMPL;
+
+    switch (V_VT(&index))
+    {
+        case VT_I2:
+        case VT_I4:
+            VariantChangeType(&index, &index, 0, VT_I4);
+            if (V_I4(&index) < 0 || V_I4(&index) >= This->item_count)
+                return S_FALSE;
+
+            V_VT(&path) = VT_BSTR;
+            V_BSTR(&path) = This->item_paths[V_I4(&index)];
+            return FolderItem_Constructor(&path, ppid);
+
+        case VT_ERROR:
+            V_VT(&path) = VT_BSTR;
+            V_BSTR(&path) = V_BSTR(&This->dir);
+            return FolderItem_Constructor(&path, ppid);
+
+        case VT_BSTR:
+            return S_FALSE;
+
+        default:
+            return E_NOTIMPL;
+    }
 }
 
 static HRESULT WINAPI FolderItemsImpl__NewEnum(FolderItems3 *iface, IUnknown **ppunk)
@@ -1139,21 +1175,87 @@ 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;
+    WCHAR path[MAX_PATH + 2];
+    HANDLE first_file;
+    WIN32_FIND_DATAW file_info;
+    BSTR *paths;
+    HRESULT ret = S_OK;
 
     TRACE("\n");
 
     *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 E_OUTOFMEMORY;
+    }
+
+    This->item_paths = HeapAlloc(GetProcessHeap(), 0, sizeof(BSTR));
+    if (!This->item_paths)
+    {
+        VariantClear(&This->dir);
+        HeapFree(GetProcessHeap(), 0, This);
+        return E_OUTOFMEMORY;
+    }
+    This->item_count = 0;
+
+    lstrcpyW(path, V_BSTR(dir));
+    lstrcatW(path, backslash_star);
+    first_file = FindFirstFileW(path, &file_info);
+    if (first_file != INVALID_HANDLE_VALUE)
+    {
+        do
+        {
+            if (!lstrcmpW(file_info.cFileName, dot) || !lstrcmpW(file_info.cFileName, dot_dot))
+                continue;
+
+            if (!PathCombineW(path, V_BSTR(dir), file_info.cFileName))
+            {
+                ret = E_OUTOFMEMORY;
+                goto fail;
+            }
+
+            paths = HeapReAlloc(GetProcessHeap(), 0, This->item_paths, (This->item_count + 1) * sizeof(BSTR));
+            if (!paths)
+            {
+                ret = E_OUTOFMEMORY;
+                goto fail;
+            }
+            This->item_paths = paths;
+            This->item_paths[This->item_count] = SysAllocString(path);
+            This->item_count++;
+        }
+        while (FindNextFileW(first_file, &file_info));
+
+        FindClose(first_file);
+    }
+
     *ppfi = (FolderItems*)&This->FolderItems3_iface;
-    return S_OK;
+    return ret;
+
+fail:
+    FolderItems3_Release(&This->FolderItems3_iface);
+    return ret;
 }
 
 static HRESULT WINAPI FolderImpl_QueryInterface(Folder3 *iface, REFIID riid,
@@ -1308,9 +1410,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/tests/shelldispatch.c b/dlls/shell32/tests/shelldispatch.c
index 0855e76..68025db 100644
--- a/dlls/shell32/tests/shelldispatch.c
+++ b/dlls/shell32/tests/shelldispatch.c
@@ -391,7 +391,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");
 
@@ -463,14 +462,11 @@ todo_wine
         r = FolderItems_Item(items, var, &item);
         if (i == VT_I2 || i == VT_I4 || i == VT_ERROR)
         {
-todo_wine
             ok(r == S_OK, "type %d: expected S_OK, got %08x\n", i, r);
-todo_wine
             ok(!!item, "item is null\n");
         }
         else if (i == VT_BSTR)
         {
-todo_wine
             ok(r == S_FALSE, "type %d: expected S_FALSE, got %08x\n", i, r);
             ok(!item, "item is not null\n");
         }
@@ -490,7 +486,6 @@ todo_wine
         V_VT(&var) = VT_BSTR;
         V_BSTR(&var) = SysAllocString(wstr);
         r = FolderItems_Item(items, var, &item);
-todo_wine
         ok(r == S_FALSE, "%d: expected S_FALSE, got %08x\n", i, r);
         ok(!item, "item is not null\n");
         SysFreeString(V_BSTR(&var));
@@ -502,31 +497,26 @@ todo_wine
         V_VT(&var) = VT_ERROR;
         V_ERROR(&var) = 0;
         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)
-        {
-            bstr = NULL;
-            r = FolderItem_get_Path(item, &bstr);
-            ok(r == S_OK, "FolderItem::get_Path failed: %08x\n", r);
-            ok(!!bstr, "bstr is null\n");
-            GetCurrentDirectoryW(MAX_PATH, wstr);
-            GetLongPathNameW(wstr, wstr2, MAX_PATH);
-            ok(!lstrcmpW(bstr, wstr2),
-               "expected %s, got %s\n", wine_dbgstr_w(wstr2), wine_dbgstr_w(bstr));
-
-            SysFreeString(bstr);
-            FolderItem_Release(item);
-        }
+
+        bstr = NULL;
+        r = FolderItem_get_Path(item, &bstr);
+        ok(r == S_OK, "FolderItem::get_Path failed: %08x\n", r);
+        ok(!!bstr, "bstr is null\n");
+        GetCurrentDirectoryW(MAX_PATH, wstr);
+        GetLongPathNameW(wstr, wstr2, MAX_PATH);
+        ok(!lstrcmpW(bstr, wstr2),
+           "expected %s, got %s\n", wine_dbgstr_w(wstr2), wine_dbgstr_w(bstr));
+
+        SysFreeString(bstr);
+        FolderItem_Release(item);
     }
 
     item = NULL;
     V_VT(&var) = VT_I4;
     V_I4(&var) = -1;
     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");
 
@@ -535,11 +525,8 @@ todo_wine
         item = NULL;
         V_I4(&var) = i;
         r = FolderItems_Item(items, var, &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) continue;
 
         r = FolderItems_Item(items, var, &item2);
         ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08x\n", i, r);
@@ -548,9 +535,12 @@ todo_wine
 
         disp = NULL;
         r = FolderItem_get_Application(item, &disp);
+todo_wine
         ok(r == S_OK, "file_defs[%d]: FolderItem::get_Application failed: %08x\n", i, r);
+todo_wine
         ok(!!disp, "file_defs[%d]: disp is null\n", i);
         r = FolderItem_get_Application(item, &disp2);
+todo_wine
         ok(r == S_OK, "file_defs[%d]: FolderItem::get_Application failed: %08x\n", i, r);
         ok(disp2 == disp, "file_defs[%d]: disp and disp2 are different\n", i);
         if (disp) IDispatch_Release(disp);
@@ -558,9 +548,12 @@ todo_wine
 
         disp = NULL;
         r = FolderItem_get_Parent(item, &disp);
+todo_wine
         ok(r == S_OK, "file_defs[%d]: FolderItem::get_Parent failed: %08x\n", i, r);
+todo_wine
         ok(!!disp, "file_defs[%d]: disp is null\n", i);
         r = FolderItem_get_Parent(item, &disp2);
+todo_wine
         ok(r == S_OK, "file_defs[%d]: FolderItem::get_Parent failed: %08x\n", i, r);
         ok(disp2 == disp, "file_defs[%d]: disp and disp2 different\n", i);
         if (disp) IDispatch_Release(disp);
@@ -579,21 +572,28 @@ todo_wine
 
         b = 0xbeef;
         r = FolderItem_get_IsLink(item, &b);
+todo_wine
         ok(r == S_OK, "file_defs[%d]: FolderItem::get_IsLink failed: %08x\n", i, r);
         disp = (IDispatch*)0xdeadbeef;
         r = FolderItem_get_GetLink(item, &disp);
         if (!lstrcmpA(PathFindExtensionA(file_defs[i].name), ".lnk"))
         {
+todo_wine
             ok(b == VARIANT_TRUE, "file_defs[%d]: expected VARIANT_TRUE, got %04x\n", i, b);
+todo_wine
             ok(r == S_OK, "file_defs[%d]: FolderItem::get_GetLink failed: %08x\n", i, r);
+todo_wine
             ok(!!disp, "file_defs[%d]: disp is null\n", i);
             r = FolderItem_get_GetLink(item, &disp2);
+todo_wine
             ok(r == S_OK, "file_defs[%d]: FolderItem::get_GetLink failed: %08x\n", i, r);
+todo_wine
             ok(disp2 != disp, "file_defs[%d]: disp and disp2 are the same\n", i);
             if (disp2) IDispatch_Release(disp2);
         }
         else
         {
+todo_wine
             ok(b == VARIANT_FALSE, "file_defs[%d]: expected VARIANT_FALSE, got %04x\n", i, b);
             ok(r == E_NOTIMPL || broken(r == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) /* xp */,
                "file_defs[%d]: expected E_NOTIMPL, got %08x\n", i, r);
@@ -603,22 +603,30 @@ todo_wine
 
         b = 0xbeef;
         r = FolderItem_get_IsFolder(item, &b);
+todo_wine
         ok(r == S_OK, "file_defs[%d]: FolderItem::get_IsFolder failed: %08x\n", i, r);
         disp = (IDispatch*)0xdeadbeef;
         r = FolderItem_get_GetFolder(item, &disp);
         if (file_defs[i].type == DIRECTORY)
         {
+todo_wine
             ok(b == VARIANT_TRUE, "file_defs[%d]: expected VARIANT_TRUE, got %04x\n", i, b);
+todo_wine
             ok(r == S_OK, "file_defs[%d]: FolderItem::get_GetFolder failed: %08x\n", i, r);
+todo_wine
             ok(!!disp, "file_defs[%d]: disp is null\n", i);
             r = FolderItem_get_GetFolder(item, &disp2);
+todo_wine
             ok(r == S_OK, "file_defs[%d]: FolderItem::get_GetFolder failed: %08x\n", i, r);
+todo_wine
             ok(disp2 != disp, "file_defs[%d]: disp and disp2 are the same\n", i);
             if (disp2) IDispatch_Release(disp2);
         }
         else
         {
+todo_wine
             ok(b == VARIANT_FALSE, "file_defs[%d]: expected VARIANT_FALSE, got %04x\n", i, b);
+todo_wine
             ok(r == E_FAIL || broken(r == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) /* xp */,
                "file_defs[%d]: expected E_FAIL, got %08x\n", i, r);
             ok(!disp, "file_defs[%d]: disp is not null\n", i);
@@ -627,10 +635,13 @@ todo_wine
 
         lcount = -1;
         r = FolderItem_get_Size(item, &lcount);
+todo_wine
         ok(r == S_OK, "file_defs[%d]: FolderItem::get_Size failed: %08x\n", i, r);
         if (file_defs[i].type == DIRECTORY || file_defs[i].type == EMPTY)
+todo_wine
             ok(!lcount, "file_defs[%d]: got %d\n", i, lcount);
         else
+todo_wine
             ok(lcount > 0, "file_defs[%d]: got %d\n", i, lcount);
 
         verbs = NULL;
@@ -649,7 +660,6 @@ todo_wine
     V_I4(&var) = sizeof(file_defs)/sizeof(file_defs[0]);
     item = 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");
 
-- 
2.9.0




More information about the wine-patches mailing list