Skip to content

Commit ea87f91

Browse files
authored
[SHELL32][SHELL32_APITEST] Fix ShellExecuteEx IDLIST folder (reactos#7464)
This is mainly to fix the shell32 apitest, a better way to handle SEE_MASK_IDLIST should be investigated in the future.
1 parent 90aee84 commit ea87f91

File tree

4 files changed

+90
-37
lines changed

4 files changed

+90
-37
lines changed

dll/win32/shell32/shlexec.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -287,11 +287,12 @@ static BOOL SHELL_ArgifyW(WCHAR* out, DWORD len, const WCHAR* fmt, const WCHAR*
287287
else
288288
cmd = lpFile;
289289

290-
used += wcslen(cmd);
290+
SIZE_T cmdlen = wcslen(cmd);
291+
used += cmdlen;
291292
if (used < len)
292293
{
293294
wcscpy(res, cmd);
294-
res += wcslen(cmd);
295+
res += cmdlen;
295296
}
296297
}
297298
found_p1 = TRUE;
@@ -1730,7 +1731,7 @@ static BOOL SHELL_translate_idlist(LPSHELLEXECUTEINFOW sei, LPWSTR wszParameters
17301731

17311732
sei->fMask &= ~SEE_MASK_INVOKEIDLIST;
17321733
} else {
1733-
WCHAR target[MAX_PATH];
1734+
WCHAR target[max(MAX_PATH, _countof(buffer))];
17341735
DWORD attribs;
17351736
DWORD resultLen;
17361737
/* 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
17441745
buffer, sizeof(buffer))) {
17451746
SHELL_ArgifyW(wszApplicationName, dwApplicationNameLen,
17461747
buffer, target, (LPITEMIDLIST)sei->lpIDList, NULL, &resultLen,
1747-
(sei->lpDirectory && *sei->lpDirectory) ? sei->lpDirectory : NULL);
1748+
!StrIsNullOrEmpty(sei->lpDirectory) ? sei->lpDirectory : NULL);
17481749
if (resultLen > dwApplicationNameLen)
1749-
ERR("Argify buffer not large enough... truncating\n");
1750+
ERR("Argify buffer not large enough... truncating\n"); // FIXME: Report this to the caller?
17501751
appKnownSingular = FALSE;
1752+
// HACKFIX: We really want the !appKnownSingular code in SHELL_execute to split the
1753+
// parameters for us but we cannot guarantee that the exe in the registry is quoted.
1754+
// We have now turned 'explorer.exe "%1" into 'explorer.exe "c:\path\from\pidl"' and
1755+
// need to split to application and parameters.
1756+
LPCWSTR params = PathGetArgsW(wszApplicationName);
1757+
lstrcpynW(wszParameters, params, parametersLen);
1758+
PathRemoveArgsW(wszApplicationName);
1759+
PathUnquoteSpacesW(wszApplicationName);
1760+
appKnownSingular = TRUE;
17511761
}
17521762
sei->fMask &= ~SEE_MASK_INVOKEIDLIST;
17531763
}

modules/rostests/apitests/shell32/ShellExecuteEx.cpp

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <stdio.h>
1515
#include <strsafe.h>
1616
#include <versionhelpers.h>
17+
#include <shellutils.h>
1718
#include "shell32_apitest_sub.h"
1819

1920
static WCHAR s_win_dir[MAX_PATH];
@@ -313,8 +314,7 @@ static BOOL TEST_Start(void)
313314

314315
static void TEST_End(void)
315316
{
316-
Sleep(500);
317-
GetWindowList(&s_List2);
317+
GetWindowListForClose(&s_List2);
318318
CloseNewWindows(&s_List1, &s_List2);
319319
FreeWindowList(&s_List1);
320320
FreeWindowList(&s_List2);
@@ -368,26 +368,40 @@ static void test_properties()
368368

369369
static void test_sei_lpIDList()
370370
{
371-
if (IsWindowsVistaOrGreater())
371+
// Note: SEE_MASK_FLAG_NO_UI prevents the test from blocking with a MessageBox
372+
WCHAR path[MAX_PATH];
373+
374+
/* This tests ShellExecuteEx with lpIDList for explorer C:\ */
375+
GetSystemDirectoryW(path, _countof(path));
376+
PathStripToRootW(path);
377+
LPITEMIDLIST pidl = ILCreateFromPathW(path);
378+
if (!pidl)
372379
{
373-
skip("Vista+\n");
380+
skip("Unable to initialize test\n");
374381
return;
375382
}
376383

377-
/* This tests ShellExecuteEx with lpIDList for explorer C:\ */
378-
379-
/* ITEMIDLIST for CLSID of 'My Computer' followed by PIDL for 'C:\' */
380-
BYTE lpitemidlist[30] = { 0x14, 0, 0x1f, 0, 0xe0, 0x4f, 0xd0, 0x20, 0xea,
381-
0x3a, 0x69, 0x10, 0xa2, 0xd8, 0x08, 0, 0x2b, 0x30, 0x30, 0x9d, // My Computer
382-
0x8, 0, 0x23, 0x43, 0x3a, 0x5c, 0x5c, 0, 0, 0,}; // C:\\ + NUL-NUL ending
383-
384384
SHELLEXECUTEINFOW ShellExecInfo = { sizeof(ShellExecInfo) };
385-
ShellExecInfo.fMask = SEE_MASK_IDLIST;
386-
ShellExecInfo.hwnd = NULL;
387385
ShellExecInfo.nShow = SW_SHOWNORMAL;
388-
ShellExecInfo.lpIDList = lpitemidlist;
386+
ShellExecInfo.fMask = SEE_MASK_IDLIST | SEE_MASK_FLAG_NO_UI | SEE_MASK_FLAG_DDEWAIT;
387+
ShellExecInfo.lpIDList = pidl;
389388
BOOL ret = ShellExecuteExW(&ShellExecInfo);
390389
ok_int(ret, TRUE);
390+
ILFree(pidl);
391+
392+
/* This tests ShellExecuteEx with lpIDList going through IContextMenu */
393+
CCoInit ComInit;
394+
pidl = SHCloneSpecialIDList(NULL, CSIDL_PROFILE, TRUE);
395+
if (!pidl)
396+
{
397+
skip("Unable to initialize test\n");
398+
return;
399+
}
400+
ShellExecInfo.fMask = SEE_MASK_INVOKEIDLIST | SEE_MASK_FLAG_NO_UI | SEE_MASK_FLAG_DDEWAIT;
401+
ShellExecInfo.lpIDList = pidl;
402+
ret = ShellExecuteExW(&ShellExecInfo);
403+
ok_int(ret, TRUE);
404+
ILFree(pidl);
391405
}
392406

393407
static BOOL

modules/rostests/apitests/shell32/closewnd.cpp

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,33 @@ void GetWindowList(PWINDOW_LIST pList)
3737
EnumWindows(EnumWindowsProc, (LPARAM)pList);
3838
}
3939

