Reactos
at master 531 lines 18 kB view raw
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 20static WCHAR s_win_dir[MAX_PATH]; 21static WCHAR s_sys_dir[MAX_PATH]; 22static WCHAR s_win_notepad[MAX_PATH]; 23static WCHAR s_sys_notepad[MAX_PATH]; 24static WCHAR s_win_test_exe[MAX_PATH]; 25static WCHAR s_sys_test_exe[MAX_PATH]; 26static WCHAR s_win_bat_file[MAX_PATH]; 27static WCHAR s_sys_bat_file[MAX_PATH]; 28static WCHAR s_win_txt_file[MAX_PATH]; 29static WCHAR s_sys_txt_file[MAX_PATH]; 30static WCHAR s_win_notepad_cmdline[MAX_PATH]; 31static WCHAR s_sys_notepad_cmdline[MAX_PATH]; 32static WCHAR s_win_test_exe_cmdline[MAX_PATH]; 33static WCHAR s_sys_test_exe_cmdline[MAX_PATH]; 34static BOOL s_bWow64; 35 36#define REG_APPPATHS L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\" 37 38typedef enum TEST_RESULT 39{ 40 TEST_FAILED, 41 TEST_SUCCESS_NO_PROCESS, 42 TEST_SUCCESS_WITH_PROCESS, 43} TEST_RESULT; 44 45typedef struct TEST_ENTRY 46{ 47 INT line; 48 TEST_RESULT result; 49 LPCWSTR lpFile; 50 LPCWSTR cmdline; 51} TEST_ENTRY, *PTEST_ENTRY; 52 53static void 54TEST_DoTestEntry(INT line, TEST_RESULT result, LPCWSTR lpFile, LPCWSTR cmdline = NULL); 55 56static 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 111static LPWSTR 112getCommandLineFromProcess(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 152static TEST_RESULT 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 (result == TEST_SUCCESS_WITH_PROCESS) 176 WaitForInputIdle(info.hProcess, 2000); 177 178 if (pEntry->result == TEST_SUCCESS_WITH_PROCESS && pEntry->cmdline && !s_bWow64) 179 { 180 LPWSTR cmdline = getCommandLineFromProcess(info.hProcess); 181 if (!cmdline) 182 { 183 skip("!cmdline\n"); 184 } 185 else 186 { 187 ok(lstrcmpiW(pEntry->cmdline, cmdline) == 0, 188 "Line %d: cmdline: '%ls' vs '%ls'\n", pEntry->line, 189 pEntry->cmdline, cmdline); 190 } 191 192 TerminateProcess(info.hProcess, 0xDEADFACE); 193 free(cmdline); 194 } 195 196 CloseHandle(info.hProcess); 197 return result; 198} 199 200static void 201TEST_DoTestEntry(INT line, TEST_RESULT result, LPCWSTR lpFile, LPCWSTR cmdline) 202{ 203 WINDOW_LIST existingwindows; 204 GetWindowList(&existingwindows); 205 HWND hWndForeground = GetForegroundWindow(); 206 207 TEST_ENTRY entry = { line, result, lpFile, cmdline }; 208 result = TEST_DoTestEntryStruct(&entry); 209 210 if (result == TEST_SUCCESS_NO_PROCESS) 211 { 212 // Wait a bit for Explorer to open its window 213 for (UINT i = 0; i < 2000 && hWndForeground == GetForegroundWindow(); i += 250) 214 Sleep(250); 215 } 216 217 CloseNewWindows(&existingwindows); 218 FreeWindowList(&existingwindows); 219} 220 221static BOOL 222enableTokenPrivilege(LPCWSTR pszPrivilege) 223{ 224 HANDLE hToken; 225 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) 226 return FALSE; 227 228 TOKEN_PRIVILEGES tkp = { 0 }; 229 if (!LookupPrivilegeValueW(NULL, pszPrivilege, &tkp.Privileges[0].Luid)) 230 return FALSE; 231 232 tkp.PrivilegeCount = 1; 233 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 234 return AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, NULL, NULL); 235} 236 237static WINDOW_LIST s_List1, s_List2; 238 239static BOOL TEST_Start(void) 240{ 241 // Check Wow64 242 s_bWow64 = FALSE; 243 IsWow64Process(GetCurrentProcess(), &s_bWow64); 244 if (s_bWow64) 245 skip("Wow64: Command Line check is skipped\n"); 246 247 // getCommandLineFromProcess needs this 248 enableTokenPrivilege(SE_DEBUG_NAME); 249 250 // s_win_dir 251 GetWindowsDirectoryW(s_win_dir, _countof(s_win_dir)); 252 253 // s_sys_dir 254 GetSystemDirectoryW(s_sys_dir, _countof(s_sys_dir)); 255 256 // s_win_notepad 257 GetWindowsDirectoryW(s_win_notepad, _countof(s_win_notepad)); 258 PathAppendW(s_win_notepad, L"notepad.exe"); 259 260 // s_sys_notepad 261 GetSystemDirectoryW(s_sys_notepad, _countof(s_sys_notepad)); 262 PathAppendW(s_sys_notepad, L"notepad.exe"); 263 264 // s_win_test_exe 265 GetWindowsDirectoryW(s_win_test_exe, _countof(s_win_test_exe)); 266 PathAppendW(s_win_test_exe, L"test program.exe"); 267 BOOL ret = CopyFileW(s_win_notepad, s_win_test_exe, FALSE); 268 if (!ret) 269 { 270 skip("Please retry with admin rights\n"); 271 return FALSE; 272 } 273 274 // s_sys_test_exe 275 GetSystemDirectoryW(s_sys_test_exe, _countof(s_sys_test_exe)); 276 PathAppendW(s_sys_test_exe, L"test program.exe"); 277 ok_int(CopyFileW(s_win_notepad, s_sys_test_exe, FALSE), TRUE); 278 279 // s_win_bat_file 280 GetWindowsDirectoryW(s_win_bat_file, _countof(s_win_bat_file)); 281 PathAppendW(s_win_bat_file, L"test program.bat"); 282 FILE *fp = _wfopen(s_win_bat_file, L"wb"); 283 fprintf(fp, "exit /b 3"); 284 fclose(fp); 285 ok_int(PathFileExistsW(s_win_bat_file), TRUE); 286 287 // s_sys_bat_file 288 GetSystemDirectoryW(s_sys_bat_file, _countof(s_sys_bat_file)); 289 PathAppendW(s_sys_bat_file, L"test program.bat"); 290 fp = _wfopen(s_sys_bat_file, L"wb"); 291 fprintf(fp, "exit /b 4"); 292 fclose(fp); 293 ok_int(PathFileExistsW(s_sys_bat_file), TRUE); 294 295 // s_win_txt_file 296 GetWindowsDirectoryW(s_win_txt_file, _countof(s_win_txt_file)); 297 PathAppendW(s_win_txt_file, L"test_file.txt"); 298 fp = _wfopen(s_win_txt_file, L"wb"); 299 fclose(fp); 300 ok_int(PathFileExistsW(s_win_txt_file), TRUE); 301 302 // s_sys_txt_file 303 GetSystemDirectoryW(s_sys_txt_file, _countof(s_sys_txt_file)); 304 PathAppendW(s_sys_txt_file, L"test_file.txt"); 305 fp = _wfopen(s_sys_txt_file, L"wb"); 306 fclose(fp); 307 ok_int(PathFileExistsW(s_sys_txt_file), TRUE); 308 309 // Check .txt settings 310 WCHAR szPath[MAX_PATH]; 311 FindExecutableW(s_sys_txt_file, NULL, szPath); 312 if (lstrcmpiW(PathFindFileNameW(szPath), L"notepad.exe") != 0) 313 { 314 skip("Please associate .txt with notepad.exe before tests\n"); 315 return FALSE; 316 } 317 318 // command lines 319 StringCchPrintfW(s_win_notepad_cmdline, _countof(s_win_notepad_cmdline), 320 L"\"%s\" ", s_win_notepad); 321 StringCchPrintfW(s_sys_notepad_cmdline, _countof(s_sys_notepad_cmdline), 322 L"\"%s\" ", s_sys_notepad); 323 StringCchPrintfW(s_win_test_exe_cmdline, _countof(s_win_test_exe_cmdline), 324 L"\"%s\" ", s_win_test_exe); 325 StringCchPrintfW(s_sys_test_exe_cmdline, _countof(s_sys_test_exe_cmdline), 326 L"\"%s\" ", s_sys_test_exe); 327 328 GetWindowList(&s_List1); 329 330 return TRUE; 331} 332 333static void TEST_End(void) 334{ 335 DeleteFileW(s_win_test_exe); 336 DeleteFileW(s_sys_test_exe); 337 DeleteFileW(s_win_txt_file); 338 DeleteFileW(s_sys_txt_file); 339 DeleteFileW(s_win_bat_file); 340 DeleteFileW(s_sys_bat_file); 341 342 // Execution can be asynchronous; you have to wait for it to finish. 343 INT nCount = GetWindowCount(); 344 for (INT i = 0; i < 100; ++i) 345 { 346 INT nOldCount = nCount; 347 Sleep(3000); 348 nCount = GetWindowCount(); 349 if (nOldCount == nCount) 350 break; 351 } 352 Sleep(3000); 353 354 // Close newly-opened window(s) 355 GetWindowList(&s_List2); 356 CloseNewWindows(&s_List1, &s_List2); 357 FreeWindowList(&s_List1); 358 FreeWindowList(&s_List2); 359} 360 361static void test_properties() 362{ 363 HRESULT hrCoInit = CoInitialize(NULL); 364 365 WCHAR Buffer[MAX_PATH * 4]; 366 GetModuleFileNameW(NULL, Buffer, _countof(Buffer)); 367 368 SHELLEXECUTEINFOW info = { sizeof(info) }; 369 info.fMask = SEE_MASK_INVOKEIDLIST | SEE_MASK_FLAG_NO_UI; 370 info.lpVerb = L"properties"; 371 info.lpFile = Buffer; 372 info.nShow = SW_SHOW; 373 374 BOOL bRet = ShellExecuteExW(&info); 375 ok(bRet, "Failed! (GetLastError(): %d)\n", (int)GetLastError()); 376 ok_ptr(info.hInstApp, (HINSTANCE)42); 377 378 WCHAR* Extension = PathFindExtensionW(Buffer); 379 if (Extension) 380 { 381 // The inclusion of this depends on the file display settings! 382 *Extension = UNICODE_NULL; 383 } 384 385 // Now retry it with the extension cut off 386 bRet = ShellExecuteExW(&info); 387 ok(bRet, "Failed! (GetLastError(): %d)\n", (int)GetLastError()); 388 ok_ptr(info.hInstApp, (HINSTANCE)42); 389 390 // Now retry it with complete garabage 391 info.lpFile = L"complete garbage, cannot run this!"; 392 bRet = ShellExecuteExW(&info); 393 ok_int(bRet, 0); 394 ok_ptr(info.hInstApp, (HINSTANCE)2); 395 396 if (SUCCEEDED(hrCoInit)) 397 CoUninitialize(); 398} 399 400static void test_sei_lpIDList() 401{ 402 // Note: SEE_MASK_FLAG_NO_UI prevents the test from blocking with a MessageBox 403 WCHAR path[MAX_PATH]; 404 405 /* This tests ShellExecuteEx with lpIDList for explorer C:\ */ 406 GetSystemDirectoryW(path, _countof(path)); 407 PathStripToRootW(path); 408 LPITEMIDLIST pidl = ILCreateFromPathW(path); 409 if (!pidl) 410 { 411 skip("Unable to initialize test\n"); 412 return; 413 } 414 415 SHELLEXECUTEINFOW ShellExecInfo = { sizeof(ShellExecInfo) }; 416 ShellExecInfo.nShow = SW_SHOWNORMAL; 417 ShellExecInfo.fMask = SEE_MASK_IDLIST | SEE_MASK_FLAG_NO_UI | SEE_MASK_FLAG_DDEWAIT; 418 ShellExecInfo.lpIDList = pidl; 419 BOOL ret = ShellExecuteExW(&ShellExecInfo); 420 ok_int(ret, TRUE); 421 ILFree(pidl); 422 423 /* This tests ShellExecuteEx with lpIDList going through IContextMenu */ 424 CCoInit ComInit; 425 pidl = SHCloneSpecialIDList(NULL, CSIDL_PROFILE, TRUE); 426 if (!pidl) 427 { 428 skip("Unable to initialize test\n"); 429 return; 430 } 431 ShellExecInfo.fMask = SEE_MASK_INVOKEIDLIST | SEE_MASK_FLAG_NO_UI | SEE_MASK_FLAG_DDEWAIT; 432 ShellExecInfo.lpIDList = pidl; 433 ret = ShellExecuteExW(&ShellExecInfo); 434 ok_int(ret, TRUE); 435 ILFree(pidl); 436} 437 438static BOOL 439CreateAppPath(LPCWSTR pszName, LPCWSTR pszValue) 440{ 441 WCHAR szSubKey[MAX_PATH]; 442 StringCchPrintfW(szSubKey, _countof(szSubKey), L"%s\\%s", REG_APPPATHS, pszName); 443 444 LSTATUS error; 445 HKEY hKey; 446 error = RegCreateKeyExW(HKEY_LOCAL_MACHINE, szSubKey, 0, NULL, 0, KEY_WRITE, NULL, 447 &hKey, NULL); 448 if (error != ERROR_SUCCESS) 449 trace("Could not create test key (%lu)\n", error); 450 451 DWORD cbValue = (lstrlenW(pszValue) + 1) * sizeof(WCHAR); 452 error = RegSetValueExW(hKey, NULL, 0, REG_SZ, (LPBYTE)pszValue, cbValue); 453 if (error != ERROR_SUCCESS) 454 trace("Could not set value of the test key (%lu)\n", error); 455 456 RegCloseKey(hKey); 457 458 return error == ERROR_SUCCESS; 459} 460 461static VOID 462DeleteAppPath(LPCWSTR pszName) 463{ 464 WCHAR szSubKey[MAX_PATH]; 465 StringCchPrintfW(szSubKey, _countof(szSubKey), L"%s\\%s", REG_APPPATHS, pszName); 466 467 LSTATUS error = RegDeleteKeyW(HKEY_LOCAL_MACHINE, szSubKey); 468 if (error != ERROR_SUCCESS) 469 trace("Could not remove the test key (%lu)\n", error); 470} 471 472static void TEST_AppPath(void) 473{ 474 if (CreateAppPath(L"app_path_test.bat", s_win_test_exe)) 475 { 476 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, L"app_path_test.bat"); 477 TEST_DoTestEntry(__LINE__, TEST_FAILED, L"app_path_test.bat.exe"); 478 DeleteAppPath(L"app_path_test.bat"); 479 } 480 481 if (CreateAppPath(L"app_path_test.bat.exe", s_sys_test_exe)) 482 { 483 TEST_DoTestEntry(__LINE__, TEST_FAILED, L"app_path_test.bat"); 484 TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, L"app_path_test.bat.exe"); 485 DeleteAppPath(L"app_path_test.bat.exe"); 486 } 487} 488 489static void test_DoInvalidDir(void) 490{ 491 WCHAR szSubProgram[MAX_PATH]; 492 if (!FindSubProgram(szSubProgram, _countof(szSubProgram))) 493 { 494 skip("shell32_apitest_sub.exe not found\n"); 495 return; 496 } 497 498 DWORD dwExitCode; 499 SHELLEXECUTEINFOW sei = { sizeof(sei), SEE_MASK_FLAG_NO_UI | SEE_MASK_NOCLOSEPROCESS }; 500 sei.lpFile = szSubProgram; 501 sei.lpParameters = L"TEST"; 502 sei.nShow = SW_SHOWNORMAL; 503 504 // Test invalid path on sei.lpDirectory 505 WCHAR szInvalidPath[MAX_PATH] = L"M:\\This is an invalid path\n"; 506 sei.lpDirectory = szInvalidPath; 507 ok_int(ShellExecuteExW(&sei), TRUE); 508 WaitForSingleObject(sei.hProcess, 20 * 1000); 509 GetExitCodeProcess(sei.hProcess, &dwExitCode); 510 ok_long(dwExitCode, 0); 511 CloseHandle(sei.hProcess); 512} 513 514START_TEST(ShellExecuteEx) 515{ 516#ifdef _WIN64 517 skip("Win64 is not supported yet\n"); 518 return; 519#endif 520 521 if (!TEST_Start()) 522 return; 523 524 TEST_AppPath(); 525 TEST_DoTestEntries(); 526 test_properties(); 527 test_sei_lpIDList(); 528 test_DoInvalidDir(); 529 530 TEST_End(); 531}