shell32: Implement IEnumShellItems for IShellItemArray.

This commit is contained in:
David Hedberg 2014-07-31 11:53:18 +02:00 committed by Alexandre Julliard
parent e6cb2dbaca
commit d016dc4004
2 changed files with 327 additions and 2 deletions

View File

@ -769,6 +769,173 @@ HRESULT WINAPI SHGetItemFromObject(IUnknown *punk, REFIID riid, void **ppv)
return ret;
}
/*************************************************************************
* 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
*/
@ -955,9 +1122,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 = {

View File

@ -3728,6 +3728,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;
@ -5090,6 +5244,7 @@ START_TEST(shlfolder)
test_LocalizedNames();
test_SHCreateShellItem();
test_SHCreateShellItemArray();
test_ShellItemArrayEnumItems();
test_desktop_IPersist();
test_GetUIObject();
test_SHSimpleIDListFromPath();