[SHELL32] Fix a careless mistake of ShellExecCmdLine (#737)
[reactos.git] / modules / rostests / apitests / shell32 / ShellExecCmdLine.cpp
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 }