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() called\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() called\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) called\n", lpServiceName); 144 145 if (lpActiveServices[0].bOwnProcess) 146 return &lpActiveServices[0]; 147 148 for (i = 0; i < dwActiveServiceCount; i++) 149 { 150 TRACE("Checking %S\n", lpActiveServices[i].ServiceName.Buffer); 151 if (_wcsicmp(lpActiveServices[i].ServiceName.Buffer, lpServiceName) == 0) 152 { 153 TRACE("Found!\n"); 154 return &lpActiveServices[i]; 155 } 156 } 157 158 TRACE("No service found!\n"); 159 160 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST); 161 162 return NULL; 163 } 164 165 166 static DWORD WINAPI 167 ScServiceMainStubA(LPVOID Context) 168 { 169 PSERVICE_THREAD_PARAMSA ThreadParams = Context; 170 171 TRACE("ScServiceMainStubA() called\n"); 172 173 /* Call the main service routine and free the arguments vector */ 174 (ThreadParams->lpServiceMain)(ThreadParams->dwArgCount, 175 ThreadParams->lpArgVector); 176 177 if (ThreadParams->lpArgVector != NULL) 178 { 179 HeapFree(GetProcessHeap(), 0, ThreadParams->lpArgVector); 180 } 181 HeapFree(GetProcessHeap(), 0, ThreadParams); 182 183 return ERROR_SUCCESS; 184 } 185 186 187 static DWORD WINAPI 188 ScServiceMainStubW(LPVOID Context) 189 { 190 PSERVICE_THREAD_PARAMSW ThreadParams = Context; 191 192 TRACE("ScServiceMainStubW() called\n"); 193 194 /* Call the main service routine and free the arguments vector */ 195 (ThreadParams->lpServiceMain)(ThreadParams->dwArgCount, 196 ThreadParams->lpArgVector); 197 198 if (ThreadParams->lpArgVector != NULL) 199 { 200 HeapFree(GetProcessHeap(), 0, ThreadParams->lpArgVector); 201 } 202 HeapFree(GetProcessHeap(), 0, ThreadParams); 203 204 return ERROR_SUCCESS; 205 } 206 207 208 static DWORD 209 ScConnectControlPipe(HANDLE *hPipe) 210 { 211 DWORD dwBytesWritten; 212 DWORD dwState; 213 DWORD dwServiceCurrent = 0; 214 NTSTATUS Status; 215 WCHAR NtControlPipeName[MAX_PATH + 1]; 216 RTL_QUERY_REGISTRY_TABLE QueryTable[2]; 217 DWORD dwProcessId; 218 219 /* Get the service number and create the named pipe */ 220 RtlZeroMemory(&QueryTable, 221 sizeof(QueryTable)); 222 223 QueryTable[0].Name = L""; 224 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; 225 QueryTable[0].EntryContext = &dwServiceCurrent; 226 227 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, 228 L"ServiceCurrent", 229 QueryTable, 230 NULL, 231 NULL); 232 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(DWORD), 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 if (lpService == NULL || ControlPacket == NULL) 433 return ERROR_INVALID_PARAMETER; 434 435 TRACE("ScStartService() called\n"); 436 TRACE("Size: %lu\n", ControlPacket->dwSize); 437 TRACE("Service: %S\n", (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset)); 438 439 /* Set the service status handle */ 440 lpService->hServiceStatus = ControlPacket->hServiceStatus; 441 442 /* Build the arguments vector */ 443 if (lpService->bUnicode != FALSE) 444 { 445 ThreadParamsW = HeapAlloc(GetProcessHeap(), 0, sizeof(*ThreadParamsW)); 446 if (ThreadParamsW == NULL) 447 return ERROR_NOT_ENOUGH_MEMORY; 448 dwError = ScBuildUnicodeArgsVector(ControlPacket, 449 &ThreadParamsW->dwArgCount, 450 &ThreadParamsW->lpArgVector); 451 if (dwError != ERROR_SUCCESS) 452 { 453 HeapFree(GetProcessHeap(), 0, ThreadParamsW); 454 return dwError; 455 } 456 ThreadParamsW->lpServiceMain = lpService->ServiceMain.W; 457 ThreadHandle = CreateThread(NULL, 458 0, 459 ScServiceMainStubW, 460 ThreadParamsW, 461 CREATE_SUSPENDED, 462 &ThreadId); 463 if (ThreadHandle == NULL) 464 { 465 if (ThreadParamsW->lpArgVector != NULL) 466 { 467 HeapFree(GetProcessHeap(), 468 0, 469 ThreadParamsW->lpArgVector); 470 } 471 HeapFree(GetProcessHeap(), 0, ThreadParamsW); 472 } 473 } 474 else 475 { 476 ThreadParamsA = HeapAlloc(GetProcessHeap(), 0, sizeof(*ThreadParamsA)); 477 if (ThreadParamsA == NULL) 478 return ERROR_NOT_ENOUGH_MEMORY; 479 dwError = ScBuildAnsiArgsVector(ControlPacket, 480 &ThreadParamsA->dwArgCount, 481 &ThreadParamsA->lpArgVector); 482 if (dwError != ERROR_SUCCESS) 483 { 484 HeapFree(GetProcessHeap(), 0, ThreadParamsA); 485 return dwError; 486 } 487 ThreadParamsA->lpServiceMain = lpService->ServiceMain.A; 488 ThreadHandle = CreateThread(NULL, 489 0, 490 ScServiceMainStubA, 491 ThreadParamsA, 492 CREATE_SUSPENDED, 493 &ThreadId); 494 if (ThreadHandle == NULL) 495 { 496 if (ThreadParamsA->lpArgVector != NULL) 497 { 498 HeapFree(GetProcessHeap(), 499 0, 500 ThreadParamsA->lpArgVector); 501 } 502 HeapFree(GetProcessHeap(), 0, ThreadParamsA); 503 } 504 } 505 506 ResumeThread(ThreadHandle); 507 CloseHandle(ThreadHandle); 508 509 return ERROR_SUCCESS; 510 } 511 512 513 static DWORD 514 ScControlService(PACTIVE_SERVICE lpService, 515 PSCM_CONTROL_PACKET ControlPacket) 516 { 517 if (lpService == NULL || ControlPacket == NULL) 518 return ERROR_INVALID_PARAMETER; 519 520 TRACE("ScControlService() called\n"); 521 TRACE("Size: %lu\n", ControlPacket->dwSize); 522 TRACE("Service: %S\n", (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset)); 523 524 if (lpService->HandlerFunction) 525 { 526 (lpService->HandlerFunction)(ControlPacket->dwControl); 527 } 528 else if (lpService->HandlerFunctionEx) 529 { 530 /* FIXME: send correct params */ 531 (lpService->HandlerFunctionEx)(ControlPacket->dwControl, 0, NULL, NULL); 532 } 533 534 TRACE("ScControlService() done\n"); 535 536 return ERROR_SUCCESS; 537 } 538 539 540 static BOOL 541 ScServiceDispatcher(HANDLE hPipe, 542 PSCM_CONTROL_PACKET ControlPacket, 543 DWORD dwBufferSize) 544 { 545 DWORD Count; 546 BOOL bResult; 547 DWORD dwRunningServices = 0; 548 LPWSTR lpServiceName; 549 PACTIVE_SERVICE lpService; 550 SCM_REPLY_PACKET ReplyPacket; 551 DWORD dwError; 552 553 TRACE("ScDispatcherLoop() called\n"); 554 555 if (ControlPacket == NULL || dwBufferSize < sizeof(SCM_CONTROL_PACKET)) 556 return FALSE; 557 558 while (TRUE) 559 { 560 /* Read command from the control pipe */ 561 bResult = ReadFile(hPipe, 562 ControlPacket, 563 dwBufferSize, 564 &Count, 565 NULL); 566 if (bResult == FALSE) 567 { 568 ERR("Pipe read failed (Error: %lu)\n", GetLastError()); 569 return FALSE; 570 } 571 572 lpServiceName = (LPWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset); 573 TRACE("Service: %S\n", lpServiceName); 574 575 if (ControlPacket->dwControl == SERVICE_CONTROL_START_OWN) 576 lpActiveServices[0].bOwnProcess = TRUE; 577 578 lpService = ScLookupServiceByServiceName(lpServiceName); 579 if (lpService != NULL) 580 { 581 /* Execute command */ 582 switch (ControlPacket->dwControl) 583 { 584 case SERVICE_CONTROL_START_SHARE: 585 case SERVICE_CONTROL_START_OWN: 586 TRACE("Start command - received SERVICE_CONTROL_START\n"); 587 dwError = ScStartService(lpService, ControlPacket); 588 if (dwError == ERROR_SUCCESS) 589 dwRunningServices++; 590 break; 591 592 case SERVICE_CONTROL_STOP: 593 TRACE("Stop command - received SERVICE_CONTROL_STOP\n"); 594 dwError = ScControlService(lpService, ControlPacket); 595 if (dwError == ERROR_SUCCESS) 596 dwRunningServices--; 597 break; 598 599 default: 600 TRACE("Command %lu received", ControlPacket->dwControl); 601 dwError = ScControlService(lpService, ControlPacket); 602 break; 603 } 604 } 605 else 606 { 607 dwError = ERROR_SERVICE_DOES_NOT_EXIST; 608 } 609 610 ReplyPacket.dwError = dwError; 611 612 /* Send the reply packet */ 613 bResult = WriteFile(hPipe, 614 &ReplyPacket, 615 sizeof(ReplyPacket), 616 &Count, 617 NULL); 618 if (bResult == FALSE) 619 { 620 ERR("Pipe write failed (Error: %lu)\n", GetLastError()); 621 return FALSE; 622 } 623 624 if (dwRunningServices == 0) 625 break; 626 } 627 628 return TRUE; 629 } 630 631 632 /********************************************************************** 633 * RegisterServiceCtrlHandlerA 634 * 635 * @implemented 636 */ 637 SERVICE_STATUS_HANDLE WINAPI 638 RegisterServiceCtrlHandlerA(LPCSTR lpServiceName, 639 LPHANDLER_FUNCTION lpHandlerProc) 640 { 641 ANSI_STRING ServiceNameA; 642 UNICODE_STRING ServiceNameU; 643 SERVICE_STATUS_HANDLE SHandle; 644 645 RtlInitAnsiString(&ServiceNameA, (LPSTR)lpServiceName); 646 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE))) 647 { 648 SetLastError(ERROR_OUTOFMEMORY); 649 return (SERVICE_STATUS_HANDLE)0; 650 } 651 652 SHandle = RegisterServiceCtrlHandlerW(ServiceNameU.Buffer, 653 lpHandlerProc); 654 655 RtlFreeUnicodeString(&ServiceNameU); 656 657 return SHandle; 658 } 659 660 661 /********************************************************************** 662 * RegisterServiceCtrlHandlerW 663 * 664 * @implemented 665 */ 666 SERVICE_STATUS_HANDLE WINAPI 667 RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName, 668 LPHANDLER_FUNCTION lpHandlerProc) 669 { 670 PACTIVE_SERVICE Service; 671 672 Service = ScLookupServiceByServiceName((LPWSTR)lpServiceName); 673 if (Service == NULL) 674 { 675 return (SERVICE_STATUS_HANDLE)NULL; 676 } 677 678 Service->HandlerFunction = lpHandlerProc; 679 Service->HandlerFunctionEx = NULL; 680 681 TRACE("RegisterServiceCtrlHandler returning %lu\n", Service->hServiceStatus); 682 683 return Service->hServiceStatus; 684 } 685 686 687 /********************************************************************** 688 * RegisterServiceCtrlHandlerExA 689 * 690 * @implemented 691 */ 692 SERVICE_STATUS_HANDLE WINAPI 693 RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName, 694 LPHANDLER_FUNCTION_EX lpHandlerProc, 695 LPVOID lpContext) 696 { 697 ANSI_STRING ServiceNameA; 698 UNICODE_STRING ServiceNameU; 699 SERVICE_STATUS_HANDLE SHandle; 700 701 RtlInitAnsiString(&ServiceNameA, (LPSTR)lpServiceName); 702 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE))) 703 { 704 SetLastError(ERROR_OUTOFMEMORY); 705 return (SERVICE_STATUS_HANDLE)0; 706 } 707 708 SHandle = RegisterServiceCtrlHandlerExW(ServiceNameU.Buffer, 709 lpHandlerProc, 710 lpContext); 711 712 RtlFreeUnicodeString(&ServiceNameU); 713 714 return SHandle; 715 } 716 717 718 /********************************************************************** 719 * RegisterServiceCtrlHandlerExW 720 * 721 * @implemented 722 */ 723 SERVICE_STATUS_HANDLE WINAPI 724 RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName, 725 LPHANDLER_FUNCTION_EX lpHandlerProc, 726 LPVOID lpContext) 727 { 728 PACTIVE_SERVICE Service; 729 730 Service = ScLookupServiceByServiceName(lpServiceName); 731 if (Service == NULL) 732 { 733 return (SERVICE_STATUS_HANDLE)NULL; 734 } 735 736 Service->HandlerFunction = NULL; 737 Service->HandlerFunctionEx = lpHandlerProc; 738 Service->HandlerContext = lpContext; 739 740 TRACE("RegisterServiceCtrlHandlerEx returning %lu\n", Service->hServiceStatus); 741 742 return Service->hServiceStatus; 743 } 744 745 746 /********************************************************************** 747 * I_ScIsSecurityProcess 748 * 749 * Undocumented 750 * 751 * @unimplemented 752 */ 753 VOID 754 WINAPI 755 I_ScIsSecurityProcess(VOID) 756 { 757 } 758 759 760 /********************************************************************** 761 * I_ScPnPGetServiceName 762 * 763 * Undocumented 764 * 765 * @implemented 766 */ 767 DWORD 768 WINAPI 769 I_ScPnPGetServiceName(IN SERVICE_STATUS_HANDLE hServiceStatus, 770 OUT LPWSTR lpServiceName, 771 IN DWORD cchServiceName) 772 { 773 DWORD i; 774 775 for (i = 0; i < dwActiveServiceCount; i++) 776 { 777 if (lpActiveServices[i].hServiceStatus == hServiceStatus) 778 { 779 wcscpy(lpServiceName, lpActiveServices[i].ServiceName.Buffer); 780 return ERROR_SUCCESS; 781 } 782 } 783 784 return ERROR_SERVICE_NOT_IN_EXE; 785 } 786 787 788 /********************************************************************** 789 * I_ScSetServiceBitsA 790 * 791 * Undocumented 792 * 793 * @implemented 794 */ 795 BOOL WINAPI 796 I_ScSetServiceBitsA(SERVICE_STATUS_HANDLE hServiceStatus, 797 DWORD dwServiceBits, 798 BOOL bSetBitsOn, 799 BOOL bUpdateImmediately, 800 LPSTR lpString) 801 { 802 BOOL bResult; 803 804 RpcTryExcept 805 { 806 /* Call to services.exe using RPC */ 807 bResult = RI_ScSetServiceBitsA((RPC_SERVICE_STATUS_HANDLE)hServiceStatus, 808 dwServiceBits, 809 bSetBitsOn, 810 bUpdateImmediately, 811 lpString); 812 } 813 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 814 { 815 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode())); 816 bResult = FALSE; 817 } 818 RpcEndExcept; 819 820 return bResult; 821 } 822 823 824 /********************************************************************** 825 * I_ScSetServiceBitsW 826 * 827 * Undocumented 828 * 829 * @implemented 830 */ 831 BOOL WINAPI 832 I_ScSetServiceBitsW(SERVICE_STATUS_HANDLE hServiceStatus, 833 DWORD dwServiceBits, 834 BOOL bSetBitsOn, 835 BOOL bUpdateImmediately, 836 LPWSTR lpString) 837 { 838 BOOL bResult; 839 840 RpcTryExcept 841 { 842 /* Call to services.exe using RPC */ 843 bResult = RI_ScSetServiceBitsW((RPC_SERVICE_STATUS_HANDLE)hServiceStatus, 844 dwServiceBits, 845 bSetBitsOn, 846 bUpdateImmediately, 847 lpString); 848 } 849 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 850 { 851 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode())); 852 bResult = FALSE; 853 } 854 RpcEndExcept; 855 856 return bResult; 857 } 858 859 860 /********************************************************************** 861 * SetServiceBits 862 * 863 * @implemented 864 */ 865 BOOL WINAPI 866 SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus, 867 DWORD dwServiceBits, 868 BOOL bSetBitsOn, 869 BOOL bUpdateImmediately) 870 { 871 return I_ScSetServiceBitsW(hServiceStatus, 872 dwServiceBits, 873 bSetBitsOn, 874 bUpdateImmediately, 875 NULL); 876 } 877 878 879 /********************************************************************** 880 * SetServiceStatus 881 * 882 * @implemented 883 */ 884 BOOL WINAPI 885 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus, 886 LPSERVICE_STATUS lpServiceStatus) 887 { 888 DWORD dwError; 889 890 TRACE("SetServiceStatus() called\n"); 891 TRACE("hServiceStatus %lu\n", hServiceStatus); 892 893 RpcTryExcept 894 { 895 /* Call to services.exe using RPC */ 896 dwError = RSetServiceStatus((RPC_SERVICE_STATUS_HANDLE)hServiceStatus, 897 lpServiceStatus); 898 } 899 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 900 { 901 dwError = ScmRpcStatusToWinError(RpcExceptionCode()); 902 } 903 RpcEndExcept; 904 905 if (dwError != ERROR_SUCCESS) 906 { 907 ERR("ScmrSetServiceStatus() failed (Error %lu)\n", dwError); 908 SetLastError(dwError); 909 return FALSE; 910 } 911 912 TRACE("SetServiceStatus() done (ret %lu)\n", dwError); 913 914 return TRUE; 915 } 916 917 918 /********************************************************************** 919 * StartServiceCtrlDispatcherA 920 * 921 * @implemented 922 */ 923 BOOL WINAPI 924 StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA *lpServiceStartTable) 925 { 926 ULONG i; 927 HANDLE hPipe; 928 DWORD dwError; 929 PSCM_CONTROL_PACKET ControlPacket; 930 DWORD dwBufSize; 931 BOOL bRet = TRUE; 932 933 TRACE("StartServiceCtrlDispatcherA() called\n"); 934 935 i = 0; 936 while (lpServiceStartTable[i].lpServiceProc != NULL) 937 { 938 i++; 939 } 940 941 dwActiveServiceCount = i; 942 lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(), 943 HEAP_ZERO_MEMORY, 944 dwActiveServiceCount * sizeof(ACTIVE_SERVICE)); 945 if (lpActiveServices == NULL) 946 { 947 return FALSE; 948 } 949 950 /* Copy service names and start procedure */ 951 for (i = 0; i < dwActiveServiceCount; i++) 952 { 953 RtlCreateUnicodeStringFromAsciiz(&lpActiveServices[i].ServiceName, 954 lpServiceStartTable[i].lpServiceName); 955 lpActiveServices[i].ServiceMain.A = lpServiceStartTable[i].lpServiceProc; 956 lpActiveServices[i].hServiceStatus = 0; 957 lpActiveServices[i].bUnicode = FALSE; 958 lpActiveServices[i].bOwnProcess = FALSE; 959 } 960 961 dwError = ScConnectControlPipe(&hPipe); 962 if (dwError != ERROR_SUCCESS) 963 { 964 bRet = FALSE; 965 goto done; 966 } 967 968 dwBufSize = sizeof(SCM_CONTROL_PACKET) + 969 (MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR); 970 971 ControlPacket = RtlAllocateHeap(RtlGetProcessHeap(), 972 HEAP_ZERO_MEMORY, 973 dwBufSize); 974 if (ControlPacket == NULL) 975 { 976 bRet = FALSE; 977 goto done; 978 } 979 980 ScCreateStatusBinding(); 981 982 ScServiceDispatcher(hPipe, ControlPacket, dwBufSize); 983 984 ScDestroyStatusBinding(); 985 986 CloseHandle(hPipe); 987 988 /* Free the control packet */ 989 RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket); 990 991 done: 992 /* Free the service table */ 993 for (i = 0; i < dwActiveServiceCount; i++) 994 { 995 RtlFreeUnicodeString(&lpActiveServices[i].ServiceName); 996 } 997 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices); 998 lpActiveServices = NULL; 999 dwActiveServiceCount = 0; 1000 1001 return bRet; 1002 } 1003 1004 1005 /********************************************************************** 1006 * StartServiceCtrlDispatcherW 1007 * 1008 * @implemented 1009 */ 1010 BOOL WINAPI 1011 StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW *lpServiceStartTable) 1012 { 1013 ULONG i; 1014 HANDLE hPipe; 1015 DWORD dwError; 1016 PSCM_CONTROL_PACKET ControlPacket; 1017 DWORD dwBufSize; 1018 BOOL bRet = TRUE; 1019 1020 TRACE("StartServiceCtrlDispatcherW() called\n"); 1021 1022 i = 0; 1023 while (lpServiceStartTable[i].lpServiceProc != NULL) 1024 { 1025 i++; 1026 } 1027 1028 dwActiveServiceCount = i; 1029 lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(), 1030 HEAP_ZERO_MEMORY, 1031 dwActiveServiceCount * sizeof(ACTIVE_SERVICE)); 1032 if (lpActiveServices == NULL) 1033 { 1034 return FALSE; 1035 } 1036 1037 /* Copy service names and start procedure */ 1038 for (i = 0; i < dwActiveServiceCount; i++) 1039 { 1040 RtlCreateUnicodeString(&lpActiveServices[i].ServiceName, 1041 lpServiceStartTable[i].lpServiceName); 1042 lpActiveServices[i].ServiceMain.W = lpServiceStartTable[i].lpServiceProc; 1043 lpActiveServices[i].hServiceStatus = 0; 1044 lpActiveServices[i].bUnicode = TRUE; 1045 lpActiveServices[i].bOwnProcess = FALSE; 1046 } 1047 1048 dwError = ScConnectControlPipe(&hPipe); 1049 if (dwError != ERROR_SUCCESS) 1050 { 1051 bRet = FALSE; 1052 goto done; 1053 } 1054 1055 dwBufSize = sizeof(SCM_CONTROL_PACKET) + 1056 (MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR); 1057 1058 ControlPacket = RtlAllocateHeap(RtlGetProcessHeap(), 1059 HEAP_ZERO_MEMORY, 1060 dwBufSize); 1061 if (ControlPacket == NULL) 1062 { 1063 bRet = FALSE; 1064 goto done; 1065 } 1066 1067 ScCreateStatusBinding(); 1068 1069 ScServiceDispatcher(hPipe, ControlPacket, dwBufSize); 1070 1071 ScDestroyStatusBinding(); 1072 1073 CloseHandle(hPipe); 1074 1075 /* Free the control packet */ 1076 RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket); 1077 1078 done: 1079 /* Free the service table */ 1080 for (i = 0; i < dwActiveServiceCount; i++) 1081 { 1082 RtlFreeUnicodeString(&lpActiveServices[i].ServiceName); 1083 } 1084 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices); 1085 lpActiveServices = NULL; 1086 dwActiveServiceCount = 0; 1087 1088 return bRet; 1089 } 1090 1091 /* EOF */ 1092