1 /*
2 * Copyright 2012 Jacek Caban for CodeWeavers
3 *
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.
8 *
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.
13 *
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
17 */
18
19 #include <stdarg.h>
20
21 #include <windef.h>
22 #include <winsvc.h>
23 #include <stdio.h>
24 #include <winbase.h>
25 #include <winuser.h>
26
27 #include "wine/test.h"
28
29 static SERVICE_STATUS_HANDLE (WINAPI *pRegisterServiceCtrlHandlerExA)(LPCSTR,LPHANDLER_FUNCTION_EX,LPVOID);
30
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;
34
35 /* Service process global variables */
36 static HANDLE service_stop_event;
37
38 static int monitor_count;
39
send_msg(const char * type,const char * msg)40 static void send_msg(const char *type, const char *msg)
41 {
42 DWORD written = 0;
43 char buf[512];
44
45 sprintf(buf, "%s:%s", type, msg);
46 WriteFile(pipe_handle, buf, strlen(buf)+1, &written, NULL);
47 }
48
service_trace(const char * msg)49 static inline void service_trace(const char *msg)
50 {
51 send_msg("TRACE", msg);
52 }
53
service_event(const char * event)54 static inline void service_event(const char *event)
55 {
56 send_msg("EVENT", event);
57 }
58
service_ok(int cnd,const char * msg,...)59 static void service_ok(int cnd, const char *msg, ...)
60 {
61 va_list valist;
62 char buf[512];
63
64 va_start(valist, msg);
65 vsprintf(buf, msg, valist);
66 va_end(valist);
67
68 send_msg(cnd ? "OK" : "FAIL", buf);
69 }
70
test_winstation(void)71 static void test_winstation(void)
72 {
73 HWINSTA winstation;
74 USEROBJECTFLAGS flags;
75 BOOL r;
76
77 winstation = GetProcessWindowStation();
78 service_ok(winstation != NULL, "winstation = NULL\n");
79
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);
83 }
84
85 /*
86 * Test creating window in a service process. Although services run in non-interactive,
87 * they may create windows that will never be visible.
88 */
test_create_window(void)89 static void test_create_window(void)
90 {
91 DWORD style;
92 ATOM class;
93 HWND hwnd;
94 BOOL r;
95
96 static WNDCLASSEXA wndclass = {
97 sizeof(WNDCLASSEXA),
98 0,
99 DefWindowProcA,
100 0, 0, NULL, NULL, NULL, NULL, NULL,
101 "service_test",
102 NULL
103 };
104
105 hwnd = GetDesktopWindow();
106 service_ok(IsWindow(hwnd), "GetDesktopWindow returned invalid window %p\n", hwnd);
107
108 class = RegisterClassExA(&wndclass);
109 service_ok(class, "RegisterClassFailed\n");
110
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());
115
116 style = GetWindowLongW(hwnd, GWL_STYLE);
117 service_ok(!(style & WS_VISIBLE), "style = %x, expected invisible\n", style);
118
119 r = ShowWindow(hwnd, SW_SHOW);
120 service_ok(!r, "ShowWindow returned %x\n", r);
121
122 style = GetWindowLongW(hwnd, GWL_STYLE);
123 service_ok(style & WS_VISIBLE, "style = %x, expected visible\n", style);
124
125 r = ShowWindow(hwnd, SW_SHOW);
126 service_ok(r, "ShowWindow returned %x\n", r);
127
128 r = DestroyWindow(hwnd);
129 service_ok(r, "DestroyWindow failed: %08x\n", GetLastError());
130 }
131
monitor_enum_proc(HMONITOR hmon,HDC hdc,LPRECT lprc,LPARAM lparam)132 static BOOL CALLBACK monitor_enum_proc(HMONITOR hmon, HDC hdc, LPRECT lprc, LPARAM lparam)
133 {
134 BOOL r;
135 MONITORINFOEXA mi;
136
137 service_ok(hmon != NULL, "Unexpected hmon=%#x\n", hmon);
138
139 monitor_count++;
140
141 mi.cbSize = sizeof(mi);
142
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");
147
148 r = GetMonitorInfoA(hmon, (MONITORINFO*)&mi);
149 service_ok(r, "GetMonitorInfo failed.\n");
150
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);
154
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);
158
159 service_ok(!strcmp(mi.szDevice, "WinDisc") || !strcmp(mi.szDevice, "\\\\.\\DISPLAY1"),
160 "Unexpected szDevice received: %s\n", mi.szDevice);
161
162 service_ok(mi.dwFlags == MONITORINFOF_PRIMARY, "Unexpected secondary monitor info.\n");
163
164 return TRUE;
165 }
166
167 /* query monitor information, even in non-interactive services */
test_monitors(void)168 static void test_monitors(void)
169 {
170 BOOL r;
171
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);
175 }
176
service_handler(DWORD ctrl,DWORD event_type,void * event_data,void * context)177 static DWORD WINAPI service_handler(DWORD ctrl, DWORD event_type, void *event_data, void *context)
178 {
179 SERVICE_STATUS status;
180
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;
187
188 switch(ctrl)
189 {
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;
208 }
209 }
210
service_main(DWORD argc,char ** argv)211 static void WINAPI service_main(DWORD argc, char **argv)
212 {
213 SERVICE_STATUS status;
214 char buf[64];
215 BOOL res;
216
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]);
221
222 buf[0] = 0;
223 GetEnvironmentVariableA("PATHEXT", buf, sizeof(buf));
224 service_ok(buf[0], "did not find PATHEXT environment variable\n");
225
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;
230
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());
240
241 service_event("RUNNING");
242
243 WaitForSingleObject(service_stop_event, INFINITE);
244
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());
249 }
250
service_process(void (WINAPI * p_service_main)(DWORD,char **))251 static void service_process(void (WINAPI *p_service_main)(DWORD, char **))
252 {
253 BOOL res;
254
255 SERVICE_TABLE_ENTRYA servtbl[] = {
256 {service_name, p_service_main},
257 {NULL, NULL}
258 };
259
260 res = WaitNamedPipeA(named_pipe_name, NMPWAIT_USE_DEFAULT_WAIT);
261 if(!res)
262 return;
263
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;
267
268 service_trace("Starting...\n");
269
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;
274
275 res = StartServiceCtrlDispatcherA(servtbl);
276 service_ok(res, "StartServiceCtrlDispatcher failed: %u\n", GetLastError());
277
278 /* Let service thread terminate */
279 Sleep(50);
280
281 CloseHandle(service_stop_event);
282 CloseHandle(pipe_handle);
283 }
284
no_stop_handler(DWORD ctrl,DWORD event_type,void * event_data,void * context)285 static DWORD WINAPI no_stop_handler(DWORD ctrl, DWORD event_type, void *event_data, void *context)
286 {
287 SERVICE_STATUS status;
288
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;
295
296 switch(ctrl)
297 {
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;
310 }
311 }
312
no_stop_main(DWORD argc,char ** argv)313 static void WINAPI no_stop_main(DWORD argc, char **argv)
314 {
315 SERVICE_STATUS status;
316 BOOL res;
317
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);
320
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;
325
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());
335
336 service_event("RUNNING");
337 }
338
339 /* Test process global variables */
340 static SC_HANDLE scm_handle;
341
342 static char current_event[32];
343 static HANDLE event_handle = INVALID_HANDLE_VALUE;
344 static CRITICAL_SECTION event_cs;
345
register_service(const char * test_name)346 static SC_HANDLE register_service(const char *test_name)
347 {
348 char service_cmd[MAX_PATH+150], *ptr;
349 SC_HANDLE service;
350
351 ptr = service_cmd + GetModuleFileNameA(NULL, service_cmd, MAX_PATH);
352
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;
357 }
358
359 strcpy(ptr, " service ");
360 ptr += strlen(ptr);
361 sprintf(ptr, "%s ", test_name);
362 ptr += strlen(ptr);
363 strcpy(ptr, service_name);
364
365 trace("service_cmd \"%s\"\n", service_cmd);
366
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;
373 }
374
375 ok(service != NULL, "CreateService failed: %u\n", GetLastError());
376 return service;
377 }
378
expect_event(const char * event_name)379 static void expect_event(const char *event_name)
380 {
381 char evt[32];
382 DWORD res;
383
384 trace("waiting for %s\n", event_name);
385
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;
390
391 EnterCriticalSection(&event_cs);
392 strcpy(evt, current_event);
393 *current_event = 0;
394 LeaveCriticalSection(&event_cs);
395
396 ok(!strcmp(evt, event_name), "Unexpected event: %s, expected %s\n", evt, event_name);
397 }
398
pipe_thread(void * arg)399 static DWORD WINAPI pipe_thread(void *arg)
400 {
401 char buf[512], *ptr;
402 DWORD read;
403 BOOL res;
404
405 res = ConnectNamedPipe(pipe_handle, NULL);
406 ok(res || GetLastError() == ERROR_PIPE_CONNECTED, "ConnectNamedPipe failed: %u\n", GetLastError());
407
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;
414 }
415
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);
432 }
433 }
434 }
435
436 DisconnectNamedPipe(pipe_handle);
437 trace("pipe disconnected\n");
438 return 0;
439 }
440
test_service(void)441 static void test_service(void)
442 {
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;
449
450 if(!service_handle)
451 return;
452
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;
460 }
461 expect_event("RUNNING");
462
463 res = QueryServiceStatus(service_handle, &status);
464 ok(res, "QueryServiceStatus failed: %d\n", GetLastError());
465 todo_wine 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);
474
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);
479
480 res = ControlService(service_handle, 128, &status);
481 ok(res, "ControlService failed: %u\n", GetLastError());
482 expect_event("CUSTOM");
483
484 res = ControlService(service_handle, SERVICE_CONTROL_STOP, &status);
485 ok(res, "ControlService failed: %u\n", GetLastError());
486 expect_event("STOP");
487
488 res = DeleteService(service_handle);
489 ok(res, "DeleteService failed: %u\n", GetLastError());
490
491 CloseServiceHandle(service_handle);
492 }
493
test_no_stop(void)494 static inline void test_no_stop(void)
495 {
496 SC_HANDLE service_handle = register_service("no_stop");
497 SERVICE_STATUS_PROCESS status2;
498 SERVICE_STATUS status;
499 DWORD bytes;
500 BOOL res;
501
502 if(!service_handle)
503 return;
504
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;
512 }
513 expect_event("RUNNING");
514
515 /* Let service thread terminate */
516 Sleep(1000);
517
518 res = QueryServiceStatus(service_handle, &status);
519 ok(res, "QueryServiceStatus failed: %d\n", GetLastError());
520 todo_wine 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);
529
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);
534
535 res = ControlService(service_handle, SERVICE_CONTROL_STOP, &status);
536 ok(res, "ControlService failed: %u\n", GetLastError());
537 expect_event("STOP");
538
539 res = QueryServiceStatus(service_handle, &status);
540 ok(res, "QueryServiceStatus failed: %d\n", GetLastError());
541 todo_wine 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);
550
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);
555
556 res = DeleteService(service_handle);
557 ok(res, "DeleteService failed: %u\n", GetLastError());
558
559 res = QueryServiceStatus(service_handle, &status);
560 ok(res, "QueryServiceStatus failed: %d\n", GetLastError());
561 todo_wine 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);
570
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);
575
576 CloseServiceHandle(service_handle);
577
578 res = QueryServiceStatus(service_handle, &status);
579 ok(!res, "QueryServiceStatus should have failed\n");
580 ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError = %d\n", GetLastError());
581 }
582
test_runner(void (* p_run_test)(void))583 static void test_runner(void (*p_run_test)(void))
584 {
585 HANDLE thread;
586
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);
590
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;
596
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;
601
602 thread = CreateThread(NULL, 0, pipe_thread, NULL, 0, NULL);
603 ok(thread != NULL, "CreateThread failed: %u\n", GetLastError());
604 if(!thread)
605 return;
606
607 p_run_test();
608
609 WaitForSingleObject(thread, INFINITE);
610 CloseHandle(event_handle);
611 CloseHandle(pipe_handle);
612 CloseHandle(thread);
613 }
614
START_TEST(service)615 START_TEST(service)
616 {
617 char **argv;
618 int argc;
619
620 InitializeCriticalSection(&event_cs);
621
622 pRegisterServiceCtrlHandlerExA = (void*)GetProcAddress(GetModuleHandleA("advapi32.dll"), "RegisterServiceCtrlHandlerExA");
623 if(!pRegisterServiceCtrlHandlerExA) {
624 win_skip("RegisterServiceCtrlHandlerExA not available, skipping tests\n");
625 return;
626 }
627
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;
633 }
634
635 argc = winetest_get_mainargs(&argv);
636
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);
643
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);
648 }
649
650 CloseServiceHandle(scm_handle);
651 }
652