hidclass.sys: Use the PDO instance id for the HID instance id.
[wine.git] / programs / services / tests / service.c
blobb184bdac79167d2411c6c9d3fe4fde43e53bf9bd
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 case 128:
87 service_event("CUSTOM");
88 return 0xdeadbeef;
89 default:
90 status.dwCurrentState = SERVICE_RUNNING;
91 SetServiceStatus( service_handle, &status );
92 return NO_ERROR;
96 static void WINAPI service_main(DWORD argc, char **argv)
98 SERVICE_STATUS status;
99 BOOL res;
101 service_ok(argc == 1, "argc = %d\n", argc);
102 if(argc)
103 service_ok(!strcmp(argv[0], service_name), "argv[0] = %s, expected %s\n", argv[0], service_name);
105 service_handle = pRegisterServiceCtrlHandlerExA(service_name, service_handler, NULL);
106 service_ok(service_handle != NULL, "RegisterServiceCtrlHandlerEx failed: %u\n", GetLastError());
107 if(!service_handle)
108 return;
110 status.dwServiceType = SERVICE_WIN32;
111 status.dwCurrentState = SERVICE_RUNNING;
112 status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
113 status.dwWin32ExitCode = 0;
114 status.dwServiceSpecificExitCode = 0;
115 status.dwCheckPoint = 0;
116 status.dwWaitHint = 10000;
117 res = SetServiceStatus(service_handle, &status);
118 service_ok(res, "SetServiceStatus(SERVICE_RUNNING) failed: %u\n", GetLastError());
120 service_event("RUNNING");
122 WaitForSingleObject(service_stop_event, INFINITE);
124 status.dwCurrentState = SERVICE_STOPPED;
125 status.dwControlsAccepted = 0;
126 res = SetServiceStatus(service_handle, &status);
127 service_ok(res, "SetServiceStatus(SERVICE_STOPPED) failed: %u\n", GetLastError());
130 static void service_process(void (WINAPI *p_service_main)(DWORD, char **))
132 BOOL res;
134 SERVICE_TABLE_ENTRYA servtbl[] = {
135 {service_name, p_service_main},
136 {NULL, NULL}
139 res = WaitNamedPipeA(named_pipe_name, NMPWAIT_USE_DEFAULT_WAIT);
140 if(!res)
141 return;
143 pipe_handle = CreateFileA(named_pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
144 if(pipe_handle == INVALID_HANDLE_VALUE)
145 return;
147 service_trace("Starting...\n");
149 service_stop_event = CreateEventA(NULL, TRUE, FALSE, NULL);
150 service_ok(service_stop_event != NULL, "Could not create event: %u\n", GetLastError());
151 if(!service_stop_event)
152 return;
154 res = StartServiceCtrlDispatcherA(servtbl);
155 service_ok(res, "StartServiceCtrlDispatcher failed: %u\n", GetLastError());
157 /* Let service thread terminate */
158 Sleep(50);
160 CloseHandle(service_stop_event);
161 CloseHandle(pipe_handle);
164 static DWORD WINAPI no_stop_handler(DWORD ctrl, DWORD event_type, void *event_data, void *context)
166 SERVICE_STATUS status;
168 status.dwServiceType = SERVICE_WIN32;
169 status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
170 status.dwWin32ExitCode = 0;
171 status.dwServiceSpecificExitCode = 0;
172 status.dwCheckPoint = 0;
173 status.dwWaitHint = 0;
175 switch(ctrl)
177 case SERVICE_CONTROL_STOP:
178 case SERVICE_CONTROL_SHUTDOWN:
179 service_event("STOP");
180 status.dwCurrentState = SERVICE_STOPPED;
181 status.dwControlsAccepted = 0;
182 SetServiceStatus(service_handle, &status);
183 SetEvent(service_stop_event);
184 return NO_ERROR;
185 default:
186 status.dwCurrentState = SERVICE_RUNNING;
187 SetServiceStatus( service_handle, &status );
188 return NO_ERROR;
192 static void WINAPI no_stop_main(DWORD argc, char **argv)
194 SERVICE_STATUS status;
195 BOOL res;
197 service_ok(argc == 1, "argc = %d\n", argc);
198 if(argc)
199 service_ok(!strcmp(argv[0], service_name), "argv[0] = %s, expected %s\n", argv[0], service_name);
201 service_handle = pRegisterServiceCtrlHandlerExA(service_name, no_stop_handler, NULL);
202 service_ok(service_handle != NULL, "RegisterServiceCtrlHandlerEx failed: %u\n", GetLastError());
203 if(!service_handle)
204 return;
206 status.dwServiceType = SERVICE_WIN32;
207 status.dwCurrentState = SERVICE_RUNNING;
208 status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
209 status.dwWin32ExitCode = 0;
210 status.dwServiceSpecificExitCode = 0;
211 status.dwCheckPoint = 0;
212 status.dwWaitHint = 10000;
213 res = SetServiceStatus(service_handle, &status);
214 service_ok(res, "SetServiceStatus(SERVICE_RUNNING) failed: %u\n", GetLastError());
216 service_event("RUNNING");
219 /* Test process global variables */
220 static SC_HANDLE scm_handle;
222 static char current_event[32];
223 static HANDLE event_handle = INVALID_HANDLE_VALUE;
224 static CRITICAL_SECTION event_cs;
226 static SC_HANDLE register_service(const char *test_name)
228 char service_cmd[MAX_PATH+150], *ptr;
229 SC_HANDLE service;
231 ptr = service_cmd + GetModuleFileNameA(NULL, service_cmd, MAX_PATH);
233 /* If the file doesn't exist, assume we're using built-in exe and append .so to the path */
234 if(GetFileAttributesA(service_cmd) == INVALID_FILE_ATTRIBUTES) {
235 strcpy(ptr, ".so");
236 ptr += 3;
239 strcpy(ptr, " service ");
240 ptr += strlen(ptr);
241 sprintf(ptr, "%s ", test_name);
242 ptr += strlen(ptr);
243 strcpy(ptr, service_name);
245 trace("service_cmd \"%s\"\n", service_cmd);
247 service = CreateServiceA(scm_handle, service_name, service_name, GENERIC_ALL,
248 SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE,
249 service_cmd, NULL, NULL, NULL, NULL, NULL);
250 if(!service && GetLastError() == ERROR_ACCESS_DENIED) {
251 skip("Not enough access right to create service\n");
252 return NULL;
255 ok(service != NULL, "CreateService failed: %u\n", GetLastError());
256 return service;
259 static void expect_event(const char *event_name)
261 char evt[32];
262 DWORD res;
264 trace("waiting for %s\n", event_name);
266 res = WaitForSingleObject(event_handle, 30000);
267 ok(res == WAIT_OBJECT_0, "WaitForSingleObject failed: %u\n", res);
268 if(res != WAIT_OBJECT_0)
269 return;
271 EnterCriticalSection(&event_cs);
272 strcpy(evt, current_event);
273 *current_event = 0;
274 LeaveCriticalSection(&event_cs);
276 ok(!strcmp(evt, event_name), "Unexpected event: %s, expected %s\n", evt, event_name);
279 static DWORD WINAPI pipe_thread(void *arg)
281 char buf[257], *ptr;
282 DWORD read;
283 BOOL res;
285 res = ConnectNamedPipe(pipe_handle, NULL);
286 ok(res || GetLastError() == ERROR_PIPE_CONNECTED, "ConnectNamedPipe failed: %u\n", GetLastError());
288 while(1) {
289 res = ReadFile(pipe_handle, buf, sizeof(buf), &read, NULL);
290 if(!res) {
291 ok(GetLastError() == ERROR_BROKEN_PIPE || GetLastError() == ERROR_INVALID_HANDLE,
292 "ReadFile failed: %u\n", GetLastError());
293 break;
296 for(ptr = buf; ptr < buf+read; ptr += strlen(ptr)+1) {
297 if(!strncmp(ptr, "TRACE:", 6)) {
298 trace("service trace: %s", ptr+6);
299 }else if(!strncmp(ptr, "OK:", 3)) {
300 ok(1, "service: %s", ptr+3);
301 }else if(!strncmp(ptr, "FAIL:", 5)) {
302 ok(0, "service: %s", ptr+5);
303 }else if(!strncmp(ptr, "EVENT:", 6)) {
304 trace("service event: %s\n", ptr+6);
305 EnterCriticalSection(&event_cs);
306 ok(!current_event[0], "event %s still queued\n", current_event);
307 strcpy(current_event, ptr+6);
308 LeaveCriticalSection(&event_cs);
309 SetEvent(event_handle);
310 }else {
311 ok(0, "malformed service message: %s\n", ptr);
316 DisconnectNamedPipe(pipe_handle);
317 trace("pipe disconnected\n");
318 return 0;
321 static void test_service(void)
323 SC_HANDLE service_handle = register_service("simple_service");
324 SERVICE_STATUS_PROCESS status2;
325 SERVICE_STATUS status;
326 DWORD bytes;
327 BOOL res;
329 if(!service_handle)
330 return;
332 trace("starting...\n");
333 res = StartServiceA(service_handle, 0, NULL);
334 ok(res, "StartService failed: %u\n", GetLastError());
335 if(!res) {
336 DeleteService(service_handle);
337 CloseServiceHandle(service_handle);
338 return;
340 expect_event("RUNNING");
342 res = QueryServiceStatus(service_handle, &status);
343 ok(res, "QueryServiceStatus failed: %d\n", GetLastError());
344 todo_wine ok(status.dwServiceType == SERVICE_WIN32_OWN_PROCESS, "status.dwServiceType = %x\n", status.dwServiceType);
345 ok(status.dwCurrentState == SERVICE_RUNNING, "status.dwCurrentState = %x\n", status.dwCurrentState);
346 ok(status.dwControlsAccepted == (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN),
347 "status.dwControlsAccepted = %x\n", status.dwControlsAccepted);
348 ok(status.dwWin32ExitCode == 0, "status.dwExitCode = %d\n", status.dwWin32ExitCode);
349 ok(status.dwServiceSpecificExitCode == 0, "status.dwServiceSpecificExitCode = %d\n",
350 status.dwServiceSpecificExitCode);
351 ok(status.dwCheckPoint == 0, "status.dwCheckPoint = %d\n", status.dwCheckPoint);
352 todo_wine ok(status.dwWaitHint == 0, "status.dwWaitHint = %d\n", status.dwWaitHint);
354 res = QueryServiceStatusEx(service_handle, SC_STATUS_PROCESS_INFO, (BYTE *)&status2, sizeof(status2), &bytes);
355 ok(res, "QueryServiceStatusEx failed: %u\n", GetLastError());
356 ok(status2.dwCurrentState == SERVICE_RUNNING, "status2.dwCurrentState = %x\n", status2.dwCurrentState);
357 ok(status2.dwProcessId != 0, "status2.dwProcessId = %d\n", status2.dwProcessId);
359 res = ControlService(service_handle, 128, &status);
360 ok(res, "ControlService failed: %u\n", GetLastError());
361 expect_event("CUSTOM");
363 res = ControlService(service_handle, SERVICE_CONTROL_STOP, &status);
364 ok(res, "ControlService failed: %u\n", GetLastError());
365 expect_event("STOP");
367 res = DeleteService(service_handle);
368 ok(res, "DeleteService failed: %u\n", GetLastError());
370 CloseServiceHandle(service_handle);
373 static inline void test_no_stop(void)
375 SC_HANDLE service_handle = register_service("no_stop");
376 SERVICE_STATUS_PROCESS status2;
377 SERVICE_STATUS status;
378 DWORD bytes;
379 BOOL res;
381 if(!service_handle)
382 return;
384 trace("starting...\n");
385 res = StartServiceA(service_handle, 0, NULL);
386 ok(res, "StartService failed: %u\n", GetLastError());
387 if(!res) {
388 DeleteService(service_handle);
389 CloseServiceHandle(service_handle);
390 return;
392 expect_event("RUNNING");
394 /* Let service thread terminate */
395 Sleep(1000);
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_RUNNING, "status.dwCurrentState = %x\n", status.dwCurrentState);
401 ok(status.dwControlsAccepted == (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN),
402 "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 todo_wine ok(status.dwWaitHint == 0, "status.dwWaitHint = %d\n", status.dwWaitHint);
409 res = QueryServiceStatusEx(service_handle, SC_STATUS_PROCESS_INFO, (BYTE *)&status2, sizeof(status2), &bytes);
410 ok(res, "QueryServiceStatusEx failed: %u\n", GetLastError());
411 ok(status2.dwCurrentState == SERVICE_RUNNING, "status2.dwCurrentState = %x\n", status2.dwCurrentState);
412 ok(status2.dwProcessId != 0, "status2.dwProcessId = %d\n", status2.dwProcessId);
414 res = ControlService(service_handle, SERVICE_CONTROL_STOP, &status);
415 ok(res, "ControlService failed: %u\n", GetLastError());
416 expect_event("STOP");
418 res = QueryServiceStatus(service_handle, &status);
419 ok(res, "QueryServiceStatus failed: %d\n", GetLastError());
420 todo_wine ok(status.dwServiceType == SERVICE_WIN32_OWN_PROCESS, "status.dwServiceType = %x\n", status.dwServiceType);
421 ok(status.dwCurrentState==SERVICE_STOPPED || status.dwCurrentState==SERVICE_STOP_PENDING,
422 "status.dwCurrentState = %x\n", status.dwCurrentState);
423 ok(status.dwControlsAccepted == 0, "status.dwControlsAccepted = %x\n", status.dwControlsAccepted);
424 ok(status.dwWin32ExitCode == 0, "status.dwExitCode = %d\n", status.dwWin32ExitCode);
425 ok(status.dwServiceSpecificExitCode == 0, "status.dwServiceSpecificExitCode = %d\n",
426 status.dwServiceSpecificExitCode);
427 ok(status.dwCheckPoint == 0, "status.dwCheckPoint = %d\n", status.dwCheckPoint);
428 ok(status.dwWaitHint == 0, "status.dwWaitHint = %d\n", status.dwWaitHint);
430 res = QueryServiceStatusEx(service_handle, SC_STATUS_PROCESS_INFO, (BYTE *)&status2, sizeof(status2), &bytes);
431 ok(res, "QueryServiceStatusEx failed: %u\n", GetLastError());
432 ok(status2.dwProcessId == 0 || broken(status2.dwProcessId != 0),
433 "status2.dwProcessId = %d\n", status2.dwProcessId);
435 res = DeleteService(service_handle);
436 ok(res, "DeleteService failed: %u\n", GetLastError());
438 res = QueryServiceStatus(service_handle, &status);
439 ok(res, "QueryServiceStatus failed: %d\n", GetLastError());
440 todo_wine ok(status.dwServiceType == SERVICE_WIN32_OWN_PROCESS, "status.dwServiceType = %x\n", status.dwServiceType);
441 ok(status.dwCurrentState==SERVICE_STOPPED || status.dwCurrentState==SERVICE_STOP_PENDING,
442 "status.dwCurrentState = %x\n", status.dwCurrentState);
443 ok(status.dwControlsAccepted == 0, "status.dwControlsAccepted = %x\n", status.dwControlsAccepted);
444 ok(status.dwWin32ExitCode == 0, "status.dwExitCode = %d\n", status.dwWin32ExitCode);
445 ok(status.dwServiceSpecificExitCode == 0, "status.dwServiceSpecificExitCode = %d\n",
446 status.dwServiceSpecificExitCode);
447 ok(status.dwCheckPoint == 0, "status.dwCheckPoint = %d\n", status.dwCheckPoint);
448 ok(status.dwWaitHint == 0, "status.dwWaitHint = %d\n", status.dwWaitHint);
450 res = QueryServiceStatusEx(service_handle, SC_STATUS_PROCESS_INFO, (BYTE *)&status2, sizeof(status2), &bytes);
451 ok(res, "QueryServiceStatusEx failed: %u\n", GetLastError());
452 ok(status2.dwProcessId == 0 || broken(status2.dwProcessId != 0),
453 "status2.dwProcessId = %d\n", status2.dwProcessId);
455 CloseServiceHandle(service_handle);
457 res = QueryServiceStatus(service_handle, &status);
458 ok(!res, "QueryServiceStatus should have failed\n");
459 ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError = %d\n", GetLastError());
462 static void test_runner(void (*p_run_test)(void))
464 HANDLE thread;
466 sprintf(service_name, "WineTestService%d", GetTickCount());
467 trace("service_name: %s\n", service_name);
468 sprintf(named_pipe_name, "\\\\.\\pipe\\%s_pipe", service_name);
470 pipe_handle = CreateNamedPipeA(named_pipe_name, PIPE_ACCESS_INBOUND,
471 PIPE_TYPE_BYTE|PIPE_READMODE_BYTE|PIPE_WAIT, 10, 2048, 2048, 10000, NULL);
472 ok(pipe_handle != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %u\n", GetLastError());
473 if(pipe_handle == INVALID_HANDLE_VALUE)
474 return;
476 event_handle = CreateEventA(NULL, FALSE, FALSE, NULL);
477 ok(event_handle != INVALID_HANDLE_VALUE, "CreateEvent failed: %u\n", GetLastError());
478 if(event_handle == INVALID_HANDLE_VALUE)
479 return;
481 thread = CreateThread(NULL, 0, pipe_thread, NULL, 0, NULL);
482 ok(thread != NULL, "CreateThread failed: %u\n", GetLastError());
483 if(!thread)
484 return;
486 p_run_test();
488 WaitForSingleObject(thread, INFINITE);
489 CloseHandle(event_handle);
490 CloseHandle(pipe_handle);
493 START_TEST(service)
495 char **argv;
496 int argc;
498 InitializeCriticalSection(&event_cs);
500 pRegisterServiceCtrlHandlerExA = (void*)GetProcAddress(GetModuleHandleA("advapi32.dll"), "RegisterServiceCtrlHandlerExA");
501 if(!pRegisterServiceCtrlHandlerExA) {
502 win_skip("RegisterServiceCtrlHandlerExA not available, skipping tests\n");
503 return;
506 scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL);
507 ok(scm_handle != NULL || GetLastError() == ERROR_ACCESS_DENIED, "OpenSCManager failed: %u\n", GetLastError());
508 if(!scm_handle) {
509 skip("OpenSCManager failed, skipping tests\n");
510 return;
513 argc = winetest_get_mainargs(&argv);
515 if(argc < 3) {
516 test_runner(test_service);
517 test_runner(test_no_stop);
518 }else {
519 strcpy(service_name, argv[3]);
520 sprintf(named_pipe_name, "\\\\.\\pipe\\%s_pipe", service_name);
522 if(!strcmp(argv[2], "simple_service"))
523 service_process(service_main);
524 else if(!strcmp(argv[2], "no_stop"))
525 service_process(no_stop_main);
528 CloseServiceHandle(scm_handle);