https://git.reactos.org/?p=reactos.git;a=commitdiff;h=ea87f9102b1c4484d4240…
commit ea87f9102b1c4484d4240708e828e236aad4ebb6
Author: Whindmar Saksit <whindsaks(a)proton.me>
AuthorDate: Thu Oct 24 16:44:53 2024 +0200
Commit: GitHub <noreply(a)github.com>
CommitDate: Thu Oct 24 16:44:53 2024 +0200
[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.
---
dll/win32/shell32/shlexec.cpp | 20 +++++--
.../rostests/apitests/shell32/ShellExecuteEx.cpp | 42 +++++++++-----
modules/rostests/apitests/shell32/closewnd.cpp | 64 ++++++++++++++++------
modules/rostests/apitests/shell32/closewnd.h | 1 +
4 files changed, 90 insertions(+), 37 deletions(-)
diff --git a/dll/win32/shell32/shlexec.cpp b/dll/win32/shell32/shlexec.cpp
index 2e1d0e2a443..3a665288535 100644
--- a/dll/win32/shell32/shlexec.cpp
+++ b/dll/win32/shell32/shlexec.cpp
@@ -287,11 +287,12 @@ static BOOL SHELL_ArgifyW(WCHAR* out, DWORD len, const WCHAR* fmt,
const WCHAR*
else
cmd = lpFile;
- used += wcslen(cmd);
+ SIZE_T cmdlen = wcslen(cmd);
+ used += cmdlen;
if (used < len)
{
wcscpy(res, cmd);
- res += wcslen(cmd);
+ res += cmdlen;
}
}
found_p1 = TRUE;
@@ -1730,7 +1731,7 @@ static BOOL SHELL_translate_idlist(LPSHELLEXECUTEINFOW sei, LPWSTR
wszParameters
sei->fMask &= ~SEE_MASK_INVOKEIDLIST;
} else {
- WCHAR target[MAX_PATH];
+ WCHAR target[max(MAX_PATH, _countof(buffer))];
DWORD attribs;
DWORD resultLen;
/* 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))) {
SHELL_ArgifyW(wszApplicationName, dwApplicationNameLen,
buffer, target, (LPITEMIDLIST)sei->lpIDList, NULL,
&resultLen,
- (sei->lpDirectory && *sei->lpDirectory) ?
sei->lpDirectory : NULL);
+ !StrIsNullOrEmpty(sei->lpDirectory) ?
sei->lpDirectory : NULL);
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;
+ // 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;
}
diff --git a/modules/rostests/apitests/shell32/ShellExecuteEx.cpp
b/modules/rostests/apitests/shell32/ShellExecuteEx.cpp
index 2c26b33be37..64759a49c1e 100644
--- a/modules/rostests/apitests/shell32/ShellExecuteEx.cpp
+++ b/modules/rostests/apitests/shell32/ShellExecuteEx.cpp
@@ -14,6 +14,7 @@
#include <stdio.h>
#include <strsafe.h>
#include <versionhelpers.h>
+#include <shellutils.h>
#include "shell32_apitest_sub.h"
static WCHAR s_win_dir[MAX_PATH];
@@ -313,8 +314,7 @@ static BOOL TEST_Start(void)
static void TEST_End(void)
{
- Sleep(500);
- GetWindowList(&s_List2);
+ GetWindowListForClose(&s_List2);
CloseNewWindows(&s_List1, &s_List2);
FreeWindowList(&s_List1);
FreeWindowList(&s_List2);
@@ -368,26 +368,40 @@ static void test_properties()
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;
}
- /* 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) };
- ShellExecInfo.fMask = SEE_MASK_IDLIST;
- ShellExecInfo.hwnd = NULL;
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);
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
diff --git a/modules/rostests/apitests/shell32/closewnd.cpp
b/modules/rostests/apitests/shell32/closewnd.cpp
index d868f65fd79..2a7d8991b5c 100644
--- a/modules/rostests/apitests/shell32/closewnd.cpp
+++ b/modules/rostests/apitests/shell32/closewnd.cpp
@@ -37,6 +37,33 @@ void GetWindowList(PWINDOW_LIST 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)
{
for (SIZE_T i2 = 0; i2 < List2->m_chWnds; ++i2)
@@ -61,30 +88,31 @@ HWND FindNewWindow(PWINDOW_LIST List1, PWINDOW_LIST List2)
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)
{
- INT cDiff = List2->m_chWnds - List1->m_chWnds;
- for (INT j = 0; j < cDiff; ++j)
+ for (SIZE_T i = 0; i < List2->m_chWnds; ++i)
{
- HWND hWnd = FindNewWindow(List1, List2);
- if (!hWnd)
- break;
-
- for (INT i = 0; i < TRIALS_COUNT; ++i)
- {
- if (!IsWindow(hWnd))
- break;
+ HWND hWnd = List2->m_phWnds[i];
+ if (!IsWindow(hWnd) || FindInWindowList(*List1, hWnd))
+ continue;
- SwitchToThisWindow(hWnd, TRUE);
+ SwitchToThisWindow(hWnd, TRUE);
+ WaitForForegroundWindow(hWnd);
- // 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);
+ if (!PostMessageW(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0))
+ {
+ DWORD_PTR result;
+ SendMessageTimeoutW(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0, 0, 3000, &result);
}
}
}
diff --git a/modules/rostests/apitests/shell32/closewnd.h
b/modules/rostests/apitests/shell32/closewnd.h
index 367c058b054..096ce88c1fe 100644
--- a/modules/rostests/apitests/shell32/closewnd.h
+++ b/modules/rostests/apitests/shell32/closewnd.h
@@ -14,6 +14,7 @@ typedef struct WINDOW_LIST
} WINDOW_LIST, *PWINDOW_LIST;
void GetWindowList(PWINDOW_LIST pList);
+void GetWindowListForClose(PWINDOW_LIST pList);
HWND FindNewWindow(PWINDOW_LIST List1, PWINDOW_LIST List2);
void CloseNewWindows(PWINDOW_LIST List1, PWINDOW_LIST List2);
void FreeWindowList(PWINDOW_LIST pList);