2 * Copyright 2012 Jacek Caban for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/test.h"
24 static SERVICE_STATUS_HANDLE (WINAPI *pRegisterServiceCtrlHandlerExA)(LPCSTR,LPHANDLER_FUNCTION_EX,LPVOID);
26 static HANDLE pipe_handle = INVALID_HANDLE_VALUE;
27 static char service_name[100], named_pipe_name[100];
28 static SERVICE_STATUS_HANDLE service_handle;
30 /* Service process global variables */
31 static HANDLE service_stop_event;
33 static void send_msg(const char *type, const char *msg)
38 sprintf(buf, "%s:%s", type, msg);
39 WriteFile(pipe_handle, buf, strlen(buf)+1, &written, NULL);
42 static inline void service_trace(const char *msg)
44 send_msg("TRACE", msg);
47 static inline void service_event(const char *event)
49 send_msg("EVENT", event);
52 static void service_ok(int cnd, const char *msg, ...)
57 va_start(valist, msg);
58 vsprintf(buf, msg, valist);
61 send_msg(cnd ? "OK" : "FAIL", buf);
64 static DWORD WINAPI service_handler(DWORD ctrl, DWORD event_type, void *event_data, void *context)
66 SERVICE_STATUS status;
68 status.dwServiceType = SERVICE_WIN32;
69 status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
70 status.dwWin32ExitCode = 0;
71 status.dwServiceSpecificExitCode = 0;
72 status.dwCheckPoint = 0;
73 status.dwWaitHint = 0;
77 case SERVICE_CONTROL_STOP:
78 case SERVICE_CONTROL_SHUTDOWN:
79 service_event("STOP");
80 status.dwCurrentState = SERVICE_STOP_PENDING;
81 status.dwControlsAccepted = 0;
82 SetServiceStatus(service_handle, &status);
83 SetEvent(service_stop_event);
86 status.dwCurrentState = SERVICE_RUNNING;
87 SetServiceStatus( service_handle, &status );
92 static void WINAPI service_main(DWORD argc, char **argv)
94 SERVICE_STATUS status;
97 service_ok(argc == 1, "argc = %d", argc);
99 service_ok(!strcmp(argv[0], service_name), "argv[0] = %s, expected %s", argv[0], service_name);
101 service_handle = pRegisterServiceCtrlHandlerExA(service_name, service_handler, NULL);
102 service_ok(service_handle != NULL, "RegisterServiceCtrlHandlerEx failed: %u\n", GetLastError());
106 status.dwServiceType = SERVICE_WIN32;
107 status.dwCurrentState = SERVICE_RUNNING;
108 status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
109 status.dwWin32ExitCode = 0;
110 status.dwServiceSpecificExitCode = 0;
111 status.dwCheckPoint = 0;
112 status.dwWaitHint = 10000;
113 res = SetServiceStatus(service_handle, &status);
114 service_ok(res, "SetServiceStatus(SERVICE_RUNNING) failed: %u", GetLastError());
116 service_event("RUNNING");
118 WaitForSingleObject(service_stop_event, INFINITE);
120 status.dwCurrentState = SERVICE_STOPPED;
121 status.dwControlsAccepted = 0;
122 res = SetServiceStatus(service_handle, &status);
123 service_ok(res, "SetServiceStatus(SERVICE_STOPPED) failed: %u", GetLastError());
126 static void service_process(void (WINAPI *p_service_main)(DWORD, char **))
130 SERVICE_TABLE_ENTRYA servtbl[] = {
131 {service_name, p_service_main},
135 res = WaitNamedPipeA(named_pipe_name, NMPWAIT_USE_DEFAULT_WAIT);
139 pipe_handle = CreateFileA(named_pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
140 if(pipe_handle == INVALID_HANDLE_VALUE)
143 service_trace("Starting...");
145 service_stop_event = CreateEventA(NULL, TRUE, FALSE, NULL);
146 service_ok(service_stop_event != NULL, "Could not create event: %u\n", GetLastError());
147 if(!service_stop_event)
150 res = StartServiceCtrlDispatcherA(servtbl);
151 service_ok(res, "StartServiceCtrlDispatcher failed: %u\n", GetLastError());
153 /* Let service thread terminate */
156 CloseHandle(service_stop_event);
157 CloseHandle(pipe_handle);
160 static DWORD WINAPI no_stop_handler(DWORD ctrl, DWORD event_type, void *event_data, void *context)
162 SERVICE_STATUS status;
164 status.dwServiceType = SERVICE_WIN32;
165 status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
166 status.dwWin32ExitCode = 0;
167 status.dwServiceSpecificExitCode = 0;
168 status.dwCheckPoint = 0;
169 status.dwWaitHint = 0;
173 case SERVICE_CONTROL_STOP:
174 case SERVICE_CONTROL_SHUTDOWN:
175 service_event("STOP");
176 status.dwCurrentState = SERVICE_STOPPED;
177 status.dwControlsAccepted = 0;
178 SetServiceStatus(service_handle, &status);
179 SetEvent(service_stop_event);
182 status.dwCurrentState = SERVICE_RUNNING;
183 SetServiceStatus( service_handle, &status );
188 static void WINAPI no_stop_main(DWORD argc, char **argv)
190 SERVICE_STATUS status;
193 service_ok(argc == 1, "argc = %d", argc);
195 service_ok(!strcmp(argv[0], service_name), "argv[0] = %s, expected %s", argv[0], service_name);
197 service_handle = pRegisterServiceCtrlHandlerExA(service_name, no_stop_handler, NULL);
198 service_ok(service_handle != NULL, "RegisterServiceCtrlHandlerEx failed: %u\n", GetLastError());
202 status.dwServiceType = SERVICE_WIN32;
203 status.dwCurrentState = SERVICE_RUNNING;
204 status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
205 status.dwWin32ExitCode = 0;
206 status.dwServiceSpecificExitCode = 0;
207 status.dwCheckPoint = 0;
208 status.dwWaitHint = 10000;
209 res = SetServiceStatus(service_handle, &status);
210 service_ok(res, "SetServiceStatus(SERVICE_RUNNING) failed: %u", GetLastError());
212 service_event("RUNNING");
215 /* Test process global variables */
216 static SC_HANDLE scm_handle;
218 static char current_event[32];
219 static HANDLE event_handle = INVALID_HANDLE_VALUE;
220 static CRITICAL_SECTION event_cs;
222 static SC_HANDLE register_service(const char *test_name)
224 char service_cmd[MAX_PATH+150], *ptr;
227 ptr = service_cmd + GetModuleFileNameA(NULL, service_cmd, MAX_PATH);
229 /* If the file doesn't exist, assume we're using built-in exe and append .so to the path */
230 if(GetFileAttributesA(service_cmd) == INVALID_FILE_ATTRIBUTES) {
235 strcpy(ptr, " service ");
237 sprintf(ptr, "%s ", test_name);
239 strcpy(ptr, service_name);
241 trace("service_cmd \"%s\"\n", service_cmd);
243 service = CreateServiceA(scm_handle, service_name, service_name, GENERIC_ALL,
244 SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE,
245 service_cmd, NULL, NULL, NULL, NULL, NULL);
246 if(!service && GetLastError() == ERROR_ACCESS_DENIED) {
247 skip("Not enough access right to create service\n");
251 ok(service != NULL, "CreateService failed: %u\n", GetLastError());
255 static void expect_event(const char *event_name)
260 trace("waiting for %s\n", event_name);
262 res = WaitForSingleObject(event_handle, 30000);
263 ok(res == WAIT_OBJECT_0, "WaitForSingleObject failed: %u\n", res);
264 if(res != WAIT_OBJECT_0)
267 EnterCriticalSection(&event_cs);
268 strcpy(evt, current_event);
270 LeaveCriticalSection(&event_cs);
272 ok(!strcmp(evt, event_name), "Unexpected event: %s, expected %s\n", evt, event_name);
275 static DWORD WINAPI pipe_thread(void *arg)
281 res = ConnectNamedPipe(pipe_handle, NULL);
282 ok(res || GetLastError() == ERROR_PIPE_CONNECTED, "ConnectNamedPipe failed: %u\n", GetLastError());
285 res = ReadFile(pipe_handle, buf, sizeof(buf), &read, NULL);
287 ok(GetLastError() == ERROR_BROKEN_PIPE || GetLastError() == ERROR_INVALID_HANDLE,
288 "ReadFile failed: %u\n", GetLastError());
292 for(ptr = buf; ptr < buf+read; ptr += strlen(ptr)+1) {
293 if(!strncmp(ptr, "TRACE:", 6)) {
294 trace("service trace: %s\n", ptr+6);
295 }else if(!strncmp(ptr, "OK:", 3)) {
296 ok(1, "service: %s\n", ptr+3);
297 }else if(!strncmp(ptr, "FAIL:", 5)) {
298 ok(0, "service: %s\n", ptr+5);
299 }else if(!strncmp(ptr, "EVENT:", 6)) {
300 trace("service event: %s\n", ptr+6);
301 EnterCriticalSection(&event_cs);
302 ok(!current_event[0], "event %s still queued\n", current_event);
303 strcpy(current_event, ptr+6);
304 LeaveCriticalSection(&event_cs);
305 SetEvent(event_handle);
307 ok(0, "malformed service message: %s\n", ptr);
312 DisconnectNamedPipe(pipe_handle);
313 trace("pipe disconnected\n");
317 static void test_service(void)
319 SC_HANDLE service_handle = register_service("simple_service");
320 SERVICE_STATUS status;
326 trace("starting...\n");
327 res = StartServiceA(service_handle, 0, NULL);
328 ok(res, "StartService failed: %u\n", GetLastError());
330 DeleteService(service_handle);
333 expect_event("RUNNING");
335 res = QueryServiceStatus(service_handle, &status);
336 ok(res, "QueryServiceStatus failed: %d\n", GetLastError());
337 todo_wine ok(status.dwServiceType == SERVICE_WIN32_OWN_PROCESS, "status.dwServiceType = %x\n", status.dwServiceType);
338 ok(status.dwCurrentState == SERVICE_RUNNING, "status.dwCurrentState = %x\n", status.dwCurrentState);
339 ok(status.dwControlsAccepted == (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN),
340 "status.dwControlsAccepted = %x\n", status.dwControlsAccepted);
341 ok(status.dwWin32ExitCode == 0, "status.dwExitCode = %d\n", status.dwWin32ExitCode);
342 ok(status.dwServiceSpecificExitCode == 0, "status.dwServiceSpecificExitCode = %d\n",
343 status.dwServiceSpecificExitCode);
344 ok(status.dwCheckPoint == 0, "status.dwCheckPoint = %d\n", status.dwCheckPoint);
345 todo_wine ok(status.dwWaitHint == 0, "status.dwWaitHint = %d\n", status.dwWaitHint);
347 res = ControlService(service_handle, SERVICE_CONTROL_STOP, &status);
348 ok(res, "ControlService failed: %u\n", GetLastError());
349 expect_event("STOP");
351 res = DeleteService(service_handle);
352 ok(res, "DeleteService failed: %u\n", GetLastError());
354 CloseServiceHandle(service_handle);
357 static inline void test_no_stop(void)
359 SC_HANDLE service_handle = register_service("no_stop");
360 SERVICE_STATUS status;
366 trace("starting...\n");
367 res = StartServiceA(service_handle, 0, NULL);
368 ok(res, "StartService failed: %u\n", GetLastError());
370 DeleteService(service_handle);
373 expect_event("RUNNING");
375 /* Let service thread terminate */
378 res = QueryServiceStatus(service_handle, &status);
379 ok(res, "QueryServiceStatus failed: %d\n", GetLastError());
380 todo_wine ok(status.dwServiceType == SERVICE_WIN32_OWN_PROCESS, "status.dwServiceType = %x\n", status.dwServiceType);
381 ok(status.dwCurrentState == SERVICE_RUNNING, "status.dwCurrentState = %x\n", status.dwCurrentState);
382 ok(status.dwControlsAccepted == (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN),
383 "status.dwControlsAccepted = %x\n", status.dwControlsAccepted);
384 ok(status.dwWin32ExitCode == 0, "status.dwExitCode = %d\n", status.dwWin32ExitCode);
385 ok(status.dwServiceSpecificExitCode == 0, "status.dwServiceSpecificExitCode = %d\n",
386 status.dwServiceSpecificExitCode);
387 ok(status.dwCheckPoint == 0, "status.dwCheckPoint = %d\n", status.dwCheckPoint);
388 todo_wine ok(status.dwWaitHint == 0, "status.dwWaitHint = %d\n", status.dwWaitHint);
390 res = ControlService(service_handle, SERVICE_CONTROL_STOP, &status);
391 ok(res, "ControlService failed: %u\n", GetLastError());
392 expect_event("STOP");
394 res = QueryServiceStatus(service_handle, &status);
395 ok(res, "QueryServiceStatus failed: %d\n", GetLastError());
396 todo_wine ok(status.dwServiceType == SERVICE_WIN32_OWN_PROCESS, "status.dwServiceType = %x\n", status.dwServiceType);
397 ok(status.dwCurrentState==SERVICE_STOPPED || status.dwCurrentState==SERVICE_STOP_PENDING,
398 "status.dwCurrentState = %x\n", status.dwCurrentState);
399 ok(status.dwControlsAccepted == 0, "status.dwControlsAccepted = %x\n", status.dwControlsAccepted);
400 ok(status.dwWin32ExitCode == 0, "status.dwExitCode = %d\n", status.dwWin32ExitCode);
401 ok(status.dwServiceSpecificExitCode == 0, "status.dwServiceSpecificExitCode = %d\n",
402 status.dwServiceSpecificExitCode);
403 ok(status.dwCheckPoint == 0, "status.dwCheckPoint = %d\n", status.dwCheckPoint);
404 ok(status.dwWaitHint == 0, "status.dwWaitHint = %d\n", status.dwWaitHint);
406 res = DeleteService(service_handle);
407 ok(res, "DeleteService failed: %u\n", GetLastError());
409 res = QueryServiceStatus(service_handle, &status);
410 ok(res, "QueryServiceStatus failed: %d\n", GetLastError());
411 todo_wine ok(status.dwServiceType == SERVICE_WIN32_OWN_PROCESS, "status.dwServiceType = %x\n", status.dwServiceType);
412 ok(status.dwCurrentState==SERVICE_STOPPED || status.dwCurrentState==SERVICE_STOP_PENDING,
413 "status.dwCurrentState = %x\n", status.dwCurrentState);
414 ok(status.dwControlsAccepted == 0, "status.dwControlsAccepted = %x\n", status.dwControlsAccepted);
415 ok(status.dwWin32ExitCode == 0, "status.dwExitCode = %d\n", status.dwWin32ExitCode);
416 ok(status.dwServiceSpecificExitCode == 0, "status.dwServiceSpecificExitCode = %d\n",
417 status.dwServiceSpecificExitCode);
418 ok(status.dwCheckPoint == 0, "status.dwCheckPoint = %d\n", status.dwCheckPoint);
419 ok(status.dwWaitHint == 0, "status.dwWaitHint = %d\n", status.dwWaitHint);
421 CloseServiceHandle(service_handle);
423 res = QueryServiceStatus(service_handle, &status);
424 ok(!res, "QueryServiceStatus should have failed\n");
425 ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError = %d\n", GetLastError());
428 static void test_runner(void (*p_run_test)(void))
432 sprintf(service_name, "WineTestService%d", GetTickCount());
433 trace("service_name: %s\n", service_name);
434 sprintf(named_pipe_name, "\\\\.\\pipe\\%s_pipe", service_name);
436 pipe_handle = CreateNamedPipeA(named_pipe_name, PIPE_ACCESS_INBOUND,
437 PIPE_TYPE_BYTE|PIPE_READMODE_BYTE|PIPE_WAIT, 10, 2048, 2048, 10000, NULL);
438 ok(pipe_handle != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %u\n", GetLastError());
439 if(pipe_handle == INVALID_HANDLE_VALUE)
442 InitializeCriticalSection(&event_cs);
443 event_handle = CreateEventA(NULL, FALSE, FALSE, NULL);
444 ok(event_handle != INVALID_HANDLE_VALUE, "CreateEvent failed: %u\n", GetLastError());
445 if(event_handle == INVALID_HANDLE_VALUE)
448 thread = CreateThread(NULL, 0, pipe_thread, NULL, 0, NULL);
449 ok(thread != NULL, "CreateThread failed: %u\n", GetLastError());
455 WaitForSingleObject(thread, INFINITE);
456 CloseHandle(event_handle);
457 CloseHandle(pipe_handle);
465 pRegisterServiceCtrlHandlerExA = (void*)GetProcAddress(GetModuleHandleA("advapi32.dll"), "RegisterServiceCtrlHandlerExA");
466 if(!pRegisterServiceCtrlHandlerExA) {
467 win_skip("RegisterServiceCtrlHandlerExA not available, skipping tests\n");
471 argc = winetest_get_mainargs(&argv);
473 scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL);
474 ok(scm_handle != NULL, "OpenSCManager failed: %u\n", GetLastError());
477 test_runner(test_service);
478 test_runner(test_no_stop);
480 strcpy(service_name, argv[3]);
481 sprintf(named_pipe_name, "\\\\.\\pipe\\%s_pipe", service_name);
483 if(!strcmp(argv[2], "simple_service"))
484 service_process(service_main);
485 else if(!strcmp(argv[2], "no_stop"))
486 service_process(no_stop_main);
489 CloseServiceHandle(scm_handle);