1 /* 2 * PROJECT: ReactOS API tests 3 * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory 4 * PURPOSE: Test for ShellExecCmdLine 5 * PROGRAMMERS: Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 6 */ 7 #include "shelltest.h" 8 #include <shlwapi.h> 9 #include <strsafe.h> 10 #include <versionhelpers.h> 11 12 #define NDEBUG 13 #include <debug.h> 14 #include <stdio.h> 15 16 #ifndef SECL_NO_UI 17 #define SECL_NO_UI 0x2 18 #define SECL_LOG_USAGE 0x8 19 #define SECL_USE_IDLIST 0x10 20 #define SECL_ALLOW_NONEXE 0x20 21 #define SECL_RUNAS 0x40 22 #endif 23 24 #define ShellExecCmdLine proxy_ShellExecCmdLine 25 26 #define shell32_hInstance GetModuleHandle(NULL) 27 #define IDS_FILE_NOT_FOUND (-1) 28 29 static const WCHAR wszOpen[] = L"open"; 30 static const WCHAR wszExe[] = L".exe"; 31 static const WCHAR wszCom[] = L".com"; 32 33 static __inline void __SHCloneStrW(WCHAR **target, const WCHAR *source) 34 { 35 *target = (WCHAR *)SHAlloc((lstrlenW(source) + 1) * sizeof(WCHAR) ); 36 lstrcpyW(*target, source); 37 } 38 39 // NOTE: You have to sync the following code to dll/win32/shell32/shlexec.cpp. 40 static LPCWSTR 41 SplitParams(LPCWSTR psz, LPWSTR pszArg0, size_t cchArg0) 42 { 43 LPCWSTR pch; 44 size_t ich = 0; 45 if (*psz == L'"') 46 { 47 // 1st argument is quoted. the string in quotes is quoted 1st argument. 48 // [pch] --> [pszArg0+ich] 49 for (pch = psz + 1; *pch && ich + 1 < cchArg0; ++ich, ++pch) 50 { 51 if (*pch == L'"' && pch[1] == L'"') 52 { 53 // doubled double quotations found! 54 pszArg0[ich] = L'"'; 55 } 56 else if (*pch == L'"') 57 { 58 // single double quotation found! 59 ++pch; 60 break; 61 } 62 else 63 { 64 // otherwise 65 pszArg0[ich] = *pch; 66 } 67 } 68 } 69 else 70 { 71 // 1st argument is unquoted. non-space sequence is 1st argument. 72 // [pch] --> [pszArg0+ich] 73 for (pch = psz; *pch && !iswspace(*pch) && ich + 1 < cchArg0; ++ich, ++pch) 74 { 75 pszArg0[ich] = *pch; 76 } 77 } 78 pszArg0[ich] = 0; 79 80 // skip space 81 while (iswspace(*pch)) 82 ++pch; 83 84 return pch; 85 } 86 87 HRESULT WINAPI ShellExecCmdLine( 88 HWND hwnd, 89 LPCWSTR pwszCommand, 90 LPCWSTR pwszStartDir, 91 int nShow, 92 LPVOID pUnused, 93 DWORD dwSeclFlags) 94 { 95 SHELLEXECUTEINFOW info; 96 DWORD dwSize, dwError, dwType, dwFlags = SEE_MASK_DOENVSUBST | SEE_MASK_NOASYNC; 97 LPCWSTR pszVerb = NULL; 98 WCHAR szFile[MAX_PATH], szFile2[MAX_PATH]; 99 HRESULT hr; 100 LPCWSTR pchParams; 101 LPWSTR lpCommand = NULL; 102 103 if (pwszCommand == NULL) 104 RaiseException(EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, 105 1, (ULONG_PTR*)pwszCommand); 106 107 __SHCloneStrW(&lpCommand, pwszCommand); 108 StrTrimW(lpCommand, L" \t"); 109 110 if (dwSeclFlags & SECL_NO_UI) 111 dwFlags |= SEE_MASK_FLAG_NO_UI; 112 if (dwSeclFlags & SECL_LOG_USAGE) 113 dwFlags |= SEE_MASK_FLAG_LOG_USAGE; 114 if (dwSeclFlags & SECL_USE_IDLIST) 115 dwFlags |= SEE_MASK_INVOKEIDLIST; 116 117 if (dwSeclFlags & SECL_RUNAS) 118 { 119 dwSize = 0; 120 hr = AssocQueryStringW(0, ASSOCSTR_COMMAND, lpCommand, L"RunAs", NULL, &dwSize); 121 if (SUCCEEDED(hr) && dwSize != 0) 122 { 123 pszVerb = L"runas"; 124 } 125 } 126 127 if (UrlIsFileUrlW(lpCommand)) 128 { 129 StringCchCopyW(szFile, _countof(szFile), lpCommand); 130 pchParams = NULL; 131 } 132 else 133 { 134 pchParams = SplitParams(lpCommand, szFile, _countof(szFile)); 135 if (szFile[0] != UNICODE_NULL && szFile[1] == L':' && 136 szFile[2] == UNICODE_NULL) 137 { 138 PathAddBackslashW(szFile); 139 } 140 141 WCHAR szCurDir[MAX_PATH]; 142 GetCurrentDirectoryW(_countof(szCurDir), szCurDir); 143 if (pwszStartDir) 144 { 145 SetCurrentDirectoryW(pwszStartDir); 146 } 147 148 if (PathIsRelativeW(szFile) && 149 GetFullPathNameW(szFile, _countof(szFile2), szFile2, NULL) && 150 PathFileExistsW(szFile2)) 151 { 152 StringCchCopyW(szFile, _countof(szFile), szFile2); 153 } 154 else if (SearchPathW(NULL, szFile, NULL, _countof(szFile2), szFile2, NULL) || 155 SearchPathW(NULL, szFile, wszExe, _countof(szFile2), szFile2, NULL) || 156 SearchPathW(NULL, szFile, wszCom, _countof(szFile2), szFile2, NULL) || 157 SearchPathW(pwszStartDir, szFile, NULL, _countof(szFile2), szFile2, NULL) || 158 SearchPathW(pwszStartDir, szFile, wszExe, _countof(szFile2), szFile2, NULL) || 159 SearchPathW(pwszStartDir, szFile, wszCom, _countof(szFile2), szFile2, NULL)) 160 { 161 StringCchCopyW(szFile, _countof(szFile), szFile2); 162 } 163 else if (SearchPathW(NULL, lpCommand, NULL, _countof(szFile2), szFile2, NULL) || 164 SearchPathW(NULL, lpCommand, wszExe, _countof(szFile2), szFile2, NULL) || 165 SearchPathW(NULL, lpCommand, wszCom, _countof(szFile2), szFile2, NULL) || 166 SearchPathW(pwszStartDir, lpCommand, NULL, _countof(szFile2), szFile2, NULL) || 167 SearchPathW(pwszStartDir, lpCommand, wszExe, _countof(szFile2), szFile2, NULL) || 168 SearchPathW(pwszStartDir, lpCommand, wszCom, _countof(szFile2), szFile2, NULL)) 169 { 170 StringCchCopyW(szFile, _countof(szFile), szFile2); 171 pchParams = NULL; 172 } 173 174 if (pwszStartDir) 175 { 176 SetCurrentDirectoryW(szCurDir); 177 } 178 179 if (!(dwSeclFlags & SECL_ALLOW_NONEXE)) 180 { 181 if (!GetBinaryTypeW(szFile, &dwType)) 182 { 183 SHFree(lpCommand); 184 185 if (!(dwSeclFlags & SECL_NO_UI)) 186 { 187 WCHAR szText[128 + MAX_PATH], szFormat[128]; 188 LoadStringW(shell32_hInstance, IDS_FILE_NOT_FOUND, szFormat, _countof(szFormat)); 189 StringCchPrintfW(szText, _countof(szText), szFormat, szFile); 190 MessageBoxW(hwnd, szText, NULL, MB_ICONERROR); 191 } 192 return CO_E_APPNOTFOUND; 193 } 194 } 195 else 196 { 197 if (GetFileAttributesW(szFile) == INVALID_FILE_ATTRIBUTES) 198 { 199 SHFree(lpCommand); 200 201 if (!(dwSeclFlags & SECL_NO_UI)) 202 { 203 WCHAR szText[128 + MAX_PATH], szFormat[128]; 204 LoadStringW(shell32_hInstance, IDS_FILE_NOT_FOUND, szFormat, _countof(szFormat)); 205 StringCchPrintfW(szText, _countof(szText), szFormat, szFile); 206 MessageBoxW(hwnd, szText, NULL, MB_ICONERROR); 207 } 208 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); 209 } 210 } 211 } 212 213 ZeroMemory(&info, sizeof(info)); 214 info.cbSize = sizeof(info); 215 info.fMask = dwFlags; 216 info.hwnd = hwnd; 217 info.lpVerb = pszVerb; 218 info.lpFile = szFile; 219 info.lpParameters = (pchParams && *pchParams) ? pchParams : NULL; 220 info.lpDirectory = pwszStartDir; 221 info.nShow = nShow; 222 if (ShellExecuteExW(&info)) 223 { 224 if (info.lpIDList) 225 CoTaskMemFree(info.lpIDList); 226 227 SHFree(lpCommand); 228 229 return S_OK; 230 } 231 232 dwError = GetLastError(); 233 234 SHFree(lpCommand); 235 236 return HRESULT_FROM_WIN32(dwError); 237 } 238 239 #undef ShellExecCmdLine 240 241 typedef HRESULT (WINAPI *SHELLEXECCMDLINE)(HWND, LPCWSTR, LPCWSTR, INT, LPVOID, DWORD); 242 SHELLEXECCMDLINE g_pShellExecCmdLine = NULL; 243 244 typedef struct TEST_ENTRY 245 { 246 INT lineno; 247 BOOL result; 248 BOOL bAllowNonExe; 249 LPCWSTR pwszCommand; 250 LPCWSTR pwszStartDir; 251 } TEST_ENTRY; 252 253 static WCHAR s_sub_program[MAX_PATH]; 254 static WCHAR s_win_test_exe[MAX_PATH]; 255 static WCHAR s_sys_bat_file[MAX_PATH]; 256 static WCHAR s_cur_dir[MAX_PATH]; 257 258 static BOOL 259 GetSubProgramPath(void) 260 { 261 GetModuleFileNameW(NULL, s_sub_program, _countof(s_sub_program)); 262 PathRemoveFileSpecW(s_sub_program); 263 PathAppendW(s_sub_program, L"shell32_apitest_sub.exe"); 264 265 if (!PathFileExistsW(s_sub_program)) 266 { 267 PathRemoveFileSpecW(s_sub_program); 268 PathAppendW(s_sub_program, L"testdata\\shell32_apitest_sub.exe"); 269 270 if (!PathFileExistsW(s_sub_program)) 271 { 272 return FALSE; 273 } 274 } 275 276 return TRUE; 277 } 278 279 static const TEST_ENTRY s_entries_1[] = 280 { 281 // NULL 282 { __LINE__, 0xBADFACE, FALSE, NULL, NULL }, 283 { __LINE__, 0xBADFACE, FALSE, NULL, L"." }, 284 { __LINE__, 0xBADFACE, FALSE, NULL, L"system32" }, 285 { __LINE__, 0xBADFACE, FALSE, NULL, L"C:\\Program Files" }, 286 { __LINE__, 0xBADFACE, TRUE, NULL, NULL }, 287 { __LINE__, 0xBADFACE, TRUE, NULL, L"." }, 288 { __LINE__, 0xBADFACE, TRUE, NULL, L"system32" }, 289 { __LINE__, 0xBADFACE, TRUE, NULL, L"C:\\Program Files" }, 290 // notepad 291 { __LINE__, TRUE, FALSE, L"notepad", NULL }, 292 { __LINE__, TRUE, FALSE, L"notepad", L"." }, 293 { __LINE__, TRUE, FALSE, L"notepad", L"system32" }, 294 { __LINE__, TRUE, FALSE, L"notepad", L"C:\\Program Files" }, 295 { __LINE__, TRUE, FALSE, L"notepad \"Test File.txt\"", NULL }, 296 { __LINE__, TRUE, FALSE, L"notepad \"Test File.txt\"", L"." }, 297 { __LINE__, TRUE, TRUE, L"notepad", NULL }, 298 { __LINE__, TRUE, TRUE, L"notepad", L"." }, 299 { __LINE__, TRUE, TRUE, L"notepad", L"system32" }, 300 { __LINE__, TRUE, TRUE, L"notepad", L"C:\\Program Files" }, 301 { __LINE__, TRUE, TRUE, L"notepad \"Test File.txt\"", NULL }, 302 { __LINE__, TRUE, TRUE, L"notepad \"Test File.txt\"", L"." }, 303 // notepad.exe 304 { __LINE__, TRUE, FALSE, L"notepad.exe", NULL }, 305 { __LINE__, TRUE, FALSE, L"notepad.exe", L"." }, 306 { __LINE__, TRUE, FALSE, L"notepad.exe", L"system32" }, 307 { __LINE__, TRUE, FALSE, L"notepad.exe", L"C:\\Program Files" }, 308 { __LINE__, TRUE, FALSE, L"notepad.exe \"Test File.txt\"", NULL }, 309 { __LINE__, TRUE, FALSE, L"notepad.exe \"Test File.txt\"", L"." }, 310 { __LINE__, TRUE, TRUE, L"notepad.exe", NULL }, 311 { __LINE__, TRUE, TRUE, L"notepad.exe", L"." }, 312 { __LINE__, TRUE, TRUE, L"notepad.exe", L"system32" }, 313 { __LINE__, TRUE, TRUE, L"notepad.exe", L"C:\\Program Files" }, 314 { __LINE__, TRUE, TRUE, L"notepad.exe \"Test File.txt\"", NULL }, 315 { __LINE__, TRUE, TRUE, L"notepad.exe \"Test File.txt\"", L"." }, 316 // C:\notepad.exe 317 { __LINE__, FALSE, FALSE, L"C:\\notepad.exe", NULL }, 318 { __LINE__, FALSE, FALSE, L"C:\\notepad.exe", L"." }, 319 { __LINE__, FALSE, FALSE, L"C:\\notepad.exe", L"system32" }, 320 { __LINE__, FALSE, FALSE, L"C:\\notepad.exe", L"C:\\Program Files" }, 321 { __LINE__, FALSE, FALSE, L"C:\\notepad.exe \"Test File.txt\"", NULL }, 322 { __LINE__, FALSE, FALSE, L"C:\\notepad.exe \"Test File.txt\"", L"." }, 323 { __LINE__, FALSE, TRUE, L"C:\\notepad.exe", NULL }, 324 { __LINE__, FALSE, TRUE, L"C:\\notepad.exe", L"." }, 325 { __LINE__, FALSE, TRUE, L"C:\\notepad.exe", L"system32" }, 326 { __LINE__, FALSE, TRUE, L"C:\\notepad.exe", L"C:\\Program Files" }, 327 { __LINE__, FALSE, TRUE, L"C:\\notepad.exe \"Test File.txt\"", NULL }, 328 { __LINE__, FALSE, TRUE, L"C:\\notepad.exe \"Test File.txt\"", L"." }, 329 // "notepad" 330 { __LINE__, TRUE, FALSE, L"\"notepad\"", NULL }, 331 { __LINE__, TRUE, FALSE, L"\"notepad\"", L"." }, 332 { __LINE__, TRUE, FALSE, L"\"notepad\"", L"system32" }, 333 { __LINE__, TRUE, FALSE, L"\"notepad\"", L"C:\\Program Files" }, 334 { __LINE__, TRUE, FALSE, L"\"notepad\" \"Test File.txt\"", NULL }, 335 { __LINE__, TRUE, FALSE, L"\"notepad\" \"Test File.txt\"", L"." }, 336 { __LINE__, TRUE, TRUE, L"\"notepad\"", NULL }, 337 { __LINE__, TRUE, TRUE, L"\"notepad\"", L"." }, 338 { __LINE__, TRUE, TRUE, L"\"notepad\"", L"system32" }, 339 { __LINE__, TRUE, TRUE, L"\"notepad\"", L"C:\\Program Files" }, 340 { __LINE__, TRUE, TRUE, L"\"notepad\" \"Test File.txt\"", NULL }, 341 { __LINE__, TRUE, TRUE, L"\"notepad\" \"Test File.txt\"", L"." }, 342 // "notepad.exe" 343 { __LINE__, TRUE, FALSE, L"\"notepad.exe\"", NULL }, 344 { __LINE__, TRUE, FALSE, L"\"notepad.exe\"", L"." }, 345 { __LINE__, TRUE, FALSE, L"\"notepad.exe\"", L"system32" }, 346 { __LINE__, TRUE, FALSE, L"\"notepad.exe\"", L"C:\\Program Files" }, 347 { __LINE__, TRUE, FALSE, L"\"notepad.exe\" \"Test File.txt\"", NULL }, 348 { __LINE__, TRUE, FALSE, L"\"notepad.exe\" \"Test File.txt\"", L"." }, 349 { __LINE__, TRUE, TRUE, L"\"notepad.exe\"", NULL }, 350 { __LINE__, TRUE, TRUE, L"\"notepad.exe\"", L"." }, 351 { __LINE__, TRUE, TRUE, L"\"notepad.exe\"", L"system32" }, 352 { __LINE__, TRUE, TRUE, L"\"notepad.exe\"", L"C:\\Program Files" }, 353 { __LINE__, TRUE, TRUE, L"\"notepad.exe\" \"Test File.txt\"", NULL }, 354 { __LINE__, TRUE, TRUE, L"\"notepad.exe\" \"Test File.txt\"", L"." }, 355 // test program 356 { __LINE__, FALSE, FALSE, L"test program", NULL }, 357 { __LINE__, FALSE, FALSE, L"test program", L"." }, 358 { __LINE__, FALSE, FALSE, L"test program", L"system32" }, 359 { __LINE__, FALSE, FALSE, L"test program", L"C:\\Program Files" }, 360 { __LINE__, FALSE, FALSE, L"test program \"Test File.txt\"", NULL }, 361 { __LINE__, FALSE, FALSE, L"test program \"Test File.txt\"", L"." }, 362 { __LINE__, FALSE, TRUE, L"test program", NULL }, 363 { __LINE__, FALSE, TRUE, L"test program", L"." }, 364 { __LINE__, FALSE, TRUE, L"test program", L"system32" }, 365 { __LINE__, FALSE, TRUE, L"test program", L"C:\\Program Files" }, 366 { __LINE__, FALSE, TRUE, L"test program \"Test File.txt\"", NULL }, 367 { __LINE__, FALSE, TRUE, L"test program \"Test File.txt\"", L"." }, 368 // test program.exe 369 { __LINE__, FALSE, FALSE, L"test program.exe", NULL }, 370 { __LINE__, FALSE, FALSE, L"test program.exe", L"." }, 371 { __LINE__, FALSE, FALSE, L"test program.exe", L"system32" }, 372 { __LINE__, FALSE, FALSE, L"test program.exe", L"C:\\Program Files" }, 373 { __LINE__, FALSE, FALSE, L"test program.exe \"Test File.txt\"", NULL }, 374 { __LINE__, FALSE, FALSE, L"test program.exe \"Test File.txt\"", L"." }, 375 { __LINE__, FALSE, TRUE, L"test program.exe", NULL }, 376 { __LINE__, FALSE, TRUE, L"test program.exe", L"." }, 377 { __LINE__, FALSE, TRUE, L"test program.exe", L"system32" }, 378 { __LINE__, FALSE, TRUE, L"test program.exe", L"C:\\Program Files" }, 379 { __LINE__, FALSE, TRUE, L"test program.exe \"Test File.txt\"", NULL }, 380 { __LINE__, FALSE, TRUE, L"test program.exe \"Test File.txt\"", L"." }, 381 // test program.bat 382 { __LINE__, FALSE, FALSE, L"test program.bat", NULL }, 383 { __LINE__, FALSE, FALSE, L"test program.bat", L"." }, 384 { __LINE__, FALSE, FALSE, L"test program.bat", L"system32" }, 385 { __LINE__, FALSE, FALSE, L"test program.bat", L"C:\\Program Files" }, 386 { __LINE__, FALSE, FALSE, L"test program.bat \"Test File.txt\"", NULL }, 387 { __LINE__, FALSE, FALSE, L"test program.bat \"Test File.txt\"", L"." }, 388 { __LINE__, FALSE, TRUE, L"test program.bat", NULL }, 389 { __LINE__, FALSE, TRUE, L"test program.bat", L"." }, 390 { __LINE__, FALSE, TRUE, L"test program.bat", L"system32" }, 391 { __LINE__, FALSE, TRUE, L"test program.bat", L"C:\\Program Files" }, 392 { __LINE__, FALSE, TRUE, L"test program.bat \"Test File.txt\"", NULL }, 393 { __LINE__, FALSE, TRUE, L"test program.bat \"Test File.txt\"", L"." }, 394 // "test program" 395 { __LINE__, FALSE, FALSE, L"\"test program\"", NULL }, 396 { __LINE__, FALSE, FALSE, L"\"test program\"", L"." }, 397 { __LINE__, FALSE, FALSE, L"\"test program\"", L"system32" }, 398 { __LINE__, FALSE, FALSE, L"\"test program\"", L"C:\\Program Files" }, 399 { __LINE__, FALSE, FALSE, L"\"test program\" \"Test File.txt\"", NULL }, 400 { __LINE__, FALSE, FALSE, L"\"test program\" \"Test File.txt\"", L"." }, 401 { __LINE__, FALSE, TRUE, L"\"test program\"", NULL }, 402 { __LINE__, FALSE, TRUE, L"\"test program\"", L"." }, 403 { __LINE__, FALSE, TRUE, L"\"test program\"", L"system32" }, 404 { __LINE__, FALSE, TRUE, L"\"test program\"", L"C:\\Program Files" }, 405 { __LINE__, FALSE, TRUE, L"\"test program\" \"Test File.txt\"", NULL }, 406 { __LINE__, FALSE, TRUE, L"\"test program\" \"Test File.txt\"", L"." }, 407 // "test program.exe" 408 { __LINE__, TRUE, FALSE, L"\"test program.exe\"", NULL }, 409 { __LINE__, TRUE, FALSE, L"\"test program.exe\"", L"." }, 410 { __LINE__, TRUE, FALSE, L"\"test program.exe\"", L"system32" }, 411 { __LINE__, TRUE, FALSE, L"\"test program.exe\"", L"C:\\Program Files" }, 412 { __LINE__, TRUE, FALSE, L"\"test program.exe\" \"Test File.txt\"", NULL }, 413 { __LINE__, TRUE, FALSE, L"\"test program.exe\" \"Test File.txt\"", L"." }, 414 { __LINE__, TRUE, TRUE, L"\"test program.exe\"", NULL }, 415 { __LINE__, TRUE, TRUE, L"\"test program.exe\"", L"." }, 416 { __LINE__, TRUE, TRUE, L"\"test program.exe\"", L"system32" }, 417 { __LINE__, TRUE, TRUE, L"\"test program.exe\"", L"C:\\Program Files" }, 418 { __LINE__, TRUE, TRUE, L"\"test program.exe\" \"Test File.txt\"", NULL }, 419 { __LINE__, TRUE, TRUE, L"\"test program.exe\" \"Test File.txt\"", L"." }, 420 // "test program.bat" 421 { __LINE__, FALSE, FALSE, L"\"test program.bat\"", NULL }, 422 { __LINE__, FALSE, FALSE, L"\"test program.bat\"", L"." }, 423 { __LINE__, FALSE, FALSE, L"\"test program.bat\"", L"system32" }, 424 { __LINE__, FALSE, FALSE, L"\"test program.bat\"", L"C:\\Program Files" }, 425 { __LINE__, FALSE, FALSE, L"\"test program.bat\" \"Test File.txt\"", NULL }, 426 { __LINE__, FALSE, FALSE, L"\"test program.bat\" \"Test File.txt\"", L"." }, 427 { __LINE__, FALSE, TRUE, L"\"test program.bat\"", NULL }, 428 { __LINE__, FALSE, TRUE, L"\"test program.bat\"", L"." }, 429 { __LINE__, FALSE, TRUE, L"\"test program.bat\"", L"system32" }, 430 { __LINE__, FALSE, TRUE, L"\"test program.bat\"", L"C:\\Program Files" }, 431 { __LINE__, FALSE, TRUE, L"\"test program.bat\" \"Test File.txt\"", NULL }, 432 { __LINE__, FALSE, TRUE, L"\"test program.bat\" \"Test File.txt\"", L"." }, 433 // invalid program 434 { __LINE__, FALSE, FALSE, L"invalid program", NULL }, 435 { __LINE__, FALSE, FALSE, L"invalid program", L"." }, 436 { __LINE__, FALSE, FALSE, L"invalid program", L"system32" }, 437 { __LINE__, FALSE, FALSE, L"invalid program", L"C:\\Program Files" }, 438 { __LINE__, FALSE, FALSE, L"invalid program \"Test File.txt\"", NULL }, 439 { __LINE__, FALSE, FALSE, L"invalid program \"Test File.txt\"", L"." }, 440 { __LINE__, FALSE, TRUE, L"invalid program", NULL }, 441 { __LINE__, FALSE, TRUE, L"invalid program", L"." }, 442 { __LINE__, FALSE, TRUE, L"invalid program", L"system32" }, 443 { __LINE__, FALSE, TRUE, L"invalid program", L"C:\\Program Files" }, 444 { __LINE__, FALSE, TRUE, L"invalid program \"Test File.txt\"", NULL }, 445 { __LINE__, FALSE, TRUE, L"invalid program \"Test File.txt\"", L"." }, 446 // \"invalid program.exe\" 447 { __LINE__, FALSE, FALSE, L"\"invalid program.exe\"", NULL }, 448 { __LINE__, FALSE, FALSE, L"\"invalid program.exe\"", L"." }, 449 { __LINE__, FALSE, FALSE, L"\"invalid program.exe\"", L"system32" }, 450 { __LINE__, FALSE, FALSE, L"\"invalid program.exe\"", L"C:\\Program Files" }, 451 { __LINE__, FALSE, FALSE, L"\"invalid program.exe\" \"Test File.txt\"", NULL }, 452 { __LINE__, FALSE, FALSE, L"\"invalid program.exe\" \"Test File.txt\"", L"." }, 453 { __LINE__, FALSE, TRUE, L"\"invalid program.exe\"", NULL }, 454 { __LINE__, FALSE, TRUE, L"\"invalid program.exe\"", L"." }, 455 { __LINE__, FALSE, TRUE, L"\"invalid program.exe\"", L"system32" }, 456 { __LINE__, FALSE, TRUE, L"\"invalid program.exe\"", L"C:\\Program Files" }, 457 { __LINE__, FALSE, TRUE, L"\"invalid program.exe\" \"Test File.txt\"", NULL }, 458 { __LINE__, FALSE, TRUE, L"\"invalid program.exe\" \"Test File.txt\"", L"." }, 459 // My Documents 460 { __LINE__, TRUE, TRUE, L"::{450d8fba-ad25-11d0-98a8-0800361b1103}", NULL }, 461 { __LINE__, TRUE, TRUE, L"shell:::{450d8fba-ad25-11d0-98a8-0800361b1103}", NULL }, 462 // shell:sendto 463 { __LINE__, TRUE, TRUE, L"shell:sendto", NULL }, 464 // iexplore.exe 465 { __LINE__, TRUE, FALSE, L"iexplore", NULL }, 466 { __LINE__, TRUE, FALSE, L"iexplore.exe", NULL }, 467 { __LINE__, TRUE, TRUE, L"iexplore", NULL }, 468 { __LINE__, TRUE, TRUE, L"iexplore.exe", NULL }, 469 // https://google.com 470 { __LINE__, TRUE, FALSE, L"https://google.com", NULL }, 471 { __LINE__, TRUE, TRUE, L"https://google.com", NULL }, 472 // Test File 1.txt 473 { __LINE__, FALSE, FALSE, L"Test File 1.txt", NULL }, 474 { __LINE__, FALSE, FALSE, L"Test File 1.txt", L"." }, 475 { __LINE__, FALSE, FALSE, L"Test File 1.txt", L"system32" }, 476 { __LINE__, FALSE, FALSE, L"Test File 1.txt", s_cur_dir }, 477 { __LINE__, FALSE, FALSE, L"\"Test File 1.txt\"", NULL }, 478 { __LINE__, FALSE, FALSE, L"\"Test File 1.txt\"", L"." }, 479 { __LINE__, FALSE, FALSE, L"\"Test File 1.txt\"", L"system32" }, 480 { __LINE__, FALSE, FALSE, L"\"Test File 1.txt\"", s_cur_dir }, 481 { __LINE__, FALSE, FALSE, L"\"Test File 1.txt\" \"Test File.txt\"", NULL }, 482 { __LINE__, FALSE, FALSE, L"\"Test File 1.txt\" \"Test File.txt\"", L"." }, 483 { __LINE__, FALSE, FALSE, L"\"Test File 1.txt\" \"Test File.txt\"", L"system32" }, 484 { __LINE__, FALSE, TRUE, L"Test File 1.txt", NULL }, 485 { __LINE__, TRUE, TRUE, L"Test File 1.txt", L"." }, 486 { __LINE__, FALSE, TRUE, L"Test File 1.txt", L"system32" }, 487 { __LINE__, TRUE, TRUE, L"Test File 1.txt", s_cur_dir }, 488 { __LINE__, FALSE, TRUE, L"\"Test File 1.txt\"", NULL }, 489 { __LINE__, TRUE, TRUE, L"\"Test File 1.txt\"", L"." }, 490 { __LINE__, TRUE, TRUE, L"\"Test File 1.txt\"", L"system32" }, 491 { __LINE__, TRUE, TRUE, L"\"Test File 1.txt\"", s_cur_dir }, 492 { __LINE__, FALSE, TRUE, L"\"Test File 1.txt\" \"Test File.txt\"", NULL }, 493 { __LINE__, TRUE, TRUE, L"\"Test File 1.txt\" \"Test File.txt\"", L"." }, 494 { __LINE__, TRUE, TRUE, L"\"Test File 1.txt\" \"Test File.txt\"", L"system32" }, 495 { __LINE__, TRUE, TRUE, L"\"Test File 1.txt\" \"Test File.txt\"", s_cur_dir }, 496 // Test File 2.bat 497 { __LINE__, FALSE, FALSE, L"Test File 2.bat", NULL }, 498 { __LINE__, FALSE, FALSE, L"Test File 2.bat", L"." }, 499 { __LINE__, FALSE, FALSE, L"Test File 2.bat", L"system32" }, 500 { __LINE__, FALSE, FALSE, L"Test File 2.bat", s_cur_dir }, 501 { __LINE__, FALSE, FALSE, L"\"Test File 2.bat\"", NULL }, 502 { __LINE__, FALSE, FALSE, L"\"Test File 2.bat\"", L"." }, 503 { __LINE__, FALSE, FALSE, L"\"Test File 2.bat\"", L"system32" }, 504 { __LINE__, FALSE, FALSE, L"\"Test File 2.bat\"", s_cur_dir }, 505 { __LINE__, FALSE, FALSE, L"\"Test File 2.bat\" \"Test File.txt\"", NULL }, 506 { __LINE__, FALSE, FALSE, L"\"Test File 2.bat\" \"Test File.txt\"", L"." }, 507 { __LINE__, FALSE, FALSE, L"\"Test File 2.bat\" \"Test File.txt\"", L"system32" }, 508 { __LINE__, FALSE, FALSE, L"\"Test File 2.bat\" \"Test File.txt\"", s_cur_dir }, 509 { __LINE__, FALSE, TRUE, L"Test File 2.bat", NULL }, 510 { __LINE__, FALSE, TRUE, L"Test File 2.bat", L"." }, 511 { __LINE__, FALSE, TRUE, L"Test File 2.bat", L"system32" }, 512 { __LINE__, FALSE, TRUE, L"Test File 2.bat", s_cur_dir }, 513 { __LINE__, FALSE, TRUE, L"\"Test File 2.bat\"", NULL }, 514 { __LINE__, FALSE, TRUE, L"\"Test File 2.bat\"", L"." }, 515 { __LINE__, FALSE, TRUE, L"\"Test File 2.bat\"", L"system32" }, 516 { __LINE__, FALSE, TRUE, L"\"Test File 2.bat\"", s_cur_dir }, 517 { __LINE__, FALSE, TRUE, L"\"Test File 2.bat\" \"Test File.txt\"", NULL }, 518 { __LINE__, FALSE, TRUE, L"\"Test File 2.bat\" \"Test File.txt\"", L"." }, 519 { __LINE__, FALSE, TRUE, L"\"Test File 2.bat\" \"Test File.txt\"", L"system32" }, 520 { __LINE__, FALSE, TRUE, L"\"Test File 2.bat\" \"Test File.txt\"", s_cur_dir }, 521 }; 522 523 static const TEST_ENTRY s_entries_2[] = 524 { 525 // Test File 1.txt (with setting path) 526 { __LINE__, FALSE, FALSE, L"Test File 1.txt", NULL }, 527 { __LINE__, FALSE, FALSE, L"Test File 1.txt", L"." }, 528 { __LINE__, FALSE, FALSE, L"Test File 1.txt", L"system32" }, 529 { __LINE__, FALSE, FALSE, L"Test File 1.txt", s_cur_dir }, 530 { __LINE__, FALSE, FALSE, L"\"Test File 1.txt\"", NULL }, 531 { __LINE__, FALSE, FALSE, L"\"Test File 1.txt\"", L"." }, 532 { __LINE__, FALSE, FALSE, L"\"Test File 1.txt\"", L"system32" }, 533 { __LINE__, FALSE, FALSE, L"\"Test File 1.txt\"", s_cur_dir }, 534 { __LINE__, FALSE, FALSE, L"\"Test File 1.txt\" \"Test File.txt\"", NULL }, 535 { __LINE__, FALSE, FALSE, L"\"Test File 1.txt\" \"Test File.txt\"", L"." }, 536 { __LINE__, FALSE, FALSE, L"\"Test File 1.txt\" \"Test File.txt\"", L"system32" }, 537 { __LINE__, FALSE, FALSE, L"\"Test File 1.txt\" \"Test File.txt\"", s_cur_dir }, 538 { __LINE__, FALSE, TRUE, L"Test File 1.txt", NULL }, 539 { __LINE__, TRUE, TRUE, L"Test File 1.txt", L"." }, 540 { __LINE__, FALSE, TRUE, L"Test File 1.txt", L"system32" }, 541 { __LINE__, TRUE, TRUE, L"Test File 1.txt", s_cur_dir }, 542 { __LINE__, TRUE, TRUE, L"\"Test File 1.txt\"", NULL }, 543 { __LINE__, TRUE, TRUE, L"\"Test File 1.txt\"", L"." }, 544 { __LINE__, TRUE, TRUE, L"\"Test File 1.txt\"", L"system32" }, 545 { __LINE__, TRUE, TRUE, L"\"Test File 1.txt\"", s_cur_dir }, 546 { __LINE__, TRUE, TRUE, L"\"Test File 1.txt\" \"Test File.txt\"", NULL }, 547 { __LINE__, TRUE, TRUE, L"\"Test File 1.txt\" \"Test File.txt\"", L"." }, 548 { __LINE__, TRUE, TRUE, L"\"Test File 1.txt\" \"Test File.txt\"", L"system32" }, 549 { __LINE__, TRUE, TRUE, L"\"Test File 1.txt\" \"Test File.txt\"", s_cur_dir }, 550 // Test File 2.bat (with setting path) 551 { __LINE__, FALSE, FALSE, L"Test File 2.bat", NULL }, 552 { __LINE__, FALSE, FALSE, L"Test File 2.bat", L"." }, 553 { __LINE__, FALSE, FALSE, L"Test File 2.bat", L"system32" }, 554 { __LINE__, FALSE, FALSE, L"Test File 2.bat", s_cur_dir }, 555 { __LINE__, FALSE, FALSE, L"\"Test File 2.bat\"", NULL }, 556 { __LINE__, FALSE, FALSE, L"\"Test File 2.bat\"", L"." }, 557 { __LINE__, FALSE, FALSE, L"\"Test File 2.bat\"", L"system32" }, 558 { __LINE__, FALSE, FALSE, L"\"Test File 2.bat\"", s_cur_dir }, 559 { __LINE__, FALSE, FALSE, L"\"Test File 2.bat\" \"Test File.txt\"", NULL }, 560 { __LINE__, FALSE, FALSE, L"\"Test File 2.bat\" \"Test File.txt\"", L"." }, 561 { __LINE__, FALSE, FALSE, L"\"Test File 2.bat\" \"Test File.txt\"", L"system32" }, 562 { __LINE__, FALSE, FALSE, L"\"Test File 2.bat\" \"Test File.txt\"", s_cur_dir }, 563 { __LINE__, FALSE, TRUE, L"Test File 2.bat", NULL }, 564 { __LINE__, FALSE, TRUE, L"Test File 2.bat", L"." }, 565 { __LINE__, FALSE, TRUE, L"Test File 2.bat", L"system32" }, 566 { __LINE__, FALSE, TRUE, L"Test File 2.bat", s_cur_dir }, 567 { __LINE__, FALSE, TRUE, L"\"Test File 2.bat\"", NULL }, 568 { __LINE__, FALSE, TRUE, L"\"Test File 2.bat\"", L"." }, 569 { __LINE__, FALSE, TRUE, L"\"Test File 2.bat\"", L"system32" }, 570 { __LINE__, FALSE, TRUE, L"\"Test File 2.bat\"", s_cur_dir }, 571 { __LINE__, FALSE, TRUE, L"\"Test File 2.bat\" \"Test File.txt\"", NULL }, 572 { __LINE__, FALSE, TRUE, L"\"Test File 2.bat\" \"Test File.txt\"", L"." }, 573 { __LINE__, FALSE, TRUE, L"\"Test File 2.bat\" \"Test File.txt\"", L"system32" }, 574 { __LINE__, FALSE, TRUE, L"\"Test File 2.bat\" \"Test File.txt\"", s_cur_dir }, 575 }; 576 577 typedef struct OPENWNDS 578 { 579 UINT count; 580 HWND *phwnd; 581 } OPENWNDS; 582 583 static OPENWNDS s_wi0 = { 0 }, s_wi1 = { 0 }; 584 585 static BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) 586 { 587 OPENWNDS *info = (OPENWNDS *)lParam; 588 info->phwnd = (HWND *)realloc(info->phwnd, (info->count + 1) * sizeof(HWND)); 589 if (!info->phwnd) 590 return FALSE; 591 info->phwnd[info->count] = hwnd; 592 ++(info->count); 593 return TRUE; 594 } 595 596 static void DoEntry(const TEST_ENTRY *pEntry) 597 { 598 HRESULT hr; 599 DWORD dwSeclFlags; 600 BOOL result; 601 602 if (pEntry->bAllowNonExe) 603 dwSeclFlags = SECL_NO_UI | SECL_ALLOW_NONEXE; 604 else 605 dwSeclFlags = SECL_NO_UI; 606 607 _SEH2_TRY 608 { 609 if (IsReactOS()) 610 { 611 hr = proxy_ShellExecCmdLine(NULL, pEntry->pwszCommand, pEntry->pwszStartDir, 612 SW_SHOWNORMAL, NULL, dwSeclFlags); 613 } 614 else 615 { 616 hr = (*g_pShellExecCmdLine)(NULL, pEntry->pwszCommand, pEntry->pwszStartDir, 617 SW_SHOWNORMAL, NULL, dwSeclFlags); 618 } 619 } 620 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 621 { 622 hr = 0xBADFACE; 623 } 624 _SEH2_END; 625 626 if (hr == 0xBADFACE) 627 result = hr; 628 else 629 result = (hr == S_OK); 630 631 ok(result == pEntry->result, "Line %d: result expected %d, was %d\n", 632 pEntry->lineno, pEntry->result, result); 633 634 // close newly opened windows 635 EnumWindows(EnumWindowsProc, (LPARAM)&s_wi1); 636 for (UINT i1 = 0; i1 < s_wi1.count; ++i1) 637 { 638 BOOL bFound = FALSE; 639 for (UINT i0 = 0; i0 < s_wi0.count; ++i0) 640 { 641 if (s_wi1.phwnd[i1] == s_wi0.phwnd[i0]) 642 { 643 bFound = TRUE; 644 break; 645 } 646 } 647 if (!bFound) 648 PostMessageW(s_wi1.phwnd[i1], WM_CLOSE, 0, 0); 649 } 650 free(s_wi1.phwnd); 651 ZeroMemory(&s_wi1, sizeof(s_wi1)); 652 } 653 654 START_TEST(ShellExecCmdLine) 655 { 656 using namespace std; 657 658 if (!IsReactOS()) 659 { 660 if (!IsWindowsVistaOrGreater()) 661 { 662 skip("ShellExecCmdLine is not available on this platform\n"); 663 return; 664 } 665 666 HMODULE hShell32 = GetModuleHandleA("shell32"); 667 g_pShellExecCmdLine = (SHELLEXECCMDLINE)GetProcAddress(hShell32, (LPCSTR)(INT_PTR)265); 668 if (!g_pShellExecCmdLine) 669 { 670 skip("ShellExecCmdLine is not found\n"); 671 return; 672 } 673 } 674 675 if (!GetSubProgramPath()) 676 { 677 skip("shell32_apitest_sub.exe is not found\n"); 678 return; 679 } 680 681 // record open windows 682 if (!EnumWindows(EnumWindowsProc, (LPARAM)&s_wi0)) 683 { 684 skip("EnumWindows failed\n"); 685 free(s_wi0.phwnd); 686 return; 687 } 688 689 // s_win_test_exe 690 GetWindowsDirectoryW(s_win_test_exe, _countof(s_win_test_exe)); 691 PathAppendW(s_win_test_exe, L"test program.exe"); 692 BOOL ret = CopyFileW(s_sub_program, s_win_test_exe, FALSE); 693 if (!ret) 694 { 695 skip("Please retry with admin rights\n"); 696 free(s_wi0.phwnd); 697 return; 698 } 699 700 FILE *fp; 701 702 // s_sys_bat_file 703 GetSystemDirectoryW(s_sys_bat_file, _countof(s_sys_bat_file)); 704 PathAppendW(s_sys_bat_file, L"test program.bat"); 705 fp = _wfopen(s_sys_bat_file, L"wb"); 706 fclose(fp); 707 ok_int(PathFileExistsW(s_sys_bat_file), TRUE); 708 709 // "Test File 1.txt" 710 fp = fopen("Test File 1.txt", "wb"); 711 ok(fp != NULL, "failed to create a test file\n"); 712 fclose(fp); 713 ok_int(PathFileExistsA("Test File 1.txt"), TRUE); 714 715 // "Test File 2.bat" 716 fp = fopen("Test File 2.bat", "wb"); 717 ok(fp != NULL, "failed to create a test file\n"); 718 fclose(fp); 719 ok_int(PathFileExistsA("Test File 2.bat"), TRUE); 720 721 // s_cur_dir 722 GetCurrentDirectoryW(_countof(s_cur_dir), s_cur_dir); 723 724 // do tests 725 for (size_t i = 0; i < _countof(s_entries_1); ++i) 726 { 727 DoEntry(&s_entries_1[i]); 728 } 729 SetEnvironmentVariableW(L"PATH", s_cur_dir); 730 for (size_t i = 0; i < _countof(s_entries_2); ++i) 731 { 732 DoEntry(&s_entries_2[i]); 733 } 734 735 // clean up 736 ok(DeleteFileW(s_win_test_exe), "failed to delete the test file\n"); 737 ok(DeleteFileW(s_sys_bat_file), "failed to delete the test file\n"); 738 ok(DeleteFileA("Test File 1.txt"), "failed to delete the test file\n"); 739 ok(DeleteFileA("Test File 2.bat"), "failed to delete the test file\n"); 740 free(s_wi0.phwnd); 741 } 742