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