From b8a40388ee8d3c763034a32c8c7f29bfdf7edcb2 Mon Sep 17 00:00:00 2001 From: David Hedberg Date: Thu, 22 Jul 2010 20:17:06 +0200 Subject: [PATCH] shell32: Implement SHGetIDListFromObject. --- 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(+) diff --git a/dlls/shell32/pidl.c b/dlls/shell32/pidl.c index 9ec0dd4ef1d..a596ebfedc4 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 88f1f5da70e..c11f20ee068 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 485cefd2544..cf7150ea547 100644 --- a/dlls/shell32/tests/shlfolder.c +++ b/dlls/shell32/tests/shlfolder.c @@ -39,6 +39,8 @@ #include "wine/test.h" +#include +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 feee7ff7ab6..19dcd28e2db 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