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