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"
10*436cfa94SKatayama Hirofumi MZ #include "closewnd.h"
11ab4c0d6aSKatayama Hirofumi MZ #include <pstypes.h>
12ab4c0d6aSKatayama Hirofumi MZ #include <psfuncs.h>
13ab4c0d6aSKatayama Hirofumi MZ #include <stdlib.h>
14c35a8498SKatayama Hirofumi MZ #include <stdio.h>
15ab4c0d6aSKatayama Hirofumi MZ #include <strsafe.h>
16ab4c0d6aSKatayama Hirofumi MZ #include <versionhelpers.h>
17c2c66affSColin Finck 
18ab4c0d6aSKatayama Hirofumi MZ static WCHAR s_win_dir[MAX_PATH];
19ab4c0d6aSKatayama Hirofumi MZ static WCHAR s_sys_dir[MAX_PATH];
20ab4c0d6aSKatayama Hirofumi MZ static WCHAR s_win_notepad[MAX_PATH];
21ab4c0d6aSKatayama Hirofumi MZ static WCHAR s_sys_notepad[MAX_PATH];
22ab4c0d6aSKatayama Hirofumi MZ static WCHAR s_win_test_exe[MAX_PATH];
23ab4c0d6aSKatayama Hirofumi MZ static WCHAR s_sys_test_exe[MAX_PATH];
24ab4c0d6aSKatayama Hirofumi MZ static WCHAR s_win_bat_file[MAX_PATH];
25ab4c0d6aSKatayama Hirofumi MZ static WCHAR s_sys_bat_file[MAX_PATH];
26ab4c0d6aSKatayama Hirofumi MZ static WCHAR s_win_txt_file[MAX_PATH];
27ab4c0d6aSKatayama Hirofumi MZ static WCHAR s_sys_txt_file[MAX_PATH];
28ab4c0d6aSKatayama Hirofumi MZ static WCHAR s_win_notepad_cmdline[MAX_PATH];
29ab4c0d6aSKatayama Hirofumi MZ static WCHAR s_sys_notepad_cmdline[MAX_PATH];
30ab4c0d6aSKatayama Hirofumi MZ static WCHAR s_win_test_exe_cmdline[MAX_PATH];
31ab4c0d6aSKatayama Hirofumi MZ static WCHAR s_sys_test_exe_cmdline[MAX_PATH];
32ab4c0d6aSKatayama Hirofumi MZ static BOOL s_bWow64;
33c2c66affSColin Finck 
34ab4c0d6aSKatayama Hirofumi MZ #define REG_APPPATHS L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\"
35ab4c0d6aSKatayama Hirofumi MZ 
36ab4c0d6aSKatayama Hirofumi MZ typedef enum TEST_RESULT
37c2c66affSColin Finck {
38ab4c0d6aSKatayama Hirofumi MZ     TEST_FAILED,
39ab4c0d6aSKatayama Hirofumi MZ     TEST_SUCCESS_NO_PROCESS,
40ab4c0d6aSKatayama Hirofumi MZ     TEST_SUCCESS_WITH_PROCESS,
41ab4c0d6aSKatayama Hirofumi MZ } TEST_RESULT;
42c35a8498SKatayama Hirofumi MZ 
43c35a8498SKatayama Hirofumi MZ typedef struct TEST_ENTRY
44c35a8498SKatayama Hirofumi MZ {
45ab4c0d6aSKatayama Hirofumi MZ     INT line;
46ab4c0d6aSKatayama Hirofumi MZ     TEST_RESULT result;
47ab4c0d6aSKatayama Hirofumi MZ     LPCWSTR lpFile;
48ab4c0d6aSKatayama Hirofumi MZ     LPCWSTR cmdline;
49ab4c0d6aSKatayama Hirofumi MZ } TEST_ENTRY, *PTEST_ENTRY;
50c35a8498SKatayama Hirofumi MZ 
51ab4c0d6aSKatayama Hirofumi MZ static void
52ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(INT line, TEST_RESULT result, LPCWSTR lpFile, LPCWSTR cmdline = NULL);
53c35a8498SKatayama Hirofumi MZ 
54ab4c0d6aSKatayama Hirofumi MZ static void TEST_DoTestEntries(void)
55c35a8498SKatayama Hirofumi MZ {
56ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, NULL);
57ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"");
58ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_FAILED, L"This is an invalid path.");
59ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, s_sys_bat_file, NULL);
60ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, s_sys_test_exe, s_sys_test_exe_cmdline);
61ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, s_sys_txt_file, NULL);
62ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, s_win_bat_file, NULL);
63ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, s_win_notepad, s_win_notepad_cmdline);
64ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, s_win_test_exe, s_win_test_exe_cmdline);
65ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, s_win_txt_file, NULL);
66ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, L"notepad", s_sys_notepad_cmdline);
67ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, L"notepad.exe", s_sys_notepad_cmdline);
68ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, L"\"notepad.exe\"", s_sys_notepad_cmdline);
69ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, L"\"notepad\"", s_sys_notepad_cmdline);
70ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, L"test program.exe", s_sys_test_exe_cmdline);
71ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, L"\"test program.exe\"", s_sys_test_exe_cmdline);
72ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, s_win_dir);
73ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, s_sys_dir);
74ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_FAILED, L"shell:ThisIsAnInvalidName");
75ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}"); // My Computer
76ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:::{20D04FE0-3AEA-1069-A2D8-08002B30309D}"); // My Computer (with shell:)
77c35a8498SKatayama Hirofumi MZ 
78ab4c0d6aSKatayama Hirofumi MZ     if (!IsWindowsVistaOrGreater())
79c35a8498SKatayama Hirofumi MZ     {
80ab4c0d6aSKatayama Hirofumi MZ         WCHAR szCurDir[MAX_PATH];
81ab4c0d6aSKatayama Hirofumi MZ         GetCurrentDirectoryW(_countof(szCurDir), szCurDir);
82ab4c0d6aSKatayama Hirofumi MZ         SetCurrentDirectoryW(s_sys_dir);
83ab4c0d6aSKatayama Hirofumi MZ         TEST_DoTestEntry(__LINE__, TEST_FAILED, L"::{21EC2020-3AEA-1069-A2DD-08002B30309D}"); // Control Panel (without path)
84ab4c0d6aSKatayama Hirofumi MZ         SetCurrentDirectoryW(szCurDir);
85c35a8498SKatayama Hirofumi MZ     }
86c35a8498SKatayama Hirofumi MZ 
87ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}"); // Control Panel (with path)
88ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}"); // Control Panel (with path and shell:)
89ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:AppData");
90ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Common Desktop");
91ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Common Programs");
92ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Common Start Menu");
93ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Common StartUp");
94ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:ControlPanelFolder");
95ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Desktop");
96ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Favorites");
97ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Fonts");
98ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Local AppData");
99ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:My Pictures");
100ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Personal");
101ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Programs");
102ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Recent");
103ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:RecycleBinFolder");
104ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:SendTo");
105ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Start Menu");
106ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:StartUp");
107307ce1a5SHermès Bélusca-Maïto }
108307ce1a5SHermès Bélusca-Maïto 
109ab4c0d6aSKatayama Hirofumi MZ static LPWSTR
110ab4c0d6aSKatayama Hirofumi MZ getCommandLineFromProcess(HANDLE hProcess)
111c35a8498SKatayama Hirofumi MZ {
112ab4c0d6aSKatayama Hirofumi MZ     PEB peb;
113ab4c0d6aSKatayama Hirofumi MZ     PROCESS_BASIC_INFORMATION info;
114ab4c0d6aSKatayama Hirofumi MZ     RTL_USER_PROCESS_PARAMETERS Params;
1154854a1d7SKatayama Hirofumi MZ     NTSTATUS Status;
1164854a1d7SKatayama Hirofumi MZ     BOOL ret;
117ab4c0d6aSKatayama Hirofumi MZ 
1184854a1d7SKatayama Hirofumi MZ     Status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &info, sizeof(info), NULL);
1194854a1d7SKatayama Hirofumi MZ     ok_ntstatus(Status, STATUS_SUCCESS);
1204854a1d7SKatayama Hirofumi MZ 
1214854a1d7SKatayama Hirofumi MZ     ret = ReadProcessMemory(hProcess, info.PebBaseAddress, &peb, sizeof(peb), NULL);
1224854a1d7SKatayama Hirofumi MZ     if (!ret)
1234854a1d7SKatayama Hirofumi MZ         trace("ReadProcessMemory failed (%ld)\n", GetLastError());
1244854a1d7SKatayama Hirofumi MZ 
125ab4c0d6aSKatayama Hirofumi MZ     ReadProcessMemory(hProcess, peb.ProcessParameters, &Params, sizeof(Params), NULL);
1264854a1d7SKatayama Hirofumi MZ     if (!ret)
1274854a1d7SKatayama Hirofumi MZ         trace("ReadProcessMemory failed (%ld)\n", GetLastError());
128ab4c0d6aSKatayama Hirofumi MZ 
129ab4c0d6aSKatayama Hirofumi MZ     LPWSTR cmdline = Params.CommandLine.Buffer;
1304854a1d7SKatayama Hirofumi MZ     if (!cmdline)
1314854a1d7SKatayama Hirofumi MZ         trace("!cmdline\n");
1324854a1d7SKatayama Hirofumi MZ 
1334854a1d7SKatayama Hirofumi MZ     SIZE_T cbCmdLine = Params.CommandLine.Length;
1344854a1d7SKatayama Hirofumi MZ     if (!cbCmdLine)
1354854a1d7SKatayama Hirofumi MZ         trace("!cbCmdLine\n");
1364854a1d7SKatayama Hirofumi MZ 
1374854a1d7SKatayama Hirofumi MZ     LPWSTR pszBuffer = (LPWSTR)calloc(cbCmdLine + sizeof(WCHAR), 1);
1384854a1d7SKatayama Hirofumi MZ     if (!pszBuffer)
1394854a1d7SKatayama Hirofumi MZ         trace("!pszBuffer\n");
1404854a1d7SKatayama Hirofumi MZ 
1414854a1d7SKatayama Hirofumi MZ     ret = ReadProcessMemory(hProcess, cmdline, pszBuffer, cbCmdLine, NULL);
1424854a1d7SKatayama Hirofumi MZ     if (!ret)
1434854a1d7SKatayama Hirofumi MZ         trace("ReadProcessMemory failed (%ld)\n", GetLastError());
1444854a1d7SKatayama Hirofumi MZ 
1454854a1d7SKatayama Hirofumi MZ     pszBuffer[cbCmdLine / sizeof(WCHAR)] = UNICODE_NULL;
146ab4c0d6aSKatayama Hirofumi MZ 
147ab4c0d6aSKatayama Hirofumi MZ     return pszBuffer; // needs free()
148ab4c0d6aSKatayama Hirofumi MZ }
149ab4c0d6aSKatayama Hirofumi MZ 
150ab4c0d6aSKatayama Hirofumi MZ static void TEST_DoTestEntryStruct(const TEST_ENTRY *pEntry)
151ab4c0d6aSKatayama Hirofumi MZ {
152ab4c0d6aSKatayama Hirofumi MZ     SHELLEXECUTEINFOW info = { sizeof(info) };
153*436cfa94SKatayama Hirofumi MZ     info.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_WAITFORINPUTIDLE |
154*436cfa94SKatayama Hirofumi MZ                  SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC;
155ab4c0d6aSKatayama Hirofumi MZ     info.hwnd = NULL;
156ab4c0d6aSKatayama Hirofumi MZ     info.lpVerb = NULL;
157ab4c0d6aSKatayama Hirofumi MZ     info.lpFile = pEntry->lpFile;
158c35a8498SKatayama Hirofumi MZ     info.nShow = SW_SHOWNORMAL;
159c35a8498SKatayama Hirofumi MZ 
160ab4c0d6aSKatayama Hirofumi MZ     BOOL ret = ShellExecuteExW(&info);
161ab4c0d6aSKatayama Hirofumi MZ 
162ab4c0d6aSKatayama Hirofumi MZ     TEST_RESULT result;
163ab4c0d6aSKatayama Hirofumi MZ     if (ret && info.hProcess)
164ab4c0d6aSKatayama Hirofumi MZ         result = TEST_SUCCESS_WITH_PROCESS;
165ab4c0d6aSKatayama Hirofumi MZ     else if (ret && !info.hProcess)
166ab4c0d6aSKatayama Hirofumi MZ         result = TEST_SUCCESS_NO_PROCESS;
167ab4c0d6aSKatayama Hirofumi MZ     else
168ab4c0d6aSKatayama Hirofumi MZ         result = TEST_FAILED;
169ab4c0d6aSKatayama Hirofumi MZ 
170ab4c0d6aSKatayama Hirofumi MZ     ok(pEntry->result == result,
171ab4c0d6aSKatayama Hirofumi MZ        "Line %d: result: %d vs %d\n", pEntry->line, pEntry->result, result);
172ab4c0d6aSKatayama Hirofumi MZ 
173ab4c0d6aSKatayama Hirofumi MZ     if (pEntry->result == TEST_SUCCESS_WITH_PROCESS && pEntry->cmdline && !s_bWow64)
174c35a8498SKatayama Hirofumi MZ     {
175ab4c0d6aSKatayama Hirofumi MZ         LPWSTR cmdline = getCommandLineFromProcess(info.hProcess);
176ab4c0d6aSKatayama Hirofumi MZ         if (!cmdline)
177c35a8498SKatayama Hirofumi MZ         {
178ab4c0d6aSKatayama Hirofumi MZ             skip("!cmdline\n");
179c35a8498SKatayama Hirofumi MZ         }
180c35a8498SKatayama Hirofumi MZ         else
181c35a8498SKatayama Hirofumi MZ         {
182ab4c0d6aSKatayama Hirofumi MZ             ok(lstrcmpiW(pEntry->cmdline, cmdline) == 0,
183ab4c0d6aSKatayama Hirofumi MZ                "Line %d: cmdline: '%ls' vs '%ls'\n", pEntry->line,
184ab4c0d6aSKatayama Hirofumi MZ                pEntry->cmdline, cmdline);
185c35a8498SKatayama Hirofumi MZ         }
186c35a8498SKatayama Hirofumi MZ 
187ab4c0d6aSKatayama Hirofumi MZ         TerminateProcess(info.hProcess, 0xDEADFACE);
188ab4c0d6aSKatayama Hirofumi MZ         free(cmdline);
189f80de47cSMark Jansen     }
190ab4c0d6aSKatayama Hirofumi MZ 
191c35a8498SKatayama Hirofumi MZ     CloseHandle(info.hProcess);
192c35a8498SKatayama Hirofumi MZ }
193c35a8498SKatayama Hirofumi MZ 
194ab4c0d6aSKatayama Hirofumi MZ static void
195ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(INT line, TEST_RESULT result, LPCWSTR lpFile, LPCWSTR cmdline)
196ab4c0d6aSKatayama Hirofumi MZ {
197ab4c0d6aSKatayama Hirofumi MZ     TEST_ENTRY entry = { line, result, lpFile, cmdline };
198ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntryStruct(&entry);
199ab4c0d6aSKatayama Hirofumi MZ }
200ab4c0d6aSKatayama Hirofumi MZ 
201c35a8498SKatayama Hirofumi MZ static BOOL
202ab4c0d6aSKatayama Hirofumi MZ enableTokenPrivilege(LPCWSTR pszPrivilege)
203c35a8498SKatayama Hirofumi MZ {
204ab4c0d6aSKatayama Hirofumi MZ     HANDLE hToken;
205ab4c0d6aSKatayama Hirofumi MZ     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
206c35a8498SKatayama Hirofumi MZ         return FALSE;
207ab4c0d6aSKatayama Hirofumi MZ 
208ab4c0d6aSKatayama Hirofumi MZ     TOKEN_PRIVILEGES tkp = { 0 };
209ab4c0d6aSKatayama Hirofumi MZ     if (!LookupPrivilegeValueW(NULL, pszPrivilege, &tkp.Privileges[0].Luid))
210ab4c0d6aSKatayama Hirofumi MZ         return FALSE;
211ab4c0d6aSKatayama Hirofumi MZ 
212ab4c0d6aSKatayama Hirofumi MZ     tkp.PrivilegeCount = 1;
213ab4c0d6aSKatayama Hirofumi MZ     tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
214ab4c0d6aSKatayama Hirofumi MZ     return AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, NULL, NULL);
215c35a8498SKatayama Hirofumi MZ }
216c35a8498SKatayama Hirofumi MZ 
217ab4c0d6aSKatayama Hirofumi MZ static WINDOW_LIST s_List1, s_List2;
218ab4c0d6aSKatayama Hirofumi MZ 
219ab4c0d6aSKatayama Hirofumi MZ static BOOL TEST_Start(void)
220ab4c0d6aSKatayama Hirofumi MZ {
221ab4c0d6aSKatayama Hirofumi MZ     // Check Wow64
222ab4c0d6aSKatayama Hirofumi MZ     s_bWow64 = FALSE;
223ab4c0d6aSKatayama Hirofumi MZ     IsWow64Process(GetCurrentProcess(), &s_bWow64);
224ab4c0d6aSKatayama Hirofumi MZ     if (s_bWow64)
225ab4c0d6aSKatayama Hirofumi MZ         skip("Wow64: Command Line check is skipped\n");
226ab4c0d6aSKatayama Hirofumi MZ 
227ab4c0d6aSKatayama Hirofumi MZ     // getCommandLineFromProcess needs this
228ab4c0d6aSKatayama Hirofumi MZ     enableTokenPrivilege(SE_DEBUG_NAME);
229ab4c0d6aSKatayama Hirofumi MZ 
230ab4c0d6aSKatayama Hirofumi MZ     // s_win_dir
231ab4c0d6aSKatayama Hirofumi MZ     GetWindowsDirectoryW(s_win_dir, _countof(s_win_dir));
232ab4c0d6aSKatayama Hirofumi MZ 
233ab4c0d6aSKatayama Hirofumi MZ     // s_sys_dir
234ab4c0d6aSKatayama Hirofumi MZ     GetSystemDirectoryW(s_sys_dir, _countof(s_sys_dir));
235ab4c0d6aSKatayama Hirofumi MZ 
236ab4c0d6aSKatayama Hirofumi MZ     // s_win_notepad
237ab4c0d6aSKatayama Hirofumi MZ     GetWindowsDirectoryW(s_win_notepad, _countof(s_win_notepad));
238ab4c0d6aSKatayama Hirofumi MZ     PathAppendW(s_win_notepad, L"notepad.exe");
239ab4c0d6aSKatayama Hirofumi MZ 
240ab4c0d6aSKatayama Hirofumi MZ     // s_sys_notepad
241ab4c0d6aSKatayama Hirofumi MZ     GetSystemDirectoryW(s_sys_notepad, _countof(s_sys_notepad));
242ab4c0d6aSKatayama Hirofumi MZ     PathAppendW(s_sys_notepad, L"notepad.exe");
243ab4c0d6aSKatayama Hirofumi MZ 
244c35a8498SKatayama Hirofumi MZ     // s_win_test_exe
245ab4c0d6aSKatayama Hirofumi MZ     GetWindowsDirectoryW(s_win_test_exe, _countof(s_win_test_exe));
246ab4c0d6aSKatayama Hirofumi MZ     PathAppendW(s_win_test_exe, L"test program.exe");
247ab4c0d6aSKatayama Hirofumi MZ     BOOL ret = CopyFileW(s_win_notepad, s_win_test_exe, FALSE);
248c35a8498SKatayama Hirofumi MZ     if (!ret)
249c35a8498SKatayama Hirofumi MZ     {
250c35a8498SKatayama Hirofumi MZ         skip("Please retry with admin rights\n");
251ab4c0d6aSKatayama Hirofumi MZ         return FALSE;
252c35a8498SKatayama Hirofumi MZ     }
253c35a8498SKatayama Hirofumi MZ 
254c35a8498SKatayama Hirofumi MZ     // s_sys_test_exe
255ab4c0d6aSKatayama Hirofumi MZ     GetSystemDirectoryW(s_sys_test_exe, _countof(s_sys_test_exe));
256ab4c0d6aSKatayama Hirofumi MZ     PathAppendW(s_sys_test_exe, L"test program.exe");
257ab4c0d6aSKatayama Hirofumi MZ     ok_int(CopyFileW(s_win_notepad, s_sys_test_exe, FALSE), TRUE);
258c35a8498SKatayama Hirofumi MZ 
259c35a8498SKatayama Hirofumi MZ     // s_win_bat_file
260ab4c0d6aSKatayama Hirofumi MZ     GetWindowsDirectoryW(s_win_bat_file, _countof(s_win_bat_file));
261ab4c0d6aSKatayama Hirofumi MZ     PathAppendW(s_win_bat_file, L"test program.bat");
262ab4c0d6aSKatayama Hirofumi MZ     FILE *fp = _wfopen(s_win_bat_file, L"wb");
263c35a8498SKatayama Hirofumi MZ     fprintf(fp, "exit /b 3");
264c35a8498SKatayama Hirofumi MZ     fclose(fp);
265ab4c0d6aSKatayama Hirofumi MZ     ok_int(PathFileExistsW(s_win_bat_file), TRUE);
266c35a8498SKatayama Hirofumi MZ 
267c35a8498SKatayama Hirofumi MZ     // s_sys_bat_file
268ab4c0d6aSKatayama Hirofumi MZ     GetSystemDirectoryW(s_sys_bat_file, _countof(s_sys_bat_file));
269ab4c0d6aSKatayama Hirofumi MZ     PathAppendW(s_sys_bat_file, L"test program.bat");
270ab4c0d6aSKatayama Hirofumi MZ     fp = _wfopen(s_sys_bat_file, L"wb");
271c35a8498SKatayama Hirofumi MZ     fprintf(fp, "exit /b 4");
272c35a8498SKatayama Hirofumi MZ     fclose(fp);
273ab4c0d6aSKatayama Hirofumi MZ     ok_int(PathFileExistsW(s_sys_bat_file), TRUE);
274c35a8498SKatayama Hirofumi MZ 
275c35a8498SKatayama Hirofumi MZ     // s_win_txt_file
276ab4c0d6aSKatayama Hirofumi MZ     GetWindowsDirectoryW(s_win_txt_file, _countof(s_win_txt_file));
277ab4c0d6aSKatayama Hirofumi MZ     PathAppendW(s_win_txt_file, L"test_file.txt");
278ab4c0d6aSKatayama Hirofumi MZ     fp = _wfopen(s_win_txt_file, L"wb");
279c35a8498SKatayama Hirofumi MZ     fclose(fp);
280ab4c0d6aSKatayama Hirofumi MZ     ok_int(PathFileExistsW(s_win_txt_file), TRUE);
281c35a8498SKatayama Hirofumi MZ 
282c35a8498SKatayama Hirofumi MZ     // s_sys_txt_file
283ab4c0d6aSKatayama Hirofumi MZ     GetSystemDirectoryW(s_sys_txt_file, _countof(s_sys_txt_file));
284ab4c0d6aSKatayama Hirofumi MZ     PathAppendW(s_sys_txt_file, L"test_file.txt");
285ab4c0d6aSKatayama Hirofumi MZ     fp = _wfopen(s_sys_txt_file, L"wb");
286c35a8498SKatayama Hirofumi MZ     fclose(fp);
287ab4c0d6aSKatayama Hirofumi MZ     ok_int(PathFileExistsW(s_sys_txt_file), TRUE);
288c35a8498SKatayama Hirofumi MZ 
289ab4c0d6aSKatayama Hirofumi MZ     // Check .txt settings
290ab4c0d6aSKatayama Hirofumi MZ     WCHAR szPath[MAX_PATH];
291ab4c0d6aSKatayama Hirofumi MZ     FindExecutableW(s_sys_txt_file, NULL, szPath);
292ab4c0d6aSKatayama Hirofumi MZ     if (lstrcmpiW(PathFindFileNameW(szPath), L"notepad.exe") != 0)
293c35a8498SKatayama Hirofumi MZ     {
294ab4c0d6aSKatayama Hirofumi MZ         skip("Please associate .txt with notepad.exe before tests\n");
295f80de47cSMark Jansen         return FALSE;
296f80de47cSMark Jansen     }
297ab4c0d6aSKatayama Hirofumi MZ 
298ab4c0d6aSKatayama Hirofumi MZ     // command lines
299ab4c0d6aSKatayama Hirofumi MZ     StringCchPrintfW(s_win_notepad_cmdline, _countof(s_win_notepad_cmdline),
300ab4c0d6aSKatayama Hirofumi MZ                      L"\"%s\" ", s_win_notepad);
301ab4c0d6aSKatayama Hirofumi MZ     StringCchPrintfW(s_sys_notepad_cmdline, _countof(s_sys_notepad_cmdline),
302ab4c0d6aSKatayama Hirofumi MZ                      L"\"%s\" ", s_sys_notepad);
303ab4c0d6aSKatayama Hirofumi MZ     StringCchPrintfW(s_win_test_exe_cmdline, _countof(s_win_test_exe_cmdline),
304ab4c0d6aSKatayama Hirofumi MZ                      L"\"%s\" ", s_win_test_exe);
305ab4c0d6aSKatayama Hirofumi MZ     StringCchPrintfW(s_sys_test_exe_cmdline, _countof(s_sys_test_exe_cmdline),
306ab4c0d6aSKatayama Hirofumi MZ                      L"\"%s\" ", s_sys_test_exe);
307ab4c0d6aSKatayama Hirofumi MZ 
308*436cfa94SKatayama Hirofumi MZ     GetWindowList(&s_List1);
309ab4c0d6aSKatayama Hirofumi MZ 
310f80de47cSMark Jansen     return TRUE;
311f80de47cSMark Jansen }
312f80de47cSMark Jansen 
313ab4c0d6aSKatayama Hirofumi MZ static void TEST_End(void)
314f80de47cSMark Jansen {
315ab4c0d6aSKatayama Hirofumi MZ     Sleep(500);
316*436cfa94SKatayama Hirofumi MZ     GetWindowList(&s_List2);
317*436cfa94SKatayama Hirofumi MZ     CloseNewWindows(&s_List1, &s_List2);
318*436cfa94SKatayama Hirofumi MZ     FreeWindowList(&s_List1);
319*436cfa94SKatayama Hirofumi MZ     FreeWindowList(&s_List2);
320f80de47cSMark Jansen 
321ab4c0d6aSKatayama Hirofumi MZ     DeleteFileW(s_win_test_exe);
322ab4c0d6aSKatayama Hirofumi MZ     DeleteFileW(s_sys_test_exe);
323ab4c0d6aSKatayama Hirofumi MZ     DeleteFileW(s_win_txt_file);
324ab4c0d6aSKatayama Hirofumi MZ     DeleteFileW(s_sys_txt_file);
325ab4c0d6aSKatayama Hirofumi MZ     DeleteFileW(s_win_bat_file);
326ab4c0d6aSKatayama Hirofumi MZ     DeleteFileW(s_sys_bat_file);
327f80de47cSMark Jansen }
328f80de47cSMark Jansen 
329f80de47cSMark Jansen static void test_properties()
330f80de47cSMark Jansen {
331ab4c0d6aSKatayama Hirofumi MZ     HRESULT hrCoInit = CoInitialize(NULL);
332f80de47cSMark Jansen 
3334854a1d7SKatayama Hirofumi MZ     WCHAR Buffer[MAX_PATH * 4];
334f80de47cSMark Jansen     GetModuleFileNameW(NULL, Buffer, _countof(Buffer));
335f80de47cSMark Jansen 
3364854a1d7SKatayama Hirofumi MZ     SHELLEXECUTEINFOW info = { sizeof(info) };
337f80de47cSMark Jansen     info.fMask = SEE_MASK_INVOKEIDLIST | SEE_MASK_FLAG_NO_UI;
338f80de47cSMark Jansen     info.lpVerb = L"properties";
339f80de47cSMark Jansen     info.lpFile = Buffer;
340f80de47cSMark Jansen     info.nShow = SW_SHOW;
341f80de47cSMark Jansen 
342f80de47cSMark Jansen     BOOL bRet = ShellExecuteExW(&info);
343f80de47cSMark Jansen     ok(bRet, "Failed! (GetLastError(): %d)\n", (int)GetLastError());
344f80de47cSMark Jansen     ok_ptr(info.hInstApp, (HINSTANCE)42);
345f80de47cSMark Jansen 
346f80de47cSMark Jansen     WCHAR* Extension = PathFindExtensionW(Buffer);
347f80de47cSMark Jansen     if (Extension)
348f80de47cSMark Jansen     {
349f80de47cSMark Jansen         // The inclusion of this depends on the file display settings!
350f80de47cSMark Jansen         *Extension = UNICODE_NULL;
351f80de47cSMark Jansen     }
352f80de47cSMark Jansen 
353f80de47cSMark Jansen     // Now retry it with the extension cut off
354f80de47cSMark Jansen     bRet = ShellExecuteExW(&info);
355f80de47cSMark Jansen     ok(bRet, "Failed! (GetLastError(): %d)\n", (int)GetLastError());
356f80de47cSMark Jansen     ok_ptr(info.hInstApp, (HINSTANCE)42);
357f80de47cSMark Jansen 
358f80de47cSMark Jansen     // Now retry it with complete garabage
359ab4c0d6aSKatayama Hirofumi MZ     info.lpFile = L"complete garbage, cannot run this!";
360f80de47cSMark Jansen     bRet = ShellExecuteExW(&info);
361ab4c0d6aSKatayama Hirofumi MZ     ok_int(bRet, 0);
362f80de47cSMark Jansen     ok_ptr(info.hInstApp, (HINSTANCE)2);
363ab4c0d6aSKatayama Hirofumi MZ 
364ab4c0d6aSKatayama Hirofumi MZ     if (SUCCEEDED(hrCoInit))
365ab4c0d6aSKatayama Hirofumi MZ         CoUninitialize();
366f80de47cSMark Jansen }
367f80de47cSMark Jansen 
3681b3eed58SDoug Lyons static void test_sei_lpIDList()
3691b3eed58SDoug Lyons {
370ab4c0d6aSKatayama Hirofumi MZ     if (IsWindowsVistaOrGreater())
371ab4c0d6aSKatayama Hirofumi MZ     {
372ab4c0d6aSKatayama Hirofumi MZ         skip("Vista+\n");
373ab4c0d6aSKatayama Hirofumi MZ         return;
374ab4c0d6aSKatayama Hirofumi MZ     }
375ab4c0d6aSKatayama Hirofumi MZ 
3761b3eed58SDoug Lyons     /* This tests ShellExecuteEx with lpIDList for explorer C:\ */
3771b3eed58SDoug Lyons 
3781b3eed58SDoug Lyons     /* ITEMIDLIST for CLSID of 'My Computer' followed by PIDL for 'C:\' */
3791b3eed58SDoug Lyons     BYTE lpitemidlist[30] = { 0x14, 0, 0x1f, 0, 0xe0, 0x4f, 0xd0, 0x20, 0xea,
3801b3eed58SDoug Lyons     0x3a, 0x69, 0x10, 0xa2, 0xd8, 0x08, 0, 0x2b, 0x30, 0x30, 0x9d, // My Computer
3811b3eed58SDoug Lyons     0x8, 0, 0x23, 0x43, 0x3a, 0x5c, 0x5c, 0, 0, 0,}; // C:\\ + NUL-NUL ending
3821b3eed58SDoug Lyons 
383ab4c0d6aSKatayama Hirofumi MZ     SHELLEXECUTEINFOW ShellExecInfo = { sizeof(ShellExecInfo) };
3841b3eed58SDoug Lyons     ShellExecInfo.fMask = SEE_MASK_IDLIST;
3851b3eed58SDoug Lyons     ShellExecInfo.hwnd = NULL;
3861b3eed58SDoug Lyons     ShellExecInfo.nShow = SW_SHOWNORMAL;
387ab4c0d6aSKatayama Hirofumi MZ     ShellExecInfo.lpIDList = lpitemidlist;
388ab4c0d6aSKatayama Hirofumi MZ     BOOL ret = ShellExecuteExW(&ShellExecInfo);
389ab4c0d6aSKatayama Hirofumi MZ     ok_int(ret, TRUE);
390ab4c0d6aSKatayama Hirofumi MZ }
3911b3eed58SDoug Lyons 
392ab4c0d6aSKatayama Hirofumi MZ static BOOL
393ab4c0d6aSKatayama Hirofumi MZ CreateAppPath(LPCWSTR pszName, LPCWSTR pszValue)
3941b3eed58SDoug Lyons {
395ab4c0d6aSKatayama Hirofumi MZ     WCHAR szSubKey[MAX_PATH];
396ab4c0d6aSKatayama Hirofumi MZ     StringCchPrintfW(szSubKey, _countof(szSubKey), L"%s\\%s", REG_APPPATHS, pszName);
397ab4c0d6aSKatayama Hirofumi MZ 
398ab4c0d6aSKatayama Hirofumi MZ     LSTATUS error;
399ab4c0d6aSKatayama Hirofumi MZ     HKEY hKey;
400ab4c0d6aSKatayama Hirofumi MZ     error = RegCreateKeyExW(HKEY_LOCAL_MACHINE, szSubKey, 0, NULL, 0, KEY_WRITE, NULL,
401ab4c0d6aSKatayama Hirofumi MZ                             &hKey, NULL);
402ab4c0d6aSKatayama Hirofumi MZ     if (error != ERROR_SUCCESS)
403ab4c0d6aSKatayama Hirofumi MZ         trace("Could not create test key (%lu)\n", error);
404ab4c0d6aSKatayama Hirofumi MZ 
405ab4c0d6aSKatayama Hirofumi MZ     DWORD cbValue = (lstrlenW(pszValue) + 1) * sizeof(WCHAR);
406ab4c0d6aSKatayama Hirofumi MZ     error = RegSetValueExW(hKey, NULL, 0, REG_SZ, (LPBYTE)pszValue, cbValue);
407ab4c0d6aSKatayama Hirofumi MZ     if (error != ERROR_SUCCESS)
408ab4c0d6aSKatayama Hirofumi MZ         trace("Could not set value of the test key (%lu)\n", error);
409ab4c0d6aSKatayama Hirofumi MZ 
410ab4c0d6aSKatayama Hirofumi MZ     RegCloseKey(hKey);
411ab4c0d6aSKatayama Hirofumi MZ 
412ab4c0d6aSKatayama Hirofumi MZ     return error == ERROR_SUCCESS;
413ab4c0d6aSKatayama Hirofumi MZ }
414ab4c0d6aSKatayama Hirofumi MZ 
415ab4c0d6aSKatayama Hirofumi MZ static VOID
416ab4c0d6aSKatayama Hirofumi MZ DeleteAppPath(LPCWSTR pszName)
417ab4c0d6aSKatayama Hirofumi MZ {
418ab4c0d6aSKatayama Hirofumi MZ     WCHAR szSubKey[MAX_PATH];
419ab4c0d6aSKatayama Hirofumi MZ     StringCchPrintfW(szSubKey, _countof(szSubKey), L"%s\\%s", REG_APPPATHS, pszName);
420ab4c0d6aSKatayama Hirofumi MZ 
421ab4c0d6aSKatayama Hirofumi MZ     LSTATUS error = RegDeleteKeyW(HKEY_LOCAL_MACHINE, szSubKey);
422ab4c0d6aSKatayama Hirofumi MZ     if (error != ERROR_SUCCESS)
423ab4c0d6aSKatayama Hirofumi MZ         trace("Could not remove the test key (%lu)\n", error);
424ab4c0d6aSKatayama Hirofumi MZ }
425ab4c0d6aSKatayama Hirofumi MZ 
426ab4c0d6aSKatayama Hirofumi MZ static void TEST_AppPath(void)
427ab4c0d6aSKatayama Hirofumi MZ {
428ab4c0d6aSKatayama Hirofumi MZ     if (CreateAppPath(L"app_path_test.bat", s_win_test_exe))
429ab4c0d6aSKatayama Hirofumi MZ     {
430ab4c0d6aSKatayama Hirofumi MZ         TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, L"app_path_test.bat");
431ab4c0d6aSKatayama Hirofumi MZ         TEST_DoTestEntry(__LINE__, TEST_FAILED, L"app_path_test.bat.exe");
432ab4c0d6aSKatayama Hirofumi MZ         DeleteAppPath(L"app_path_test.bat");
433ab4c0d6aSKatayama Hirofumi MZ     }
434ab4c0d6aSKatayama Hirofumi MZ 
435ab4c0d6aSKatayama Hirofumi MZ     if (CreateAppPath(L"app_path_test.bat.exe", s_sys_test_exe))
436ab4c0d6aSKatayama Hirofumi MZ     {
437ab4c0d6aSKatayama Hirofumi MZ         TEST_DoTestEntry(__LINE__, TEST_FAILED, L"app_path_test.bat");
438ab4c0d6aSKatayama Hirofumi MZ         TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, L"app_path_test.bat.exe");
439ab4c0d6aSKatayama Hirofumi MZ         DeleteAppPath(L"app_path_test.bat.exe");
4401b3eed58SDoug Lyons     }
4411b3eed58SDoug Lyons }
4421b3eed58SDoug Lyons 
443c35a8498SKatayama Hirofumi MZ START_TEST(ShellExecuteEx)
444c35a8498SKatayama Hirofumi MZ {
445ab4c0d6aSKatayama Hirofumi MZ #ifdef _WIN64
446ab4c0d6aSKatayama Hirofumi MZ     skip("Win64 is not supported yet\n");
447ab4c0d6aSKatayama Hirofumi MZ     return;
448ab4c0d6aSKatayama Hirofumi MZ #endif
449ab4c0d6aSKatayama Hirofumi MZ 
450ab4c0d6aSKatayama Hirofumi MZ     if (!TEST_Start())
451ab4c0d6aSKatayama Hirofumi MZ         return;
452ab4c0d6aSKatayama Hirofumi MZ 
453ab4c0d6aSKatayama Hirofumi MZ     TEST_AppPath();
454ab4c0d6aSKatayama Hirofumi MZ     TEST_DoTestEntries();
455f80de47cSMark Jansen     test_properties();
4561b3eed58SDoug Lyons     test_sei_lpIDList();
4571b3eed58SDoug Lyons 
458ab4c0d6aSKatayama Hirofumi MZ     TEST_End();
459c35a8498SKatayama Hirofumi MZ }
460