diff --git a/modules/rostests/apitests/shell32/ShellExecuteEx.cpp b/modules/rostests/apitests/shell32/ShellExecuteEx.cpp index 3343713631a..6d6b94e5723 100644 --- a/modules/rostests/apitests/shell32/ShellExecuteEx.cpp +++ b/modules/rostests/apitests/shell32/ShellExecuteEx.cpp @@ -149,7 +149,7 @@ getCommandLineFromProcess(HANDLE hProcess) return pszBuffer; // needs free() } -static void TEST_DoTestEntryStruct(const TEST_ENTRY *pEntry) +static TEST_RESULT TEST_DoTestEntryStruct(const TEST_ENTRY *pEntry) { SHELLEXECUTEINFOW info = { sizeof(info) }; info.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_WAITFORINPUTIDLE | @@ -172,6 +172,9 @@ static void TEST_DoTestEntryStruct(const TEST_ENTRY *pEntry) ok(pEntry->result == result, "Line %d: result: %d vs %d\n", pEntry->line, pEntry->result, result); + if (result == TEST_SUCCESS_WITH_PROCESS) + WaitForInputIdle(info.hProcess, 2000); + if (pEntry->result == TEST_SUCCESS_WITH_PROCESS && pEntry->cmdline && !s_bWow64) { LPWSTR cmdline = getCommandLineFromProcess(info.hProcess); @@ -191,13 +194,28 @@ static void TEST_DoTestEntryStruct(const TEST_ENTRY *pEntry) } CloseHandle(info.hProcess); + return result; } static void TEST_DoTestEntry(INT line, TEST_RESULT result, LPCWSTR lpFile, LPCWSTR cmdline) { + WINDOW_LIST existingwindows; + GetWindowList(&existingwindows); + HWND hWndForeground = GetForegroundWindow(); + TEST_ENTRY entry = { line, result, lpFile, cmdline }; - TEST_DoTestEntryStruct(&entry); + result = TEST_DoTestEntryStruct(&entry); + + if (result == TEST_SUCCESS_NO_PROCESS) + { + // Wait a bit for Explorer to open its window + for (UINT i = 0; i < 2000 && hWndForeground == GetForegroundWindow(); i += 250) + Sleep(250); + } + + CloseNewWindows(&existingwindows); + FreeWindowList(&existingwindows); } static BOOL diff --git a/modules/rostests/apitests/shell32/ShellExecuteW.cpp b/modules/rostests/apitests/shell32/ShellExecuteW.cpp index d367203e32f..4974cd35308 100644 --- a/modules/rostests/apitests/shell32/ShellExecuteW.cpp +++ b/modules/rostests/apitests/shell32/ShellExecuteW.cpp @@ -12,11 +12,29 @@ #include #include "closewnd.h" -#define WAIT_SLEEP 700 // ShellExecuteW(handle, "open", , , NULL, SW_SHOWNORMAL); -static WINDOW_LIST s_List1, s_List2; +WINDOW_LIST g_winlist; + +static void CloseWindow(HINSTANCE hInstance, PCWSTR ClassName, PCWSTR Title) +{ + if ((SIZE_T)hInstance <= 32) + return; + + HWND hWnd = NULL; + for (UINT i = 0; i < 1500; i += 250) + { + hWnd = FindWindowW(ClassName, Title); + if (hWnd && IsWindowVisible(hWnd) && !FindInWindowList(g_winlist, hWnd)) + break; + hWnd = NULL; + Sleep(250); + } + + if (!hWnd || !PostMessage(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0)) + CloseNewWindows(&g_winlist); +} START_TEST(ShellExecuteW) { @@ -24,8 +42,6 @@ START_TEST(ShellExecuteW) HINSTANCE hInstance; WCHAR WinDir[MAX_PATH], SysDir[MAX_PATH], SysDrive[MAX_PATH]; - GetWindowList(&s_List1); - if (!GetWindowsDirectoryW(WinDir, _countof(WinDir))) { skip("GetWindowsDirectoryW failed\n"); @@ -45,63 +61,67 @@ START_TEST(ShellExecuteW) } PathAddBackslashW(SysDrive); + GetWindowList(&g_winlist); + // TEST #1: Open Control Panel hInstance = ShellExecuteW(NULL, L"open", L"rundll32.exe", L"shell32.dll,Control_RunDLL desk.cpl", NULL, SW_SHOWNORMAL); ret = (INT)(UINT_PTR)hInstance; ok(ret > 31, "TEST #1: ret:%d, LastError: %ld\n", ret, GetLastError()); trace("TEST #1 ret: %d.\n", ret); + CloseWindow(hInstance, NULL, L"Properties for Display"); // FIXME: Dynamically determine the window title. // TEST #2: Open Notepad hInstance = ShellExecuteW(NULL, L"open", L"notepad.exe", NULL, NULL, SW_SHOWNORMAL); ret = (INT)(UINT_PTR)hInstance; ok(ret > 31, "TEST #2: ret:%d, LastError: %ld\n", ret, GetLastError()); trace("TEST #2 ret: %d.\n", ret); + CloseWindow(hInstance, L"Notepad", L"Untitled - Notepad"); // FIXME: Dynamically determine the window title. // TEST #3: Open Windows folder hInstance = ShellExecuteW(NULL, NULL, WinDir, NULL, NULL, SW_SHOWNORMAL); ret = (INT)(UINT_PTR)hInstance; ok(ret > 31, "TEST #3: ret:%d, LastError: %ld\n", ret, GetLastError()); trace("TEST #3 ret: %d.\n", ret); + CloseWindow(hInstance, L"CabinetWClass", PathFindFileNameW(WinDir)); // TEST #4: Open system32 folder hInstance = ShellExecuteW(NULL, L"open", SysDir, NULL, NULL, SW_SHOWNORMAL); ret = (INT)(UINT_PTR)hInstance; ok(ret > 31, "TEST #4: ret:%d, LastError: %ld\n", ret, GetLastError()); trace("TEST #4 ret: %d.\n", ret); + CloseWindow(hInstance, L"CabinetWClass", PathFindFileNameW(SysDir)); // TEST #5: Open %SystemDrive% hInstance = ShellExecuteW(NULL, L"explore", SysDrive, NULL, NULL, SW_SHOWNORMAL); ret = (INT)(UINT_PTR)hInstance; ok(ret > 31, "TEST #5: ret:%d, LastError: %ld\n", ret, GetLastError()); trace("TEST #5 ret: %d.\n", ret); + CloseWindow(hInstance, L"ExploreWClass", NULL); // TEST #6: Open Explorer Search on %SYSTEMDRIVE% hInstance = ShellExecuteW(NULL, L"find", SysDrive, NULL, NULL, SW_SHOWNORMAL); ret = (INT)(UINT_PTR)hInstance; ok(ret > 31, "TEST #6: ret:%d, LastError: %ld\n", ret, GetLastError()); trace("TEST #6 ret: %d.\n", ret); + CloseWindow(hInstance, L"CabinetWClass", L"Search Results"); // FIXME: Dynamically determine the window title. // TEST #7: Open My Documents ("::{450d8fba-ad25-11d0-98a8-0800361b1103}") hInstance = ShellExecuteW(NULL, NULL, L"::{450d8fba-ad25-11d0-98a8-0800361b1103}", NULL, NULL, SW_SHOWNORMAL); ret = (INT)(UINT_PTR)hInstance; ok(ret > 31, "TEST #7: ret:%d, LastError: %ld\n", ret, GetLastError()); trace("TEST #7 ret: %d.\n", ret); + CloseWindow(hInstance, L"CabinetWClass", NULL); // TEST #8: Open My Documents ("shell:::{450d8fba-ad25-11d0-98a8-0800361b1103}") hInstance = ShellExecuteW(NULL, L"open", L"shell:::{450d8fba-ad25-11d0-98a8-0800361b1103}", NULL, NULL, SW_SHOWNORMAL); ret = (INT)(UINT_PTR)hInstance; ok(ret > 31, "TEST #8: ret:%d, LastError: %ld\n", ret, GetLastError()); trace("TEST #8 ret: %d.\n", ret); + CloseWindow(hInstance, L"CabinetWClass", NULL); - // Execution can be asynchronous; you have to wait for it to finish. - Sleep(2000); - - // Close newly-opened window(s) - GetWindowList(&s_List2); - CloseNewWindows(&s_List1, &s_List2); - FreeWindowList(&s_List1); - FreeWindowList(&s_List2); + CloseNewWindows(&g_winlist); + FreeWindowList(&g_winlist); } // Windows Server 2003 and Windows XP SP3 return values (Win 7 returns 42 in all cases) diff --git a/modules/rostests/apitests/shell32/closewnd.h b/modules/rostests/apitests/shell32/closewnd.h index 2e62f18cd3a..4dc1e5d01a1 100644 --- a/modules/rostests/apitests/shell32/closewnd.h +++ b/modules/rostests/apitests/shell32/closewnd.h @@ -7,12 +7,28 @@ #pragma once +#define WaitForWindow(hWnd, Func, Seconds) \ + for (UINT waited = 0; !Func(hWnd) && waited < (Seconds) * 1000; waited += 250) Sleep(250); + +static BOOL WaitForForegroundWindow(HWND hWnd, UINT wait = 500) +{ + for (UINT waited = 0, interval = 50; waited < wait; waited += interval) + { + if (GetForegroundWindow() == hWnd) + return TRUE; + if (IsWindowVisible(hWnd)) + Sleep(interval); + } + return FALSE; +} + typedef struct WINDOW_LIST { SIZE_T m_chWnds; HWND *m_phWnds; } WINDOW_LIST, *PWINDOW_LIST; + static inline VOID FreeWindowList(PWINDOW_LIST pList) { free(pList->m_phWnds); @@ -42,6 +58,25 @@ static inline VOID GetWindowList(PWINDOW_LIST pList) EnumWindows(EnumWindowsProc, (LPARAM)pList); } +static inline VOID GetWindowListForClose(PWINDOW_LIST pList) +{ + WINDOW_LIST list; + pList->m_phWnds = NULL; + pList->m_chWnds = 0; + for (SIZE_T tries = 5, count; tries--;) + { + if (tries) + FreeWindowList(pList); + GetWindowList(pList); + Sleep(250); + GetWindowList(&list); + count = list.m_chWnds; + FreeWindowList(&list); + if (count == pList->m_chWnds) + break; + } +} + static inline HWND FindInWindowList(const WINDOW_LIST &list, HWND hWnd) { for (SIZE_T i = 0; i < list.m_chWnds; ++i) @@ -52,47 +87,57 @@ static inline HWND FindInWindowList(const WINDOW_LIST &list, HWND hWnd) return NULL; } -static inline VOID CloseNewWindows(PWINDOW_LIST List1, PWINDOW_LIST List2) +static inline BOOL SendAltF4Input() { - for (SIZE_T i = 0; i < List2->m_chWnds; ++i) + INPUT inputs[4]; + ZeroMemory(&inputs, sizeof(inputs)); + inputs[0].type = inputs[1].type = inputs[2].type = inputs[3].type = INPUT_KEYBOARD; + inputs[0].ki.wVk = inputs[3].ki.wVk = VK_LMENU; + inputs[1].ki.wVk = inputs[2].ki.wVk = VK_F4; + inputs[2].ki.dwFlags = inputs[3].ki.dwFlags = KEYEVENTF_KEYUP; + return SendInput(_countof(inputs), inputs, sizeof(INPUT)) == _countof(inputs); +} + +static inline VOID CloseNewWindows(PWINDOW_LIST pExisting, PWINDOW_LIST pNew) +{ + for (SIZE_T i = 0; i < pNew->m_chWnds; ++i) { - HWND hWnd = List2->m_phWnds[i]; - if (!IsWindowVisible(hWnd) || FindInWindowList(*List1, hWnd)) + HWND hWnd = pNew->m_phWnds[i]; + if (!IsWindowVisible(hWnd) || FindInWindowList(*pExisting, hWnd)) continue; - if (!PostMessageW(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0)) + SwitchToThisWindow(hWnd, TRUE); + WaitForForegroundWindow(hWnd); // SetForegroundWindow may take some time + DWORD_PTR result; + if (!SendMessageTimeoutW(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0, SMTO_ABORTIFHUNG, 3000, &result) && + !PostMessageW(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0)) { - DWORD_PTR result; - if (!SendMessageTimeoutW(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0, SMTO_ABORTIFHUNG, 3000, &result)) + if (WaitForForegroundWindow(hWnd)) // We can't fake keyboard input if the target is not foreground { - SwitchToThisWindow(hWnd, TRUE); + SendAltF4Input(); + WaitForWindow(hWnd, IsWindowVisible, 1); // Closing a window may take some time + } - // SwitchToThisWindow may take time - Sleep(500); - - // Alt+F4 - INPUT inputs[4]; - ZeroMemory(&inputs, sizeof(inputs)); - inputs[0].type = inputs[1].type = inputs[2].type = inputs[3].type = INPUT_KEYBOARD; - inputs[0].ki.wVk = inputs[3].ki.wVk = VK_LMENU; - inputs[1].ki.wVk = inputs[2].ki.wVk = VK_F4; - inputs[2].ki.dwFlags = inputs[3].ki.dwFlags = KEYEVENTF_KEYUP; - SendInput(_countof(inputs), inputs, sizeof(INPUT)); - - // Closing a window may take time - Sleep(1000); - - if (IsWindowVisible(hWnd)) - { - CHAR szClass[64]; - GetClassNameA(hWnd, szClass, _countof(szClass)); - trace("Unable to close window %p (%s)\n", hWnd, szClass); - } + if (IsWindowVisible(hWnd)) + { + CHAR szClass[64]; + GetClassNameA(hWnd, szClass, _countof(szClass)); + trace("Unable to close window %p (%s)\n", hWnd, szClass); } } } } +#ifdef __cplusplus +static inline VOID CloseNewWindows(PWINDOW_LIST InitialList) +{ + WINDOW_LIST newwindows; + GetWindowListForClose(&newwindows); + CloseNewWindows(InitialList, &newwindows); + FreeWindowList(&newwindows); +} +#endif + static inline HWND FindNewWindow(PWINDOW_LIST List1, PWINDOW_LIST List2) { for (SIZE_T i2 = 0; i2 < List2->m_chWnds; ++i2) @@ -117,7 +162,7 @@ static inline HWND FindNewWindow(PWINDOW_LIST List1, PWINDOW_LIST List2) return NULL; } -static inline BOOL CALLBACK CountWindowsProc(HWND hwnd, LPARAM lParam) +static inline BOOL CALLBACK CountVisibleWindowsProc(HWND hwnd, LPARAM lParam) { if (!IsWindowVisible(hwnd)) return TRUE; @@ -129,6 +174,6 @@ static inline BOOL CALLBACK CountWindowsProc(HWND hwnd, LPARAM lParam) static inline INT GetWindowCount(VOID) { INT nCount = 0; - EnumWindows(CountWindowsProc, (LPARAM)&nCount); + EnumWindows(CountVisibleWindowsProc, (LPARAM)&nCount); return nCount; }