[PATCH 4/6] shell32: Implement SHGetItemFromDataObject.

David Hedberg david.hedberg at gmail.com
Wed Jul 21 14:46:02 CDT 2010


---
 dlls/shell32/shell32.spec      |    1 +
 dlls/shell32/shellitem.c       |   99 +++++++++++++++++++++++++++++++++
 dlls/shell32/tests/shlfolder.c |  117 ++++++++++++++++++++++++++++++++++++++++
 include/shobjidl.idl           |   11 ++++
 4 files changed, 228 insertions(+), 0 deletions(-)

diff --git a/dlls/shell32/shell32.spec b/dlls/shell32/shell32.spec
index cc7744d..88f1f5d 100644
--- a/dlls/shell32/shell32.spec
+++ b/dlls/shell32/shell32.spec
@@ -360,6 +360,7 @@
 @ stdcall SHGetIconOverlayIndexA(str long)
 @ stdcall SHGetIconOverlayIndexW(wstr long)
 @ stdcall SHGetInstanceExplorer(long)
+@ stdcall SHGetItemFromDataObject(ptr long ptr ptr)
 @ stdcall SHGetLocalizedName(wstr ptr long ptr)
 @ stdcall SHGetMalloc(ptr)
 @ stdcall SHGetNameFromIDList(ptr long ptr)
diff --git a/dlls/shell32/shellitem.c b/dlls/shell32/shellitem.c
index 84a195f..523bdb9 100644
--- a/dlls/shell32/shellitem.c
+++ b/dlls/shell32/shellitem.c
@@ -437,3 +437,102 @@ HRESULT WINAPI SHCreateItemFromIDList(PCIDLIST_ABSOLUTE pidl, REFIID riid, void
 
     return ret;
 }
