1c2c66affSColin Finck /*
2c2c66affSColin Finck * PROJECT: ReactOS api tests
3c2c66affSColin Finck * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory
4c2c66affSColin Finck * PURPOSE: Test for TerminateProcess
5c2c66affSColin Finck * PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
6c2c66affSColin Finck */
7c2c66affSColin Finck
8*e00cc972SAmine Khaldi #include "precomp.h"
9c2c66affSColin Finck
10c2c66affSColin Finck #include <ndk/obfuncs.h>
11c2c66affSColin Finck
12c2c66affSColin Finck static
13c2c66affSColin Finck HANDLE
StartChild(_In_ PCWSTR Argument,_In_ DWORD Flags,_Out_opt_ PDWORD ProcessId)14c2c66affSColin Finck StartChild(
15c2c66affSColin Finck _In_ PCWSTR Argument,
16c2c66affSColin Finck _In_ DWORD Flags,
17c2c66affSColin Finck _Out_opt_ PDWORD ProcessId)
18c2c66affSColin Finck {
19c2c66affSColin Finck BOOL Success;
20c2c66affSColin Finck WCHAR FileName[MAX_PATH];
21c2c66affSColin Finck WCHAR CommandLine[MAX_PATH];
22c2c66affSColin Finck STARTUPINFOW StartupInfo;
23c2c66affSColin Finck PROCESS_INFORMATION ProcessInfo;
24c2c66affSColin Finck
25c2c66affSColin Finck GetModuleFileNameW(NULL, FileName, _countof(FileName));
26c2c66affSColin Finck StringCbPrintfW(CommandLine,
27c2c66affSColin Finck sizeof(CommandLine),
28c2c66affSColin Finck L"\"%ls\" TerminateProcess %ls",
29c2c66affSColin Finck FileName,
30c2c66affSColin Finck Argument);
31c2c66affSColin Finck
32c2c66affSColin Finck RtlZeroMemory(&StartupInfo, sizeof(StartupInfo));
33c2c66affSColin Finck StartupInfo.cb = sizeof(StartupInfo);
34c2c66affSColin Finck /* HACK: running the test under rosautotest seems to keep another reference
35c2c66affSColin Finck * to the child process around until the test finishes (on both ROS and
36c2c66affSColin Finck * Windows)... I'm too lazy to investigate very much so let's just redirect
37c2c66affSColin Finck * the child std handles to nowhere. ok() is useless in half the child
38c2c66affSColin Finck * processes anyway.
39c2c66affSColin Finck */
40c2c66affSColin Finck StartupInfo.dwFlags = STARTF_USESTDHANDLES;
41c2c66affSColin Finck
42c2c66affSColin Finck Success = CreateProcessW(FileName,
43c2c66affSColin Finck CommandLine,
44c2c66affSColin Finck NULL,
45c2c66affSColin Finck NULL,
46c2c66affSColin Finck FALSE,
47c2c66affSColin Finck Flags,
48c2c66affSColin Finck NULL,
49c2c66affSColin Finck NULL,
50c2c66affSColin Finck &StartupInfo,
51c2c66affSColin Finck &ProcessInfo);
52c2c66affSColin Finck if (!Success)
53c2c66affSColin Finck {
54c2c66affSColin Finck skip("CreateProcess failed with %lu\n", GetLastError());
55c2c66affSColin Finck if (ProcessId)
56c2c66affSColin Finck *ProcessId = 0;
57c2c66affSColin Finck return NULL;
58c2c66affSColin Finck }
59c2c66affSColin Finck CloseHandle(ProcessInfo.hThread);
60c2c66affSColin Finck if (ProcessId)
61c2c66affSColin Finck *ProcessId = ProcessInfo.dwProcessId;
62c2c66affSColin Finck return ProcessInfo.hProcess;
63c2c66affSColin Finck }
64c2c66affSColin Finck
65c2c66affSColin Finck static
66c2c66affSColin Finck VOID
TraceHandleCount_(_In_ HANDLE hObject,_In_ PCSTR File,_In_ INT Line)67c2c66affSColin Finck TraceHandleCount_(
68c2c66affSColin Finck _In_ HANDLE hObject,
69c2c66affSColin Finck _In_ PCSTR File,
70c2c66affSColin Finck _In_ INT Line)
71c2c66affSColin Finck {
72c2c66affSColin Finck NTSTATUS Status;
73c2c66affSColin Finck OBJECT_BASIC_INFORMATION BasicInfo;
74c2c66affSColin Finck
75c2c66affSColin Finck Status = NtQueryObject(hObject,
76c2c66affSColin Finck ObjectBasicInformation,
77c2c66affSColin Finck &BasicInfo,
78c2c66affSColin Finck sizeof(BasicInfo),
79c2c66affSColin Finck NULL);
80c2c66affSColin Finck if (!NT_SUCCESS(Status))
81c2c66affSColin Finck {
82c2c66affSColin Finck ok_(File, Line)(0, "NtQueryObject failed with status 0x%lx\n", Status);
83c2c66affSColin Finck return;
84c2c66affSColin Finck }
85c2c66affSColin Finck ok_(File, Line)(0, "Handle %p still has %lu open handles, %lu references\n", hObject, BasicInfo.HandleCount, BasicInfo.PointerCount);
86c2c66affSColin Finck }
87c2c66affSColin Finck
88c2c66affSColin Finck #define WaitExpectSuccess(h, ms) WaitExpect_(h, ms, WAIT_OBJECT_0, __FILE__, __LINE__)
89c2c66affSColin Finck #define WaitExpectTimeout(h, ms) WaitExpect_(h, ms, WAIT_TIMEOUT, __FILE__, __LINE__)
90c2c66affSColin Finck static
91c2c66affSColin Finck VOID
WaitExpect_(_In_ HANDLE hWait,_In_ DWORD Milliseconds,_In_ DWORD ExpectedError,_In_ PCSTR File,_In_ INT Line)92c2c66affSColin Finck WaitExpect_(
93c2c66affSColin Finck _In_ HANDLE hWait,
94c2c66affSColin Finck _In_ DWORD Milliseconds,
95c2c66affSColin Finck _In_ DWORD ExpectedError,
96c2c66affSColin Finck _In_ PCSTR File,
97c2c66affSColin Finck _In_ INT Line)
98c2c66affSColin Finck {
99c2c66affSColin Finck DWORD Error;
100c2c66affSColin Finck
101c2c66affSColin Finck Error = WaitForSingleObject(hWait, Milliseconds);
102c2c66affSColin Finck ok_(File, Line)(Error == ExpectedError, "Wait for %p return %lu\n", hWait, Error);
103c2c66affSColin Finck }
104c2c66affSColin Finck
105c2c66affSColin Finck #define CloseProcessAndVerify(hp, pid, code) CloseProcessAndVerify_(hp, pid, code, __FILE__, __LINE__)
106c2c66affSColin Finck static
107c2c66affSColin Finck VOID
CloseProcessAndVerify_(_In_ HANDLE hProcess,_In_ DWORD ProcessId,_In_ UINT ExpectedExitCode,_In_ PCSTR File,_In_ INT Line)108c2c66affSColin Finck CloseProcessAndVerify_(
109c2c66affSColin Finck _In_ HANDLE hProcess,
110c2c66affSColin Finck _In_ DWORD ProcessId,
111c2c66affSColin Finck _In_ UINT ExpectedExitCode,
112c2c66affSColin Finck _In_ PCSTR File,
113c2c66affSColin Finck _In_ INT Line)
114c2c66affSColin Finck {
115c2c66affSColin Finck int i = 0;
116c2c66affSColin Finck DWORD Error;
117c2c66affSColin Finck DWORD ExitCode;
118c2c66affSColin Finck BOOL Success;
119c2c66affSColin Finck
120c2c66affSColin Finck WaitExpect_(hProcess, 0, WAIT_OBJECT_0, File, Line);
121c2c66affSColin Finck Success = GetExitCodeProcess(hProcess, &ExitCode);
122c2c66affSColin Finck ok_(File, Line)(Success, "GetExitCodeProcess failed with %lu\n", GetLastError());
123c2c66affSColin Finck CloseHandle(hProcess);
124c2c66affSColin Finck while ((hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ProcessId)) != NULL)
125c2c66affSColin Finck {
126c2c66affSColin Finck if (++i >= 100)
127c2c66affSColin Finck {
128c2c66affSColin Finck TraceHandleCount_(hProcess, File, Line);
129c2c66affSColin Finck CloseHandle(hProcess);
130c2c66affSColin Finck break;
131c2c66affSColin Finck }
132c2c66affSColin Finck CloseHandle(hProcess);
133c2c66affSColin Finck Sleep(100);
134c2c66affSColin Finck }
135c2c66affSColin Finck Error = GetLastError();
136c2c66affSColin Finck ok_(File, Line)(hProcess == NULL, "OpenProcess succeeded unexpectedly for pid 0x%lx\n", ProcessId);
137c2c66affSColin Finck ok_(File, Line)(Error == ERROR_INVALID_PARAMETER, "Error = %lu\n", Error);
138c2c66affSColin Finck ok_(File, Line)(ExitCode == ExpectedExitCode, "Exit code is %lu but expected %u\n", ExitCode, ExpectedExitCode);
139c2c66affSColin Finck }
140c2c66affSColin Finck
141c2c66affSColin Finck static
142c2c66affSColin Finck VOID
TestTerminateProcess(_In_ HANDLE hEvent)143c2c66affSColin Finck TestTerminateProcess(
144c2c66affSColin Finck _In_ HANDLE hEvent)
145c2c66affSColin Finck {
146c2c66affSColin Finck HANDLE hProcess;
147c2c66affSColin Finck DWORD ProcessId;
148c2c66affSColin Finck
149c2c66affSColin Finck /* Regular child process that returns from the test function */
150c2c66affSColin Finck /* HACK: These two tests don't work if stdout is a pipe. See StartChild */
151c2c66affSColin Finck ResetEvent(hEvent);
152c2c66affSColin Finck hProcess = StartChild(L"child", 0, &ProcessId);
153c2c66affSColin Finck WaitExpectSuccess(hEvent, 5000);
154c2c66affSColin Finck WaitExpectSuccess(hProcess, 5000);
155c2c66affSColin Finck CloseProcessAndVerify(hProcess, ProcessId, 0);
156c2c66affSColin Finck
157c2c66affSColin Finck ResetEvent(hEvent);
158c2c66affSColin Finck hProcess = StartChild(L"child", 0, &ProcessId);
159c2c66affSColin Finck WaitExpectSuccess(hProcess, 5000);
160c2c66affSColin Finck WaitExpectSuccess(hEvent, 0);
161c2c66affSColin Finck CloseProcessAndVerify(hProcess, ProcessId, 0);
162c2c66affSColin Finck
163c2c66affSColin Finck /* Suspended process -- never gets a chance to initialize */
164c2c66affSColin Finck ResetEvent(hEvent);
165c2c66affSColin Finck hProcess = StartChild(L"child", CREATE_SUSPENDED, &ProcessId);
166c2c66affSColin Finck WaitExpectTimeout(hEvent, 100);
167c2c66affSColin Finck WaitExpectTimeout(hProcess, 100);
168c2c66affSColin Finck TerminateProcess(hProcess, 123);
169c2c66affSColin Finck WaitExpectSuccess(hProcess, 5000);
170c2c66affSColin Finck CloseProcessAndVerify(hProcess, ProcessId, 123);
171c2c66affSColin Finck
172c2c66affSColin Finck /* Waiting process -- we have to terminate it */
173c2c66affSColin Finck ResetEvent(hEvent);
174c2c66affSColin Finck hProcess = StartChild(L"wait", 0, &ProcessId);
175c2c66affSColin Finck WaitExpectTimeout(hProcess, 100);
176c2c66affSColin Finck TerminateProcess(hProcess, 123);
177c2c66affSColin Finck WaitExpectSuccess(hProcess, 5000);
178c2c66affSColin Finck CloseProcessAndVerify(hProcess, ProcessId, 123);
179c2c66affSColin Finck
180c2c66affSColin Finck /* Process calls ExitProcess */
181c2c66affSColin Finck ResetEvent(hEvent);
182c2c66affSColin Finck hProcess = StartChild(L"child exit 456", 0, &ProcessId);
183c2c66affSColin Finck WaitExpectSuccess(hEvent, 5000);
184c2c66affSColin Finck WaitExpectSuccess(hProcess, 5000);
185c2c66affSColin Finck CloseProcessAndVerify(hProcess, ProcessId, 456);
186c2c66affSColin Finck
187c2c66affSColin Finck /* Process calls TerminateProcess with GetCurrentProcess */
188c2c66affSColin Finck ResetEvent(hEvent);
189c2c66affSColin Finck hProcess = StartChild(L"child terminate 456", 0, &ProcessId);
190c2c66affSColin Finck WaitExpectSuccess(hEvent, 5000);
191c2c66affSColin Finck WaitExpectSuccess(hProcess, 5000);
192c2c66affSColin Finck CloseProcessAndVerify(hProcess, ProcessId, 456);
193c2c66affSColin Finck
194c2c66affSColin Finck /* Process calls TerminateProcess with real handle to itself */
195c2c66affSColin Finck ResetEvent(hEvent);
196c2c66affSColin Finck hProcess = StartChild(L"child terminate2 456", 0, &ProcessId);
197c2c66affSColin Finck WaitExpectSuccess(hEvent, 5000);
198c2c66affSColin Finck WaitExpectSuccess(hProcess, 5000);
199c2c66affSColin Finck CloseProcessAndVerify(hProcess, ProcessId, 456);
200c2c66affSColin Finck }
201c2c66affSColin Finck
START_TEST(TerminateProcess)202c2c66affSColin Finck START_TEST(TerminateProcess)
203c2c66affSColin Finck {
204c2c66affSColin Finck HANDLE hEvent;
205c2c66affSColin Finck BOOL Success;
206c2c66affSColin Finck DWORD Error;
207c2c66affSColin Finck int argc;
208c2c66affSColin Finck char **argv;
209c2c66affSColin Finck
210c2c66affSColin Finck hEvent = CreateEventW(NULL, TRUE, FALSE, L"kernel32_apitest_TerminateProcess_event");
211c2c66affSColin Finck Error = GetLastError();
212c2c66affSColin Finck if (!hEvent)
213c2c66affSColin Finck {
214c2c66affSColin Finck skip("CreateEvent failed with error %lu\n", Error);
215c2c66affSColin Finck return;
216c2c66affSColin Finck }
217c2c66affSColin Finck argc = winetest_get_mainargs(&argv);
218c2c66affSColin Finck if (argc >= 3)
219c2c66affSColin Finck {
220c2c66affSColin Finck ok(Error == ERROR_ALREADY_EXISTS, "Error = %lu\n", Error);
221c2c66affSColin Finck if (!strcmp(argv[2], "wait"))
222c2c66affSColin Finck {
223c2c66affSColin Finck WaitExpectSuccess(hEvent, 30000);
224c2c66affSColin Finck }
225c2c66affSColin Finck else
226c2c66affSColin Finck {
227c2c66affSColin Finck Success = SetEvent(hEvent);
228c2c66affSColin Finck ok(Success, "SetEvent failed with return %d, error %lu\n", Success, GetLastError());
229c2c66affSColin Finck }
230c2c66affSColin Finck }
231c2c66affSColin Finck else
232c2c66affSColin Finck {
233c2c66affSColin Finck ok(Error == NO_ERROR, "Error = %lu\n", Error);
234c2c66affSColin Finck TestTerminateProcess(hEvent);
235c2c66affSColin Finck }
236c2c66affSColin Finck CloseHandle(hEvent);
237c2c66affSColin Finck if (argc >= 5)
238c2c66affSColin Finck {
239c2c66affSColin Finck UINT ExitCode = strtol(argv[4], NULL, 10);
240c2c66affSColin Finck
241c2c66affSColin Finck fflush(stdout);
242c2c66affSColin Finck if (!strcmp(argv[3], "exit"))
243c2c66affSColin Finck ExitProcess(ExitCode);
244c2c66affSColin Finck else if (!strcmp(argv[3], "terminate"))
245c2c66affSColin Finck TerminateProcess(GetCurrentProcess(), ExitCode);
246c2c66affSColin Finck else if (!strcmp(argv[3], "terminate2"))
247c2c66affSColin Finck {
248c2c66affSColin Finck HANDLE hProcess;
249c2c66affSColin Finck hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, GetCurrentProcessId());
250c2c66affSColin Finck TerminateProcess(hProcess, ExitCode);
251c2c66affSColin Finck }
252c2c66affSColin Finck ok(0, "Should have terminated\n");
253c2c66affSColin Finck }
254c2c66affSColin Finck }
255