po: Fix a mistake in Dutch translation.
[wine.git] / programs / services / tests / service.c
blob203882d45e1a805999fd8d7132728f29e144dfc1
1 /*
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
19 #include <windef.h>
20 #include <winsvc.h>
21 #include <stdio.h>
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)
36 DWORD written = 0;
37 char buf[512];
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, ...)
55 va_list valist;
56 char buf[512];
58 va_start(valist, msg);
59 vsprintf(buf, msg, valist);
60 va_end(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;
76 switch(ctrl)
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);
85 return NO_ERROR;
86 default:
87 status.dwCurrentState = SERVICE_RUNNING;
88 SetServiceStatus( service_handle, &status );
89 return NO_ERROR;
93 static void WINAPI service_main(DWORD argc, char **argv)
95 SERVICE_STATUS status;
96 BOOL res;
98 service_ok(argc == 1, "argc = %d", argc);
99 if(argc)
100 service_ok(!strcmp(argv[0], service_name), "argv[0] = %s, expected %s", argv[0], service_name);
102 service_handle = pRegisterServiceCtrlHandlerExA(service_name, service_handler, NULL);
103 service_ok(service_handle != NULL, "RegisterServiceCtrlHandlerEx failed: %u\n", GetLastError());
104 if(!service_handle)
105 return;
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", 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", GetLastError());
127 static void service_process(void (WINAPI *p_service_main)(DWORD, char **))
129 BOOL res;
131 SERVICE_TABLE_ENTRYA servtbl[] = {
132 {service_name, p_service_main},
133 {NULL, NULL}
136 res = WaitNamedPipeA(named_pipe_name, NMPWAIT_USE_DEFAULT_WAIT);
137 if(!res)
138 return;
140 pipe_handle = CreateFileA(named_pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
141 if(pipe_handle == INVALID_HANDLE_VALUE)
142 return;
144 service_trace("Starting...");
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)
149 return;
151 res = StartServiceCtrlDispatcherA(servtbl);
152 service_ok(res, "StartServiceCtrlDispatcher failed: %u\n", GetLastError());
154 /* Let service thread terminate */
155 Sleep(50);
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;
172 switch(ctrl)
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);
181 return NO_ERROR;
182 default:
183 status.dwCurrentState = SERVICE_RUNNING;
184 SetServiceStatus( service_handle, &status );
185 return NO_ERROR;
189 static void WINAPI no_stop_main(DWORD argc, char **argv)
191 SERVICE_STATUS status;
192 BOOL res;
194 service_ok(argc == 1, "argc = %d", argc);
195 if(argc)
196 service_ok(!strcmp(argv[0], service_name), "argv[0] = %s, expected %s", 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());
200 if(!service_handle)
201 return;
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", 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;
226 SC_HANDLE service;
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) {
232 strcpy(ptr, ".so");
233 ptr += 3;
236 strcpy(ptr, " service ");
237 ptr += strlen(ptr);
238 sprintf(ptr, "%s ", test_name);
239 ptr += strlen(ptr);
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");
249 return NULL;
252 ok(service != NULL, "CreateService failed: %u\n", GetLastError());
253 return service;
256 static void expect_event(const char *event_name)
258 char evt[32];
259 DWORD res;
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)
266 return;
268 EnterCriticalSection(&event_cs);
269 strcpy(evt, current_event);
270 *current_event = 0;
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)
278 char buf[257], *ptr;
279 DWORD read;
280 BOOL res;
282 res = ConnectNamedPipe(pipe_handle, NULL);
283 ok(res || GetLastError() == ERROR_PIPE_CONNECTED, "ConnectNamedPipe failed: %u\n", GetLastError());
285 while(1) {
286 res = ReadFile(pipe_handle, buf, sizeof(buf), &read, NULL);
287 if(!res) {
288 ok(GetLastError() == ERROR_BROKEN_PIPE || GetLastError() == ERROR_INVALID_HANDLE,
289 "ReadFile failed: %u\n", GetLastError());
290 break;
293 for(ptr = buf; ptr < buf+read; ptr += strlen(ptr)+1) {
294 if(!strncmp(ptr, "TRACE:", 6)) {
295 trace("service trace: %s\n", ptr+6);
296 }else if(!strncmp(ptr, "OK:", 3)) {
297 ok(1, "service: %s\n", ptr+3);
298 }else if(!strncmp(ptr, "FAIL:", 5)) {
299 ok(0, "service: %s\n", 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);
307 }else {
308 ok(0, "malformed service message: %s\n", ptr);
313 DisconnectNamedPipe(pipe_handle);
314 trace("pipe disconnected\n");
315 return 0;
318 static void test_service(void)
320 SC_HANDLE service_handle = register_service("simple_service");
321 SERVICE_STATUS status;
322 BOOL res;
324 if(!service_handle)
325 return;
327 trace("starting...\n");
328 res = StartServiceA(service_handle, 0, NULL);
329 ok(res, "StartService failed: %u\n", GetLastError());
330 if(!res) {
331 DeleteService(service_handle);
332 CloseServiceHandle(service_handle);
333 return;
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;
363 BOOL res;
365 if(!service_handle)
366 return;
368 trace("starting...\n");
369 res = StartServiceA(service_handle, 0, NULL);
370 ok(res, "StartService failed: %u\n", GetLastError());
371 if(!res) {
372 DeleteService(service_handle);
373 CloseServiceHandle(service_handle);
374 return;
376 expect_event("RUNNING");
378 /* Let service thread terminate */
379 Sleep(1000);
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))
433 HANDLE thread;
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)
443 return;
445 InitializeCriticalSection(&event_cs);
446 event_handle = CreateEventA(NULL, FALSE, FALSE, NULL);
447 ok(event_handle != INVALID_HANDLE_VALUE, "CreateEvent failed: %u\n", GetLastError());
448 if(event_handle == INVALID_HANDLE_VALUE)
449 return;
451 thread = CreateThread(NULL, 0, pipe_thread, NULL, 0, NULL);
452 ok(thread != NULL, "CreateThread failed: %u\n", GetLastError());
453 if(!thread)
454 return;
456 p_run_test();
458 WaitForSingleObject(thread, INFINITE);
459 CloseHandle(event_handle);
460 CloseHandle(pipe_handle);
463 START_TEST(service)
465 char **argv;
466 int argc;
468 pRegisterServiceCtrlHandlerExA = (void*)GetProcAddress(GetModuleHandleA("advapi32.dll"), "RegisterServiceCtrlHandlerExA");
469 if(!pRegisterServiceCtrlHandlerExA) {
470 win_skip("RegisterServiceCtrlHandlerExA not available, skipping tests\n");
471 return;
474 scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL);
475 ok(scm_handle != NULL || GetLastError() == ERROR_ACCESS_DENIED, "OpenSCManager failed: %u\n", GetLastError());
476 if(!scm_handle) {
477 skip("OpenSCManager failed, skipping tests\n");
478 return;
481 argc = winetest_get_mainargs(&argv);
483 if(argc < 3) {
484 test_runner(test_service);
485 test_runner(test_no_stop);
486 }else {
487 strcpy(service_name, argv[3]);
488 sprintf(named_pipe_name, "\\\\.\\pipe\\%s_pipe", service_name);
490 if(!strcmp(argv[2], "simple_service"))
491 service_process(service_main);
492 else if(!strcmp(argv[2], "no_stop"))
493 service_process(no_stop_main);
496 CloseServiceHandle(scm_handle);