[PATCH 2/5] shell32: Use shellfolder API to construct FolderItems

Nikolay Sivov nsivov at codeweavers.com
Sun Sep 24 12:38:45 CDT 2017


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/shell32/shelldispatch.c       | 195 ++++++++++++++++++++++---------------
 dlls/shell32/tests/shelldispatch.c |   3 +
 2 files changed, 118 insertions(+), 80 deletions(-)

diff --git a/dlls/shell32/shelldispatch.c b/dlls/shell32/shelldispatch.c
index 8742cb3efd..a5236b971b 100644
--- a/dlls/shell32/shelldispatch.c
+++ b/dlls/shell32/shelldispatch.c
@@ -73,7 +73,7 @@ typedef struct {
     FolderItems3 FolderItems3_iface;
     LONG ref;
     FolderImpl *folder;
-    WCHAR **item_filenames;
+    WCHAR **item_names;
     LONG item_count;
 } FolderItemsImpl;
 
@@ -1023,8 +1023,8 @@ static ULONG WINAPI FolderItemsImpl_Release(FolderItems3 *iface)
     {
         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);
+            HeapFree(GetProcessHeap(), 0, This->item_names[i]);
+        HeapFree(GetProcessHeap(), 0, This->item_names);
         HeapFree(GetProcessHeap(), 0, This);
     }
     return ref;
@@ -1111,16 +1111,16 @@ static HRESULT WINAPI FolderItemsImpl_get_Parent(FolderItems3 *iface, IDispatch
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI FolderItemsImpl_Item(FolderItems3 *iface, VARIANT index, FolderItem **ppid)
+static HRESULT WINAPI FolderItemsImpl_Item(FolderItems3 *iface, VARIANT index, FolderItem **item)
 {
     FolderItemsImpl *This = impl_from_FolderItems(iface);
-    WCHAR canonicalized_index[MAX_PATH], path_str[MAX_PATH];
-    VARIANT path_var;
-    HRESULT ret;
+    WCHAR buffW[MAX_PATH], *display_name;
+    HRESULT hr;
+    VARIANT v;
 
-    TRACE("(%p,%s,%p)\n", iface, debugstr_variant(&index), ppid);
+    TRACE("(%p,%s,%p)\n", iface, debugstr_variant(&index), item);
 
-    *ppid = NULL;
+    *item = NULL;
 
     if (!PathIsDirectoryW(V_BSTR(&This->folder->dir)))
         return S_FALSE;
@@ -1135,41 +1135,41 @@ 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->folder->dir), This->item_filenames[V_I4(&index)]))
-                return S_FALSE;
-
+            display_name = This->item_names[V_I4(&index)];
             break;
 
         case VT_BSTR:
-            if (!V_BSTR(&index))
-                return S_FALSE;
-
-            if (!PathCanonicalizeW(canonicalized_index, V_BSTR(&index)))
-                return S_FALSE;
+        {
+            LPITEMIDLIST pidl;
+            STRRET strret;
 
-            if (strcmpW(V_BSTR(&index), canonicalized_index) != 0)
+            if (!V_BSTR(&index))
                 return S_FALSE;
 
-            if (!PathCombineW(path_str, V_BSTR(&This->folder->dir), V_BSTR(&index)))
+            if (FAILED(hr = IShellFolder2_ParseDisplayName(This->folder->folder, NULL, NULL, V_BSTR(&index),
+                    NULL, &pidl, NULL)))
                 return S_FALSE;
 
-            if (!PathFileExistsW(path_str))
-                return S_FALSE;
+            IShellFolder2_GetDisplayNameOf(This->folder->folder, pidl, SHGDN_FORPARSING, &strret);
+            StrRetToBufW(&strret, NULL, buffW, sizeof(buffW)/sizeof(*buffW));
+            ILFree(pidl);
 
+            display_name = buffW;
             break;
-
+        }
         case VT_ERROR:
-            return FolderItem_Constructor(This->folder, &This->folder->dir, ppid);
+            return FolderItem_Constructor(This->folder, &This->folder->dir, item);
 
         default:
+            FIXME("Index type %d not handled.\n", V_VT(&index));
             return E_NOTIMPL;
     }
 
-    V_VT(&path_var) = VT_BSTR;
-    V_BSTR(&path_var) = SysAllocString(path_str);
-    ret = FolderItem_Constructor(This->folder, &path_var, ppid);
-    VariantClear(&path_var);
-    return ret;
+    V_VT(&v) = VT_BSTR;
+    V_BSTR(&v) = SysAllocString(display_name);
+    hr = FolderItem_Constructor(This->folder, &v, item);
+    VariantClear(&v);
+    return hr;
 }
 
 static HRESULT WINAPI FolderItemsImpl__NewEnum(FolderItems3 *iface, IUnknown **ppunk)
@@ -1226,21 +1226,49 @@ static const FolderItems3Vtbl FolderItemsImpl_Vtbl = {
     FolderItemsImpl_get_Verbs
 };
 
