Zhiyi Zhang : shell32: Implement SHOpenFolderAndSelectItems().
Alexandre Julliard
julliard at winehq.org
Fri Jul 15 14:44:42 CDT 2022
Module: wine
Branch: master
Commit: c03409e9d782ccd96ce4f14913814acc0184ee43
URL: https://gitlab.winehq.org/wine/wine/-/commit/c03409e9d782ccd96ce4f14913814acc0184ee43
Author: Zhiyi Zhang <zzhang at codeweavers.com>
Date: Fri Jul 8 17:13:49 2022 +0800
shell32: Implement SHOpenFolderAndSelectItems().
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=39987
Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
dlls/shell32/shlfolder.c | 138 ++++++++++++++++++++++++++++++++++++++++-
dlls/shell32/tests/shlfolder.c | 11 ----
programs/explorer/explorer.c | 39 ++++++++++++
3 files changed, 175 insertions(+), 13 deletions(-)
diff --git a/dlls/shell32/shlfolder.c b/dlls/shell32/shlfolder.c
index 7308f49c7d5..ab99ed6b4c9 100644
--- a/dlls/shell32/shlfolder.c
+++ b/dlls/shell32/shlfolder.c
@@ -618,8 +618,142 @@ HRESULT WINAPI SHCreateLinks( HWND hWnd, LPCSTR lpszDir, LPDATAOBJECT lpDataObje
HRESULT WINAPI SHOpenFolderAndSelectItems(PCIDLIST_ABSOLUTE pidlFolder, UINT cidl,
PCUITEMID_CHILD_ARRAY apidl, DWORD flags)
{
- FIXME("%p %u %p 0x%lx: stub\n", pidlFolder, cidl, apidl, flags);
- return E_NOTIMPL;
+ static const unsigned int magic = 0xe32ee32e;
+ unsigned int i, uint_flags, size, child_count = 0;
+ const ITEMIDLIST *pidl_parent, *pidl_child;
+ VARIANT var_parent, var_empty;
+ ITEMIDLIST *pidl_tmp = NULL;
+ SHELLEXECUTEINFOW sei = {0};
+ COPYDATASTRUCT cds = {0};
+ IDispatch *dispatch;
+ int timeout = 1000;
+ unsigned char *ptr;
+ IShellWindows *sw;
+ BOOL ret = FALSE;
+ HRESULT hr;
+ LONG hwnd;
+
+ TRACE("%p %u %p 0x%lx\n", pidlFolder, cidl, apidl, flags);
+
+ if (!pidlFolder)
+ return E_INVALIDARG;
+
+ if (flags & OFASI_OPENDESKTOP)
+ FIXME("Ignoring unsupported OFASI_OPENDESKTOP flag.\n");
+
+ if (flags & OFASI_EDIT && cidl > 1)
+ flags &= ~OFASI_EDIT;
+
+ hr = CoCreateInstance(&CLSID_ShellWindows, NULL, CLSCTX_LOCAL_SERVER, &IID_IShellWindows,
+ (void **)&sw);
+ if (FAILED(hr))
+ return hr;
+
+ if (!cidl)
+ {
+ pidl_tmp = ILClone(pidlFolder);
+ ILRemoveLastID(pidl_tmp);
+ pidl_parent = pidl_tmp;
+
+ pidl_child = ILFindLastID(pidlFolder);
+ apidl = &pidl_child;
+ cidl = 1;
+ }
+ else
+ {
+ pidl_parent = pidlFolder;
+ }
+
+ /* Find the existing explorer window for the parent path. Create a new one if not present. */
+ VariantInit(&var_empty);
+ VariantInit(&var_parent);
+ size = ILGetSize(pidl_parent);
+ V_VT(&var_parent) = VT_ARRAY | VT_UI1;
+ V_ARRAY(&var_parent) = SafeArrayCreateVector(VT_UI1, 0, size);
+ memcpy(V_ARRAY(&var_parent)->pvData, pidl_parent, size);
+ hr = IShellWindows_FindWindowSW(sw, &var_parent, &var_empty, SWC_EXPLORER, &hwnd, 0, &dispatch);
+ if (hr != S_OK)
+ {
+ sei.cbSize = sizeof(sei);
+ sei.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_IDLIST | SEE_MASK_NOASYNC | SEE_MASK_WAITFORINPUTIDLE;
+ sei.lpVerb = L"explore";
+ sei.lpIDList = (void *)pidl_parent;
+ sei.nShow = SW_NORMAL;
+ if (!ShellExecuteExW(&sei))
+ {
+ WARN("Failed to create a explorer window.\n");
+ goto done;
+ }
+
+ while (timeout > 0)
+ {
+ hr = IShellWindows_FindWindowSW(sw, &var_parent, &var_empty, SWC_EXPLORER, &hwnd, 0,
+ &dispatch);
+ if (hr == S_OK)
+ break;
+
+ timeout -= 100;
+ Sleep(100);
+ }
+
+ if (hr != S_OK)
+ {
+ WARN("Failed to find the explorer window.\n");
+ goto done;
+ }
+ }
+
+ /* Send WM_COPYDATA to tell explorer.exe to open windows */
+ size = sizeof(cidl) + sizeof(uint_flags);
+ for (i = 0; i < cidl; ++i)
+ size += ILGetSize(apidl[i]);
+
+ cds.dwData = magic;
+ cds.cbData = size;
+ cds.lpData = malloc(size);
+ if (!cds.lpData)
+ {
+ hr = E_OUTOFMEMORY;
+ goto done;
+ }
+
+ /* Add the count of child ITEMIDLIST, set its value at the end */
+ ptr = (unsigned char *)cds.lpData + sizeof(cidl);
+
+ /* Add flags. Have to use unsigned int because DWORD may have a different size */
+ uint_flags = flags;
+ memcpy(ptr, &uint_flags, sizeof(uint_flags));
+ ptr += sizeof(uint_flags);
+
+ /* Add child ITEMIDLIST */
+ for (i = 0; i < cidl; ++i)
+ {
+ if (apidl != &pidl_child)
+ pidl_child = ILFindChild(pidl_parent, apidl[i]);
+
+ if (pidl_child)
+ {
+ size = ILGetSize(pidl_child);
+ memcpy(ptr, pidl_child, size);
+ ptr += size;
+ ++child_count;
+ }
+ }
+
+ /* Set the count of child ITEMIDLIST */
+ memcpy(cds.lpData, &child_count, sizeof(child_count));
+
+ SetForegroundWindow(GetAncestor((HWND)(LONG_PTR)hwnd, GA_ROOT));
+ ret = SendMessageW((HWND)(LONG_PTR)hwnd, WM_COPYDATA, 0, (LPARAM)&cds);
+ hr = ret ? S_OK : E_FAIL;
+
+done:
+ free(cds.lpData);
+ VariantClear(&var_parent);
+ if (pidl_tmp)
+ ILFree(pidl_tmp);
+ IShellWindows_Release(sw);
+ return hr;
}
/***********************************************************************
diff --git a/dlls/shell32/tests/shlfolder.c b/dlls/shell32/tests/shlfolder.c
index 10a989e9ca4..267c81a0ec5 100644
--- a/dlls/shell32/tests/shlfolder.c
+++ b/dlls/shell32/tests/shlfolder.c
@@ -5448,15 +5448,12 @@ static void test_SHOpenFolderAndSelectItems(void)
/* NULL folder */
hr = SHOpenFolderAndSelectItems(NULL, 0, NULL, 0);
- todo_wine
ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
/* Open and select folder without child items */
folder = ILCreateFromPathW(L"C:\\Windows\\System32");
hr = SHOpenFolderAndSelectItems(folder, 0, NULL, 0);
- todo_wine
ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
- todo_wine
ok(check_window_exists("Windows"), "Failed to create window.\n");
ILFree(folder);
@@ -5464,9 +5461,7 @@ static void test_SHOpenFolderAndSelectItems(void)
folder = ILCreateFromPathW(L"C:\\Windows");
items[0] = ILCreateFromPathW(L"C:\\Windows\\System32");
hr = SHOpenFolderAndSelectItems(folder, 1, (PCUITEMID_CHILD_ARRAY)items, 0);
- todo_wine
ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
- todo_wine
ok(check_window_exists("Windows"), "Failed to create window.\n");
ILFree(items[0]);
ILFree(folder);
@@ -5476,9 +5471,7 @@ static void test_SHOpenFolderAndSelectItems(void)
items[0] = ILCreateFromPathW(L"C:\\Windows\\System32");
items[1] = ILCreateFromPathW(L"C:\\Windows\\Resources");
hr = SHOpenFolderAndSelectItems(folder, 2, (PCUITEMID_CHILD_ARRAY)items, 0);
- todo_wine
ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
- todo_wine
ok(check_window_exists("Windows"), "Failed to create window.\n");
ILFree(items[1]);
ILFree(items[0]);
@@ -5488,9 +5481,7 @@ static void test_SHOpenFolderAndSelectItems(void)
folder = ILCreateFromPathW(L"C:\\Windows");
items[0] = ILCreateFromPathW(L"C:\\Windows\\System32");
hr = SHOpenFolderAndSelectItems(folder, 1, (PCUITEMID_CHILD_ARRAY)items, OFASI_EDIT);
- todo_wine
ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
- todo_wine
ok(check_window_exists("Windows"), "Failed to create window.\n");
ILFree(items[0]);
ILFree(folder);
@@ -5500,9 +5491,7 @@ static void test_SHOpenFolderAndSelectItems(void)
items[0] = ILCreateFromPathW(L"C:\\Windows\\System32");
items[1] = ILCreateFromPathW(L"C:\\Windows\\Resources");
hr = SHOpenFolderAndSelectItems(folder, 2, (PCUITEMID_CHILD_ARRAY)items, 0);
- todo_wine
ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
- todo_wine
ok(check_window_exists("Windows"), "Failed to create window.\n");
ILFree(items[1]);
ILFree(items[0]);
diff --git a/programs/explorer/explorer.c b/programs/explorer/explorer.c
index 26928912649..7924991383f 100644
--- a/programs/explorer/explorer.c
+++ b/programs/explorer/explorer.c
@@ -667,6 +667,43 @@ static LRESULT explorer_on_notify(explorer_info* info,NMHDR* notification)
return 0;
}
+static BOOL handle_copydata(const explorer_info *info, const COPYDATASTRUCT *cds)
+{
+ static const unsigned int magic = 0xe32ee32e;
+ unsigned int i, flags, count;
+ const ITEMIDLIST *child;
+ unsigned char *ptr;
+ IShellView *sv;
+ SVSIF sv_flags;
+
+ TRACE("\n");
+
+ /* For SHOpenFolderAndSelectItems() */
+ if (cds->dwData != magic)
+ return FALSE;
+
+ ptr = cds->lpData;
+ memcpy(&count, ptr, sizeof(count));
+ ptr += sizeof(count);
+ memcpy(&flags, ptr, sizeof(flags));
+ ptr += sizeof(flags);
+
+ sv_flags = flags & OFASI_EDIT ? SVSI_EDIT : SVSI_SELECT;
+
+ IExplorerBrowser_GetCurrentView(info->browser, &IID_IShellView, (void **)&sv);
+ for (i = 0; i < count; ++i)
+ {
+ child = (const ITEMIDLIST *)ptr;
+ if (i == 0)
+ IShellView_SelectItem(sv, child, sv_flags | SVSI_ENSUREVISIBLE | SVSI_FOCUSED | SVSI_DESELECTOTHERS);
+ else
+ IShellView_SelectItem(sv, child, sv_flags);
+ ptr += ILGetSize(child);
+ }
+ IShellView_Release(sv);
+ return TRUE;
+}
+
static LRESULT CALLBACK explorer_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
explorer_info *info
@@ -718,6 +755,8 @@ static LRESULT CALLBACK explorer_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, L
case WM_SIZE:
update_window_size(info,HIWORD(lParam),LOWORD(lParam));
break;
+ case WM_COPYDATA:
+ return handle_copydata(info, (const COPYDATASTRUCT *)lParam);
default:
return DefWindowProcW(hwnd,uMsg,wParam,lParam);
}
More information about the wine-cvs
mailing list