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 #if !defined(__WINE_USE_MSVCRT) || defined(__MINGW32__)
30 #define __WINE_PRINTF_ATTR(fmt,args) __attribute__((format (printf,fmt,args)))
32 #define __WINE_PRINTF_ATTR(fmt,args)
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
)
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
, ...)
71 __ms_va_start(valist
, msg
);
72 vsprintf(buf
, msg
, valist
);
75 send_msg(cnd
? "OK" : "FAIL", buf
);
78 static void test_winstation(void)
81 USEROBJECTFLAGS flags
;
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)
103 static WNDCLASSEXA wndclass
= {
107 0, 0, NULL
, NULL
, NULL
, NULL
, 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};
145 service_ok(hmon
!= NULL
, "Unexpected hmon %p\n", hmon
);
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");
171 /* query monitor information, even in non-interactive services */
172 static void test_monitors(void)
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;
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
);
204 test_create_window();
206 service_event("CUSTOM");
209 status
.dwCurrentState
= SERVICE_RUNNING
;
210 SetServiceStatus( service_handle
, &status
);
215 static void WINAPI
service_main(DWORD argc
, char **argv
)
217 SERVICE_STATUS status
;
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]);
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());
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 **))
259 SERVICE_TABLE_ENTRYA servtbl
[] = {
260 {service_name
, p_service_main
},
264 res
= WaitNamedPipeA(named_pipe_name
, NMPWAIT_USE_DEFAULT_WAIT
);
268 pipe_handle
= CreateFileA(named_pipe_name
, GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
269 if(pipe_handle
== INVALID_HANDLE_VALUE
)
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
)
279 res
= StartServiceCtrlDispatcherA(servtbl
);
280 service_ok(res
, "StartServiceCtrlDispatcher failed: %u\n", GetLastError());
282 /* Let service thread terminate */
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;
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
);
311 status
.dwCurrentState
= SERVICE_RUNNING
;
312 SetServiceStatus( service_handle
, &status
);
317 static void WINAPI
no_stop_main(DWORD argc
, char **argv
)
319 SERVICE_STATUS status
;
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());
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
;
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
) {
363 strcpy(ptr
, " service ");
365 sprintf(ptr
, "%s ", test_name
);
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");
379 ok(service
!= NULL
, "CreateService failed: %u\n", GetLastError());
383 static void expect_event(const char *event_name
)
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
)
395 EnterCriticalSection(&event_cs
);
396 strcpy(evt
, current_event
);
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
)
409 res
= ConnectNamedPipe(pipe_handle
, NULL
);
410 ok(res
|| GetLastError() == ERROR_PIPE_CONNECTED
, "ConnectNamedPipe failed: %u\n", GetLastError());
413 res
= ReadFile(pipe_handle
, buf
, sizeof(buf
), &read
, NULL
);
415 ok(GetLastError() == ERROR_BROKEN_PIPE
|| GetLastError() == ERROR_INVALID_HANDLE
,
416 "ReadFile failed: %u\n", GetLastError());
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
);
435 ok(0, "malformed service message: %s\n", ptr
);
440 DisconnectNamedPipe(pipe_handle
);
441 trace("pipe disconnected\n");
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
;
457 trace("starting...\n");
458 res
= StartServiceA(service_handle
, 2, argv
);
459 ok(res
, "StartService failed: %u\n", GetLastError());
461 DeleteService(service_handle
);
462 CloseServiceHandle(service_handle
);
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
;
509 trace("starting...\n");
510 res
= StartServiceA(service_handle
, 0, NULL
);
511 ok(res
, "StartService failed: %u\n", GetLastError());
513 DeleteService(service_handle
);
514 CloseServiceHandle(service_handle
);
517 expect_event("RUNNING");
519 /* Let service thread terminate */
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))
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
)
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
)
606 thread
= CreateThread(NULL
, 0, pipe_thread
, NULL
, 0, NULL
);
607 ok(thread
!= NULL
, "CreateThread failed: %u\n", GetLastError());
613 WaitForSingleObject(thread
, INFINITE
);
614 CloseHandle(event_handle
);
615 CloseHandle(pipe_handle
);
624 InitializeCriticalSection(&event_cs
);
626 pRegisterServiceCtrlHandlerExA
= (void*)GetProcAddress(GetModuleHandleA("advapi32.dll"), "RegisterServiceCtrlHandlerExA");
627 if(!pRegisterServiceCtrlHandlerExA
) {
628 win_skip("RegisterServiceCtrlHandlerExA not available, skipping tests\n");
632 scm_handle
= OpenSCManagerA(NULL
, NULL
, GENERIC_ALL
);
633 ok(scm_handle
!= NULL
|| GetLastError() == ERROR_ACCESS_DENIED
, "OpenSCManager failed: %u\n", GetLastError());
635 skip("OpenSCManager failed, skipping tests\n");
639 argc
= winetest_get_mainargs(&argv
);
642 test_runner(test_service
);
643 test_runner(test_no_stop
);
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
);