1 /* 2 * PROJECT: ReactOS advapi32 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: dll/win32/advapi32/service/sctrl.c 5 * PURPOSE: Service control manager functions 6 * COPYRIGHT: Copyright 1999 Emanuele Aliberti 7 * Copyright 2007 Ged Murphy <gedmurphy@reactos.org> 8 * Gregor Brunmar <gregor.brunmar@home.se> 9 */ 10 11 12 /* INCLUDES ******************************************************************/ 13 14 #include <advapi32.h> 15 WINE_DEFAULT_DEBUG_CHANNEL(advapi); 16 17 18 /* TYPES *********************************************************************/ 19 20 typedef struct _SERVICE_THREAD_PARAMSA 21 { 22 LPSERVICE_MAIN_FUNCTIONA lpServiceMain; 23 DWORD dwArgCount; 24 LPSTR *lpArgVector; 25 } SERVICE_THREAD_PARAMSA, *PSERVICE_THREAD_PARAMSA; 26 27 28 typedef struct _SERVICE_THREAD_PARAMSW 29 { 30 LPSERVICE_MAIN_FUNCTIONW lpServiceMain; 31 DWORD dwArgCount; 32 LPWSTR *lpArgVector; 33 } SERVICE_THREAD_PARAMSW, *PSERVICE_THREAD_PARAMSW; 34 35 36 typedef struct _ACTIVE_SERVICE 37 { 38 SERVICE_STATUS_HANDLE hServiceStatus; 39 UNICODE_STRING ServiceName; 40 union 41 { 42 LPSERVICE_MAIN_FUNCTIONA A; 43 LPSERVICE_MAIN_FUNCTIONW W; 44 } ServiceMain; 45 LPHANDLER_FUNCTION HandlerFunction; 46 LPHANDLER_FUNCTION_EX HandlerFunctionEx; 47 LPVOID HandlerContext; 48 BOOL bUnicode; 49 BOOL bOwnProcess; 50 } ACTIVE_SERVICE, *PACTIVE_SERVICE; 51 52 53 /* GLOBALS *******************************************************************/ 54 55 static DWORD dwActiveServiceCount = 0; 56 static PACTIVE_SERVICE lpActiveServices = NULL; 57 static handle_t hStatusBinding = NULL; 58 59 60 /* FUNCTIONS *****************************************************************/ 61 62 handle_t __RPC_USER 63 RPC_SERVICE_STATUS_HANDLE_bind(RPC_SERVICE_STATUS_HANDLE hServiceStatus) 64 { 65 return hStatusBinding; 66 } 67 68 69 void __RPC_USER 70 RPC_SERVICE_STATUS_HANDLE_unbind(RPC_SERVICE_STATUS_HANDLE hServiceStatus, 71 handle_t hBinding) 72 { 73 } 74 75 76 static RPC_STATUS 77 ScCreateStatusBinding(VOID) 78 { 79 LPWSTR pszStringBinding; 80 RPC_STATUS status; 81 82 TRACE("ScCreateStatusBinding()\n"); 83 84 status = RpcStringBindingComposeW(NULL, 85 L"ncacn_np", 86 NULL, 87 L"\\pipe\\ntsvcs", 88 NULL, 89 &pszStringBinding); 90 if (status != RPC_S_OK) 91 { 92 ERR("RpcStringBindingCompose returned 0x%x\n", status); 93 return status; 94 } 95 96 /* Set the binding handle that will be used to bind to the server. */ 97 status = RpcBindingFromStringBindingW(pszStringBinding, 98 &hStatusBinding); 99 if (status != RPC_S_OK) 100 { 101 ERR("RpcBindingFromStringBinding returned 0x%x\n", status); 102 } 103 104 status = RpcStringFreeW(&pszStringBinding); 105 if (status != RPC_S_OK) 106 { 107 ERR("RpcStringFree returned 0x%x\n", status); 108 } 109 110 return status; 111 } 112 113 114 static RPC_STATUS 115 ScDestroyStatusBinding(VOID) 116 { 117 RPC_STATUS status; 118 119 TRACE("ScDestroyStatusBinding()\n"); 120 121 if (hStatusBinding == NULL) 122 return RPC_S_OK; 123 124 status = RpcBindingFree(&hStatusBinding); 125 if (status != RPC_S_OK) 126 { 127 ERR("RpcBindingFree returned 0x%x\n", status); 128 } 129 else 130 { 131 hStatusBinding = NULL; 132 } 133 134 return status; 135 } 136 137 138 static PACTIVE_SERVICE 139 ScLookupServiceByServiceName(LPCWSTR lpServiceName) 140 { 141 DWORD i; 142 143 TRACE("ScLookupServiceByServiceName(%S)\n", 144 lpServiceName); 145 146 if (lpActiveServices[0].bOwnProcess) 147 return &lpActiveServices[0]; 148 149 for (i = 0; i < dwActiveServiceCount; i++) 150 { 151 TRACE("Checking %S\n", lpActiveServices[i].ServiceName.Buffer); 152 if (_wcsicmp(lpActiveServices[i].ServiceName.Buffer, lpServiceName) == 0) 153 { 154 TRACE("Found!\n"); 155 return &lpActiveServices[i]; 156 } 157 } 158 159 TRACE("No service found!\n"); 160 return NULL; 161 } 162 163 164 static DWORD WINAPI 165 ScServiceMainStubA(LPVOID Context) 166 { 167 PSERVICE_THREAD_PARAMSA ThreadParams = Context; 168 169 TRACE("ScServiceMainStubA(%p)\n", Context); 170 171 /* Call the main service routine and free the arguments vector */ 172 (ThreadParams->lpServiceMain)(ThreadParams->dwArgCount, 173 ThreadParams->lpArgVector); 174 175 if (ThreadParams->lpArgVector != NULL) 176 { 177 HeapFree(GetProcessHeap(), 0, ThreadParams->lpArgVector); 178 } 179 HeapFree(GetProcessHeap(), 0, ThreadParams); 180 181 return ERROR_SUCCESS; 182 } 183 184 185 static DWORD WINAPI 186 ScServiceMainStubW(LPVOID Context) 187 { 188 PSERVICE_THREAD_PARAMSW ThreadParams = Context; 189 190 TRACE("ScServiceMainStubW(%p)\n", Context); 191 192 /* Call the main service routine and free the arguments vector */ 193 (ThreadParams->lpServiceMain)(ThreadParams->dwArgCount, 194 ThreadParams->lpArgVector); 195 196 if (ThreadParams->lpArgVector != NULL) 197 { 198 HeapFree(GetProcessHeap(), 0, ThreadParams->lpArgVector); 199 } 200 HeapFree(GetProcessHeap(), 0, ThreadParams); 201 202 return ERROR_SUCCESS; 203 } 204 205 206 static DWORD 207 ScConnectControlPipe(HANDLE *hPipe) 208 { 209 DWORD dwBytesWritten; 210 DWORD dwState; 211 DWORD dwServiceCurrent = 0; 212 NTSTATUS Status; 213 WCHAR NtControlPipeName[MAX_PATH + 1]; 214 RTL_QUERY_REGISTRY_TABLE QueryTable[2]; 215 DWORD dwProcessId; 216 217 TRACE("ScConnectControlPipe(%p)\n", 218 hPipe); 219 220 /* Get the service number and create the named pipe */ 221 RtlZeroMemory(&QueryTable, 222 sizeof(QueryTable)); 223 224 QueryTable[0].Name = L""; 225 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; 226 QueryTable[0].EntryContext = &dwServiceCurrent; 227 228 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, 229 L"ServiceCurrent", 230 QueryTable, 231 NULL, 232 NULL); 233 if (!NT_SUCCESS(Status)) 234 { 235 ERR("RtlQueryRegistryValues() failed (Status %lx)\n", Status); 236 return RtlNtStatusToDosError(Status); 237 } 238 239 swprintf(NtControlPipeName, L"\\\\.\\pipe\\net\\NtControlPipe%u", dwServiceCurrent); 240 241 if (!WaitNamedPipeW(NtControlPipeName, 30000)) 242 { 243 ERR("WaitNamedPipe(%S) failed (Error %lu)\n", NtControlPipeName, GetLastError()); 244 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT; 245 } 246 247 *hPipe = CreateFileW(NtControlPipeName, 248 GENERIC_READ | GENERIC_WRITE, 249 FILE_SHARE_READ | FILE_SHARE_WRITE, 250 NULL, 251 OPEN_EXISTING, 252 FILE_ATTRIBUTE_NORMAL, 253 NULL); 254 if (*hPipe == INVALID_HANDLE_VALUE) 255 { 256 ERR("CreateFileW() failed for pipe %S (Error %lu)\n", NtControlPipeName, GetLastError()); 257 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT; 258 } 259 260 dwState = PIPE_READMODE_MESSAGE; 261 if (!SetNamedPipeHandleState(*hPipe, &dwState, NULL, NULL)) 262 { 263 CloseHandle(*hPipe); 264 *hPipe = INVALID_HANDLE_VALUE; 265 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT; 266 } 267 268 /* Pass the ProcessId to the SCM */ 269 dwProcessId = GetCurrentProcessId(); 270 WriteFile(*hPipe, 271 &dwProcessId, 272 sizeof(dwProcessId), 273 &dwBytesWritten, 274 NULL); 275 276 TRACE("Sent Process ID %lu\n", dwProcessId); 277 278 return ERROR_SUCCESS; 279 } 280 281 282 /* 283 * Ansi/Unicode argument layout of the vector passed to a service at startup, 284 * depending on the different versions of Windows considered: 285 * 286 * - XP/2003: 287 * [argv array of pointers][parameter 1][parameter 2]...[service name] 288 * 289 * - Vista: 290 * [argv array of pointers][align to 8 bytes] 291 * [parameter 1][parameter 2]...[service name] 292 * 293 * - Win7/8: 294 * [argv array of pointers][service name] 295 * [parameter 1][align to 4 bytes][parameter 2][align to 4 bytes]... 296 * 297 * Space for parameters and service name is always enough to store 298 * both the Ansi and the Unicode versions including NULL terminator. 299 */ 300 301 static DWORD 302 ScBuildUnicodeArgsVector(PSCM_CONTROL_PACKET ControlPacket, 303 LPDWORD lpArgCount, 304 LPWSTR **lpArgVector) 305 { 306 PWSTR *lpVector; 307 PWSTR pszServiceName; 308 DWORD cbServiceName; 309 DWORD cbArguments; 310 DWORD cbTotal; 311 DWORD i; 312 313 if (ControlPacket == NULL || lpArgCount == NULL || lpArgVector == NULL) 314 return ERROR_INVALID_PARAMETER; 315 316 *lpArgCount = 0; 317 *lpArgVector = NULL; 318 319 /* Retrieve and count the start command line (NULL-terminated) */ 320 pszServiceName = (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset); 321 cbServiceName = lstrlenW(pszServiceName) * sizeof(WCHAR) + sizeof(UNICODE_NULL); 322 323 /* 324 * The total size of the argument vector is equal to the entry for 325 * the service name, plus the size of the original argument vector. 326 */ 327 cbTotal = sizeof(PWSTR) + cbServiceName; 328 if (ControlPacket->dwArgumentsCount > 0) 329 cbArguments = ControlPacket->dwSize - ControlPacket->dwArgumentsOffset; 330 else 331 cbArguments = 0; 332 cbTotal += cbArguments; 333 334 /* Allocate the new argument vector */ 335 lpVector = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbTotal); 336 if (lpVector == NULL) 337 return ERROR_NOT_ENOUGH_MEMORY; 338 339 /* 340 * The first argument is reserved for the service name, which 341 * will be appended to the end of the argument string list. 342 */ 343 344 /* Copy the remaining arguments */ 345 if (ControlPacket->dwArgumentsCount > 0) 346 { 347 memcpy(&lpVector[1], 348 (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwArgumentsOffset), 349 cbArguments); 350 351 for (i = 0; i < ControlPacket->dwArgumentsCount; i++) 352 { 353 lpVector[i + 1] = (PWSTR)((ULONG_PTR)&lpVector[1] + (ULONG_PTR)lpVector[i + 1]); 354 TRACE("Unicode lpVector[%lu] = '%ls'\n", i + 1, lpVector[i + 1]); 355 } 356 } 357 358 /* Now copy the service name */ 359 lpVector[0] = (PWSTR)((ULONG_PTR)&lpVector[1] + cbArguments); 360 memcpy(lpVector[0], pszServiceName, cbServiceName); 361 TRACE("Unicode lpVector[%lu] = '%ls'\n", 0, lpVector[0]); 362 363 *lpArgCount = ControlPacket->dwArgumentsCount + 1; 364 *lpArgVector = lpVector; 365 366 return ERROR_SUCCESS; 367 } 368 369 370 static DWORD 371 ScBuildAnsiArgsVector(PSCM_CONTROL_PACKET ControlPacket, 372 LPDWORD lpArgCount, 373 LPSTR **lpArgVector) 374 { 375 DWORD dwError; 376 NTSTATUS Status; 377 DWORD ArgCount, i; 378 PWSTR *lpVectorW; 379 PSTR *lpVectorA; 380 UNICODE_STRING UnicodeString; 381 ANSI_STRING AnsiString; 382 383 if (ControlPacket == NULL || lpArgCount == NULL || lpArgVector == NULL) 384 return ERROR_INVALID_PARAMETER; 385 386 *lpArgCount = 0; 387 *lpArgVector = NULL; 388 389 /* Build the UNICODE arguments vector */ 390 dwError = ScBuildUnicodeArgsVector(ControlPacket, &ArgCount, &lpVectorW); 391 if (dwError != ERROR_SUCCESS) 392 return dwError; 393 394 /* Convert the vector to ANSI in place */ 395 lpVectorA = (PSTR*)lpVectorW; 396 for (i = 0; i < ArgCount; i++) 397 { 398 RtlInitUnicodeString(&UnicodeString, lpVectorW[i]); 399 RtlInitEmptyAnsiString(&AnsiString, lpVectorA[i], UnicodeString.MaximumLength); 400 Status = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE); 401 if (!NT_SUCCESS(Status)) 402 { 403 /* Failed to convert to ANSI; free the allocated vector and return */ 404 dwError = RtlNtStatusToDosError(Status); 405 HeapFree(GetProcessHeap(), 0, lpVectorW); 406 return dwError; 407 } 408 409 /* NULL-terminate the string */ 410 AnsiString.Buffer[AnsiString.Length / sizeof(CHAR)] = ANSI_NULL; 411 412 TRACE("Ansi lpVector[%lu] = '%s'\n", i, lpVectorA[i]); 413 } 414 415 *lpArgCount = ArgCount; 416 *lpArgVector = lpVectorA; 417 418 return ERROR_SUCCESS; 419 } 420 421 422 static DWORD 423 ScStartService(PACTIVE_SERVICE lpService, 424 PSCM_CONTROL_PACKET ControlPacket) 425 { 426 HANDLE ThreadHandle; 427 DWORD ThreadId; 428 DWORD dwError; 429 PSERVICE_THREAD_PARAMSA ThreadParamsA; 430 PSERVICE_THREAD_PARAMSW ThreadParamsW; 431 432 TRACE("ScStartService(%p %p)\n", 433 lpService, ControlPacket); 434 435 if (lpService == NULL || ControlPacket == NULL) 436 return ERROR_INVALID_PARAMETER; 437 438 TRACE("Size: %lu\n", ControlPacket->dwSize); 439 TRACE("Service: %S\n", (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset)); 440 441 /* Set the service status handle */ 442 lpService->hServiceStatus = ControlPacket->hServiceStatus; 443 444 /* Build the arguments vector */ 445 if (lpService->bUnicode != FALSE) 446 { 447 ThreadParamsW = HeapAlloc(GetProcessHeap(), 0, sizeof(*ThreadParamsW)); 448 if (ThreadParamsW == NULL) 449 return ERROR_NOT_ENOUGH_MEMORY; 450 dwError = ScBuildUnicodeArgsVector(ControlPacket, 451 &ThreadParamsW->dwArgCount, 452 &ThreadParamsW->lpArgVector); 453 if (dwError != ERROR_SUCCESS) 454 { 455 HeapFree(GetProcessHeap(), 0, ThreadParamsW); 456 return dwError; 457 } 458 ThreadParamsW->lpServiceMain = lpService->ServiceMain.W; 459 ThreadHandle = CreateThread(NULL, 460 0, 461 ScServiceMainStubW, 462 ThreadParamsW, 463 0, 464 &ThreadId); 465 if (ThreadHandle == NULL) 466 { 467 if (ThreadParamsW->lpArgVector != NULL) 468 { 469 HeapFree(GetProcessHeap(), 0, ThreadParamsW->lpArgVector); 470 } 471 HeapFree(GetProcessHeap(), 0, ThreadParamsW); 472 473 return ERROR_SERVICE_NO_THREAD; 474 } 475 476 CloseHandle(ThreadHandle); 477 } 478 else 479 { 480 ThreadParamsA = HeapAlloc(GetProcessHeap(), 0, sizeof(*ThreadParamsA)); 481 if (ThreadParamsA == NULL) 482 return ERROR_NOT_ENOUGH_MEMORY; 483 dwError = ScBuildAnsiArgsVector(ControlPacket, 484 &ThreadParamsA->dwArgCount, 485 &ThreadParamsA->lpArgVector); 486 if (dwError != ERROR_SUCCESS) 487 { 488 HeapFree(GetProcessHeap(), 0, ThreadParamsA); 489 return dwError; 490 } 491 ThreadParamsA->lpServiceMain = lpService->ServiceMain.A; 492 ThreadHandle = CreateThread(NULL, 493 0, 494 ScServiceMainStubA, 495 ThreadParamsA, 496 0, 497 &ThreadId); 498 if (ThreadHandle == NULL) 499 { 500 if (ThreadParamsA->lpArgVector != NULL) 501 { 502 HeapFree(GetProcessHeap(), 0, ThreadParamsA->lpArgVector); 503 } 504 HeapFree(GetProcessHeap(), 0, ThreadParamsA); 505 506 return ERROR_SERVICE_NO_THREAD; 507 } 508 509 CloseHandle(ThreadHandle); 510 } 511 512 return ERROR_SUCCESS; 513 } 514 515 516 static DWORD 517 ScControlService(PACTIVE_SERVICE lpService, 518 PSCM_CONTROL_PACKET ControlPacket) 519 { 520 DWORD dwError = ERROR_SUCCESS; 521 522 TRACE("ScControlService(%p %p)\n", 523 lpService, ControlPacket); 524 525 if (lpService == NULL || ControlPacket == NULL) 526 return ERROR_INVALID_PARAMETER; 527 528 TRACE("Size: %lu\n", ControlPacket->dwSize); 529 TRACE("Service: %S\n", (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset)); 530 531 if (lpService->HandlerFunction) 532 { 533 _SEH2_TRY 534 { 535 (lpService->HandlerFunction)(ControlPacket->dwControl); 536 } 537 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 538 { 539 dwError = ERROR_EXCEPTION_IN_SERVICE; 540 } 541 _SEH2_END; 542 } 543 else if (lpService->HandlerFunctionEx) 544 { 545 _SEH2_TRY 546 { 547 /* FIXME: Send correct 2nd and 3rd parameters */ 548 (lpService->HandlerFunctionEx)(ControlPacket->dwControl, 549 0, NULL, 550 lpService->HandlerContext); 551 } 552 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 553 { 554 dwError = ERROR_EXCEPTION_IN_SERVICE; 555 } 556 _SEH2_END; 557 } 558 else 559 { 560 dwError = ERROR_SERVICE_CANNOT_ACCEPT_CTRL; 561 } 562 563 TRACE("ScControlService() done (Error %lu)\n", dwError); 564 565 return dwError; 566 } 567 568 569 static BOOL 570 ScServiceDispatcher(HANDLE hPipe, 571 PSCM_CONTROL_PACKET ControlPacket, 572 DWORD dwBufferSize) 573 { 574 DWORD Count; 575 BOOL bResult; 576 BOOL bRunning = TRUE; 577 LPWSTR lpServiceName; 578 PACTIVE_SERVICE lpService; 579 SCM_REPLY_PACKET ReplyPacket; 580 DWORD dwError; 581 582 TRACE("ScServiceDispatcher(%p %p %lu)\n", 583 hPipe, ControlPacket, dwBufferSize); 584 585 if (ControlPacket == NULL || dwBufferSize < sizeof(SCM_CONTROL_PACKET)) 586 return FALSE; 587 588 while (bRunning) 589 { 590 /* Read command from the control pipe */ 591 bResult = ReadFile(hPipe, 592 ControlPacket, 593 dwBufferSize, 594 &Count, 595 NULL); 596 if (bResult == FALSE) 597 { 598 ERR("Pipe read failed (Error: %lu)\n", GetLastError()); 599 return FALSE; 600 } 601 602 lpServiceName = (LPWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset); 603 TRACE("Service: %S\n", lpServiceName); 604 605 if ((ControlPacket->dwControl == SERVICE_CONTROL_STOP) && 606 (lpServiceName[0] == UNICODE_NULL)) 607 { 608 TRACE("Stop dispatcher thread\n"); 609 bRunning = FALSE; 610 dwError = ERROR_SUCCESS; 611 } 612 else 613 { 614 if (ControlPacket->dwControl == SERVICE_CONTROL_START_OWN) 615 lpActiveServices[0].bOwnProcess = TRUE; 616 617 lpService = ScLookupServiceByServiceName(lpServiceName); 618 if (lpService != NULL) 619 { 620 /* Execute command */ 621 switch (ControlPacket->dwControl) 622 { 623 case SERVICE_CONTROL_START_SHARE: 624 case SERVICE_CONTROL_START_OWN: 625 TRACE("Start command - received SERVICE_CONTROL_START\n"); 626 dwError = ScStartService(lpService, ControlPacket); 627 break; 628 629 case SERVICE_CONTROL_STOP: 630 TRACE("Stop command - received SERVICE_CONTROL_STOP\n"); 631 dwError = ScControlService(lpService, ControlPacket); 632 break; 633 634 default: 635 TRACE("Command %lu received", ControlPacket->dwControl); 636 dwError = ScControlService(lpService, ControlPacket); 637 break; 638 } 639 } 640 else 641 { 642 dwError = ERROR_SERVICE_NOT_IN_EXE; 643 } 644 } 645 646 ReplyPacket.dwError = dwError; 647 648 /* Send the reply packet */ 649 bResult = WriteFile(hPipe, 650 &ReplyPacket, 651 sizeof(ReplyPacket), 652 &Count, 653 NULL); 654 if (bResult == FALSE) 655 { 656 ERR("Pipe write failed (Error: %lu)\n", GetLastError()); 657 return FALSE; 658 } 659 } 660 661 return TRUE; 662 } 663 664 665 /********************************************************************** 666 * RegisterServiceCtrlHandlerA 667 * 668 * @implemented 669 */ 670 SERVICE_STATUS_HANDLE WINAPI 671 RegisterServiceCtrlHandlerA(LPCSTR lpServiceName, 672 LPHANDLER_FUNCTION lpHandlerProc) 673 { 674 ANSI_STRING ServiceNameA; 675 UNICODE_STRING ServiceNameU; 676 SERVICE_STATUS_HANDLE hServiceStatus; 677 678 TRACE("RegisterServiceCtrlHandlerA(%s %p)\n", 679 debugstr_a(lpServiceName), lpHandlerProc); 680 681 RtlInitAnsiString(&ServiceNameA, lpServiceName); 682 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE))) 683 { 684 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 685 return NULL; 686 } 687 688 hServiceStatus = RegisterServiceCtrlHandlerW(ServiceNameU.Buffer, 689 lpHandlerProc); 690 691 RtlFreeUnicodeString(&ServiceNameU); 692 693 return hServiceStatus; 694 } 695 696 697 /********************************************************************** 698 * RegisterServiceCtrlHandlerW 699 * 700 * @implemented 701 */ 702 SERVICE_STATUS_HANDLE WINAPI 703 RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName, 704 LPHANDLER_FUNCTION lpHandlerProc) 705 { 706 PACTIVE_SERVICE Service; 707 708 TRACE("RegisterServiceCtrlHandlerW(%s %p)\n", 709 debugstr_w(lpServiceName), lpHandlerProc); 710 711 Service = ScLookupServiceByServiceName(lpServiceName); 712 if (Service == NULL) 713 { 714 SetLastError(ERROR_SERVICE_NOT_IN_EXE); 715 return NULL; 716 } 717 718 if (!lpHandlerProc) 719 { 720 SetLastError(ERROR_INVALID_PARAMETER); 721 return NULL; 722 } 723 724 Service->HandlerFunction = lpHandlerProc; 725 Service->HandlerFunctionEx = NULL; 726 727 TRACE("RegisterServiceCtrlHandler returning %p\n", Service->hServiceStatus); 728 729 return Service->hServiceStatus; 730 } 731 732 733 /********************************************************************** 734 * RegisterServiceCtrlHandlerExA 735 * 736 * @implemented 737 */ 738 SERVICE_STATUS_HANDLE WINAPI 739 RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName, 740 LPHANDLER_FUNCTION_EX lpHandlerProc, 741 LPVOID lpContext) 742 { 743 ANSI_STRING ServiceNameA; 744 UNICODE_STRING ServiceNameU; 745 SERVICE_STATUS_HANDLE hServiceStatus; 746 747 TRACE("RegisterServiceCtrlHandlerExA(%s %p %p)\n", 748 debugstr_a(lpServiceName), lpHandlerProc, lpContext); 749 750 RtlInitAnsiString(&ServiceNameA, lpServiceName); 751 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE))) 752 { 753 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 754 return NULL; 755 } 756 757 hServiceStatus = RegisterServiceCtrlHandlerExW(ServiceNameU.Buffer, 758 lpHandlerProc, 759 lpContext); 760 761 RtlFreeUnicodeString(&ServiceNameU); 762 763 return hServiceStatus; 764 } 765 766 767 /********************************************************************** 768 * RegisterServiceCtrlHandlerExW 769 * 770 * @implemented 771 */ 772 SERVICE_STATUS_HANDLE WINAPI 773 RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName, 774 LPHANDLER_FUNCTION_EX lpHandlerProc, 775 LPVOID lpContext) 776 { 777 PACTIVE_SERVICE Service; 778 779 TRACE("RegisterServiceCtrlHandlerExW(%s %p %p)\n", 780 debugstr_w(lpServiceName), lpHandlerProc, lpContext); 781 782 Service = ScLookupServiceByServiceName(lpServiceName); 783 if (Service == NULL) 784 { 785 SetLastError(ERROR_SERVICE_NOT_IN_EXE); 786 return NULL; 787 } 788 789 if (!lpHandlerProc) 790 { 791 SetLastError(ERROR_INVALID_PARAMETER); 792 return NULL; 793 } 794 795 Service->HandlerFunction = NULL; 796 Service->HandlerFunctionEx = lpHandlerProc; 797 Service->HandlerContext = lpContext; 798 799 TRACE("RegisterServiceCtrlHandlerEx returning %p\n", Service->hServiceStatus); 800 801 return Service->hServiceStatus; 802 } 803 804 805 /********************************************************************** 806 * I_ScIsSecurityProcess 807 * 808 * Undocumented 809 * 810 * @unimplemented 811 */ 812 VOID 813 WINAPI 814 I_ScIsSecurityProcess(VOID) 815 { 816 FIXME("I_ScIsSecurityProcess()\n"); 817 } 818 819 820 /********************************************************************** 821 * I_ScPnPGetServiceName 822 * 823 * Undocumented 824 * 825 * @implemented 826 */ 827 DWORD 828 WINAPI 829 I_ScPnPGetServiceName(IN SERVICE_STATUS_HANDLE hServiceStatus, 830 OUT LPWSTR lpServiceName, 831 IN DWORD cchServiceName) 832 { 833 DWORD i; 834 835 TRACE("I_ScPnPGetServiceName(%lu %p %lu)\n", 836 hServiceStatus, lpServiceName, cchServiceName); 837 838 for (i = 0; i < dwActiveServiceCount; i++) 839 { 840 if (lpActiveServices[i].hServiceStatus == hServiceStatus) 841 { 842 wcscpy(lpServiceName, lpActiveServices[i].ServiceName.Buffer); 843 return ERROR_SUCCESS; 844 } 845 } 846 847 return ERROR_SERVICE_NOT_IN_EXE; 848 } 849 850 851 /********************************************************************** 852 * I_ScSetServiceBitsA 853 * 854 * Undocumented 855 * 856 * @implemented 857 */ 858 BOOL WINAPI 859 I_ScSetServiceBitsA(SERVICE_STATUS_HANDLE hServiceStatus, 860 DWORD dwServiceBits, 861 BOOL bSetBitsOn, 862 BOOL bUpdateImmediately, 863 LPSTR lpString) 864 { 865 BOOL bResult; 866 867 TRACE("I_ScSetServiceBitsA(%lu %lx %u %u %s)\n", 868 hServiceStatus, dwServiceBits, bSetBitsOn, bUpdateImmediately, 869 debugstr_a(lpString)); 870 871 RpcTryExcept 872 { 873 bResult = RI_ScSetServiceBitsA((RPC_SERVICE_STATUS_HANDLE)hServiceStatus, 874 dwServiceBits, 875 bSetBitsOn, 876 bUpdateImmediately, 877 lpString); 878 } 879 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 880 { 881 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode())); 882 bResult = FALSE; 883 } 884 RpcEndExcept; 885 886 return bResult; 887 } 888 889 890 /********************************************************************** 891 * I_ScSetServiceBitsW 892 * 893 * Undocumented 894 * 895 * @implemented 896 */ 897 BOOL WINAPI 898 I_ScSetServiceBitsW(SERVICE_STATUS_HANDLE hServiceStatus, 899 DWORD dwServiceBits, 900 BOOL bSetBitsOn, 901 BOOL bUpdateImmediately, 902 LPWSTR lpString) 903 { 904 BOOL bResult; 905 906 TRACE("I_ScSetServiceBitsW(%lu %lx %u %u %s)\n", 907 hServiceStatus, dwServiceBits, bSetBitsOn, bUpdateImmediately, 908 debugstr_w(lpString)); 909 910 RpcTryExcept 911 { 912 bResult = RI_ScSetServiceBitsW((RPC_SERVICE_STATUS_HANDLE)hServiceStatus, 913 dwServiceBits, 914 bSetBitsOn, 915 bUpdateImmediately, 916 lpString); 917 } 918 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 919 { 920 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode())); 921 bResult = FALSE; 922 } 923 RpcEndExcept; 924 925 return bResult; 926 } 927 928 929 /********************************************************************** 930 * SetServiceBits 931 * 932 * @implemented 933 */ 934 BOOL WINAPI 935 SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus, 936 DWORD dwServiceBits, 937 BOOL bSetBitsOn, 938 BOOL bUpdateImmediately) 939 { 940 TRACE("SetServiceBits(%lu %lx %u %u)\n", 941 hServiceStatus, dwServiceBits, bSetBitsOn, bUpdateImmediately); 942 943 return I_ScSetServiceBitsW(hServiceStatus, 944 dwServiceBits, 945 bSetBitsOn, 946 bUpdateImmediately, 947 NULL); 948 } 949 950 951 /********************************************************************** 952 * SetServiceStatus 953 * 954 * @implemented 955 */ 956 BOOL WINAPI 957 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus, 958 LPSERVICE_STATUS lpServiceStatus) 959 { 960 DWORD dwError; 961 962 TRACE("SetServiceStatus(%lu %p)\n", 963 hServiceStatus, lpServiceStatus); 964 965 RpcTryExcept 966 { 967 dwError = RSetServiceStatus((RPC_SERVICE_STATUS_HANDLE)hServiceStatus, 968 lpServiceStatus); 969 } 970 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 971 { 972 dwError = ScmRpcStatusToWinError(RpcExceptionCode()); 973 } 974 RpcEndExcept; 975 976 if (dwError != ERROR_SUCCESS) 977 { 978 ERR("RSetServiceStatus() failed (Error %lu)\n", dwError); 979 SetLastError(dwError); 980 return FALSE; 981 } 982 983 TRACE("SetServiceStatus() done\n"); 984 985 return TRUE; 986 } 987 988 989 /********************************************************************** 990 * StartServiceCtrlDispatcherA 991 * 992 * @implemented 993 */ 994 BOOL WINAPI 995 StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA *lpServiceStartTable) 996 { 997 ULONG i; 998 HANDLE hPipe; 999 DWORD dwError; 1000 PSCM_CONTROL_PACKET ControlPacket; 1001 DWORD dwBufSize; 1002 BOOL bRet = TRUE; 1003 1004 TRACE("StartServiceCtrlDispatcherA(%p)\n", 1005 lpServiceStartTable); 1006 1007 i = 0; 1008 while (lpServiceStartTable[i].lpServiceProc != NULL) 1009 { 1010 i++; 1011 } 1012 1013 dwActiveServiceCount = i; 1014 1015 /* Allocate the service table */ 1016 lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(), 1017 HEAP_ZERO_MEMORY, 1018 dwActiveServiceCount * sizeof(ACTIVE_SERVICE)); 1019 if (lpActiveServices == NULL) 1020 { 1021 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1022 return FALSE; 1023 } 1024 1025 /* Copy service names and start procedure */ 1026 for (i = 0; i < dwActiveServiceCount; i++) 1027 { 1028 RtlCreateUnicodeStringFromAsciiz(&lpActiveServices[i].ServiceName, 1029 lpServiceStartTable[i].lpServiceName); 1030 lpActiveServices[i].ServiceMain.A = lpServiceStartTable[i].lpServiceProc; 1031 lpActiveServices[i].hServiceStatus = NULL; 1032 lpActiveServices[i].bUnicode = FALSE; 1033 lpActiveServices[i].bOwnProcess = FALSE; 1034 } 1035 1036 /* Connect to the SCM */ 1037 dwError = ScConnectControlPipe(&hPipe); 1038 if (dwError != ERROR_SUCCESS) 1039 { 1040 bRet = FALSE; 1041 goto done; 1042 } 1043 1044 dwBufSize = sizeof(SCM_CONTROL_PACKET) + 1045 (MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR); 1046 1047 ControlPacket = RtlAllocateHeap(RtlGetProcessHeap(), 1048 HEAP_ZERO_MEMORY, 1049 dwBufSize); 1050 if (ControlPacket == NULL) 1051 { 1052 dwError = ERROR_NOT_ENOUGH_MEMORY; 1053 bRet = FALSE; 1054 goto done; 1055 } 1056 1057 ScCreateStatusBinding(); 1058 1059 /* Call the dispatcher loop */ 1060 ScServiceDispatcher(hPipe, ControlPacket, dwBufSize); 1061 1062 1063 ScDestroyStatusBinding(); 1064 1065 /* Close the connection */ 1066 CloseHandle(hPipe); 1067 1068 /* Free the control packet */ 1069 RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket); 1070 1071 done: 1072 /* Free the service table */ 1073 for (i = 0; i < dwActiveServiceCount; i++) 1074 { 1075 RtlFreeUnicodeString(&lpActiveServices[i].ServiceName); 1076 } 1077 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices); 1078 lpActiveServices = NULL; 1079 dwActiveServiceCount = 0; 1080 1081 if (!bRet) 1082 SetLastError(dwError); 1083 1084 return bRet; 1085 } 1086 1087 1088 /********************************************************************** 1089 * StartServiceCtrlDispatcherW 1090 * 1091 * @implemented 1092 */ 1093 BOOL WINAPI 1094 StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW *lpServiceStartTable) 1095 { 1096 ULONG i; 1097 HANDLE hPipe; 1098 DWORD dwError; 1099 PSCM_CONTROL_PACKET ControlPacket; 1100 DWORD dwBufSize; 1101 BOOL bRet = TRUE; 1102 1103 TRACE("StartServiceCtrlDispatcherW(%p)\n", 1104 lpServiceStartTable); 1105 1106 i = 0; 1107 while (lpServiceStartTable[i].lpServiceProc != NULL) 1108 { 1109 i++; 1110 } 1111 1112 dwActiveServiceCount = i; 1113 1114 /* Allocate the service table */ 1115 lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(), 1116 HEAP_ZERO_MEMORY, 1117 dwActiveServiceCount * sizeof(ACTIVE_SERVICE)); 1118 if (lpActiveServices == NULL) 1119 { 1120 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1121 return FALSE; 1122 } 1123 1124 /* Copy service names and start procedure */ 1125 for (i = 0; i < dwActiveServiceCount; i++) 1126 { 1127 RtlCreateUnicodeString(&lpActiveServices[i].ServiceName, 1128 lpServiceStartTable[i].lpServiceName); 1129 lpActiveServices[i].ServiceMain.W = lpServiceStartTable[i].lpServiceProc; 1130 lpActiveServices[i].hServiceStatus = NULL; 1131 lpActiveServices[i].bUnicode = TRUE; 1132 lpActiveServices[i].bOwnProcess = FALSE; 1133 } 1134 1135 /* Connect to the SCM */ 1136 dwError = ScConnectControlPipe(&hPipe); 1137 if (dwError != ERROR_SUCCESS) 1138 { 1139 bRet = FALSE; 1140 goto done; 1141 } 1142 1143 dwBufSize = sizeof(SCM_CONTROL_PACKET) + 1144 (MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR); 1145 1146 ControlPacket = RtlAllocateHeap(RtlGetProcessHeap(), 1147 HEAP_ZERO_MEMORY, 1148 dwBufSize); 1149 if (ControlPacket == NULL) 1150 { 1151 dwError = ERROR_NOT_ENOUGH_MEMORY; 1152 bRet = FALSE; 1153 goto done; 1154 } 1155 1156 ScCreateStatusBinding(); 1157 1158 /* Call the dispatcher loop */ 1159 ScServiceDispatcher(hPipe, ControlPacket, dwBufSize); 1160 1161 ScDestroyStatusBinding(); 1162 1163 /* Close the connection */ 1164 CloseHandle(hPipe); 1165 1166 /* Free the control packet */ 1167 RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket); 1168 1169 done: 1170 /* Free the service table */ 1171 for (i = 0; i < dwActiveServiceCount; i++) 1172 { 1173 RtlFreeUnicodeString(&lpActiveServices[i].ServiceName); 1174 } 1175 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices); 1176 lpActiveServices = NULL; 1177 dwActiveServiceCount = 0; 1178 1179 if (!bRet) 1180 SetLastError(dwError); 1181 1182 return bRet; 1183 } 1184 1185 /* EOF */ 1186