[PATCH 5/6] shell32: Implement SHGetIDListFromObject. (resend)

David Hedberg david.hedberg at gmail.com
Thu Jul 22 13:17:06 CDT 2010


---
 dlls/shell32/pidl.c            |   75 ++++++++++++++
 dlls/shell32/shell32.spec      |    1 +
 dlls/shell32/tests/shlfolder.c |  219 ++++++++++++++++++++++++++++++++++++++++
 include/shobjidl.idl           |    1 +
 4 files changed, 296 insertions(+), 0 deletions(-)

diff --git a/dlls/shell32/pidl.c b/dlls/shell32/pidl.c
index 9ec0dd4..a596ebf 100644
--- a/dlls/shell32/pidl.c
+++ b/dlls/shell32/pidl.c
@@ -1405,6 +1405,81 @@ HRESULT WINAPI SHGetNameFromIDList(PCIDLIST_ABSOLUTE pidl, SIGDN sigdnName, PWST
 
         IShellFolder_Release(psfparent);
     }
+    return ret;
+}
+
+/*************************************************************************
+ * SHGetIDListFromObject             [SHELL32.@]
+ */
+HRESULT WINAPI SHGetIDListFromObject(IUnknown *punk, PIDLIST_ABSOLUTE *ppidl)
+{
+    IPersistIDList *ppersidl;
+    IPersistFolder2 *ppf2;
+    IDataObject *pdo;
+    IFolderView *pfv;
+    HRESULT ret;
+
+    if(!punk)
+        return E_NOINTERFACE;
+
+    *ppidl = NULL;
+
+    /* Try IPersistIDList */
+    ret = IUnknown_QueryInterface(punk, &IID_IPersistIDList, (void**)&ppersidl);
+    if(SUCCEEDED(ret))
+    {
+        TRACE("IPersistIDList (%p)\n", ppersidl);
+        ret = IPersistIDList_GetIDList(ppersidl, ppidl);
+        IPersistIDList_Release(ppersidl);
+        if(SUCCEEDED(ret))
+            return ret;
+    }
+
+    /* Try IPersistFolder2 */
+    ret = IUnknown_QueryInterface(punk, &IID_IPersistFolder2, (void**)&ppf2);
+    if(SUCCEEDED(ret))
+    {
+        TRACE("IPersistFolder2 (%p)\n", ppf2);
+        ret = IPersistFolder2_GetCurFolder(ppf2, ppidl);
+        IPersistFolder2_Release(ppf2);
+        if(SUCCEEDED(ret))
+            return ret;
+    }
+
+    /* Try IDataObject */
+    ret = IUnknown_QueryInterface(punk, &IID_IDataObject, (void**)&pdo);
+    if(SUCCEEDED(ret))
+    {
+        IShellItem *psi;
+        TRACE("IDataObject (%p)\n", pdo);
+        ret = SHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE,
+                                      &IID_IShellItem, (void**)&psi);
+        if(SUCCEEDED(ret))
+        {
+            ret = SHGetIDListFromObject((IUnknown*)psi, ppidl);
+            IShellItem_Release(psi);
+        }
+        IDataObject_Release(pdo);
+
+        if(SUCCEEDED(ret))
+            return ret;
+    }
+
+    /* Try IFolderView */
+    ret = IUnknown_QueryInterface(punk, &IID_IFolderView, (void**)&pfv);
+    if(SUCCEEDED(ret))
+    {
+        IShellFolder *psf;
+        TRACE("IFolderView (%p)\n", pfv);
+        ret = IFolderView_GetFolder(pfv, &IID_IShellFolder, (void**)&psf);
+        if(SUCCEEDED(ret))
+        {
+            /* We might be able to get IPersistFolder2 from a shellfolder. */
+            ret = SHGetIDListFromObject((IUnknown*)psf, ppidl);
+        }
+        IFolderView_Release(pfv);
+        return ret;
+    }
 
     return ret;
 }
diff --git a/dlls/shell32/shell32.spec b/dlls/shell32/shell32.spec
index 88f1f5d..c11f20e 100644
--- a/dlls/shell32/shell32.spec
+++ b/dlls/shell32/shell32.spec
@@ -359,6 +359,7 @@
 @ stub SHGetFreeDiskSpace
 @ stdcall SHGetIconOverlayIndexA(str long)
 @ stdcall SHGetIconOverlayIndexW(wstr long)
+@ stdcall SHGetIDListFromObject(ptr ptr)
 @ stdcall SHGetInstanceExplorer(long)
 @ stdcall SHGetItemFromDataObject(ptr long ptr ptr)
 @ stdcall SHGetLocalizedName(wstr ptr long ptr)
diff --git a/dlls/shell32/tests/shlfolder.c b/dlls/shell32/tests/shlfolder.c
index 485cefd..cf7150e 100644
--- a/dlls/shell32/tests/shlfolder.c
+++ b/dlls/shell32/tests/shlfolder.c
@@ -39,6 +39,8 @@
 
 #include "wine/test.h"
 
