shell32: Implement IEnumShellItems for IShellItemArray.
This commit is contained in:
parent
e6cb2dbaca
commit
d016dc4004
|
@ -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 = {
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue