diff --git a/dlls/shell32/shell32.spec b/dlls/shell32/shell32.spec index cc7744d0a2e..88f1f5da70e 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 84a195fb11a..6abc02c7e6c 100644 --- a/dlls/shell32/shellitem.c +++ b/dlls/shell32/shellitem.c @@ -437,3 +437,101 @@ 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 7eda9914140..485cefd2544 100644 --- a/dlls/shell32/tests/shlfolder.c +++ b/dlls/shell32/tests/shlfolder.c @@ -60,6 +60,7 @@ static LPITEMIDLIST (WINAPI *pILCombine)(LPCITEMIDLIST,LPCITEMIDLIST); static HRESULT (WINAPI *pSHParseDisplayName)(LPCWSTR,IBindCtx*,LPITEMIDLIST*,SFGAOF,SFGAOF*); 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 void init_function_pointers(void) { @@ -82,6 +83,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))) @@ -2293,6 +2295,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; @@ -2799,6 +2915,7 @@ START_TEST(shlfolder) test_SHSimpleIDListFromPath(); test_ParseDisplayNamePBC(); test_SHGetNameFromIDList(); + test_SHGetItemFromDataObject(); OleUninitialize(); } diff --git a/include/shobjidl.idl b/include/shobjidl.idl index d79c932bc56..feee7ff7ab6 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