Index: rostests/apitests/shell32/ShellExecuteEx.cpp =================================================================== --- rostests/apitests/shell32/ShellExecuteEx.cpp (revision 74978) +++ rostests/apitests/shell32/ShellExecuteEx.cpp (working copy) @@ -2,16 +2,157 @@ * PROJECT: ReactOS api tests * LICENSE: GPLv2+ - See COPYING in the top level directory * PURPOSE: Testing ShellExecuteEx - * PROGRAMMER: Yaroslav Veremenko + * PROGRAMMERS: Yaroslav Veremenko + * Katayama Hirofumi MZ */ #include "shelltest.h" +#include +#define ok_ShellExecuteEx (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : TestShellExecuteEx +#define ok_ShellExecuteEx2 (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : TestShellExecuteEx2 +#define MAX_PROCESS 512 +typedef struct PROCESS_LIST +{ + INT ProcessCount; + DWORD ProcessIDs[MAX_PROCESS]; +} PROCESS_LIST; -#define ok_ShellExecuteEx (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : TestShellExecuteEx +#define MAX_WINDOWS 512 +typedef struct WINDOW_LIST +{ + INT WindowCount; + HWND Windows[MAX_WINDOWS]; +} WINDOW_LIST; +BOOL EnableProcessPriviledge(LPCTSTR pszSE_) +{ + BOOL f; + HANDLE hProcess; + HANDLE hToken; + LUID luid; + TOKEN_PRIVILEGES tp; + + f = FALSE; + hProcess = GetCurrentProcess(); + if (OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &hToken)) + { + if (LookupPrivilegeValue(NULL, pszSE_, &luid)) + { + tp.PrivilegeCount = 1; + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + tp.Privileges[0].Luid = luid; + f = AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL); + } + CloseHandle(hToken); + } + return f; +} + +static BOOL ListProcess(PROCESS_LIST *pList) +{ + pList->ProcessCount = 0; + + HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (hSnap == INVALID_HANDLE_VALUE) + return FALSE; + + PROCESSENTRY32 pe; + pe.dwSize = sizeof(pe); + if (Process32First(hSnap, &pe)) + { + do + { + pList->ProcessIDs[pList->ProcessCount++] = pe.th32ProcessID; + } while (Process32Next(hSnap, &pe)); + } + + CloseHandle(hSnap); + + return TRUE; +} + +static BOOL ListWindows(WINDOW_LIST *pList) +{ + pList->WindowCount = 0; + + HWND hwnd = GetTopWindow(NULL); + while (hwnd) + { + pList->Windows[pList->WindowCount++] = hwnd; + hwnd = GetWindow(hwnd, GW_HWNDNEXT); + } + + return TRUE; +} + +static BOOL +CloseProcessID(DWORD ProcessID) +{ + BOOL Ret = TRUE; + HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessID); + if (hProcess) + { + Ret = TerminateProcess(hProcess, 0xDEADFACE); + CloseHandle(hProcess); + } + return Ret; +} + +static INT +CloseOpenedProcess(PROCESS_LIST *pListBefore, PROCESS_LIST *pListAfter) +{ + INT m, n, Count = 0; + for (n = 0; n < pListAfter->ProcessCount; ++n) + { + DWORD ProcessID = pListAfter->ProcessIDs[n]; + for (m = 0; m < pListBefore->ProcessCount; ++m) + { + if (pListBefore->ProcessIDs[m] == ProcessID) + break; + } + if (m == pListBefore->ProcessCount) + { + Count += CloseProcessID(ProcessID); + } + } + return Count; +} + +static INT +CloseOpenedWindows(WINDOW_LIST *pListBefore, WINDOW_LIST *pListAfter) +{ + INT m, n, Count = 0; + for (n = 0; n < pListAfter->WindowCount; ++n) + { + for (m = 0; m < pListBefore->WindowCount; ++m) + { + if (pListBefore->Windows[m] == pListAfter->Windows[n]) + break; + } + if (m == pListBefore->WindowCount) + { + HWND hwnd = pListAfter->Windows[n]; + DWORD pid; + DWORD tid = GetWindowThreadProcessId(hwnd, &pid); + PostThreadMessage(tid, WM_CLOSE, 0, 0); + PostThreadMessage(tid, WM_SYSCOMMAND, SC_CLOSE, 0); + if (IsWindow(hwnd)) + { + Sleep(200); + if (IsWindow(hwnd)) + { + CloseProcessID(pid); // dangerous! + } + } + Count += !IsWindow(hwnd); + } + } + return Count; +} + static BOOL CreateAppPathRegKey(const WCHAR* Name) @@ -84,7 +225,8 @@ } } -START_TEST(ShellExecuteEx) +static void +Test_ShellExecuteEx(void) { ok_ShellExecuteEx(L"iexplore", TRUE); ok_ShellExecuteEx(L"iexplore.exe", TRUE); @@ -103,3 +245,173 @@ DeleteAppPathRegKey(L"iexplore.bat.exe"); } } + +static void +TestShellExecuteEx2(const WCHAR* File, const WCHAR* Params, BOOL ExpectedResult) +{ + SHELLEXECUTEINFOW ShellExecInfo; + BOOL Result; + ZeroMemory(&ShellExecInfo, sizeof(ShellExecInfo)); + ShellExecInfo.cbSize = sizeof(ShellExecInfo); + ShellExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI | + SEE_MASK_WAITFORINPUTIDLE; + ShellExecInfo.hwnd = NULL; + ShellExecInfo.nShow = SW_SHOWNORMAL; + ShellExecInfo.lpFile = File; + ShellExecInfo.lpParameters = Params; + Result = ShellExecuteExW(&ShellExecInfo); + ok(Result == ExpectedResult, "ShellExecute (%s, %s) failed. Error: %lu\n", + wine_dbgstr_w(File), wine_dbgstr_w(Params), GetLastError()); + if (ShellExecInfo.hProcess) + { + Result = TerminateProcess(ShellExecInfo.hProcess, 0); + if (!Result) trace("Terminate process failed. Error: %lu\n", GetLastError()); + WaitForSingleObject(ShellExecInfo.hProcess, 1000); + CloseHandle(ShellExecInfo.hProcess); + } +} + +static void +Test_ShellExecuteEx2(void) +{ + WCHAR WinDir[MAX_PATH], SysDir[MAX_PATH], FontsDir[MAX_PATH]; + WCHAR *pch, ReadMePath[MAX_PATH], ModifiedPath[MAX_PATH]; + + GetWindowsDirectoryW(WinDir, _countof(WinDir)); + GetSystemDirectoryW(SysDir, _countof(SysDir)); + lstrcpyW(FontsDir, WinDir); + lstrcatW(FontsDir, L"\\Fonts"); + + ok_ShellExecuteEx2(WinDir, NULL, TRUE); + ok_ShellExecuteEx2(SysDir, NULL, TRUE); + ok_ShellExecuteEx2(FontsDir, NULL, TRUE); + ok_ShellExecuteEx2(L"fonts", NULL, TRUE); + + ok_ShellExecuteEx2(L"explorer", WinDir, TRUE); + ok_ShellExecuteEx2(L"explorer", SysDir, TRUE); + ok_ShellExecuteEx2(L"explorer", FontsDir, TRUE); + ok_ShellExecuteEx2(L"explorer", L"fonts", TRUE); + + ok_ShellExecuteEx2(L"EXPLORER", WinDir, TRUE); + ok_ShellExecuteEx2(L"EXPLORER", SysDir, TRUE); + ok_ShellExecuteEx2(L"EXPLORER", FontsDir, TRUE); + ok_ShellExecuteEx2(L"EXPLORER", L"fonts", TRUE); + + ok_ShellExecuteEx2(L"explorer.exe", WinDir, TRUE); + ok_ShellExecuteEx2(L"explorer.exe", SysDir, TRUE); + ok_ShellExecuteEx2(L"explorer.exe", FontsDir, TRUE); + ok_ShellExecuteEx2(L"explorer.exe", L"fonts", TRUE); + + ok_ShellExecuteEx2(L"EXPLORER.EXE", WinDir, TRUE); + ok_ShellExecuteEx2(L"EXPLORER.EXE", SysDir, TRUE); + ok_ShellExecuteEx2(L"EXPLORER.EXE", FontsDir, TRUE); + ok_ShellExecuteEx2(L"EXPLORER.EXE", L"fonts", TRUE); + + ok_ShellExecuteEx2(L"notepad", NULL, TRUE); + ok_ShellExecuteEx2(L"NOTEPAD", NULL, TRUE); + + ok_ShellExecuteEx2(L"notepad.exe", NULL, TRUE); + ok_ShellExecuteEx2(L"NOTEPAD.EXE", NULL, TRUE); + + ok_ShellExecuteEx2(L"notepad.exe ", NULL, TRUE); + ok_ShellExecuteEx2(L"notepad.exe\t", NULL, FALSE); + ok_ShellExecuteEx2(L"notepad.exe\n", NULL, FALSE); + + ok_ShellExecuteEx2(L" notepad.exe", NULL, FALSE); + ok_ShellExecuteEx2(L"\tnotepad.exe", NULL, FALSE); + ok_ShellExecuteEx2(L"\nnotepad.exe", NULL, FALSE); + + GetModuleFileNameW(NULL, ReadMePath, _countof(ReadMePath)); + pch = wcsrchr(ReadMePath, L'\\'); + lstrcpyW(pch, L"\\testdata\\README.txt"); + + if (GetFileAttributesW(ReadMePath) == INVALID_FILE_ATTRIBUTES) + { + skip("Not found: %s\n", wine_dbgstr_w(ReadMePath)); + } + else + { + ok_ShellExecuteEx2(ReadMePath, NULL, TRUE); + + ok_ShellExecuteEx2(L"notepad", ReadMePath, TRUE); + ok_ShellExecuteEx2(L"NOTEPAD", ReadMePath, TRUE); + ok_ShellExecuteEx2(L"notepad.exe", ReadMePath, TRUE); + ok_ShellExecuteEx2(L"NOTEPAD.EXE", ReadMePath, TRUE); + + ok_ShellExecuteEx2(L"notepad.exe ", ReadMePath, TRUE); + ok_ShellExecuteEx2(L"notepad.exe\t", ReadMePath, FALSE); + ok_ShellExecuteEx2(L"notepad.exe\n", ReadMePath, FALSE); + ok_ShellExecuteEx2(L" notepad.exe", ReadMePath, FALSE); + ok_ShellExecuteEx2(L"\tnotepad.exe", ReadMePath, FALSE); + ok_ShellExecuteEx2(L"\nnotepad.exe", ReadMePath, FALSE); + + lstrcpyW(ModifiedPath, ReadMePath); + lstrcatW(ModifiedPath, L" "); + ok_ShellExecuteEx2(ModifiedPath, NULL, TRUE); + + lstrcpyW(ModifiedPath, ReadMePath); + lstrcatW(ModifiedPath, L"\t"); + ok_ShellExecuteEx2(ModifiedPath, NULL, FALSE); + + lstrcpyW(ModifiedPath, ReadMePath); + lstrcatW(ModifiedPath, L"\n"); + ok_ShellExecuteEx2(ModifiedPath, NULL, FALSE); + + lstrcpyW(ModifiedPath, L" "); + lstrcatW(ModifiedPath, ReadMePath); + ok_ShellExecuteEx2(ModifiedPath, NULL, FALSE); + + lstrcpyW(ModifiedPath, L"\t"); + lstrcatW(ModifiedPath, ReadMePath); + ok_ShellExecuteEx2(ModifiedPath, NULL, FALSE); + + lstrcpyW(ModifiedPath, L"\n"); + lstrcatW(ModifiedPath, ReadMePath); + ok_ShellExecuteEx2(ModifiedPath, NULL, FALSE); + } +} + +START_TEST(ShellExecuteEx) +{ + PROCESS_LIST ProcessListBefore, ProcessListAfter; + WINDOW_LIST WindowListBefore, WindowListAfter; + + trace("WARNING: This program will close newly-created process/window automatically.\n"); + + // CreateToolhelp32Snapshot needs this + EnableProcessPriviledge(SE_DEBUG_NAME); + + // get list before + if (!ListProcess(&ProcessListBefore)) + { + skip("ListProcess failed\n"); + return; + } + if (!ListWindows(&WindowListBefore)) + { + skip("ListWindows failed\n"); + return; + } + + // do tests + Test_ShellExecuteEx(); + Test_ShellExecuteEx2(); + + // get list after + ok(ListProcess(&ProcessListAfter), "ListProcess failed\n"); + ok(ListWindows(&WindowListAfter), "ListWindows failed\n"); + + // close the difference + CloseOpenedProcess(&ProcessListBefore, &ProcessListAfter); + CloseOpenedWindows(&WindowListBefore, &WindowListAfter); + + // get list after again + ok(ListProcess(&ProcessListAfter), "ListProcess failed\n"); + ok(ListWindows(&WindowListAfter), "ListWindows failed\n"); + + // check count + trace("ProcessCount before: %d, after: %d\n", + ProcessListBefore.ProcessCount, ProcessListAfter.ProcessCount); + trace("WindowCount before: %d, after: %d\n", + WindowListBefore.WindowCount, WindowListAfter.WindowCount); +}