[PATCH 3/5] shell32: Initial implementation of IShellItemArray with SHCreateShellItemArray. (try 2)

David Hedberg david.hedberg at gmail.com
Mon Jul 26 04:54:03 CDT 2010


Moved it to into shellitem.c.

---
 dlls/shell32/shell32.spec      |    1 +
 dlls/shell32/shellitem.c       |  237 +++++++++++++++++++++++++++++++++++++++-
 dlls/shell32/tests/shlfolder.c |  132 ++++++++++++++++++++++
 include/shobjidl.idl           |    1 +
 4 files changed, 370 insertions(+), 1 deletions(-)

diff --git a/dlls/shell32/shell32.spec b/dlls/shell32/shell32.spec
index ed61f0b..426e841 100644
--- a/dlls/shell32/shell32.spec
+++ b/dlls/shell32/shell32.spec
@@ -334,6 +334,7 @@
 @ stdcall SHCreateItemFromParsingName(wstr ptr ptr ptr)
 @ stub SHCreateProcessAsUserW
 @ stdcall SHCreateShellItem(ptr ptr ptr ptr)
+@ stdcall SHCreateShellItemArray(ptr ptr long ptr ptr)
 @ stdcall SHEmptyRecycleBinA(long str long)
 @ stdcall SHEmptyRecycleBinW(long wstr long)
 @ stub SHExtractIconsW
