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
23 #include "wine/test.h"
25 static SERVICE_STATUS_HANDLE (WINAPI
*pRegisterServiceCtrlHandlerExA
)(LPCSTR
,LPHANDLER_FUNCTION_EX
,LPVOID
);
27 static HANDLE pipe_handle
= INVALID_HANDLE_VALUE
;
28 static char service_name
[100], named_pipe_name
[100];
29 static SERVICE_STATUS_HANDLE service_handle
;
31 /* Service process global variables */
32 static HANDLE service_stop_event
;
34 static void send_msg(const char *type
, const char *msg
)
39 sprintf(buf
, "%s:%s", type
, msg
);
40 WriteFile(pipe_handle
, buf
, strlen(buf
)+1, &written
, NULL
);
43 static inline void service_trace(const char *msg
)
45 send_msg("TRACE", msg
);
48 static inline void service_event(const char *event
)
50 send_msg("EVENT", event
);
53 static void service_ok(int cnd
, const char *msg
, ...)
58 va_start(valist
, msg
);
59 vsprintf(buf
, msg
, valist
);
62 send_msg(cnd
? "OK" : "FAIL", buf
);
65 static DWORD WINAPI
service_handler(DWORD ctrl
, DWORD event_type
, void *event_data
, void *context
)
67 SERVICE_STATUS status
;
69 status
.dwServiceType
= SERVICE_WIN32
;
70 status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
71 status
.dwWin32ExitCode
= 0;
72 status
.dwServiceSpecificExitCode
= 0;
73 status
.dwCheckPoint
= 0;
74 status
.dwWaitHint
= 0;
78 case SERVICE_CONTROL_STOP
:
79 case SERVICE_CONTROL_SHUTDOWN
:
80 service_event("STOP");
81 status
.dwCurrentState
= SERVICE_STOP_PENDING
;
82 status
.dwControlsAccepted
= 0;
83 SetServiceStatus(service_handle
, &status
);
84 SetEvent(service_stop_event
);
87 status
.dwCurrentState
= SERVICE_RUNNING
;
88 SetServiceStatus( service_handle
, &status
);
93 static void WINAPI
service_main(DWORD argc
, char **argv
)
95 SERVICE_STATUS status
;
98 service_ok(argc
== 1, "argc = %d\n", argc
);
100 service_ok(!strcmp(argv
[0], service_name
), "argv[0] = %s, expected %s\n", argv
[0], service_name
);
102 service_handle
= pRegisterServiceCtrlHandlerExA(service_name
, service_handler
, NULL
);
103 service_ok(service_handle
!= NULL
, "RegisterServiceCtrlHandlerEx failed: %u\n", GetLastError());
107 status
.dwServiceType
= SERVICE_WIN32
;
108 status
.dwCurrentState
= SERVICE_RUNNING
;
109 status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
| SERVICE_ACCEPT_SHUTDOWN
;
110 status
.dwWin32ExitCode
= 0;
111 status
.dwServiceSpecificExitCode
= 0;
112 status
.dwCheckPoint
= 0;
113 status
.dwWaitHint
= 10000;
114 res
= SetServiceStatus(service_handle
, &status
);
115 service_ok(res
, "SetServiceStatus(SERVICE_RUNNING) failed: %u\n", GetLastError());
117 service_event("RUNNING");
119 WaitForSingleObject(service_stop_event
, INFINITE
);
121 status
.dwCurrentState
= SERVICE_STOPPED
;
122 status
.dwControlsAccepted
= 0;
123 res
= SetServiceStatus(service_handle
, &status
);
124 service_ok(res
, "SetServiceStatus(SERVICE_STOPPED) failed: %u\n", GetLastError());
127 static void service_process(void (WINAPI
*p_service_main
)(DWORD
, char **))
131 SERVICE_TABLE_ENTRYA servtbl
[] = {
132 {service_name
, p_service_main
},
136 res
= WaitNamedPipeA(named_pipe_name
, NMPWAIT_USE_DEFAULT_WAIT
);
140 pipe_handle
= CreateFileA(named_pipe_name
, GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
141 if(pipe_handle
== INVALID_HANDLE_VALUE
)
144 service_trace("Starting...\n");
146 service_stop_event
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
147 service_ok(service_stop_event
!= NULL
, "Could not create event: %u\n", GetLastError());
148 if(!service_stop_event
)
151 res
= StartServiceCtrlDispatcherA(servtbl
);
152 service_ok(res
, "StartServiceCtrlDispatcher failed: %u\n", GetLastError());
154 /* Let service thread terminate */
157 CloseHandle(service_stop_event
);
158 CloseHandle(pipe_handle
);
161 static DWORD WINAPI
no_stop_handler(DWORD ctrl
, DWORD event_type
, void *event_data
, void *context
)
163 SERVICE_STATUS status
;
165 status
.dwServiceType
= SERVICE_WIN32
;
166 status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
167 status
.dwWin32ExitCode
= 0;
168 status
.dwServiceSpecificExitCode
= 0;
169 status
.dwCheckPoint
= 0;
170 status
.dwWaitHint
= 0;
174 case SERVICE_CONTROL_STOP
:
175 case SERVICE_CONTROL_SHUTDOWN
:
176 service_event("STOP");
177 status
.dwCurrentState
= SERVICE_STOPPED
;
178 status
.dwControlsAccepted
= 0;
179 SetServiceStatus(service_handle
, &status
);
180 SetEvent(service_stop_event
);
183 status
.dwCurrentState
= SERVICE_RUNNING
;
184 SetServiceStatus( service_handle
, &status
);
189 static void WINAPI
no_stop_main(DWORD argc
, char **argv
)
191 SERVICE_STATUS status
;
194 service_ok(argc
== 1, "argc = %d\n", argc
);
196 service_ok(!strcmp(argv
[0], service_name
), "argv[0] = %s, expected %s\n", argv
[0], service_name
);
198 service_handle
= pRegisterServiceCtrlHandlerExA(service_name
, no_stop_handler
, NULL
);
199 service_ok(service_handle
!= NULL
, "RegisterServiceCtrlHandlerEx failed: %u\n", GetLastError());
203 status
.dwServiceType
= SERVICE_WIN32
;
204 status
.dwCurrentState
= SERVICE_RUNNING
;
205 status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
| SERVICE_ACCEPT_SHUTDOWN
;
206 status
.dwWin32ExitCode
= 0;
207 status
.dwServiceSpecificExitCode
= 0;
208 status
.dwCheckPoint
= 0;
209 status
.dwWaitHint
= 10000;
210 res
= SetServiceStatus(service_handle
, &status
);
211 service_ok(res
, "SetServiceStatus(SERVICE_RUNNING) failed: %u\n", GetLastError());
213 service_event("RUNNING");
216 /* Test process global variables */
217 static SC_HANDLE scm_handle
;
219 static char current_event
[32];
220 static HANDLE event_handle
= INVALID_HANDLE_VALUE
;
221 static CRITICAL_SECTION event_cs
;
223 static SC_HANDLE
register_service(const char *test_name
)
225 char service_cmd
[MAX_PATH
+150], *ptr
;
228 ptr
= service_cmd
+ GetModuleFileNameA(NULL
, service_cmd
, MAX_PATH
);
230 /* If the file doesn't exist, assume we're using built-in exe and append .so to the path */
231 if(GetFileAttributesA(service_cmd
) == INVALID_FILE_ATTRIBUTES
) {
236 strcpy(ptr
, " service ");
238 sprintf(ptr
, "%s ", test_name
);
240 strcpy(ptr
, service_name
);
242 trace("service_cmd \"%s\"\n", service_cmd
);
244 service
= CreateServiceA(scm_handle
, service_name
, service_name
, GENERIC_ALL
,
245 SERVICE_WIN32_OWN_PROCESS
, SERVICE_DEMAND_START
, SERVICE_ERROR_IGNORE
,
246 service_cmd
, NULL
, NULL
, NULL
, NULL
, NULL
);
247 if(!service
&& GetLastError() == ERROR_ACCESS_DENIED
) {
248 skip("Not enough access right to create service\n");
252 ok(service
!= NULL
, "CreateService failed: %u\n", GetLastError());
256 static void expect_event(const char *event_name
)
261 trace("waiting for %s\n", event_name
);
263 res
= WaitForSingleObject(event_handle
, 30000);
264 ok(res
== WAIT_OBJECT_0
, "WaitForSingleObject failed: %u\n", res
);
265 if(res
!= WAIT_OBJECT_0
)
268 EnterCriticalSection(&event_cs
);
269 strcpy(evt
, current_event
);
271 LeaveCriticalSection(&event_cs
);
273 ok(!strcmp(evt
, event_name
), "Unexpected event: %s, expected %s\n", evt
, event_name
);
276 static DWORD WINAPI
pipe_thread(void *arg
)
282 res
= ConnectNamedPipe(pipe_handle
, NULL
);
283 ok(res
|| GetLastError() == ERROR_PIPE_CONNECTED
, "ConnectNamedPipe failed: %u\n", GetLastError());
286 res
= ReadFile(pipe_handle
, buf
, sizeof(buf
), &read
, NULL
);
288 ok(GetLastError() == ERROR_BROKEN_PIPE
|| GetLastError() == ERROR_INVALID_HANDLE
,
289 "ReadFile failed: %u\n", GetLastError());
293 for(ptr
= buf
; ptr
< buf
+read
; ptr
+= strlen(ptr
)+1) {
294 if(!strncmp(ptr
, "TRACE:", 6)) {
295 trace("service trace: %s", ptr
+6);
296 }else if(!strncmp(ptr
, "OK:", 3)) {
297 ok(1, "service: %s", ptr
+3);
298 }else if(!strncmp(ptr
, "FAIL:", 5)) {
299 ok(0, "service: %s", ptr
+5);
300 }else if(!strncmp(ptr
, "EVENT:", 6)) {
301 trace("service event: %s\n", ptr
+6);
302 EnterCriticalSection(&event_cs
);
303 ok(!current_event
[0], "event %s still queued\n", current_event
);
304 strcpy(current_event
, ptr
+6);
305 LeaveCriticalSection(&event_cs
);
306 SetEvent(event_handle
);
308 ok(0, "malformed service message: %s\n", ptr
);
313 DisconnectNamedPipe(pipe_handle
);
314 trace("pipe disconnected\n");
318 static void test_service(void)
320 SC_HANDLE service_handle
= register_service("simple_service");
321 SERVICE_STATUS status
;
327 trace("starting...\n");
328 res
= StartServiceA(service_handle
, 0, NULL
);
329 ok(res
, "StartService failed: %u\n", GetLastError());
331 DeleteService(service_handle
);
332 CloseServiceHandle(service_handle
);
335 expect_event("RUNNING");
337 res
= QueryServiceStatus(service_handle
, &status
);
338 ok(res
, "QueryServiceStatus failed: %d\n", GetLastError());
339 todo_wine
ok(status
.dwServiceType
== SERVICE_WIN32_OWN_PROCESS
, "status.dwServiceType = %x\n", status
.dwServiceType
);
340 ok(status
.dwCurrentState
== SERVICE_RUNNING
, "status.dwCurrentState = %x\n", status
.dwCurrentState
);
341 ok(status
.dwControlsAccepted
== (SERVICE_ACCEPT_STOP
| SERVICE_ACCEPT_SHUTDOWN
),
342 "status.dwControlsAccepted = %x\n", status
.dwControlsAccepted
);
343 ok(status
.dwWin32ExitCode
== 0, "status.dwExitCode = %d\n", status
.dwWin32ExitCode
);
344 ok(status
.dwServiceSpecificExitCode
== 0, "status.dwServiceSpecificExitCode = %d\n",
345 status
.dwServiceSpecificExitCode
);
346 ok(status
.dwCheckPoint
== 0, "status.dwCheckPoint = %d\n", status
.dwCheckPoint
);
347 todo_wine
ok(status
.dwWaitHint
== 0, "status.dwWaitHint = %d\n", status
.dwWaitHint
);
349 res
= ControlService(service_handle
, SERVICE_CONTROL_STOP
, &status
);
350 ok(res
, "ControlService failed: %u\n", GetLastError());
351 expect_event("STOP");
353 res
= DeleteService(service_handle
);
354 ok(res
, "DeleteService failed: %u\n", GetLastError());
356 CloseServiceHandle(service_handle
);
359 static inline void test_no_stop(void)
361 SC_HANDLE service_handle
= register_service("no_stop");
362 SERVICE_STATUS status
;
368 trace("starting...\n");
369 res
= StartServiceA(service_handle
, 0, NULL
);
370 ok(res
, "StartService failed: %u\n", GetLastError());
372 DeleteService(service_handle
);
373 CloseServiceHandle(service_handle
);
376 expect_event("RUNNING");
378 /* Let service thread terminate */
381 res
= QueryServiceStatus(service_handle
, &status
);
382 ok(res
, "QueryServiceStatus failed: %d\n", GetLastError());
383 todo_wine
ok(status
.dwServiceType
== SERVICE_WIN32_OWN_PROCESS
, "status.dwServiceType = %x\n", status
.dwServiceType
);
384 ok(status
.dwCurrentState
== SERVICE_RUNNING
, "status.dwCurrentState = %x\n", status
.dwCurrentState
);
385 ok(status
.dwControlsAccepted
== (SERVICE_ACCEPT_STOP
| SERVICE_ACCEPT_SHUTDOWN
),
386 "status.dwControlsAccepted = %x\n", status
.dwControlsAccepted
);
387 ok(status
.dwWin32ExitCode
== 0, "status.dwExitCode = %d\n", status
.dwWin32ExitCode
);
388 ok(status
.dwServiceSpecificExitCode
== 0, "status.dwServiceSpecificExitCode = %d\n",
389 status
.dwServiceSpecificExitCode
);
390 ok(status
.dwCheckPoint
== 0, "status.dwCheckPoint = %d\n", status
.dwCheckPoint
);
391 todo_wine
ok(status
.dwWaitHint
== 0, "status.dwWaitHint = %d\n", status
.dwWaitHint
);
393 res
= ControlService(service_handle
, SERVICE_CONTROL_STOP
, &status
);
394 ok(res
, "ControlService failed: %u\n", GetLastError());
395 expect_event("STOP");
397 res
= QueryServiceStatus(service_handle
, &status
);
398 ok(res
, "QueryServiceStatus failed: %d\n", GetLastError());
399 todo_wine
ok(status
.dwServiceType
== SERVICE_WIN32_OWN_PROCESS
, "status.dwServiceType = %x\n", status
.dwServiceType
);
400 ok(status
.dwCurrentState
==SERVICE_STOPPED
|| status
.dwCurrentState
==SERVICE_STOP_PENDING
,
401 "status.dwCurrentState = %x\n", status
.dwCurrentState
);
402 ok(status
.dwControlsAccepted
== 0, "status.dwControlsAccepted = %x\n", status
.dwControlsAccepted
);
403 ok(status
.dwWin32ExitCode
== 0, "status.dwExitCode = %d\n", status
.dwWin32ExitCode
);
404 ok(status
.dwServiceSpecificExitCode
== 0, "status.dwServiceSpecificExitCode = %d\n",
405 status
.dwServiceSpecificExitCode
);
406 ok(status
.dwCheckPoint
== 0, "status.dwCheckPoint = %d\n", status
.dwCheckPoint
);
407 ok(status
.dwWaitHint
== 0, "status.dwWaitHint = %d\n", status
.dwWaitHint
);
409 res
= DeleteService(service_handle
);
410 ok(res
, "DeleteService failed: %u\n", GetLastError());
412 res
= QueryServiceStatus(service_handle
, &status
);
413 ok(res
, "QueryServiceStatus failed: %d\n", GetLastError());
414 todo_wine
ok(status
.dwServiceType
== SERVICE_WIN32_OWN_PROCESS
, "status.dwServiceType = %x\n", status
.dwServiceType
);
415 ok(status
.dwCurrentState
==SERVICE_STOPPED
|| status
.dwCurrentState
==SERVICE_STOP_PENDING
,
416 "status.dwCurrentState = %x\n", status
.dwCurrentState
);
417 ok(status
.dwControlsAccepted
== 0, "status.dwControlsAccepted = %x\n", status
.dwControlsAccepted
);
418 ok(status
.dwWin32ExitCode
== 0, "status.dwExitCode = %d\n", status
.dwWin32ExitCode
);
419 ok(status
.dwServiceSpecificExitCode
== 0, "status.dwServiceSpecificExitCode = %d\n",
420 status
.dwServiceSpecificExitCode
);
421 ok(status
.dwCheckPoint
== 0, "status.dwCheckPoint = %d\n", status
.dwCheckPoint
);
422 ok(status
.dwWaitHint
== 0, "status.dwWaitHint = %d\n", status
.dwWaitHint
);
424 CloseServiceHandle(service_handle
);
426 res
= QueryServiceStatus(service_handle
, &status
);
427 ok(!res
, "QueryServiceStatus should have failed\n");
428 ok(GetLastError() == ERROR_INVALID_HANDLE
, "GetLastError = %d\n", GetLastError());
431 static void test_runner(void (*p_run_test
)(void))
435 sprintf(service_name
, "WineTestService%d", GetTickCount());
436 trace("service_name: %s\n", service_name
);
437 sprintf(named_pipe_name
, "\\\\.\\pipe\\%s_pipe", service_name
);
439 pipe_handle
= CreateNamedPipeA(named_pipe_name
, PIPE_ACCESS_INBOUND
,
440 PIPE_TYPE_BYTE
|PIPE_READMODE_BYTE
|PIPE_WAIT
, 10, 2048, 2048, 10000, NULL
);
441 ok(pipe_handle
!= INVALID_HANDLE_VALUE
, "CreateNamedPipe failed: %u\n", GetLastError());
442 if(pipe_handle
== INVALID_HANDLE_VALUE
)
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 InitializeCriticalSection(&event_cs
);
469 pRegisterServiceCtrlHandlerExA
= (void*)GetProcAddress(GetModuleHandleA("advapi32.dll"), "RegisterServiceCtrlHandlerExA");
470 if(!pRegisterServiceCtrlHandlerExA
) {
471 win_skip("RegisterServiceCtrlHandlerExA not available, skipping tests\n");
475 scm_handle
= OpenSCManagerA(NULL
, NULL
, GENERIC_ALL
);
476 ok(scm_handle
!= NULL
|| GetLastError() == ERROR_ACCESS_DENIED
, "OpenSCManager failed: %u\n", GetLastError());
478 skip("OpenSCManager failed, skipping tests\n");
482 argc
= winetest_get_mainargs(&argv
);
485 test_runner(test_service
);
486 test_runner(test_no_stop
);
488 strcpy(service_name
, argv
[3]);
489 sprintf(named_pipe_name
, "\\\\.\\pipe\\%s_pipe", service_name
);
491 if(!strcmp(argv
[2], "simple_service"))
492 service_process(service_main
);
493 else if(!strcmp(argv
[2], "no_stop"))
494 service_process(no_stop_main
);
497 CloseServiceHandle(scm_handle
);