2 * PROJECT: ReactOS api tests
3 * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory
4 * PURPOSE: Support helpers for embedded services inside api tests.
5 * PROGRAMMERS: Jacek Caban for CodeWeavers
6 * Thomas Faber <thomas.faber@reactos.org>
9 * NOTE: Room for improvements:
10 * - One test_runner managing 1 pipe for 1 service process that is shared
11 * by multiple services of type SERVICE_WIN32_SHARE_PROCESS.
12 * - Find a way to elegantly determine the registered service name inside
13 * the service process, without really passing it
18 static HANDLE hClientPipe
= INVALID_HANDLE_VALUE
;
19 static WCHAR named_pipe_name
[100]; // Shared: FIXME!
21 static CHAR service_nameA
[100];
22 static WCHAR service_nameW
[100];
25 /********** S E R V I C E ( C L I E N T ) M O D U L E S I D E *********/
27 void send_msg(const char *type
, const char *msg
)
32 StringCbPrintfA(buf
, sizeof(buf
), "%s:%s", type
, msg
);
33 WriteFile(hClientPipe
, buf
, lstrlenA(buf
)+1, &written
, NULL
);
36 void service_trace(const char *msg
, ...)
41 va_start(valist
, msg
);
42 StringCbVPrintfA(buf
, sizeof(buf
), msg
, valist
);
45 send_msg("TRACE", buf
);
48 void service_ok(int cnd
, const char *msg
, ...)
53 va_start(valist
, msg
);
54 StringCbVPrintfA(buf
, sizeof(buf
), msg
, valist
);
57 send_msg(cnd
? "OK" : "FAIL", buf
);
60 void service_process(BOOL (*start_service
)(PCSTR
, PCWSTR
), int argc
, char** argv
)
64 StringCbCopyA(service_nameA
, sizeof(service_nameA
), argv
[2]);
65 MultiByteToWideChar(CP_ACP
, 0, service_nameA
, -1, service_nameW
, _countof(service_nameW
));
66 StringCbPrintfW(named_pipe_name
, sizeof(named_pipe_name
), L
"\\\\.\\pipe\\%ls_pipe", service_nameW
);
68 res
= WaitNamedPipeW(named_pipe_name
, NMPWAIT_USE_DEFAULT_WAIT
);
72 hClientPipe
= CreateFileW(named_pipe_name
, GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
73 if (hClientPipe
== INVALID_HANDLE_VALUE
)
76 service_trace("Service process starting...\n");
77 res
= start_service(service_nameA
, service_nameW
);
78 service_trace("Service process stopped.\n");
80 CloseHandle(hClientPipe
);
84 /*********** T E S T E R ( S E R V E R ) M O D U L E S I D E **********/
86 SC_HANDLE
register_service_exA(
89 PCSTR service_name
, // LPCSTR lpServiceName,
90 PCSTR extra_args OPTIONAL
,
91 DWORD dwDesiredAccess
,
95 LPCSTR lpLoadOrderGroup OPTIONAL
,
96 LPDWORD lpdwTagId OPTIONAL
,
97 LPCSTR lpDependencies OPTIONAL
,
98 LPCSTR lpServiceStartName OPTIONAL
,
99 LPCSTR lpPassword OPTIONAL
)
102 CHAR service_cmd
[MAX_PATH
+150];
104 /* Retrieve our full path */
105 if (!GetModuleFileNameA(NULL
, service_cmd
, MAX_PATH
))
107 skip("GetModuleFileNameW failed with error %lu!\n", GetLastError());
112 * Build up our custom command line. The first parameter is the test name,
113 * the second parameter is the flag used to decide whether we should start
116 StringCbCatA(service_cmd
, sizeof(service_cmd
), " ");
117 StringCbCatA(service_cmd
, sizeof(service_cmd
), test_name
);
118 StringCbCatA(service_cmd
, sizeof(service_cmd
), " ");
119 StringCbCatA(service_cmd
, sizeof(service_cmd
), service_name
);
122 StringCbCatA(service_cmd
, sizeof(service_cmd
), " ");
123 StringCbCatA(service_cmd
, sizeof(service_cmd
), extra_args
);
126 trace("service_cmd \"%s\"\n", service_cmd
);
128 service
= CreateServiceA(scm_handle
, service_name
, service_name
,
129 dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
130 service_cmd
, lpLoadOrderGroup
, lpdwTagId
, lpDependencies
,
131 lpServiceStartName
, lpPassword
);
132 if (!service
&& GetLastError() == ERROR_ACCESS_DENIED
)
134 skip("Not enough access right to create service.\n");
138 ok(service
!= NULL
, "CreateService failed: %lu\n", GetLastError());
142 SC_HANDLE
register_service_exW(
143 SC_HANDLE scm_handle
,
145 PCWSTR service_name
, // LPCWSTR lpServiceName,
146 PCWSTR extra_args OPTIONAL
,
147 DWORD dwDesiredAccess
,
150 DWORD dwErrorControl
,
151 LPCWSTR lpLoadOrderGroup OPTIONAL
,
152 LPDWORD lpdwTagId OPTIONAL
,
153 LPCWSTR lpDependencies OPTIONAL
,
154 LPCWSTR lpServiceStartName OPTIONAL
,
155 LPCWSTR lpPassword OPTIONAL
)
158 WCHAR service_cmd
[MAX_PATH
+150];
160 /* Retrieve our full path */
161 if (!GetModuleFileNameW(NULL
, service_cmd
, MAX_PATH
))
163 skip("GetModuleFileNameW failed with error %lu!\n", GetLastError());
168 * Build up our custom command line. The first parameter is the test name,
169 * the second parameter is the flag used to decide whether we should start
172 StringCbCatW(service_cmd
, sizeof(service_cmd
), L
" ");
173 StringCbCatW(service_cmd
, sizeof(service_cmd
), test_name
);
174 StringCbCatW(service_cmd
, sizeof(service_cmd
), L
" ");
175 StringCbCatW(service_cmd
, sizeof(service_cmd
), service_name
);
178 StringCbCatW(service_cmd
, sizeof(service_cmd
), L
" ");
179 StringCbCatW(service_cmd
, sizeof(service_cmd
), extra_args
);
182 trace("service_cmd \"%ls\"\n", service_cmd
);
184 service
= CreateServiceW(scm_handle
, service_name
, service_name
,
185 dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
186 service_cmd
, lpLoadOrderGroup
, lpdwTagId
, lpDependencies
,
187 lpServiceStartName
, lpPassword
);
188 if (!service
&& GetLastError() == ERROR_ACCESS_DENIED
)
190 skip("Not enough access right to create service.\n");
194 ok(service
!= NULL
, "CreateService failed: %lu\n", GetLastError());
198 SC_HANDLE
register_serviceA(
199 SC_HANDLE scm_handle
,
202 PCSTR extra_args OPTIONAL
)
204 return register_service_exA(scm_handle
, test_name
, service_name
, extra_args
,
206 SERVICE_WIN32_OWN_PROCESS
,
207 SERVICE_DEMAND_START
,
208 SERVICE_ERROR_IGNORE
,
209 NULL
, NULL
, NULL
, NULL
, NULL
);
212 SC_HANDLE
register_serviceW(
213 SC_HANDLE scm_handle
,
216 PCWSTR extra_args OPTIONAL
)
218 return register_service_exW(scm_handle
, test_name
, service_name
, extra_args
,
220 SERVICE_WIN32_OWN_PROCESS
,
221 SERVICE_DEMAND_START
,
222 SERVICE_ERROR_IGNORE
,
223 NULL
, NULL
, NULL
, NULL
, NULL
);
226 static DWORD WINAPI
pipe_thread(void *param
)
228 HANDLE hServerPipe
= (HANDLE
)param
;
233 // printf("pipe_thread -- ConnectNamedPipe...\n");
234 res
= ConnectNamedPipe(hServerPipe
, NULL
);
235 ok(res
|| GetLastError() == ERROR_PIPE_CONNECTED
, "ConnectNamedPipe failed: %lu\n", GetLastError());
236 // printf("pipe_thread -- ConnectNamedPipe ok\n");
240 res
= ReadFile(hServerPipe
, buf
, sizeof(buf
), &read
, NULL
);
243 ok(GetLastError() == ERROR_BROKEN_PIPE
|| GetLastError() == ERROR_INVALID_HANDLE
,
244 "ReadFile failed: %lu\n", GetLastError());
245 // printf("pipe_thread -- break loop\n");
249 if (!strncmp(buf
, "TRACE:", 6))
251 trace("service trace: %s", buf
+6);
253 else if (!strncmp(buf
, "OK:", 3))
255 ok(1, "service: %s", buf
+3);
257 else if (!strncmp(buf
, "FAIL:", 5))
259 ok(0, "service: %s", buf
+5);
263 ok(0, "malformed service message: %s\n", buf
);
267 // printf("pipe_thread -- DisconnectNamedPipe\n");
270 * Flush the pipe to allow the client to read
271 * the pipe's contents before disconnecting.
273 FlushFileBuffers(hServerPipe
);
275 DisconnectNamedPipe(hServerPipe
);
276 trace("pipe disconnected\n");
280 void test_runner(void (*run_test
)(PCSTR
, PCWSTR
, void*), void *param
)
282 HANDLE hServerPipe
= INVALID_HANDLE_VALUE
;
285 StringCbPrintfW(service_nameW
, sizeof(service_nameW
), L
"WineTestService%lu", GetTickCount());
286 WideCharToMultiByte(CP_ACP
, 0, service_nameW
, -1, service_nameA
, _countof(service_nameA
), NULL
, NULL
);
287 //trace("service_name: %ls\n", service_nameW);
288 StringCbPrintfW(named_pipe_name
, sizeof(named_pipe_name
), L
"\\\\.\\pipe\\%ls_pipe", service_nameW
);
290 hServerPipe
= CreateNamedPipeW(named_pipe_name
, PIPE_ACCESS_INBOUND
,
291 PIPE_TYPE_MESSAGE
|PIPE_READMODE_MESSAGE
|PIPE_WAIT
, 10, 2048, 2048, 10000, NULL
);
292 ok(hServerPipe
!= INVALID_HANDLE_VALUE
, "CreateNamedPipe failed: %lu\n", GetLastError());
293 if (hServerPipe
== INVALID_HANDLE_VALUE
)
296 hThread
= CreateThread(NULL
, 0, pipe_thread
, (LPVOID
)hServerPipe
, 0, NULL
);
297 ok(hThread
!= NULL
, "CreateThread failed: %lu\n", GetLastError());
301 run_test(service_nameA
, service_nameW
, param
);
303 ok(WaitForSingleObject(hThread
, 10000) == WAIT_OBJECT_0
, "Timeout waiting for thread\n");
308 /* Be sure to kill the thread if it did not already terminate */
309 TerminateThread(hThread
, 0);
310 CloseHandle(hThread
);
313 if (hServerPipe
!= INVALID_HANDLE_VALUE
)
314 CloseHandle(hServerPipe
);