+#include <initguid.h>
+DEFINE_GUID(IID_IParentAndItem, 0xB3A4B685, 0xB685, 0x4805, 0x99,0xD9, 0x5D,0xEA,0xD2,0x87,0x32,0x36);
 
 static IMalloc *ppM;
 
@@ -61,6 +63,7 @@ static HRESULT (WINAPI *pSHParseDisplayName)(LPCWSTR,IBindCtx*,LPITEMIDLIST*,SFG
 static LPITEMIDLIST (WINAPI *pSHSimpleIDListFromPathAW)(LPCVOID);
 static HRESULT (WINAPI *pSHGetNameFromIDList)(PCIDLIST_ABSOLUTE,SIGDN,PWSTR*);
 static HRESULT (WINAPI *pSHGetItemFromDataObject)(IDataObject*,DATAOBJ_GET_ITEM_FLAGS,REFIID,void**);
+static HRESULT (WINAPI *pSHGetIDListFromObject)(IUnknown*, PIDLIST_ABSOLUTE*);
 
 static void init_function_pointers(void)
 {
@@ -84,6 +87,7 @@ static void init_function_pointers(void)
     MAKEFUNC(SHParseDisplayName);
     MAKEFUNC(SHGetNameFromIDList);
     MAKEFUNC(SHGetItemFromDataObject);
+    MAKEFUNC(SHGetIDListFromObject);
 #undef MAKEFUNC
 
 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
@@ -2390,6 +2394,219 @@ static void test_SHGetItemFromDataObject(void)
                     hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
                     ok(hres == E_FAIL, "got 0x%08x\n", hres);
                     if(SUCCEEDED(hres)) IShellItem_Release(psi);
+                    IDataObject_Release(pdo);
+                }
+            }
+            else
+                skip("zero or one file found - skipping multi-file test.\n");
+
+            for(i = 0; i < count; i++)
+                pILFree(apidl[i]);
+
+            IEnumIDList_Release(peidl);
+        }
+
+        IShellView_Release(psv);
+    }
+
+    IShellFolder_Release(psfdesktop);
+}
+
+/**************************************************************/
+/* IUnknown implementation for counting QueryInterface calls. */
+typedef struct {
+    const IUnknownVtbl *lpVtbl;
+    struct if_count {
+        REFIID id;
+        LONG count;
+    } *ifaces;
+    LONG unknown;
+} IUnknownImpl;
+
+static HRESULT WINAPI unk_fnQueryInterface(IUnknown *iunk, REFIID riid, void** punk)
+{
+    IUnknownImpl *This = (IUnknownImpl*)iunk;
+    UINT i, found;
+    for(i = found = 0; This->ifaces[i].id != NULL; i++)
+    {
+        if(IsEqualIID(This->ifaces[i].id, riid))
+        {
+            This->ifaces[i].count++;
+            found = 1;
+            break;
+        }
+    }
+    if(!found)
+        This->unknown++;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI unk_fnAddRef(IUnknown *iunk)
+{
+    return 2;
+}
+
+static ULONG WINAPI unk_fnRelease(IUnknown *iunk)
+{
+    return 1;
+}
+
+const IUnknownVtbl vt_IUnknown = {
+    unk_fnQueryInterface,
+    unk_fnAddRef,
+    unk_fnRelease
+};
+
+static void test_SHGetIDListFromObject(void)
+{
+    IUnknownImpl *punkimpl;
+    IShellFolder *psfdesktop;
+    IShellView *psv;
+    LPITEMIDLIST pidl, pidl_desktop;
+    HRESULT hres;
+    UINT i;
+    struct if_count ifaces[] =
+        { {&IID_IPersistIDList, 0},
+          {&IID_IPersistFolder2, 0},
+          {&IID_IDataObject, 0},
+          {&IID_IParentAndItem, 0},
+          {&IID_IFolderView, 0},
+          {NULL, 0} };
+
+    if(!pSHGetIDListFromObject)
+    {
+        win_skip("SHGetIDListFromObject missing.\n");
+        return;
+    }
+
+    ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
+
+    if(0)
+    {
+        /* Crashes native */
+        pSHGetIDListFromObject(NULL, NULL);
+        pSHGetIDListFromObject((void*)0xDEADBEEF, NULL);
+    }
+
+    hres = pSHGetIDListFromObject(NULL, &pidl);
+    ok(hres == E_NOINTERFACE, "Got %x\n", hres);
+
+    punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
+    punkimpl->lpVtbl = &vt_IUnknown;
+    punkimpl->ifaces = ifaces;
+    punkimpl->unknown = 0;
+
+    hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
+    ok(hres == E_NOINTERFACE, "Got %x\n", hres);
+    ok(ifaces[0].count, "interface not requested.\n");
+    ok(ifaces[1].count, "interface not requested.\n");
+    ok(ifaces[2].count, "interface not requested.\n");
+    todo_wine
+        ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
+           "interface not requested.\n");
+    ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
+       "interface not requested.\n");
+
+    ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
+    HeapFree(GetProcessHeap(), 0, punkimpl);
+
+    pidl_desktop = NULL;
+    pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
+    ok(pidl_desktop != NULL, "Failed to get desktop pidl.\n");
+
+    SHGetDesktopFolder(&psfdesktop);
+
+    /* Test IShellItem */
+    if(pSHCreateShellItem)
+    {
+        IShellItem *shellitem;
+        hres = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
+        ok(hres == S_OK, "got 0x%08x\n", hres);
+        if(SUCCEEDED(hres))
+        {
+            hres = pSHGetIDListFromObject((IUnknown*)shellitem, &pidl);
+            ok(hres == S_OK, "got 0x%08x\n", hres);
+            if(SUCCEEDED(hres))
+            {
+                ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
+                pILFree(pidl);
+            }
+            IShellItem_Release(shellitem);
+        }
+    }
+    else
+        skip("no SHCreateShellItem.\n");
+
+    /* Test IShellFolder */
+    hres = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl);
+    ok(hres == S_OK, "got 0x%08x\n", hres);
+    if(SUCCEEDED(hres))
+    {
+        ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
+        pILFree(pidl);
+    }
+
+    hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
+    ok(hres == S_OK, "got 0x%08x\n", hres);
+    if(SUCCEEDED(hres))
+    {
+        IEnumIDList *peidl;
+        IDataObject *pdo;
+        SHCONTF enum_flags;
+
+        /* Test IFolderView */
+        hres = pSHGetIDListFromObject((IUnknown*)psv, &pidl);
+        ok(hres == S_OK, "got 0x%08x\n", hres);
+        if(SUCCEEDED(hres))
+        {
+            ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
+            pILFree(pidl);
+        }
+
+        /* Test IDataObject */
+        enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
+        hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
+        ok(hres == S_OK, "got 0x%08x\n", hres);
+        if(SUCCEEDED(hres))
+        {
+            LPITEMIDLIST apidl[5];
+            UINT count = 0;
+            for(count = 0; count < 5; count++)
+                if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
+                    break;
+
+            if(count)
+            {
+                hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
+                                                  &IID_IDataObject, NULL, (void**)&pdo);
+                ok(hres == S_OK, "got 0x%08x\n", hres);
+                if(SUCCEEDED(hres))
+                {
+                    pidl = (void*)0xDEADBEEF;
+                    hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
+                    ok(hres == S_OK, "got 0x%08x\n", hres);
+                    ok(pidl != NULL, "pidl is NULL.\n");
+                    ok(ILIsEqual(pidl, apidl[0]), "pidl not equal.\n");
+                    pILFree(pidl);
+
+                    IDataObject_Release(pdo);
+                }
+            }
+            else
+                skip("No files found - skipping single-file test.\n");
+
+            if(count > 1)
+            {
+                hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
+                                                  &IID_IDataObject, NULL, (void**)&pdo);
+                ok(hres == S_OK, "got 0x%08x\n", hres);
+                if(SUCCEEDED(hres))
+                {
+                    pidl = (void*)0xDEADBEEF;
+                    hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
+                    ok(hres == E_NOINTERFACE || hres == E_FAIL /*Vista*/,
+                       "got 0x%08x\n", hres);
+                    ok(pidl == NULL, "pidl is not NULL.\n");
 
                     IDataObject_Release(pdo);
                 }
@@ -2407,6 +2624,7 @@ static void test_SHGetItemFromDataObject(void)
     }
 
     IShellFolder_Release(psfdesktop);
+    pILFree(pidl_desktop);
 }
 
 static void test_SHParseDisplayName(void)
@@ -2916,6 +3134,7 @@ START_TEST(shlfolder)
     test_ParseDisplayNamePBC();
     test_SHGetNameFromIDList();
     test_SHGetItemFromDataObject();
+    test_SHGetIDListFromObject();
 
     OleUninitialize();
 }
diff --git a/include/shobjidl.idl b/include/shobjidl.idl
index feee7ff..19dcd28 100644
--- a/include/shobjidl.idl
+++ b/include/shobjidl.idl
@@ -508,6 +508,7 @@ cpp_quote("HRESULT WINAPI SHGetNameFromIDList(PCIDLIST_ABSOLUTE pidl, SIGDN sigd
 cpp_quote("HRESULT WINAPI SHCreateItemFromParsingName(PCWSTR pszPath, IBindCtx *pbc, REFIID riid, void **ppv);")
 cpp_quote("HRESULT WINAPI SHCreateItemFromIDList(PCIDLIST_ABSOLUTE pidl, REFIID riid, void **ppv);")
 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);")
 
 /*****************************************************************************
  * IShellItemFilter interface
-- 
1.7.1.1




More information about the wine-patches mailing list