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
);
331 CloseServiceHandle(service_handle
);
334 expect_event("RUNNING");
336 res
= QueryServiceStatus(service_handle
, &status
);
337 ok(res
, "QueryServiceStatus failed: %d\n", GetLastError());
338 todo_wine
ok(status
.dwServiceType
== SERVICE_WIN32_OWN_PROCESS
, "status.dwServiceType = %x\n", status
.dwServiceType
);
339 ok(status
.dwCurrentState
== SERVICE_RUNNING
, "status.dwCurrentState = %x\n", status
.dwCurrentState
);
340 ok(status
.dwControlsAccepted
== (SERVICE_ACCEPT_STOP
| SERVICE_ACCEPT_SHUTDOWN
),
341 "status.dwControlsAccepted = %x\n", status
.dwControlsAccepted
);
342 ok(status
.dwWin32ExitCode
== 0, "status.dwExitCode = %d\n", status
.dwWin32ExitCode
);
343 ok(status
.dwServiceSpecificExitCode
== 0, "status.dwServiceSpecificExitCode = %d\n",
344 status
.dwServiceSpecificExitCode
);
345 ok(status
.dwCheckPoint
== 0, "status.dwCheckPoint = %d\n", status
.dwCheckPoint
);
346 todo_wine
ok(status
.dwWaitHint
== 0, "status.dwWaitHint = %d\n", status
.dwWaitHint
);
348 res
= ControlService(service_handle
, SERVICE_CONTROL_STOP
, &status
);
349 ok(res
, "ControlService failed: %u\n", GetLastError());
350 expect_event("STOP");
352 res
= DeleteService(service_handle
);
353 ok(res
, "DeleteService failed: %u\n", GetLastError());
355 CloseServiceHandle(service_handle
);
358 static inline void test_no_stop(void)
360 SC_HANDLE service_handle
= register_service("no_stop");
361 SERVICE_STATUS status
;
367 trace("starting...\n");
368 res
= StartServiceA(service_handle
, 0, NULL
);
369 ok(res
, "StartService failed: %u\n", GetLastError());
371 DeleteService(service_handle
);
372 CloseServiceHandle(service_handle
);
375 expect_event("RUNNING");
377 /* Let service thread terminate */
380 res
= QueryServiceStatus(service_handle
, &status
);
381 ok(res
, "QueryServiceStatus failed: %d\n", GetLastError());
382 todo_wine
ok(status
.dwServiceType
== SERVICE_WIN32_OWN_PROCESS
, "status.dwServiceType = %x\n", status
.dwServiceType
);
383 ok(status
.dwCurrentState
== SERVICE_RUNNING
, "status.dwCurrentState = %x\n", status
.dwCurrentState
);
384 ok(status
.dwControlsAccepted
== (SERVICE_ACCEPT_STOP
| SERVICE_ACCEPT_SHUTDOWN
),
385 "status.dwControlsAccepted = %x\n", status
.dwControlsAccepted
);
386 ok(status
.dwWin32ExitCode
== 0, "status.dwExitCode = %d\n", status
.dwWin32ExitCode
);
387 ok(status
.dwServiceSpecificExitCode
== 0, "status.dwServiceSpecificExitCode = %d\n",
388 status
.dwServiceSpecificExitCode
);
389 ok(status
.dwCheckPoint
== 0, "status.dwCheckPoint = %d\n", status
.dwCheckPoint
);
390 todo_wine
ok(status
.dwWaitHint
== 0, "status.dwWaitHint = %d\n", status
.dwWaitHint
);
392 res
= ControlService(service_handle
, SERVICE_CONTROL_STOP
, &status
);
393 ok(res
, "ControlService failed: %u\n", GetLastError());
394 expect_event("STOP");
396 res
= QueryServiceStatus(service_handle
, &status
);
397 ok(res
, "QueryServiceStatus failed: %d\n", GetLastError());
398 todo_wine
ok(status
.dwServiceType
== SERVICE_WIN32_OWN_PROCESS
, "status.dwServiceType = %x\n", status
.dwServiceType
);
399 ok(status
.dwCurrentState
==SERVICE_STOPPED
|| status
.dwCurrentState
==SERVICE_STOP_PENDING
,
400 "status.dwCurrentState = %x\n", status
.dwCurrentState
);
401 ok(status
.dwControlsAccepted
== 0, "status.dwControlsAccepted = %x\n", status
.dwControlsAccepted
);
402 ok(status
.dwWin32ExitCode
== 0, "status.dwExitCode = %d\n", status
.dwWin32ExitCode
);
403 ok(status
.dwServiceSpecificExitCode
== 0, "status.dwServiceSpecificExitCode = %d\n",
404 status
.dwServiceSpecificExitCode
);
405 ok(status
.dwCheckPoint
== 0, "status.dwCheckPoint = %d\n", status
.dwCheckPoint
);
406 ok(status
.dwWaitHint
== 0, "status.dwWaitHint = %d\n", status
.dwWaitHint
);
408 res
= DeleteService(service_handle
);
409 ok(res
, "DeleteService failed: %u\n", GetLastError());
411 res
= QueryServiceStatus(service_handle
, &status
);
412 ok(res
, "QueryServiceStatus failed: %d\n", GetLastError());
413 todo_wine
ok(status
.dwServiceType
== SERVICE_WIN32_OWN_PROCESS
, "status.dwServiceType = %x\n", status
.dwServiceType
);
414 ok(status
.dwCurrentState
==SERVICE_STOPPED
|| status
.dwCurrentState
==SERVICE_STOP_PENDING
,
415 "status.dwCurrentState = %x\n", status
.dwCurrentState
);
416 ok(status
.dwControlsAccepted
== 0, "status.dwControlsAccepted = %x\n", status
.dwControlsAccepted
);
417 ok(status
.dwWin32ExitCode
== 0, "status.dwExitCode = %d\n", status
.dwWin32ExitCode
);
418 ok(status
.dwServiceSpecificExitCode
== 0, "status.dwServiceSpecificExitCode = %d\n",
419 status
.dwServiceSpecificExitCode
);
420 ok(status
.dwCheckPoint
== 0, "status.dwCheckPoint = %d\n", status
.dwCheckPoint
);
421 ok(status
.dwWaitHint
== 0, "status.dwWaitHint = %d\n", status
.dwWaitHint
);
423 CloseServiceHandle(service_handle
);
425 res
= QueryServiceStatus(service_handle
, &status
);
426 ok(!res
, "QueryServiceStatus should have failed\n");
427 ok(GetLastError() == ERROR_INVALID_HANDLE
, "GetLastError = %d\n", GetLastError());
430 static void test_runner(void (*p_run_test
)(void))
434 sprintf(service_name
, "WineTestService%d", GetTickCount());
435 trace("service_name: %s\n", service_name
);
436 sprintf(named_pipe_name
, "\\\\.\\pipe\\%s_pipe", service_name
);
438 pipe_handle
= CreateNamedPipeA(named_pipe_name
, PIPE_ACCESS_INBOUND
,
439 PIPE_TYPE_BYTE
|PIPE_READMODE_BYTE
|PIPE_WAIT
, 10, 2048, 2048, 10000, NULL
);
440 ok(pipe_handle
!= INVALID_HANDLE_VALUE
, "CreateNamedPipe failed: %u\n", GetLastError());
441 if(pipe_handle
== INVALID_HANDLE_VALUE
)
444 InitializeCriticalSection(&event_cs
);
445 event_handle
= CreateEventA(NULL
, FALSE
, FALSE
, NULL
);
446 ok(event_handle
!= INVALID_HANDLE_VALUE
, "CreateEvent failed: %u\n", GetLastError());
447 if(event_handle
== INVALID_HANDLE_VALUE
)
450 thread
= CreateThread(NULL
, 0, pipe_thread
, NULL
, 0, NULL
);
451 ok(thread
!= NULL
, "CreateThread failed: %u\n", GetLastError());
457 WaitForSingleObject(thread
, INFINITE
);
458 CloseHandle(event_handle
);
459 CloseHandle(pipe_handle
);
467 pRegisterServiceCtrlHandlerExA
= (void*)GetProcAddress(GetModuleHandleA("advapi32.dll"), "RegisterServiceCtrlHandlerExA");
468 if(!pRegisterServiceCtrlHandlerExA
) {
469 win_skip("RegisterServiceCtrlHandlerExA not available, skipping tests\n");
473 argc
= winetest_get_mainargs(&argv
);
475 scm_handle
= OpenSCManagerA(NULL
, NULL
, GENERIC_ALL
);
476 ok(scm_handle
!= NULL
, "OpenSCManager failed: %u\n", GetLastError());
479 test_runner(test_service
);
480 test_runner(test_no_stop
);
482 strcpy(service_name
, argv
[3]);
483 sprintf(named_pipe_name
, "\\\\.\\pipe\\%s_pipe", service_name
);
485 if(!strcmp(argv
[2], "simple_service"))
486 service_process(service_main
);
487 else if(!strcmp(argv
[2], "no_stop"))
488 service_process(no_stop_main
);
491 CloseServiceHandle(scm_handle
);