shell32: Implement IEnumShellItems for IShellItemArray.

David Hedberg david.hedberg at gmail.com
Wed Jul 30 17:06:27 CDT 2014


Should fix #35987.
---
 dlls/shell32/shellitem.c       | 173 ++++++++++++++++++++++++++++++++++++++++-
 dlls/shell32/tests/shlfolder.c | 155 ++++++++++++++++++++++++++++++++++++
 2 files changed, 326 insertions(+), 2 deletions(-)

diff --git a/dlls/shell32/shellitem.c b/dlls/shell32/shellitem.c
index f58c566..8f42958 100644
--- a/dlls/shell32/shellitem.c
+++ b/dlls/shell32/shellitem.c
@@ -763,6 +763,172 @@ HRESULT WINAPI SHGetItemFromObject(IUnknown *punk, REFIID riid, void **ppv)
 }
 
 /*************************************************************************
+ * IEnumShellItems implementation
+ */
+typedef struct {
+    IEnumShellItems IEnumShellItems_iface;
+    LONG ref;
+
+    IShellItemArray *array;
+    DWORD count;
+    DWORD position;
+} IEnumShellItemsImpl;
+
+static inline IEnumShellItemsImpl *impl_from_IEnumShellItems(IEnumShellItems *iface)
+{
+    return CONTAINING_RECORD(iface, IEnumShellItemsImpl, IEnumShellItems_iface);
+}
+
+static HRESULT WINAPI IEnumShellItems_fnQueryInterface(IEnumShellItems *iface,
+                                                       REFIID riid,
+                                                       void **ppvObject)
+{
+    IEnumShellItemsImpl *This = impl_from_IEnumShellItems(iface);
+    TRACE("%p (%s, %p)\n", This, shdebugstr_guid(riid), ppvObject);
+
+    *ppvObject = NULL;
+    if(IsEqualIID(riid, &IID_IEnumShellItems) ||
+       IsEqualIID(riid, &IID_IUnknown))
+    {
+        *ppvObject = &This->IEnumShellItems_iface;
+    }
+
+    if(*ppvObject)
+    {
+        IUnknown_AddRef((IUnknown*)*ppvObject);
+        return S_OK;
+    }
+
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IEnumShellItems_fnAddRef(IEnumShellItems *iface)
+{
+    IEnumShellItemsImpl *This = impl_from_IEnumShellItems(iface);
+    LONG ref = InterlockedIncrement(&This->ref);
+    TRACE("%p - ref %d\n", This, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI IEnumShellItems_fnRelease(IEnumShellItems *iface)
+{
+    IEnumShellItemsImpl *This = impl_from_IEnumShellItems(iface);
+    LONG ref = InterlockedDecrement(&This->ref);
+    TRACE("%p - ref %d\n", This, ref);
+
+    if(!ref)
+    {
+        TRACE("Freeing.\n");
+        IShellItemArray_Release(This->array);
+        HeapFree(GetProcessHeap(), 0, This);
+        return 0;
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI IEnumShellItems_fnNext(IEnumShellItems* iface,
+                                             ULONG celt,
+                                             IShellItem **rgelt,
+                                             ULONG *pceltFetched)
+{
+    IEnumShellItemsImpl *This = impl_from_IEnumShellItems(iface);
+    HRESULT hr = S_FALSE;
+    UINT i;
+    ULONG fetched = 0;
+    TRACE("%p (%d %p %p)\n", This, celt, rgelt, pceltFetched);
+
+    if(pceltFetched == NULL && celt != 1)
+        return E_INVALIDARG;
+
+    for(i = This->position; fetched < celt && i < This->count; i++) {
+        hr = IShellItemArray_GetItemAt(This->array, i, &rgelt[fetched]);
+        if(FAILED(hr))
+            break;
+        fetched++;
+        This->position++;
+    }
+
+    if(SUCCEEDED(hr))
+    {
+        if(pceltFetched != NULL)
+            *pceltFetched = fetched;
+
+        if(fetched > 0)
+            return S_OK;
+
+        return S_FALSE;
+    }
+
+    return hr;
+}
+
+static HRESULT WINAPI IEnumShellItems_fnSkip(IEnumShellItems* iface, ULONG celt)
+{
+    IEnumShellItemsImpl *This = impl_from_IEnumShellItems(iface);
+    TRACE("%p (%d)\n", This, celt);
+
+    This->position = min(This->position + celt, This->count-1);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI IEnumShellItems_fnReset(IEnumShellItems* iface)
+{
+    IEnumShellItemsImpl *This = impl_from_IEnumShellItems(iface);
+    TRACE("%p\n", This);
+
+    This->position = 0;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI IEnumShellItems_fnClone(IEnumShellItems* iface, IEnumShellItems **ppenum)
+{
+    IEnumShellItemsImpl *This = impl_from_IEnumShellItems(iface);
+    TRACE("%p (%p)\n", This, ppenum);
+
+    /* Not implemented anywhere */
+
+    return E_NOTIMPL;
+}
+
+static const IEnumShellItemsVtbl vt_IEnumShellItems = {
+    IEnumShellItems_fnQueryInterface,
+    IEnumShellItems_fnAddRef,
+    IEnumShellItems_fnRelease,
+    IEnumShellItems_fnNext,
+    IEnumShellItems_fnSkip,
+    IEnumShellItems_fnReset,
+    IEnumShellItems_fnClone
+};
+
+static HRESULT IEnumShellItems_Constructor(IShellItemArray *array, IEnumShellItems **ppesi)
+{
+    IEnumShellItemsImpl *This;
+    HRESULT ret;
+
+    This = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumShellItemsImpl));
+    if(!This)
+        return E_OUTOFMEMORY;
+
+    This->ref = 1;
+    This->IEnumShellItems_iface.lpVtbl = &vt_IEnumShellItems;
+    This->array = array;
+    This->position = 0;
+
+    IShellItemArray_AddRef(This->array);
+    IShellItemArray_GetCount(This->array, &This->count);
+
+    ret = IEnumShellItems_QueryInterface(&This->IEnumShellItems_iface, &IID_IEnumShellItems, (void**)ppesi);
+    IEnumShellItems_Release(&This->IEnumShellItems_iface);
+
+    return ret;
+}
+
+
+/*************************************************************************
  * IShellItemArray implementation
  */
 typedef struct {
@@ -911,9 +1077,12 @@ static HRESULT WINAPI IShellItemArray_fnEnumItems(IShellItemArray *iface,
                                                   IEnumShellItems **ppenumShellItems)
 {
     IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
-    FIXME("Stub: %p (%p)\n", This, ppenumShellItems);
+    HRESULT hr;
+    TRACE("%p (%p)\n", This, ppenumShellItems);
 
-    return E_NOTIMPL;
+    hr = IEnumShellItems_Constructor(iface, ppenumShellItems);
+
+    return hr;
 }
 
 static const IShellItemArrayVtbl vt_IShellItemArray = {
diff --git a/dlls/shell32/tests/shlfolder.c b/dlls/shell32/tests/shlfolder.c
index e58a863..7a7674e 100644
--- a/dlls/shell32/tests/shlfolder.c
+++ b/dlls/shell32/tests/shlfolder.c
@@ -3545,6 +3545,160 @@ static void test_SHCreateShellItemArray(void)
     Cleanup();
 }
 
+static void test_ShellItemArrayEnumItems(void)
+{
+    IShellFolder *pdesktopsf, *psf;
+    IEnumIDList *peidl;
+    WCHAR cTestDirW[MAX_PATH];
+    HRESULT hr;
+    LPITEMIDLIST pidl_testdir;
+    static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
+
+    if(!pSHCreateShellItemArray)
+    {
+        win_skip("No SHCreateShellItemArray, skipping test..");
+        return;
+    }
+
+    CreateFilesFolders();
+
+    SHGetDesktopFolder(&pdesktopsf);
+
+    GetCurrentDirectoryW(MAX_PATH, cTestDirW);
+    myPathAddBackslashW(cTestDirW);
+    lstrcatW(cTestDirW, testdirW);
+
+    hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    if(SUCCEEDED(hr))
+    {
+        hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
+                                       (void**)&psf);
+        ok(hr == S_OK, "Got 0x%08x\n", hr);
+        if(SUCCEEDED(hr))
+            pILFree(pidl_testdir);
+    }
+    IShellFolder_Release(pdesktopsf);
+
+    hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
+    ok(hr == S_OK, "Got %08x\n", hr);
+    if(SUCCEEDED(hr))
+    {
+        IShellItemArray *psia;
+        LPITEMIDLIST apidl[5];
+        UINT done, numitems, i;
+
+        for(done = 0; done < 5; done++)
+            if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
+                break;
+        ok(done == 5, "Got %d pidls\n", done);
+        IEnumIDList_Release(peidl);
+
+        /* Create a ShellItemArray */
+        hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
+        ok(hr == S_OK, "Got 0x%08x\n", hr);
+        if(SUCCEEDED(hr))
+        {
+            IEnumShellItems *iesi;
+            IShellItem *my_array[10];
+            ULONG fetched;
+
+            IShellItemArray_GetCount(psia, &numitems);
+            ok(numitems == done, "Got %d, expected %d\n", numitems, done);
+
+            iesi = NULL;
+            hr = IShellItemArray_EnumItems(psia, &iesi);
+            ok(hr == S_OK, "Got 0x%08x\n", hr);
+            ok(iesi != NULL, "Got NULL\n");
+            if(SUCCEEDED(hr))
+            {
+                IEnumShellItems *iesi2;
+
+                /* This should fail according to the documentation and Win7+ */
+                for(i = 0; i < 10; i++) my_array[i] = (void*)0xdeadbeef;
+                hr = IEnumShellItems_Next(iesi, 2, my_array, NULL);
+                ok(hr == E_INVALIDARG || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
+                for(i = 0; i < 2; i++)
+                {
+                    ok(my_array[i] == (void*)0xdeadbeef ||
+                       broken(my_array[i] != (void*)0xdeadbeef && my_array[i] != NULL), /* Vista */
+                       "Got %p (%d)\n", my_array[i], i);
+
+                    if(my_array[i] != (void*)0xdeadbeef)
+                        IShellItem_Release(my_array[i]);
+                }
+                ok(my_array[2] == (void*)0xdeadbeef, "Got %p\n", my_array[2]);
+
+                IEnumShellItems_Reset(iesi);
+                for(i = 0; i < 10; i++) my_array[i] = (void*)0xdeadbeef;
+                hr = IEnumShellItems_Next(iesi, 1, my_array, NULL);
+                ok(hr == S_OK, "Got 0x%08x\n", hr);
+                ok(my_array[0] != NULL && my_array[0] != (void*)0xdeadbeef, "Got %p\n", my_array[0]);
+                if(my_array[0] != NULL && my_array[0] != (void*)0xdeadbeef)
+                    IShellItem_Release(my_array[0]);
+                ok(my_array[1] == (void*)0xdeadbeef, "Got %p\n", my_array[1]);
+
+                IEnumShellItems_Reset(iesi);
+                fetched = 0;
+                for(i = 0; i < 10; i++) my_array[i] = (void*)0xdeadbeef;
+                hr = IEnumShellItems_Next(iesi, numitems, my_array, &fetched);
+                ok(hr == S_OK, "Got 0x%08x\n", hr);
+                ok(fetched == numitems, "Got %d\n", fetched);
+                for(i = 0;i < numitems; i++)
+                {
+                    ok(my_array[i] != NULL && my_array[i] != (void*)0xdeadbeef,
+                       "Got %p at %d\n", my_array[i], i);
+
+                    if(my_array[i] != NULL && my_array[i] != (void*)0xdeadbeef)
+                        IShellItem_Release(my_array[i]);
+                }
+                ok(my_array[i] == (void*)0xdeadbeef, "Got %p\n", my_array[i]);
+
+                /* Compare all the items */
+                IEnumShellItems_Reset(iesi);
+                for(i = 0; i < numitems; i++)
+                {
+                    IShellItem *psi;
+                    int order;
+
+                    hr = IShellItemArray_GetItemAt(psia, i, &psi);
+                    ok(hr == S_OK, "Got 0x%08x\n", hr);
+                    hr = IEnumShellItems_Next(iesi, 1, my_array, &fetched);
+                    ok(hr == S_OK, "Got 0x%08x\n", hr);
+                    ok(fetched == 1, "Got %d\n", fetched);
+
+                    hr = IShellItem_Compare(psi, my_array[0], 0, &order);
+                    ok(hr == S_OK, "Got 0x%08x\n", hr);
+                    ok(order == 0, "Got %d\n", order);
+
+                    IShellItem_Release(psi);
+                    IShellItem_Release(my_array[0]);
+                }
+
+                my_array[0] = (void*)0xdeadbeef;
+                hr = IEnumShellItems_Next(iesi, 1, my_array, &fetched);
+                ok(hr == S_FALSE, "Got 0x%08x\n", hr);
+                ok(fetched == 0, "Got %d\n", fetched);
+                ok(my_array[0] == (void*)0xdeadbeef, "Got %p\n", my_array[0]);
+
+                /* Cloning not implemented anywhere */
+                iesi2 = (void*)0xdeadbeef;
+                hr = IEnumShellItems_Clone(iesi, &iesi2);
+                ok(hr == E_NOTIMPL, "Got 0x%08x\n", hr);
+                ok(iesi2 == (void*)0xdeadbeef, "Got %p\n", iesi2);
+
+                IEnumShellItems_Release(iesi);
+            }
+
+            IShellItemArray_Release(psia);
+        }
+
+        for(i = 0; i < done; i++)
+            pILFree(apidl[i]);
+    }
+}
+
+
 static void test_ShellItemBindToHandler(void)
 {
     IShellItem *psi;
@@ -4760,6 +4914,7 @@ START_TEST(shlfolder)
     test_LocalizedNames();
     test_SHCreateShellItem();
     test_SHCreateShellItemArray();
+    test_ShellItemArrayEnumItems();
     test_desktop_IPersist();
     test_GetUIObject();
     test_SHSimpleIDListFromPath();
-- 
2.0.1




More information about the wine-patches mailing list