The value of SVSI_EDIT is 0x3.
Signed-off-by: Zhiyi Zhang zzhang@codeweavers.com
-- v2: shell32: Implement SHOpenFolderAndSelectItems(). shell32/tests: Add SHOpenFolderAndSelectItems() tests. include: Add SHOpenFolderAndSelectItems() declaration and flags. shell32: Correct SHOpenFolderAndSelectItems() prototype. shell32: Add LVS_SHOWSELALWAYS to the list view in shell views. shell32: Correctly apply SVSI_FOCUSED. shell32: Correctly check SVSI_EDIT.
From: Zhiyi Zhang zzhang@codeweavers.com
The value of SVSI_EDIT is 0x3.
Signed-off-by: Zhiyi Zhang zzhang@codeweavers.com --- dlls/shell32/shlview.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/shell32/shlview.c b/dlls/shell32/shlview.c index 2e557d79622..e2b4ae4c9ca 100644 --- a/dlls/shell32/shlview.c +++ b/dlls/shell32/shlview.c @@ -2873,7 +2873,7 @@ static HRESULT WINAPI FolderView_SelectItem(IFolderView2 *iface, int item, DWORD
SendMessageW(This->hWndList, LVM_SETITEMSTATE, item, (LPARAM)&lvItem);
- if (flags & SVSI_EDIT) + if ((flags & SVSI_EDIT) == SVSI_EDIT) SendMessageW(This->hWndList, LVM_EDITLABELW, item, 0);
return S_OK;
From: Zhiyi Zhang zzhang@codeweavers.com
LVIS_FOCUSED has to be added to both stateMask and state to set focused state for list views.
Signed-off-by: Zhiyi Zhang zzhang@codeweavers.com --- dlls/shell32/shlview.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/dlls/shell32/shlview.c b/dlls/shell32/shlview.c index e2b4ae4c9ca..1b4ba304dc1 100644 --- a/dlls/shell32/shlview.c +++ b/dlls/shell32/shlview.c @@ -2869,7 +2869,10 @@ static HRESULT WINAPI FolderView_SelectItem(IFolderView2 *iface, int item, DWORD lvItem.state |= LVIS_SELECTED;
if (flags & SVSI_FOCUSED) + { lvItem.stateMask |= LVIS_FOCUSED; + lvItem.state |= LVIS_FOCUSED; + }
SendMessageW(This->hWndList, LVM_SETITEMSTATE, item, (LPARAM)&lvItem);
This merge request was approved by Alexandre Julliard.
From: Zhiyi Zhang zzhang@codeweavers.com
FWF_SHOWSELALWAYS is deprecated and has no effect. Manual tests show that LVS_SHOWSELALWAYS is always used.
Signed-off-by: Zhiyi Zhang zzhang@codeweavers.com --- dlls/shell32/shlview.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/shell32/shlview.c b/dlls/shell32/shlview.c index 1b4ba304dc1..40a7d76c359 100644 --- a/dlls/shell32/shlview.c +++ b/dlls/shell32/shlview.c @@ -358,7 +358,7 @@ static BOOL ShellView_CreateList (IShellViewImpl * This) TRACE("%p\n",This);
dwStyle = WS_TABSTOP | WS_VISIBLE | WS_CHILDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | - LVS_SHAREIMAGELISTS | LVS_EDITLABELS | LVS_ALIGNLEFT | LVS_AUTOARRANGE; + LVS_SHAREIMAGELISTS | LVS_EDITLABELS | LVS_ALIGNLEFT | LVS_AUTOARRANGE | LVS_SHOWSELALWAYS; dwExStyle = WS_EX_CLIENTEDGE;
dwStyle |= ViewModeToListStyle(This->FolderSettings.ViewMode);
From: Zhiyi Zhang zzhang@codeweavers.com
The third parameter is of type PCUITEMID_CHILD_ARRAY, not PCUITEMID_CHILD_ARRAY *.
Signed-off-by: Zhiyi Zhang zzhang@codeweavers.com --- dlls/shell32/shlfolder.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/shell32/shlfolder.c b/dlls/shell32/shlfolder.c index 120376ba82c..7308f49c7d5 100644 --- a/dlls/shell32/shlfolder.c +++ b/dlls/shell32/shlfolder.c @@ -615,8 +615,8 @@ HRESULT WINAPI SHCreateLinks( HWND hWnd, LPCSTR lpszDir, LPDATAOBJECT lpDataObje * * Added in XP. */ -HRESULT WINAPI SHOpenFolderAndSelectItems( PCIDLIST_ABSOLUTE pidlFolder, UINT cidl, - PCUITEMID_CHILD_ARRAY *apidl, DWORD flags ) +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;
From: Zhiyi Zhang zzhang@codeweavers.com
Signed-off-by: Zhiyi Zhang zzhang@codeweavers.com --- include/shlobj.h | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/include/shlobj.h b/include/shlobj.h index d30944662f7..8d6eab85eb6 100644 --- a/include/shlobj.h +++ b/include/shlobj.h @@ -96,6 +96,7 @@ BOOL WINAPI SHGetPathFromIDListEx(PCIDLIST_ABSOLUTE,WCHAR*,DWORD,GPFIDL_ INT WINAPI SHHandleUpdateImage(LPCITEMIDLIST); HRESULT WINAPI SHILCreateFromPath(LPCWSTR,LPITEMIDLIST*,DWORD*); HRESULT WINAPI SHLoadOLE(LPARAM); +HRESULT WINAPI SHOpenFolderAndSelectItems(PCIDLIST_ABSOLUTE,UINT,PCUITEMID_CHILD_ARRAY,DWORD); HRESULT WINAPI SHParseDisplayName(LPCWSTR,IBindCtx*,LPITEMIDLIST*,SFGAOF,SFGAOF*); HRESULT WINAPI SHPathPrepareForWriteA(HWND,IUnknown*,LPCSTR,DWORD); HRESULT WINAPI SHPathPrepareForWriteW(HWND,IUnknown*,LPCWSTR,DWORD); @@ -142,6 +143,10 @@ BOOL WINAPI ImportPrivacySettings(LPCWSTR, BOOL*, BOOL*); #define SHOP_FILEPATH 0x02 #define SHOP_VOLUMEGUID 0x04
+/* SHOpenFolderAndSelectItems flags */ +#define OFASI_EDIT 0x0001 +#define OFASI_OPENDESKTOP 0x0002 + BOOL WINAPI SHObjectProperties(HWND,DWORD,LPCWSTR,LPCWSTR);
#define PCS_FATAL 0x80000000
From: Zhiyi Zhang zzhang@codeweavers.com
Signed-off-by: Zhiyi Zhang zzhang@codeweavers.com --- dlls/shell32/tests/shlfolder.c | 100 +++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+)
diff --git a/dlls/shell32/tests/shlfolder.c b/dlls/shell32/tests/shlfolder.c index da606a9e707..10a989e9ca4 100644 --- a/dlls/shell32/tests/shlfolder.c +++ b/dlls/shell32/tests/shlfolder.c @@ -81,6 +81,37 @@ static WCHAR *make_wstr(const char *str) return ret; }
+static BOOL check_window_exists(const char *name) +{ + HWND window = NULL; + int i; + + for (i = 0; i < 10; i++) + { + if ((window = FindWindowA("ExplorerWClass", name)) + || (window = FindWindowA("CabinetWClass", name))) + { + SendMessageA(window, WM_SYSCOMMAND, SC_CLOSE, 0); + break; + } + + Sleep(100); + } + + if (!window) + return FALSE; + + for (i = 0; i < 10; i++) + { + if (!IsWindow(window)) + break; + + Sleep(100); + } + + return TRUE; +} + static void init_function_pointers(void) { HMODULE hmod; @@ -5410,6 +5441,74 @@ static void test_SHGetSetFolderCustomSettings(void) RemoveDirectoryW(pathW); }
+static void test_SHOpenFolderAndSelectItems(void) +{ + PIDLIST_ABSOLUTE folder, items[2]; + HRESULT hr; + + /* 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); + + /* Open folder and select one child item */ + 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); + + /* Open folder and select two child items */ + folder = ILCreateFromPathW(L"C:\Windows"); + 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]); + ILFree(folder); + + /* Open folder and select one child item with OFASI_EDIT */ + 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); + + /* Open folder and select two child items and OFASI_EDIT */ + folder = ILCreateFromPathW(L"C:\Windows"); + 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]); + ILFree(folder); +} + START_TEST(shlfolder) { init_function_pointers(); @@ -5455,6 +5554,7 @@ START_TEST(shlfolder) test_GetDefaultSearchGUID(); test_SHLimitInputEdit(); test_SHGetSetFolderCustomSettings(); + test_SHOpenFolderAndSelectItems();
OleUninitialize(); }
From: Zhiyi Zhang zzhang@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=39987 Signed-off-by: Zhiyi Zhang zzhang@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); }