1c2c66affSColin Finck /* 2c2c66affSColin Finck * PROJECT: ReactOS api tests 3c2c66affSColin Finck * LICENSE: GPLv2+ - See COPYING in the top level directory 4c2c66affSColin Finck * PURPOSE: Testing ShellExecuteEx 5c2c66affSColin Finck * PROGRAMMER: Yaroslav Veremenko <yaroslav@veremenko.info> 6c35a8498SKatayama Hirofumi MZ * Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 7c2c66affSColin Finck */ 8c2c66affSColin Finck 9c2c66affSColin Finck #include "shelltest.h" 10c35a8498SKatayama Hirofumi MZ #include <shlwapi.h> 11c35a8498SKatayama Hirofumi MZ #include <stdio.h> 1260b89da3SKatayama Hirofumi MZ #include "shell32_apitest_sub.h" 13c2c66affSColin Finck 14c2c66affSColin Finck #define ok_ShellExecuteEx (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : TestShellExecuteEx 15c2c66affSColin Finck 16c2c66affSColin Finck static 17c2c66affSColin Finck BOOL 18c2c66affSColin Finck CreateAppPathRegKey(const WCHAR* Name) 19c2c66affSColin Finck { 20c2c66affSColin Finck HKEY RegistryKey; 21c2c66affSColin Finck LONG Result; 22c2c66affSColin Finck WCHAR Buffer[1024]; 23c2c66affSColin Finck WCHAR KeyValue[1024]; 24c2c66affSColin Finck DWORD Length = sizeof(KeyValue); 25c2c66affSColin Finck DWORD Disposition; 26c2c66affSColin Finck 27c2c66affSColin Finck wcscpy(Buffer, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\"); 28c2c66affSColin Finck wcscat(Buffer, L"IEXPLORE.EXE"); 29c2c66affSColin Finck Result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, Buffer, 0, KEY_READ, &RegistryKey); 30c2c66affSColin Finck if (Result != ERROR_SUCCESS) trace("Could not open iexplore.exe key. Status: %lu\n", Result); 31c2c66affSColin Finck if (Result) goto end; 32c2c66affSColin Finck Result = RegQueryValueExW(RegistryKey, NULL, NULL, NULL, (LPBYTE)KeyValue, &Length); 33c2c66affSColin Finck if (Result != ERROR_SUCCESS) trace("Could not read iexplore.exe key. Status: %lu\n", Result); 34c2c66affSColin Finck if (Result) goto end; 35c2c66affSColin Finck RegCloseKey(RegistryKey); 36c2c66affSColin Finck 37c2c66affSColin Finck wcscpy(Buffer, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\"); 38c2c66affSColin Finck wcscat(Buffer, Name); 39c2c66affSColin Finck Result = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Buffer, 0, NULL, 40c2c66affSColin Finck 0, KEY_WRITE, NULL, &RegistryKey, &Disposition); 41c2c66affSColin Finck if (Result != ERROR_SUCCESS) trace("Could not create test key. Status: %lu\n", Result); 42c2c66affSColin Finck if (Result) goto end; 43c2c66affSColin Finck Result = RegSetValueW(RegistryKey, NULL, REG_SZ, KeyValue, 0); 44c2c66affSColin Finck if (Result != ERROR_SUCCESS) trace("Could not set value of the test key. Status: %lu\n", Result); 45c2c66affSColin Finck if (Result) goto end; 46c2c66affSColin Finck RegCloseKey(RegistryKey); 47c2c66affSColin Finck end: 48c2c66affSColin Finck if (RegistryKey) RegCloseKey(RegistryKey); 49c2c66affSColin Finck return Result == ERROR_SUCCESS; 50c2c66affSColin Finck } 51c2c66affSColin Finck 52c2c66affSColin Finck static 53c2c66affSColin Finck VOID 54c2c66affSColin Finck DeleteAppPathRegKey(const WCHAR* Name) 55c2c66affSColin Finck { 56c2c66affSColin Finck LONG Result; 57c2c66affSColin Finck WCHAR Buffer[1024]; 58c2c66affSColin Finck wcscpy(Buffer, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\"); 59c2c66affSColin Finck wcscat(Buffer, Name); 60c2c66affSColin Finck Result = RegDeleteKeyW(HKEY_LOCAL_MACHINE, Buffer); 61c2c66affSColin Finck if (Result != ERROR_SUCCESS) trace("Could not remove the test key. Status: %lu\n", Result); 62c2c66affSColin Finck } 63c2c66affSColin Finck 64c2c66affSColin Finck static 65c2c66affSColin Finck VOID 66c2c66affSColin Finck TestShellExecuteEx(const WCHAR* Name, BOOL ExpectedResult) 67c2c66affSColin Finck { 68c2c66affSColin Finck SHELLEXECUTEINFOW ShellExecInfo; 69c2c66affSColin Finck BOOL Result; 70307ce1a5SHermès Bélusca-Maïto 71c2c66affSColin Finck ZeroMemory(&ShellExecInfo, sizeof(ShellExecInfo)); 72c2c66affSColin Finck ShellExecInfo.cbSize = sizeof(ShellExecInfo); 73c2c66affSColin Finck ShellExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI; 74c2c66affSColin Finck ShellExecInfo.hwnd = NULL; 75c2c66affSColin Finck ShellExecInfo.nShow = SW_SHOWNORMAL; 76c2c66affSColin Finck ShellExecInfo.lpFile = Name; 77c2c66affSColin Finck ShellExecInfo.lpDirectory = NULL; 78307ce1a5SHermès Bélusca-Maïto 79c2c66affSColin Finck Result = ShellExecuteExW(&ShellExecInfo); 80c2c66affSColin Finck ok(Result == ExpectedResult, "ShellExecuteEx lpFile %s failed. Error: %lu\n", wine_dbgstr_w(Name), GetLastError()); 81c2c66affSColin Finck if (ShellExecInfo.hProcess) 82c2c66affSColin Finck { 83c2c66affSColin Finck Result = TerminateProcess(ShellExecInfo.hProcess, 0); 84c2c66affSColin Finck if (!Result) trace("Terminate process failed. Error: %lu\n", GetLastError()); 85c2c66affSColin Finck WaitForSingleObject(ShellExecInfo.hProcess, INFINITE); 86c2c66affSColin Finck CloseHandle(ShellExecInfo.hProcess); 87c2c66affSColin Finck } 88c2c66affSColin Finck } 89c2c66affSColin Finck 90c35a8498SKatayama Hirofumi MZ static void DoAppPathTest(void) 91c2c66affSColin Finck { 92c2c66affSColin Finck ok_ShellExecuteEx(L"iexplore", TRUE); 93c2c66affSColin Finck ok_ShellExecuteEx(L"iexplore.exe", TRUE); 94c2c66affSColin Finck 95c2c66affSColin Finck if (CreateAppPathRegKey(L"iexplore.bat")) 96c2c66affSColin Finck { 97c2c66affSColin Finck ok_ShellExecuteEx(L"iexplore.bat", TRUE); 98c2c66affSColin Finck ok_ShellExecuteEx(L"iexplore.bat.exe", FALSE); 99c2c66affSColin Finck DeleteAppPathRegKey(L"iexplore.bat"); 100c2c66affSColin Finck } 101c2c66affSColin Finck 102c2c66affSColin Finck if (CreateAppPathRegKey(L"iexplore.bat.exe")) 103c2c66affSColin Finck { 104c2c66affSColin Finck ok_ShellExecuteEx(L"iexplore.bat", FALSE); 105c2c66affSColin Finck ok_ShellExecuteEx(L"iexplore.bat.exe", TRUE); 106c2c66affSColin Finck DeleteAppPathRegKey(L"iexplore.bat.exe"); 107c2c66affSColin Finck } 108c2c66affSColin Finck } 109c35a8498SKatayama Hirofumi MZ 110c35a8498SKatayama Hirofumi MZ typedef struct TEST_ENTRY 111c35a8498SKatayama Hirofumi MZ { 112c35a8498SKatayama Hirofumi MZ INT lineno; 113c35a8498SKatayama Hirofumi MZ BOOL ret; 114c35a8498SKatayama Hirofumi MZ BOOL bProcessHandle; 115c35a8498SKatayama Hirofumi MZ LPCSTR file; 116c35a8498SKatayama Hirofumi MZ LPCSTR params; 117c35a8498SKatayama Hirofumi MZ LPCSTR curdir; 118c35a8498SKatayama Hirofumi MZ } TEST_ENTRY; 119c35a8498SKatayama Hirofumi MZ 120c35a8498SKatayama Hirofumi MZ static char s_sub_program[MAX_PATH]; 121c35a8498SKatayama Hirofumi MZ static char s_win_test_exe[MAX_PATH]; 122c35a8498SKatayama Hirofumi MZ static char s_sys_test_exe[MAX_PATH]; 123c35a8498SKatayama Hirofumi MZ static char s_win_bat_file[MAX_PATH]; 124c35a8498SKatayama Hirofumi MZ static char s_sys_bat_file[MAX_PATH]; 125c35a8498SKatayama Hirofumi MZ static char s_win_txt_file[MAX_PATH]; 126c35a8498SKatayama Hirofumi MZ static char s_sys_txt_file[MAX_PATH]; 127c35a8498SKatayama Hirofumi MZ 128c35a8498SKatayama Hirofumi MZ #define DONT_CARE 0x0BADF00D 129c35a8498SKatayama Hirofumi MZ 130c35a8498SKatayama Hirofumi MZ static const TEST_ENTRY s_entries_1[] = 131c35a8498SKatayama Hirofumi MZ { 132c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, "test program" }, 133c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, "test program.bat" }, 134c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, "test program.exe" }, 135c35a8498SKatayama Hirofumi MZ { __LINE__, FALSE, FALSE, " test program" }, 136c35a8498SKatayama Hirofumi MZ { __LINE__, FALSE, FALSE, " test program.bat" }, 137c35a8498SKatayama Hirofumi MZ { __LINE__, FALSE, FALSE, " test program.exe" }, 138c35a8498SKatayama Hirofumi MZ { __LINE__, FALSE, FALSE, "test program " }, 139c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, "test program.bat " }, 140c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, "test program.exe " }, 141c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, "test program", "TEST" }, 142c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, "test program.bat", "TEST" }, 143c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, "test program.exe", "TEST" }, 144c35a8498SKatayama Hirofumi MZ { __LINE__, FALSE, FALSE, ".\\test program.bat" }, 145c35a8498SKatayama Hirofumi MZ { __LINE__, FALSE, FALSE, ".\\test program.exe" }, 146c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, "\"test program\"" }, 147c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, "\"test program.bat\"" }, 148c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, "\"test program.exe\"" }, 149c35a8498SKatayama Hirofumi MZ { __LINE__, FALSE, FALSE, "\"test program\" TEST" }, 150c35a8498SKatayama Hirofumi MZ { __LINE__, FALSE, FALSE, "\"test program.bat\" TEST" }, 151c35a8498SKatayama Hirofumi MZ { __LINE__, FALSE, FALSE, "\"test program.exe\" TEST" }, 152c35a8498SKatayama Hirofumi MZ { __LINE__, FALSE, FALSE, " \"test program\"" }, 153c35a8498SKatayama Hirofumi MZ { __LINE__, FALSE, FALSE, " \"test program.bat\"" }, 154c35a8498SKatayama Hirofumi MZ { __LINE__, FALSE, FALSE, " \"test program.exe\"" }, 155c35a8498SKatayama Hirofumi MZ { __LINE__, FALSE, FALSE, "\"test program\" " }, 156c35a8498SKatayama Hirofumi MZ { __LINE__, FALSE, FALSE, "\"test program.bat\" " }, 157c35a8498SKatayama Hirofumi MZ { __LINE__, FALSE, FALSE, "\"test program.exe\" " }, 158c35a8498SKatayama Hirofumi MZ { __LINE__, FALSE, FALSE, "\".\\test program.bat\"" }, 159c35a8498SKatayama Hirofumi MZ { __LINE__, FALSE, FALSE, "\".\\test program.exe\"" }, 160c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, s_win_test_exe }, 161c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, s_sys_test_exe }, 162c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, s_win_bat_file }, 163c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, s_sys_bat_file }, 164c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, s_win_bat_file, "TEST" }, 165c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, s_sys_bat_file, "TEST" }, 166c35a8498SKatayama Hirofumi MZ { __LINE__, FALSE, FALSE, "invalid program" }, 167c35a8498SKatayama Hirofumi MZ { __LINE__, FALSE, FALSE, "invalid program.bat" }, 168c35a8498SKatayama Hirofumi MZ { __LINE__, FALSE, FALSE, "invalid program.exe" }, 169c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, "test_file.txt" }, 170c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, "test_file.txt", "parameters parameters" }, 171c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, "test_file.txt", "parameters parameters", "." }, 172c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, "shell32_apitest_sub.exe" }, 173c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, ".\\shell32_apitest_sub.exe" }, 174c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, "\"shell32_apitest_sub.exe\"" }, 175c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, "\".\\shell32_apitest_sub.exe\"" }, 176c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, DONT_CARE, "https://google.com" }, 177c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, FALSE, "::{450d8fba-ad25-11d0-98a8-0800361b1103}" }, 178c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, FALSE, "shell:::{450d8fba-ad25-11d0-98a8-0800361b1103}" }, 179c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, FALSE, "shell:sendto" }, 180c35a8498SKatayama Hirofumi MZ }; 181c35a8498SKatayama Hirofumi MZ 182c35a8498SKatayama Hirofumi MZ static const TEST_ENTRY s_entries_2[] = 183c35a8498SKatayama Hirofumi MZ { 184c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, "test program" }, 185c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, "test program", "TEST" }, 186c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, "\"test program\"" }, 187c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, s_win_test_exe }, 188c35a8498SKatayama Hirofumi MZ { __LINE__, TRUE, TRUE, s_sys_test_exe }, 189c35a8498SKatayama Hirofumi MZ { __LINE__, FALSE, FALSE, s_win_bat_file }, 190c35a8498SKatayama Hirofumi MZ { __LINE__, FALSE, FALSE, s_sys_bat_file }, 191c35a8498SKatayama Hirofumi MZ { __LINE__, FALSE, FALSE, s_win_bat_file, "TEST" }, 192c35a8498SKatayama Hirofumi MZ { __LINE__, FALSE, FALSE, s_sys_bat_file, "TEST" }, 193c35a8498SKatayama Hirofumi MZ }; 194c35a8498SKatayama Hirofumi MZ 195c35a8498SKatayama Hirofumi MZ typedef struct OPENWNDS 196c35a8498SKatayama Hirofumi MZ { 197c35a8498SKatayama Hirofumi MZ UINT count; 198c35a8498SKatayama Hirofumi MZ HWND *phwnd; 199c35a8498SKatayama Hirofumi MZ } OPENWNDS; 200c35a8498SKatayama Hirofumi MZ 201c35a8498SKatayama Hirofumi MZ static OPENWNDS s_wi0 = { 0 }, s_wi1 = { 0 }; 202c35a8498SKatayama Hirofumi MZ 203c35a8498SKatayama Hirofumi MZ static BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) 204c35a8498SKatayama Hirofumi MZ { 205c35a8498SKatayama Hirofumi MZ OPENWNDS *info = (OPENWNDS *)lParam; 206c35a8498SKatayama Hirofumi MZ info->phwnd = (HWND *)realloc(info->phwnd, (info->count + 1) * sizeof(HWND)); 207c35a8498SKatayama Hirofumi MZ if (!info->phwnd) 208c35a8498SKatayama Hirofumi MZ return FALSE; 209c35a8498SKatayama Hirofumi MZ info->phwnd[info->count] = hwnd; 210c35a8498SKatayama Hirofumi MZ ++(info->count); 211c35a8498SKatayama Hirofumi MZ return TRUE; 212c35a8498SKatayama Hirofumi MZ } 213c35a8498SKatayama Hirofumi MZ 214307ce1a5SHermès Bélusca-Maïto static void CleanupNewlyCreatedWindows(void) 215307ce1a5SHermès Bélusca-Maïto { 216307ce1a5SHermès Bélusca-Maïto EnumWindows(EnumWindowsProc, (LPARAM)&s_wi1); 217307ce1a5SHermès Bélusca-Maïto for (UINT i1 = 0; i1 < s_wi1.count; ++i1) 218307ce1a5SHermès Bélusca-Maïto { 219307ce1a5SHermès Bélusca-Maïto BOOL bFound = FALSE; 220307ce1a5SHermès Bélusca-Maïto for (UINT i0 = 0; i0 < s_wi0.count; ++i0) 221307ce1a5SHermès Bélusca-Maïto { 222307ce1a5SHermès Bélusca-Maïto if (s_wi1.phwnd[i1] == s_wi0.phwnd[i0]) 223307ce1a5SHermès Bélusca-Maïto { 224307ce1a5SHermès Bélusca-Maïto bFound = TRUE; 225307ce1a5SHermès Bélusca-Maïto break; 226307ce1a5SHermès Bélusca-Maïto } 227307ce1a5SHermès Bélusca-Maïto } 228307ce1a5SHermès Bélusca-Maïto if (!bFound) 229307ce1a5SHermès Bélusca-Maïto PostMessageW(s_wi1.phwnd[i1], WM_CLOSE, 0, 0); 230307ce1a5SHermès Bélusca-Maïto } 231307ce1a5SHermès Bélusca-Maïto free(s_wi1.phwnd); 232307ce1a5SHermès Bélusca-Maïto ZeroMemory(&s_wi1, sizeof(s_wi1)); 233307ce1a5SHermès Bélusca-Maïto } 234307ce1a5SHermès Bélusca-Maïto 235c35a8498SKatayama Hirofumi MZ static VOID DoTestEntry(const TEST_ENTRY *pEntry) 236c35a8498SKatayama Hirofumi MZ { 237c35a8498SKatayama Hirofumi MZ SHELLEXECUTEINFOA info = { sizeof(info) }; 238c35a8498SKatayama Hirofumi MZ info.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI; 239c35a8498SKatayama Hirofumi MZ info.nShow = SW_SHOWNORMAL; 240c35a8498SKatayama Hirofumi MZ info.lpFile = pEntry->file; 241c35a8498SKatayama Hirofumi MZ info.lpParameters = pEntry->params; 242c35a8498SKatayama Hirofumi MZ info.lpDirectory = pEntry->curdir; 243c35a8498SKatayama Hirofumi MZ BOOL ret = ShellExecuteExA(&info); 244c35a8498SKatayama Hirofumi MZ ok(ret == pEntry->ret, "Line %u: ret expected %d, got %d\n", 245c35a8498SKatayama Hirofumi MZ pEntry->lineno, pEntry->ret, ret); 246c35a8498SKatayama Hirofumi MZ if (!pEntry->ret) 247c35a8498SKatayama Hirofumi MZ return; 248c35a8498SKatayama Hirofumi MZ 249c35a8498SKatayama Hirofumi MZ if ((UINT)pEntry->bProcessHandle != DONT_CARE) 250c35a8498SKatayama Hirofumi MZ { 251c35a8498SKatayama Hirofumi MZ if (pEntry->bProcessHandle) 252c35a8498SKatayama Hirofumi MZ { 253c35a8498SKatayama Hirofumi MZ ok(!!info.hProcess, "Line %u: hProcess expected non-NULL\n", pEntry->lineno); 254c35a8498SKatayama Hirofumi MZ } 255c35a8498SKatayama Hirofumi MZ else 256c35a8498SKatayama Hirofumi MZ { 257c35a8498SKatayama Hirofumi MZ ok(!info.hProcess, "Line %u: hProcess expected NULL\n", pEntry->lineno); 258c35a8498SKatayama Hirofumi MZ return; 259c35a8498SKatayama Hirofumi MZ } 260c35a8498SKatayama Hirofumi MZ } 261c35a8498SKatayama Hirofumi MZ 262c35a8498SKatayama Hirofumi MZ WaitForInputIdle(info.hProcess, INFINITE); 263c35a8498SKatayama Hirofumi MZ 264307ce1a5SHermès Bélusca-Maïto CleanupNewlyCreatedWindows(); 265c35a8498SKatayama Hirofumi MZ 266f80de47cSMark Jansen if (WaitForSingleObject(info.hProcess, 10 * 1000) == WAIT_TIMEOUT) 267f80de47cSMark Jansen { 268f80de47cSMark Jansen TerminateProcess(info.hProcess, 11); 269f80de47cSMark Jansen ok(0, "Process %s did not quit!\n", pEntry->file); 270f80de47cSMark Jansen } 271c35a8498SKatayama Hirofumi MZ CloseHandle(info.hProcess); 272c35a8498SKatayama Hirofumi MZ } 273c35a8498SKatayama Hirofumi MZ 274c35a8498SKatayama Hirofumi MZ static BOOL 275c35a8498SKatayama Hirofumi MZ GetSubProgramPath(void) 276c35a8498SKatayama Hirofumi MZ { 277c35a8498SKatayama Hirofumi MZ GetModuleFileNameA(NULL, s_sub_program, _countof(s_sub_program)); 278c35a8498SKatayama Hirofumi MZ PathRemoveFileSpecA(s_sub_program); 279c35a8498SKatayama Hirofumi MZ PathAppendA(s_sub_program, "shell32_apitest_sub.exe"); 280c35a8498SKatayama Hirofumi MZ 281c35a8498SKatayama Hirofumi MZ if (!PathFileExistsA(s_sub_program)) 282c35a8498SKatayama Hirofumi MZ { 283c35a8498SKatayama Hirofumi MZ PathRemoveFileSpecA(s_sub_program); 284c35a8498SKatayama Hirofumi MZ PathAppendA(s_sub_program, "testdata\\shell32_apitest_sub.exe"); 285c35a8498SKatayama Hirofumi MZ 286c35a8498SKatayama Hirofumi MZ if (!PathFileExistsA(s_sub_program)) 287c35a8498SKatayama Hirofumi MZ { 288c35a8498SKatayama Hirofumi MZ return FALSE; 289c35a8498SKatayama Hirofumi MZ } 290c35a8498SKatayama Hirofumi MZ } 291c35a8498SKatayama Hirofumi MZ 292c35a8498SKatayama Hirofumi MZ return TRUE; 293c35a8498SKatayama Hirofumi MZ } 294c35a8498SKatayama Hirofumi MZ 295c35a8498SKatayama Hirofumi MZ static void DoTestEntries(void) 296c35a8498SKatayama Hirofumi MZ { 297c35a8498SKatayama Hirofumi MZ if (!GetSubProgramPath()) 298c35a8498SKatayama Hirofumi MZ { 299c35a8498SKatayama Hirofumi MZ skip("shell32_apitest_sub.exe is not found\n"); 300c35a8498SKatayama Hirofumi MZ return; 301c35a8498SKatayama Hirofumi MZ } 302c35a8498SKatayama Hirofumi MZ 303c35a8498SKatayama Hirofumi MZ // s_win_test_exe 304c35a8498SKatayama Hirofumi MZ GetWindowsDirectoryA(s_win_test_exe, _countof(s_win_test_exe)); 305c35a8498SKatayama Hirofumi MZ PathAppendA(s_win_test_exe, "test program.exe"); 306c35a8498SKatayama Hirofumi MZ BOOL ret = CopyFileA(s_sub_program, s_win_test_exe, FALSE); 307c35a8498SKatayama Hirofumi MZ if (!ret) 308c35a8498SKatayama Hirofumi MZ { 309c35a8498SKatayama Hirofumi MZ skip("Please retry with admin rights\n"); 310c35a8498SKatayama Hirofumi MZ return; 311c35a8498SKatayama Hirofumi MZ } 312c35a8498SKatayama Hirofumi MZ 313c35a8498SKatayama Hirofumi MZ // record open windows 314c35a8498SKatayama Hirofumi MZ if (!EnumWindows(EnumWindowsProc, (LPARAM)&s_wi0)) 315c35a8498SKatayama Hirofumi MZ { 316c35a8498SKatayama Hirofumi MZ skip("EnumWindows failed\n"); 317c35a8498SKatayama Hirofumi MZ DeleteFileA(s_win_test_exe); 318c35a8498SKatayama Hirofumi MZ free(s_wi0.phwnd); 319c35a8498SKatayama Hirofumi MZ return; 320c35a8498SKatayama Hirofumi MZ } 321c35a8498SKatayama Hirofumi MZ 322c35a8498SKatayama Hirofumi MZ // s_sys_test_exe 323c35a8498SKatayama Hirofumi MZ GetSystemDirectoryA(s_sys_test_exe, _countof(s_sys_test_exe)); 324c35a8498SKatayama Hirofumi MZ PathAppendA(s_sys_test_exe, "test program.exe"); 325c35a8498SKatayama Hirofumi MZ ok_int(CopyFileA(s_sub_program, s_sys_test_exe, FALSE), TRUE); 326c35a8498SKatayama Hirofumi MZ 327c35a8498SKatayama Hirofumi MZ // s_win_bat_file 328c35a8498SKatayama Hirofumi MZ GetWindowsDirectoryA(s_win_bat_file, _countof(s_win_bat_file)); 329c35a8498SKatayama Hirofumi MZ PathAppendA(s_win_bat_file, "test program.bat"); 330c35a8498SKatayama Hirofumi MZ FILE *fp = fopen(s_win_bat_file, "wb"); 331c35a8498SKatayama Hirofumi MZ fprintf(fp, "exit /b 3"); 332c35a8498SKatayama Hirofumi MZ fclose(fp); 333c35a8498SKatayama Hirofumi MZ ok_int(PathFileExistsA(s_win_bat_file), TRUE); 334c35a8498SKatayama Hirofumi MZ 335c35a8498SKatayama Hirofumi MZ // s_sys_bat_file 336c35a8498SKatayama Hirofumi MZ GetSystemDirectoryA(s_sys_bat_file, _countof(s_sys_bat_file)); 337c35a8498SKatayama Hirofumi MZ PathAppendA(s_sys_bat_file, "test program.bat"); 338c35a8498SKatayama Hirofumi MZ fp = fopen(s_sys_bat_file, "wb"); 339c35a8498SKatayama Hirofumi MZ fprintf(fp, "exit /b 4"); 340c35a8498SKatayama Hirofumi MZ fclose(fp); 341c35a8498SKatayama Hirofumi MZ ok_int(PathFileExistsA(s_sys_bat_file), TRUE); 342c35a8498SKatayama Hirofumi MZ 343c35a8498SKatayama Hirofumi MZ // s_win_txt_file 344c35a8498SKatayama Hirofumi MZ GetWindowsDirectoryA(s_win_txt_file, _countof(s_win_txt_file)); 345c35a8498SKatayama Hirofumi MZ PathAppendA(s_win_txt_file, "test_file.txt"); 346c35a8498SKatayama Hirofumi MZ fp = fopen(s_win_txt_file, "wb"); 347c35a8498SKatayama Hirofumi MZ fclose(fp); 348c35a8498SKatayama Hirofumi MZ ok_int(PathFileExistsA(s_win_txt_file), TRUE); 349c35a8498SKatayama Hirofumi MZ 350c35a8498SKatayama Hirofumi MZ // s_sys_txt_file 351c35a8498SKatayama Hirofumi MZ GetSystemDirectoryA(s_sys_txt_file, _countof(s_sys_txt_file)); 352c35a8498SKatayama Hirofumi MZ PathAppendA(s_sys_txt_file, "test_file.txt"); 353c35a8498SKatayama Hirofumi MZ fp = fopen(s_sys_txt_file, "wb"); 354c35a8498SKatayama Hirofumi MZ fclose(fp); 355c35a8498SKatayama Hirofumi MZ ok_int(PathFileExistsA(s_sys_txt_file), TRUE); 356c35a8498SKatayama Hirofumi MZ 357c35a8498SKatayama Hirofumi MZ for (UINT iTest = 0; iTest < _countof(s_entries_1); ++iTest) 358c35a8498SKatayama Hirofumi MZ { 359c35a8498SKatayama Hirofumi MZ DoTestEntry(&s_entries_1[iTest]); 360c35a8498SKatayama Hirofumi MZ } 361c35a8498SKatayama Hirofumi MZ 362c35a8498SKatayama Hirofumi MZ DeleteFileA(s_win_bat_file); 363c35a8498SKatayama Hirofumi MZ DeleteFileA(s_sys_bat_file); 364c35a8498SKatayama Hirofumi MZ 365c35a8498SKatayama Hirofumi MZ for (UINT iTest = 0; iTest < _countof(s_entries_2); ++iTest) 366c35a8498SKatayama Hirofumi MZ { 367c35a8498SKatayama Hirofumi MZ DoTestEntry(&s_entries_2[iTest]); 368c35a8498SKatayama Hirofumi MZ } 369c35a8498SKatayama Hirofumi MZ 370c35a8498SKatayama Hirofumi MZ DeleteFileA(s_win_test_exe); 371c35a8498SKatayama Hirofumi MZ DeleteFileA(s_sys_test_exe); 372c35a8498SKatayama Hirofumi MZ DeleteFileA(s_win_txt_file); 373c35a8498SKatayama Hirofumi MZ DeleteFileA(s_sys_txt_file); 374c35a8498SKatayama Hirofumi MZ 375c35a8498SKatayama Hirofumi MZ free(s_wi0.phwnd); 376c35a8498SKatayama Hirofumi MZ } 377c35a8498SKatayama Hirofumi MZ 378f80de47cSMark Jansen WCHAR* ExeName = NULL; 379f80de47cSMark Jansen 380f80de47cSMark Jansen BOOL CALLBACK EnumProc(_In_ HWND hwnd, _In_ LPARAM lParam) 381f80de47cSMark Jansen { 382f80de47cSMark Jansen DWORD pid = 0; 383f80de47cSMark Jansen GetWindowThreadProcessId(hwnd, &pid); 384f80de47cSMark Jansen if (pid == GetCurrentProcessId() && 385f80de47cSMark Jansen IsWindowVisible(hwnd)) 386f80de47cSMark Jansen { 387f80de47cSMark Jansen WCHAR Buffer[512] = {0}; 388f80de47cSMark Jansen 389f80de47cSMark Jansen GetWindowTextW(hwnd, Buffer, _countof(Buffer) - 1); 390f80de47cSMark Jansen if (Buffer[0] && StrStrIW(Buffer, ExeName)) 391f80de47cSMark Jansen { 392f80de47cSMark Jansen HWND* pHwnd = (HWND*)lParam; 393f80de47cSMark Jansen *pHwnd = hwnd; 394f80de47cSMark Jansen return FALSE; 395f80de47cSMark Jansen } 396f80de47cSMark Jansen } 397f80de47cSMark Jansen return TRUE; 398f80de47cSMark Jansen } 399f80de47cSMark Jansen 400f80de47cSMark Jansen BOOL WaitAndCloseWindow() 401f80de47cSMark Jansen { 402f80de47cSMark Jansen HWND hWnd = NULL; 403f80de47cSMark Jansen for (int n = 0; n < 100; ++n) 404f80de47cSMark Jansen { 405f80de47cSMark Jansen Sleep(50); 406f80de47cSMark Jansen 407f80de47cSMark Jansen EnumWindows(EnumProc, (LPARAM)&hWnd); 408f80de47cSMark Jansen 409f80de47cSMark Jansen if (hWnd) 410f80de47cSMark Jansen { 411f80de47cSMark Jansen SendMessageW(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0); 412f80de47cSMark Jansen return TRUE; 413f80de47cSMark Jansen break; 414f80de47cSMark Jansen } 415f80de47cSMark Jansen } 416f80de47cSMark Jansen return FALSE; 417f80de47cSMark Jansen } 418f80de47cSMark Jansen 419f80de47cSMark Jansen static void test_properties() 420f80de47cSMark Jansen { 421f80de47cSMark Jansen WCHAR Buffer[MAX_PATH * 4]; 422f80de47cSMark Jansen 423f80de47cSMark Jansen CoInitialize(NULL); 424f80de47cSMark Jansen 425f80de47cSMark Jansen GetModuleFileNameW(NULL, Buffer, _countof(Buffer)); 426f80de47cSMark Jansen SHELLEXECUTEINFOW info = { 0 }; 427f80de47cSMark Jansen 428f80de47cSMark Jansen info.cbSize = sizeof(SHELLEXECUTEINFOW); 429f80de47cSMark Jansen info.fMask = SEE_MASK_INVOKEIDLIST | SEE_MASK_FLAG_NO_UI; 430f80de47cSMark Jansen info.lpVerb = L"properties"; 431f80de47cSMark Jansen info.lpFile = Buffer; 432f80de47cSMark Jansen info.lpParameters = L""; 433f80de47cSMark Jansen info.nShow = SW_SHOW; 434f80de47cSMark Jansen 435f80de47cSMark Jansen BOOL bRet = ShellExecuteExW(&info); 436f80de47cSMark Jansen ok(bRet, "Failed! (GetLastError(): %d)\n", (int)GetLastError()); 437f80de47cSMark Jansen ok_ptr(info.hInstApp, (HINSTANCE)42); 438f80de47cSMark Jansen 439f80de47cSMark Jansen ExeName = PathFindFileNameW(Buffer); 440f80de47cSMark Jansen WCHAR* Extension = PathFindExtensionW(Buffer); 441f80de47cSMark Jansen if (Extension) 442f80de47cSMark Jansen { 443f80de47cSMark Jansen // The inclusion of this depends on the file display settings! 444f80de47cSMark Jansen *Extension = UNICODE_NULL; 445f80de47cSMark Jansen } 446f80de47cSMark Jansen 447f80de47cSMark Jansen if (bRet) 448f80de47cSMark Jansen { 449f80de47cSMark Jansen ok(WaitAndCloseWindow(), "Could not find properties window!\n"); 450f80de47cSMark Jansen } 451f80de47cSMark Jansen 452f80de47cSMark Jansen // Now retry it with the extension cut off 453f80de47cSMark Jansen bRet = ShellExecuteExW(&info); 454f80de47cSMark Jansen ok(bRet, "Failed! (GetLastError(): %d)\n", (int)GetLastError()); 455f80de47cSMark Jansen ok_ptr(info.hInstApp, (HINSTANCE)42); 456f80de47cSMark Jansen 457f80de47cSMark Jansen if (bRet) 458f80de47cSMark Jansen { 459f80de47cSMark Jansen ok(WaitAndCloseWindow(), "Could not find properties window!\n"); 460f80de47cSMark Jansen } 461f80de47cSMark Jansen 462f80de47cSMark Jansen info.lpFile = L"complete garbage, cannot run this!"; 463f80de47cSMark Jansen 464f80de47cSMark Jansen // Now retry it with complete garabage 465f80de47cSMark Jansen bRet = ShellExecuteExW(&info); 466f80de47cSMark Jansen ok(bRet == 0, "Succeeded!\n"); 467f80de47cSMark Jansen ok_ptr(info.hInstApp, (HINSTANCE)2); 468f80de47cSMark Jansen } 469f80de47cSMark Jansen 470*1b3eed58SDoug Lyons static void test_sei_lpIDList() 471*1b3eed58SDoug Lyons { 472*1b3eed58SDoug Lyons /* This tests ShellExecuteEx with lpIDList for explorer C:\ */ 473*1b3eed58SDoug Lyons 474*1b3eed58SDoug Lyons /* ITEMIDLIST for CLSID of 'My Computer' followed by PIDL for 'C:\' */ 475*1b3eed58SDoug Lyons BYTE lpitemidlist[30] = { 0x14, 0, 0x1f, 0, 0xe0, 0x4f, 0xd0, 0x20, 0xea, 476*1b3eed58SDoug Lyons 0x3a, 0x69, 0x10, 0xa2, 0xd8, 0x08, 0, 0x2b, 0x30, 0x30, 0x9d, // My Computer 477*1b3eed58SDoug Lyons 0x8, 0, 0x23, 0x43, 0x3a, 0x5c, 0x5c, 0, 0, 0,}; // C:\\ + NUL-NUL ending 478*1b3eed58SDoug Lyons BYTE *lpBytes; 479*1b3eed58SDoug Lyons lpBytes = lpitemidlist; 480*1b3eed58SDoug Lyons 481*1b3eed58SDoug Lyons SHELLEXECUTEINFOW ShellExecInfo; 482*1b3eed58SDoug Lyons BOOL Result; 483*1b3eed58SDoug Lyons STARTUPINFOW si; 484*1b3eed58SDoug Lyons PROCESS_INFORMATION pi; 485*1b3eed58SDoug Lyons HWND hWnd; 486*1b3eed58SDoug Lyons 487*1b3eed58SDoug Lyons ZeroMemory( &si, sizeof(si) ); 488*1b3eed58SDoug Lyons si.cb = sizeof(si); 489*1b3eed58SDoug Lyons ZeroMemory( &pi, sizeof(pi) ); 490*1b3eed58SDoug Lyons 491*1b3eed58SDoug Lyons ZeroMemory(&ShellExecInfo, sizeof(ShellExecInfo)); 492*1b3eed58SDoug Lyons ShellExecInfo.cbSize = sizeof(ShellExecInfo); 493*1b3eed58SDoug Lyons ShellExecInfo.fMask = SEE_MASK_IDLIST; 494*1b3eed58SDoug Lyons ShellExecInfo.hwnd = NULL; 495*1b3eed58SDoug Lyons ShellExecInfo.nShow = SW_SHOWNORMAL; 496*1b3eed58SDoug Lyons ShellExecInfo.lpFile = NULL; 497*1b3eed58SDoug Lyons ShellExecInfo.lpDirectory = NULL; 498*1b3eed58SDoug Lyons ShellExecInfo.lpIDList = lpBytes; 499*1b3eed58SDoug Lyons 500*1b3eed58SDoug Lyons Result = ShellExecuteExW(&ShellExecInfo); 501*1b3eed58SDoug Lyons ok(Result == TRUE, "ShellExecuteEx lpIDList 'C:\\' failed\n"); 502*1b3eed58SDoug Lyons trace("sei_lpIDList returned: %s\n", Result ? "SUCCESS" : "FAILURE"); 503*1b3eed58SDoug Lyons if (Result) 504*1b3eed58SDoug Lyons { 505*1b3eed58SDoug Lyons Sleep(700); 506*1b3eed58SDoug Lyons // Terminate Window 507*1b3eed58SDoug Lyons hWnd = FindWindowW(L"CabinetWClass", L"Local Disk (C:)"); 508*1b3eed58SDoug Lyons PostMessage(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0); 509*1b3eed58SDoug Lyons } 510*1b3eed58SDoug Lyons } 511*1b3eed58SDoug Lyons 512c35a8498SKatayama Hirofumi MZ START_TEST(ShellExecuteEx) 513c35a8498SKatayama Hirofumi MZ { 514c35a8498SKatayama Hirofumi MZ DoAppPathTest(); 515c35a8498SKatayama Hirofumi MZ DoTestEntries(); 516f80de47cSMark Jansen test_properties(); 51760b89da3SKatayama Hirofumi MZ 51860b89da3SKatayama Hirofumi MZ DoWaitForWindow(CLASSNAME, CLASSNAME, TRUE, TRUE); 51960b89da3SKatayama Hirofumi MZ Sleep(100); 520*1b3eed58SDoug Lyons 521*1b3eed58SDoug Lyons test_sei_lpIDList(); 522*1b3eed58SDoug Lyons 523c35a8498SKatayama Hirofumi MZ } 524