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"
10436cfa94SKatayama 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>
17*ea87f910SWhindmar Saksit #include <shellutils.h>
18089788a5SKatayama Hirofumi MZ #include "shell32_apitest_sub.h"
19c2c66affSColin Finck
20ab4c0d6aSKatayama Hirofumi MZ static WCHAR s_win_dir[MAX_PATH];
21ab4c0d6aSKatayama Hirofumi MZ static WCHAR s_sys_dir[MAX_PATH];
22ab4c0d6aSKatayama Hirofumi MZ static WCHAR s_win_notepad[MAX_PATH];
23ab4c0d6aSKatayama Hirofumi MZ static WCHAR s_sys_notepad[MAX_PATH];
24ab4c0d6aSKatayama Hirofumi MZ static WCHAR s_win_test_exe[MAX_PATH];
25ab4c0d6aSKatayama Hirofumi MZ static WCHAR s_sys_test_exe[MAX_PATH];
26ab4c0d6aSKatayama Hirofumi MZ static WCHAR s_win_bat_file[MAX_PATH];
27ab4c0d6aSKatayama Hirofumi MZ static WCHAR s_sys_bat_file[MAX_PATH];
28ab4c0d6aSKatayama Hirofumi MZ static WCHAR s_win_txt_file[MAX_PATH];
29ab4c0d6aSKatayama Hirofumi MZ static WCHAR s_sys_txt_file[MAX_PATH];
30ab4c0d6aSKatayama Hirofumi MZ static WCHAR s_win_notepad_cmdline[MAX_PATH];
31ab4c0d6aSKatayama Hirofumi MZ static WCHAR s_sys_notepad_cmdline[MAX_PATH];
32ab4c0d6aSKatayama Hirofumi MZ static WCHAR s_win_test_exe_cmdline[MAX_PATH];
33ab4c0d6aSKatayama Hirofumi MZ static WCHAR s_sys_test_exe_cmdline[MAX_PATH];
34ab4c0d6aSKatayama Hirofumi MZ static BOOL s_bWow64;
35c2c66affSColin Finck
36ab4c0d6aSKatayama Hirofumi MZ #define REG_APPPATHS L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\"
37ab4c0d6aSKatayama Hirofumi MZ
38ab4c0d6aSKatayama Hirofumi MZ typedef enum TEST_RESULT
39c2c66affSColin Finck {
40ab4c0d6aSKatayama Hirofumi MZ TEST_FAILED,
41ab4c0d6aSKatayama Hirofumi MZ TEST_SUCCESS_NO_PROCESS,
42ab4c0d6aSKatayama Hirofumi MZ TEST_SUCCESS_WITH_PROCESS,
43ab4c0d6aSKatayama Hirofumi MZ } TEST_RESULT;
44c35a8498SKatayama Hirofumi MZ
45c35a8498SKatayama Hirofumi MZ typedef struct TEST_ENTRY
46c35a8498SKatayama Hirofumi MZ {
47ab4c0d6aSKatayama Hirofumi MZ INT line;
48ab4c0d6aSKatayama Hirofumi MZ TEST_RESULT result;
49ab4c0d6aSKatayama Hirofumi MZ LPCWSTR lpFile;
50ab4c0d6aSKatayama Hirofumi MZ LPCWSTR cmdline;
51ab4c0d6aSKatayama Hirofumi MZ } TEST_ENTRY, *PTEST_ENTRY;
52c35a8498SKatayama Hirofumi MZ
53ab4c0d6aSKatayama Hirofumi MZ static void
54ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(INT line, TEST_RESULT result, LPCWSTR lpFile, LPCWSTR cmdline = NULL);
55c35a8498SKatayama Hirofumi MZ
TEST_DoTestEntries(void)56ab4c0d6aSKatayama Hirofumi MZ static void TEST_DoTestEntries(void)
57c35a8498SKatayama Hirofumi MZ {
58ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, NULL);
59ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"");
60ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_FAILED, L"This is an invalid path.");
61ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, s_sys_bat_file, NULL);
62ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, s_sys_test_exe, s_sys_test_exe_cmdline);
63ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, s_sys_txt_file, NULL);
64ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, s_win_bat_file, NULL);
65ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, s_win_notepad, s_win_notepad_cmdline);
66ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, s_win_test_exe, s_win_test_exe_cmdline);
67ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, s_win_txt_file, NULL);
68ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, L"notepad", s_sys_notepad_cmdline);
69ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, L"notepad.exe", s_sys_notepad_cmdline);
70ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, L"\"notepad.exe\"", s_sys_notepad_cmdline);
71ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, L"\"notepad\"", s_sys_notepad_cmdline);
72ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, L"test program.exe", s_sys_test_exe_cmdline);
73ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, L"\"test program.exe\"", s_sys_test_exe_cmdline);
74ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, s_win_dir);
75ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, s_sys_dir);
76ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_FAILED, L"shell:ThisIsAnInvalidName");
77ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}"); // My Computer
78ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:::{20D04FE0-3AEA-1069-A2D8-08002B30309D}"); // My Computer (with shell:)
79c35a8498SKatayama Hirofumi MZ
80ab4c0d6aSKatayama Hirofumi MZ if (!IsWindowsVistaOrGreater())
81c35a8498SKatayama Hirofumi MZ {
82ab4c0d6aSKatayama Hirofumi MZ WCHAR szCurDir[MAX_PATH];
83ab4c0d6aSKatayama Hirofumi MZ GetCurrentDirectoryW(_countof(szCurDir), szCurDir);
84ab4c0d6aSKatayama Hirofumi MZ SetCurrentDirectoryW(s_sys_dir);
85ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_FAILED, L"::{21EC2020-3AEA-1069-A2DD-08002B30309D}"); // Control Panel (without path)
86ab4c0d6aSKatayama Hirofumi MZ SetCurrentDirectoryW(szCurDir);
87c35a8498SKatayama Hirofumi MZ }
88c35a8498SKatayama Hirofumi MZ
89ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}"); // Control Panel (with path)
90ab4c0d6aSKatayama 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:)
91ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:AppData");
92ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Common Desktop");
93ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Common Programs");
94ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Common Start Menu");
95ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Common StartUp");
96ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:ControlPanelFolder");
97ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Desktop");
98ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Favorites");
99ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Fonts");
100ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Local AppData");
101ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:My Pictures");
102ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Personal");
103ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Programs");
104ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Recent");
105ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:RecycleBinFolder");
106ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:SendTo");
107ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:Start Menu");
108ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_NO_PROCESS, L"shell:StartUp");
109307ce1a5SHermès Bélusca-Maïto }
110307ce1a5SHermès Bélusca-Maïto
111ab4c0d6aSKatayama Hirofumi MZ static LPWSTR
getCommandLineFromProcess(HANDLE hProcess)112ab4c0d6aSKatayama Hirofumi MZ getCommandLineFromProcess(HANDLE hProcess)
113c35a8498SKatayama Hirofumi MZ {
114ab4c0d6aSKatayama Hirofumi MZ PEB peb;
115ab4c0d6aSKatayama Hirofumi MZ PROCESS_BASIC_INFORMATION info;
116ab4c0d6aSKatayama Hirofumi MZ RTL_USER_PROCESS_PARAMETERS Params;
1174854a1d7SKatayama Hirofumi MZ NTSTATUS Status;
1184854a1d7SKatayama Hirofumi MZ BOOL ret;
119ab4c0d6aSKatayama Hirofumi MZ
1204854a1d7SKatayama Hirofumi MZ Status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &info, sizeof(info), NULL);
1214854a1d7SKatayama Hirofumi MZ ok_ntstatus(Status, STATUS_SUCCESS);
1224854a1d7SKatayama Hirofumi MZ
1234854a1d7SKatayama Hirofumi MZ ret = ReadProcessMemory(hProcess, info.PebBaseAddress, &peb, sizeof(peb), NULL);
1244854a1d7SKatayama Hirofumi MZ if (!ret)
1254854a1d7SKatayama Hirofumi MZ trace("ReadProcessMemory failed (%ld)\n", GetLastError());
1264854a1d7SKatayama Hirofumi MZ
127ab4c0d6aSKatayama Hirofumi MZ ReadProcessMemory(hProcess, peb.ProcessParameters, &Params, sizeof(Params), NULL);
1284854a1d7SKatayama Hirofumi MZ if (!ret)
1294854a1d7SKatayama Hirofumi MZ trace("ReadProcessMemory failed (%ld)\n", GetLastError());
130ab4c0d6aSKatayama Hirofumi MZ
131ab4c0d6aSKatayama Hirofumi MZ LPWSTR cmdline = Params.CommandLine.Buffer;
1324854a1d7SKatayama Hirofumi MZ if (!cmdline)
1334854a1d7SKatayama Hirofumi MZ trace("!cmdline\n");
1344854a1d7SKatayama Hirofumi MZ
1354854a1d7SKatayama Hirofumi MZ SIZE_T cbCmdLine = Params.CommandLine.Length;
1364854a1d7SKatayama Hirofumi MZ if (!cbCmdLine)
1374854a1d7SKatayama Hirofumi MZ trace("!cbCmdLine\n");
1384854a1d7SKatayama Hirofumi MZ
1394854a1d7SKatayama Hirofumi MZ LPWSTR pszBuffer = (LPWSTR)calloc(cbCmdLine + sizeof(WCHAR), 1);
1404854a1d7SKatayama Hirofumi MZ if (!pszBuffer)
1414854a1d7SKatayama Hirofumi MZ trace("!pszBuffer\n");
1424854a1d7SKatayama Hirofumi MZ
1434854a1d7SKatayama Hirofumi MZ ret = ReadProcessMemory(hProcess, cmdline, pszBuffer, cbCmdLine, NULL);
1444854a1d7SKatayama Hirofumi MZ if (!ret)
1454854a1d7SKatayama Hirofumi MZ trace("ReadProcessMemory failed (%ld)\n", GetLastError());
1464854a1d7SKatayama Hirofumi MZ
1474854a1d7SKatayama Hirofumi MZ pszBuffer[cbCmdLine / sizeof(WCHAR)] = UNICODE_NULL;
148ab4c0d6aSKatayama Hirofumi MZ
149ab4c0d6aSKatayama Hirofumi MZ return pszBuffer; // needs free()
150ab4c0d6aSKatayama Hirofumi MZ }
151ab4c0d6aSKatayama Hirofumi MZ
TEST_DoTestEntryStruct(const TEST_ENTRY * pEntry)152ab4c0d6aSKatayama Hirofumi MZ static void TEST_DoTestEntryStruct(const TEST_ENTRY *pEntry)
153ab4c0d6aSKatayama Hirofumi MZ {
154ab4c0d6aSKatayama Hirofumi MZ SHELLEXECUTEINFOW info = { sizeof(info) };
155436cfa94SKatayama Hirofumi MZ info.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_WAITFORINPUTIDLE |
156436cfa94SKatayama Hirofumi MZ SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC;
157ab4c0d6aSKatayama Hirofumi MZ info.hwnd = NULL;
158ab4c0d6aSKatayama Hirofumi MZ info.lpVerb = NULL;
159ab4c0d6aSKatayama Hirofumi MZ info.lpFile = pEntry->lpFile;
160c35a8498SKatayama Hirofumi MZ info.nShow = SW_SHOWNORMAL;
161c35a8498SKatayama Hirofumi MZ
162ab4c0d6aSKatayama Hirofumi MZ BOOL ret = ShellExecuteExW(&info);
163ab4c0d6aSKatayama Hirofumi MZ
164ab4c0d6aSKatayama Hirofumi MZ TEST_RESULT result;
165ab4c0d6aSKatayama Hirofumi MZ if (ret && info.hProcess)
166ab4c0d6aSKatayama Hirofumi MZ result = TEST_SUCCESS_WITH_PROCESS;
167ab4c0d6aSKatayama Hirofumi MZ else if (ret && !info.hProcess)
168ab4c0d6aSKatayama Hirofumi MZ result = TEST_SUCCESS_NO_PROCESS;
169ab4c0d6aSKatayama Hirofumi MZ else
170ab4c0d6aSKatayama Hirofumi MZ result = TEST_FAILED;
171ab4c0d6aSKatayama Hirofumi MZ
172ab4c0d6aSKatayama Hirofumi MZ ok(pEntry->result == result,
173ab4c0d6aSKatayama Hirofumi MZ "Line %d: result: %d vs %d\n", pEntry->line, pEntry->result, result);
174ab4c0d6aSKatayama Hirofumi MZ
175ab4c0d6aSKatayama Hirofumi MZ if (pEntry->result == TEST_SUCCESS_WITH_PROCESS && pEntry->cmdline && !s_bWow64)
176c35a8498SKatayama Hirofumi MZ {
177ab4c0d6aSKatayama Hirofumi MZ LPWSTR cmdline = getCommandLineFromProcess(info.hProcess);
178ab4c0d6aSKatayama Hirofumi MZ if (!cmdline)
179c35a8498SKatayama Hirofumi MZ {
180ab4c0d6aSKatayama Hirofumi MZ skip("!cmdline\n");
181c35a8498SKatayama Hirofumi MZ }
182c35a8498SKatayama Hirofumi MZ else
183c35a8498SKatayama Hirofumi MZ {
184ab4c0d6aSKatayama Hirofumi MZ ok(lstrcmpiW(pEntry->cmdline, cmdline) == 0,
185ab4c0d6aSKatayama Hirofumi MZ "Line %d: cmdline: '%ls' vs '%ls'\n", pEntry->line,
186ab4c0d6aSKatayama Hirofumi MZ pEntry->cmdline, cmdline);
187c35a8498SKatayama Hirofumi MZ }
188c35a8498SKatayama Hirofumi MZ
189ab4c0d6aSKatayama Hirofumi MZ TerminateProcess(info.hProcess, 0xDEADFACE);
190ab4c0d6aSKatayama Hirofumi MZ free(cmdline);
191f80de47cSMark Jansen }
192ab4c0d6aSKatayama Hirofumi MZ
193c35a8498SKatayama Hirofumi MZ CloseHandle(info.hProcess);
194c35a8498SKatayama Hirofumi MZ }
195c35a8498SKatayama Hirofumi MZ
196ab4c0d6aSKatayama Hirofumi MZ static void
TEST_DoTestEntry(INT line,TEST_RESULT result,LPCWSTR lpFile,LPCWSTR cmdline)197ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(INT line, TEST_RESULT result, LPCWSTR lpFile, LPCWSTR cmdline)
198ab4c0d6aSKatayama Hirofumi MZ {
199ab4c0d6aSKatayama Hirofumi MZ TEST_ENTRY entry = { line, result, lpFile, cmdline };
200ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntryStruct(&entry);
201ab4c0d6aSKatayama Hirofumi MZ }
202ab4c0d6aSKatayama Hirofumi MZ
203c35a8498SKatayama Hirofumi MZ static BOOL
enableTokenPrivilege(LPCWSTR pszPrivilege)204ab4c0d6aSKatayama Hirofumi MZ enableTokenPrivilege(LPCWSTR pszPrivilege)
205c35a8498SKatayama Hirofumi MZ {
206ab4c0d6aSKatayama Hirofumi MZ HANDLE hToken;
207ab4c0d6aSKatayama Hirofumi MZ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
208c35a8498SKatayama Hirofumi MZ return FALSE;
209ab4c0d6aSKatayama Hirofumi MZ
210ab4c0d6aSKatayama Hirofumi MZ TOKEN_PRIVILEGES tkp = { 0 };
211ab4c0d6aSKatayama Hirofumi MZ if (!LookupPrivilegeValueW(NULL, pszPrivilege, &tkp.Privileges[0].Luid))
212ab4c0d6aSKatayama Hirofumi MZ return FALSE;
213ab4c0d6aSKatayama Hirofumi MZ
214ab4c0d6aSKatayama Hirofumi MZ tkp.PrivilegeCount = 1;
215ab4c0d6aSKatayama Hirofumi MZ tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
216ab4c0d6aSKatayama Hirofumi MZ return AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, NULL, NULL);
217c35a8498SKatayama Hirofumi MZ }
218c35a8498SKatayama Hirofumi MZ
219ab4c0d6aSKatayama Hirofumi MZ static WINDOW_LIST s_List1, s_List2;
220ab4c0d6aSKatayama Hirofumi MZ
TEST_Start(void)221ab4c0d6aSKatayama Hirofumi MZ static BOOL TEST_Start(void)
222ab4c0d6aSKatayama Hirofumi MZ {
223ab4c0d6aSKatayama Hirofumi MZ // Check Wow64
224ab4c0d6aSKatayama Hirofumi MZ s_bWow64 = FALSE;
225ab4c0d6aSKatayama Hirofumi MZ IsWow64Process(GetCurrentProcess(), &s_bWow64);
226ab4c0d6aSKatayama Hirofumi MZ if (s_bWow64)
227ab4c0d6aSKatayama Hirofumi MZ skip("Wow64: Command Line check is skipped\n");
228ab4c0d6aSKatayama Hirofumi MZ
229ab4c0d6aSKatayama Hirofumi MZ // getCommandLineFromProcess needs this
230ab4c0d6aSKatayama Hirofumi MZ enableTokenPrivilege(SE_DEBUG_NAME);
231ab4c0d6aSKatayama Hirofumi MZ
232ab4c0d6aSKatayama Hirofumi MZ // s_win_dir
233ab4c0d6aSKatayama Hirofumi MZ GetWindowsDirectoryW(s_win_dir, _countof(s_win_dir));
234ab4c0d6aSKatayama Hirofumi MZ
235ab4c0d6aSKatayama Hirofumi MZ // s_sys_dir
236ab4c0d6aSKatayama Hirofumi MZ GetSystemDirectoryW(s_sys_dir, _countof(s_sys_dir));
237ab4c0d6aSKatayama Hirofumi MZ
238ab4c0d6aSKatayama Hirofumi MZ // s_win_notepad
239ab4c0d6aSKatayama Hirofumi MZ GetWindowsDirectoryW(s_win_notepad, _countof(s_win_notepad));
240ab4c0d6aSKatayama Hirofumi MZ PathAppendW(s_win_notepad, L"notepad.exe");
241ab4c0d6aSKatayama Hirofumi MZ
242ab4c0d6aSKatayama Hirofumi MZ // s_sys_notepad
243ab4c0d6aSKatayama Hirofumi MZ GetSystemDirectoryW(s_sys_notepad, _countof(s_sys_notepad));
244ab4c0d6aSKatayama Hirofumi MZ PathAppendW(s_sys_notepad, L"notepad.exe");
245ab4c0d6aSKatayama Hirofumi MZ
246c35a8498SKatayama Hirofumi MZ // s_win_test_exe
247ab4c0d6aSKatayama Hirofumi MZ GetWindowsDirectoryW(s_win_test_exe, _countof(s_win_test_exe));
248ab4c0d6aSKatayama Hirofumi MZ PathAppendW(s_win_test_exe, L"test program.exe");
249ab4c0d6aSKatayama Hirofumi MZ BOOL ret = CopyFileW(s_win_notepad, s_win_test_exe, FALSE);
250c35a8498SKatayama Hirofumi MZ if (!ret)
251c35a8498SKatayama Hirofumi MZ {
252c35a8498SKatayama Hirofumi MZ skip("Please retry with admin rights\n");
253ab4c0d6aSKatayama Hirofumi MZ return FALSE;
254c35a8498SKatayama Hirofumi MZ }
255c35a8498SKatayama Hirofumi MZ
256c35a8498SKatayama Hirofumi MZ // s_sys_test_exe
257ab4c0d6aSKatayama Hirofumi MZ GetSystemDirectoryW(s_sys_test_exe, _countof(s_sys_test_exe));
258ab4c0d6aSKatayama Hirofumi MZ PathAppendW(s_sys_test_exe, L"test program.exe");
259ab4c0d6aSKatayama Hirofumi MZ ok_int(CopyFileW(s_win_notepad, s_sys_test_exe, FALSE), TRUE);
260c35a8498SKatayama Hirofumi MZ
261c35a8498SKatayama Hirofumi MZ // s_win_bat_file
262ab4c0d6aSKatayama Hirofumi MZ GetWindowsDirectoryW(s_win_bat_file, _countof(s_win_bat_file));
263ab4c0d6aSKatayama Hirofumi MZ PathAppendW(s_win_bat_file, L"test program.bat");
264ab4c0d6aSKatayama Hirofumi MZ FILE *fp = _wfopen(s_win_bat_file, L"wb");
265c35a8498SKatayama Hirofumi MZ fprintf(fp, "exit /b 3");
266c35a8498SKatayama Hirofumi MZ fclose(fp);
267ab4c0d6aSKatayama Hirofumi MZ ok_int(PathFileExistsW(s_win_bat_file), TRUE);
268c35a8498SKatayama Hirofumi MZ
269c35a8498SKatayama Hirofumi MZ // s_sys_bat_file
270ab4c0d6aSKatayama Hirofumi MZ GetSystemDirectoryW(s_sys_bat_file, _countof(s_sys_bat_file));
271ab4c0d6aSKatayama Hirofumi MZ PathAppendW(s_sys_bat_file, L"test program.bat");
272ab4c0d6aSKatayama Hirofumi MZ fp = _wfopen(s_sys_bat_file, L"wb");
273c35a8498SKatayama Hirofumi MZ fprintf(fp, "exit /b 4");
274c35a8498SKatayama Hirofumi MZ fclose(fp);
275ab4c0d6aSKatayama Hirofumi MZ ok_int(PathFileExistsW(s_sys_bat_file), TRUE);
276c35a8498SKatayama Hirofumi MZ
277c35a8498SKatayama Hirofumi MZ // s_win_txt_file
278ab4c0d6aSKatayama Hirofumi MZ GetWindowsDirectoryW(s_win_txt_file, _countof(s_win_txt_file));
279ab4c0d6aSKatayama Hirofumi MZ PathAppendW(s_win_txt_file, L"test_file.txt");
280ab4c0d6aSKatayama Hirofumi MZ fp = _wfopen(s_win_txt_file, L"wb");
281c35a8498SKatayama Hirofumi MZ fclose(fp);
282ab4c0d6aSKatayama Hirofumi MZ ok_int(PathFileExistsW(s_win_txt_file), TRUE);
283c35a8498SKatayama Hirofumi MZ
284c35a8498SKatayama Hirofumi MZ // s_sys_txt_file
285ab4c0d6aSKatayama Hirofumi MZ GetSystemDirectoryW(s_sys_txt_file, _countof(s_sys_txt_file));
286ab4c0d6aSKatayama Hirofumi MZ PathAppendW(s_sys_txt_file, L"test_file.txt");
287ab4c0d6aSKatayama Hirofumi MZ fp = _wfopen(s_sys_txt_file, L"wb");
288c35a8498SKatayama Hirofumi MZ fclose(fp);
289ab4c0d6aSKatayama Hirofumi MZ ok_int(PathFileExistsW(s_sys_txt_file), TRUE);
290c35a8498SKatayama Hirofumi MZ
291ab4c0d6aSKatayama Hirofumi MZ // Check .txt settings
292ab4c0d6aSKatayama Hirofumi MZ WCHAR szPath[MAX_PATH];
293ab4c0d6aSKatayama Hirofumi MZ FindExecutableW(s_sys_txt_file, NULL, szPath);
294ab4c0d6aSKatayama Hirofumi MZ if (lstrcmpiW(PathFindFileNameW(szPath), L"notepad.exe") != 0)
295c35a8498SKatayama Hirofumi MZ {
296ab4c0d6aSKatayama Hirofumi MZ skip("Please associate .txt with notepad.exe before tests\n");
297f80de47cSMark Jansen return FALSE;
298f80de47cSMark Jansen }
299ab4c0d6aSKatayama Hirofumi MZ
300ab4c0d6aSKatayama Hirofumi MZ // command lines
301ab4c0d6aSKatayama Hirofumi MZ StringCchPrintfW(s_win_notepad_cmdline, _countof(s_win_notepad_cmdline),
302ab4c0d6aSKatayama Hirofumi MZ L"\"%s\" ", s_win_notepad);
303ab4c0d6aSKatayama Hirofumi MZ StringCchPrintfW(s_sys_notepad_cmdline, _countof(s_sys_notepad_cmdline),
304ab4c0d6aSKatayama Hirofumi MZ L"\"%s\" ", s_sys_notepad);
305ab4c0d6aSKatayama Hirofumi MZ StringCchPrintfW(s_win_test_exe_cmdline, _countof(s_win_test_exe_cmdline),
306ab4c0d6aSKatayama Hirofumi MZ L"\"%s\" ", s_win_test_exe);
307ab4c0d6aSKatayama Hirofumi MZ StringCchPrintfW(s_sys_test_exe_cmdline, _countof(s_sys_test_exe_cmdline),
308ab4c0d6aSKatayama Hirofumi MZ L"\"%s\" ", s_sys_test_exe);
309ab4c0d6aSKatayama Hirofumi MZ
310436cfa94SKatayama Hirofumi MZ GetWindowList(&s_List1);
311ab4c0d6aSKatayama Hirofumi MZ
312f80de47cSMark Jansen return TRUE;
313f80de47cSMark Jansen }
314f80de47cSMark Jansen
TEST_End(void)315ab4c0d6aSKatayama Hirofumi MZ static void TEST_End(void)
316f80de47cSMark Jansen {
317*ea87f910SWhindmar Saksit GetWindowListForClose(&s_List2);
318436cfa94SKatayama Hirofumi MZ CloseNewWindows(&s_List1, &s_List2);
319436cfa94SKatayama Hirofumi MZ FreeWindowList(&s_List1);
320436cfa94SKatayama Hirofumi MZ FreeWindowList(&s_List2);
321f80de47cSMark Jansen
322ab4c0d6aSKatayama Hirofumi MZ DeleteFileW(s_win_test_exe);
323ab4c0d6aSKatayama Hirofumi MZ DeleteFileW(s_sys_test_exe);
324ab4c0d6aSKatayama Hirofumi MZ DeleteFileW(s_win_txt_file);
325ab4c0d6aSKatayama Hirofumi MZ DeleteFileW(s_sys_txt_file);
326ab4c0d6aSKatayama Hirofumi MZ DeleteFileW(s_win_bat_file);
327ab4c0d6aSKatayama Hirofumi MZ DeleteFileW(s_sys_bat_file);
328f80de47cSMark Jansen }
329f80de47cSMark Jansen
test_properties()330f80de47cSMark Jansen static void test_properties()
331f80de47cSMark Jansen {
332ab4c0d6aSKatayama Hirofumi MZ HRESULT hrCoInit = CoInitialize(NULL);
333f80de47cSMark Jansen
3344854a1d7SKatayama Hirofumi MZ WCHAR Buffer[MAX_PATH * 4];
335f80de47cSMark Jansen GetModuleFileNameW(NULL, Buffer, _countof(Buffer));
336f80de47cSMark Jansen
3374854a1d7SKatayama Hirofumi MZ SHELLEXECUTEINFOW info = { sizeof(info) };
338f80de47cSMark Jansen info.fMask = SEE_MASK_INVOKEIDLIST | SEE_MASK_FLAG_NO_UI;
339f80de47cSMark Jansen info.lpVerb = L"properties";
340f80de47cSMark Jansen info.lpFile = Buffer;
341f80de47cSMark Jansen info.nShow = SW_SHOW;
342f80de47cSMark Jansen
343f80de47cSMark Jansen BOOL bRet = ShellExecuteExW(&info);
344f80de47cSMark Jansen ok(bRet, "Failed! (GetLastError(): %d)\n", (int)GetLastError());
345f80de47cSMark Jansen ok_ptr(info.hInstApp, (HINSTANCE)42);
346f80de47cSMark Jansen
347f80de47cSMark Jansen WCHAR* Extension = PathFindExtensionW(Buffer);
348f80de47cSMark Jansen if (Extension)
349f80de47cSMark Jansen {
350f80de47cSMark Jansen // The inclusion of this depends on the file display settings!
351f80de47cSMark Jansen *Extension = UNICODE_NULL;
352f80de47cSMark Jansen }
353f80de47cSMark Jansen
354f80de47cSMark Jansen // Now retry it with the extension cut off
355f80de47cSMark Jansen bRet = ShellExecuteExW(&info);
356f80de47cSMark Jansen ok(bRet, "Failed! (GetLastError(): %d)\n", (int)GetLastError());
357f80de47cSMark Jansen ok_ptr(info.hInstApp, (HINSTANCE)42);
358f80de47cSMark Jansen
359f80de47cSMark Jansen // Now retry it with complete garabage
360ab4c0d6aSKatayama Hirofumi MZ info.lpFile = L"complete garbage, cannot run this!";
361f80de47cSMark Jansen bRet = ShellExecuteExW(&info);
362ab4c0d6aSKatayama Hirofumi MZ ok_int(bRet, 0);
363f80de47cSMark Jansen ok_ptr(info.hInstApp, (HINSTANCE)2);
364ab4c0d6aSKatayama Hirofumi MZ
365ab4c0d6aSKatayama Hirofumi MZ if (SUCCEEDED(hrCoInit))
366ab4c0d6aSKatayama Hirofumi MZ CoUninitialize();
367f80de47cSMark Jansen }
368f80de47cSMark Jansen
test_sei_lpIDList()3691b3eed58SDoug Lyons static void test_sei_lpIDList()
3701b3eed58SDoug Lyons {
371*ea87f910SWhindmar Saksit // Note: SEE_MASK_FLAG_NO_UI prevents the test from blocking with a MessageBox
372*ea87f910SWhindmar Saksit WCHAR path[MAX_PATH];
373*ea87f910SWhindmar Saksit
374*ea87f910SWhindmar Saksit /* This tests ShellExecuteEx with lpIDList for explorer C:\ */
375*ea87f910SWhindmar Saksit GetSystemDirectoryW(path, _countof(path));
376*ea87f910SWhindmar Saksit PathStripToRootW(path);
377*ea87f910SWhindmar Saksit LPITEMIDLIST pidl = ILCreateFromPathW(path);
378*ea87f910SWhindmar Saksit if (!pidl)
379ab4c0d6aSKatayama Hirofumi MZ {
380*ea87f910SWhindmar Saksit skip("Unable to initialize test\n");
381ab4c0d6aSKatayama Hirofumi MZ return;
382ab4c0d6aSKatayama Hirofumi MZ }
383ab4c0d6aSKatayama Hirofumi MZ
384ab4c0d6aSKatayama Hirofumi MZ SHELLEXECUTEINFOW ShellExecInfo = { sizeof(ShellExecInfo) };
3851b3eed58SDoug Lyons ShellExecInfo.nShow = SW_SHOWNORMAL;
386*ea87f910SWhindmar Saksit ShellExecInfo.fMask = SEE_MASK_IDLIST | SEE_MASK_FLAG_NO_UI | SEE_MASK_FLAG_DDEWAIT;
387*ea87f910SWhindmar Saksit ShellExecInfo.lpIDList = pidl;
388ab4c0d6aSKatayama Hirofumi MZ BOOL ret = ShellExecuteExW(&ShellExecInfo);
389ab4c0d6aSKatayama Hirofumi MZ ok_int(ret, TRUE);
390*ea87f910SWhindmar Saksit ILFree(pidl);
391*ea87f910SWhindmar Saksit
392*ea87f910SWhindmar Saksit /* This tests ShellExecuteEx with lpIDList going through IContextMenu */
393*ea87f910SWhindmar Saksit CCoInit ComInit;
394*ea87f910SWhindmar Saksit pidl = SHCloneSpecialIDList(NULL, CSIDL_PROFILE, TRUE);
395*ea87f910SWhindmar Saksit if (!pidl)
396*ea87f910SWhindmar Saksit {
397*ea87f910SWhindmar Saksit skip("Unable to initialize test\n");
398*ea87f910SWhindmar Saksit return;
399*ea87f910SWhindmar Saksit }
400*ea87f910SWhindmar Saksit ShellExecInfo.fMask = SEE_MASK_INVOKEIDLIST | SEE_MASK_FLAG_NO_UI | SEE_MASK_FLAG_DDEWAIT;
401*ea87f910SWhindmar Saksit ShellExecInfo.lpIDList = pidl;
402*ea87f910SWhindmar Saksit ret = ShellExecuteExW(&ShellExecInfo);
403*ea87f910SWhindmar Saksit ok_int(ret, TRUE);
404*ea87f910SWhindmar Saksit ILFree(pidl);
405ab4c0d6aSKatayama Hirofumi MZ }
4061b3eed58SDoug Lyons
407ab4c0d6aSKatayama Hirofumi MZ static BOOL
CreateAppPath(LPCWSTR pszName,LPCWSTR pszValue)408ab4c0d6aSKatayama Hirofumi MZ CreateAppPath(LPCWSTR pszName, LPCWSTR pszValue)
4091b3eed58SDoug Lyons {
410ab4c0d6aSKatayama Hirofumi MZ WCHAR szSubKey[MAX_PATH];
411ab4c0d6aSKatayama Hirofumi MZ StringCchPrintfW(szSubKey, _countof(szSubKey), L"%s\\%s", REG_APPPATHS, pszName);
412ab4c0d6aSKatayama Hirofumi MZ
413ab4c0d6aSKatayama Hirofumi MZ LSTATUS error;
414ab4c0d6aSKatayama Hirofumi MZ HKEY hKey;
415ab4c0d6aSKatayama Hirofumi MZ error = RegCreateKeyExW(HKEY_LOCAL_MACHINE, szSubKey, 0, NULL, 0, KEY_WRITE, NULL,
416ab4c0d6aSKatayama Hirofumi MZ &hKey, NULL);
417ab4c0d6aSKatayama Hirofumi MZ if (error != ERROR_SUCCESS)
418ab4c0d6aSKatayama Hirofumi MZ trace("Could not create test key (%lu)\n", error);
419ab4c0d6aSKatayama Hirofumi MZ
420ab4c0d6aSKatayama Hirofumi MZ DWORD cbValue = (lstrlenW(pszValue) + 1) * sizeof(WCHAR);
421ab4c0d6aSKatayama Hirofumi MZ error = RegSetValueExW(hKey, NULL, 0, REG_SZ, (LPBYTE)pszValue, cbValue);
422ab4c0d6aSKatayama Hirofumi MZ if (error != ERROR_SUCCESS)
423ab4c0d6aSKatayama Hirofumi MZ trace("Could not set value of the test key (%lu)\n", error);
424ab4c0d6aSKatayama Hirofumi MZ
425ab4c0d6aSKatayama Hirofumi MZ RegCloseKey(hKey);
426ab4c0d6aSKatayama Hirofumi MZ
427ab4c0d6aSKatayama Hirofumi MZ return error == ERROR_SUCCESS;
428ab4c0d6aSKatayama Hirofumi MZ }
429ab4c0d6aSKatayama Hirofumi MZ
430ab4c0d6aSKatayama Hirofumi MZ static VOID
DeleteAppPath(LPCWSTR pszName)431ab4c0d6aSKatayama Hirofumi MZ DeleteAppPath(LPCWSTR pszName)
432ab4c0d6aSKatayama Hirofumi MZ {
433ab4c0d6aSKatayama Hirofumi MZ WCHAR szSubKey[MAX_PATH];
434ab4c0d6aSKatayama Hirofumi MZ StringCchPrintfW(szSubKey, _countof(szSubKey), L"%s\\%s", REG_APPPATHS, pszName);
435ab4c0d6aSKatayama Hirofumi MZ
436ab4c0d6aSKatayama Hirofumi MZ LSTATUS error = RegDeleteKeyW(HKEY_LOCAL_MACHINE, szSubKey);
437ab4c0d6aSKatayama Hirofumi MZ if (error != ERROR_SUCCESS)
438ab4c0d6aSKatayama Hirofumi MZ trace("Could not remove the test key (%lu)\n", error);
439ab4c0d6aSKatayama Hirofumi MZ }
440ab4c0d6aSKatayama Hirofumi MZ
TEST_AppPath(void)441ab4c0d6aSKatayama Hirofumi MZ static void TEST_AppPath(void)
442ab4c0d6aSKatayama Hirofumi MZ {
443ab4c0d6aSKatayama Hirofumi MZ if (CreateAppPath(L"app_path_test.bat", s_win_test_exe))
444ab4c0d6aSKatayama Hirofumi MZ {
445ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, L"app_path_test.bat");
446ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_FAILED, L"app_path_test.bat.exe");
447ab4c0d6aSKatayama Hirofumi MZ DeleteAppPath(L"app_path_test.bat");
448ab4c0d6aSKatayama Hirofumi MZ }
449ab4c0d6aSKatayama Hirofumi MZ
450ab4c0d6aSKatayama Hirofumi MZ if (CreateAppPath(L"app_path_test.bat.exe", s_sys_test_exe))
451ab4c0d6aSKatayama Hirofumi MZ {
452ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_FAILED, L"app_path_test.bat");
453ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntry(__LINE__, TEST_SUCCESS_WITH_PROCESS, L"app_path_test.bat.exe");
454ab4c0d6aSKatayama Hirofumi MZ DeleteAppPath(L"app_path_test.bat.exe");
4551b3eed58SDoug Lyons }
4561b3eed58SDoug Lyons }
4571b3eed58SDoug Lyons
test_DoInvalidDir(void)458089788a5SKatayama Hirofumi MZ static void test_DoInvalidDir(void)
459089788a5SKatayama Hirofumi MZ {
460089788a5SKatayama Hirofumi MZ WCHAR szSubProgram[MAX_PATH];
461089788a5SKatayama Hirofumi MZ if (!FindSubProgram(szSubProgram, _countof(szSubProgram)))
462089788a5SKatayama Hirofumi MZ {
463089788a5SKatayama Hirofumi MZ skip("shell32_apitest_sub.exe not found\n");
464089788a5SKatayama Hirofumi MZ return;
465089788a5SKatayama Hirofumi MZ }
466089788a5SKatayama Hirofumi MZ
467089788a5SKatayama Hirofumi MZ DWORD dwExitCode;
468089788a5SKatayama Hirofumi MZ SHELLEXECUTEINFOW sei = { sizeof(sei), SEE_MASK_FLAG_NO_UI | SEE_MASK_NOCLOSEPROCESS };
469089788a5SKatayama Hirofumi MZ sei.lpFile = szSubProgram;
470089788a5SKatayama Hirofumi MZ sei.lpParameters = L"TEST";
471089788a5SKatayama Hirofumi MZ sei.nShow = SW_SHOWNORMAL;
472089788a5SKatayama Hirofumi MZ
473089788a5SKatayama Hirofumi MZ // Test invalid path on sei.lpDirectory
474089788a5SKatayama Hirofumi MZ WCHAR szInvalidPath[MAX_PATH] = L"M:\\This is an invalid path\n";
475089788a5SKatayama Hirofumi MZ sei.lpDirectory = szInvalidPath;
476089788a5SKatayama Hirofumi MZ ok_int(ShellExecuteExW(&sei), TRUE);
477089788a5SKatayama Hirofumi MZ WaitForSingleObject(sei.hProcess, 20 * 1000);
478089788a5SKatayama Hirofumi MZ GetExitCodeProcess(sei.hProcess, &dwExitCode);
479089788a5SKatayama Hirofumi MZ ok_long(dwExitCode, 0);
480089788a5SKatayama Hirofumi MZ CloseHandle(sei.hProcess);
481089788a5SKatayama Hirofumi MZ }
482089788a5SKatayama Hirofumi MZ
START_TEST(ShellExecuteEx)483c35a8498SKatayama Hirofumi MZ START_TEST(ShellExecuteEx)
484c35a8498SKatayama Hirofumi MZ {
485ab4c0d6aSKatayama Hirofumi MZ #ifdef _WIN64
486ab4c0d6aSKatayama Hirofumi MZ skip("Win64 is not supported yet\n");
487ab4c0d6aSKatayama Hirofumi MZ return;
488ab4c0d6aSKatayama Hirofumi MZ #endif
489ab4c0d6aSKatayama Hirofumi MZ
490ab4c0d6aSKatayama Hirofumi MZ if (!TEST_Start())
491ab4c0d6aSKatayama Hirofumi MZ return;
492ab4c0d6aSKatayama Hirofumi MZ
493ab4c0d6aSKatayama Hirofumi MZ TEST_AppPath();
494ab4c0d6aSKatayama Hirofumi MZ TEST_DoTestEntries();
495f80de47cSMark Jansen test_properties();
4961b3eed58SDoug Lyons test_sei_lpIDList();
497089788a5SKatayama Hirofumi MZ test_DoInvalidDir();
4981b3eed58SDoug Lyons
499ab4c0d6aSKatayama Hirofumi MZ TEST_End();
500c35a8498SKatayama Hirofumi MZ }
501