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
21 static HANDLE hClientPipe
= INVALID_HANDLE_VALUE
;
22 static WCHAR named_pipe_name
[100]; // Shared: FIXME!
24 static CHAR service_nameA
[100];
25 static WCHAR service_nameW
[100];
28 /********** S E R V I C E ( C L I E N T ) M O D U L E S I D E *********/
30 void send_msg(const char *type
, const char *msg
)
35 StringCbPrintfA(buf
, sizeof(buf
), "%s:%s", type
, msg
);
36 WriteFile(hClientPipe
, buf
, strlen(buf
)+1, &written
, NULL
);
39 void service_trace(const char *msg
, ...)
44 va_start(valist
, msg
);
45 StringCbVPrintfA(buf
, sizeof(buf
), msg
, valist
);
48 send_msg("TRACE", buf
);
51 void service_ok(int cnd
, const char *msg
, ...)
56 va_start(valist
, msg
);
57 StringCbVPrintfA(buf
, sizeof(buf
), msg
, valist
);
60 send_msg(cnd
? "OK" : "FAIL", buf
);
63 void service_process(BOOL (*start_service
)(PCSTR
, PCWSTR
), int argc
, char** argv
)
67 StringCbCopyA(service_nameA
, sizeof(service_nameA
), argv
[2]);
68 MultiByteToWideChar(CP_ACP
, 0, service_nameA
, -1, service_nameW
, _countof(service_nameW
));
69 StringCbPrintfW(named_pipe_name
, sizeof(named_pipe_name
), L
"\\\\.\\pipe\\%ls_pipe", service_nameW
);
71 res
= WaitNamedPipeW(named_pipe_name
, NMPWAIT_USE_DEFAULT_WAIT
);
75 hClientPipe
= CreateFileW(named_pipe_name
, GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
76 if (hClientPipe
== INVALID_HANDLE_VALUE
)
79 service_trace("Service process starting...\n");
80 res
= start_service(service_nameA
, service_nameW
);
81 service_trace("Service process stopped.\n");
83 CloseHandle(hClientPipe
);
87 /*********** T E S T E R ( S E R V E R ) M O D U L E S I D E **********/
89 SC_HANDLE
register_service_exA(
92 PCSTR service_name
, // LPCSTR lpServiceName,
93 PCSTR extra_args OPTIONAL
,
94 DWORD dwDesiredAccess
,
98 LPCSTR lpLoadOrderGroup OPTIONAL
,
99 LPDWORD lpdwTagId OPTIONAL
,
100 LPCSTR lpDependencies OPTIONAL
,
101 LPCSTR lpServiceStartName OPTIONAL
,
102 LPCSTR lpPassword OPTIONAL
)
105 CHAR service_cmd
[MAX_PATH
+150];
107 /* Retrieve our full path */
108 if (!GetModuleFileNameA(NULL
, service_cmd
, MAX_PATH
))
110 skip("GetModuleFileNameW failed with error %lu!\n", GetLastError());
115 * Build up our custom command line. The first parameter is the test name,
116 * the second parameter is the flag used to decide whether we should start
119 StringCbCatA(service_cmd
, sizeof(service_cmd
), " ");
120 StringCbCatA(service_cmd
, sizeof(service_cmd
), test_name
);
121 StringCbCatA(service_cmd
, sizeof(service_cmd
), " ");
122 StringCbCatA(service_cmd
, sizeof(service_cmd
), service_name
);
125 StringCbCatA(service_cmd
, sizeof(service_cmd
), " ");
126 StringCbCatA(service_cmd
, sizeof(service_cmd
), extra_args
);
129 trace("service_cmd \"%s\"\n", service_cmd
);
131 service
= CreateServiceA(scm_handle
, service_name
, service_name
,
132 dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
133 service_cmd
, lpLoadOrderGroup
, lpdwTagId
, lpDependencies
,
134 lpServiceStartName
, lpPassword
);
135 if (!service
&& GetLastError() == ERROR_ACCESS_DENIED
)
137 skip("Not enough access right to create service.\n");
141 ok(service
!= NULL
, "CreateService failed: %lu\n", GetLastError());
145 SC_HANDLE
register_service_exW(
146 SC_HANDLE scm_handle
,
148 PCWSTR service_name
, // LPCWSTR lpServiceName,
149 PCWSTR extra_args OPTIONAL
,
150 DWORD dwDesiredAccess
,
153 DWORD dwErrorControl
,
154 LPCWSTR lpLoadOrderGroup OPTIONAL
,
155 LPDWORD lpdwTagId OPTIONAL
,
156 LPCWSTR lpDependencies OPTIONAL
,
157 LPCWSTR lpServiceStartName OPTIONAL
,
158 LPCWSTR lpPassword OPTIONAL
)
161 WCHAR service_cmd
[MAX_PATH
+150];
163 /* Retrieve our full path */
164 if (!GetModuleFileNameW(NULL
, service_cmd
, MAX_PATH
))
166 skip("GetModuleFileNameW failed with error %lu!\n", GetLastError());
171 * Build up our custom command line. The first parameter is the test name,
172 * the second parameter is the flag used to decide whether we should start
175 StringCbCatW(service_cmd
, sizeof(service_cmd
), L
" ");
176 StringCbCatW(service_cmd
, sizeof(service_cmd
), test_name
);
177 StringCbCatW(service_cmd
, sizeof(service_cmd
), L
" ");
178 StringCbCatW(service_cmd
, sizeof(service_cmd
), service_name
);
181 StringCbCatW(service_cmd
, sizeof(service_cmd
), L
" ");
182 StringCbCatW(service_cmd
, sizeof(service_cmd
), extra_args
);
185 trace("service_cmd \"%ls\"\n", service_cmd
);
187 service
= CreateServiceW(scm_handle
, service_name
, service_name
,
188 dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
189 service_cmd
, lpLoadOrderGroup
, lpdwTagId
, lpDependencies
,
190 lpServiceStartName
, lpPassword
);
191 if (!service
&& GetLastError() == ERROR_ACCESS_DENIED
)
193 skip("Not enough access right to create service.\n");
197 ok(service
!= NULL
, "CreateService failed: %lu\n", GetLastError());
201 SC_HANDLE
register_serviceA(
202 SC_HANDLE scm_handle
,
205 PCSTR extra_args OPTIONAL
)
207 return register_service_exA(scm_handle
, test_name
, service_name
, extra_args
,
209 SERVICE_WIN32_OWN_PROCESS
,
210 SERVICE_DEMAND_START
,
211 SERVICE_ERROR_IGNORE
,
212 NULL
, NULL
, NULL
, NULL
, NULL
);
215 SC_HANDLE
register_serviceW(
216 SC_HANDLE scm_handle
,
219 PCWSTR extra_args OPTIONAL
)
221 return register_service_exW(scm_handle
, test_name
, service_name
, extra_args
,
223 SERVICE_WIN32_OWN_PROCESS
,
224 SERVICE_DEMAND_START
,
225 SERVICE_ERROR_IGNORE
,
226 NULL
, NULL
, NULL
, NULL
, NULL
);
229 static DWORD WINAPI
pipe_thread(void *param
)
231 HANDLE hServerPipe
= (HANDLE
)param
;
236 // printf("pipe_thread -- ConnectNamedPipe...\n");
237 res
= ConnectNamedPipe(hServerPipe
, NULL
);
238 ok(res
|| GetLastError() == ERROR_PIPE_CONNECTED
, "ConnectNamedPipe failed: %lu\n", GetLastError());
239 // printf("pipe_thread -- ConnectNamedPipe ok\n");
243 res
= ReadFile(hServerPipe
, buf
, sizeof(buf
), &read
, NULL
);
246 ok(GetLastError() == ERROR_BROKEN_PIPE
|| GetLastError() == ERROR_INVALID_HANDLE
,
247 "ReadFile failed: %lu\n", GetLastError());
248 // printf("pipe_thread -- break loop\n");
252 if (!strncmp(buf
, "TRACE:", 6))
254 trace("service trace: %s", buf
+6);
256 else if (!strncmp(buf
, "OK:", 3))
258 ok(1, "service: %s", buf
+3);
260 else if (!strncmp(buf
, "FAIL:", 5))
262 ok(0, "service: %s", buf
+5);
266 ok(0, "malformed service message: %s\n", buf
);
270 // printf("pipe_thread -- DisconnectNamedPipe\n");
273 * Flush the pipe to allow the client to read
274 * the pipe's contents before disconnecting.
276 FlushFileBuffers(hServerPipe
);
278 DisconnectNamedPipe(hServerPipe
);
279 trace("pipe disconnected\n");
283 void test_runner(void (*run_test
)(PCSTR
, PCWSTR
, void*), void *param
)
285 HANDLE hServerPipe
= INVALID_HANDLE_VALUE
;
288 StringCbPrintfW(service_nameW
, sizeof(service_nameW
), L
"WineTestService%lu", GetTickCount());
289 WideCharToMultiByte(CP_ACP
, 0, service_nameW
, -1, service_nameA
, _countof(service_nameA
), NULL
, NULL
);
290 //trace("service_name: %ls\n", service_nameW);
291 StringCbPrintfW(named_pipe_name
, sizeof(named_pipe_name
), L
"\\\\.\\pipe\\%ls_pipe", service_nameW
);
293 hServerPipe
= CreateNamedPipeW(named_pipe_name
, PIPE_ACCESS_INBOUND
,
294 PIPE_TYPE_MESSAGE
|PIPE_READMODE_MESSAGE
|PIPE_WAIT
, 10, 2048, 2048, 10000, NULL
);
295 ok(hServerPipe
!= INVALID_HANDLE_VALUE
, "CreateNamedPipe failed: %lu\n", GetLastError());
296 if (hServerPipe
== INVALID_HANDLE_VALUE
)
299 hThread
= CreateThread(NULL
, 0, pipe_thread
, (LPVOID
)hServerPipe
, 0, NULL
);
300 ok(hThread
!= NULL
, "CreateThread failed: %lu\n", GetLastError());
304 run_test(service_nameA
, service_nameW
, param
);
306 ok(WaitForSingleObject(hThread
, 10000) == WAIT_OBJECT_0
, "Timeout waiting for thread\n");
311 /* Be sure to kill the thread if it did not already terminate */
312 TerminateThread(hThread
, 0);
313 CloseHandle(hThread
);
316 if (hServerPipe
!= INVALID_HANDLE_VALUE
)
317 CloseHandle(hServerPipe
);