mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-06 07:06:52 +00:00
shell32: Implement SHOpenFolderAndSelectItems().
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=39987 Signed-off-by: Zhiyi Zhang <zzhang@codeweavers.com>
This commit is contained in:
parent
7c60e6233a
commit
c03409e9d7
|
@ -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;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue