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 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 49 static inline void service_trace(const char *msg) 50 { 51 send_msg("TRACE", msg); 52 } 53 54 static inline void service_event(const char *event) 55 { 56 send_msg("EVENT", event); 57 } 58 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 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 */ 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 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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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