services/tests: Fix printf-style helper format (Coverity).
[wine.git] / programs / services / tests / service.c
blob93eff0e36f0a8c7c5a9963fa250c04c48c95f8da
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 <stdarg.h>
21 #include <windef.h>
22 #include <winsvc.h>
23 #include <stdio.h>
24 #include <winbase.h>
25 #include <winuser.h>
27 #include "wine/test.h"
29 #if !defined(__WINE_USE_MSVCRT) || defined(__MINGW32__)
30 #define __WINE_PRINTF_ATTR(fmt,args) __attribute__((format (printf,fmt,args)))
31 #else
32 #define __WINE_PRINTF_ATTR(fmt,args)
33 #endif
35 static SERVICE_STATUS_HANDLE (WINAPI *pRegisterServiceCtrlHandlerExA)(LPCSTR,LPHANDLER_FUNCTION_EX,LPVOID);
37 static HANDLE pipe_handle = INVALID_HANDLE_VALUE;
38 static char service_name[100], named_pipe_name[114];
39 static SERVICE_STATUS_HANDLE service_handle;
41 /* Service process global variables */
42 static HANDLE service_stop_event;
44 static int monitor_count;
46 static void send_msg(const char *type, const char *msg)
48 DWORD written = 0;
49 char buf[512];
51 sprintf(buf, "%s:%s", type, msg);
52 WriteFile(pipe_handle, buf, strlen(buf)+1, &written, NULL);
55 static inline void service_trace(const char *msg)
57 send_msg("TRACE", msg);
60 static inline void service_event(const char *event)
62 send_msg("EVENT", event);
65 static void WINAPIV service_ok(int cnd, const char *msg, ...) __WINE_PRINTF_ATTR(2,3);
66 static void WINAPIV service_ok(int cnd, const char *msg, ...)
68 __ms_va_list valist;
69 char buf[512];
71 __ms_va_start(valist, msg);
72 vsprintf(buf, msg, valist);
73 __ms_va_end(valist);
75 send_msg(cnd ? "OK" : "FAIL", buf);
78 static void test_winstation(void)
80 HWINSTA winstation;
81 USEROBJECTFLAGS flags;
82 BOOL r;
84 winstation = GetProcessWindowStation();
85 service_ok(winstation != NULL, "winstation = NULL\n");
87 r = GetUserObjectInformationA(winstation, UOI_FLAGS, &flags, sizeof(flags), NULL);
88 service_ok(r, "GetUserObjectInformation(UOI_NAME) failed: %u\n", GetLastError());
89 service_ok(!(flags.dwFlags & WSF_VISIBLE), "winstation has flags %x\n", flags.dwFlags);
93 * Test creating window in a service process. Although services run in non-interactive,
94 * they may create windows that will never be visible.
96 static void test_create_window(void)
98 DWORD style;
99 ATOM class;
100 HWND hwnd;
101 BOOL r;
103 static WNDCLASSEXA wndclass = {
104 sizeof(WNDCLASSEXA),
106 DefWindowProcA,
107 0, 0, NULL, NULL, NULL, NULL, NULL,
108 "service_test",
109 NULL
112 hwnd = GetDesktopWindow();
113 service_ok(IsWindow(hwnd), "GetDesktopWindow returned invalid window %p\n", hwnd);
115 class = RegisterClassExA(&wndclass);
116 service_ok(class, "RegisterClassFailed\n");
118 hwnd = CreateWindowA("service_test", "service_test",
119 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
120 515, 530, NULL, NULL, NULL, NULL);
121 service_ok(hwnd != NULL, "CreateWindow failed: %u\n", GetLastError());
123 style = GetWindowLongW(hwnd, GWL_STYLE);
124 service_ok(!(style & WS_VISIBLE), "style = %x, expected invisible\n", style);
126 r = ShowWindow(hwnd, SW_SHOW);
127 service_ok(!r, "ShowWindow returned %x\n", r);
129 style = GetWindowLongW(hwnd, GWL_STYLE);
130 service_ok(style & WS_VISIBLE, "style = %x, expected visible\n", style);
132 r = ShowWindow(hwnd, SW_SHOW);
133 service_ok(r, "ShowWindow returned %x\n", r);
135 r = DestroyWindow(hwnd);
136 service_ok(r, "DestroyWindow failed: %08x\n", GetLastError());
139 static BOOL CALLBACK monitor_enum_proc(HMONITOR hmon, HDC hdc, LPRECT lprc, LPARAM lparam)
141 static const RECT expected_rect = {0, 0, 1024, 768};
142 BOOL r;
143 MONITORINFOEXA mi;
145 service_ok(hmon != NULL, "Unexpected hmon %p\n", hmon);
147 monitor_count++;
149 mi.cbSize = sizeof(mi);
151 SetLastError(0xdeadbeef);
152 r = GetMonitorInfoA(NULL, (MONITORINFO*)&mi);
153 service_ok(GetLastError() == ERROR_INVALID_MONITOR_HANDLE, "Unexpected GetLastError: %#x.\n", GetLastError());
154 service_ok(!r, "GetMonitorInfo with NULL HMONITOR succeeded.\n");
156 r = GetMonitorInfoA(hmon, (MONITORINFO*)&mi);
157 service_ok(r, "GetMonitorInfo failed.\n");
159 service_ok(EqualRect(lprc, &expected_rect), "Unexpected rect: %s\n", wine_dbgstr_rect(lprc));
160 service_ok(EqualRect(&mi.rcMonitor, &expected_rect), "Unexpected rcMonitor: %s\n",
161 wine_dbgstr_rect(&mi.rcMonitor));
162 service_ok(EqualRect(&mi.rcWork, &expected_rect), "Unexpected rcWork: %s\n",
163 wine_dbgstr_rect(&mi.rcWork));
164 service_ok(!strcmp(mi.szDevice, "WinDisc"), "Unexpected szDevice received: %s\n", mi.szDevice);
166 service_ok(mi.dwFlags == MONITORINFOF_PRIMARY, "Unexpected secondary monitor info.\n");
168 return TRUE;
171 /* query monitor information, even in non-interactive services */
172 static void test_monitors(void)
174 BOOL r;
176 r = EnumDisplayMonitors(0, 0, monitor_enum_proc, 0);
177 service_ok(r, "EnumDisplayMonitors failed.\n");
178 service_ok(monitor_count == 1, "Callback got called less or more than once. %d\n", monitor_count);
181 static DWORD WINAPI service_handler(DWORD ctrl, DWORD event_type, void *event_data, void *context)
183 SERVICE_STATUS status;
185 status.dwServiceType = SERVICE_WIN32;
186 status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
187 status.dwWin32ExitCode = 0;
188 status.dwServiceSpecificExitCode = 0;
189 status.dwCheckPoint = 0;
190 status.dwWaitHint = 0;
192 switch(ctrl)
194 case SERVICE_CONTROL_STOP:
195 case SERVICE_CONTROL_SHUTDOWN:
196 service_event("STOP");
197 status.dwCurrentState = SERVICE_STOP_PENDING;
198 status.dwControlsAccepted = 0;
199 SetServiceStatus(service_handle, &status);
200 SetEvent(service_stop_event);
201 return NO_ERROR;
202 case 128:
203 test_winstation();
204 test_create_window();
205 test_monitors();
206 service_event("CUSTOM");
207 return 0xdeadbeef;
208 default:
209 status.dwCurrentState = SERVICE_RUNNING;
210 SetServiceStatus( service_handle, &status );
211 return NO_ERROR;
215 static void WINAPI service_main(DWORD argc, char **argv)
217 SERVICE_STATUS status;
218 char buf[64];
219 BOOL res;
221 service_ok(argc == 3, "argc = %u, expected 3\n", argc);
222 service_ok(!strcmp(argv[0], service_name), "argv[0] = '%s', expected '%s'\n", argv[0], service_name);
223 service_ok(!strcmp(argv[1], "param1"), "argv[1] = '%s', expected 'param1'\n", argv[1]);
224 service_ok(!strcmp(argv[2], "param2"), "argv[2] = '%s', expected 'param2'\n", argv[2]);
226 buf[0] = 0;
227 GetEnvironmentVariableA("PATHEXT", buf, sizeof(buf));
228 service_ok(buf[0], "did not find PATHEXT environment variable\n");
230 service_handle = pRegisterServiceCtrlHandlerExA(service_name, service_handler, NULL);
231 service_ok(service_handle != NULL, "RegisterServiceCtrlHandlerEx failed: %u\n", GetLastError());
232 if(!service_handle)
233 return;
235 status.dwServiceType = SERVICE_WIN32;
236 status.dwCurrentState = SERVICE_RUNNING;
237 status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
238 status.dwWin32ExitCode = 0;
239 status.dwServiceSpecificExitCode = 0;
240 status.dwCheckPoint = 0;
241 status.dwWaitHint = 10000;
242 res = SetServiceStatus(service_handle, &status);
243 service_ok(res, "SetServiceStatus(SERVICE_RUNNING) failed: %u\n", GetLastError());
245 service_event("RUNNING");
247 WaitForSingleObject(service_stop_event, INFINITE);
249 status.dwCurrentState = SERVICE_STOPPED;
250 status.dwControlsAccepted = 0;
251 res = SetServiceStatus(service_handle, &status);
252 service_ok(res, "SetServiceStatus(SERVICE_STOPPED) failed: %u\n", GetLastError());
255 static void service_process(void (WINAPI *p_service_main)(DWORD, char **))
257 BOOL res;
259 SERVICE_TABLE_ENTRYA servtbl[] = {
260 {service_name, p_service_main},
261 {NULL, NULL}
264 res = WaitNamedPipeA(named_pipe_name, NMPWAIT_USE_DEFAULT_WAIT);
265 if(!res)
266 return;
268 pipe_handle = CreateFileA(named_pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
269 if(pipe_handle == INVALID_HANDLE_VALUE)
270 return;
272 service_trace("Starting...\n");
274 service_stop_event = CreateEventA(NULL, TRUE, FALSE, NULL);
275 service_ok(service_stop_event != NULL, "Could not create event: %u\n", GetLastError());
276 if(!service_stop_event)
277 return;
279 res = StartServiceCtrlDispatcherA(servtbl);
280 service_ok(res, "StartServiceCtrlDispatcher failed: %u\n", GetLastError());
282 /* Let service thread terminate */
283 Sleep(50);
285 CloseHandle(service_stop_event);
286 CloseHandle(pipe_handle);
289 static DWORD WINAPI no_stop_handler(DWORD ctrl, DWORD event_type, void *event_data, void *context)
291 SERVICE_STATUS status;
293 status.dwServiceType = SERVICE_WIN32;
294 status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
295 status.dwWin32ExitCode = 0;
296 status.dwServiceSpecificExitCode = 0;
297 status.dwCheckPoint = 0;
298 status.dwWaitHint = 0;
300 switch(ctrl)
302 case SERVICE_CONTROL_STOP:
303 case SERVICE_CONTROL_SHUTDOWN:
304 service_event("STOP");
305 status.dwCurrentState = SERVICE_STOPPED;
306 status.dwControlsAccepted = 0;
307 SetServiceStatus(service_handle, &status);
308 SetEvent(service_stop_event);
309 return NO_ERROR;
310 default:
311 status.dwCurrentState = SERVICE_RUNNING;
312 SetServiceStatus( service_handle, &status );
313 return NO_ERROR;
317 static void WINAPI no_stop_main(DWORD argc, char **argv)
319 SERVICE_STATUS status;
320 BOOL res;
322 service_ok(argc == 1, "argc = %u, expected 1\n", argc);
323 service_ok(!strcmp(argv[0], service_name), "argv[0] = '%s', expected '%s'\n", argv[0], service_name);
325 service_handle = pRegisterServiceCtrlHandlerExA(service_name, no_stop_handler, NULL);
326 service_ok(service_handle != NULL, "RegisterServiceCtrlHandlerEx failed: %u\n", GetLastError());
327 if(!service_handle)
328 return;
330 status.dwServiceType = SERVICE_WIN32;
331 status.dwCurrentState = SERVICE_RUNNING;
332 status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
333 status.dwWin32ExitCode = 0;
334 status.dwServiceSpecificExitCode = 0;
335 status.dwCheckPoint = 0;
336 status.dwWaitHint = 10000;
337 res = SetServiceStatus(service_handle, &status);
338 service_ok(res, "SetServiceStatus(SERVICE_RUNNING) failed: %u\n", GetLastError());
340 service_event("RUNNING");
343 /* Test process global variables */
344 static SC_HANDLE scm_handle;
346 static char current_event[32];
347 static HANDLE event_handle = INVALID_HANDLE_VALUE;
348 static CRITICAL_SECTION event_cs;
350 static SC_HANDLE register_service(const char *test_name)
352 char service_cmd[MAX_PATH+150], *ptr;
353 SC_HANDLE service;
355 ptr = service_cmd + GetModuleFileNameA(NULL, service_cmd, MAX_PATH);
357 /* If the file doesn't exist, assume we're using built-in exe and append .so to the path */
358 if(GetFileAttributesA(service_cmd) == INVALID_FILE_ATTRIBUTES) {
359 strcpy(ptr, ".so");
360 ptr += 3;
363 strcpy(ptr, " service ");
364 ptr += strlen(ptr);
365 sprintf(ptr, "%s ", test_name);
366 ptr += strlen(ptr);
367 strcpy(ptr, service_name);
369 trace("service_cmd \"%s\"\n", service_cmd);
371 service = CreateServiceA(scm_handle, service_name, service_name, GENERIC_ALL,
372 SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE,
373 service_cmd, NULL, NULL, NULL, NULL, NULL);
374 if(!service && GetLastError() == ERROR_ACCESS_DENIED) {
375 skip("Not enough access right to create service\n");
376 return NULL;
379 ok(service != NULL, "CreateService failed: %u\n", GetLastError());
380 return service;
383 static void expect_event(const char *event_name)
385 char evt[32];
386 DWORD res;
388 trace("waiting for %s\n", event_name);
390 res = WaitForSingleObject(event_handle, 30000);
391 ok(res == WAIT_OBJECT_0, "WaitForSingleObject failed: %u\n", res);
392 if(res != WAIT_OBJECT_0)
393 return;
395 EnterCriticalSection(&event_cs);
396 strcpy(evt, current_event);
397 *current_event = 0;
398 LeaveCriticalSection(&event_cs);
400 ok(!strcmp(evt, event_name), "Unexpected event: %s, expected %s\n", evt, event_name);
403 static DWORD WINAPI pipe_thread(void *arg)
405 char buf[512], *ptr;
406 DWORD read;
407 BOOL res;
409 res = ConnectNamedPipe(pipe_handle, NULL);
410 ok(res || GetLastError() == ERROR_PIPE_CONNECTED, "ConnectNamedPipe failed: %u\n", GetLastError());
412 while(1) {
413 res = ReadFile(pipe_handle, buf, sizeof(buf), &read, NULL);
414 if(!res) {
415 ok(GetLastError() == ERROR_BROKEN_PIPE || GetLastError() == ERROR_INVALID_HANDLE,
416 "ReadFile failed: %u\n", GetLastError());
417 break;
420 for(ptr = buf; ptr < buf+read; ptr += strlen(ptr)+1) {
421 if(!strncmp(ptr, "TRACE:", 6)) {
422 trace("service trace: %s", ptr+6);
423 }else if(!strncmp(ptr, "OK:", 3)) {
424 ok(1, "service: %s", ptr+3);
425 }else if(!strncmp(ptr, "FAIL:", 5)) {
426 ok(0, "service: %s", ptr+5);
427 }else if(!strncmp(ptr, "EVENT:", 6)) {
428 trace("service event: %s\n", ptr+6);
429 EnterCriticalSection(&event_cs);
430 ok(!current_event[0], "event %s still queued\n", current_event);
431 strcpy(current_event, ptr+6);
432 LeaveCriticalSection(&event_cs);
433 SetEvent(event_handle);
434 }else {
435 ok(0, "malformed service message: %s\n", ptr);
440 DisconnectNamedPipe(pipe_handle);
441 trace("pipe disconnected\n");
442 return 0;
445 static void test_service(void)
447 static const char *argv[2] = {"param1", "param2"};
448 SC_HANDLE service_handle = register_service("simple_service");
449 SERVICE_STATUS_PROCESS status2;
450 SERVICE_STATUS status;
451 DWORD bytes;
452 BOOL res;
454 if(!service_handle)
455 return;
457 trace("starting...\n");
458 res = StartServiceA(service_handle, 2, argv);
459 ok(res, "StartService failed: %u\n", GetLastError());
460 if(!res) {
461 DeleteService(service_handle);
462 CloseServiceHandle(service_handle);
463 return;
465 expect_event("RUNNING");
467 res = QueryServiceStatus(service_handle, &status);
468 ok(res, "QueryServiceStatus failed: %d\n", GetLastError());
469 ok(status.dwServiceType == SERVICE_WIN32_OWN_PROCESS, "status.dwServiceType = %x\n", status.dwServiceType);
470 ok(status.dwCurrentState == SERVICE_RUNNING, "status.dwCurrentState = %x\n", status.dwCurrentState);
471 ok(status.dwControlsAccepted == (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN),
472 "status.dwControlsAccepted = %x\n", status.dwControlsAccepted);
473 ok(status.dwWin32ExitCode == 0, "status.dwExitCode = %d\n", status.dwWin32ExitCode);
474 ok(status.dwServiceSpecificExitCode == 0, "status.dwServiceSpecificExitCode = %d\n",
475 status.dwServiceSpecificExitCode);
476 ok(status.dwCheckPoint == 0, "status.dwCheckPoint = %d\n", status.dwCheckPoint);
477 todo_wine ok(status.dwWaitHint == 0, "status.dwWaitHint = %d\n", status.dwWaitHint);
479 res = QueryServiceStatusEx(service_handle, SC_STATUS_PROCESS_INFO, (BYTE *)&status2, sizeof(status2), &bytes);
480 ok(res, "QueryServiceStatusEx failed: %u\n", GetLastError());
481 ok(status2.dwCurrentState == SERVICE_RUNNING, "status2.dwCurrentState = %x\n", status2.dwCurrentState);
482 ok(status2.dwProcessId != 0, "status2.dwProcessId = %d\n", status2.dwProcessId);
484 res = ControlService(service_handle, 128, &status);
485 ok(res, "ControlService failed: %u\n", GetLastError());
486 expect_event("CUSTOM");
488 res = ControlService(service_handle, SERVICE_CONTROL_STOP, &status);
489 ok(res, "ControlService failed: %u\n", GetLastError());
490 expect_event("STOP");
492 res = DeleteService(service_handle);
493 ok(res, "DeleteService failed: %u\n", GetLastError());
495 CloseServiceHandle(service_handle);
498 static inline void test_no_stop(void)
500 SC_HANDLE service_handle = register_service("no_stop");
501 SERVICE_STATUS_PROCESS status2;
502 SERVICE_STATUS status;
503 DWORD bytes;
504 BOOL res;
506 if(!service_handle)
507 return;
509 trace("starting...\n");
510 res = StartServiceA(service_handle, 0, NULL);
511 ok(res, "StartService failed: %u\n", GetLastError());
512 if(!res) {
513 DeleteService(service_handle);
514 CloseServiceHandle(service_handle);
515 return;
517 expect_event("RUNNING");
519 /* Let service thread terminate */
520 Sleep(1000);
522 res = QueryServiceStatus(service_handle, &status);
523 ok(res, "QueryServiceStatus failed: %d\n", GetLastError());
524 ok(status.dwServiceType == SERVICE_WIN32_OWN_PROCESS, "status.dwServiceType = %x\n", status.dwServiceType);
525 ok(status.dwCurrentState == SERVICE_RUNNING, "status.dwCurrentState = %x\n", status.dwCurrentState);
526 ok(status.dwControlsAccepted == (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN),
527 "status.dwControlsAccepted = %x\n", status.dwControlsAccepted);
528 ok(status.dwWin32ExitCode == 0, "status.dwExitCode = %d\n", status.dwWin32ExitCode);
529 ok(status.dwServiceSpecificExitCode == 0, "status.dwServiceSpecificExitCode = %d\n",
530 status.dwServiceSpecificExitCode);
531 ok(status.dwCheckPoint == 0, "status.dwCheckPoint = %d\n", status.dwCheckPoint);
532 todo_wine ok(status.dwWaitHint == 0, "status.dwWaitHint = %d\n", status.dwWaitHint);
534 res = QueryServiceStatusEx(service_handle, SC_STATUS_PROCESS_INFO, (BYTE *)&status2, sizeof(status2), &bytes);
535 ok(res, "QueryServiceStatusEx failed: %u\n", GetLastError());
536 ok(status2.dwCurrentState == SERVICE_RUNNING, "status2.dwCurrentState = %x\n", status2.dwCurrentState);
537 ok(status2.dwProcessId != 0, "status2.dwProcessId = %d\n", status2.dwProcessId);
539 res = ControlService(service_handle, SERVICE_CONTROL_STOP, &status);
540 ok(res, "ControlService failed: %u\n", GetLastError());
541 expect_event("STOP");
543 res = QueryServiceStatus(service_handle, &status);
544 ok(res, "QueryServiceStatus failed: %d\n", GetLastError());
545 ok(status.dwServiceType == SERVICE_WIN32_OWN_PROCESS, "status.dwServiceType = %x\n", status.dwServiceType);
546 ok(status.dwCurrentState==SERVICE_STOPPED || status.dwCurrentState==SERVICE_STOP_PENDING,
547 "status.dwCurrentState = %x\n", status.dwCurrentState);
548 ok(status.dwControlsAccepted == 0, "status.dwControlsAccepted = %x\n", status.dwControlsAccepted);
549 ok(status.dwWin32ExitCode == 0, "status.dwExitCode = %d\n", status.dwWin32ExitCode);
550 ok(status.dwServiceSpecificExitCode == 0, "status.dwServiceSpecificExitCode = %d\n",
551 status.dwServiceSpecificExitCode);
552 ok(status.dwCheckPoint == 0, "status.dwCheckPoint = %d\n", status.dwCheckPoint);
553 ok(status.dwWaitHint == 0, "status.dwWaitHint = %d\n", status.dwWaitHint);
555 res = QueryServiceStatusEx(service_handle, SC_STATUS_PROCESS_INFO, (BYTE *)&status2, sizeof(status2), &bytes);
556 ok(res, "QueryServiceStatusEx failed: %u\n", GetLastError());
557 ok(status2.dwProcessId == 0 || broken(status2.dwProcessId != 0),
558 "status2.dwProcessId = %d\n", status2.dwProcessId);
560 res = DeleteService(service_handle);
561 ok(res, "DeleteService failed: %u\n", GetLastError());
563 res = QueryServiceStatus(service_handle, &status);
564 ok(res, "QueryServiceStatus failed: %d\n", GetLastError());
565 ok(status.dwServiceType == SERVICE_WIN32_OWN_PROCESS, "status.dwServiceType = %x\n", status.dwServiceType);
566 ok(status.dwCurrentState==SERVICE_STOPPED || status.dwCurrentState==SERVICE_STOP_PENDING,
567 "status.dwCurrentState = %x\n", status.dwCurrentState);
568 ok(status.dwControlsAccepted == 0, "status.dwControlsAccepted = %x\n", status.dwControlsAccepted);
569 ok(status.dwWin32ExitCode == 0, "status.dwExitCode = %d\n", status.dwWin32ExitCode);
570 ok(status.dwServiceSpecificExitCode == 0, "status.dwServiceSpecificExitCode = %d\n",
571 status.dwServiceSpecificExitCode);
572 ok(status.dwCheckPoint == 0, "status.dwCheckPoint = %d\n", status.dwCheckPoint);
573 ok(status.dwWaitHint == 0, "status.dwWaitHint = %d\n", status.dwWaitHint);
575 res = QueryServiceStatusEx(service_handle, SC_STATUS_PROCESS_INFO, (BYTE *)&status2, sizeof(status2), &bytes);
576 ok(res, "QueryServiceStatusEx failed: %u\n", GetLastError());
577 ok(status2.dwProcessId == 0 || broken(status2.dwProcessId != 0),
578 "status2.dwProcessId = %d\n", status2.dwProcessId);
580 CloseServiceHandle(service_handle);
582 res = QueryServiceStatus(service_handle, &status);
583 ok(!res, "QueryServiceStatus should have failed\n");
584 ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError = %d\n", GetLastError());
587 static void test_runner(void (*p_run_test)(void))
589 HANDLE thread;
591 sprintf(service_name, "WineTestService%d", GetTickCount());
592 trace("service_name: %s\n", service_name);
593 sprintf(named_pipe_name, "\\\\.\\pipe\\%s_pipe", service_name);
595 pipe_handle = CreateNamedPipeA(named_pipe_name, PIPE_ACCESS_INBOUND,
596 PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE|PIPE_WAIT, 10, 2048, 2048, 10000, NULL);
597 ok(pipe_handle != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %u\n", GetLastError());
598 if(pipe_handle == INVALID_HANDLE_VALUE)
599 return;
601 event_handle = CreateEventA(NULL, FALSE, FALSE, NULL);
602 ok(event_handle != INVALID_HANDLE_VALUE, "CreateEvent failed: %u\n", GetLastError());
603 if(event_handle == INVALID_HANDLE_VALUE)
604 return;
606 thread = CreateThread(NULL, 0, pipe_thread, NULL, 0, NULL);
607 ok(thread != NULL, "CreateThread failed: %u\n", GetLastError());
608 if(!thread)
609 return;
611 p_run_test();
613 WaitForSingleObject(thread, INFINITE);
614 CloseHandle(event_handle);
615 CloseHandle(pipe_handle);
616 CloseHandle(thread);
619 START_TEST(service)
621 char **argv;
622 int argc;
624 InitializeCriticalSection(&event_cs);
626 pRegisterServiceCtrlHandlerExA = (void*)GetProcAddress(GetModuleHandleA("advapi32.dll"), "RegisterServiceCtrlHandlerExA");
627 if(!pRegisterServiceCtrlHandlerExA) {
628 win_skip("RegisterServiceCtrlHandlerExA not available, skipping tests\n");
629 return;
632 scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL);
633 ok(scm_handle != NULL || GetLastError() == ERROR_ACCESS_DENIED, "OpenSCManager failed: %u\n", GetLastError());
634 if(!scm_handle) {
635 skip("OpenSCManager failed, skipping tests\n");
636 return;
639 argc = winetest_get_mainargs(&argv);
641 if(argc < 3) {
642 test_runner(test_service);
643 test_runner(test_no_stop);
644 }else {
645 strcpy(service_name, argv[3]);
646 sprintf(named_pipe_name, "\\\\.\\pipe\\%s_pipe", service_name);
648 if(!strcmp(argv[2], "simple_service"))
649 service_process(service_main);
650 else if(!strcmp(argv[2], "no_stop"))
651 service_process(no_stop_main);
654 CloseServiceHandle(scm_handle);