1c2c66affSColin Finck /*
2c2c66affSColin Finck  * PROJECT:         ReactOS api tests
3c2c66affSColin Finck  * LICENSE:         GPLv2+ - See COPYING in the top level directory
4c2c66affSColin Finck  * PURPOSE:         Testing ShellExecuteEx
5c2c66affSColin Finck  * PROGRAMMER:      Yaroslav Veremenko <yaroslav@veremenko.info>
6c35a8498SKatayama Hirofumi MZ  *                  Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
7c2c66affSColin Finck  */
8c2c66affSColin Finck 
9c2c66affSColin Finck #include "shelltest.h"
10c35a8498SKatayama Hirofumi MZ #include <shlwapi.h>
11c35a8498SKatayama Hirofumi MZ #include <stdio.h>
1260b89da3SKatayama Hirofumi MZ #include "shell32_apitest_sub.h"
13c2c66affSColin Finck 
14c2c66affSColin Finck #define ok_ShellExecuteEx (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : TestShellExecuteEx
15c2c66affSColin Finck 
16c2c66affSColin Finck static
17c2c66affSColin Finck BOOL
18c2c66affSColin Finck CreateAppPathRegKey(const WCHAR* Name)
19c2c66affSColin Finck {
20c2c66affSColin Finck     HKEY RegistryKey;
21c2c66affSColin Finck     LONG Result;
22c2c66affSColin Finck     WCHAR Buffer[1024];
23c2c66affSColin Finck     WCHAR KeyValue[1024];
24c2c66affSColin Finck     DWORD Length = sizeof(KeyValue);
25c2c66affSColin Finck     DWORD Disposition;
26c2c66affSColin Finck 
27c2c66affSColin Finck     wcscpy(Buffer, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\");
28c2c66affSColin Finck     wcscat(Buffer, L"IEXPLORE.EXE");
29c2c66affSColin Finck     Result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, Buffer, 0, KEY_READ, &RegistryKey);
30c2c66affSColin Finck     if (Result != ERROR_SUCCESS) trace("Could not open iexplore.exe key. Status: %lu\n", Result);
31c2c66affSColin Finck     if (Result) goto end;
32c2c66affSColin Finck     Result = RegQueryValueExW(RegistryKey, NULL, NULL, NULL, (LPBYTE)KeyValue, &Length);
33c2c66affSColin Finck     if (Result != ERROR_SUCCESS) trace("Could not read iexplore.exe key. Status: %lu\n", Result);
34c2c66affSColin Finck     if (Result) goto end;
35c2c66affSColin Finck     RegCloseKey(RegistryKey);
36c2c66affSColin Finck 
37c2c66affSColin Finck     wcscpy(Buffer, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\");
38c2c66affSColin Finck     wcscat(Buffer, Name);
39c2c66affSColin Finck     Result = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Buffer, 0, NULL,
40c2c66affSColin Finck         0, KEY_WRITE, NULL, &RegistryKey, &Disposition);
41c2c66affSColin Finck     if (Result != ERROR_SUCCESS) trace("Could not create test key. Status: %lu\n", Result);
42c2c66affSColin Finck     if (Result) goto end;
43c2c66affSColin Finck     Result = RegSetValueW(RegistryKey, NULL, REG_SZ, KeyValue, 0);
44c2c66affSColin Finck     if (Result != ERROR_SUCCESS) trace("Could not set value of the test key. Status: %lu\n", Result);
45c2c66affSColin Finck     if (Result) goto end;
46c2c66affSColin Finck     RegCloseKey(RegistryKey);
47c2c66affSColin Finck end:
48c2c66affSColin Finck     if (RegistryKey) RegCloseKey(RegistryKey);
49c2c66affSColin Finck     return Result == ERROR_SUCCESS;
50c2c66affSColin Finck }
51c2c66affSColin Finck 
52c2c66affSColin Finck static
53c2c66affSColin Finck VOID
54c2c66affSColin Finck DeleteAppPathRegKey(const WCHAR* Name)
55c2c66affSColin Finck {
56c2c66affSColin Finck     LONG Result;
57c2c66affSColin Finck     WCHAR Buffer[1024];
58c2c66affSColin Finck     wcscpy(Buffer, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\");
59c2c66affSColin Finck     wcscat(Buffer, Name);
60c2c66affSColin Finck     Result = RegDeleteKeyW(HKEY_LOCAL_MACHINE, Buffer);
61c2c66affSColin Finck     if (Result != ERROR_SUCCESS) trace("Could not remove the test key. Status: %lu\n", Result);
62c2c66affSColin Finck }
63c2c66affSColin Finck 
64c2c66affSColin Finck static
65c2c66affSColin Finck VOID
66c2c66affSColin Finck TestShellExecuteEx(const WCHAR* Name, BOOL ExpectedResult)
67c2c66affSColin Finck {
68c2c66affSColin Finck     SHELLEXECUTEINFOW ShellExecInfo;
69c2c66affSColin Finck     BOOL Result;
70307ce1a5SHermès Bélusca-Maïto 
71c2c66affSColin Finck     ZeroMemory(&ShellExecInfo, sizeof(ShellExecInfo));
72c2c66affSColin Finck     ShellExecInfo.cbSize = sizeof(ShellExecInfo);
73c2c66affSColin Finck     ShellExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI;
74c2c66affSColin Finck     ShellExecInfo.hwnd = NULL;
75c2c66affSColin Finck     ShellExecInfo.nShow = SW_SHOWNORMAL;
76c2c66affSColin Finck     ShellExecInfo.lpFile = Name;
77c2c66affSColin Finck     ShellExecInfo.lpDirectory = NULL;
78307ce1a5SHermès Bélusca-Maïto 
79c2c66affSColin Finck     Result = ShellExecuteExW(&ShellExecInfo);
80c2c66affSColin Finck     ok(Result == ExpectedResult, "ShellExecuteEx lpFile %s failed. Error: %lu\n", wine_dbgstr_w(Name), GetLastError());
81c2c66affSColin Finck     if (ShellExecInfo.hProcess)
82c2c66affSColin Finck     {
83c2c66affSColin Finck         Result = TerminateProcess(ShellExecInfo.hProcess, 0);
84c2c66affSColin Finck         if (!Result) trace("Terminate process failed. Error: %lu\n", GetLastError());
85c2c66affSColin Finck         WaitForSingleObject(ShellExecInfo.hProcess, INFINITE);
86c2c66affSColin Finck         CloseHandle(ShellExecInfo.hProcess);
87c2c66affSColin Finck     }
88c2c66affSColin Finck }
89c2c66affSColin Finck 
90c35a8498SKatayama Hirofumi MZ static void DoAppPathTest(void)
91c2c66affSColin Finck {
92c2c66affSColin Finck     ok_ShellExecuteEx(L"iexplore", TRUE);
93c2c66affSColin Finck     ok_ShellExecuteEx(L"iexplore.exe", TRUE);
94c2c66affSColin Finck 
95c2c66affSColin Finck     if (CreateAppPathRegKey(L"iexplore.bat"))
96c2c66affSColin Finck     {
97c2c66affSColin Finck         ok_ShellExecuteEx(L"iexplore.bat", TRUE);
98c2c66affSColin Finck         ok_ShellExecuteEx(L"iexplore.bat.exe", FALSE);
99c2c66affSColin Finck         DeleteAppPathRegKey(L"iexplore.bat");
100c2c66affSColin Finck     }
101c2c66affSColin Finck 
102c2c66affSColin Finck     if (CreateAppPathRegKey(L"iexplore.bat.exe"))
103c2c66affSColin Finck     {
104c2c66affSColin Finck         ok_ShellExecuteEx(L"iexplore.bat", FALSE);
105c2c66affSColin Finck         ok_ShellExecuteEx(L"iexplore.bat.exe", TRUE);
106c2c66affSColin Finck         DeleteAppPathRegKey(L"iexplore.bat.exe");
107c2c66affSColin Finck     }
108c2c66affSColin Finck }
109c35a8498SKatayama Hirofumi MZ 
110c35a8498SKatayama Hirofumi MZ typedef struct TEST_ENTRY
111c35a8498SKatayama Hirofumi MZ {
112c35a8498SKatayama Hirofumi MZ     INT lineno;
113c35a8498SKatayama Hirofumi MZ     BOOL ret;
114c35a8498SKatayama Hirofumi MZ     BOOL bProcessHandle;
115c35a8498SKatayama Hirofumi MZ     LPCSTR file;
116c35a8498SKatayama Hirofumi MZ     LPCSTR params;
117c35a8498SKatayama Hirofumi MZ     LPCSTR curdir;
118c35a8498SKatayama Hirofumi MZ } TEST_ENTRY;
119c35a8498SKatayama Hirofumi MZ 
120c35a8498SKatayama Hirofumi MZ static char s_sub_program[MAX_PATH];
121c35a8498SKatayama Hirofumi MZ static char s_win_test_exe[MAX_PATH];
122c35a8498SKatayama Hirofumi MZ static char s_sys_test_exe[MAX_PATH];
123c35a8498SKatayama Hirofumi MZ static char s_win_bat_file[MAX_PATH];
124c35a8498SKatayama Hirofumi MZ static char s_sys_bat_file[MAX_PATH];
125c35a8498SKatayama Hirofumi MZ static char s_win_txt_file[MAX_PATH];
126c35a8498SKatayama Hirofumi MZ static char s_sys_txt_file[MAX_PATH];
127c35a8498SKatayama Hirofumi MZ 
128c35a8498SKatayama Hirofumi MZ #define DONT_CARE 0x0BADF00D
129c35a8498SKatayama Hirofumi MZ 
130c35a8498SKatayama Hirofumi MZ static const TEST_ENTRY s_entries_1[] =
131c35a8498SKatayama Hirofumi MZ {
132c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, "test program" },
133c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, "test program.bat" },
134c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, "test program.exe" },
135c35a8498SKatayama Hirofumi MZ     { __LINE__, FALSE, FALSE, "  test program" },
136c35a8498SKatayama Hirofumi MZ     { __LINE__, FALSE, FALSE, "  test program.bat" },
137c35a8498SKatayama Hirofumi MZ     { __LINE__, FALSE, FALSE, "  test program.exe" },
138c35a8498SKatayama Hirofumi MZ     { __LINE__, FALSE, FALSE, "test program  " },
139c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, "test program.bat  " },
140c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, "test program.exe  " },
141c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, "test program", "TEST" },
142c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, "test program.bat", "TEST" },
143c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, "test program.exe", "TEST" },
144c35a8498SKatayama Hirofumi MZ     { __LINE__, FALSE, FALSE, ".\\test program.bat" },
145c35a8498SKatayama Hirofumi MZ     { __LINE__, FALSE, FALSE, ".\\test program.exe" },
146c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, "\"test program\"" },
147c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, "\"test program.bat\"" },
148c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, "\"test program.exe\"" },
149c35a8498SKatayama Hirofumi MZ     { __LINE__, FALSE, FALSE, "\"test program\" TEST" },
150c35a8498SKatayama Hirofumi MZ     { __LINE__, FALSE, FALSE, "\"test program.bat\" TEST" },
151c35a8498SKatayama Hirofumi MZ     { __LINE__, FALSE, FALSE, "\"test program.exe\" TEST" },
152c35a8498SKatayama Hirofumi MZ     { __LINE__, FALSE, FALSE, "  \"test program\"" },
153c35a8498SKatayama Hirofumi MZ     { __LINE__, FALSE, FALSE, "  \"test program.bat\"" },
154c35a8498SKatayama Hirofumi MZ     { __LINE__, FALSE, FALSE, "  \"test program.exe\"" },
155c35a8498SKatayama Hirofumi MZ     { __LINE__, FALSE, FALSE, "\"test program\"  " },
156c35a8498SKatayama Hirofumi MZ     { __LINE__, FALSE, FALSE, "\"test program.bat\"  " },
157c35a8498SKatayama Hirofumi MZ     { __LINE__, FALSE, FALSE, "\"test program.exe\"  " },
158c35a8498SKatayama Hirofumi MZ     { __LINE__, FALSE, FALSE, "\".\\test program.bat\"" },
159c35a8498SKatayama Hirofumi MZ     { __LINE__, FALSE, FALSE, "\".\\test program.exe\"" },
160c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, s_win_test_exe },
161c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, s_sys_test_exe },
162c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, s_win_bat_file },
163c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, s_sys_bat_file },
164c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, s_win_bat_file, "TEST" },
165c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, s_sys_bat_file, "TEST" },
166c35a8498SKatayama Hirofumi MZ     { __LINE__, FALSE, FALSE, "invalid program" },
167c35a8498SKatayama Hirofumi MZ     { __LINE__, FALSE, FALSE, "invalid program.bat" },
168c35a8498SKatayama Hirofumi MZ     { __LINE__, FALSE, FALSE, "invalid program.exe" },
169c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, "test_file.txt" },
170c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, "test_file.txt", "parameters parameters" },
171c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, "test_file.txt", "parameters parameters", "." },
172c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, "shell32_apitest_sub.exe" },
173c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, ".\\shell32_apitest_sub.exe" },
174c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, "\"shell32_apitest_sub.exe\"" },
175c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, "\".\\shell32_apitest_sub.exe\"" },
176c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, DONT_CARE, "https://google.com" },
177c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, FALSE, "::{450d8fba-ad25-11d0-98a8-0800361b1103}" },
178c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, FALSE, "shell:::{450d8fba-ad25-11d0-98a8-0800361b1103}" },
179c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, FALSE, "shell:sendto" },
180c35a8498SKatayama Hirofumi MZ };
181c35a8498SKatayama Hirofumi MZ 
182c35a8498SKatayama Hirofumi MZ static const TEST_ENTRY s_entries_2[] =
183c35a8498SKatayama Hirofumi MZ {
184c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, "test program" },
185c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, "test program", "TEST" },
186c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, "\"test program\"" },
187c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, s_win_test_exe },
188c35a8498SKatayama Hirofumi MZ     { __LINE__, TRUE, TRUE, s_sys_test_exe },
189c35a8498SKatayama Hirofumi MZ     { __LINE__, FALSE, FALSE, s_win_bat_file },
190c35a8498SKatayama Hirofumi MZ     { __LINE__, FALSE, FALSE, s_sys_bat_file },
191c35a8498SKatayama Hirofumi MZ     { __LINE__, FALSE, FALSE, s_win_bat_file, "TEST" },
192c35a8498SKatayama Hirofumi MZ     { __LINE__, FALSE, FALSE, s_sys_bat_file, "TEST" },
193c35a8498SKatayama Hirofumi MZ };
194c35a8498SKatayama Hirofumi MZ 
195c35a8498SKatayama Hirofumi MZ typedef struct OPENWNDS
196c35a8498SKatayama Hirofumi MZ {
197c35a8498SKatayama Hirofumi MZ     UINT count;
198c35a8498SKatayama Hirofumi MZ     HWND *phwnd;
199c35a8498SKatayama Hirofumi MZ } OPENWNDS;
200c35a8498SKatayama Hirofumi MZ 
201c35a8498SKatayama Hirofumi MZ static OPENWNDS s_wi0 = { 0 }, s_wi1 = { 0 };
202c35a8498SKatayama Hirofumi MZ 
203c35a8498SKatayama Hirofumi MZ static BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
204c35a8498SKatayama Hirofumi MZ {
205c35a8498SKatayama Hirofumi MZ     OPENWNDS *info = (OPENWNDS *)lParam;
206c35a8498SKatayama Hirofumi MZ     info->phwnd = (HWND *)realloc(info->phwnd, (info->count + 1) * sizeof(HWND));
207c35a8498SKatayama Hirofumi MZ     if (!info->phwnd)
208c35a8498SKatayama Hirofumi MZ         return FALSE;
209c35a8498SKatayama Hirofumi MZ     info->phwnd[info->count] = hwnd;
210c35a8498SKatayama Hirofumi MZ     ++(info->count);
211c35a8498SKatayama Hirofumi MZ     return TRUE;
212c35a8498SKatayama Hirofumi MZ }
213c35a8498SKatayama Hirofumi MZ 
214307ce1a5SHermès Bélusca-Maïto static void CleanupNewlyCreatedWindows(void)
215307ce1a5SHermès Bélusca-Maïto {
216307ce1a5SHermès Bélusca-Maïto     EnumWindows(EnumWindowsProc, (LPARAM)&s_wi1);
217307ce1a5SHermès Bélusca-Maïto     for (UINT i1 = 0; i1 < s_wi1.count; ++i1)
218307ce1a5SHermès Bélusca-Maïto     {
219307ce1a5SHermès Bélusca-Maïto         BOOL bFound = FALSE;
220307ce1a5SHermès Bélusca-Maïto         for (UINT i0 = 0; i0 < s_wi0.count; ++i0)
221307ce1a5SHermès Bélusca-Maïto         {
222307ce1a5SHermès Bélusca-Maïto             if (s_wi1.phwnd[i1] == s_wi0.phwnd[i0])
223307ce1a5SHermès Bélusca-Maïto             {
224307ce1a5SHermès Bélusca-Maïto                 bFound = TRUE;
225307ce1a5SHermès Bélusca-Maïto                 break;
226307ce1a5SHermès Bélusca-Maïto             }
227307ce1a5SHermès Bélusca-Maïto         }
228307ce1a5SHermès Bélusca-Maïto         if (!bFound)
229307ce1a5SHermès Bélusca-Maïto             PostMessageW(s_wi1.phwnd[i1], WM_CLOSE, 0, 0);
230307ce1a5SHermès Bélusca-Maïto     }
231307ce1a5SHermès Bélusca-Maïto     free(s_wi1.phwnd);
232307ce1a5SHermès Bélusca-Maïto     ZeroMemory(&s_wi1, sizeof(s_wi1));
233307ce1a5SHermès Bélusca-Maïto }
234307ce1a5SHermès Bélusca-Maïto 
235c35a8498SKatayama Hirofumi MZ static VOID DoTestEntry(const TEST_ENTRY *pEntry)
236c35a8498SKatayama Hirofumi MZ {
237c35a8498SKatayama Hirofumi MZ     SHELLEXECUTEINFOA info = { sizeof(info) };
238c35a8498SKatayama Hirofumi MZ     info.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI;
239c35a8498SKatayama Hirofumi MZ     info.nShow = SW_SHOWNORMAL;
240c35a8498SKatayama Hirofumi MZ     info.lpFile = pEntry->file;
241c35a8498SKatayama Hirofumi MZ     info.lpParameters = pEntry->params;
242c35a8498SKatayama Hirofumi MZ     info.lpDirectory = pEntry->curdir;
243c35a8498SKatayama Hirofumi MZ     BOOL ret = ShellExecuteExA(&info);
244c35a8498SKatayama Hirofumi MZ     ok(ret == pEntry->ret, "Line %u: ret expected %d, got %d\n",
245c35a8498SKatayama Hirofumi MZ        pEntry->lineno, pEntry->ret, ret);
246c35a8498SKatayama Hirofumi MZ     if (!pEntry->ret)
247c35a8498SKatayama Hirofumi MZ         return;
248c35a8498SKatayama Hirofumi MZ 
249c35a8498SKatayama Hirofumi MZ     if ((UINT)pEntry->bProcessHandle != DONT_CARE)
250c35a8498SKatayama Hirofumi MZ     {
251c35a8498SKatayama Hirofumi MZ         if (pEntry->bProcessHandle)
252c35a8498SKatayama Hirofumi MZ         {
253c35a8498SKatayama Hirofumi MZ             ok(!!info.hProcess, "Line %u: hProcess expected non-NULL\n", pEntry->lineno);
254c35a8498SKatayama Hirofumi MZ         }
255c35a8498SKatayama Hirofumi MZ         else
256c35a8498SKatayama Hirofumi MZ         {
257c35a8498SKatayama Hirofumi MZ             ok(!info.hProcess, "Line %u: hProcess expected NULL\n", pEntry->lineno);
258c35a8498SKatayama Hirofumi MZ             return;
259c35a8498SKatayama Hirofumi MZ         }
260c35a8498SKatayama Hirofumi MZ     }
261c35a8498SKatayama Hirofumi MZ 
262c35a8498SKatayama Hirofumi MZ     WaitForInputIdle(info.hProcess, INFINITE);
263c35a8498SKatayama Hirofumi MZ 
264307ce1a5SHermès Bélusca-Maïto     CleanupNewlyCreatedWindows();
265c35a8498SKatayama Hirofumi MZ 
266f80de47cSMark Jansen     if (WaitForSingleObject(info.hProcess, 10 * 1000) == WAIT_TIMEOUT)
267f80de47cSMark Jansen     {
268f80de47cSMark Jansen         TerminateProcess(info.hProcess, 11);
269f80de47cSMark Jansen         ok(0, "Process %s did not quit!\n", pEntry->file);
270f80de47cSMark Jansen     }
271c35a8498SKatayama Hirofumi MZ     CloseHandle(info.hProcess);
272c35a8498SKatayama Hirofumi MZ }
273c35a8498SKatayama Hirofumi MZ 
274c35a8498SKatayama Hirofumi MZ static BOOL
275c35a8498SKatayama Hirofumi MZ GetSubProgramPath(void)
276c35a8498SKatayama Hirofumi MZ {
277c35a8498SKatayama Hirofumi MZ     GetModuleFileNameA(NULL, s_sub_program, _countof(s_sub_program));
278c35a8498SKatayama Hirofumi MZ     PathRemoveFileSpecA(s_sub_program);
279c35a8498SKatayama Hirofumi MZ     PathAppendA(s_sub_program, "shell32_apitest_sub.exe");
280c35a8498SKatayama Hirofumi MZ 
281c35a8498SKatayama Hirofumi MZ     if (!PathFileExistsA(s_sub_program))
282c35a8498SKatayama Hirofumi MZ     {
283c35a8498SKatayama Hirofumi MZ         PathRemoveFileSpecA(s_sub_program);
284c35a8498SKatayama Hirofumi MZ         PathAppendA(s_sub_program, "testdata\\shell32_apitest_sub.exe");
285c35a8498SKatayama Hirofumi MZ 
286c35a8498SKatayama Hirofumi MZ         if (!PathFileExistsA(s_sub_program))
287c35a8498SKatayama Hirofumi MZ         {
288c35a8498SKatayama Hirofumi MZ             return FALSE;
289c35a8498SKatayama Hirofumi MZ         }
290c35a8498SKatayama Hirofumi MZ     }
291c35a8498SKatayama Hirofumi MZ 
292c35a8498SKatayama Hirofumi MZ     return TRUE;
293c35a8498SKatayama Hirofumi MZ }
294c35a8498SKatayama Hirofumi MZ 
295c35a8498SKatayama Hirofumi MZ static void DoTestEntries(void)
296c35a8498SKatayama Hirofumi MZ {
297c35a8498SKatayama Hirofumi MZ     if (!GetSubProgramPath())
298c35a8498SKatayama Hirofumi MZ     {
299c35a8498SKatayama Hirofumi MZ         skip("shell32_apitest_sub.exe is not found\n");
300c35a8498SKatayama Hirofumi MZ         return;
301c35a8498SKatayama Hirofumi MZ     }
302c35a8498SKatayama Hirofumi MZ 
303c35a8498SKatayama Hirofumi MZ     // s_win_test_exe
304c35a8498SKatayama Hirofumi MZ     GetWindowsDirectoryA(s_win_test_exe, _countof(s_win_test_exe));
305c35a8498SKatayama Hirofumi MZ     PathAppendA(s_win_test_exe, "test program.exe");
306c35a8498SKatayama Hirofumi MZ     BOOL ret = CopyFileA(s_sub_program, s_win_test_exe, FALSE);
307c35a8498SKatayama Hirofumi MZ     if (!ret)
308c35a8498SKatayama Hirofumi MZ     {
309c35a8498SKatayama Hirofumi MZ         skip("Please retry with admin rights\n");
310c35a8498SKatayama Hirofumi MZ         return;
311c35a8498SKatayama Hirofumi MZ     }
312c35a8498SKatayama Hirofumi MZ 
313c35a8498SKatayama Hirofumi MZ     // record open windows
314c35a8498SKatayama Hirofumi MZ     if (!EnumWindows(EnumWindowsProc, (LPARAM)&s_wi0))
315c35a8498SKatayama Hirofumi MZ     {
316c35a8498SKatayama Hirofumi MZ         skip("EnumWindows failed\n");
317c35a8498SKatayama Hirofumi MZ         DeleteFileA(s_win_test_exe);
318c35a8498SKatayama Hirofumi MZ         free(s_wi0.phwnd);
319c35a8498SKatayama Hirofumi MZ         return;
320c35a8498SKatayama Hirofumi MZ     }
321c35a8498SKatayama Hirofumi MZ 
322c35a8498SKatayama Hirofumi MZ     // s_sys_test_exe
323c35a8498SKatayama Hirofumi MZ     GetSystemDirectoryA(s_sys_test_exe, _countof(s_sys_test_exe));
324c35a8498SKatayama Hirofumi MZ     PathAppendA(s_sys_test_exe, "test program.exe");
325c35a8498SKatayama Hirofumi MZ     ok_int(CopyFileA(s_sub_program, s_sys_test_exe, FALSE), TRUE);
326c35a8498SKatayama Hirofumi MZ 
327c35a8498SKatayama Hirofumi MZ     // s_win_bat_file
328c35a8498SKatayama Hirofumi MZ     GetWindowsDirectoryA(s_win_bat_file, _countof(s_win_bat_file));
329c35a8498SKatayama Hirofumi MZ     PathAppendA(s_win_bat_file, "test program.bat");
330c35a8498SKatayama Hirofumi MZ     FILE *fp = fopen(s_win_bat_file, "wb");
331c35a8498SKatayama Hirofumi MZ     fprintf(fp, "exit /b 3");
332c35a8498SKatayama Hirofumi MZ     fclose(fp);
333c35a8498SKatayama Hirofumi MZ     ok_int(PathFileExistsA(s_win_bat_file), TRUE);
334c35a8498SKatayama Hirofumi MZ 
335c35a8498SKatayama Hirofumi MZ     // s_sys_bat_file
336c35a8498SKatayama Hirofumi MZ     GetSystemDirectoryA(s_sys_bat_file, _countof(s_sys_bat_file));
337c35a8498SKatayama Hirofumi MZ     PathAppendA(s_sys_bat_file, "test program.bat");
338c35a8498SKatayama Hirofumi MZ     fp = fopen(s_sys_bat_file, "wb");
339c35a8498SKatayama Hirofumi MZ     fprintf(fp, "exit /b 4");
340c35a8498SKatayama Hirofumi MZ     fclose(fp);
341c35a8498SKatayama Hirofumi MZ     ok_int(PathFileExistsA(s_sys_bat_file), TRUE);
342c35a8498SKatayama Hirofumi MZ 
343c35a8498SKatayama Hirofumi MZ     // s_win_txt_file
344c35a8498SKatayama Hirofumi MZ     GetWindowsDirectoryA(s_win_txt_file, _countof(s_win_txt_file));
345c35a8498SKatayama Hirofumi MZ     PathAppendA(s_win_txt_file, "test_file.txt");
346c35a8498SKatayama Hirofumi MZ     fp = fopen(s_win_txt_file, "wb");
347c35a8498SKatayama Hirofumi MZ     fclose(fp);
348c35a8498SKatayama Hirofumi MZ     ok_int(PathFileExistsA(s_win_txt_file), TRUE);
349c35a8498SKatayama Hirofumi MZ 
350c35a8498SKatayama Hirofumi MZ     // s_sys_txt_file
351c35a8498SKatayama Hirofumi MZ     GetSystemDirectoryA(s_sys_txt_file, _countof(s_sys_txt_file));
352c35a8498SKatayama Hirofumi MZ     PathAppendA(s_sys_txt_file, "test_file.txt");
353c35a8498SKatayama Hirofumi MZ     fp = fopen(s_sys_txt_file, "wb");
354c35a8498SKatayama Hirofumi MZ     fclose(fp);
355c35a8498SKatayama Hirofumi MZ     ok_int(PathFileExistsA(s_sys_txt_file), TRUE);
356c35a8498SKatayama Hirofumi MZ 
357c35a8498SKatayama Hirofumi MZ     for (UINT iTest = 0; iTest < _countof(s_entries_1); ++iTest)
358c35a8498SKatayama Hirofumi MZ     {
359c35a8498SKatayama Hirofumi MZ         DoTestEntry(&s_entries_1[iTest]);
360c35a8498SKatayama Hirofumi MZ     }
361c35a8498SKatayama Hirofumi MZ 
362c35a8498SKatayama Hirofumi MZ     DeleteFileA(s_win_bat_file);
363c35a8498SKatayama Hirofumi MZ     DeleteFileA(s_sys_bat_file);
364c35a8498SKatayama Hirofumi MZ 
365c35a8498SKatayama Hirofumi MZ     for (UINT iTest = 0; iTest < _countof(s_entries_2); ++iTest)
366c35a8498SKatayama Hirofumi MZ     {
367c35a8498SKatayama Hirofumi MZ         DoTestEntry(&s_entries_2[iTest]);
368c35a8498SKatayama Hirofumi MZ     }
369c35a8498SKatayama Hirofumi MZ 
370c35a8498SKatayama Hirofumi MZ     DeleteFileA(s_win_test_exe);
371c35a8498SKatayama Hirofumi MZ     DeleteFileA(s_sys_test_exe);
372c35a8498SKatayama Hirofumi MZ     DeleteFileA(s_win_txt_file);
373c35a8498SKatayama Hirofumi MZ     DeleteFileA(s_sys_txt_file);
374c35a8498SKatayama Hirofumi MZ 
375c35a8498SKatayama Hirofumi MZ     free(s_wi0.phwnd);
376c35a8498SKatayama Hirofumi MZ }
377c35a8498SKatayama Hirofumi MZ 
378f80de47cSMark Jansen WCHAR* ExeName = NULL;
379f80de47cSMark Jansen 
380f80de47cSMark Jansen BOOL CALLBACK EnumProc(_In_ HWND hwnd, _In_ LPARAM lParam)
381f80de47cSMark Jansen {
382f80de47cSMark Jansen     DWORD pid = 0;
383f80de47cSMark Jansen     GetWindowThreadProcessId(hwnd, &pid);
384f80de47cSMark Jansen     if (pid == GetCurrentProcessId() &&
385f80de47cSMark Jansen         IsWindowVisible(hwnd))
386f80de47cSMark Jansen     {
387f80de47cSMark Jansen         WCHAR Buffer[512] = {0};
388f80de47cSMark Jansen 
389f80de47cSMark Jansen         GetWindowTextW(hwnd, Buffer, _countof(Buffer) - 1);
390f80de47cSMark Jansen         if (Buffer[0] && StrStrIW(Buffer, ExeName))
391f80de47cSMark Jansen         {
392f80de47cSMark Jansen             HWND* pHwnd = (HWND*)lParam;
393f80de47cSMark Jansen             *pHwnd = hwnd;
394f80de47cSMark Jansen             return FALSE;
395f80de47cSMark Jansen         }
396f80de47cSMark Jansen     }
397f80de47cSMark Jansen     return TRUE;
398f80de47cSMark Jansen }
399f80de47cSMark Jansen 
400f80de47cSMark Jansen BOOL WaitAndCloseWindow()
401f80de47cSMark Jansen {
402f80de47cSMark Jansen     HWND hWnd = NULL;
403f80de47cSMark Jansen     for (int n = 0; n < 100; ++n)
404f80de47cSMark Jansen     {
405f80de47cSMark Jansen         Sleep(50);
406f80de47cSMark Jansen 
407f80de47cSMark Jansen         EnumWindows(EnumProc, (LPARAM)&hWnd);
408f80de47cSMark Jansen 
409f80de47cSMark Jansen         if (hWnd)
410f80de47cSMark Jansen         {
411f80de47cSMark Jansen             SendMessageW(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0);
412f80de47cSMark Jansen             return TRUE;
413f80de47cSMark Jansen             break;
414f80de47cSMark Jansen         }
415f80de47cSMark Jansen     }
416f80de47cSMark Jansen     return FALSE;
417f80de47cSMark Jansen }
418f80de47cSMark Jansen 
419f80de47cSMark Jansen static void test_properties()
420f80de47cSMark Jansen {
421f80de47cSMark Jansen     WCHAR Buffer[MAX_PATH * 4];
422f80de47cSMark Jansen 
423f80de47cSMark Jansen     CoInitialize(NULL);
424f80de47cSMark Jansen 
425f80de47cSMark Jansen     GetModuleFileNameW(NULL, Buffer, _countof(Buffer));
426f80de47cSMark Jansen     SHELLEXECUTEINFOW info = { 0 };
427f80de47cSMark Jansen 
428f80de47cSMark Jansen     info.cbSize = sizeof(SHELLEXECUTEINFOW);
429f80de47cSMark Jansen     info.fMask = SEE_MASK_INVOKEIDLIST | SEE_MASK_FLAG_NO_UI;
430f80de47cSMark Jansen     info.lpVerb = L"properties";
431f80de47cSMark Jansen     info.lpFile = Buffer;
432f80de47cSMark Jansen     info.lpParameters = L"";
433f80de47cSMark Jansen     info.nShow = SW_SHOW;
434f80de47cSMark Jansen 
435f80de47cSMark Jansen     BOOL bRet = ShellExecuteExW(&info);
436f80de47cSMark Jansen     ok(bRet, "Failed! (GetLastError(): %d)\n", (int)GetLastError());
437f80de47cSMark Jansen     ok_ptr(info.hInstApp, (HINSTANCE)42);
438f80de47cSMark Jansen 
439f80de47cSMark Jansen     ExeName = PathFindFileNameW(Buffer);
440f80de47cSMark Jansen     WCHAR* Extension = PathFindExtensionW(Buffer);
441f80de47cSMark Jansen     if (Extension)
442f80de47cSMark Jansen     {
443f80de47cSMark Jansen         // The inclusion of this depends on the file display settings!
444f80de47cSMark Jansen         *Extension = UNICODE_NULL;
445f80de47cSMark Jansen     }
446f80de47cSMark Jansen 
447f80de47cSMark Jansen     if (bRet)
448f80de47cSMark Jansen     {
449f80de47cSMark Jansen         ok(WaitAndCloseWindow(), "Could not find properties window!\n");
450f80de47cSMark Jansen     }
451f80de47cSMark Jansen 
452f80de47cSMark Jansen     // Now retry it with the extension cut off
453f80de47cSMark Jansen     bRet = ShellExecuteExW(&info);
454f80de47cSMark Jansen     ok(bRet, "Failed! (GetLastError(): %d)\n", (int)GetLastError());
455f80de47cSMark Jansen     ok_ptr(info.hInstApp, (HINSTANCE)42);
456f80de47cSMark Jansen 
457f80de47cSMark Jansen     if (bRet)
458f80de47cSMark Jansen     {
459f80de47cSMark Jansen         ok(WaitAndCloseWindow(), "Could not find properties window!\n");
460f80de47cSMark Jansen     }
461f80de47cSMark Jansen 
462f80de47cSMark Jansen     info.lpFile = L"complete garbage, cannot run this!";
463f80de47cSMark Jansen 
464f80de47cSMark Jansen     // Now retry it with complete garabage
465f80de47cSMark Jansen     bRet = ShellExecuteExW(&info);
466f80de47cSMark Jansen     ok(bRet == 0, "Succeeded!\n");
467f80de47cSMark Jansen     ok_ptr(info.hInstApp, (HINSTANCE)2);
468f80de47cSMark Jansen }
469f80de47cSMark Jansen 
470*1b3eed58SDoug Lyons static void test_sei_lpIDList()
471*1b3eed58SDoug Lyons {
472*1b3eed58SDoug Lyons     /* This tests ShellExecuteEx with lpIDList for explorer C:\ */
473*1b3eed58SDoug Lyons 
474*1b3eed58SDoug Lyons     /* ITEMIDLIST for CLSID of 'My Computer' followed by PIDL for 'C:\' */
475*1b3eed58SDoug Lyons     BYTE lpitemidlist[30] = { 0x14, 0, 0x1f, 0, 0xe0, 0x4f, 0xd0, 0x20, 0xea,
476*1b3eed58SDoug Lyons     0x3a, 0x69, 0x10, 0xa2, 0xd8, 0x08, 0, 0x2b, 0x30, 0x30, 0x9d, // My Computer
477*1b3eed58SDoug Lyons     0x8, 0, 0x23, 0x43, 0x3a, 0x5c, 0x5c, 0, 0, 0,}; // C:\\ + NUL-NUL ending
478*1b3eed58SDoug Lyons     BYTE *lpBytes;
479*1b3eed58SDoug Lyons     lpBytes = lpitemidlist;
480*1b3eed58SDoug Lyons 
481*1b3eed58SDoug Lyons     SHELLEXECUTEINFOW ShellExecInfo;
482*1b3eed58SDoug Lyons     BOOL Result;
483*1b3eed58SDoug Lyons     STARTUPINFOW si;
484*1b3eed58SDoug Lyons     PROCESS_INFORMATION pi;
485*1b3eed58SDoug Lyons     HWND hWnd;
486*1b3eed58SDoug Lyons 
487*1b3eed58SDoug Lyons     ZeroMemory( &si, sizeof(si) );
488*1b3eed58SDoug Lyons     si.cb = sizeof(si);
489*1b3eed58SDoug Lyons     ZeroMemory( &pi, sizeof(pi) );
490*1b3eed58SDoug Lyons 
491*1b3eed58SDoug Lyons     ZeroMemory(&ShellExecInfo, sizeof(ShellExecInfo));
492*1b3eed58SDoug Lyons     ShellExecInfo.cbSize = sizeof(ShellExecInfo);
493*1b3eed58SDoug Lyons     ShellExecInfo.fMask = SEE_MASK_IDLIST;
494*1b3eed58SDoug Lyons     ShellExecInfo.hwnd = NULL;
495*1b3eed58SDoug Lyons     ShellExecInfo.nShow = SW_SHOWNORMAL;
496*1b3eed58SDoug Lyons     ShellExecInfo.lpFile = NULL;
497*1b3eed58SDoug Lyons     ShellExecInfo.lpDirectory = NULL;
498*1b3eed58SDoug Lyons     ShellExecInfo.lpIDList = lpBytes;
499*1b3eed58SDoug Lyons 
500*1b3eed58SDoug Lyons     Result = ShellExecuteExW(&ShellExecInfo);
501*1b3eed58SDoug Lyons     ok(Result == TRUE, "ShellExecuteEx lpIDList 'C:\\' failed\n");
502*1b3eed58SDoug Lyons     trace("sei_lpIDList returned: %s\n", Result ? "SUCCESS" : "FAILURE");
503*1b3eed58SDoug Lyons     if (Result)
504*1b3eed58SDoug Lyons     {
505*1b3eed58SDoug Lyons         Sleep(700);
506*1b3eed58SDoug Lyons         // Terminate Window
507*1b3eed58SDoug Lyons         hWnd = FindWindowW(L"CabinetWClass", L"Local Disk (C:)");
508*1b3eed58SDoug Lyons         PostMessage(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0);
509*1b3eed58SDoug Lyons     }
510*1b3eed58SDoug Lyons }
511*1b3eed58SDoug Lyons 
512c35a8498SKatayama Hirofumi MZ START_TEST(ShellExecuteEx)
513c35a8498SKatayama Hirofumi MZ {
514c35a8498SKatayama Hirofumi MZ     DoAppPathTest();
515c35a8498SKatayama Hirofumi MZ     DoTestEntries();
516f80de47cSMark Jansen     test_properties();
51760b89da3SKatayama Hirofumi MZ 
51860b89da3SKatayama Hirofumi MZ     DoWaitForWindow(CLASSNAME, CLASSNAME, TRUE, TRUE);
51960b89da3SKatayama Hirofumi MZ     Sleep(100);
520*1b3eed58SDoug Lyons 
521*1b3eed58SDoug Lyons     test_sei_lpIDList();
522*1b3eed58SDoug Lyons 
523c35a8498SKatayama Hirofumi MZ }
524