[SERVICES_WINETEST] Sync with Wine Staging 3.3. CORE-14434
[reactos.git] / modules / rostests / winetests / services / service.c
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 void send_msg(const char *type, const char *msg)
39 {
40 DWORD written = 0;
41 char buf[512];
42
43 sprintf(buf, "%s:%s", type, msg);
44 WriteFile(pipe_handle, buf, strlen(buf)+1, &written, NULL);
45 }
46
47 static inline void service_trace(const char *msg)
48 {
49 send_msg("TRACE", msg);
50 }
51
52 static inline void service_event(const char *event)
53 {
54 send_msg("EVENT", event);
55 }
56
57 static void service_ok(int cnd, const char *msg, ...)
58 {
59 va_list valist;
60 char buf[512];
61
62 va_start(valist, msg);
63 vsprintf(buf, msg, valist);
64 va_end(valist);
65
66 send_msg(cnd ? "OK" : "FAIL", buf);
67 }
68
69 static void test_winstation(void)
70 {
71 HWINSTA winstation;
72 USEROBJECTFLAGS flags;
73 BOOL r;
74
75 winstation = GetProcessWindowStation();
76 service_ok(winstation != NULL, "winstation = NULL\n");
77
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);
81 }
82
83 /*
84 * Test creating window in a service process. Although services run in non-interactive,
85 * they may create windows that will never be visible.
86 */
87 static void test_create_window(void)
88 {
89 DWORD style;
90 ATOM class;
91 HWND hwnd;
92 BOOL r;
93
94 static WNDCLASSEXA wndclass = {
95 sizeof(WNDCLASSEXA),
96 0,
97 DefWindowProcA,
98 0, 0, NULL, NULL, NULL, NULL, NULL,
99 "service_test",
100 NULL
101 };
102
103 hwnd = GetDesktopWindow();
104 service_ok(IsWindow(hwnd), "GetDesktopWindow returned invalid window %p\n", hwnd);
105
106 class = RegisterClassExA(&wndclass);
107 service_ok(class, "RegisterClassFailed\n");
108
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());
113
114 style = GetWindowLongW(hwnd, GWL_STYLE);
115 service_ok(!(style & WS_VISIBLE), "style = %x, expected invisible\n", style);
116
117 r = ShowWindow(hwnd, SW_SHOW);
118 service_ok(!r, "ShowWindow returned %x\n", r);
119
120 style = GetWindowLongW(hwnd, GWL_STYLE);
121 service_ok(style & WS_VISIBLE, "style = %x, expected visible\n", style);
122
123 r = ShowWindow(hwnd, SW_SHOW);
124 service_ok(r, "ShowWindow returned %x\n", r);
125
126 r = DestroyWindow(hwnd);
127 service_ok(r, "DestroyWindow failed: %08x\n", GetLastError());
128 }
129
130 static DWORD WINAPI service_handler(DWORD ctrl, DWORD event_type, void *event_data, void *context)
131 {
132 SERVICE_STATUS status;
133
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;
140
141 switch(ctrl)
142 {
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);
150 return NO_ERROR;
151 case 128:
152 test_winstation();
153 test_create_window();
154 service_event("CUSTOM");
155 return 0xdeadbeef;
156 default:
157 status.dwCurrentState = SERVICE_RUNNING;
158 SetServiceStatus( service_handle, &status );
159 return NO_ERROR;
160 }
161 }
162
163 static void WINAPI service_main(DWORD argc, char **argv)
164 {
165 SERVICE_STATUS status;
166 char buf[64];
167 BOOL res;
168
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]);
173
174 buf[0] = 0;
175 GetEnvironmentVariableA("PATHEXT", buf, sizeof(buf));
176 service_ok(buf[0], "did not find PATHEXT environment variable\n");
177
178 service_handle = pRegisterServiceCtrlHandlerExA(service_name, service_handler, NULL);
179 service_ok(service_handle != NULL, "RegisterServiceCtrlHandlerEx failed: %u\n", GetLastError());
180 if(!service_handle)
181 return;
182
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());
192
193 service_event("RUNNING");
194
195 WaitForSingleObject(service_stop_event, INFINITE);
196
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());
201 }
202
203 static void service_process(void (WINAPI *p_service_main)(DWORD, char **))
204 {
205 BOOL res;
206
207 SERVICE_TABLE_ENTRYA servtbl[] = {
208 {service_name, p_service_main},
209 {NULL, NULL}
210 };
211
212 res = WaitNamedPipeA(named_pipe_name, NMPWAIT_USE_DEFAULT_WAIT);
213 if(!res)
214 return;
215
216 pipe_handle = CreateFileA(named_pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
217 if(pipe_handle == INVALID_HANDLE_VALUE)
218 return;
219
220 service_trace("Starting...\n");
221
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)
225 return;
226
227 res = StartServiceCtrlDispatcherA(servtbl);
228 service_ok(res, "StartServiceCtrlDispatcher failed: %u\n", GetLastError());
229
230 /* Let service thread terminate */
231 Sleep(50);
232
233 CloseHandle(service_stop_event);
234 CloseHandle(pipe_handle);
235 }
236
237 static DWORD WINAPI no_stop_handler(DWORD ctrl, DWORD event_type, void *event_data, void *context)
238 {
239 SERVICE_STATUS status;
240
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;
247
248 switch(ctrl)
249 {
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);
257 return NO_ERROR;
258 default:
259 status.dwCurrentState = SERVICE_RUNNING;
260 SetServiceStatus( service_handle, &status );
261 return NO_ERROR;
262 }
263 }
264
265 static void WINAPI no_stop_main(DWORD argc, char **argv)
266 {
267 SERVICE_STATUS status;
268 BOOL res;
269
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);
272
273 service_handle = pRegisterServiceCtrlHandlerExA(service_name, no_stop_handler, NULL);
274 service_ok(service_handle != NULL, "RegisterServiceCtrlHandlerEx failed: %u\n", GetLastError());
275 if(!service_handle)
276 return;
277
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());
287
288 service_event("RUNNING");
289 }
290
291 /* Test process global variables */
292 static SC_HANDLE scm_handle;
293
294 static char current_event[32];
295 static HANDLE event_handle = INVALID_HANDLE_VALUE;
296 static CRITICAL_SECTION event_cs;
297
298 static SC_HANDLE register_service(const char *test_name)
299 {
300 char service_cmd[MAX_PATH+150], *ptr;
301 SC_HANDLE service;
302
303 ptr = service_cmd + GetModuleFileNameA(NULL, service_cmd, MAX_PATH);
304
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) {
307 strcpy(ptr, ".so");
308 ptr += 3;
309 }
310
311 strcpy(ptr, " service ");
312 ptr += strlen(ptr);
313 sprintf(ptr, "%s ", test_name);
314 ptr += strlen(ptr);
315 strcpy(ptr, service_name);
316
317 trace("service_cmd \"%s\"\n", service_cmd);
318
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");
324 return NULL;
325 }
326
327 ok(service != NULL, "CreateService failed: %u\n", GetLastError());
328 return service;
329 }
330
331 static void expect_event(const char *event_name)
332 {
333 char evt[32];
334 DWORD res;
335
336 trace("waiting for %s\n", event_name);
337
338 res = WaitForSingleObject(event_handle, 30000);
339 ok(res == WAIT_OBJECT_0, "WaitForSingleObject failed: %u\n", res);
340 if(res != WAIT_OBJECT_0)
341 return;
342
343 EnterCriticalSection(&event_cs);
344 strcpy(evt, current_event);
345 *current_event = 0;
346 LeaveCriticalSection(&event_cs);
347
348 ok(!strcmp(evt, event_name), "Unexpected event: %s, expected %s\n", evt, event_name);
349 }
350
351 static DWORD WINAPI pipe_thread(void *arg)
352 {
353 char buf[512], *ptr;
354 DWORD read;
355 BOOL res;
356
357 res = ConnectNamedPipe(pipe_handle, NULL);
358 ok(res || GetLastError() == ERROR_PIPE_CONNECTED, "ConnectNamedPipe failed: %u\n", GetLastError());
359
360 while(1) {
361 res = ReadFile(pipe_handle, buf, sizeof(buf), &read, NULL);
362 if(!res) {
363 ok(GetLastError() == ERROR_BROKEN_PIPE || GetLastError() == ERROR_INVALID_HANDLE,
364 "ReadFile failed: %u\n", GetLastError());
365 break;
366 }
367
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);
382 }else {
383 ok(0, "malformed service message: %s\n", ptr);
384 }
385 }
386 }
387
388 DisconnectNamedPipe(pipe_handle);
389 trace("pipe disconnected\n");
390 return 0;
391 }
392
393 static void test_service(void)
394 {
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;
399 DWORD bytes;
400 BOOL res;
401
402 if(!service_handle)
403 return;
404
405 trace("starting...\n");
406 res = StartServiceA(service_handle, 2, argv);
407 ok(res, "StartService failed: %u\n", GetLastError());
408 if(!res) {
409 DeleteService(service_handle);
410 CloseServiceHandle(service_handle);
411 return;
412 }
413 expect_event("RUNNING");
414
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);
426
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);
431
432 res = ControlService(service_handle, 128, &status);
433 ok(res, "ControlService failed: %u\n", GetLastError());
434 expect_event("CUSTOM");
435
436 res = ControlService(service_handle, SERVICE_CONTROL_STOP, &status);
437 ok(res, "ControlService failed: %u\n", GetLastError());
438 expect_event("STOP");
439
440 res = DeleteService(service_handle);
441 ok(res, "DeleteService failed: %u\n", GetLastError());
442
443 CloseServiceHandle(service_handle);
444 }
445
446 static inline void test_no_stop(void)
447 {
448 SC_HANDLE service_handle = register_service("no_stop");
449 SERVICE_STATUS_PROCESS status2;
450 SERVICE_STATUS status;
451 DWORD bytes;
452 BOOL res;
453
454 if(!service_handle)
455 return;
456
457 trace("starting...\n");
458 res = StartServiceA(service_handle, 0, NULL);
459 ok(res, "StartService failed: %u\n", GetLastError());
460 if(!res) {
461 DeleteService(service_handle);
462 CloseServiceHandle(service_handle);
463 return;
464 }
465 expect_event("RUNNING");
466
467 /* Let service thread terminate */
468 Sleep(1000);
469
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);
481
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);
486
487 res = ControlService(service_handle, SERVICE_CONTROL_STOP, &status);
488 ok(res, "ControlService failed: %u\n", GetLastError());
489 expect_event("STOP");
490
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);
502
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);
507
508 res = DeleteService(service_handle);
509 ok(res, "DeleteService failed: %u\n", GetLastError());
510
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);
522
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);
527
528 CloseServiceHandle(service_handle);
529
530 res = QueryServiceStatus(service_handle, &status);
531 ok(!res, "QueryServiceStatus should have failed\n");
532 ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError = %d\n", GetLastError());
533 }
534
535 static void test_runner(void (*p_run_test)(void))
536 {
537 HANDLE thread;
538
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);
542
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)
547 return;
548
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)
552 return;
553
554 thread = CreateThread(NULL, 0, pipe_thread, NULL, 0, NULL);
555 ok(thread != NULL, "CreateThread failed: %u\n", GetLastError());
556 if(!thread)
557 return;
558
559 p_run_test();
560
561 WaitForSingleObject(thread, INFINITE);
562 CloseHandle(event_handle);
563 CloseHandle(pipe_handle);
564 CloseHandle(thread);
565 }
566
567 START_TEST(service)
568 {
569 char **argv;
570 int argc;
571
572 InitializeCriticalSection(&event_cs);
573
574 pRegisterServiceCtrlHandlerExA = (void*)GetProcAddress(GetModuleHandleA("advapi32.dll"), "RegisterServiceCtrlHandlerExA");
575 if(!pRegisterServiceCtrlHandlerExA) {
576 win_skip("RegisterServiceCtrlHandlerExA not available, skipping tests\n");
577 return;
578 }
579
580 scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL);
581 ok(scm_handle != NULL || GetLastError() == ERROR_ACCESS_DENIED, "OpenSCManager failed: %u\n", GetLastError());
582 if(!scm_handle) {
583 skip("OpenSCManager failed, skipping tests\n");
584 return;
585 }
586
587 argc = winetest_get_mainargs(&argv);
588
589 if(argc < 3) {
590 test_runner(test_service);
591 test_runner(test_no_stop);
592 }else {
593 strcpy(service_name, argv[3]);
594 sprintf(named_pipe_name, "\\\\.\\pipe\\%s_pipe", service_name);
595
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);
600 }
601
602 CloseServiceHandle(scm_handle);
603 }