diff --git a/dlls/shell32/shellitem.c b/dlls/shell32/shellitem.c
index bbd85e6..8dd6239 100644
--- a/dlls/shell32/shellitem.c
+++ b/dlls/shell32/shellitem.c
@@ -1,5 +1,5 @@
 /*
- * IShellItem implementation
+ * IShellItem and IShellItemArray implementations
  *
  * Copyright 2008 Vincent Povirk for CodeWeavers
  *
@@ -592,3 +592,238 @@ HRESULT WINAPI SHGetItemFromObject(IUnknown *punk, REFIID riid, void **ppv)
 
     return ret;
 }
+
+/*************************************************************************
+ * IShellItemArray implementation
+ */
+typedef struct {
+    const IShellItemArrayVtbl *lpVtbl;
+    LONG ref;
+
+    IShellItem **array;
+    DWORD item_count;
+} IShellItemArrayImpl;
+
+static HRESULT WINAPI IShellItemArray_fnQueryInterface(IShellItemArray *iface,
+                                                       REFIID riid,
+                                                       void **ppvObject)
+{
+    IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
+    TRACE("%p (%s, %p)\n", This, shdebugstr_guid(riid), ppvObject);
+
+    *ppvObject = NULL;
+    if(IsEqualIID(riid, &IID_IShellItemArray) ||
+       IsEqualIID(riid, &IID_IUnknown))
+    {
+        *ppvObject = This;
+    }
+
+    if(*ppvObject)
+    {
+        IUnknown_AddRef((IUnknown*)*ppvObject);
+        return S_OK;
+    }
+
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IShellItemArray_fnAddRef(IShellItemArray *iface)
+{
+    IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
+    LONG ref = InterlockedIncrement(&This->ref);
+    TRACE("%p - ref %d\n", This, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI IShellItemArray_fnRelease(IShellItemArray *iface)
+{
+    IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
+    LONG ref = InterlockedDecrement(&This->ref);
+    TRACE("%p - ref %d\n", This, ref);
+
+    if(!ref)
+    {
+        UINT i;
+        TRACE("Freeing.\n");
+
+        for(i = 0; i < This->item_count; i++)
+            IShellItem_Release(This->array[i]);
+
+        HeapFree(GetProcessHeap(), 0, This->array);
+        HeapFree(GetProcessHeap(), 0, This);
+        return 0;
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI IShellItemArray_fnBindToHandler(IShellItemArray *iface,
+                                                      IBindCtx *pbc,
+                                                      REFGUID bhid,
+                                                      REFIID riid,
+                                                      void **ppvOut)
+{
+    IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
+    FIXME("Stub: %p (%p, %s, %s, %p)\n",
+          This, pbc, shdebugstr_guid(bhid), shdebugstr_guid(riid), ppvOut);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IShellItemArray_fnGetPropertyStore(IShellItemArray *iface,
+                                                         GETPROPERTYSTOREFLAGS flags,
+                                                         REFIID riid,
+                                                         void **ppv)
+{
+    IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
+    FIXME("Stub: %p (%x, %s, %p)\n", This, flags, shdebugstr_guid(riid), ppv);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IShellItemArray_fnGetPropertyDescriptionList(IShellItemArray *iface,
+                                                                   REFPROPERTYKEY keyType,
+                                                                   REFIID riid,
+                                                                   void **ppv)
+{
+    IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
+    FIXME("Stub: %p (%p, %s, %p)\n",
+          This, keyType, shdebugstr_guid(riid), ppv);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IShellItemArray_fnGetAttributes(IShellItemArray *iface,
+                                                      SIATTRIBFLAGS AttribFlags,
+                                                      SFGAOF sfgaoMask,
+                                                      SFGAOF *psfgaoAttribs)
+{
+    IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
+    FIXME("Stub: %p (%x, %x, %p)\n", This, AttribFlags, sfgaoMask, psfgaoAttribs);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IShellItemArray_fnGetCount(IShellItemArray *iface,
+                                                 DWORD *pdwNumItems)
+{
+    IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
+    TRACE("%p (%p)\n", This, pdwNumItems);
+
+    *pdwNumItems = This->item_count;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI IShellItemArray_fnGetItemAt(IShellItemArray *iface,
+                                                  DWORD dwIndex,
+                                                  IShellItem **ppsi)
+{
+    IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
+    TRACE("%p (%x, %p)\n", This, dwIndex, ppsi);
+
+    /* zero indexed */
+    if(dwIndex + 1 > This->item_count)
+        return E_FAIL;
+
+    *ppsi = This->array[dwIndex];
+    IShellItem_AddRef(*ppsi);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI IShellItemArray_fnEnumItems(IShellItemArray *iface,
+                                                  IEnumShellItems **ppenumShellItems)
+{
+    IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
+    FIXME("Stub: %p (%p)\n", This, ppenumShellItems);
+
+    return E_NOTIMPL;
+}
+
+static const IShellItemArrayVtbl vt_IShellItemArray = {
+    IShellItemArray_fnQueryInterface,
+    IShellItemArray_fnAddRef,
+    IShellItemArray_fnRelease,
+    IShellItemArray_fnBindToHandler,
+    IShellItemArray_fnGetPropertyStore,
+    IShellItemArray_fnGetPropertyDescriptionList,
+    IShellItemArray_fnGetAttributes,
+    IShellItemArray_fnGetCount,
+    IShellItemArray_fnGetItemAt,
+    IShellItemArray_fnEnumItems
+};
+
+static HRESULT WINAPI IShellItemArray_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
+{
+    IShellItemArrayImpl *This;
+    HRESULT ret;
+
+    TRACE("(%p, %s, %p)\n",pUnkOuter, debugstr_guid(riid), ppv);
+
+    if(pUnkOuter)
+        return CLASS_E_NOAGGREGATION;
+
+    This = HeapAlloc(GetProcessHeap(), 0, sizeof(IShellItemArrayImpl));
+    if(!This)
+        return E_OUTOFMEMORY;
+
+    This->ref = 1;
+    This->lpVtbl = &vt_IShellItemArray;
+
+    ret = IShellItemArray_QueryInterface((IShellItemArray*)This, riid, ppv);
+    IShellItemArray_Release((IShellItemArray*)This);
+
+    return ret;
+}
+
+HRESULT WINAPI SHCreateShellItemArray(PCIDLIST_ABSOLUTE pidlParent,
+                                      IShellFolder *psf,
+                                      UINT cidl,
+                                      PCUITEMID_CHILD_ARRAY ppidl,
+                                      IShellItemArray **ppsiItemArray)
+{
+    IShellItemArrayImpl *This;
+    IShellItem **array;
+    HRESULT ret = E_FAIL;
+    UINT i;
+
+    TRACE("%p, %p, %d, %p, %p\n", pidlParent, psf, cidl, ppidl, ppsiItemArray);
+
+    if(!pidlParent && !psf)
+        return E_POINTER;
+
+    if(!ppidl)
+        return E_INVALIDARG;
+
+    array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cidl*sizeof(IShellItem*));
+    if(!array)
+        return E_OUTOFMEMORY;
+
+    for(i = 0; i < cidl; i++)
+    {
+        ret = SHCreateShellItem(pidlParent, psf, ppidl[i], &array[i]);
+        if(FAILED(ret)) break;
+    }
+
+    if(SUCCEEDED(ret))
+    {
+        ret = IShellItemArray_Constructor(NULL, &IID_IShellItemArray, (void**)&This);
+        if(SUCCEEDED(ret))
+        {
+            This->array = array;
+            This->item_count = cidl;
+            *ppsiItemArray = (IShellItemArray*)This;
+
+            return ret;
+        }
+    }
+
+    /* Something failed, clean up. */
+    for(i = 0; i < cidl; i++)
+        if(array[i]) IShellItem_Release(array[i]);
+    HeapFree(GetProcessHeap(), 0, array);
+    *ppsiItemArray = NULL;
+    return ret;
+}
diff --git a/dlls/shell32/tests/shlfolder.c b/dlls/shell32/tests/shlfolder.c
index 2781b23..491327e 100644
--- a/dlls/shell32/tests/shlfolder.c
+++ b/dlls/shell32/tests/shlfolder.c
@@ -58,6 +58,7 @@ static BOOL (WINAPI *pILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST);
 static HRESULT (WINAPI *pSHCreateItemFromIDList)(PCIDLIST_ABSOLUTE pidl, REFIID riid, void **ppv);
 static HRESULT (WINAPI *pSHCreateItemFromParsingName)(PCWSTR,IBindCtx*,REFIID,void**);
 static HRESULT (WINAPI *pSHCreateShellItem)(LPCITEMIDLIST,IShellFolder*,LPCITEMIDLIST,IShellItem**);
+static HRESULT (WINAPI *pSHCreateShellItemArray)(LPCITEMIDLIST,IShellFolder*,UINT,LPCITEMIDLIST*,IShellItemArray**);
 static LPITEMIDLIST (WINAPI *pILCombine)(LPCITEMIDLIST,LPCITEMIDLIST);
 static HRESULT (WINAPI *pSHParseDisplayName)(LPCWSTR,IBindCtx*,LPITEMIDLIST*,SFGAOF,SFGAOF*);
 static LPITEMIDLIST (WINAPI *pSHSimpleIDListFromPathAW)(LPCVOID);
@@ -79,6 +80,7 @@ static void init_function_pointers(void)
     MAKEFUNC(SHCreateItemFromIDList);
     MAKEFUNC(SHCreateItemFromParsingName);
     MAKEFUNC(SHCreateShellItem);
+    MAKEFUNC(SHCreateShellItemArray);
     MAKEFUNC(SHGetFolderPathA);
     MAKEFUNC(SHGetFolderPathAndSubDirA);
     MAKEFUNC(SHGetPathFromIDListW);
@@ -2930,6 +2932,135 @@ static void test_SHGetItemFromObject(void)
     IShellFolder_Release(psfdesktop);
 }
 
+static void test_SHCreateShellItemArray(void)
+{
+    IShellFolder *pdesktopsf, *psf;
+    IShellItemArray *psia;
+    IEnumIDList *peidl;
+    HRESULT hr;
+    WCHAR cTestDirW[MAX_PATH];
+    LPITEMIDLIST pidl_testdir, pidl;
+    static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
+
+    if(!pSHCreateShellItemArray) {
+        skip("No pSHCreateShellItemArray!\n");
+        return;
+    }
+
+    ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
+
+    if(0)
+    {
+        /* Crashes under native */
+        pSHCreateShellItemArray(NULL, NULL, 0, NULL, NULL);
+        pSHCreateShellItemArray(NULL, NULL, 1, NULL, NULL);
+        pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, NULL);
+        pSHCreateShellItemArray(pidl, NULL, 0, NULL, NULL);
+    }
+
+    hr = pSHCreateShellItemArray(NULL, NULL, 0, NULL, &psia);
+    ok(hr == E_POINTER, "got 0x%08x\n", hr);
+
+    SHGetDesktopFolder(&pdesktopsf);
+    hr = pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, &psia);
+    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+
+    hr = pSHCreateShellItemArray(NULL, pdesktopsf, 1, NULL, &psia);
+    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+
+    pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
+    hr = pSHCreateShellItemArray(pidl, NULL, 0, NULL, &psia);
+    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+    pILFree(pidl);
+
+    GetCurrentDirectoryW(MAX_PATH, cTestDirW);
+    myPathAddBackslashW(cTestDirW);
+    lstrcatW(cTestDirW, testdirW);
+
+    CreateFilesFolders();
+
+    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);
+    }
+    IShellFolder_Release(pdesktopsf);
+
+    if(FAILED(hr))
+    {
+        skip("Failed to set up environment for SHCreateShellItemArray tests.\n");
+        pILFree(pidl_testdir);
+        Cleanup();
+        return;
+    }
+
+    hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
+    ok(hr == S_OK, "Got %08x\n", hr);
+    if(SUCCEEDED(hr))
+    {
+        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))
+        {
+            IShellItem *psi;
+
+            if(0)
+            {
+                /* Crashes in Windows 7 */
+                hr = IShellItemArray_GetCount(psia, NULL);
+            }
+
+            IShellItemArray_GetCount(psia, &numitems);
+            ok(numitems == done, "Got %d, expected %d\n", numitems, done);
+
+            hr = IShellItemArray_GetItemAt(psia, numitems, &psi);
+            ok(hr == E_FAIL, "Got 0x%08x\n", hr);
+
+            /* Compare all the items */
+            for(i = 0; i < numitems; i++)
+            {
+                LPITEMIDLIST pidl_abs;
+                pidl_abs = ILCombine(pidl_testdir, apidl[i]);
+
+                hr = IShellItemArray_GetItemAt(psia, i, &psi);
+                ok(hr == S_OK, "(%d) Failed with 0x%08x\n", i, hr);
+                if(SUCCEEDED(hr))
+                {
+                    hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
+                    ok(hr == S_OK, "Got 0x%08x\n", hr);
+                    if(SUCCEEDED(hr))
+                    {
+                        ok(ILIsEqual(pidl_abs, pidl), "Pidl not equal.\n");
+                        pILFree(pidl);
+                    }
+                    IShellItem_Release(psi);
+                }
+                pILFree(pidl_abs);
+            }
+            for(i = 0; i < done; i++)
+                pILFree(apidl[i]);
+            IShellItemArray_Release(psia);
+        }
+    }
+
+    IShellFolder_Release(psf);
+    pILFree(pidl_testdir);
+    Cleanup();
+}
+
 static void test_SHParseDisplayName(void)
 {
     LPITEMIDLIST pidl1, pidl2;
@@ -3431,6 +3562,7 @@ START_TEST(shlfolder)
     test_SHGetFolderPathAndSubDirA();
     test_LocalizedNames();
     test_SHCreateShellItem();
+    test_SHCreateShellItemArray();
     test_desktop_IPersist();
     test_GetUIObject();
     test_SHSimpleIDListFromPath();
diff --git a/include/shobjidl.idl b/include/shobjidl.idl
index 6bd6b07..d982cc1 100644
--- a/include/shobjidl.idl
+++ b/include/shobjidl.idl
@@ -517,6 +517,7 @@ cpp_quote("HRESULT WINAPI SHCreateItemFromIDList(PCIDLIST_ABSOLUTE pidl, REFIID
 cpp_quote("HRESULT WINAPI SHGetItemFromDataObject(IDataObject *pdtobj, DATAOBJ_GET_ITEM_FLAGS dwFlags, REFIID riid, void **ppv);")
 cpp_quote("HRESULT WINAPI SHGetIDListFromObject(IUnknown *punk, PIDLIST_ABSOLUTE *ppidl);")
 cpp_quote("HRESULT WINAPI SHGetItemFromObject(IUnknown *punk, REFIID riid, void **ppv);")
+cpp_quote("HRESULT WINAPI SHCreateShellItemArray(PCIDLIST_ABSOLUTE pidlParent, IShellFolder* psf, UINT cidl, PCUITEMID_CHILD_ARRAY ppidl, IShellItemArray **ppsiItemArray);")
 
 /*****************************************************************************
  * IShellItemFilter interface
-- 
1.7.1.1




More information about the wine-patches mailing list