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