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
__SHCloneStrW(WCHAR ** target,const WCHAR * source)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
SplitParams(LPCWSTR psz,LPWSTR pszArg0,size_t cchArg0)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
ShellExecCmdLine(HWND hwnd,LPCWSTR pwszCommand,LPCWSTR pwszStartDir,int nShow,LPVOID pUnused,DWORD dwSeclFlags)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
EnumWindowsProc(HWND hwnd,LPARAM lParam)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
CleanupNewlyCreatedWindows(void)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
DoEntry(const TEST_ENTRY * pEntry)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
START_TEST(ShellExecCmdLine)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