1 /* 2 * PROJECT: ReactOS api tests 3 * LICENSE: GPLv2+ - See COPYING in the top level directory 4 * PURPOSE: Testing ShellExecuteEx 5 * PROGRAMMER: Yaroslav Veremenko <yaroslav@veremenko.info> 6 * Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 7 */ 8 9 #include "shelltest.h" 10 #include "closewnd.h" 11 #include <pstypes.h> 12 #include <psfuncs.h> 13 #include <stdlib.h> 14 #include <stdio.h> 15 #include <strsafe.h> 16 #include <versionhelpers.h> 17 #include <shellutils.h> 18 #include "shell32_apitest_sub.h" 19 20 static WCHAR s_win_dir[MAX_PATH]; 21 static WCHAR s_sys_dir[MAX_PATH]; 22 static WCHAR s_win_notepad[MAX_PATH]; 23 static WCHAR s_sys_notepad[MAX_PATH]; 24 static WCHAR s_win_test_exe[MAX_PATH]; 25 static WCHAR s_sys_test_exe[MAX_PATH]; 26 static WCHAR s_win_bat_file[MAX_PATH]; 27 static WCHAR s_sys_bat_file[MAX_PATH]; 28 static WCHAR s_win_txt_file[MAX_PATH]; 29 static WCHAR s_sys_txt_file[MAX_PATH]; 30 static WCHAR s_win_notepad_cmdline[MAX_PATH]; 31 static WCHAR s_sys_notepad_cmdline[MAX_PATH]; 32 static WCHAR s_win_test_exe_cmdline[MAX_PATH]; 33 static WCHAR s_sys_test_exe_cmdline[MAX_PATH]; 34 static BOOL s_bWow64; 35 36 #define REG_APPPATHS L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\" 37 38 typedef enum TEST_RESULT 39 { 40 TEST_FAILED, 41 TEST_SUCCESS_NO_PROCESS, 42 TEST_SUCCESS_WITH_PROCESS, 43 } TEST_RESULT; 44 45 typedef struct TEST_ENTRY 46 { 47 INT line; 48 TEST_RESULT result; 49 LPCWSTR lpFile; 50 LPCWSTR cmdline; 51 } TEST_ENTRY, *PTEST_ENTRY; 52 53 static void 54 TEST_DoTestEntry(INT line, TEST_RESULT result, LPCWSTR lpFile, LPCWSTR cmdline = NULL); 55 56 static void TEST_DoTestEntries(void) 57 { 58 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, NULL); 59 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L""); 60 TEST_DoTestEntry(__LINE__, TEST_FAILED, L"This is an invalid path."); 61 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, s_sys_bat_file, NULL); 62 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, s_sys_test_exe, s_sys_test_exe_cmdline); 63 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, s_sys_txt_file, NULL); 64 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, s_win_bat_file, NULL); 65 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, s_win_notepad, s_win_notepad_cmdline); 66 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, s_win_test_exe, s_win_test_exe_cmdline); 67 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, s_win_txt_file, NULL); 68 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, L"notepad", s_sys_notepad_cmdline); 69 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, L"notepad.exe", s_sys_notepad_cmdline); 70 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, L"\"notepad.exe\"", s_sys_notepad_cmdline); 71 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, L"\"notepad\"", s_sys_notepad_cmdline); 72 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, L"test program.exe", s_sys_test_exe_cmdline); 73 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, L"\"test program.exe\"", s_sys_test_exe_cmdline); 74 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, s_win_dir); 75 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, s_sys_dir); 76 TEST_DoTestEntry(__LINE__, TEST_FAILED, L"shell:ThisIsAnInvalidName"); 77 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}"); // My Computer 78 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:::{20D04FE0-3AEA-1069-A2D8-08002B30309D}"); // My Computer (with shell:) 79 80 if (!IsWindowsVistaOrGreater()) 81 { 82 WCHAR szCurDir[MAX_PATH]; 83 GetCurrentDirectoryW(_countof(szCurDir), szCurDir); 84 SetCurrentDirectoryW(s_sys_dir); 85 TEST_DoTestEntry(__LINE__, TEST_FAILED, L"::{21EC2020-3AEA-1069-A2DD-08002B30309D}"); // Control Panel (without path) 86 SetCurrentDirectoryW(szCurDir); 87 } 88 89 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}"); // Control Panel (with path) 90 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}"); // Control Panel (with path and shell:) 91 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:AppData"); 92 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Common Desktop"); 93 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Common Programs"); 94 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Common Start Menu"); 95 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Common StartUp"); 96 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:ControlPanelFolder"); 97 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Desktop"); 98 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Favorites"); 99 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Fonts"); 100 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Local AppData"); 101 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:My Pictures"); 102 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Personal"); 103 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Programs"); 104 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Recent"); 105 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:RecycleBinFolder"); 106 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:SendTo"); 107 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Start Menu"); 108 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:StartUp"); 109 } 110 111 static LPWSTR 112 getCommandLineFromProcess(HANDLE hProcess) 113 { 114 PEB peb; 115 PROCESS_BASIC_INFORMATION info; 116 RTL_USER_PROCESS_PARAMETERS Params; 117 NTSTATUS Status; 118 BOOL ret; 119 120 Status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &info, sizeof(info), NULL); 121 ok_ntstatus(Status, STATUS_SUCCESS); 122 123 ret = ReadProcessMemory(hProcess, info.PebBaseAddress, &peb, sizeof(peb), NULL); 124 if (!ret) 125 trace("ReadProcessMemory failed (%ld)\n", GetLastError()); 126 127 ReadProcessMemory(hProcess, peb.ProcessParameters, &Params, sizeof(Params), NULL); 128 if (!ret) 129 trace("ReadProcessMemory failed (%ld)\n", GetLastError()); 130 131 LPWSTR cmdline = Params.CommandLine.Buffer; 132 if (!cmdline) 133 trace("!cmdline\n"); 134 135 SIZE_T cbCmdLine = Params.CommandLine.Length; 136 if (!cbCmdLine) 137 trace("!cbCmdLine\n"); 138 139 LPWSTR pszBuffer = (LPWSTR)calloc(cbCmdLine + sizeof(WCHAR), 1); 140 if (!pszBuffer) 141 trace("!pszBuffer\n"); 142 143 ret = ReadProcessMemory(hProcess, cmdline, pszBuffer, cbCmdLine, NULL); 144 if (!ret) 145 trace("ReadProcessMemory failed (%ld)\n", GetLastError()); 146 147 pszBuffer[cbCmdLine / sizeof(WCHAR)] = UNICODE_NULL; 148 149 return pszBuffer; // needs free() 150 } 151 152 static void TEST_DoTestEntryStruct(const TEST_ENTRY *pEntry) 153 { 154 SHELLEXECUTEINFOW info = { sizeof(info) }; 155 info.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_WAITFORINPUTIDLE | 156 SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC; 157 info.hwnd = NULL; 158 info.lpVerb = NULL; 159 info.lpFile = pEntry->lpFile; 160 info.nShow = SW_SHOWNORMAL; 161 162 BOOL ret = ShellExecuteExW(&info); 163 164 TEST_RESULT result; 165 if (ret && info.hProcess) 166 result = TEST_SUCCESS_WITH_PROCESS; 167 else if (ret && !info.hProcess) 168 result = TEST_SUCCESS_NO_PROCESS; 169 else 170 result = TEST_FAILED; 171 172 ok(pEntry->result == result, 173 "Line %d: result: %d vs %d\n", pEntry->line, pEntry->result, result); 174 175 if (pEntry->result == TEST_SUCCESS_WITH_PROCESS && pEntry->cmdline && !s_bWow64) 176 { 177 LPWSTR cmdline = getCommandLineFromProcess(info.hProcess); 178 if (!cmdline) 179 { 180 skip("!cmdline\n"); 181 } 182 else 183 { 184 ok(lstrcmpiW(pEntry->cmdline, cmdline) == 0, 185 "Line %d: cmdline: '%ls' vs '%ls'\n", pEntry->line, 186 pEntry->cmdline, cmdline); 187 } 188 189 TerminateProcess(info.hProcess, 0xDEADFACE); 190 free(cmdline); 191 } 192 193 CloseHandle(info.hProcess); 194 } 195 196 static void 197 TEST_DoTestEntry(INT line, TEST_RESULT result, LPCWSTR lpFile, LPCWSTR cmdline) 198 { 199 TEST_ENTRY entry = { line, result, lpFile, cmdline }; 200 TEST_DoTestEntryStruct(&entry); 201 } 202 203 static BOOL 204 enableTokenPrivilege(LPCWSTR pszPrivilege) 205 { 206 HANDLE hToken; 207 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) 208 return FALSE; 209 210 TOKEN_PRIVILEGES tkp = { 0 }; 211 if (!LookupPrivilegeValueW(NULL, pszPrivilege, &tkp.Privileges[0].Luid)) 212 return FALSE; 213 214 tkp.PrivilegeCount = 1; 215 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 216 return AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, NULL, NULL); 217 } 218 219 static WINDOW_LIST s_List1, s_List2; 220 221 static BOOL TEST_Start(void) 222 { 223 // Check Wow64 224 s_bWow64 = FALSE; 225 IsWow64Process(GetCurrentProcess(), &s_bWow64); 226 if (s_bWow64) 227 skip("Wow64: Command Line check is skipped\n"); 228 229 // getCommandLineFromProcess needs this 230 enableTokenPrivilege(SE_DEBUG_NAME); 231 232 // s_win_dir 233 GetWindowsDirectoryW(s_win_dir, _countof(s_win_dir)); 234 235 // s_sys_dir 236 GetSystemDirectoryW(s_sys_dir, _countof(s_sys_dir)); 237 238 // s_win_notepad 239 GetWindowsDirectoryW(s_win_notepad, _countof(s_win_notepad)); 240 PathAppendW(s_win_notepad, L"notepad.exe"); 241 242 // s_sys_notepad 243 GetSystemDirectoryW(s_sys_notepad, _countof(s_sys_notepad)); 244 PathAppendW(s_sys_notepad, L"notepad.exe"); 245 246 // s_win_test_exe 247 GetWindowsDirectoryW(s_win_test_exe, _countof(s_win_test_exe)); 248 PathAppendW(s_win_test_exe, L"test program.exe"); 249 BOOL ret = CopyFileW(s_win_notepad, s_win_test_exe, FALSE); 250 if (!ret) 251 { 252 skip("Please retry with admin rights\n"); 253 return FALSE; 254 } 255 256 // s_sys_test_exe 257 GetSystemDirectoryW(s_sys_test_exe, _countof(s_sys_test_exe)); 258 PathAppendW(s_sys_test_exe, L"test program.exe"); 259 ok_int(CopyFileW(s_win_notepad, s_sys_test_exe, FALSE), TRUE); 260 261 // s_win_bat_file 262 GetWindowsDirectoryW(s_win_bat_file, _countof(s_win_bat_file)); 263 PathAppendW(s_win_bat_file, L"test program.bat"); 264 FILE *fp = _wfopen(s_win_bat_file, L"wb"); 265 fprintf(fp, "exit /b 3"); 266 fclose(fp); 267 ok_int(PathFileExistsW(s_win_bat_file), TRUE); 268 269 // s_sys_bat_file 270 GetSystemDirectoryW(s_sys_bat_file, _countof(s_sys_bat_file)); 271 PathAppendW(s_sys_bat_file, L"test program.bat"); 272 fp = _wfopen(s_sys_bat_file, L"wb"); 273 fprintf(fp, "exit /b 4"); 274 fclose(fp); 275 ok_int(PathFileExistsW(s_sys_bat_file), TRUE); 276 277 // s_win_txt_file 278 GetWindowsDirectoryW(s_win_txt_file, _countof(s_win_txt_file)); 279 PathAppendW(s_win_txt_file, L"test_file.txt"); 280 fp = _wfopen(s_win_txt_file, L"wb"); 281 fclose(fp); 282 ok_int(PathFileExistsW(s_win_txt_file), TRUE); 283 284 // s_sys_txt_file 285 GetSystemDirectoryW(s_sys_txt_file, _countof(s_sys_txt_file)); 286 PathAppendW(s_sys_txt_file, L"test_file.txt"); 287 fp = _wfopen(s_sys_txt_file, L"wb"); 288 fclose(fp); 289 ok_int(PathFileExistsW(s_sys_txt_file), TRUE); 290 291 // Check .txt settings 292 WCHAR szPath[MAX_PATH]; 293 FindExecutableW(s_sys_txt_file, NULL, szPath); 294 if (lstrcmpiW(PathFindFileNameW(szPath), L"notepad.exe") != 0) 295 { 296 skip("Please associate .txt with notepad.exe before tests\n"); 297 return FALSE; 298 } 299 300 // command lines 301 StringCchPrintfW(s_win_notepad_cmdline, _countof(s_win_notepad_cmdline), 302 L"\"%s\" ", s_win_notepad); 303 StringCchPrintfW(s_sys_notepad_cmdline, _countof(s_sys_notepad_cmdline), 304 L"\"%s\" ", s_sys_notepad); 305 StringCchPrintfW(s_win_test_exe_cmdline, _countof(s_win_test_exe_cmdline), 306 L"\"%s\" ", s_win_test_exe); 307 StringCchPrintfW(s_sys_test_exe_cmdline, _countof(s_sys_test_exe_cmdline), 308 L"\"%s\" ", s_sys_test_exe); 309 310 GetWindowList(&s_List1); 311 312 return TRUE; 313 } 314 315 static void TEST_End(void) 316 { 317 GetWindowListForClose(&s_List2); 318 CloseNewWindows(&s_List1, &s_List2); 319 FreeWindowList(&s_List1); 320 FreeWindowList(&s_List2); 321 322 DeleteFileW(s_win_test_exe); 323 DeleteFileW(s_sys_test_exe); 324 DeleteFileW(s_win_txt_file); 325 DeleteFileW(s_sys_txt_file); 326 DeleteFileW(s_win_bat_file); 327 DeleteFileW(s_sys_bat_file); 328 } 329 330 static void test_properties() 331 { 332 HRESULT hrCoInit = CoInitialize(NULL); 333 334 WCHAR Buffer[MAX_PATH * 4]; 335 GetModuleFileNameW(NULL, Buffer, _countof(Buffer)); 336 337 SHELLEXECUTEINFOW info = { sizeof(info) }; 338 info.fMask = SEE_MASK_INVOKEIDLIST | SEE_MASK_FLAG_NO_UI; 339 info.lpVerb = L"properties"; 340 info.lpFile = Buffer; 341 info.nShow = SW_SHOW; 342 343 BOOL bRet = ShellExecuteExW(&info); 344 ok(bRet, "Failed! (GetLastError(): %d)\n", (int)GetLastError()); 345 ok_ptr(info.hInstApp, (HINSTANCE)42); 346 347 WCHAR* Extension = PathFindExtensionW(Buffer); 348 if (Extension) 349 { 350 // The inclusion of this depends on the file display settings! 351 *Extension = UNICODE_NULL; 352 } 353 354 // Now retry it with the extension cut off 355 bRet = ShellExecuteExW(&info); 356 ok(bRet, "Failed! (GetLastError(): %d)\n", (int)GetLastError()); 357 ok_ptr(info.hInstApp, (HINSTANCE)42); 358 359 // Now retry it with complete garabage 360 info.lpFile = L"complete garbage, cannot run this!"; 361 bRet = ShellExecuteExW(&info); 362 ok_int(bRet, 0); 363 ok_ptr(info.hInstApp, (HINSTANCE)2); 364 365 if (SUCCEEDED(hrCoInit)) 366 CoUninitialize(); 367 } 368 369 static void test_sei_lpIDList() 370 { 371 // Note: SEE_MASK_FLAG_NO_UI prevents the test from blocking with a MessageBox 372 WCHAR path[MAX_PATH]; 373 374 /* This tests ShellExecuteEx with lpIDList for explorer C:\ */ 375 GetSystemDirectoryW(path, _countof(path)); 376 PathStripToRootW(path); 377 LPITEMIDLIST pidl = ILCreateFromPathW(path); 378 if (!pidl) 379 { 380 skip("Unable to initialize test\n"); 381 return; 382 } 383 384 SHELLEXECUTEINFOW ShellExecInfo = { sizeof(ShellExecInfo) }; 385 ShellExecInfo.nShow = SW_SHOWNORMAL; 386 ShellExecInfo.fMask = SEE_MASK_IDLIST | SEE_MASK_FLAG_NO_UI | SEE_MASK_FLAG_DDEWAIT; 387 ShellExecInfo.lpIDList = pidl; 388 BOOL ret = ShellExecuteExW(&ShellExecInfo); 389 ok_int(ret, TRUE); 390 ILFree(pidl); 391 392 /* This tests ShellExecuteEx with lpIDList going through IContextMenu */ 393 CCoInit ComInit; 394 pidl = SHCloneSpecialIDList(NULL, CSIDL_PROFILE, TRUE); 395 if (!pidl) 396 { 397 skip("Unable to initialize test\n"); 398 return; 399 } 400 ShellExecInfo.fMask = SEE_MASK_INVOKEIDLIST | SEE_MASK_FLAG_NO_UI | SEE_MASK_FLAG_DDEWAIT; 401 ShellExecInfo.lpIDList = pidl; 402 ret = ShellExecuteExW(&ShellExecInfo); 403 ok_int(ret, TRUE); 404 ILFree(pidl); 405 } 406 407 static BOOL 408 CreateAppPath(LPCWSTR pszName, LPCWSTR pszValue) 409 { 410 WCHAR szSubKey[MAX_PATH]; 411 StringCchPrintfW(szSubKey, _countof(szSubKey), L"%s\\%s", REG_APPPATHS, pszName); 412 413 LSTATUS error; 414 HKEY hKey; 415 error = RegCreateKeyExW(HKEY_LOCAL_MACHINE, szSubKey, 0, NULL, 0, KEY_WRITE, NULL, 416 &hKey, NULL); 417 if (error != ERROR_SUCCESS) 418 trace("Could not create test key (%lu)\n", error); 419 420 DWORD cbValue = (lstrlenW(pszValue) + 1) * sizeof(WCHAR); 421 error = RegSetValueExW(hKey, NULL, 0, REG_SZ, (LPBYTE)pszValue, cbValue); 422 if (error != ERROR_SUCCESS) 423 trace("Could not set value of the test key (%lu)\n", error); 424 425 RegCloseKey(hKey); 426 427 return error == ERROR_SUCCESS; 428 } 429 430 static VOID 431 DeleteAppPath(LPCWSTR pszName) 432 { 433 WCHAR szSubKey[MAX_PATH]; 434 StringCchPrintfW(szSubKey, _countof(szSubKey), L"%s\\%s", REG_APPPATHS, pszName); 435 436 LSTATUS error = RegDeleteKeyW(HKEY_LOCAL_MACHINE, szSubKey); 437 if (error != ERROR_SUCCESS) 438 trace("Could not remove the test key (%lu)\n", error); 439 } 440 441 static void TEST_AppPath(void) 442 { 443 if (CreateAppPath(L"app_path_test.bat", s_win_test_exe)) 444 { 445 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, L"app_path_test.bat"); 446 TEST_DoTestEntry(__LINE__, TEST_FAILED, L"app_path_test.bat.exe"); 447 DeleteAppPath(L"app_path_test.bat"); 448 } 449 450 if (CreateAppPath(L"app_path_test.bat.exe", s_sys_test_exe)) 451 { 452 TEST_DoTestEntry(__LINE__, TEST_FAILED, L"app_path_test.bat"); 453 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, L"app_path_test.bat.exe"); 454 DeleteAppPath(L"app_path_test.bat.exe"); 455 } 456 } 457 458 static void test_DoInvalidDir(void) 459 { 460 WCHAR szSubProgram[MAX_PATH]; 461 if (!FindSubProgram(szSubProgram, _countof(szSubProgram))) 462 { 463 skip("shell32_apitest_sub.exe not found\n"); 464 return; 465 } 466 467 DWORD dwExitCode; 468 SHELLEXECUTEINFOW sei = { sizeof(sei), SEE_MASK_FLAG_NO_UI | SEE_MASK_NOCLOSEPROCESS }; 469 sei.lpFile = szSubProgram; 470 sei.lpParameters = L"TEST"; 471 sei.nShow = SW_SHOWNORMAL; 472 473 // Test invalid path on sei.lpDirectory 474 WCHAR szInvalidPath[MAX_PATH] = L"M:\\This is an invalid path\n"; 475 sei.lpDirectory = szInvalidPath; 476 ok_int(ShellExecuteExW(&sei), TRUE); 477 WaitForSingleObject(sei.hProcess, 20 * 1000); 478 GetExitCodeProcess(sei.hProcess, &dwExitCode); 479 ok_long(dwExitCode, 0); 480 CloseHandle(sei.hProcess); 481 } 482 483 START_TEST(ShellExecuteEx) 484 { 485 #ifdef _WIN64 486 skip("Win64 is not supported yet\n"); 487 return; 488 #endif 489 490 if (!TEST_Start()) 491 return; 492 493 TEST_AppPath(); 494 TEST_DoTestEntries(); 495 test_properties(); 496 test_sei_lpIDList(); 497 test_DoInvalidDir(); 498 499 TEST_End(); 500 } 501