ntdll: Also ignore missing directories in NtGetNlsSectionPtr().
[wine.git] / programs / services / tests / service.c
blobaa9878b97696164a8078dc32968cbd3091cad4f9
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 static SERVICE_STATUS_HANDLE (WINAPI *pRegisterServiceCtrlHandlerExA)(LPCSTR,LPHANDLER_FUNCTION_EX,LPVOID);
31 static HANDLE pipe_handle = INVALID_HANDLE_VALUE;
32 static char service_name[100], named_pipe_name[114];
33 static SERVICE_STATUS_HANDLE service_handle;
35 /* Service process global variables */
36 static HANDLE service_stop_event;
38 static int monitor_count;
40 static void send_msg(const char *type, const char *msg)
42 DWORD written = 0;
43 char buf[512];
45 sprintf(buf, "%s:%s", type, msg);
46 WriteFile(pipe_handle, buf, strlen(buf)+1, &written, NULL);
49 static inline void service_trace(const char *msg)
51 send_msg("TRACE", msg);
54 static inline void service_event(const char *event)
56 send_msg("EVENT", event);
59 static void WINAPIV service_ok(int cnd, const char *msg, ...)
61 __ms_va_list valist;
62 char buf[512];
64 __ms_va_start(valist, msg);
65 vsprintf(buf, msg, valist);
66 __ms_va_end(valist);
68 send_msg(cnd ? "OK" : "FAIL", buf);
71 static void test_winstation(void)
73 HWINSTA winstation;
74 USEROBJECTFLAGS flags;
75 BOOL r;
77 winstation = GetProcessWindowStation();
78 service_ok(winstation != NULL, "winstation = NULL\n");
80 r = GetUserObjectInformationA(winstation, UOI_FLAGS, &flags, sizeof(flags), NULL);
81 service_ok(r, "GetUserObjectInformation(UOI_NAME) failed: %u\n", GetLastError());
82 service_ok(!(flags.dwFlags & WSF_VISIBLE), "winstation has flags %x\n", flags.dwFlags);
86 * Test creating window in a service process. Although services run in non-interactive,
87 * they may create windows that will never be visible.
89 static void test_create_window(void)
91 DWORD style;
92 ATOM class;
93 HWND hwnd;
94 BOOL r;
96 static WNDCLASSEXA wndclass = {
97 sizeof(WNDCLASSEXA),
99 DefWindowProcA,
100 0, 0, NULL, NULL, NULL, NULL, NULL,
101 "service_test",
102 NULL
105 hwnd = GetDesktopWindow();
106 service_ok(IsWindow(hwnd), "GetDesktopWindow returned invalid window %p\n", hwnd);
108 class = RegisterClassExA(&wndclass);
109 service_ok(class, "RegisterClassFailed\n");
111 hwnd = CreateWindowA("service_test", "service_test",
112 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
113 515, 530, NULL, NULL, NULL, NULL);
114 service_ok(hwnd != NULL, "CreateWindow failed: %u\n", GetLastError());
116 style = GetWindowLongW(hwnd, GWL_STYLE);
117 service_ok(!(style & WS_VISIBLE), "style = %x, expected invisible\n", style);
119 r = ShowWindow(hwnd, SW_SHOW);
120 service_ok(!r, "ShowWindow returned %x\n", r);
122 style = GetWindowLongW(hwnd, GWL_STYLE);
123 service_ok(style & WS_VISIBLE, "style = %x, expected visible\n", style);
125 r = ShowWindow(hwnd, SW_SHOW);
126 service_ok(r, "ShowWindow returned %x\n", r);
128 r = DestroyWindow(hwnd);
129 service_ok(r, "DestroyWindow failed: %08x\n", GetLastError());
132 static BOOL CALLBACK monitor_enum_proc(HMONITOR hmon, HDC hdc, LPRECT lprc, LPARAM lparam)
134 BOOL r;
135 MONITORINFOEXA mi;
137 service_ok(hmon != NULL, "Unexpected hmon=%#x\n", hmon);
139 monitor_count++;
141 mi.cbSize = sizeof(mi);
143 SetLastError(0xdeadbeef);
144 r = GetMonitorInfoA(NULL, (MONITORINFO*)&mi);
145 service_ok(GetLastError() == ERROR_INVALID_MONITOR_HANDLE, "Unexpected GetLastError: %#x.\n", GetLastError());
146 service_ok(!r, "GetMonitorInfo with NULL HMONITOR succeeded.\n");
148 r = GetMonitorInfoA(hmon, (MONITORINFO*)&mi);
149 service_ok(r, "GetMonitorInfo failed.\n");
151 service_ok(mi.rcMonitor.left == 0 && mi.rcMonitor.top == 0 && mi.rcMonitor.right >= 640 && mi.rcMonitor.bottom >= 480,
152 "Unexpected monitor rcMonitor values: {%d,%d,%d,%d}\n",
153 mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom);
155 service_ok(mi.rcWork.left == 0 && mi.rcWork.top == 0 && mi.rcWork.right >= 640 && mi.rcWork.bottom >= 480,
156 "Unexpected monitor rcWork values: {%d,%d,%d,%d}\n",
157 mi.rcWork.left, mi.rcWork.top, mi.rcWork.right, mi.rcWork.bottom);
159 service_ok(!strcmp(mi.szDevice, "WinDisc") || !strcmp(mi.szDevice, "\\\\.\\DISPLAY1"),
160 "Unexpected szDevice received: %s\n", mi.szDevice);
162 service_ok(mi.dwFlags == MONITORINFOF_PRIMARY, "Unexpected secondary monitor info.\n");
164 return TRUE;
167 /* query monitor information, even in non-interactive services */
168 static void test_monitors(void)
170 BOOL r;
172 r = EnumDisplayMonitors(0, 0, monitor_enum_proc, 0);
173 service_ok(r, "EnumDisplayMonitors failed.\n");
174 service_ok(monitor_count == 1, "Callback got called less or more than once. %d\n", monitor_count);
177 static DWORD WINAPI service_handler(DWORD ctrl, DWORD event_type, void *event_data, void *context)
179 SERVICE_STATUS status;
181 status.dwServiceType = SERVICE_WIN32;
182 status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
183 status.dwWin32ExitCode = 0;
184 status.dwServiceSpecificExitCode = 0;
185 status.dwCheckPoint = 0;
186 status.dwWaitHint = 0;
188 switch(ctrl)
190 case SERVICE_CONTROL_STOP:
191 case SERVICE_CONTROL_SHUTDOWN:
192 service_event("STOP");
193 status.dwCurrentState = SERVICE_STOP_PENDING;
194 status.dwControlsAccepted = 0;
195 SetServiceStatus(service_handle, &status);
196 SetEvent(service_stop_event);
197 return NO_ERROR;
198 case 128:
199 test_winstation();
200 test_create_window();
201 test_monitors();
202 service_event("CUSTOM");
203 return 0xdeadbeef;
204 default:
205 status.dwCurrentState = SERVICE_RUNNING;
206 SetServiceStatus( service_handle, &status );
207 return NO_ERROR;
211 static void WINAPI service_main(DWORD argc, char **argv)
213 SERVICE_STATUS status;
214 char buf[64];
215 BOOL res;
217 service_ok(argc == 3, "argc = %u, expected 3\n", argc);
218 service_ok(!strcmp(argv[0], service_name), "argv[0] = '%s', expected '%s'\n", argv[0], service_name);
219 service_ok(!strcmp(argv[1], "param1"), "argv[1] = '%s', expected 'param1'\n", argv[1]);
220 service_ok(!strcmp(argv[2], "param2"), "argv[2] = '%s', expected 'param2'\n", argv[2]);
222 buf[0] = 0;
223 GetEnvironmentVariableA("PATHEXT", buf, sizeof(buf));
224 service_ok(buf[0], "did not find PATHEXT environment variable\n");
226 service_handle = pRegisterServiceCtrlHandlerExA(service_name, service_handler, NULL);
227 service_ok(service_handle != NULL, "RegisterServiceCtrlHandlerEx failed: %u\n", GetLastError());
228 if(!service_handle)
229 return;
231 status.dwServiceType = SERVICE_WIN32;
232 status.dwCurrentState = SERVICE_RUNNING;
233 status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
234 status.dwWin32ExitCode = 0;
235 status.dwServiceSpecificExitCode = 0;
236 status.dwCheckPoint = 0;
237 status.dwWaitHint = 10000;
238 res = SetServiceStatus(service_handle, &status);
239 service_ok(res, "SetServiceStatus(SERVICE_RUNNING) failed: %u\n", GetLastError());
241 service_event("RUNNING");
243 WaitForSingleObject(service_stop_event, INFINITE);
245 status.dwCurrentState = SERVICE_STOPPED;
246 status.dwControlsAccepted = 0;
247 res = SetServiceStatus(service_handle, &status);
248 service_ok(res, "SetServiceStatus(SERVICE_STOPPED) failed: %u\n", GetLastError());
251 static void service_process(void (WINAPI *p_service_main)(DWORD, char **))
253 BOOL res;
255 SERVICE_TABLE_ENTRYA servtbl[] = {
256 {service_name, p_service_main},
257 {NULL, NULL}
260 res = WaitNamedPipeA(named_pipe_name, NMPWAIT_USE_DEFAULT_WAIT);
261 if(!res)
262 return;
264 pipe_handle = CreateFileA(named_pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
265 if(pipe_handle == INVALID_HANDLE_VALUE)
266 return;
268 service_trace("Starting...\n");
270 service_stop_event = CreateEventA(NULL, TRUE, FALSE, NULL);
271 service_ok(service_stop_event != NULL, "Could not create event: %u\n", GetLastError());
272 if(!service_stop_event)
273 return;
275 res = StartServiceCtrlDispatcherA(servtbl);
276 service_ok(res, "StartServiceCtrlDispatcher failed: %u\n", GetLastError());
278 /* Let service thread terminate */
279 Sleep(50);
281 CloseHandle(service_stop_event);
282 CloseHandle(pipe_handle);
285 static DWORD WINAPI no_stop_handler(DWORD ctrl, DWORD event_type, void *event_data, void *context)
287 SERVICE_STATUS status;
289 status.dwServiceType = SERVICE_WIN32;
290 status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
291 status.dwWin32ExitCode = 0;
292 status.dwServiceSpecificExitCode = 0;
293 status.dwCheckPoint = 0;
294 status.dwWaitHint = 0;
296 switch(ctrl)
298 case SERVICE_CONTROL_STOP:
299 case SERVICE_CONTROL_SHUTDOWN:
300 service_event("STOP");
301 status.dwCurrentState = SERVICE_STOPPED;
302 status.dwControlsAccepted = 0;
303 SetServiceStatus(service_handle, &status);
304 SetEvent(service_stop_event);
305 return NO_ERROR;
306 default:
307 status.dwCurrentState = SERVICE_RUNNING;
308 SetServiceStatus( service_handle, &status );
309 return NO_ERROR;
313 static void WINAPI no_stop_main(DWORD argc, char **argv)
315 SERVICE_STATUS status;
316 BOOL res;
318 service_ok(argc == 1, "argc = %u, expected 1\n", argc);
319 service_ok(!strcmp(argv[0], service_name), "argv[0] = '%s', expected '%s'\n", argv[0], service_name);
321 service_handle = pRegisterServiceCtrlHandlerExA(service_name, no_stop_handler, NULL);
322 service_ok(service_handle != NULL, "RegisterServiceCtrlHandlerEx failed: %u\n", GetLastError());
323 if(!service_handle)
324 return;
326 status.dwServiceType = SERVICE_WIN32;
327 status.dwCurrentState = SERVICE_RUNNING;
328 status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
329 status.dwWin32ExitCode = 0;
330 status.dwServiceSpecificExitCode = 0;
331 status.dwCheckPoint = 0;
332 status.dwWaitHint = 10000;
333 res = SetServiceStatus(service_handle, &status);
334 service_ok(res, "SetServiceStatus(SERVICE_RUNNING) failed: %u\n", GetLastError());
336 service_event("RUNNING");
339 /* Test process global variables */
340 static SC_HANDLE scm_handle;
342 static char current_event[32];
343 static HANDLE event_handle = INVALID_HANDLE_VALUE;
344 static CRITICAL_SECTION event_cs;
346 static SC_HANDLE register_service(const char *test_name)
348 char service_cmd[MAX_PATH+150], *ptr;
349 SC_HANDLE service;
351 ptr = service_cmd + GetModuleFileNameA(NULL, service_cmd, MAX_PATH);
353 /* If the file doesn't exist, assume we're using built-in exe and append .so to the path */
354 if(GetFileAttributesA(service_cmd) == INVALID_FILE_ATTRIBUTES) {
355 strcpy(ptr, ".so");
356 ptr += 3;
359 strcpy(ptr, " service ");
360 ptr += strlen(ptr);
361 sprintf(ptr, "%s ", test_name);
362 ptr += strlen(ptr);
363 strcpy(ptr, service_name);
365 trace("service_cmd \"%s\"\n", service_cmd);
367 service = CreateServiceA(scm_handle, service_name, service_name, GENERIC_ALL,
368 SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE,
369 service_cmd, NULL, NULL, NULL, NULL, NULL);
370 if(!service && GetLastError() == ERROR_ACCESS_DENIED) {
371 skip("Not enough access right to create service\n");
372 return NULL;
375 ok(service != NULL, "CreateService failed: %u\n", GetLastError());
376 return service;
379 static void expect_event(const char *event_name)
381 char evt[32];
382 DWORD res;
384 trace("waiting for %s\n", event_name);
386 res = WaitForSingleObject(event_handle, 30000);
387 ok(res == WAIT_OBJECT_0, "WaitForSingleObject failed: %u\n", res);
388 if(res != WAIT_OBJECT_0)
389 return;
391 EnterCriticalSection(&event_cs);
392 strcpy(evt, current_event);
393 *current_event = 0;
394 LeaveCriticalSection(&event_cs);
396 ok(!strcmp(evt, event_name), "Unexpected event: %s, expected %s\n", evt, event_name);
399 static DWORD WINAPI pipe_thread(void *arg)
401 char buf[512], *ptr;
402 DWORD read;
403 BOOL res;
405 res = ConnectNamedPipe(pipe_handle, NULL);
406 ok(res || GetLastError() == ERROR_PIPE_CONNECTED, "ConnectNamedPipe failed: %u\n", GetLastError());
408 while(1) {
409 res = ReadFile(pipe_handle, buf, sizeof(buf), &read, NULL);
410 if(!res) {
411 ok(GetLastError() == ERROR_BROKEN_PIPE || GetLastError() == ERROR_INVALID_HANDLE,
412 "ReadFile failed: %u\n", GetLastError());
413 break;
416 for(ptr = buf; ptr < buf+read; ptr += strlen(ptr)+1) {
417 if(!strncmp(ptr, "TRACE:", 6)) {
418 trace("service trace: %s", ptr+6);
419 }else if(!strncmp(ptr, "OK:", 3)) {
420 ok(1, "service: %s", ptr+3);
421 }else if(!strncmp(ptr, "FAIL:", 5)) {
422 ok(0, "service: %s", ptr+5);
423 }else if(!strncmp(ptr, "EVENT:", 6)) {
424 trace("service event: %s\n", ptr+6);
425 EnterCriticalSection(&event_cs);
426 ok(!current_event[0], "event %s still queued\n", current_event);
427 strcpy(current_event, ptr+6);
428 LeaveCriticalSection(&event_cs);
429 SetEvent(event_handle);
430 }else {
431 ok(0, "malformed service message: %s\n", ptr);
436 DisconnectNamedPipe(pipe_handle);
437 trace("pipe disconnected\n");
438 return 0;
441 static void test_service(void)
443 static const char *argv[2] = {"param1", "param2"};
444 SC_HANDLE service_handle = register_service("simple_service");
445 SERVICE_STATUS_PROCESS status2;
446 SERVICE_STATUS status;
447 DWORD bytes;
448 BOOL res;
450 if(!service_handle)
451 return;
453 trace("starting...\n");
454 res = StartServiceA(service_handle, 2, argv);
455 ok(res, "StartService failed: %u\n", GetLastError());
456 if(!res) {
457 DeleteService(service_handle);
458 CloseServiceHandle(service_handle);
459 return;
461 expect_event("RUNNING");
463 res = QueryServiceStatus(service_handle, &status);
464 ok(res, "QueryServiceStatus failed: %d\n", GetLastError());
465 ok(status.dwServiceType == SERVICE_WIN32_OWN_PROCESS, "status.dwServiceType = %x\n", status.dwServiceType);
466 ok(status.dwCurrentState == SERVICE_RUNNING, "status.dwCurrentState = %x\n", status.dwCurrentState);
467 ok(status.dwControlsAccepted == (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN),
468 "status.dwControlsAccepted = %x\n", status.dwControlsAccepted);
469 ok(status.dwWin32ExitCode == 0, "status.dwExitCode = %d\n", status.dwWin32ExitCode);
470 ok(status.dwServiceSpecificExitCode == 0, "status.dwServiceSpecificExitCode = %d\n",
471 status.dwServiceSpecificExitCode);
472 ok(status.dwCheckPoint == 0, "status.dwCheckPoint = %d\n", status.dwCheckPoint);
473 todo_wine ok(status.dwWaitHint == 0, "status.dwWaitHint = %d\n", status.dwWaitHint);
475 res = QueryServiceStatusEx(service_handle, SC_STATUS_PROCESS_INFO, (BYTE *)&status2, sizeof(status2), &bytes);
476 ok(res, "QueryServiceStatusEx failed: %u\n", GetLastError());
477 ok(status2.dwCurrentState == SERVICE_RUNNING, "status2.dwCurrentState = %x\n", status2.dwCurrentState);
478 ok(status2.dwProcessId != 0, "status2.dwProcessId = %d\n", status2.dwProcessId);
480 res = ControlService(service_handle, 128, &status);
481 ok(res, "ControlService failed: %u\n", GetLastError());
482 expect_event("CUSTOM");
484 res = ControlService(service_handle, SERVICE_CONTROL_STOP, &status);
485 ok(res, "ControlService failed: %u\n", GetLastError());
486 expect_event("STOP");
488 res = DeleteService(service_handle);
489 ok(res, "DeleteService failed: %u\n", GetLastError());
491 CloseServiceHandle(service_handle);
494 static inline void test_no_stop(void)
496 SC_HANDLE service_handle = register_service("no_stop");
497 SERVICE_STATUS_PROCESS status2;
498 SERVICE_STATUS status;
499 DWORD bytes;
500 BOOL res;
502 if(!service_handle)
503 return;
505 trace("starting...\n");
506 res = StartServiceA(service_handle, 0, NULL);
507 ok(res, "StartService failed: %u\n", GetLastError());
508 if(!res) {
509 DeleteService(service_handle);
510 CloseServiceHandle(service_handle);
511 return;
513 expect_event("RUNNING");
515 /* Let service thread terminate */
516 Sleep(1000);
518 res = QueryServiceStatus(service_handle, &status);
519 ok(res, "QueryServiceStatus failed: %d\n", GetLastError());
520 ok(status.dwServiceType == SERVICE_WIN32_OWN_PROCESS, "status.dwServiceType = %x\n", status.dwServiceType);
521 ok(status.dwCurrentState == SERVICE_RUNNING, "status.dwCurrentState = %x\n", status.dwCurrentState);
522 ok(status.dwControlsAccepted == (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN),
523 "status.dwControlsAccepted = %x\n", status.dwControlsAccepted);
524 ok(status.dwWin32ExitCode == 0, "status.dwExitCode = %d\n", status.dwWin32ExitCode);
525 ok(status.dwServiceSpecificExitCode == 0, "status.dwServiceSpecificExitCode = %d\n",
526 status.dwServiceSpecificExitCode);
527 ok(status.dwCheckPoint == 0, "status.dwCheckPoint = %d\n", status.dwCheckPoint);
528 todo_wine ok(status.dwWaitHint == 0, "status.dwWaitHint = %d\n", status.dwWaitHint);
530 res = QueryServiceStatusEx(service_handle, SC_STATUS_PROCESS_INFO, (BYTE *)&status2, sizeof(status2), &bytes);
531 ok(res, "QueryServiceStatusEx failed: %u\n", GetLastError());
532 ok(status2.dwCurrentState == SERVICE_RUNNING, "status2.dwCurrentState = %x\n", status2.dwCurrentState);
533 ok(status2.dwProcessId != 0, "status2.dwProcessId = %d\n", status2.dwProcessId);
535 res = ControlService(service_handle, SERVICE_CONTROL_STOP, &status);
536 ok(res, "ControlService failed: %u\n", GetLastError());
537 expect_event("STOP");
539 res = QueryServiceStatus(service_handle, &status);
540 ok(res, "QueryServiceStatus failed: %d\n", GetLastError());
541 ok(status.dwServiceType == SERVICE_WIN32_OWN_PROCESS, "status.dwServiceType = %x\n", status.dwServiceType);
542 ok(status.dwCurrentState==SERVICE_STOPPED || status.dwCurrentState==SERVICE_STOP_PENDING,
543 "status.dwCurrentState = %x\n", status.dwCurrentState);
544 ok(status.dwControlsAccepted == 0, "status.dwControlsAccepted = %x\n", status.dwControlsAccepted);
545 ok(status.dwWin32ExitCode == 0, "status.dwExitCode = %d\n", status.dwWin32ExitCode);
546 ok(status.dwServiceSpecificExitCode == 0, "status.dwServiceSpecificExitCode = %d\n",
547 status.dwServiceSpecificExitCode);
548 ok(status.dwCheckPoint == 0, "status.dwCheckPoint = %d\n", status.dwCheckPoint);
549 ok(status.dwWaitHint == 0, "status.dwWaitHint = %d\n", status.dwWaitHint);
551 res = QueryServiceStatusEx(service_handle, SC_STATUS_PROCESS_INFO, (BYTE *)&status2, sizeof(status2), &bytes);
552 ok(res, "QueryServiceStatusEx failed: %u\n", GetLastError());
553 ok(status2.dwProcessId == 0 || broken(status2.dwProcessId != 0),
554 "status2.dwProcessId = %d\n", status2.dwProcessId);
556 res = DeleteService(service_handle);
557 ok(res, "DeleteService failed: %u\n", GetLastError());
559 res = QueryServiceStatus(service_handle, &status);
560 ok(res, "QueryServiceStatus failed: %d\n", GetLastError());
561 ok(status.dwServiceType == SERVICE_WIN32_OWN_PROCESS, "status.dwServiceType = %x\n", status.dwServiceType);
562 ok(status.dwCurrentState==SERVICE_STOPPED || status.dwCurrentState==SERVICE_STOP_PENDING,
563 "status.dwCurrentState = %x\n", status.dwCurrentState);
564 ok(status.dwControlsAccepted == 0, "status.dwControlsAccepted = %x\n", status.dwControlsAccepted);
565 ok(status.dwWin32ExitCode == 0, "status.dwExitCode = %d\n", status.dwWin32ExitCode);
566 ok(status.dwServiceSpecificExitCode == 0, "status.dwServiceSpecificExitCode = %d\n",
567 status.dwServiceSpecificExitCode);
568 ok(status.dwCheckPoint == 0, "status.dwCheckPoint = %d\n", status.dwCheckPoint);
569 ok(status.dwWaitHint == 0, "status.dwWaitHint = %d\n", status.dwWaitHint);
571 res = QueryServiceStatusEx(service_handle, SC_STATUS_PROCESS_INFO, (BYTE *)&status2, sizeof(status2), &bytes);
572 ok(res, "QueryServiceStatusEx failed: %u\n", GetLastError());
573 ok(status2.dwProcessId == 0 || broken(status2.dwProcessId != 0),
574 "status2.dwProcessId = %d\n", status2.dwProcessId);
576 CloseServiceHandle(service_handle);
578 res = QueryServiceStatus(service_handle, &status);
579 ok(!res, "QueryServiceStatus should have failed\n");
580 ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError = %d\n", GetLastError());
583 static void test_runner(void (*p_run_test)(void))
585 HANDLE thread;
587 sprintf(service_name, "WineTestService%d", GetTickCount());
588 trace("service_name: %s\n", service_name);
589 sprintf(named_pipe_name, "\\\\.\\pipe\\%s_pipe", service_name);
591 pipe_handle = CreateNamedPipeA(named_pipe_name, PIPE_ACCESS_INBOUND,
592 PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE|PIPE_WAIT, 10, 2048, 2048, 10000, NULL);
593 ok(pipe_handle != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %u\n", GetLastError());
594 if(pipe_handle == INVALID_HANDLE_VALUE)
595 return;
597 event_handle = CreateEventA(NULL, FALSE, FALSE, NULL);
598 ok(event_handle != INVALID_HANDLE_VALUE, "CreateEvent failed: %u\n", GetLastError());
599 if(event_handle == INVALID_HANDLE_VALUE)
600 return;
602 thread = CreateThread(NULL, 0, pipe_thread, NULL, 0, NULL);
603 ok(thread != NULL, "CreateThread failed: %u\n", GetLastError());
604 if(!thread)
605 return;
607 p_run_test();
609 WaitForSingleObject(thread, INFINITE);
610 CloseHandle(event_handle);
611 CloseHandle(pipe_handle);
612 CloseHandle(thread);
615 START_TEST(service)
617 char **argv;
618 int argc;
620 InitializeCriticalSection(&event_cs);
622 pRegisterServiceCtrlHandlerExA = (void*)GetProcAddress(GetModuleHandleA("advapi32.dll"), "RegisterServiceCtrlHandlerExA");
623 if(!pRegisterServiceCtrlHandlerExA) {
624 win_skip("RegisterServiceCtrlHandlerExA not available, skipping tests\n");
625 return;
628 scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL);
629 ok(scm_handle != NULL || GetLastError() == ERROR_ACCESS_DENIED, "OpenSCManager failed: %u\n", GetLastError());
630 if(!scm_handle) {
631 skip("OpenSCManager failed, skipping tests\n");
632 return;
635 argc = winetest_get_mainargs(&argv);
637 if(argc < 3) {
638 test_runner(test_service);
639 test_runner(test_no_stop);
640 }else {
641 strcpy(service_name, argv[3]);
642 sprintf(named_pipe_name, "\\\\.\\pipe\\%s_pipe", service_name);
644 if(!strcmp(argv[2], "simple_service"))
645 service_process(service_main);
646 else if(!strcmp(argv[2], "no_stop"))
647 service_process(no_stop_main);
650 CloseServiceHandle(scm_handle);