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 } 604