shell32: Implement IEnumShellItems for IShellItemArray. (try2)
David Hedberg
david.hedberg at gmail.com
Thu Jul 31 04:53:18 CDT 2014
Try2: Set the returned pointer to null in ::Clone();
Should fix #35987.
---
dlls/shell32/shellitem.c | 174 ++++++++++++++++++++++++++++++++++++++++-
dlls/shell32/tests/shlfolder.c | 155 ++++++++++++++++++++++++++++++++++++
2 files changed, 327 insertions(+), 2 deletions(-)
diff --git a/dlls/shell32/shellitem.c b/dlls/shell32/shellitem.c
index f58c566..b26c099 100644
--- a/dlls/shell32/shellitem.c
+++ b/dlls/shell32/shellitem.c
@@ -763,6 +763,173 @@ 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 */
+ *ppenum = NULL;
+
+ 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 +1078,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..295904e 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 == NULL || broken(iesi2 == (void*)0xdeadbeef) /* Vista */, "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