mirror of
https://github.com/reactos/reactos.git
synced 2025-05-07 02:41:22 +00:00
[SHELL32][SHELL32_APITEST] Fix ShellExecuteEx IDLIST folder (#7464)
This is mainly to fix the shell32 apitest, a better way to handle SEE_MASK_IDLIST should be investigated in the future.
This commit is contained in:
parent
90aee8453f
commit
ea87f9102b
4 changed files with 90 additions and 37 deletions
|
@ -287,11 +287,12 @@ static BOOL SHELL_ArgifyW(WCHAR* out, DWORD len, const WCHAR* fmt, const WCHAR*
|
||||||
else
|
else
|
||||||
cmd = lpFile;
|
cmd = lpFile;
|
||||||
|
|
||||||
used += wcslen(cmd);
|
SIZE_T cmdlen = wcslen(cmd);
|
||||||
|
used += cmdlen;
|
||||||
if (used < len)
|
if (used < len)
|
||||||
{
|
{
|
||||||
wcscpy(res, cmd);
|
wcscpy(res, cmd);
|
||||||
res += wcslen(cmd);
|
res += cmdlen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
found_p1 = TRUE;
|
found_p1 = TRUE;
|
||||||
|
@ -1730,7 +1731,7 @@ static BOOL SHELL_translate_idlist(LPSHELLEXECUTEINFOW sei, LPWSTR wszParameters
|
||||||
|
|
||||||
sei->fMask &= ~SEE_MASK_INVOKEIDLIST;
|
sei->fMask &= ~SEE_MASK_INVOKEIDLIST;
|
||||||
} else {
|
} else {
|
||||||
WCHAR target[MAX_PATH];
|
WCHAR target[max(MAX_PATH, _countof(buffer))];
|
||||||
DWORD attribs;
|
DWORD attribs;
|
||||||
DWORD resultLen;
|
DWORD resultLen;
|
||||||
/* Check if we're executing a directory and if so use the
|
/* Check if we're executing a directory and if so use the
|
||||||
|
@ -1744,10 +1745,19 @@ static BOOL SHELL_translate_idlist(LPSHELLEXECUTEINFOW sei, LPWSTR wszParameters
|
||||||
buffer, sizeof(buffer))) {
|
buffer, sizeof(buffer))) {
|
||||||
SHELL_ArgifyW(wszApplicationName, dwApplicationNameLen,
|
SHELL_ArgifyW(wszApplicationName, dwApplicationNameLen,
|
||||||
buffer, target, (LPITEMIDLIST)sei->lpIDList, NULL, &resultLen,
|
buffer, target, (LPITEMIDLIST)sei->lpIDList, NULL, &resultLen,
|
||||||
(sei->lpDirectory && *sei->lpDirectory) ? sei->lpDirectory : NULL);
|
!StrIsNullOrEmpty(sei->lpDirectory) ? sei->lpDirectory : NULL);
|
||||||
if (resultLen > dwApplicationNameLen)
|
if (resultLen > dwApplicationNameLen)
|
||||||
ERR("Argify buffer not large enough... truncating\n");
|
ERR("Argify buffer not large enough... truncating\n"); // FIXME: Report this to the caller?
|
||||||
appKnownSingular = FALSE;
|
appKnownSingular = FALSE;
|
||||||
|
// HACKFIX: We really want the !appKnownSingular code in SHELL_execute to split the
|
||||||
|
// parameters for us but we cannot guarantee that the exe in the registry is quoted.
|
||||||
|
// We have now turned 'explorer.exe "%1" into 'explorer.exe "c:\path\from\pidl"' and
|
||||||
|
// need to split to application and parameters.
|
||||||
|
LPCWSTR params = PathGetArgsW(wszApplicationName);
|
||||||
|
lstrcpynW(wszParameters, params, parametersLen);
|
||||||
|
PathRemoveArgsW(wszApplicationName);
|
||||||
|
PathUnquoteSpacesW(wszApplicationName);
|
||||||
|
appKnownSingular = TRUE;
|
||||||
}
|
}
|
||||||
sei->fMask &= ~SEE_MASK_INVOKEIDLIST;
|
sei->fMask &= ~SEE_MASK_INVOKEIDLIST;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <strsafe.h>
|
#include <strsafe.h>
|
||||||
#include <versionhelpers.h>
|
#include <versionhelpers.h>
|
||||||
|
#include <shellutils.h>
|
||||||
#include "shell32_apitest_sub.h"
|
#include "shell32_apitest_sub.h"
|
||||||
|
|
||||||
static WCHAR s_win_dir[MAX_PATH];
|
static WCHAR s_win_dir[MAX_PATH];
|
||||||
|
@ -313,8 +314,7 @@ static BOOL TEST_Start(void)
|
||||||
|
|
||||||
static void TEST_End(void)
|
static void TEST_End(void)
|
||||||
{
|
{
|
||||||
Sleep(500);
|
GetWindowListForClose(&s_List2);
|
||||||
GetWindowList(&s_List2);
|
|
||||||
CloseNewWindows(&s_List1, &s_List2);
|
CloseNewWindows(&s_List1, &s_List2);
|
||||||
FreeWindowList(&s_List1);
|
FreeWindowList(&s_List1);
|
||||||
FreeWindowList(&s_List2);
|
FreeWindowList(&s_List2);
|
||||||
|
@ -368,26 +368,40 @@ static void test_properties()
|
||||||
|
|
||||||
static void test_sei_lpIDList()
|
static void test_sei_lpIDList()
|
||||||
{
|
{
|
||||||
if (IsWindowsVistaOrGreater())
|
// Note: SEE_MASK_FLAG_NO_UI prevents the test from blocking with a MessageBox
|
||||||
|
WCHAR path[MAX_PATH];
|
||||||
|
|
||||||
|
/* This tests ShellExecuteEx with lpIDList for explorer C:\ */
|
||||||
|
GetSystemDirectoryW(path, _countof(path));
|
||||||
|
PathStripToRootW(path);
|
||||||
|
LPITEMIDLIST pidl = ILCreateFromPathW(path);
|
||||||
|
if (!pidl)
|
||||||
{
|
{
|
||||||
skip("Vista+\n");
|
skip("Unable to initialize test\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This tests ShellExecuteEx with lpIDList for explorer C:\ */
|
|
||||||
|
|
||||||
/* ITEMIDLIST for CLSID of 'My Computer' followed by PIDL for 'C:\' */
|
|
||||||
BYTE lpitemidlist[30] = { 0x14, 0, 0x1f, 0, 0xe0, 0x4f, 0xd0, 0x20, 0xea,
|
|
||||||
0x3a, 0x69, 0x10, 0xa2, 0xd8, 0x08, 0, 0x2b, 0x30, 0x30, 0x9d, // My Computer
|
|
||||||
0x8, 0, 0x23, 0x43, 0x3a, 0x5c, 0x5c, 0, 0, 0,}; // C:\\ + NUL-NUL ending
|
|
||||||
|
|
||||||
SHELLEXECUTEINFOW ShellExecInfo = { sizeof(ShellExecInfo) };
|
SHELLEXECUTEINFOW ShellExecInfo = { sizeof(ShellExecInfo) };
|
||||||
ShellExecInfo.fMask = SEE_MASK_IDLIST;
|
|
||||||
ShellExecInfo.hwnd = NULL;
|
|
||||||
ShellExecInfo.nShow = SW_SHOWNORMAL;
|
ShellExecInfo.nShow = SW_SHOWNORMAL;
|
||||||
ShellExecInfo.lpIDList = lpitemidlist;
|
ShellExecInfo.fMask = SEE_MASK_IDLIST | SEE_MASK_FLAG_NO_UI | SEE_MASK_FLAG_DDEWAIT;
|
||||||
|
ShellExecInfo.lpIDList = pidl;
|
||||||
BOOL ret = ShellExecuteExW(&ShellExecInfo);
|
BOOL ret = ShellExecuteExW(&ShellExecInfo);
|
||||||
ok_int(ret, TRUE);
|
ok_int(ret, TRUE);
|
||||||
|
ILFree(pidl);
|
||||||
|
|
||||||
|
/* This tests ShellExecuteEx with lpIDList going through IContextMenu */
|
||||||
|
CCoInit ComInit;
|
||||||
|
pidl = SHCloneSpecialIDList(NULL, CSIDL_PROFILE, TRUE);
|
||||||
|
if (!pidl)
|
||||||
|
{
|
||||||
|
skip("Unable to initialize test\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ShellExecInfo.fMask = SEE_MASK_INVOKEIDLIST | SEE_MASK_FLAG_NO_UI | SEE_MASK_FLAG_DDEWAIT;
|
||||||
|
ShellExecInfo.lpIDList = pidl;
|
||||||
|
ret = ShellExecuteExW(&ShellExecInfo);
|
||||||
|
ok_int(ret, TRUE);
|
||||||
|
ILFree(pidl);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOL
|
static BOOL
|
||||||
|
|
|
@ -37,6 +37,33 @@ void GetWindowList(PWINDOW_LIST pList)
|
||||||
EnumWindows(EnumWindowsProc, (LPARAM)pList);
|
EnumWindows(EnumWindowsProc, (LPARAM)pList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GetWindowListForClose(PWINDOW_LIST pList)
|
||||||
|
{
|
||||||
|
for (UINT tries = 5; tries--;)
|
||||||
|
{
|
||||||
|
if (tries)
|
||||||
|
FreeWindowList(pList);
|
||||||
|
GetWindowList(pList);
|
||||||
|
Sleep(500);
|
||||||
|
WINDOW_LIST list;
|
||||||
|
GetWindowList(&list);
|
||||||
|
SIZE_T count = list.m_chWnds;
|
||||||
|
FreeWindowList(&list);
|
||||||
|
if (count == pList->m_chWnds)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static HWND FindInWindowList(const WINDOW_LIST &list, HWND hWnd)
|
||||||
|
{
|
||||||
|
for (SIZE_T i = 0; i < list.m_chWnds; ++i)
|
||||||
|
{
|
||||||
|
if (list.m_phWnds[i] == hWnd)
|
||||||
|
return hWnd;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
HWND FindNewWindow(PWINDOW_LIST List1, PWINDOW_LIST List2)
|
HWND FindNewWindow(PWINDOW_LIST List1, PWINDOW_LIST List2)
|
||||||
{
|
{
|
||||||
for (SIZE_T i2 = 0; i2 < List2->m_chWnds; ++i2)
|
for (SIZE_T i2 = 0; i2 < List2->m_chWnds; ++i2)
|
||||||
|
@ -61,30 +88,31 @@ HWND FindNewWindow(PWINDOW_LIST List1, PWINDOW_LIST List2)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TRIALS_COUNT 8
|
static void WaitForForegroundWindow(HWND hWnd, UINT wait = 250)
|
||||||
|
{
|
||||||
|
for (UINT waited = 0, interval = 50; waited < wait; waited += interval)
|
||||||
|
{
|
||||||
|
if (GetForegroundWindow() == hWnd || !IsWindowVisible(hWnd))
|
||||||
|
return;
|
||||||
|
Sleep(interval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CloseNewWindows(PWINDOW_LIST List1, PWINDOW_LIST List2)
|
void CloseNewWindows(PWINDOW_LIST List1, PWINDOW_LIST List2)
|
||||||
{
|
{
|
||||||
INT cDiff = List2->m_chWnds - List1->m_chWnds;
|
for (SIZE_T i = 0; i < List2->m_chWnds; ++i)
|
||||||
for (INT j = 0; j < cDiff; ++j)
|
|
||||||
{
|
{
|
||||||
HWND hWnd = FindNewWindow(List1, List2);
|
HWND hWnd = List2->m_phWnds[i];
|
||||||
if (!hWnd)
|
if (!IsWindow(hWnd) || FindInWindowList(*List1, hWnd))
|
||||||
break;
|
continue;
|
||||||
|
|
||||||
for (INT i = 0; i < TRIALS_COUNT; ++i)
|
SwitchToThisWindow(hWnd, TRUE);
|
||||||
|
WaitForForegroundWindow(hWnd);
|
||||||
|
|
||||||
|
if (!PostMessageW(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0))
|
||||||
{
|
{
|
||||||
if (!IsWindow(hWnd))
|
DWORD_PTR result;
|
||||||
break;
|
SendMessageTimeoutW(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0, 0, 3000, &result);
|
||||||
|
|
||||||
SwitchToThisWindow(hWnd, TRUE);
|
|
||||||
|
|
||||||
// Alt+F4
|
|
||||||
keybd_event(VK_MENU, 0x38, 0, 0);
|
|
||||||
keybd_event(VK_F4, 0x3E, 0, 0);
|
|
||||||
keybd_event(VK_F4, 0x3E, KEYEVENTF_KEYUP, 0);
|
|
||||||
keybd_event(VK_MENU, 0x38, KEYEVENTF_KEYUP, 0);
|
|
||||||
Sleep(100);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ typedef struct WINDOW_LIST
|
||||||
} WINDOW_LIST, *PWINDOW_LIST;
|
} WINDOW_LIST, *PWINDOW_LIST;
|
||||||
|
|
||||||
void GetWindowList(PWINDOW_LIST pList);
|
void GetWindowList(PWINDOW_LIST pList);
|
||||||
|
void GetWindowListForClose(PWINDOW_LIST pList);
|
||||||
HWND FindNewWindow(PWINDOW_LIST List1, PWINDOW_LIST List2);
|
HWND FindNewWindow(PWINDOW_LIST List1, PWINDOW_LIST List2);
|
||||||
void CloseNewWindows(PWINDOW_LIST List1, PWINDOW_LIST List2);
|
void CloseNewWindows(PWINDOW_LIST List1, PWINDOW_LIST List2);
|
||||||
void FreeWindowList(PWINDOW_LIST pList);
|
void FreeWindowList(PWINDOW_LIST pList);
|
||||||
|
|
Loading…
Reference in a new issue