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 11 #define NDEBUG 12 #include <debug.h> 13 #include <stdio.h> 14 15 //#define ShellExecCmdLine ShellExecCmdLine 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 #ifdef 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 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 (SearchPathW(NULL, szFile, NULL, _countof(szFile2), szFile2, NULL) || 136 SearchPathW(NULL, szFile, wszExe, _countof(szFile2), szFile2, NULL) || 137 SearchPathW(NULL, szFile, wszCom, _countof(szFile2), szFile2, NULL) || 138 SearchPathW(pwszStartDir, szFile, NULL, _countof(szFile2), szFile2, NULL) || 139 SearchPathW(pwszStartDir, szFile, wszExe, _countof(szFile2), szFile2, NULL) || 140 SearchPathW(pwszStartDir, szFile, wszCom, _countof(szFile2), szFile2, NULL)) 141 { 142 StringCchCopyW(szFile, _countof(szFile), szFile2); 143 } 144 else if (SearchPathW(NULL, lpCommand, NULL, _countof(szFile2), szFile2, NULL) || 145 SearchPathW(NULL, lpCommand, wszExe, _countof(szFile2), szFile2, NULL) || 146 SearchPathW(NULL, lpCommand, wszCom, _countof(szFile2), szFile2, NULL) || 147 SearchPathW(pwszStartDir, lpCommand, NULL, _countof(szFile2), szFile2, NULL) || 148 SearchPathW(pwszStartDir, lpCommand, wszExe, _countof(szFile2), szFile2, NULL) || 149 SearchPathW(pwszStartDir, lpCommand, wszCom, _countof(szFile2), szFile2, NULL)) 150 { 151 StringCchCopyW(szFile, _countof(szFile), szFile2); 152 pchParams = NULL; 153 } 154 155 if (!(dwSeclFlags & SECL_ALLOW_NONEXE)) 156 { 157 if (!GetBinaryTypeW(szFile, &dwType)) 158 { 159 SHFree(lpCommand); 160 161 if (!(dwSeclFlags & SECL_NO_UI)) 162 { 163 WCHAR szText[128 + MAX_PATH], szFormat[128]; 164 LoadStringW(shell32_hInstance, IDS_FILE_NOT_FOUND, szFormat, _countof(szFormat)); 165 StringCchPrintfW(szText, _countof(szText), szFormat, szFile); 166 MessageBoxW(hwnd, szText, NULL, MB_ICONERROR); 167 } 168 return CO_E_APPNOTFOUND; 169 } 170 } 171 else 172 { 173 if (GetFileAttributesW(szFile) == INVALID_FILE_ATTRIBUTES) 174 { 175 SHFree(lpCommand); 176 177 if (!(dwSeclFlags & SECL_NO_UI)) 178 { 179 WCHAR szText[128 + MAX_PATH], szFormat[128]; 180 LoadStringW(shell32_hInstance, IDS_FILE_NOT_FOUND, szFormat, _countof(szFormat)); 181 StringCchPrintfW(szText, _countof(szText), szFormat, szFile); 182 MessageBoxW(hwnd, szText, NULL, MB_ICONERROR); 183 } 184 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); 185 } 186 } 187 } 188 189 ZeroMemory(&info, sizeof(info)); 190 info.cbSize = sizeof(info); 191 info.fMask = dwFlags; 192 info.hwnd = hwnd; 193 info.lpVerb = pszVerb; 194 info.lpFile = szFile; 195 info.lpParameters = (pchParams && *pchParams) ? pchParams : NULL; 196 info.lpDirectory = pwszStartDir; 197 info.nShow = nShow; 198 if (ShellExecuteExW(&info)) 199 { 200 if (info.lpIDList) 201 CoTaskMemFree(info.lpIDList); 202 203 SHFree(lpCommand); 204 205 return S_OK; 206 } 207 208 dwError = GetLastError(); 209 210 SHFree(lpCommand); 211 212 return HRESULT_FROM_WIN32(dwError); 213 } 214 #else 215 typedef HRESULT (WINAPI *SHELLEXECCMDLINE)(HWND, LPCWSTR, LPCWSTR, INT, LPVOID, DWORD); 216 SHELLEXECCMDLINE g_pShellExecCmdLine = NULL; 217 #endif 218 219 typedef struct TEST_ENTRY 220 { 221 INT lineno; 222 HRESULT hr; 223 BOOL bAllowNonExe; 224 LPCWSTR pwszWindowClass; 225 LPCWSTR pwszCommand; 226 LPCWSTR pwszStartDir; 227 } TEST_ENTRY; 228 229 static const char s_testfile1[] = "Test File.txt"; 230 static const char s_testfile2[] = "Test File.bat"; 231 static char s_notepad[] = "notepad.exe"; 232 233 static const TEST_ENTRY s_entries[] = 234 { 235 // NULL 236 { __LINE__, (HRESULT)0xDEADFACE, FALSE, NULL, NULL, NULL }, 237 { __LINE__, (HRESULT)0xDEADFACE, FALSE, NULL, NULL, L"." }, 238 { __LINE__, (HRESULT)0xDEADFACE, FALSE, NULL, NULL, L"system32" }, 239 { __LINE__, (HRESULT)0xDEADFACE, FALSE, NULL, NULL, L"C:\\Program Files" }, 240 { __LINE__, (HRESULT)0xDEADFACE, TRUE, NULL, NULL, NULL }, 241 { __LINE__, (HRESULT)0xDEADFACE, TRUE, NULL, NULL, L"." }, 242 { __LINE__, (HRESULT)0xDEADFACE, TRUE, NULL, NULL, L"system32" }, 243 { __LINE__, (HRESULT)0xDEADFACE, TRUE, NULL, NULL, L"C:\\Program Files" }, 244 // notepad 245 { __LINE__, S_OK, FALSE, L"Notepad", L"notepad", NULL }, 246 { __LINE__, S_OK, FALSE, L"Notepad", L"notepad", L"." }, 247 { __LINE__, S_OK, FALSE, L"Notepad", L"notepad", L"system32" }, 248 { __LINE__, S_OK, FALSE, L"Notepad", L"notepad", L"C:\\Program Files" }, 249 { __LINE__, S_OK, FALSE, L"Notepad", L"notepad \"Test File.txt\"", NULL }, 250 { __LINE__, S_OK, FALSE, L"Notepad", L"notepad \"Test File.txt\"", L"." }, 251 { __LINE__, S_OK, TRUE, L"Notepad", L"notepad", NULL }, 252 { __LINE__, S_OK, TRUE, L"Notepad", L"notepad", L"." }, 253 { __LINE__, S_OK, TRUE, L"Notepad", L"notepad", L"system32" }, 254 { __LINE__, S_OK, TRUE, L"Notepad", L"notepad", L"C:\\Program Files" }, 255 { __LINE__, S_OK, TRUE, L"Notepad", L"notepad \"Test File.txt\"", NULL }, 256 { __LINE__, S_OK, TRUE, L"Notepad", L"notepad \"Test File.txt\"", L"." }, 257 // notepad.exe 258 { __LINE__, S_OK, FALSE, L"Notepad", L"notepad.exe", NULL }, 259 { __LINE__, S_OK, FALSE, L"Notepad", L"notepad.exe", L"." }, 260 { __LINE__, S_OK, FALSE, L"Notepad", L"notepad.exe", L"system32" }, 261 { __LINE__, S_OK, FALSE, L"Notepad", L"notepad.exe", L"C:\\Program Files" }, 262 { __LINE__, S_OK, FALSE, L"Notepad", L"notepad.exe \"Test File.txt\"", NULL }, 263 { __LINE__, S_OK, FALSE, L"Notepad", L"notepad.exe \"Test File.txt\"", L"." }, 264 { __LINE__, S_OK, TRUE, L"Notepad", L"notepad.exe", NULL }, 265 { __LINE__, S_OK, TRUE, L"Notepad", L"notepad.exe", L"." }, 266 { __LINE__, S_OK, TRUE, L"Notepad", L"notepad.exe", L"system32" }, 267 { __LINE__, S_OK, TRUE, L"Notepad", L"notepad.exe", L"C:\\Program Files" }, 268 { __LINE__, S_OK, TRUE, L"Notepad", L"notepad.exe \"Test File.txt\"", NULL }, 269 { __LINE__, S_OK, TRUE, L"Notepad", L"notepad.exe \"Test File.txt\"", L"." }, 270 // C:\notepad.exe 271 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"C:\\notepad.exe", NULL }, 272 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"C:\\notepad.exe", L"." }, 273 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"C:\\notepad.exe", L"system32" }, 274 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"C:\\notepad.exe", L"C:\\Program Files" }, 275 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"C:\\notepad.exe \"Test File.txt\"", NULL }, 276 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"C:\\notepad.exe \"Test File.txt\"", L"." }, 277 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"C:\\notepad.exe", NULL }, 278 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"C:\\notepad.exe", L"." }, 279 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"C:\\notepad.exe", L"system32" }, 280 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"C:\\notepad.exe", L"C:\\Program Files" }, 281 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"C:\\notepad.exe \"Test File.txt\"", NULL }, 282 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"C:\\notepad.exe \"Test File.txt\"", L"." }, 283 // "notepad" 284 { __LINE__, S_OK, FALSE, L"Notepad", L"\"notepad\"", NULL }, 285 { __LINE__, S_OK, FALSE, L"Notepad", L"\"notepad\"", L"." }, 286 { __LINE__, S_OK, FALSE, L"Notepad", L"\"notepad\"", L"system32" }, 287 { __LINE__, S_OK, FALSE, L"Notepad", L"\"notepad\"", L"C:\\Program Files" }, 288 { __LINE__, S_OK, FALSE, L"Notepad", L"\"notepad\" \"Test File.txt\"", NULL }, 289 { __LINE__, S_OK, FALSE, L"Notepad", L"\"notepad\" \"Test File.txt\"", L"." }, 290 { __LINE__, S_OK, TRUE, L"Notepad", L"\"notepad\"", NULL }, 291 { __LINE__, S_OK, TRUE, L"Notepad", L"\"notepad\"", L"." }, 292 { __LINE__, S_OK, TRUE, L"Notepad", L"\"notepad\"", L"system32" }, 293 { __LINE__, S_OK, TRUE, L"Notepad", L"\"notepad\"", L"C:\\Program Files" }, 294 { __LINE__, S_OK, TRUE, L"Notepad", L"\"notepad\" \"Test File.txt\"", NULL }, 295 { __LINE__, S_OK, TRUE, L"Notepad", L"\"notepad\" \"Test File.txt\"", L"." }, 296 // "notepad.exe" 297 { __LINE__, S_OK, FALSE, L"Notepad", L"\"notepad.exe\"", NULL }, 298 { __LINE__, S_OK, FALSE, L"Notepad", L"\"notepad.exe\"", L"." }, 299 { __LINE__, S_OK, FALSE, L"Notepad", L"\"notepad.exe\"", L"system32" }, 300 { __LINE__, S_OK, FALSE, L"Notepad", L"\"notepad.exe\"", L"C:\\Program Files" }, 301 { __LINE__, S_OK, FALSE, L"Notepad", L"\"notepad.exe\" \"Test File.txt\"", NULL }, 302 { __LINE__, S_OK, FALSE, L"Notepad", L"\"notepad.exe\" \"Test File.txt\"", L"." }, 303 { __LINE__, S_OK, TRUE, L"Notepad", L"\"notepad.exe\"", NULL }, 304 { __LINE__, S_OK, TRUE, L"Notepad", L"\"notepad.exe\"", L"." }, 305 { __LINE__, S_OK, TRUE, L"Notepad", L"\"notepad.exe\"", L"system32" }, 306 { __LINE__, S_OK, TRUE, L"Notepad", L"\"notepad.exe\"", L"C:\\Program Files" }, 307 { __LINE__, S_OK, TRUE, L"Notepad", L"\"notepad.exe\" \"Test File.txt\"", NULL }, 308 { __LINE__, S_OK, TRUE, L"Notepad", L"\"notepad.exe\" \"Test File.txt\"", L"." }, 309 // test program.exe 310 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"test program.exe", NULL }, 311 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"test program.exe", L"." }, 312 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"test program.exe", L"system32" }, 313 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"test program.exe", L"C:\\Program Files" }, 314 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"test program.exe \"Test File.txt\"", NULL }, 315 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"test program.exe \"Test File.txt\"", L"." }, 316 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"test program.exe", NULL }, 317 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"test program.exe", L"." }, 318 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"test program.exe", L"system32" }, 319 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"test program.exe", L"C:\\Program Files" }, 320 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"test program.exe \"Test File.txt\"", NULL }, 321 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"test program.exe \"Test File.txt\"", L"." }, 322 // "test program" 323 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"test program\"", NULL }, 324 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"test program\"", L"." }, 325 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"test program\"", L"system32" }, 326 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"test program\"", L"C:\\Program Files" }, 327 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"test program\" \"Test File.txt\"", NULL }, 328 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"test program\" \"Test File.txt\"", L"." }, 329 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"\"test program\"", NULL }, 330 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"\"test program\"", L"." }, 331 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"\"test program\"", L"system32" }, 332 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"\"test program\"", L"C:\\Program Files" }, 333 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"\"test program\" \"Test File.txt\"", NULL }, 334 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"\"test program\" \"Test File.txt\"", L"." }, 335 // "test program.exe" 336 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"test program.exe\"", NULL }, 337 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"test program.exe\"", L"." }, 338 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"test program.exe\"", L"system32" }, 339 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"test program.exe\"", L"C:\\Program Files" }, 340 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"test program.exe\" \"Test File.txt\"", NULL }, 341 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"test program.exe\" \"Test File.txt\"", L"." }, 342 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"\"test program.exe\"", NULL }, 343 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"\"test program.exe\"", L"." }, 344 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"\"test program.exe\"", L"system32" }, 345 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"\"test program.exe\"", L"C:\\Program Files" }, 346 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"\"test program.exe\" \"Test File.txt\"", NULL }, 347 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"\"test program.exe\" \"Test File.txt\"", L"." }, 348 // invalid program 349 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"invalid program", NULL }, 350 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"invalid program", L"." }, 351 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"invalid program", L"system32" }, 352 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"invalid program", L"C:\\Program Files" }, 353 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"invalid program \"Test File.txt\"", NULL }, 354 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"invalid program \"Test File.txt\"", L"." }, 355 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"invalid program", NULL }, 356 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"invalid program", L"." }, 357 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"invalid program", L"system32" }, 358 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"invalid program", L"C:\\Program Files" }, 359 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"invalid program \"Test File.txt\"", NULL }, 360 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"invalid program \"Test File.txt\"", L"." }, 361 // \"invalid program.exe\" 362 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"invalid program.exe\"", NULL }, 363 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"invalid program.exe\"", L"." }, 364 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"invalid program.exe\"", L"system32" }, 365 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"invalid program.exe\"", L"C:\\Program Files" }, 366 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"invalid program.exe\" \"Test File.txt\"", NULL }, 367 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"invalid program.exe\" \"Test File.txt\"", L"." }, 368 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"\"invalid program.exe\"", NULL }, 369 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"\"invalid program.exe\"", L"." }, 370 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"\"invalid program.exe\"", L"system32" }, 371 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"\"invalid program.exe\"", L"C:\\Program Files" }, 372 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"\"invalid program.exe\" \"Test File.txt\"", NULL }, 373 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", L"\"invalid program.exe\" \"Test File.txt\"", L"." }, 374 }; 375 376 static void DoEntry(const TEST_ENTRY *pEntry) 377 { 378 HRESULT hr; 379 DWORD dwSeclFlags; 380 381 if (pEntry->bAllowNonExe) 382 dwSeclFlags = SECL_NO_UI | SECL_ALLOW_NONEXE; 383 else 384 dwSeclFlags = SECL_NO_UI; 385 386 _SEH2_TRY 387 { 388 #ifdef ShellExecCmdLine 389 hr = ShellExecCmdLine(NULL, pEntry->pwszCommand, pEntry->pwszStartDir, 390 SW_SHOWNORMAL, NULL, dwSeclFlags); 391 #else 392 hr = (*g_pShellExecCmdLine)(NULL, pEntry->pwszCommand, pEntry->pwszStartDir, 393 SW_SHOWNORMAL, NULL, dwSeclFlags); 394 #endif 395 } 396 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 397 { 398 hr = 0xDEADFACE; 399 } 400 _SEH2_END; 401 402 ok(hr == pEntry->hr, "Line %d: hr expected 0x%lX, was 0x%lX\n", pEntry->lineno, pEntry->hr, hr); 403 404 #define RETRY_COUNT 5 405 #define RETRY_INTERVAL 250 406 if (SUCCEEDED(hr) && pEntry->pwszWindowClass) 407 { 408 BOOL bFound = FALSE; 409 Sleep(RETRY_INTERVAL / 2); 410 for (int i = 0; i < RETRY_COUNT; ++i) 411 { 412 HWND hwnd = FindWindowW(pEntry->pwszWindowClass, NULL); 413 if (hwnd) 414 { 415 bFound = TRUE; 416 SendMessage(hwnd, WM_CLOSE, 0, 0); 417 Sleep(RETRY_INTERVAL); 418 break; 419 } 420 Sleep(RETRY_INTERVAL); 421 } 422 ok(bFound, "Line %d: The window not found\n", pEntry->lineno); 423 } 424 #undef RETRY_COUNT 425 #undef RETRY_INTERVAL 426 } 427 428 START_TEST(ShellExecCmdLine) 429 { 430 using namespace std; 431 432 #ifndef ShellExecCmdLine 433 HMODULE hShell32 = GetModuleHandleA("shell32"); 434 g_pShellExecCmdLine = (SHELLEXECCMDLINE)GetProcAddress(hShell32, (LPCSTR)(INT_PTR)265); 435 if (!g_pShellExecCmdLine) 436 { 437 skip("ShellExecCmdLine is not found\n"); 438 return; 439 } 440 #endif 441 442 // s_testfile1 443 FILE *fp = fopen(s_testfile1, "wb"); 444 ok(fp != NULL, "failed to create a test file\n"); 445 fclose(fp); 446 447 // s_testfile2 448 fp = fopen(s_testfile2, "wb"); 449 ok(fp != NULL, "failed to create a test file\n"); 450 if (fp) 451 { 452 fprintf(fp, "echo OK\n"); 453 } 454 fclose(fp); 455 456 for (size_t i = 0; i < _countof(s_entries); ++i) 457 { 458 DoEntry(&s_entries[i]); 459 } 460 461 WCHAR buf0[MAX_PATH]; 462 WCHAR buf1[MAX_PATH]; 463 WCHAR buf2[MAX_PATH]; 464 TEST_ENTRY additionals[] = 465 { 466 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", buf0, NULL }, 467 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", buf0, L"." }, 468 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", buf0, L"system32" }, 469 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", buf1, NULL }, 470 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", buf1, L"." }, 471 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", buf1, L"system32" }, 472 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", buf2, NULL }, 473 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", buf2, L"." }, 474 { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", buf2, L"system32" }, 475 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", buf0, NULL }, // FIXME 476 { __LINE__, S_OK, TRUE, L"Notepad", buf0, L"." }, 477 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", buf0, L"system32" }, // FIXME 478 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", buf1, NULL }, // FIXME 479 { __LINE__, S_OK, TRUE, L"Notepad", buf1, L"." }, 480 { __LINE__, S_OK, TRUE, L"Notepad", buf1, L"system32" }, 481 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad", buf2, NULL }, // FIXME 482 { __LINE__, S_OK, TRUE, L"Notepad", buf2, L"." }, 483 { __LINE__, S_OK, TRUE, L"Notepad", buf2, L"system32" }, 484 }; 485 486 wsprintfW(buf0, L"%hs", s_testfile1); 487 wsprintfW(buf1, L"\"%hs\"", s_testfile1); 488 wsprintfW(buf2, L"\"%hs\" \"Test File.txt\"", s_testfile1); 489 for (size_t i = 0; i < _countof(additionals); ++i) 490 { 491 DoEntry(&additionals[i]); 492 } 493 494 TEST_ENTRY additionals2[] = 495 { 496 { __LINE__, CO_E_APPNOTFOUND, FALSE, NULL, buf0, NULL }, 497 { __LINE__, CO_E_APPNOTFOUND, FALSE, NULL, buf0, L"." }, 498 { __LINE__, CO_E_APPNOTFOUND, FALSE, NULL, buf0, L"system32" }, 499 { __LINE__, CO_E_APPNOTFOUND, FALSE, NULL, buf1, NULL }, 500 { __LINE__, CO_E_APPNOTFOUND, FALSE, NULL, buf1, L"." }, 501 { __LINE__, CO_E_APPNOTFOUND, FALSE, NULL, buf1, L"system32" }, 502 { __LINE__, CO_E_APPNOTFOUND, FALSE, NULL, buf2, NULL }, 503 { __LINE__, CO_E_APPNOTFOUND, FALSE, NULL, buf2, L"." }, 504 { __LINE__, CO_E_APPNOTFOUND, FALSE, NULL, buf2, L"system32" }, 505 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, NULL, buf0, NULL }, // FIXME 506 { __LINE__, S_OK, TRUE, NULL, buf0, L"." }, 507 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, NULL, buf0, L"system32" }, // FIXME 508 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, NULL, buf1, NULL }, // FIXME 509 { __LINE__, S_OK, TRUE, NULL, buf1, L"." }, 510 { __LINE__, S_OK, TRUE, NULL, buf1, L"system32" }, 511 { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, NULL, buf2, NULL }, // FIXME 512 { __LINE__, S_OK, TRUE, NULL, buf2, L"." }, 513 { __LINE__, S_OK, TRUE, NULL, buf2, L"system32" }, 514 }; 515 516 wsprintfW(buf0, L"%hs", s_testfile2); 517 wsprintfW(buf1, L"\"%hs\"", s_testfile2); 518 wsprintfW(buf2, L"\"%hs\" \"Test File.txt\"", s_testfile2); 519 for (size_t i = 0; i < _countof(additionals2); ++i) 520 { 521 DoEntry(&additionals2[i]); 522 } 523 524 char path[MAX_PATH]; 525 ok((INT_PTR)FindExecutableA("notepad.exe", NULL, s_notepad) >= 32, "FindExecutableA failed\n"); 526 ok(GetModuleFileNameA(NULL, path, _countof(path)), "GetModuleFileNameA failed\n"); 527 char *pch = strrchr(path, '\\'); 528 529 if (pch == NULL) 530 { 531 skip("pch == NULL\n"); 532 } 533 else 534 { 535 // create "My Directory" 536 strcpy(pch, "\\My Directory"); 537 if (GetFileAttributesA(path) == INVALID_FILE_ATTRIBUTES) 538 ok(CreateDirectoryA(path, NULL), "CreateDirectoryA failed\n"); 539 540 // create "My Directory\\Notepad.exe" as clone of Notepad.exe 541 strcpy(pch, "\\My Directory\\Notepad.exe"); 542 ok(CopyFileA(s_notepad, path, FALSE), "CopyFileA failed\n"); 543 544 wsprintfW(buf0, L"%hs", path); 545 wsprintfW(buf1, L"\"%hs\"", path); 546 wsprintfW(buf2, L"\"%hs\" \"Test File.txt\"", path); 547 TEST_ENTRY additionals3[] = 548 { 549 { __LINE__, S_OK, FALSE, NULL, buf0, NULL }, 550 { __LINE__, S_OK, FALSE, NULL, buf0, L"." }, 551 { __LINE__, S_OK, FALSE, NULL, buf0, L"system32" }, 552 { __LINE__, S_OK, FALSE, NULL, buf1, NULL }, 553 { __LINE__, S_OK, FALSE, NULL, buf1, L"." }, 554 { __LINE__, S_OK, FALSE, NULL, buf1, L"system32" }, 555 { __LINE__, S_OK, FALSE, NULL, buf2, NULL }, 556 { __LINE__, S_OK, FALSE, NULL, buf2, L"." }, 557 { __LINE__, S_OK, FALSE, NULL, buf2, L"system32" }, 558 { __LINE__, S_OK, TRUE, NULL, buf0, NULL }, 559 { __LINE__, S_OK, TRUE, NULL, buf0, L"." }, 560 { __LINE__, S_OK, TRUE, NULL, buf0, L"system32" }, 561 { __LINE__, S_OK, TRUE, NULL, buf1, NULL }, 562 { __LINE__, S_OK, TRUE, NULL, buf1, L"." }, 563 { __LINE__, S_OK, TRUE, NULL, buf1, L"system32" }, 564 { __LINE__, S_OK, TRUE, NULL, buf2, NULL }, 565 { __LINE__, S_OK, TRUE, NULL, buf2, L"." }, 566 { __LINE__, S_OK, TRUE, NULL, buf2, L"system32" }, 567 }; 568 for (size_t i = 0; i < _countof(additionals3); ++i) 569 { 570 DoEntry(&additionals3[i]); 571 } 572 573 DeleteFileA(path); 574 575 strcpy(pch, "\\My Directory"); 576 RemoveDirectory(path); 577 } 578 579 // clean up 580 ok(DeleteFileA(s_testfile1), "failed to delete the test file\n"); 581 ok(DeleteFileA(s_testfile2), "failed to delete the test file\n"); 582 } 583