40+
void GetWindowListForClose(PWINDOW_LIST pList)
41+
{
42+
for (UINT tries = 5; tries--;)
43+
{
44+
if (tries)
45+
FreeWindowList(pList);
46+
GetWindowList(pList);
47+
Sleep(500);
48+
WINDOW_LIST list;
49+
GetWindowList(&list);
50+
SIZE_T count = list.m_chWnds;
51+
FreeWindowList(&list);
52+
if (count == pList->m_chWnds)
53+
break;
54+
}
55+
}
56+
57+
static HWND FindInWindowList(const WINDOW_LIST &list, HWND hWnd)
58+
{
59+
for (SIZE_T i = 0; i < list.m_chWnds; ++i)
60+
{
61+
if (list.m_phWnds[i] == hWnd)
62+
return hWnd;
63+
}
64+
return NULL;
65+
}
66+
4067
HWND FindNewWindow(PWINDOW_LIST List1, PWINDOW_LIST List2)
4168
{
4269
for (SIZE_T i2 = 0; i2 < List2->m_chWnds; ++i2)
@@ -61,30 +88,31 @@ HWND FindNewWindow(PWINDOW_LIST List1, PWINDOW_LIST List2)
6188
return NULL;
6289
}
6390

64-
#define TRIALS_COUNT 8
91+
static void WaitForForegroundWindow(HWND hWnd, UINT wait = 250)
92+
{
93+
for (UINT waited = 0, interval = 50; waited < wait; waited += interval)
94+
{
95+
if (GetForegroundWindow() == hWnd || !IsWindowVisible(hWnd))
96+
return;
97+
Sleep(interval);
98+
}
99+
}
65100

66101
void CloseNewWindows(PWINDOW_LIST List1, PWINDOW_LIST List2)
67102
{
68-
INT cDiff = List2->m_chWnds - List1->m_chWnds;
69-
for (INT j = 0; j < cDiff; ++j)
103+
for (SIZE_T i = 0; i < List2->m_chWnds; ++i)
70104
{
71-
HWND hWnd = FindNewWindow(List1, List2);
72-
if (!hWnd)
73-
break;
74-
75-
for (INT i = 0; i < TRIALS_COUNT; ++i)
76-
{
77-
if (!IsWindow(hWnd))
78-
break;
105+
HWND hWnd = List2->m_phWnds[i];
106+
if (!IsWindow(hWnd) || FindInWindowList(*List1, hWnd))
107+
continue;
79108

80-
SwitchToThisWindow(hWnd, TRUE);
109+
SwitchToThisWindow(hWnd, TRUE);
110+
WaitForForegroundWindow(hWnd);
81111

82-
// Alt+F4
83-
keybd_event(VK_MENU, 0x38, 0, 0);
84-
keybd_event(VK_F4, 0x3E, 0, 0);
85-
keybd_event(VK_F4, 0x3E, KEYEVENTF_KEYUP, 0);
86-
keybd_event(VK_MENU, 0x38, KEYEVENTF_KEYUP, 0);
87-
Sleep(100);
112+
if (!PostMessageW(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0))
113+
{
114+
DWORD_PTR result;
115+
SendMessageTimeoutW(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0, 0, 3000, &result);
88116
}
89117
}
90118
}

modules/rostests/apitests/shell32/closewnd.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ typedef struct WINDOW_LIST
1414
} WINDOW_LIST, *PWINDOW_LIST;
1515

1616
void GetWindowList(PWINDOW_LIST pList);
17+
void GetWindowListForClose(PWINDOW_LIST pList);
1718
HWND FindNewWindow(PWINDOW_LIST List1, PWINDOW_LIST List2);
1819
void CloseNewWindows(PWINDOW_LIST List1, PWINDOW_LIST List2);
1920
void FreeWindowList(PWINDOW_LIST pList);

0 commit comments

Comments
 (0)