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
[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
)
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
, ...)
64 __ms_va_start(valist
, msg
);
65 vsprintf(buf
, msg
, valist
);
68 send_msg(cnd
? "OK" : "FAIL", buf
);
71 static void test_winstation(void)
74 USEROBJECTFLAGS flags
;
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)
96 static WNDCLASSEXA wndclass
= {
100 0, 0, NULL
, NULL
, NULL
, NULL
, 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
)
137 service_ok(hmon
!= NULL
, "Unexpected hmon=%#x\n", hmon
);
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");
167 /* query monitor information, even in non-interactive services */
168 static void test_monitors(void)
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;
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
);
200 test_create_window();
202 service_event("CUSTOM");
205 status
.dwCurrentState
= SERVICE_RUNNING
;
206 SetServiceStatus( service_handle
, &status
);
211 static void WINAPI
service_main(DWORD argc
, char **argv
)
213 SERVICE_STATUS status
;
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]);
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());
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 **))
255 SERVICE_TABLE_ENTRYA servtbl
[] = {
256 {service_name
, p_service_main
},
260 res
= WaitNamedPipeA(named_pipe_name
, NMPWAIT_USE_DEFAULT_WAIT
);
264 pipe_handle
= CreateFileA(named_pipe_name
, GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
265 if(pipe_handle
== INVALID_HANDLE_VALUE
)
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
)
275 res
= StartServiceCtrlDispatcherA(servtbl
);
276 service_ok(res
, "StartServiceCtrlDispatcher failed: %u\n", GetLastError());
278 /* Let service thread terminate */
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;
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
);
307 status
.dwCurrentState
= SERVICE_RUNNING
;
308 SetServiceStatus( service_handle
, &status
);
313 static void WINAPI
no_stop_main(DWORD argc
, char **argv
)
315 SERVICE_STATUS status
;
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());
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
;
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
) {
359 strcpy(ptr
, " service ");
361 sprintf(ptr
, "%s ", test_name
);
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");
375 ok(service
!= NULL
, "CreateService failed: %u\n", GetLastError());
379 static void expect_event(const char *event_name
)
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
)
391 EnterCriticalSection(&event_cs
);
392 strcpy(evt
, current_event
);
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
)
405 res
= ConnectNamedPipe(pipe_handle
, NULL
);
406 ok(res
|| GetLastError() == ERROR_PIPE_CONNECTED
, "ConnectNamedPipe failed: %u\n", GetLastError());
409 res
= ReadFile(pipe_handle
, buf
, sizeof(buf
), &read
, NULL
);
411 ok(GetLastError() == ERROR_BROKEN_PIPE
|| GetLastError() == ERROR_INVALID_HANDLE
,
412 "ReadFile failed: %u\n", GetLastError());
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
);
431 ok(0, "malformed service message: %s\n", ptr
);
436 DisconnectNamedPipe(pipe_handle
);
437 trace("pipe disconnected\n");
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
;
453 trace("starting...\n");
454 res
= StartServiceA(service_handle
, 2, argv
);
455 ok(res
, "StartService failed: %u\n", GetLastError());
457 DeleteService(service_handle
);
458 CloseServiceHandle(service_handle
);
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
;
505 trace("starting...\n");
506 res
= StartServiceA(service_handle
, 0, NULL
);
507 ok(res
, "StartService failed: %u\n", GetLastError());
509 DeleteService(service_handle
);
510 CloseServiceHandle(service_handle
);
513 expect_event("RUNNING");
515 /* Let service thread terminate */
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))
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
)
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
)
602 thread
= CreateThread(NULL
, 0, pipe_thread
, NULL
, 0, NULL
);
603 ok(thread
!= NULL
, "CreateThread failed: %u\n", GetLastError());
609 WaitForSingleObject(thread
, INFINITE
);
610 CloseHandle(event_handle
);
611 CloseHandle(pipe_handle
);
620 InitializeCriticalSection(&event_cs
);
622 pRegisterServiceCtrlHandlerExA
= (void*)GetProcAddress(GetModuleHandleA("advapi32.dll"), "RegisterServiceCtrlHandlerExA");
623 if(!pRegisterServiceCtrlHandlerExA
) {
624 win_skip("RegisterServiceCtrlHandlerExA not available, skipping tests\n");
628 scm_handle
= OpenSCManagerA(NULL
, NULL
, GENERIC_ALL
);
629 ok(scm_handle
!= NULL
|| GetLastError() == ERROR_ACCESS_DENIED
, "OpenSCManager failed: %u\n", GetLastError());
631 skip("OpenSCManager failed, skipping tests\n");
635 argc
= winetest_get_mainargs(&argv
);
638 test_runner(test_service
);
639 test_runner(test_no_stop
);
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
);