Based on SHBindToParent and SHBindToObject implementations.
Signed-off-by: Dmitry Timoshkov <dmitry(a)baikal.ru>
---
dlls/shell32/pidl.c | 46 +++++++++++++++++++++++++++++
dlls/shell32/shell32.spec | 1 +
dlls/shell32/tests/shlfolder.c | 53 ++++++++++++++++++++++++++++++++++
3 files changed, 100 insertions(+)
diff --git a/dlls/shell32/pidl.c b/dlls/shell32/pidl.c
index f9c91a79132..8d42f58acc7 100644
--- a/dlls/shell32/pidl.c
+++ b/dlls/shell32/pidl.c
@@ -1364,6 +1364,52 @@ HRESULT WINAPI SHBindToObject(IShellFolder *psf, LPCITEMIDLIST pidl, IBindCtx *p
}
+HRESULT WINAPI SHBindToFolderIDListParent(IShellFolder *psf, LPCITEMIDLIST pidl,
+ REFIID riid, void **ppv, LPCITEMIDLIST *ppidlLast)
+{
+ IShellFolder *psfDesktop = NULL;
+ HRESULT hr;
+
+ TRACE_(shell)("%p,%p,%s,%p,%p\n", psf, pidl, debugstr_guid(riid), ppv, ppidlLast);
+ pdump(pidl);
+
+ *ppv = NULL;
+ if (ppidlLast)
+ *ppidlLast = NULL;
+
+ if (!pidl)
+ return E_INVALIDARG;
+
+ if (!psf)
+ {
+ hr = SHGetDesktopFolder(&psfDesktop);
+ if (FAILED(hr))
+ return hr;
+ psf = psfDesktop;
+ }
+
+ if (_ILIsPidlSimple(pidl))
+ /* we are on desktop level */
+ hr = IShellFolder_QueryInterface(psf, riid, ppv);
+ else
+ {
+ LPITEMIDLIST pidlParent = ILClone(pidl);
+ ILRemoveLastID(pidlParent);
+ hr = IShellFolder_BindToObject(psf, pidlParent, NULL, riid, ppv);
+ SHFree(pidlParent);
+ }
+
+ if (psfDesktop)
+ IShellFolder_Release(psfDesktop);
+
+ if (SUCCEEDED(hr) && ppidlLast)
+ *ppidlLast = ILFindLastID(pidl);
+
+ TRACE_(shell)("-- psf=%p pidl=%p ret=0x%08lx\n", *ppv, ppidlLast ? *ppidlLast : NULL, hr);
+ return hr;
+}
+
+
/*************************************************************************
* SHParseDisplayName [SHELL32.@]
*/
diff --git a/dlls/shell32/shell32.spec b/dlls/shell32/shell32.spec
index f8bf8f246e8..5b812774e1f 100644
--- a/dlls/shell32/shell32.spec
+++ b/dlls/shell32/shell32.spec
@@ -334,6 +334,7 @@
@ stdcall SHAssocEnumHandlers(wstr long ptr)
@ stdcall SHBindToObject(ptr ptr ptr ptr ptr)
@ stdcall SHBindToParent(ptr ptr ptr ptr)
+@ stdcall SHBindToFolderIDListParent(ptr ptr ptr ptr ptr)
@ stdcall SHBrowseForFolder(ptr) SHBrowseForFolderA
@ stdcall SHBrowseForFolderA(ptr)
@ stdcall SHBrowseForFolderW(ptr)
diff --git a/dlls/shell32/tests/shlfolder.c b/dlls/shell32/tests/shlfolder.c
index da606a9e707..1c482c06407 100644
--- a/dlls/shell32/tests/shlfolder.c
+++ b/dlls/shell32/tests/shlfolder.c
@@ -60,6 +60,7 @@ static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
static HRESULT (WINAPI *pSHCreateDefaultContextMenu)(const DEFCONTEXTMENU*,REFIID,void**);
static BOOL (WINAPI *pSHGetPathFromIDListEx)(PCIDLIST_ABSOLUTE,WCHAR*,DWORD,GPFIDL_FLAGS);
static HRESULT (WINAPI *pSHGetSetFolderCustomSettings)(LPSHFOLDERCUSTOMSETTINGS,PCWSTR,DWORD);
+static HRESULT (WINAPI *pSHBindToFolderIDListParent)(IShellFolder*,LPCITEMIDLIST,REFIID,void **,LPCITEMIDLIST*);
static WCHAR *make_wstr(const char *str)
{
@@ -89,6 +90,7 @@ static void init_function_pointers(void)
hmod = GetModuleHandleA("shell32.dll");
#define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hmod, #f))
+ MAKEFUNC(SHBindToFolderIDListParent);
MAKEFUNC(SHCreateItemFromIDList);
MAKEFUNC(SHCreateItemFromParsingName);
MAKEFUNC(SHCreateItemFromRelativeName);
@@ -5410,6 +5412,56 @@ static void test_SHGetSetFolderCustomSettings(void)
RemoveDirectoryW(pathW);
}
+static void test_SHBindToFolderIDListParent(void)
+{
+ IShellFolder *psf_desktop;
+ LPITEMIDLIST pidl;
+ HRESULT hr;
+ WCHAR path[MAX_PATH];
+ SHITEMID empty_item = { 0, { 0 } };
+ LPITEMIDLIST pidl_empty = (LPITEMIDLIST)&empty_item;
+ LPCITEMIDLIST pidl_last;
+ IShellFolder *psf;
+
+ if (!pSHBindToFolderIDListParent)
+ {
+ win_skip("SHBindToFolderIDListParent not available\n");
+ return;
+ }
+
+ GetTempPathW(ARRAY_SIZE(path), path);
+ SHGetDesktopFolder(&psf_desktop);
+
+ hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, path, NULL, &pidl, 0);
+ ok(hr == S_OK, "got %#lx\n", hr);
+
+ pidl_last = NULL;
+ hr = pSHBindToFolderIDListParent(psf_desktop, pidl, &IID_IShellFolder, (void **)&psf, &pidl_last);
+ ok(hr == S_OK, "got %#lx\n", hr);
+ ok(pidl_last != NULL, "got %p\n", pidl_last);
+ IShellFolder_Release(psf);
+
+ hr = pSHBindToFolderIDListParent(NULL, pidl_empty, &IID_IShellFolder, (void **)&psf, &pidl_last);
+ ok(hr == S_OK, "got %#lx\n", hr);
+ ok(pidl_last == pidl_empty, "got %p\n", pidl_last);
+ IShellFolder_Release(psf);
+
+ hr = pSHBindToFolderIDListParent(NULL, pidl, &IID_IShellFolder, (void **)&psf, NULL);
+ ok(hr == S_OK, "got %#lx\n", hr);
+ IShellFolder_Release(psf);
+
+ if (0) /* crashes under Windows */
+ hr = pSHBindToFolderIDListParent(NULL, pidl, &IID_IShellFolder, NULL, NULL);
+
+ ILFree(pidl);
+ IShellFolder_Release(psf_desktop);
+
+ pidl_last = (LPITEMIDLIST)0xdeadbeef;
+ hr = pSHBindToFolderIDListParent(NULL, NULL, &IID_IShellFolder, (void **)&psf, &pidl_last);
+ ok(hr == E_INVALIDARG, "got %#lx\n", hr);
+ ok(pidl_last == NULL, "got %p\n", pidl_last);
+}
+
START_TEST(shlfolder)
{
init_function_pointers();
@@ -5417,6 +5469,7 @@ START_TEST(shlfolder)
CO_E_NOTINITIALIZED for malformed directory names */
OleInitialize(NULL);
+ test_SHBindToFolderIDListParent();
test_ParseDisplayName();
test_SHParseDisplayName();
test_BindToObject();
--
2.36.1