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
22 #include "wine/test.h"
24 static SERVICE_STATUS_HANDLE (WINAPI
*pRegisterServiceCtrlHandlerExA
)(LPCSTR
,LPHANDLER_FUNCTION_EX
,LPVOID
);
26 static HANDLE pipe_handle
= INVALID_HANDLE_VALUE
;
27 static char service_name
[100], named_pipe_name
[100];
28 static SERVICE_STATUS_HANDLE service_handle
;
30 /* Service process global variables */
31 static HANDLE service_stop_event
;
33 static void send_msg(const char *type
, const char *msg
)
38 sprintf(buf
, "%s:%s", type
, msg
);
39 WriteFile(pipe_handle
, buf
, strlen(buf
)+1, &written
, NULL
);
42 static inline void service_trace(const char *msg
)
44 send_msg("TRACE", msg
);
47 static inline void service_event(const char *event
)
49 send_msg("EVENT", event
);
52 static void service_ok(int cnd
, const char *msg
, ...)
57 va_start(valist
, msg
);
58 vsprintf(buf
, msg
, valist
);
61 send_msg(cnd
? "OK" : "FAIL", buf
);
64 static DWORD WINAPI
service_handler(DWORD ctrl
, DWORD event_type
, void *event_data
, void *context
)
66 SERVICE_STATUS status
;
68 status
.dwServiceType
= SERVICE_WIN32
;
69 status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
70 status
.dwWin32ExitCode
= 0;
71 status
.dwServiceSpecificExitCode
= 0;
72 status
.dwCheckPoint
= 0;
73 status
.dwWaitHint
= 0;
77 case SERVICE_CONTROL_STOP
:
78 case SERVICE_CONTROL_SHUTDOWN
:
79 service_event("STOP");
80 status
.dwCurrentState
= SERVICE_STOP_PENDING
;
81 status
.dwControlsAccepted
= 0;
82 SetServiceStatus(service_handle
, &status
);
83 SetEvent(service_stop_event
);
86 status
.dwCurrentState
= SERVICE_RUNNING
;
87 SetServiceStatus( service_handle
, &status
);
92 static void WINAPI
service_main(DWORD argc
, char **argv
)
94 SERVICE_STATUS status
;
97 service_ok(argc
== 1, "argc = %d", argc
);
99 service_ok(!strcmp(argv
[0], service_name
), "argv[0] = %s, expected %s", argv
[0], service_name
);
101 service_handle
= pRegisterServiceCtrlHandlerExA(service_name
, service_handler
, NULL
);
102 service_ok(service_handle
!= NULL
, "RegisterServiceCtrlHandlerEx failed: %u\n", GetLastError());
106 status
.dwServiceType
= SERVICE_WIN32
;
107 status
.dwCurrentState
= SERVICE_RUNNING
;
108 status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
| SERVICE_ACCEPT_SHUTDOWN
;
109 status
.dwWin32ExitCode
= 0;
110 status
.dwServiceSpecificExitCode
= 0;
111 status
.dwCheckPoint
= 0;
112 status
.dwWaitHint
= 10000;
113 res
= SetServiceStatus(service_handle
, &status
);
114 service_ok(res
, "SetServiceStatus(SERVICE_RUNNING) failed: %u", GetLastError());
116 service_event("RUNNING");
118 WaitForSingleObject(service_stop_event
, INFINITE
);
120 status
.dwCurrentState
= SERVICE_STOPPED
;
121 status
.dwControlsAccepted
= 0;
122 res
= SetServiceStatus(service_handle
, &status
);
123 service_ok(res
, "SetServiceStatus(SERVICE_STOPPED) failed: %u", GetLastError());
126 static void service_process(void)
130 static const SERVICE_TABLE_ENTRYA servtbl
[] = {
131 {service_name
, service_main
},
135 res
= WaitNamedPipeA(named_pipe_name
, NMPWAIT_USE_DEFAULT_WAIT
);
139 pipe_handle
= CreateFileA(named_pipe_name
, GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
140 if(pipe_handle
== INVALID_HANDLE_VALUE
)
143 service_trace("Starting...");
145 service_stop_event
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
146 service_ok(service_stop_event
!= NULL
, "Could not create event: %u\n", GetLastError());
147 if(!service_stop_event
)
150 res
= StartServiceCtrlDispatcherA(servtbl
);
151 service_ok(res
, "StartServiceCtrlDispatcher failed: %u\n", GetLastError());
153 CloseHandle(service_stop_event
);
156 /* Test process global variables */
157 static SC_HANDLE scm_handle
;
159 static char current_event
[32];
160 static HANDLE event_handle
= INVALID_HANDLE_VALUE
;
161 static CRITICAL_SECTION event_cs
;
163 static SC_HANDLE
register_service(void)
165 char service_cmd
[MAX_PATH
+150], *ptr
;
168 ptr
= service_cmd
+ GetModuleFileNameA(NULL
, service_cmd
, MAX_PATH
);
170 /* If the file doesn't exist, assume we're using built-in exe and append .so to the path */
171 if(GetFileAttributesA(service_cmd
) == INVALID_FILE_ATTRIBUTES
) {
176 strcpy(ptr
, " service ");
178 strcpy(ptr
, service_name
);
180 trace("service_cmd \"%s\"\n", service_cmd
);
182 service
= CreateServiceA(scm_handle
, service_name
, service_name
, GENERIC_ALL
,
183 SERVICE_WIN32_OWN_PROCESS
, SERVICE_DEMAND_START
, SERVICE_ERROR_IGNORE
,
184 service_cmd
, NULL
, NULL
, NULL
, NULL
, NULL
);
185 if(!service
&& GetLastError() == ERROR_ACCESS_DENIED
) {
186 skip("Not enough access right to create service\n");
190 ok(service
!= NULL
, "CreateService failed: %u\n", GetLastError());
194 static void expect_event(const char *event_name
)
199 trace("waiting for %s\n", event_name
);
201 res
= WaitForSingleObject(event_handle
, 30000);
202 ok(res
== WAIT_OBJECT_0
, "WaitForSingleObject failed: %u\n", res
);
203 if(res
!= WAIT_OBJECT_0
)
206 EnterCriticalSection(&event_cs
);
207 strcpy(evt
, current_event
);
209 LeaveCriticalSection(&event_cs
);
211 ok(!strcmp(evt
, event_name
), "Unexpected event: %s, expected %s\n", evt
, event_name
);
214 static DWORD WINAPI
pipe_thread(void *arg
)
220 res
= ConnectNamedPipe(pipe_handle
, NULL
);
221 ok(res
|| GetLastError() == ERROR_PIPE_CONNECTED
, "ConnectNamedPipe failed: %u\n", GetLastError());
224 res
= ReadFile(pipe_handle
, buf
, sizeof(buf
), &read
, NULL
);
226 ok(GetLastError() == ERROR_BROKEN_PIPE
|| GetLastError() == ERROR_INVALID_HANDLE
,
227 "ReadFile failed: %u\n", GetLastError());
231 for(ptr
= buf
; ptr
< buf
+read
; ptr
+= strlen(ptr
)+1) {
232 if(!strncmp(ptr
, "TRACE:", 6)) {
233 trace("service trace: %s\n", ptr
+6);
234 }else if(!strncmp(ptr
, "OK:", 3)) {
235 ok(1, "service: %s\n", ptr
+3);
236 }else if(!strncmp(ptr
, "FAIL:", 3)) {
237 ok(0, "service: %s\n", ptr
+5);
238 }else if(!strncmp(ptr
, "EVENT:", 6)) {
239 trace("service event: %s\n", ptr
+6);
240 EnterCriticalSection(&event_cs
);
241 ok(!current_event
[0], "event %s still queued\n", current_event
);
242 strcpy(current_event
, ptr
+6);
243 LeaveCriticalSection(&event_cs
);
244 SetEvent(event_handle
);
246 ok(0, "malformed service message: %s\n", ptr
);
251 DisconnectNamedPipe(pipe_handle
);
252 trace("pipe disconnected\n");
256 static void test_process(void)
258 SC_HANDLE service_handle
;
259 SERVICE_STATUS status
;
263 sprintf(service_name
, "WineTestService%d", GetTickCount());
264 trace("service_name: %s\n", service_name
);
265 sprintf(named_pipe_name
, "\\\\.\\pipe\\%s_pipe", service_name
);
267 pipe_handle
= CreateNamedPipeA(named_pipe_name
, PIPE_ACCESS_INBOUND
,
268 PIPE_TYPE_BYTE
|PIPE_READMODE_BYTE
|PIPE_WAIT
, 10, 2048, 2048, 10000, NULL
);
269 ok(pipe_handle
!= INVALID_HANDLE_VALUE
, "CreateNamedPipe failed: %u\n", GetLastError());
270 if(pipe_handle
== INVALID_HANDLE_VALUE
)
273 InitializeCriticalSection(&event_cs
);
274 event_handle
= CreateEventA(NULL
, FALSE
, FALSE
, NULL
);
275 ok(event_handle
!= INVALID_HANDLE_VALUE
, "CreateEvent failed: %u\n", GetLastError());
276 if(event_handle
== INVALID_HANDLE_VALUE
)
279 thread
= CreateThread(NULL
, 0, pipe_thread
, NULL
, 0, NULL
);
280 ok(thread
!= NULL
, "CreateThread failed: %u\n", GetLastError());
284 service_handle
= register_service();
288 trace("starting...\n");
289 res
= StartServiceA(service_handle
, 0, NULL
);
290 ok(res
, "StartService failed: %u\n", GetLastError());
293 expect_event("RUNNING");
295 res
= ControlService(service_handle
, SERVICE_CONTROL_STOP
, &status
);
296 ok(res
, "ControlService failed: %u\n", GetLastError());
297 expect_event("STOP");
299 res
= DeleteService(service_handle
);
300 ok(res
, "DeleteService failed: %u\n", GetLastError());
302 CloseServiceHandle(service_handle
);
310 pRegisterServiceCtrlHandlerExA
= (void*)GetProcAddress(GetModuleHandleA("advapi32.dll"), "RegisterServiceCtrlHandlerExA");
311 if(!pRegisterServiceCtrlHandlerExA
) {
312 win_skip("RegisterServiceCtrlHandlerExA not available, skipping tests\n");
316 argc
= winetest_get_mainargs(&argv
);
318 scm_handle
= OpenSCManagerA(NULL
, NULL
, GENERIC_ALL
);
319 ok(scm_handle
!= NULL
, "OpenSCManager failed: %u\n", GetLastError());
324 strcpy(service_name
, argv
[2]);
325 sprintf(named_pipe_name
, "\\\\.\\pipe\\%s_pipe", service_name
);
330 CloseHandle(event_handle
);
331 CloseHandle(pipe_handle
);
332 CloseServiceHandle(scm_handle
);