-static HRESULT FolderItems_Constructor(FolderImpl *folder, FolderItems **ppfi)
+static void idlist_sort(LPITEMIDLIST *idlist, unsigned int l, unsigned int r, IShellFolder2 *folder)
 {
-    static const WCHAR backslash_star[] = {'\\','*',0};
-    static const WCHAR dot[] = {'.',0};
-    static const WCHAR dot_dot[] = {'.','.',0};
+    unsigned int m;
+
+    if (l == r)
+        return;
+
+    if (r < l)
+    {
+        idlist_sort(idlist, r, l, folder);
+        return;
+    }
+
+    m = (l + r) / 2;
+    idlist_sort(idlist, l, m, folder);
+    idlist_sort(idlist, m + 1, r, folder);
+
+    /* join the two sides */
+    while (l <= m && m < r)
+    {
+        if (HRESULT_CODE(IShellFolder2_CompareIDs(folder, 0, idlist[l], idlist[m + 1]) > 0))
+        {
+            LPITEMIDLIST t = idlist[m + 1];
+            memmove(&idlist[l + 1], &idlist[l], (m - l + 1) * sizeof(idlist[l]));
+            idlist[l] = t;
+
+            m++;
+        }
+        l++;
+    }
+}
+
+static HRESULT FolderItems_Constructor(FolderImpl *folder, FolderItems **ret)
+{
+    IEnumIDList *enumidlist;
     FolderItemsImpl *This;
-    LONG item_size;
-    WCHAR glob[MAX_PATH + 2];
-    HANDLE first_file;
-    WIN32_FIND_DATAW file_info;
-    WCHAR **filenames;
+    LPITEMIDLIST pidl;
+    unsigned int i;
+    HRESULT hr;
 
-    TRACE("(%s,%p)\n", debugstr_variant(&folder->dir), ppfi);
+    TRACE("(%s,%p)\n", debugstr_variant(&folder->dir), ret);
 
-    *ppfi = NULL;
+    *ret = NULL;
 
     if (V_VT(&folder->dir) == VT_I4)
     {
@@ -1248,61 +1276,68 @@ static HRESULT FolderItems_Constructor(FolderImpl *folder, FolderItems **ppfi)
         return E_NOTIMPL;
     }
 
-    This = HeapAlloc(GetProcessHeap(), 0, sizeof(FolderItemsImpl));
-    if (!This) return E_OUTOFMEMORY;
+    This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
+    if (!This)
+        return E_OUTOFMEMORY;
+
     This->FolderItems3_iface.lpVtbl = &FolderItemsImpl_Vtbl;
     This->ref = 1;
     This->folder = folder;
     Folder3_AddRef(&folder->Folder3_iface);
 
-    This->item_count = 0;
-    lstrcpyW(glob, V_BSTR(&folder->dir));
-    lstrcatW(glob, backslash_star);
-    first_file = FindFirstFileW(glob, &file_info);
-    if (first_file != INVALID_HANDLE_VALUE)
+    enumidlist = NULL;
+    if (FAILED(hr = IShellFolder2_EnumObjects(folder->folder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS,
+            &enumidlist)))
     {
-        item_size = 128;
-        This->item_filenames = HeapAlloc(GetProcessHeap(), 0, item_size * sizeof(WCHAR*));
-        if (!This->item_filenames)
-            goto fail;
+        goto failed;
+    }
 
-        do
+    while (IEnumIDList_Next(enumidlist, 1, &pidl, NULL) == S_OK)
+    {
+        This->item_count++;
+        ILFree(pidl);
+    }
+
+    if (This->item_count)
+    {
+        LPITEMIDLIST *pidls = HeapAlloc(GetProcessHeap(), 0, This->item_count * sizeof(*pidls));
+        This->item_names = HeapAlloc(GetProcessHeap(), 0, This->item_count * sizeof(*This->item_names));
+
+        if (!pidls || !This->item_names)
         {
-            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++;
+            HeapFree(GetProcessHeap(), 0, pidls);
+            HeapFree(GetProcessHeap(), 0, This->item_names);
+            hr = E_OUTOFMEMORY;
+            goto failed;
         }
-        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;
+        IEnumIDList_Reset(enumidlist);
+        if (IEnumIDList_Next(enumidlist, This->item_count, pidls, NULL) == S_OK)
+            idlist_sort(pidls, 0, This->item_count - 1, folder->folder);
+
+        for (i = 0; i < This->item_count; i++)
+        {
+            WCHAR buffW[MAX_PATH];
+            STRRET strret;
+
+            IShellFolder2_GetDisplayNameOf(folder->folder, pidls[i], SHGDN_FORPARSING, &strret);
+            StrRetToBufW(&strret, NULL, buffW, sizeof(buffW)/sizeof(*buffW));
+
+            This->item_names[i] = strdupW(buffW);
+
+            ILFree(pidls[i]);
+        }
+        HeapFree(GetProcessHeap(), 0, pidls);
     }
+    IEnumIDList_Release(enumidlist);
 
-    *ppfi = (FolderItems*)&This->FolderItems3_iface;
+    *ret = (FolderItems *)&This->FolderItems3_iface;
     return S_OK;
 
-fail:
-    FindClose(first_file);
-    FolderItems3_Release(&This->FolderItems3_iface);
-    return E_OUTOFMEMORY;
+failed:
+    if (enumidlist)
+        IEnumIDList_Release(enumidlist);
+    return hr;
 }
 
 static HRESULT WINAPI FolderImpl_QueryInterface(Folder3 *iface, REFIID riid,
diff --git a/dlls/shell32/tests/shelldispatch.c b/dlls/shell32/tests/shelldispatch.c
index 21cb6bb519..8495373cd4 100644
--- a/dlls/shell32/tests/shelldispatch.c
+++ b/dlls/shell32/tests/shelldispatch.c
@@ -653,8 +653,11 @@ static void test_items(void)
             variant_set_string(&str_index2, cstr);
             item2 = (FolderItem*)0xdeadbeef;
             r = FolderItems_Item(items, str_index2, &item2);
+       todo_wine {
             ok(r == S_FALSE, "file_defs[%d]: expected S_FALSE, got %08x\n", i, r);
             ok(!item2, "file_defs[%d]: item is not null\n", i);
+       }
+            if (item2) FolderItem_Release(item2);
             VariantClear(&str_index2);
 
             /* remove the directory */
-- 
2.14.1




More information about the wine-patches mailing list