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_service); 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 DWORD 139 ScLookupServiceByServiceName(IN LPCWSTR lpServiceName, 140 OUT PACTIVE_SERVICE* pService) 141 { 142 DWORD i; 143 144 TRACE("ScLookupServiceByServiceName(%S) called\n", lpServiceName); 145 146 if (lpActiveServices[0].bOwnProcess) 147 { 148 *pService = &lpActiveServices[0]; 149 return ERROR_SUCCESS; 150 } 151 152 for (i = 0; i < dwActiveServiceCount; i++) 153 { 154 TRACE("Checking %S\n", lpActiveServices[i].ServiceName.Buffer); 155 if (_wcsicmp(lpActiveServices[i].ServiceName.Buffer, lpServiceName) == 0) 156 { 157 TRACE("Found!\n"); 158 *pService = &lpActiveServices[i]; 159 return ERROR_SUCCESS; 160 } 161 } 162 163 TRACE("No service found!\n"); 164 *pService = NULL; 165 return ERROR_SERVICE_NOT_IN_EXE; 166 } 167 168 169 static DWORD WINAPI 170 ScServiceMainStubA(LPVOID Context) 171 { 172 PSERVICE_THREAD_PARAMSA ThreadParams = Context; 173 174 TRACE("ScServiceMainStubA() called\n"); 175 176 /* Call the main service routine and free the arguments vector */ 177 (ThreadParams->lpServiceMain)(ThreadParams->dwArgCount, 178 ThreadParams->lpArgVector); 179 180 if (ThreadParams->lpArgVector != NULL) 181 { 182 HeapFree(GetProcessHeap(), 0, ThreadParams->lpArgVector); 183 } 184 HeapFree(GetProcessHeap(), 0, ThreadParams); 185 186 return ERROR_SUCCESS; 187 } 188 189 190 static DWORD WINAPI 191 ScServiceMainStubW(LPVOID Context) 192 { 193 PSERVICE_THREAD_PARAMSW ThreadParams = Context; 194 195 TRACE("ScServiceMainStubW() called\n"); 196 197 /* Call the main service routine and free the arguments vector */ 198 (ThreadParams->lpServiceMain)(ThreadParams->dwArgCount, 199 ThreadParams->lpArgVector); 200 201 if (ThreadParams->lpArgVector != NULL) 202 { 203 HeapFree(GetProcessHeap(), 0, ThreadParams->lpArgVector); 204 } 205 HeapFree(GetProcessHeap(), 0, ThreadParams); 206 207 return ERROR_SUCCESS; 208 } 209 210 211 static DWORD 212 ScConnectControlPipe(HANDLE *hPipe) 213 { 214 DWORD dwBytesWritten; 215 DWORD dwState; 216 DWORD dwServiceCurrent = 0; 217 NTSTATUS Status; 218 WCHAR NtControlPipeName[MAX_PATH + 1]; 219 RTL_QUERY_REGISTRY_TABLE QueryTable[2]; 220 DWORD dwProcessId; 221 222 /* Get the service number and create the named pipe */ 223 RtlZeroMemory(&QueryTable, 224 sizeof(QueryTable)); 225 226 QueryTable[0].Name = L""; 227 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; 228 QueryTable[0].EntryContext = &dwServiceCurrent; 229 230 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, 231 L"ServiceCurrent", 232 QueryTable, 233 NULL, 234 NULL); 235 if (!NT_SUCCESS(Status)) 236 { 237 ERR("RtlQueryRegistryValues() failed (Status %lx)\n", Status); 238 return RtlNtStatusToDosError(Status); 239 } 240 241 swprintf(NtControlPipeName, L"\\\\.\\pipe\\net\\NtControlPipe%u", dwServiceCurrent); 242 243 if (!WaitNamedPipeW(NtControlPipeName, 30000)) 244 { 245 ERR("WaitNamedPipe(%S) failed (Error %lu)\n", NtControlPipeName, GetLastError()); 246 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT; 247 } 248 249 *hPipe = CreateFileW(NtControlPipeName, 250 GENERIC_READ | GENERIC_WRITE, 251 FILE_SHARE_READ | FILE_SHARE_WRITE, 252 NULL, 253 OPEN_EXISTING, 254 FILE_ATTRIBUTE_NORMAL, 255 NULL); 256 if (*hPipe == INVALID_HANDLE_VALUE) 257 { 258 ERR("CreateFileW() failed for pipe %S (Error %lu)\n", NtControlPipeName, GetLastError()); 259 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT; 260 } 261 262 dwState = PIPE_READMODE_MESSAGE; 263 if (!SetNamedPipeHandleState(*hPipe, &dwState, NULL, NULL)) 264 { 265 CloseHandle(*hPipe); 266 *hPipe = INVALID_HANDLE_VALUE; 267 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT; 268 } 269 270 /* Pass the ProcessId to the SCM */ 271 dwProcessId = GetCurrentProcessId(); 272 WriteFile(*hPipe, 273 &dwProcessId, 274 sizeof(dwProcessId), 275 &dwBytesWritten, 276 NULL); 277 278 TRACE("Sent Process ID %lu\n", dwProcessId); 279 280 return ERROR_SUCCESS; 281 } 282 283 284 /* 285 * Ansi/Unicode argument layout of the vector passed to a service at startup, 286 * depending on the different versions of Windows considered: 287 * 288 * - XP/2003: 289 * [argv array of pointers][parameter 1][parameter 2]...[service name] 290 * 291 * - Vista: 292 * [argv array of pointers][align to 8 bytes] 293 * [parameter 1][parameter 2]...[service name] 294 * 295 * - Win7/8: 296 * [argv array of pointers][service name] 297 * [parameter 1][align to 4 bytes][parameter 2][align to 4 bytes]... 298 * 299 * Space for parameters and service name is always enough to store 300 * both the Ansi and the Unicode versions including NULL terminator. 301 */ 302 303 static DWORD 304 ScBuildUnicodeArgsVector(PSCM_CONTROL_PACKET ControlPacket, 305 LPDWORD lpArgCount, 306 LPWSTR **lpArgVector) 307 { 308 PWSTR *lpVector; 309 PWSTR pszServiceName; 310 DWORD cbServiceName; 311 DWORD cbArguments; 312 DWORD cbTotal; 313 DWORD i; 314 315 if (ControlPacket == NULL || lpArgCount == NULL || lpArgVector == NULL) 316 return ERROR_INVALID_PARAMETER; 317 318 *lpArgCount = 0; 319 *lpArgVector = NULL; 320 321 /* Retrieve and count the start command line (NULL-terminated) */ 322 pszServiceName = (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset); 323 cbServiceName = lstrlenW(pszServiceName) * sizeof(WCHAR) + sizeof(UNICODE_NULL); 324 325 /* 326 * The total size of the argument vector is equal to the entry for 327 * the service name, plus the size of the original argument vector. 328 */ 329 cbTotal = sizeof(PWSTR) + cbServiceName; 330 if (ControlPacket->dwArgumentsCount > 0) 331 cbArguments = ControlPacket->dwSize - ControlPacket->dwArgumentsOffset; 332 else 333 cbArguments = 0; 334 cbTotal += cbArguments; 335 336 /* Allocate the new argument vector */ 337 lpVector = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbTotal); 338 if (lpVector == NULL) 339 return ERROR_NOT_ENOUGH_MEMORY; 340 341 /* 342 * The first argument is reserved for the service name, which 343 * will be appended to the end of the argument string list. 344 */ 345 346 /* Copy the remaining arguments */ 347 if (ControlPacket->dwArgumentsCount > 0) 348 { 349 memcpy(&lpVector[1], 350 (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwArgumentsOffset), 351 cbArguments); 352 353 for (i = 0; i < ControlPacket->dwArgumentsCount; i++) 354 { 355 lpVector[i + 1] = (PWSTR)((ULONG_PTR)&lpVector[1] + (ULONG_PTR)lpVector[i + 1]); 356 TRACE("Unicode lpVector[%lu] = '%ls'\n", i + 1, lpVector[i + 1]); 357 } 358 } 359 360 /* Now copy the service name */ 361 lpVector[0] = (PWSTR)((ULONG_PTR)&lpVector[1] + cbArguments); 362 memcpy(lpVector[0], pszServiceName, cbServiceName); 363 TRACE("Unicode lpVector[%lu] = '%ls'\n", 0, lpVector[0]); 364 365 *lpArgCount = ControlPacket->dwArgumentsCount + 1; 366 *lpArgVector = lpVector; 367 368 return ERROR_SUCCESS; 369 } 370 371 372 static DWORD 373 ScBuildAnsiArgsVector(PSCM_CONTROL_PACKET ControlPacket, 374 LPDWORD lpArgCount, 375 LPSTR **lpArgVector) 376 { 377 DWORD dwError; 378 NTSTATUS Status; 379 DWORD ArgCount, i; 380 PWSTR *lpVectorW; 381 PSTR *lpVectorA; 382 UNICODE_STRING UnicodeString; 383 ANSI_STRING AnsiString; 384 385 if (ControlPacket == NULL || lpArgCount == NULL || lpArgVector == NULL) 386 return ERROR_INVALID_PARAMETER; 387 388 *lpArgCount = 0; 389 *lpArgVector = NULL; 390 391 /* Build the UNICODE arguments vector */ 392 dwError = ScBuildUnicodeArgsVector(ControlPacket, &ArgCount, &lpVectorW); 393 if (dwError != ERROR_SUCCESS) 394 return dwError; 395 396 /* Convert the vector to ANSI in place */ 397 lpVectorA = (PSTR*)lpVectorW; 398 for (i = 0; i < ArgCount; i++) 399 { 400 RtlInitUnicodeString(&UnicodeString, lpVectorW[i]); 401 RtlInitEmptyAnsiString(&AnsiString, lpVectorA[i], UnicodeString.MaximumLength); 402 Status = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE); 403 if (!NT_SUCCESS(Status)) 404 { 405 /* Failed to convert to ANSI; free the allocated vector and return */ 406 dwError = RtlNtStatusToDosError(Status); 407 HeapFree(GetProcessHeap(), 0, lpVectorW); 408 return dwError; 409 } 410 411 /* NULL-terminate the string */ 412 AnsiString.Buffer[AnsiString.Length / sizeof(CHAR)] = ANSI_NULL; 413 414 TRACE("Ansi lpVector[%lu] = '%s'\n", i, lpVectorA[i]); 415 } 416 417 *lpArgCount = ArgCount; 418 *lpArgVector = lpVectorA; 419 420 return ERROR_SUCCESS; 421 } 422 423 424 static DWORD 425 ScStartService(PACTIVE_SERVICE lpService, 426 PSCM_CONTROL_PACKET ControlPacket) 427 { 428 HANDLE ThreadHandle; 429 DWORD ThreadId; 430 DWORD dwError; 431 PSERVICE_THREAD_PARAMSA ThreadParamsA; 432 PSERVICE_THREAD_PARAMSW ThreadParamsW; 433 434 if (lpService == NULL || ControlPacket == NULL) 435 return ERROR_INVALID_PARAMETER; 436 437 TRACE("ScStartService(Size: %lu, Service: '%S') called\n", 438 ControlPacket->dwSize, 439 (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; 521 522 if (lpService == NULL || ControlPacket == NULL) 523 return ERROR_INVALID_PARAMETER; 524 525 TRACE("ScControlService(Size: %lu, Service: '%S') called\n", 526 ControlPacket->dwSize, 527 (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset)); 528 529 if (lpService->HandlerFunction) 530 { 531 (lpService->HandlerFunction)(ControlPacket->dwControl); 532 dwError = ERROR_SUCCESS; 533 } 534 else if (lpService->HandlerFunctionEx) 535 { 536 /* FIXME: Send correct 2nd and 3rd parameters */ 537 dwError = (lpService->HandlerFunctionEx)(ControlPacket->dwControl, 538 0, NULL, 539 lpService->HandlerContext); 540 } 541 542 TRACE("ScControlService() done (error %lu)\n", dwError); 543 544 return dwError; 545 } 546 547 548 static BOOL 549 ScServiceDispatcher(HANDLE hPipe, 550 PSCM_CONTROL_PACKET ControlPacket, 551 DWORD dwBufferSize) 552 { 553 DWORD Count; 554 BOOL bResult; 555 BOOL bRunning = TRUE; 556 LPWSTR lpServiceName; 557 PACTIVE_SERVICE lpService; 558 SCM_REPLY_PACKET ReplyPacket; 559 DWORD dwError; 560 561 TRACE("ScDispatcherLoop() called\n"); 562 563 if (ControlPacket == NULL || dwBufferSize < sizeof(SCM_CONTROL_PACKET)) 564 return FALSE; 565 566 while (bRunning) 567 { 568 /* Read command from the control pipe */ 569 bResult = ReadFile(hPipe, 570 ControlPacket, 571 dwBufferSize, 572 &Count, 573 NULL); 574 if (bResult == FALSE) 575 { 576 ERR("Pipe read failed (Error: %lu)\n", GetLastError()); 577 return FALSE; 578 } 579 580 lpServiceName = (LPWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset); 581 TRACE("Service: %S\n", lpServiceName); 582 583 if (lpServiceName[0] == UNICODE_NULL) 584 { 585 ERR("Stop dispatcher thread\n"); 586 bRunning = FALSE; 587 dwError = ERROR_SUCCESS; 588 } 589 else 590 { 591 if (ControlPacket->dwControl == SERVICE_CONTROL_START_OWN) 592 lpActiveServices[0].bOwnProcess = TRUE; 593 594 dwError = ScLookupServiceByServiceName(lpServiceName, &lpService); 595 if ((dwError == ERROR_SUCCESS) && (lpService != NULL)) 596 { 597 /* Execute command */ 598 switch (ControlPacket->dwControl) 599 { 600 case SERVICE_CONTROL_START_SHARE: 601 case SERVICE_CONTROL_START_OWN: 602 TRACE("Start command - received SERVICE_CONTROL_START\n"); 603 dwError = ScStartService(lpService, ControlPacket); 604 break; 605 606 case SERVICE_CONTROL_STOP: 607 TRACE("Stop command - received SERVICE_CONTROL_STOP\n"); 608 dwError = ScControlService(lpService, ControlPacket); 609 break; 610 611 default: 612 TRACE("Command %lu received", ControlPacket->dwControl); 613 dwError = ScControlService(lpService, ControlPacket); 614 break; 615 } 616 } 617 } 618 619 ReplyPacket.dwError = dwError; 620 621 /* Send the reply packet */ 622 bResult = WriteFile(hPipe, 623 &ReplyPacket, 624 sizeof(ReplyPacket), 625 &Count, 626 NULL); 627 if (bResult == FALSE) 628 { 629 ERR("Pipe write failed (Error: %lu)\n", GetLastError()); 630 return FALSE; 631 } 632 } 633 634 return TRUE; 635 } 636 637 638 /********************************************************************** 639 * RegisterServiceCtrlHandlerA 640 * 641 * @implemented 642 */ 643 SERVICE_STATUS_HANDLE WINAPI 644 RegisterServiceCtrlHandlerA(LPCSTR lpServiceName, 645 LPHANDLER_FUNCTION lpHandlerProc) 646 { 647 ANSI_STRING ServiceNameA; 648 UNICODE_STRING ServiceNameU; 649 SERVICE_STATUS_HANDLE hServiceStatus; 650 651 RtlInitAnsiString(&ServiceNameA, lpServiceName); 652 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE))) 653 { 654 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 655 return NULL; 656 } 657 658 hServiceStatus = RegisterServiceCtrlHandlerW(ServiceNameU.Buffer, 659 lpHandlerProc); 660 661 RtlFreeUnicodeString(&ServiceNameU); 662 663 return hServiceStatus; 664 } 665 666 667 /********************************************************************** 668 * RegisterServiceCtrlHandlerW 669 * 670 * @implemented 671 */ 672 SERVICE_STATUS_HANDLE WINAPI 673 RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName, 674 LPHANDLER_FUNCTION lpHandlerProc) 675 { 676 DWORD dwError; 677 PACTIVE_SERVICE Service; 678 679 dwError = ScLookupServiceByServiceName(lpServiceName, &Service); 680 if ((dwError != ERROR_SUCCESS) || (Service == NULL)) 681 { 682 SetLastError(dwError); 683 return NULL; 684 } 685 686 if (!lpHandlerProc) 687 { 688 SetLastError(ERROR_INVALID_PARAMETER); 689 return NULL; 690 } 691 692 Service->HandlerFunction = lpHandlerProc; 693 Service->HandlerFunctionEx = NULL; 694 695 TRACE("RegisterServiceCtrlHandler returning 0x%p\n", Service->hServiceStatus); 696 697 return Service->hServiceStatus; 698 } 699 700 701 /********************************************************************** 702 * RegisterServiceCtrlHandlerExA 703 * 704 * @implemented 705 */ 706 SERVICE_STATUS_HANDLE WINAPI 707 RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName, 708 LPHANDLER_FUNCTION_EX lpHandlerProc, 709 LPVOID lpContext) 710 { 711 ANSI_STRING ServiceNameA; 712 UNICODE_STRING ServiceNameU; 713 SERVICE_STATUS_HANDLE hServiceStatus; 714 715 RtlInitAnsiString(&ServiceNameA, lpServiceName); 716 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE))) 717 { 718 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 719 return NULL; 720 } 721 722 hServiceStatus = RegisterServiceCtrlHandlerExW(ServiceNameU.Buffer, 723 lpHandlerProc, 724 lpContext); 725 726 RtlFreeUnicodeString(&ServiceNameU); 727 728 return hServiceStatus; 729 } 730 731 732 /********************************************************************** 733 * RegisterServiceCtrlHandlerExW 734 * 735 * @implemented 736 */ 737 SERVICE_STATUS_HANDLE WINAPI 738 RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName, 739 LPHANDLER_FUNCTION_EX lpHandlerProc, 740 LPVOID lpContext) 741 { 742 DWORD dwError; 743 PACTIVE_SERVICE Service; 744 745 dwError = ScLookupServiceByServiceName(lpServiceName, &Service); 746 if ((dwError != ERROR_SUCCESS) || (Service == NULL)) 747 { 748 SetLastError(dwError); 749 return NULL; 750 } 751 752 if (!lpHandlerProc) 753 { 754 SetLastError(ERROR_INVALID_PARAMETER); 755 return NULL; 756 } 757 758 Service->HandlerFunction = NULL; 759 Service->HandlerFunctionEx = lpHandlerProc; 760 Service->HandlerContext = lpContext; 761 762 TRACE("RegisterServiceCtrlHandlerEx returning 0x%p\n", Service->hServiceStatus); 763 764 return Service->hServiceStatus; 765 } 766 767 768 /********************************************************************** 769 * I_ScIsSecurityProcess 770 * 771 * Undocumented 772 * 773 * @unimplemented 774 */ 775 VOID 776 WINAPI 777 I_ScIsSecurityProcess(VOID) 778 { 779 } 780 781 782 /********************************************************************** 783 * I_ScPnPGetServiceName 784 * 785 * Undocumented 786 * 787 * @implemented 788 */ 789 DWORD 790 WINAPI 791 I_ScPnPGetServiceName(IN SERVICE_STATUS_HANDLE hServiceStatus, 792 OUT LPWSTR lpServiceName, 793 IN DWORD cchServiceName) 794 { 795 DWORD i; 796 797 for (i = 0; i < dwActiveServiceCount; i++) 798 { 799 if (lpActiveServices[i].hServiceStatus == hServiceStatus) 800 { 801 wcscpy(lpServiceName, lpActiveServices[i].ServiceName.Buffer); 802 return ERROR_SUCCESS; 803 } 804 } 805 806 return ERROR_SERVICE_NOT_IN_EXE; 807 } 808 809 810 /********************************************************************** 811 * I_ScSetServiceBitsA 812 * 813 * Undocumented 814 * 815 * @implemented 816 */ 817 BOOL WINAPI 818 I_ScSetServiceBitsA(SERVICE_STATUS_HANDLE hServiceStatus, 819 DWORD dwServiceBits, 820 BOOL bSetBitsOn, 821 BOOL bUpdateImmediately, 822 LPSTR lpString) 823 { 824 BOOL bResult; 825 826 RpcTryExcept 827 { 828 bResult = RI_ScSetServiceBitsA((RPC_SERVICE_STATUS_HANDLE)hServiceStatus, 829 dwServiceBits, 830 bSetBitsOn, 831 bUpdateImmediately, 832 lpString); 833 } 834 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 835 { 836 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode())); 837 bResult = FALSE; 838 } 839 RpcEndExcept; 840 841 return bResult; 842 } 843 844 845 /********************************************************************** 846 * I_ScSetServiceBitsW 847 * 848 * Undocumented 849 * 850 * @implemented 851 */ 852 BOOL WINAPI 853 I_ScSetServiceBitsW(SERVICE_STATUS_HANDLE hServiceStatus, 854 DWORD dwServiceBits, 855 BOOL bSetBitsOn, 856 BOOL bUpdateImmediately, 857 LPWSTR lpString) 858 { 859 BOOL bResult; 860 861 RpcTryExcept 862 { 863 bResult = RI_ScSetServiceBitsW((RPC_SERVICE_STATUS_HANDLE)hServiceStatus, 864 dwServiceBits, 865 bSetBitsOn, 866 bUpdateImmediately, 867 lpString); 868 } 869 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 870 { 871 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode())); 872 bResult = FALSE; 873 } 874 RpcEndExcept; 875 876 return bResult; 877 } 878 879 880 /********************************************************************** 881 * SetServiceBits 882 * 883 * @implemented 884 */ 885 BOOL WINAPI 886 SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus, 887 DWORD dwServiceBits, 888 BOOL bSetBitsOn, 889 BOOL bUpdateImmediately) 890 { 891 return I_ScSetServiceBitsW(hServiceStatus, 892 dwServiceBits, 893 bSetBitsOn, 894 bUpdateImmediately, 895 NULL); 896 } 897 898 899 /********************************************************************** 900 * SetServiceStatus 901 * 902 * @implemented 903 */ 904 BOOL WINAPI 905 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus, 906 LPSERVICE_STATUS lpServiceStatus) 907 { 908 DWORD dwError; 909 910 TRACE("SetServiceStatus(hServiceStatus %lu) called\n", hServiceStatus); 911 912 RpcTryExcept 913 { 914 dwError = RSetServiceStatus((RPC_SERVICE_STATUS_HANDLE)hServiceStatus, 915 lpServiceStatus); 916 } 917 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 918 { 919 dwError = ScmRpcStatusToWinError(RpcExceptionCode()); 920 } 921 RpcEndExcept; 922 923 if (dwError != ERROR_SUCCESS) 924 { 925 ERR("RSetServiceStatus() failed (Error %lu)\n", dwError); 926 SetLastError(dwError); 927 return FALSE; 928 } 929 930 TRACE("SetServiceStatus() done (ret %lu)\n", dwError); 931 932 return TRUE; 933 } 934 935 936 /********************************************************************** 937 * StartServiceCtrlDispatcherA 938 * 939 * @implemented 940 */ 941 BOOL WINAPI 942 StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA *lpServiceStartTable) 943 { 944 ULONG i; 945 HANDLE hPipe; 946 DWORD dwError; 947 PSCM_CONTROL_PACKET ControlPacket; 948 DWORD dwBufSize; 949 BOOL bRet = TRUE; 950 951 TRACE("StartServiceCtrlDispatcherA() called\n"); 952 953 i = 0; 954 while (lpServiceStartTable[i].lpServiceProc != NULL) 955 { 956 i++; 957 } 958 959 dwActiveServiceCount = i; 960 961 /* Initialize the service table */ 962 lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(), 963 HEAP_ZERO_MEMORY, 964 dwActiveServiceCount * sizeof(ACTIVE_SERVICE)); 965 if (lpActiveServices == NULL) 966 { 967 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 968 return FALSE; 969 } 970 971 /* Copy service names and start procedure */ 972 for (i = 0; i < dwActiveServiceCount; i++) 973 { 974 RtlCreateUnicodeStringFromAsciiz(&lpActiveServices[i].ServiceName, 975 lpServiceStartTable[i].lpServiceName); 976 lpActiveServices[i].ServiceMain.A = lpServiceStartTable[i].lpServiceProc; 977 lpActiveServices[i].hServiceStatus = NULL; 978 lpActiveServices[i].bUnicode = FALSE; 979 lpActiveServices[i].bOwnProcess = FALSE; 980 } 981 982 /* Initialize the connection to the SCM */ 983 984 dwError = ScConnectControlPipe(&hPipe); 985 if (dwError != ERROR_SUCCESS) 986 { 987 bRet = FALSE; 988 goto Done; 989 } 990 991 dwBufSize = sizeof(SCM_CONTROL_PACKET) + 992 (MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR); 993 994 ControlPacket = RtlAllocateHeap(RtlGetProcessHeap(), 995 HEAP_ZERO_MEMORY, 996 dwBufSize); 997 if (ControlPacket == NULL) 998 { 999 dwError = ERROR_NOT_ENOUGH_MEMORY; 1000 bRet = FALSE; 1001 goto Done; 1002 } 1003 1004 ScCreateStatusBinding(); 1005 1006 /* Start the dispatcher loop */ 1007 ScServiceDispatcher(hPipe, ControlPacket, dwBufSize); 1008 1009 /* Close the connection */ 1010 ScDestroyStatusBinding(); 1011 CloseHandle(hPipe); 1012 1013 /* Free the control packet */ 1014 RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket); 1015 1016 Done: 1017 /* Free the service table */ 1018 for (i = 0; i < dwActiveServiceCount; i++) 1019 { 1020 RtlFreeUnicodeString(&lpActiveServices[i].ServiceName); 1021 } 1022 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices); 1023 lpActiveServices = NULL; 1024 dwActiveServiceCount = 0; 1025 1026 if (!bRet) SetLastError(dwError); 1027 1028 return bRet; 1029 } 1030 1031 1032 /********************************************************************** 1033 * StartServiceCtrlDispatcherW 1034 * 1035 * @implemented 1036 */ 1037 BOOL WINAPI 1038 StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW *lpServiceStartTable) 1039 { 1040 ULONG i; 1041 HANDLE hPipe; 1042 DWORD dwError; 1043 PSCM_CONTROL_PACKET ControlPacket; 1044 DWORD dwBufSize; 1045 BOOL bRet = TRUE; 1046 1047 TRACE("StartServiceCtrlDispatcherW() called\n"); 1048 1049 i = 0; 1050 while (lpServiceStartTable[i].lpServiceProc != NULL) 1051 { 1052 i++; 1053 } 1054 1055 dwActiveServiceCount = i; 1056 1057 /* Initialize the service table */ 1058 lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(), 1059 HEAP_ZERO_MEMORY, 1060 dwActiveServiceCount * sizeof(ACTIVE_SERVICE)); 1061 if (lpActiveServices == NULL) 1062 { 1063 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1064 return FALSE; 1065 } 1066 1067 /* Copy service names and start procedure */ 1068 for (i = 0; i < dwActiveServiceCount; i++) 1069 { 1070 RtlCreateUnicodeString(&lpActiveServices[i].ServiceName, 1071 lpServiceStartTable[i].lpServiceName); 1072 lpActiveServices[i].ServiceMain.W = lpServiceStartTable[i].lpServiceProc; 1073 lpActiveServices[i].hServiceStatus = NULL; 1074 lpActiveServices[i].bUnicode = TRUE; 1075 lpActiveServices[i].bOwnProcess = FALSE; 1076 } 1077 1078 /* Initialize the connection to the SCM */ 1079 1080 dwError = ScConnectControlPipe(&hPipe); 1081 if (dwError != ERROR_SUCCESS) 1082 { 1083 bRet = FALSE; 1084 goto Done; 1085 } 1086 1087 dwBufSize = sizeof(SCM_CONTROL_PACKET) + 1088 (MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR); 1089 1090 ControlPacket = RtlAllocateHeap(RtlGetProcessHeap(), 1091 HEAP_ZERO_MEMORY, 1092 dwBufSize); 1093 if (ControlPacket == NULL) 1094 { 1095 dwError = ERROR_NOT_ENOUGH_MEMORY; 1096 bRet = FALSE; 1097 goto Done; 1098 } 1099 1100 ScCreateStatusBinding(); 1101 1102 /* Start the dispatcher loop */ 1103 ScServiceDispatcher(hPipe, ControlPacket, dwBufSize); 1104 1105 /* Close the connection */ 1106 ScDestroyStatusBinding(); 1107 CloseHandle(hPipe); 1108 1109 /* Free the control packet */ 1110 RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket); 1111 1112 Done: 1113 /* Free the service table */ 1114 for (i = 0; i < dwActiveServiceCount; i++) 1115 { 1116 RtlFreeUnicodeString(&lpActiveServices[i].ServiceName); 1117 } 1118 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices); 1119 lpActiveServices = NULL; 1120 dwActiveServiceCount = 0; 1121 1122 if (!bRet) SetLastError(dwError); 1123 1124 return bRet; 1125 } 1126 1127 /* EOF */ 1128