+
+HRESULT WINAPI SHGetItemFromDataObject(IDataObject *pdtobj,
+    DATAOBJ_GET_ITEM_FLAGS dwFlags, REFIID riid, void **ppv)
+{
+    FORMATETC fmt;
+    STGMEDIUM medium;
+    HRESULT ret;
+
+    TRACE("%p, %x, %s, %p\n", pdtobj, dwFlags, debugstr_guid(riid), ppv);
+
+    if(!pdtobj)
+        return E_INVALIDARG;
+
+    fmt.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
+    fmt.ptd = NULL;
+    fmt.dwAspect = DVASPECT_CONTENT;
+    fmt.lindex = -1;
+    fmt.tymed = TYMED_HGLOBAL;
+
+    ret = IDataObject_GetData(pdtobj, &fmt, &medium);
+    if(SUCCEEDED(ret))
+    {
+        LPIDA pida = GlobalLock(medium.u.hGlobal);
+
+        if((pida->cidl > 1 && !(dwFlags & DOGIF_ONLY_IF_ONE)) ||
+           pida->cidl == 1)
+        {
+            LPITEMIDLIST pidl;
+
+            /* Get the first pidl (parent + child1) */
+            pidl = ILCombine((LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[0]),
+                             (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[1]));
+
+            ret = SHCreateItemFromIDList(pidl, riid, ppv);
+            ILFree(pidl);
+        }
+        else
+        {
+            ret = E_FAIL;
+        }
+
+        GlobalUnlock(medium.u.hGlobal);
+        GlobalFree(medium.u.hGlobal);
+    }
+
+    if(FAILED(ret) && !(dwFlags & DOGIF_NO_HDROP))
+    {
+        TRACE("Attempting to fall back on CF_HDROP.\n");
+
+        fmt.cfFormat = CF_HDROP;
+        fmt.ptd = NULL;
+        fmt.dwAspect = DVASPECT_CONTENT;
+        fmt.lindex = -1;
+        fmt.tymed = TYMED_HGLOBAL;
+
+        ret = IDataObject_GetData(pdtobj, &fmt, &medium);
+        if(SUCCEEDED(ret))
+        {
+            DROPFILES *df = GlobalLock(medium.u.hGlobal);
+            LPBYTE files = (LPBYTE)df + df->pFiles;
+            BOOL multiple_files = FALSE;
+
+            ret = E_FAIL;
+            if(!df->fWide)
+            {
+                WCHAR filename[MAX_PATH];
+                PCSTR first_file = (PCSTR)files;
+                if(*(files + lstrlenA(first_file) + 1) != 0)
+                    multiple_files = TRUE;
+
+                if( !(multiple_files && (dwFlags & DOGIF_ONLY_IF_ONE)) )
+                {
+                    MultiByteToWideChar(CP_ACP, 0, first_file, -1, filename, MAX_PATH);
+                    ret = SHCreateItemFromParsingName(filename, NULL, riid, ppv);
+                }
+            }
+            else
+            {
+                PCWSTR first_file = (PCWSTR)files;
+                if(*((PCWSTR)files + lstrlenW(first_file) + 1) != 0)
+                    multiple_files = TRUE;
+
+                if( !(multiple_files && (dwFlags & DOGIF_ONLY_IF_ONE)) )
+                    ret = SHCreateItemFromParsingName(first_file, NULL, riid, ppv);
+            }
+
+            GlobalUnlock(medium.u.hGlobal);
+            GlobalFree(medium.u.hGlobal);
+        }
+    }
+
+    if(FAILED(ret) && !(dwFlags & DOGIF_NO_URL))
+    {
+        FIXME("Failed to create item, should try CF_URL.\n");
+    }
+
+    return ret;
+}
+
diff --git a/dlls/shell32/tests/shlfolder.c b/dlls/shell32/tests/shlfolder.c
index f386e40..b4dd6a8 100644
--- a/dlls/shell32/tests/shlfolder.c
+++ b/dlls/shell32/tests/shlfolder.c
@@ -59,6 +59,7 @@ static HRESULT (WINAPI *pSHCreateShellItem)(LPCITEMIDLIST,IShellFolder*,LPCITEMI
 static LPITEMIDLIST (WINAPI *pILCombine)(LPCITEMIDLIST,LPCITEMIDLIST);
 static HRESULT (WINAPI *pSHParseDisplayName)(LPCWSTR,IBindCtx*,LPITEMIDLIST*,SFGAOF,SFGAOF*);
 static HRESULT (WINAPI *pSHGetNameFromIDList)(PCIDLIST_ABSOLUTE,SIGDN,PWSTR*);
+static HRESULT (WINAPI *pSHGetItemFromDataObject)(IDataObject*,DATAOBJ_GET_ITEM_FLAGS,REFIID,void**);
 
 static void init_function_pointers(void)
 {
@@ -81,6 +82,7 @@ static void init_function_pointers(void)
     MAKEFUNC(SHGetSpecialFolderLocation);
     MAKEFUNC(SHParseDisplayName);
     MAKEFUNC(SHGetNameFromIDList);
+    MAKEFUNC(SHGetItemFromDataObject);
 #undef MAKEFUNC
 
 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
@@ -2291,6 +2293,120 @@ static void test_SHGetNameFromIDList(void)
     pILFree(pidl);
 }
 
+static void test_SHGetItemFromDataObject(void)
+{
+    IShellFolder *psfdesktop;
+    IShellItem *psi;
+    IShellView *psv;
+    HRESULT hres;
+
+    if(!pSHGetItemFromDataObject)
+    {
+        win_skip("No SHGetItemFromDataObject.\n");
+        return;
+    }
+
+    if(0)
+    {
+        /* Crashes under win7 */
+        hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, NULL);
+    }
+
+    hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, (void**)&psv);
+    ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
+
+    SHGetDesktopFolder(&psfdesktop);
+
+    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;
+
+        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, i;
+
+            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))
+                {
+                    hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
+                    ok(hres == S_OK, "got 0x%08x\n", hres);
+                    if(SUCCEEDED(hres)) IShellItem_Release(psi);
+                    hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
+                    ok(hres == S_OK, "got 0x%08x\n", hres);
+                    if(SUCCEEDED(hres)) IShellItem_Release(psi);
+                    hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
+                    ok(hres == S_OK, "got 0x%08x\n", hres);
+                    if(SUCCEEDED(hres)) IShellItem_Release(psi);
+                    hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
+                    ok(hres == S_OK, "got 0x%08x\n", hres);
+                    if(SUCCEEDED(hres)) IShellItem_Release(psi);
+                    hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
+                    ok(hres == S_OK, "got 0x%08x\n", hres);
+                    if(SUCCEEDED(hres)) IShellItem_Release(psi);
+
+                    IDataObject_Release(pdo);
+                }
+            }
+            else
+                skip("No file(s) 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))
+                {
+                    hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
+                    ok(hres == S_OK, "got 0x%08x\n", hres);
+                    if(SUCCEEDED(hres)) IShellItem_Release(psi);
+                    hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
+                    ok(hres == S_OK, "got 0x%08x\n", hres);
+                    if(SUCCEEDED(hres)) IShellItem_Release(psi);
+                    hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
+                    ok(hres == S_OK, "got 0x%08x\n", hres);
+                    if(SUCCEEDED(hres)) IShellItem_Release(psi);
+                    hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
+                    ok(hres == S_OK, "got 0x%08x\n", hres);
+                    if(SUCCEEDED(hres)) IShellItem_Release(psi);
+                    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);
+}
+
 static void test_SHParseDisplayName(void)
 {
     LPITEMIDLIST pidl1, pidl2;
@@ -2536,6 +2652,7 @@ START_TEST(shlfolder)
     test_desktop_IPersist();
     test_GetUIObject();
     test_SHGetNameFromIDList();
+    test_SHGetItemFromDataObject();
 
     OleUninitialize();
 }
diff --git a/include/shobjidl.idl b/include/shobjidl.idl
index d79c932..feee7ff 100644
--- a/include/shobjidl.idl
+++ b/include/shobjidl.idl
@@ -494,9 +494,20 @@ interface IShellItemArray : IUnknown
 
 }
 
+typedef [v1_enum] enum DATAOBJ_GET_ITEM_FLAGS
+{
+    DOGIF_DEFAULT       = 0x0,
+    DOGIF_TRAVERSE_LINK = 0x1,
+    DOGIF_NO_HDROP      = 0x2,
+    DOGIF_NO_URL        = 0x4,
+    DOGIF_ONLY_IF_ONE   = 0x8
+} DATAOBJ_GET_ITEM_FLAGS;
+cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(DATAOBJ_GET_ITEM_FLAGS)")
+
 cpp_quote("HRESULT WINAPI SHGetNameFromIDList(PCIDLIST_ABSOLUTE pidl, SIGDN sigdnName, PWSTR *ppszName);")
 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);")
 
 /*****************************************************************************
  * IShellItemFilter interface
-- 
1.7.1.1




More information about the wine-patches mailing list