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
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
[100];
33 static SERVICE_STATUS_HANDLE service_handle
;
35 /* Service process global variables */
36 static HANDLE service_stop_event
;
38 static void send_msg(const char *type
, const char *msg
)
43 sprintf(buf
, "%s:%s", type
, msg
);
44 WriteFile(pipe_handle
, buf
, strlen(buf
)+1, &written
, NULL
);
47 static inline void service_trace(const char *msg
)
49 send_msg("TRACE", msg
);
52 static inline void service_event(const char *event
)
54 send_msg("EVENT", event
);
57 static void service_ok(int cnd
, const char *msg
, ...)
62 va_start(valist
, msg
);
63 vsprintf(buf
, msg
, valist
);
66 send_msg(cnd
? "OK" : "FAIL", buf
);
69 static void test_winstation(void)
72 USEROBJECTFLAGS flags
;
75 winstation
= GetProcessWindowStation();
76 service_ok(winstation
!= NULL
, "winstation = NULL\n");
78 r
= GetUserObjectInformationA(winstation
, UOI_FLAGS
, &flags
, sizeof(flags
), NULL
);
79 service_ok(r
, "GetUserObjectInformation(UOI_NAME) failed: %u\n", GetLastError());
80 service_ok(!(flags
.dwFlags
& WSF_VISIBLE
), "winstation has flags %x\n", flags
.dwFlags
);
84 * Test creating window in a service process. Although services run in non-interactive,
85 * they may create windows that will never be visible.
87 static void test_create_window(void)
94 static WNDCLASSEXA wndclass
= {
98 0, 0, NULL
, NULL
, NULL
, NULL
, NULL
,
103 hwnd
= GetDesktopWindow();
104 service_ok(IsWindow(hwnd
), "GetDesktopWindow returned invalid window %p\n", hwnd
);
106 class = RegisterClassExA(&wndclass
);
107 service_ok(class, "RegisterClassFailed\n");
109 hwnd
= CreateWindowA("service_test", "service_test",
110 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, CW_USEDEFAULT
,
111 515, 530, NULL
, NULL
, NULL
, NULL
);
112 service_ok(hwnd
!= NULL
, "CreateWindow failed: %u\n", GetLastError());
114 style
= GetWindowLongW(hwnd
, GWL_STYLE
);
115 service_ok(!(style
& WS_VISIBLE
), "style = %x, expected invisible\n", style
);
117 r
= ShowWindow(hwnd
, SW_SHOW
);
118 service_ok(!r
, "ShowWindow returned %x\n", r
);
120 style
= GetWindowLongW(hwnd
, GWL_STYLE
);
121 service_ok(style
& WS_VISIBLE
, "style = %x, expected visible\n", style
);
123 r
= ShowWindow(hwnd
, SW_SHOW
);
124 service_ok(r
, "ShowWindow returned %x\n", r
);
126 r
= DestroyWindow(hwnd
);
127 service_ok(r
, "DestroyWindow failed: %08x\n", GetLastError());
130 static DWORD WINAPI
service_handler(DWORD ctrl
, DWORD event_type
, void *event_data
, void *context
)
132 SERVICE_STATUS status
;
134 status
.dwServiceType
= SERVICE_WIN32
;
135 status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
136 status
.dwWin32ExitCode
= 0;
137 status
.dwServiceSpecificExitCode
= 0;
138 status
.dwCheckPoint
= 0;
139 status
.dwWaitHint
= 0;
143 case SERVICE_CONTROL_STOP
:
144 case SERVICE_CONTROL_SHUTDOWN
:
145 service_event("STOP");
146 status
.dwCurrentState
= SERVICE_STOP_PENDING
;
147 status
.dwControlsAccepted
= 0;
148 SetServiceStatus(service_handle
, &status
);
149 SetEvent(service_stop_event
);
153 test_create_window();
154 service_event("CUSTOM");
157 status
.dwCurrentState
= SERVICE_RUNNING
;
158 SetServiceStatus( service_handle
, &status
);
163 static void WINAPI
service_main(DWORD argc
, char **argv
)
165 SERVICE_STATUS status
;
169 service_ok(argc
== 3, "argc = %u, expected 3\n", argc
);
170 service_ok(!strcmp(argv
[0], service_name
), "argv[0] = '%s', expected '%s'\n", argv
[0], service_name
);
171 service_ok(!strcmp(argv
[1], "param1"), "argv[1] = '%s', expected 'param1'\n", argv
[1]);
172 service_ok(!strcmp(argv
[2], "param2"), "argv[2] = '%s', expected 'param2'\n", argv
[2]);
175 GetEnvironmentVariableA("PATHEXT", buf
, sizeof(buf
));
176 service_ok(buf
[0], "did not find PATHEXT environment variable\n");
178 service_handle
= pRegisterServiceCtrlHandlerExA(service_name
, service_handler
, NULL
);
179 service_ok(service_handle
!= NULL
, "RegisterServiceCtrlHandlerEx failed: %u\n", GetLastError());
183 status
.dwServiceType
= SERVICE_WIN32
;
184 status
.dwCurrentState
= SERVICE_RUNNING
;
185 status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
| SERVICE_ACCEPT_SHUTDOWN
;
186 status
.dwWin32ExitCode
= 0;
187 status
.dwServiceSpecificExitCode
= 0;
188 status
.dwCheckPoint
= 0;
189 status
.dwWaitHint
= 10000;
190 res
= SetServiceStatus(service_handle
, &status
);
191 service_ok(res
, "SetServiceStatus(SERVICE_RUNNING) failed: %u\n", GetLastError());
193 service_event("RUNNING");
195 WaitForSingleObject(service_stop_event
, INFINITE
);
197 status
.dwCurrentState
= SERVICE_STOPPED
;
198 status
.dwControlsAccepted
= 0;
199 res
= SetServiceStatus(service_handle
, &status
);
200 service_ok(res
, "SetServiceStatus(SERVICE_STOPPED) failed: %u\n", GetLastError());
203 static void service_process(void (WINAPI
*p_service_main
)(DWORD
, char **))
207 SERVICE_TABLE_ENTRYA servtbl
[] = {
208 {service_name
, p_service_main
},
212 res
= WaitNamedPipeA(named_pipe_name
, NMPWAIT_USE_DEFAULT_WAIT
);
216 pipe_handle
= CreateFileA(named_pipe_name
, GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
217 if(pipe_handle
== INVALID_HANDLE_VALUE
)
220 service_trace("Starting...\n");
222 service_stop_event
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
223 service_ok(service_stop_event
!= NULL
, "Could not create event: %u\n", GetLastError());
224 if(!service_stop_event
)
227 res
= StartServiceCtrlDispatcherA(servtbl
);
228 service_ok(res
, "StartServiceCtrlDispatcher failed: %u\n", GetLastError());
230 /* Let service thread terminate */
233 CloseHandle(service_stop_event
);
234 CloseHandle(pipe_handle
);
237 static DWORD WINAPI
no_stop_handler(DWORD ctrl
, DWORD event_type
, void *event_data
, void *context
)
239 SERVICE_STATUS status
;
241 status
.dwServiceType
= SERVICE_WIN32
;
242 status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
243 status
.dwWin32ExitCode
= 0;
244 status
.dwServiceSpecificExitCode
= 0;
245 status
.dwCheckPoint
= 0;
246 status
.dwWaitHint
= 0;
250 case SERVICE_CONTROL_STOP
:
251 case SERVICE_CONTROL_SHUTDOWN
:
252 service_event("STOP");
253 status
.dwCurrentState
= SERVICE_STOPPED
;
254 status
.dwControlsAccepted
= 0;
255 SetServiceStatus(service_handle
, &status
);
256 SetEvent(service_stop_event
);
259 status
.dwCurrentState
= SERVICE_RUNNING
;
260 SetServiceStatus( service_handle
, &status
);
265 static void WINAPI
no_stop_main(DWORD argc
, char **argv
)
267 SERVICE_STATUS status
;
270 service_ok(argc
== 1, "argc = %u, expected 1\n", argc
);
271 service_ok(!strcmp(argv
[0], service_name
), "argv[0] = '%s', expected '%s'\n", argv
[0], service_name
);
273 service_handle
= pRegisterServiceCtrlHandlerExA(service_name
, no_stop_handler
, NULL
);
274 service_ok(service_handle
!= NULL
, "RegisterServiceCtrlHandlerEx failed: %u\n", GetLastError());
278 status
.dwServiceType
= SERVICE_WIN32
;
279 status
.dwCurrentState
= SERVICE_RUNNING
;
280 status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
| SERVICE_ACCEPT_SHUTDOWN
;
281 status
.dwWin32ExitCode
= 0;
282 status
.dwServiceSpecificExitCode
= 0;
283 status
.dwCheckPoint
= 0;
284 status
.dwWaitHint
= 10000;
285 res
= SetServiceStatus(service_handle
, &status
);
286 service_ok(res
, "SetServiceStatus(SERVICE_RUNNING) failed: %u\n", GetLastError());
288 service_event("RUNNING");
291 /* Test process global variables */
292 static SC_HANDLE scm_handle
;
294 static char current_event
[32];
295 static HANDLE event_handle
= INVALID_HANDLE_VALUE
;
296 static CRITICAL_SECTION event_cs
;
298 static SC_HANDLE
register_service(const char *test_name
)
300 char service_cmd
[MAX_PATH
+150], *ptr
;
303 ptr
= service_cmd
+ GetModuleFileNameA(NULL
, service_cmd
, MAX_PATH
);
305 /* If the file doesn't exist, assume we're using built-in exe and append .so to the path */
306 if(GetFileAttributesA(service_cmd
) == INVALID_FILE_ATTRIBUTES
) {
311 strcpy(ptr
, " service ");
313 sprintf(ptr
, "%s ", test_name
);
315 strcpy(ptr
, service_name
);
317 trace("service_cmd \"%s\"\n", service_cmd
);
319 service
= CreateServiceA(scm_handle
, service_name
, service_name
, GENERIC_ALL
,
320 SERVICE_WIN32_OWN_PROCESS
, SERVICE_DEMAND_START
, SERVICE_ERROR_IGNORE
,
321 service_cmd
, NULL
, NULL
, NULL
, NULL
, NULL
);
322 if(!service
&& GetLastError() == ERROR_ACCESS_DENIED
) {
323 skip("Not enough access right to create service\n");
327 ok(service
!= NULL
, "CreateService failed: %u\n", GetLastError());
331 static void expect_event(const char *event_name
)
336 trace("waiting for %s\n", event_name
);
338 res
= WaitForSingleObject(event_handle
, 30000);
339 ok(res
== WAIT_OBJECT_0
, "WaitForSingleObject failed: %u\n", res
);
340 if(res
!= WAIT_OBJECT_0
)
343 EnterCriticalSection(&event_cs
);
344 strcpy(evt
, current_event
);
346 LeaveCriticalSection(&event_cs
);
348 ok(!strcmp(evt
, event_name
), "Unexpected event: %s, expected %s\n", evt
, event_name
);
351 static DWORD WINAPI
pipe_thread(void *arg
)
357 res
= ConnectNamedPipe(pipe_handle
, NULL
);
358 ok(res
|| GetLastError() == ERROR_PIPE_CONNECTED
, "ConnectNamedPipe failed: %u\n", GetLastError());
361 res
= ReadFile(pipe_handle
, buf
, sizeof(buf
), &read
, NULL
);
363 ok(GetLastError() == ERROR_BROKEN_PIPE
|| GetLastError() == ERROR_INVALID_HANDLE
,
364 "ReadFile failed: %u\n", GetLastError());
368 for(ptr
= buf
; ptr
< buf
+read
; ptr
+= strlen(ptr
)+1) {
369 if(!strncmp(ptr
, "TRACE:", 6)) {
370 trace("service trace: %s", ptr
+6);
371 }else if(!strncmp(ptr
, "OK:", 3)) {
372 ok(1, "service: %s", ptr
+3);
373 }else if(!strncmp(ptr
, "FAIL:", 5)) {
374 ok(0, "service: %s", ptr
+5);
375 }else if(!strncmp(ptr
, "EVENT:", 6)) {
376 trace("service event: %s\n", ptr
+6);
377 EnterCriticalSection(&event_cs
);
378 ok(!current_event
[0], "event %s still queued\n", current_event
);
379 strcpy(current_event
, ptr
+6);
380 LeaveCriticalSection(&event_cs
);
381 SetEvent(event_handle
);
383 ok(0, "malformed service message: %s\n", ptr
);
388 DisconnectNamedPipe(pipe_handle
);
389 trace("pipe disconnected\n");
393 static void test_service(void)
395 static const char *argv
[2] = {"param1", "param2"};
396 SC_HANDLE service_handle
= register_service("simple_service");
397 SERVICE_STATUS_PROCESS status2
;
398 SERVICE_STATUS status
;
405 trace("starting...\n");
406 res
= StartServiceA(service_handle
, 2, argv
);
407 ok(res
, "StartService failed: %u\n", GetLastError());
409 DeleteService(service_handle
);
410 CloseServiceHandle(service_handle
);
413 expect_event("RUNNING");
415 res
= QueryServiceStatus(service_handle
, &status
);
416 ok(res
, "QueryServiceStatus failed: %d\n", GetLastError());
417 todo_wine
ok(status
.dwServiceType
== SERVICE_WIN32_OWN_PROCESS
, "status.dwServiceType = %x\n", status
.dwServiceType
);
418 ok(status
.dwCurrentState
== SERVICE_RUNNING
, "status.dwCurrentState = %x\n", status
.dwCurrentState
);
419 ok(status
.dwControlsAccepted
== (SERVICE_ACCEPT_STOP
| SERVICE_ACCEPT_SHUTDOWN
),
420 "status.dwControlsAccepted = %x\n", status
.dwControlsAccepted
);
421 ok(status
.dwWin32ExitCode
== 0, "status.dwExitCode = %d\n", status
.dwWin32ExitCode
);
422 ok(status
.dwServiceSpecificExitCode
== 0, "status.dwServiceSpecificExitCode = %d\n",
423 status
.dwServiceSpecificExitCode
);
424 ok(status
.dwCheckPoint
== 0, "status.dwCheckPoint = %d\n", status
.dwCheckPoint
);
425 todo_wine
ok(status
.dwWaitHint
== 0, "status.dwWaitHint = %d\n", status
.dwWaitHint
);
427 res
= QueryServiceStatusEx(service_handle
, SC_STATUS_PROCESS_INFO
, (BYTE
*)&status2
, sizeof(status2
), &bytes
);
428 ok(res
, "QueryServiceStatusEx failed: %u\n", GetLastError());
429 ok(status2
.dwCurrentState
== SERVICE_RUNNING
, "status2.dwCurrentState = %x\n", status2
.dwCurrentState
);
430 ok(status2
.dwProcessId
!= 0, "status2.dwProcessId = %d\n", status2
.dwProcessId
);
432 res
= ControlService(service_handle
, 128, &status
);
433 ok(res
, "ControlService failed: %u\n", GetLastError());
434 expect_event("CUSTOM");
436 res
= ControlService(service_handle
, SERVICE_CONTROL_STOP
, &status
);
437 ok(res
, "ControlService failed: %u\n", GetLastError());
438 expect_event("STOP");
440 res
= DeleteService(service_handle
);
441 ok(res
, "DeleteService failed: %u\n", GetLastError());
443 CloseServiceHandle(service_handle
);
446 static inline void test_no_stop(void)
448 SC_HANDLE service_handle
= register_service("no_stop");
449 SERVICE_STATUS_PROCESS status2
;
450 SERVICE_STATUS status
;
457 trace("starting...\n");
458 res
= StartServiceA(service_handle
, 0, NULL
);
459 ok(res
, "StartService failed: %u\n", GetLastError());
461 DeleteService(service_handle
);
462 CloseServiceHandle(service_handle
);
465 expect_event("RUNNING");
467 /* Let service thread terminate */
470 res
= QueryServiceStatus(service_handle
, &status
);
471 ok(res
, "QueryServiceStatus failed: %d\n", GetLastError());
472 todo_wine
ok(status
.dwServiceType
== SERVICE_WIN32_OWN_PROCESS
, "status.dwServiceType = %x\n", status
.dwServiceType
);
473 ok(status
.dwCurrentState
== SERVICE_RUNNING
, "status.dwCurrentState = %x\n", status
.dwCurrentState
);
474 ok(status
.dwControlsAccepted
== (SERVICE_ACCEPT_STOP
| SERVICE_ACCEPT_SHUTDOWN
),
475 "status.dwControlsAccepted = %x\n", status
.dwControlsAccepted
);
476 ok(status
.dwWin32ExitCode
== 0, "status.dwExitCode = %d\n", status
.dwWin32ExitCode
);
477 ok(status
.dwServiceSpecificExitCode
== 0, "status.dwServiceSpecificExitCode = %d\n",
478 status
.dwServiceSpecificExitCode
);
479 ok(status
.dwCheckPoint
== 0, "status.dwCheckPoint = %d\n", status
.dwCheckPoint
);
480 todo_wine
ok(status
.dwWaitHint
== 0, "status.dwWaitHint = %d\n", status
.dwWaitHint
);
482 res
= QueryServiceStatusEx(service_handle
, SC_STATUS_PROCESS_INFO
, (BYTE
*)&status2
, sizeof(status2
), &bytes
);
483 ok(res
, "QueryServiceStatusEx failed: %u\n", GetLastError());
484 ok(status2
.dwCurrentState
== SERVICE_RUNNING
, "status2.dwCurrentState = %x\n", status2
.dwCurrentState
);
485 ok(status2
.dwProcessId
!= 0, "status2.dwProcessId = %d\n", status2
.dwProcessId
);
487 res
= ControlService(service_handle
, SERVICE_CONTROL_STOP
, &status
);
488 ok(res
, "ControlService failed: %u\n", GetLastError());
489 expect_event("STOP");
491 res
= QueryServiceStatus(service_handle
, &status
);
492 ok(res
, "QueryServiceStatus failed: %d\n", GetLastError());
493 todo_wine
ok(status
.dwServiceType
== SERVICE_WIN32_OWN_PROCESS
, "status.dwServiceType = %x\n", status
.dwServiceType
);
494 ok(status
.dwCurrentState
==SERVICE_STOPPED
|| status
.dwCurrentState
==SERVICE_STOP_PENDING
,
495 "status.dwCurrentState = %x\n", status
.dwCurrentState
);
496 ok(status
.dwControlsAccepted
== 0, "status.dwControlsAccepted = %x\n", status
.dwControlsAccepted
);
497 ok(status
.dwWin32ExitCode
== 0, "status.dwExitCode = %d\n", status
.dwWin32ExitCode
);
498 ok(status
.dwServiceSpecificExitCode
== 0, "status.dwServiceSpecificExitCode = %d\n",
499 status
.dwServiceSpecificExitCode
);
500 ok(status
.dwCheckPoint
== 0, "status.dwCheckPoint = %d\n", status
.dwCheckPoint
);
501 ok(status
.dwWaitHint
== 0, "status.dwWaitHint = %d\n", status
.dwWaitHint
);
503 res
= QueryServiceStatusEx(service_handle
, SC_STATUS_PROCESS_INFO
, (BYTE
*)&status2
, sizeof(status2
), &bytes
);
504 ok(res
, "QueryServiceStatusEx failed: %u\n", GetLastError());
505 ok(status2
.dwProcessId
== 0 || broken(status2
.dwProcessId
!= 0),
506 "status2.dwProcessId = %d\n", status2
.dwProcessId
);
508 res
= DeleteService(service_handle
);
509 ok(res
, "DeleteService failed: %u\n", GetLastError());
511 res
= QueryServiceStatus(service_handle
, &status
);
512 ok(res
, "QueryServiceStatus failed: %d\n", GetLastError());
513 todo_wine
ok(status
.dwServiceType
== SERVICE_WIN32_OWN_PROCESS
, "status.dwServiceType = %x\n", status
.dwServiceType
);
514 ok(status
.dwCurrentState
==SERVICE_STOPPED
|| status
.dwCurrentState
==SERVICE_STOP_PENDING
,
515 "status.dwCurrentState = %x\n", status
.dwCurrentState
);
516 ok(status
.dwControlsAccepted
== 0, "status.dwControlsAccepted = %x\n", status
.dwControlsAccepted
);
517 ok(status
.dwWin32ExitCode
== 0, "status.dwExitCode = %d\n", status
.dwWin32ExitCode
);
518 ok(status
.dwServiceSpecificExitCode
== 0, "status.dwServiceSpecificExitCode = %d\n",
519 status
.dwServiceSpecificExitCode
);
520 ok(status
.dwCheckPoint
== 0, "status.dwCheckPoint = %d\n", status
.dwCheckPoint
);
521 ok(status
.dwWaitHint
== 0, "status.dwWaitHint = %d\n", status
.dwWaitHint
);
523 res
= QueryServiceStatusEx(service_handle
, SC_STATUS_PROCESS_INFO
, (BYTE
*)&status2
, sizeof(status2
), &bytes
);
524 ok(res
, "QueryServiceStatusEx failed: %u\n", GetLastError());
525 ok(status2
.dwProcessId
== 0 || broken(status2
.dwProcessId
!= 0),
526 "status2.dwProcessId = %d\n", status2
.dwProcessId
);
528 CloseServiceHandle(service_handle
);
530 res
= QueryServiceStatus(service_handle
, &status
);
531 ok(!res
, "QueryServiceStatus should have failed\n");
532 ok(GetLastError() == ERROR_INVALID_HANDLE
, "GetLastError = %d\n", GetLastError());
535 static void test_runner(void (*p_run_test
)(void))
539 sprintf(service_name
, "WineTestService%d", GetTickCount());
540 trace("service_name: %s\n", service_name
);
541 sprintf(named_pipe_name
, "\\\\.\\pipe\\%s_pipe", service_name
);
543 pipe_handle
= CreateNamedPipeA(named_pipe_name
, PIPE_ACCESS_INBOUND
,
544 PIPE_TYPE_BYTE
|PIPE_READMODE_BYTE
|PIPE_WAIT
, 10, 2048, 2048, 10000, NULL
);
545 ok(pipe_handle
!= INVALID_HANDLE_VALUE
, "CreateNamedPipe failed: %u\n", GetLastError());
546 if(pipe_handle
== INVALID_HANDLE_VALUE
)
549 event_handle
= CreateEventA(NULL
, FALSE
, FALSE
, NULL
);
550 ok(event_handle
!= INVALID_HANDLE_VALUE
, "CreateEvent failed: %u\n", GetLastError());
551 if(event_handle
== INVALID_HANDLE_VALUE
)
554 thread
= CreateThread(NULL
, 0, pipe_thread
, NULL
, 0, NULL
);
555 ok(thread
!= NULL
, "CreateThread failed: %u\n", GetLastError());
561 WaitForSingleObject(thread
, INFINITE
);
562 CloseHandle(event_handle
);
563 CloseHandle(pipe_handle
);
572 InitializeCriticalSection(&event_cs
);
574 pRegisterServiceCtrlHandlerExA
= (void*)GetProcAddress(GetModuleHandleA("advapi32.dll"), "RegisterServiceCtrlHandlerExA");
575 if(!pRegisterServiceCtrlHandlerExA
) {
576 win_skip("RegisterServiceCtrlHandlerExA not available, skipping tests\n");
580 scm_handle
= OpenSCManagerA(NULL
, NULL
, GENERIC_ALL
);
581 ok(scm_handle
!= NULL
|| GetLastError() == ERROR_ACCESS_DENIED
, "OpenSCManager failed: %u\n", GetLastError());
583 skip("OpenSCManager failed, skipping tests\n");
587 argc
= winetest_get_mainargs(&argv
);
590 test_runner(test_service
);
591 test_runner(test_no_stop
);
593 strcpy(service_name
, argv
[3]);
594 sprintf(named_pipe_name
, "\\\\.\\pipe\\%s_pipe", service_name
);
596 if(!strcmp(argv
[2], "simple_service"))
597 service_process(service_main
);
598 else if(!strcmp(argv
[2], "no_stop"))
599 service_process(no_stop_main
);
602 CloseServiceHandle(scm_handle
);