https://git.reactos.org/?p=reactos.git;a=commitdiff;h=ea87f9102b1c4484d4240708e828e236aad4ebb6

commit ea87f9102b1c4484d4240708e828e236aad4ebb6
Author:     Whindmar Saksit <whinds...@proton.me>
AuthorDate: Thu Oct 24 16:44:53 2024 +0200
Commit:     GitHub <nore...@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);

Reply via email to