Index: rostests/apitests/shell32/CMakeLists.txt =================================================================== --- rostests/apitests/shell32/CMakeLists.txt (revision 74978) +++ rostests/apitests/shell32/CMakeLists.txt (working copy) @@ -1,7 +1,7 @@ spec2def(shell32_apitest.exe shell32_apitest.spec) -set_cpp(WITH_RUNTIME) +set_cpp(WITH_EXCEPTIONS WITH_STL WITH_RUNTIME) include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/atl) Index: rostests/apitests/shell32/ShellExecuteEx.cpp =================================================================== --- rostests/apitests/shell32/ShellExecuteEx.cpp (revision 74978) +++ rostests/apitests/shell32/ShellExecuteEx.cpp (working copy) @@ -2,16 +2,150 @@ * 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 +#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 +typedef std::vector PROCESS_LIST; +typedef std::vector WINDOW_LIST; -#define ok_ShellExecuteEx (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : TestShellExecuteEx +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& vec) +{ + vec.clear(); + + HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (hSnap == INVALID_HANDLE_VALUE) + return FALSE; + + PROCESSENTRY32 pe; + pe.dwSize = sizeof(pe); + if (Process32First(hSnap, &pe)) + { + do + { + vec.push_back(pe.th32ProcessID); + } while (Process32Next(hSnap, &pe)); + } + + CloseHandle(hSnap); + + return TRUE; +} + +static BOOL ListWindows(WINDOW_LIST& vec) +{ + vec.clear(); + + HWND hwnd = GetTopWindow(NULL); + while (hwnd) + { + vec.push_back(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& vec_before, PROCESS_LIST& vec_after) +{ + INT Count = 0; + PROCESS_LIST::iterator it1, end1 = vec_after.end(); + for (it1 = vec_after.begin(); it1 != end1; ++it1) + { + PROCESS_LIST::iterator it2, end2 = vec_before.end(); + for (it2 = vec_before.begin(); it2 != end2; ++it2) + { + if (*it1 == *it2) + break; + } + if (it2 == end2) + { + Count += CloseProcessID(*it1); + } + } + return Count; +} + +static INT +CloseOpenedWindows(WINDOW_LIST& vec_before, WINDOW_LIST& vec_after) +{ + INT Count = 0; + WINDOW_LIST::iterator it1, end1 = vec_after.end(); + for (it1 = vec_after.begin(); it1 != end1; ++it1) + { + WINDOW_LIST::iterator it2, end2 = vec_before.end(); + for (it2 = vec_before.begin(); it2 != end2; ++it2) + { + if (*it1 == *it2) + break; + } + if (it2 == end2) + { + HWND hwnd = *it1; + 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 +218,8 @@ } } -START_TEST(ShellExecuteEx) +static void +Test_ShellExecuteEx(void) { ok_ShellExecuteEx(L"iexplore", TRUE); ok_ShellExecuteEx(L"iexplore.exe", TRUE); @@ -103,3 +238,175 @@ 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 + INT PCount = CloseOpenedProcess(ProcessListBefore, ProcessListAfter); + INT WCount = CloseOpenedWindows(WindowListBefore, WindowListAfter); + trace("PCount: %d\n", PCount); + trace("WCount: %d\n", WCount); + + // 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", + int(ProcessListBefore.size()), int(ProcessListAfter.size())); + trace("WindowCount before: %d, after: %d\n", + int(WindowListBefore.size()), int(WindowListAfter.size())); +}