[ADVAPI32/SERVICES]: Windows services (as per MSDN and testing) must always get at...
[reactos.git] / reactos / dll / win32 / advapi32 / service / sctrl.c
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
13 /* INCLUDES ******************************************************************/
14
15 #include <advapi32.h>
16 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
17
18
19 /* TYPES *********************************************************************/
20
21 typedef struct _SERVICE_THREAD_PARAMSA
22 {
23 LPSERVICE_MAIN_FUNCTIONA lpServiceMain;
24 DWORD dwArgCount;
25 LPSTR *lpArgVector;
26 } SERVICE_THREAD_PARAMSA, *PSERVICE_THREAD_PARAMSA;
27
28
29 typedef struct _SERVICE_THREAD_PARAMSW
30 {
31 LPSERVICE_MAIN_FUNCTIONW lpServiceMain;
32 DWORD dwArgCount;
33 LPWSTR *lpArgVector;
34 } SERVICE_THREAD_PARAMSW, *PSERVICE_THREAD_PARAMSW;
35
36
37 typedef struct _ACTIVE_SERVICE
38 {
39 SERVICE_STATUS_HANDLE hServiceStatus;
40 UNICODE_STRING ServiceName;
41 union
42 {
43 SERVICE_THREAD_PARAMSA A;
44 SERVICE_THREAD_PARAMSW W;
45 } ThreadParams;
46 LPHANDLER_FUNCTION HandlerFunction;
47 LPHANDLER_FUNCTION_EX HandlerFunctionEx;
48 LPVOID HandlerContext;
49 BOOL bUnicode;
50 BOOL bOwnProcess;
51 } ACTIVE_SERVICE, *PACTIVE_SERVICE;
52
53
54 /* GLOBALS *******************************************************************/
55
56 static DWORD dwActiveServiceCount = 0;
57 static PACTIVE_SERVICE lpActiveServices = NULL;
58 static handle_t hStatusBinding = NULL;
59
60
61 /* FUNCTIONS *****************************************************************/
62
63 handle_t __RPC_USER
64 RPC_SERVICE_STATUS_HANDLE_bind(RPC_SERVICE_STATUS_HANDLE hServiceStatus)
65 {
66 return hStatusBinding;
67 }
68
69
70 void __RPC_USER
71 RPC_SERVICE_STATUS_HANDLE_unbind(RPC_SERVICE_STATUS_HANDLE hServiceStatus,
72 handle_t hBinding)
73 {
74 }
75
76
77 static RPC_STATUS
78 ScCreateStatusBinding(VOID)
79 {
80 LPWSTR pszStringBinding;
81 RPC_STATUS status;
82
83 TRACE("ScCreateStatusBinding() called\n");
84
85 status = RpcStringBindingComposeW(NULL,
86 L"ncacn_np",
87 NULL,
88 L"\\pipe\\ntsvcs",
89 NULL,
90 &pszStringBinding);
91 if (status != RPC_S_OK)
92 {
93 ERR("RpcStringBindingCompose returned 0x%x\n", status);
94 return status;
95 }
96
97 /* Set the binding handle that will be used to bind to the server. */
98 status = RpcBindingFromStringBindingW(pszStringBinding,
99 &hStatusBinding);
100 if (status != RPC_S_OK)
101 {
102 ERR("RpcBindingFromStringBinding returned 0x%x\n", status);
103 }
104
105 status = RpcStringFreeW(&pszStringBinding);
106 if (status != RPC_S_OK)
107 {
108 ERR("RpcStringFree returned 0x%x\n", status);
109 }
110
111 return status;
112 }
113
114
115 static RPC_STATUS
116 ScDestroyStatusBinding(VOID)
117 {
118 RPC_STATUS status;
119
120 TRACE("ScDestroyStatusBinding() called\n");
121
122 if (hStatusBinding == NULL)
123 return RPC_S_OK;
124
125 status = RpcBindingFree(&hStatusBinding);
126 if (status != RPC_S_OK)
127 {
128 ERR("RpcBindingFree returned 0x%x\n", status);
129 }
130 else
131 {
132 hStatusBinding = NULL;
133 }
134
135 return status;
136 }
137
138
139 static PACTIVE_SERVICE
140 ScLookupServiceByServiceName(LPCWSTR lpServiceName)
141 {
142 DWORD i;
143
144 TRACE("ScLookupServiceByServiceName(%S) called\n", 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
161 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
162
163 return NULL;
164 }
165
166
167 static DWORD WINAPI
168 ScServiceMainStub(LPVOID Context)
169 {
170 PACTIVE_SERVICE lpService = (PACTIVE_SERVICE)Context;
171
172 TRACE("ScServiceMainStub() called\n");
173
174 /* Call the main service routine and free the arguments vector */
175 if (lpService->bUnicode)
176 {
177 (lpService->ThreadParams.W.lpServiceMain)(lpService->ThreadParams.W.dwArgCount,
178 lpService->ThreadParams.W.lpArgVector);
179
180 if (lpService->ThreadParams.W.lpArgVector != NULL)
181 {
182 HeapFree(GetProcessHeap(),
183 0,
184 lpService->ThreadParams.W.lpArgVector);
185
186 lpService->ThreadParams.W.lpArgVector = NULL;
187 lpService->ThreadParams.W.dwArgCount = 0;
188 }
189 }
190 else
191 {
192 (lpService->ThreadParams.A.lpServiceMain)(lpService->ThreadParams.A.dwArgCount,
193 lpService->ThreadParams.A.lpArgVector);
194
195 if (lpService->ThreadParams.A.lpArgVector != NULL)
196 {
197 HeapFree(GetProcessHeap(),
198 0,
199 lpService->ThreadParams.A.lpArgVector);
200
201 lpService->ThreadParams.A.lpArgVector = NULL;
202 lpService->ThreadParams.A.dwArgCount = 0;
203 }
204 }
205
206 return ERROR_SUCCESS;
207 }
208
209
210 static DWORD
211 ScConnectControlPipe(HANDLE *hPipe)
212 {
213 DWORD dwBytesWritten;
214 DWORD dwState;
215 DWORD dwServiceCurrent = 0;
216 NTSTATUS Status;
217 WCHAR NtControlPipeName[MAX_PATH + 1];
218 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
219 DWORD dwProcessId;
220
221 /* Get the service number and create the named pipe */
222 RtlZeroMemory(&QueryTable,
223 sizeof(QueryTable));
224
225 QueryTable[0].Name = L"";
226 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
227 QueryTable[0].EntryContext = &dwServiceCurrent;
228
229 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
230 L"ServiceCurrent",
231 QueryTable,
232 NULL,
233 NULL);
234
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, 15000))
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 0,
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(DWORD),
275 &dwBytesWritten,
276 NULL);
277
278 TRACE("Sent Process ID %lu\n", dwProcessId);
279
280 return ERROR_SUCCESS;
281 }
282
283
284 static DWORD
285 ScBuildUnicodeArgsVector(PSCM_CONTROL_PACKET ControlPacket,
286 LPDWORD lpArgCount,
287 LPWSTR **lpArgVector)
288 {
289 LPWSTR *lpVector;
290 LPWSTR *lpArg;
291 DWORD i, cbServiceName, cbTotal;
292 LPWSTR pszServiceName;
293
294 if (ControlPacket == NULL || lpArgCount == NULL || lpArgVector == NULL)
295 return ERROR_INVALID_PARAMETER;
296
297 *lpArgCount = 0;
298 *lpArgVector = NULL;
299
300 pszServiceName = (PWSTR) ((PBYTE) ControlPacket + ControlPacket->dwServiceNameOffset);
301 cbServiceName = lstrlenW(pszServiceName) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
302
303 if (ControlPacket->dwArgumentsCount > 0)
304 {
305 cbTotal = ControlPacket->dwSize - ControlPacket->dwArgumentsOffset +
306 cbServiceName + sizeof(LPWSTR);
307 }
308 else
309 {
310 cbTotal = cbServiceName + sizeof(LPWSTR);
311 }
312
313 lpVector = HeapAlloc(GetProcessHeap(),
314 HEAP_ZERO_MEMORY,
315 cbTotal);
316 if (lpVector == NULL)
317 return ERROR_OUTOFMEMORY;
318
319 lpArg = lpVector;
320 *lpArg = (LPWSTR)(lpArg + 1);
321 lpArg++;
322
323 memcpy(lpArg, pszServiceName, cbServiceName);
324 lpArg = (LPWSTR*) ((ULONG_PTR) lpArg + cbServiceName);
325
326 if (ControlPacket->dwArgumentsCount > 0)
327 {
328 memcpy(lpArg,
329 ((PBYTE)ControlPacket + ControlPacket->dwArgumentsOffset),
330 ControlPacket->dwSize - ControlPacket->dwArgumentsOffset);
331
332 for (i = 0; i < ControlPacket->dwArgumentsCount; i++)
333 {
334 *lpArg = (LPWSTR)((ULONG_PTR)lpArg + (ULONG_PTR)*lpArg);
335 lpArg++;
336 }
337 }
338
339 *lpArgCount = ControlPacket->dwArgumentsCount + 1;
340 *lpArgVector = lpVector;
341
342 return ERROR_SUCCESS;
343 }
344
345
346 static DWORD
347 ScBuildAnsiArgsVector(PSCM_CONTROL_PACKET ControlPacket,
348 LPDWORD lpArgCount,
349 LPSTR **lpArgVector)
350 {
351 LPSTR *lpVector;
352 LPSTR *lpPtr;
353 LPWSTR lpUnicodeString;
354 LPSTR lpAnsiString;
355 DWORD dwVectorSize;
356 DWORD dwUnicodeSize;
357 DWORD dwAnsiSize;
358 DWORD i;
359
360 if (ControlPacket == NULL || lpArgCount == NULL || lpArgVector == NULL)
361 return ERROR_INVALID_PARAMETER;
362
363 *lpArgCount = 0;
364 *lpArgVector = NULL;
365
366 /* FIXME: There should always be one argument (the name) sent to services... */
367 /* FIXME: See the Unicode version above on how to achieve this */
368
369 if (ControlPacket->dwArgumentsCount > 0)
370 {
371 dwVectorSize = ControlPacket->dwArgumentsCount * sizeof(LPWSTR);
372
373 lpUnicodeString = (LPWSTR)((PBYTE)ControlPacket +
374 ControlPacket->dwArgumentsOffset +
375 dwVectorSize);
376 dwUnicodeSize = (ControlPacket->dwSize -
377 ControlPacket->dwArgumentsOffset -
378 dwVectorSize) / sizeof(WCHAR);
379
380 dwAnsiSize = WideCharToMultiByte(CP_ACP,
381 0,
382 lpUnicodeString,
383 dwUnicodeSize,
384 NULL,
385 0,
386 NULL,
387 NULL);
388
389 lpVector = HeapAlloc(GetProcessHeap(),
390 HEAP_ZERO_MEMORY,
391 dwVectorSize + dwAnsiSize);
392 if (lpVector == NULL)
393 return ERROR_OUTOFMEMORY;
394
395 lpPtr = (LPSTR*)lpVector;
396 lpAnsiString = (LPSTR)((ULONG_PTR)lpVector + dwVectorSize);
397
398 WideCharToMultiByte(CP_ACP,
399 0,
400 lpUnicodeString,
401 dwUnicodeSize,
402 lpAnsiString,
403 dwAnsiSize,
404 NULL,
405 NULL);
406
407 for (i = 0; i < ControlPacket->dwArgumentsCount; i++)
408 {
409 *lpPtr = lpAnsiString;
410
411 lpPtr++;
412 lpAnsiString += (strlen(lpAnsiString) + 1);
413 }
414
415 *lpArgCount = ControlPacket->dwArgumentsCount;
416 *lpArgVector = lpVector;
417 }
418
419 return ERROR_SUCCESS;
420 }
421
422
423 static DWORD
424 ScStartService(PACTIVE_SERVICE lpService,
425 PSCM_CONTROL_PACKET ControlPacket)
426 {
427 HANDLE ThreadHandle;
428 DWORD ThreadId;
429 DWORD dwError;
430
431 if (lpService == NULL || ControlPacket == NULL)
432 return ERROR_INVALID_PARAMETER;
433
434 TRACE("ScStartService() called\n");
435 TRACE("Size: %lu\n", ControlPacket->dwSize);
436 TRACE("Service: %S\n", (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset));
437
438 /* Set the service status handle */
439 lpService->hServiceStatus = ControlPacket->hServiceStatus;
440
441 /* Build the arguments vector */
442 if (lpService->bUnicode == TRUE)
443 {
444 dwError = ScBuildUnicodeArgsVector(ControlPacket,
445 &lpService->ThreadParams.W.dwArgCount,
446 &lpService->ThreadParams.W.lpArgVector);
447 }
448 else
449 {
450 dwError = ScBuildAnsiArgsVector(ControlPacket,
451 &lpService->ThreadParams.A.dwArgCount,
452 &lpService->ThreadParams.A.lpArgVector);
453 }
454
455 if (dwError != ERROR_SUCCESS)
456 return dwError;
457
458 /* Invoke the services entry point and implement the command loop */
459 ThreadHandle = CreateThread(NULL,
460 0,
461 ScServiceMainStub,
462 lpService,
463 CREATE_SUSPENDED,
464 &ThreadId);
465 if (ThreadHandle == NULL)
466 {
467 /* Free the arguments vector */
468 if (lpService->bUnicode)
469 {
470 if (lpService->ThreadParams.W.lpArgVector != NULL)
471 {
472 HeapFree(GetProcessHeap(),
473 0,
474 lpService->ThreadParams.W.lpArgVector);
475 lpService->ThreadParams.W.lpArgVector = NULL;
476 lpService->ThreadParams.W.dwArgCount = 0;
477 }
478 }
479 else
480 {
481 if (lpService->ThreadParams.A.lpArgVector != NULL)
482 {
483 HeapFree(GetProcessHeap(),
484 0,
485 lpService->ThreadParams.A.lpArgVector);
486 lpService->ThreadParams.A.lpArgVector = NULL;
487 lpService->ThreadParams.A.dwArgCount = 0;
488 }
489 }
490
491 return ERROR_SERVICE_NO_THREAD;
492 }
493
494 ResumeThread(ThreadHandle);
495 CloseHandle(ThreadHandle);
496
497 return ERROR_SUCCESS;
498 }
499
500
501 static DWORD
502 ScControlService(PACTIVE_SERVICE lpService,
503 PSCM_CONTROL_PACKET ControlPacket)
504 {
505 if (lpService == NULL || ControlPacket == NULL)
506 return ERROR_INVALID_PARAMETER;
507
508 TRACE("ScControlService() called\n");
509 TRACE("Size: %lu\n", ControlPacket->dwSize);
510 TRACE("Service: %S\n", (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset));
511
512 if (lpService->HandlerFunction)
513 {
514 (lpService->HandlerFunction)(ControlPacket->dwControl);
515 }
516 else if (lpService->HandlerFunctionEx)
517 {
518 /* FIXME: send correct params */
519 (lpService->HandlerFunctionEx)(ControlPacket->dwControl, 0, NULL, NULL);
520 }
521
522 TRACE("ScControlService() done\n");
523
524 return ERROR_SUCCESS;
525 }
526
527
528 static BOOL
529 ScServiceDispatcher(HANDLE hPipe,
530 PSCM_CONTROL_PACKET ControlPacket,
531 DWORD dwBufferSize)
532 {
533 DWORD Count;
534 BOOL bResult;
535 DWORD dwRunningServices = 0;
536 LPWSTR lpServiceName;
537 PACTIVE_SERVICE lpService;
538 SCM_REPLY_PACKET ReplyPacket;
539 DWORD dwError;
540
541 TRACE("ScDispatcherLoop() called\n");
542
543 if (ControlPacket == NULL || dwBufferSize < sizeof(SCM_CONTROL_PACKET))
544 return FALSE;
545
546 while (TRUE)
547 {
548 /* Read command from the control pipe */
549 bResult = ReadFile(hPipe,
550 ControlPacket,
551 dwBufferSize,
552 &Count,
553 NULL);
554 if (bResult == FALSE)
555 {
556 ERR("Pipe read failed (Error: %lu)\n", GetLastError());
557 return FALSE;
558 }
559
560 lpServiceName = (LPWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
561 TRACE("Service: %S\n", lpServiceName);
562
563 if (ControlPacket->dwControl == SERVICE_CONTROL_START_OWN)
564 lpActiveServices[0].bOwnProcess = TRUE;
565
566 lpService = ScLookupServiceByServiceName(lpServiceName);
567 if (lpService != NULL)
568 {
569 /* Execute command */
570 switch (ControlPacket->dwControl)
571 {
572 case SERVICE_CONTROL_START_SHARE:
573 case SERVICE_CONTROL_START_OWN:
574 TRACE("Start command - received SERVICE_CONTROL_START\n");
575 dwError = ScStartService(lpService, ControlPacket);
576 if (dwError == ERROR_SUCCESS)
577 dwRunningServices++;
578 break;
579
580 case SERVICE_CONTROL_STOP:
581 TRACE("Stop command - received SERVICE_CONTROL_STOP\n");
582 dwError = ScControlService(lpService, ControlPacket);
583 if (dwError == ERROR_SUCCESS)
584 dwRunningServices--;
585 break;
586
587 default:
588 TRACE("Command %lu received", ControlPacket->dwControl);
589 dwError = ScControlService(lpService, ControlPacket);
590 break;
591 }
592 }
593 else
594 {
595 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
596 }
597
598 ReplyPacket.dwError = dwError;
599
600 /* Send the reply packet */
601 bResult = WriteFile(hPipe,
602 &ReplyPacket,
603 sizeof(ReplyPacket),
604 &Count,
605 NULL);
606 if (bResult == FALSE)
607 {
608 ERR("Pipe write failed (Error: %lu)\n", GetLastError());
609 return FALSE;
610 }
611
612 if (dwRunningServices == 0)
613 break;
614 }
615
616 return TRUE;
617 }
618
619
620 /**********************************************************************
621 * RegisterServiceCtrlHandlerA
622 *
623 * @implemented
624 */
625 SERVICE_STATUS_HANDLE WINAPI
626 RegisterServiceCtrlHandlerA(LPCSTR lpServiceName,
627 LPHANDLER_FUNCTION lpHandlerProc)
628 {
629 ANSI_STRING ServiceNameA;
630 UNICODE_STRING ServiceNameU;
631 SERVICE_STATUS_HANDLE SHandle;
632
633 RtlInitAnsiString(&ServiceNameA, (LPSTR)lpServiceName);
634 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
635 {
636 SetLastError(ERROR_OUTOFMEMORY);
637 return (SERVICE_STATUS_HANDLE)0;
638 }
639
640 SHandle = RegisterServiceCtrlHandlerW(ServiceNameU.Buffer,
641 lpHandlerProc);
642
643 RtlFreeUnicodeString(&ServiceNameU);
644
645 return SHandle;
646 }
647
648
649 /**********************************************************************
650 * RegisterServiceCtrlHandlerW
651 *
652 * @implemented
653 */
654 SERVICE_STATUS_HANDLE WINAPI
655 RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName,
656 LPHANDLER_FUNCTION lpHandlerProc)
657 {
658 PACTIVE_SERVICE Service;
659
660 Service = ScLookupServiceByServiceName((LPWSTR)lpServiceName);
661 if (Service == NULL)
662 {
663 return (SERVICE_STATUS_HANDLE)NULL;
664 }
665
666 Service->HandlerFunction = lpHandlerProc;
667 Service->HandlerFunctionEx = NULL;
668
669 TRACE("RegisterServiceCtrlHandler returning %lu\n", Service->hServiceStatus);
670
671 return Service->hServiceStatus;
672 }
673
674
675 /**********************************************************************
676 * RegisterServiceCtrlHandlerExA
677 *
678 * @implemented
679 */
680 SERVICE_STATUS_HANDLE WINAPI
681 RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName,
682 LPHANDLER_FUNCTION_EX lpHandlerProc,
683 LPVOID lpContext)
684 {
685 ANSI_STRING ServiceNameA;
686 UNICODE_STRING ServiceNameU;
687 SERVICE_STATUS_HANDLE SHandle;
688
689 RtlInitAnsiString(&ServiceNameA, (LPSTR)lpServiceName);
690 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
691 {
692 SetLastError(ERROR_OUTOFMEMORY);
693 return (SERVICE_STATUS_HANDLE)0;
694 }
695
696 SHandle = RegisterServiceCtrlHandlerExW(ServiceNameU.Buffer,
697 lpHandlerProc,
698 lpContext);
699
700 RtlFreeUnicodeString(&ServiceNameU);
701
702 return SHandle;
703 }
704
705
706 /**********************************************************************
707 * RegisterServiceCtrlHandlerExW
708 *
709 * @implemented
710 */
711 SERVICE_STATUS_HANDLE WINAPI
712 RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName,
713 LPHANDLER_FUNCTION_EX lpHandlerProc,
714 LPVOID lpContext)
715 {
716 PACTIVE_SERVICE Service;
717
718 Service = ScLookupServiceByServiceName(lpServiceName);
719 if (Service == NULL)
720 {
721 return (SERVICE_STATUS_HANDLE)NULL;
722 }
723
724 Service->HandlerFunction = NULL;
725 Service->HandlerFunctionEx = lpHandlerProc;
726 Service->HandlerContext = lpContext;
727
728 TRACE("RegisterServiceCtrlHandlerEx returning %lu\n", Service->hServiceStatus);
729
730 return Service->hServiceStatus;
731 }
732
733
734 /**********************************************************************
735 * I_ScSetServiceBitsA
736 *
737 * Undocumented
738 *
739 * @implemented
740 */
741 BOOL WINAPI
742 I_ScSetServiceBitsA(SERVICE_STATUS_HANDLE hServiceStatus,
743 DWORD dwServiceBits,
744 BOOL bSetBitsOn,
745 BOOL bUpdateImmediately,
746 LPSTR lpString)
747 {
748 BOOL bResult;
749
750 RpcTryExcept
751 {
752 /* Call to services.exe using RPC */
753 bResult = RI_ScSetServiceBitsA((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
754 dwServiceBits,
755 bSetBitsOn,
756 bUpdateImmediately,
757 lpString);
758 }
759 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
760 {
761 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
762 bResult = FALSE;
763 }
764 RpcEndExcept;
765
766 return bResult;
767 }
768
769
770 /**********************************************************************
771 * I_ScSetServiceBitsW
772 *
773 * Undocumented
774 *
775 * @implemented
776 */
777 BOOL WINAPI
778 I_ScSetServiceBitsW(SERVICE_STATUS_HANDLE hServiceStatus,
779 DWORD dwServiceBits,
780 BOOL bSetBitsOn,
781 BOOL bUpdateImmediately,
782 LPWSTR lpString)
783 {
784 BOOL bResult;
785
786 RpcTryExcept
787 {
788 /* Call to services.exe using RPC */
789 bResult = RI_ScSetServiceBitsW((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
790 dwServiceBits,
791 bSetBitsOn,
792 bUpdateImmediately,
793 lpString);
794 }
795 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
796 {
797 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
798 bResult = FALSE;
799 }
800 RpcEndExcept;
801
802 return bResult;
803 }
804
805
806 /**********************************************************************
807 * SetServiceBits
808 *
809 * @implemented
810 */
811 BOOL WINAPI
812 SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus,
813 DWORD dwServiceBits,
814 BOOL bSetBitsOn,
815 BOOL bUpdateImmediately)
816 {
817 return I_ScSetServiceBitsW(hServiceStatus,
818 dwServiceBits,
819 bSetBitsOn,
820 bUpdateImmediately,
821 NULL);
822 }
823
824
825 /**********************************************************************
826 * SetServiceStatus
827 *
828 * @implemented
829 */
830 BOOL WINAPI
831 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus,
832 LPSERVICE_STATUS lpServiceStatus)
833 {
834 DWORD dwError;
835
836 TRACE("SetServiceStatus() called\n");
837 TRACE("hServiceStatus %lu\n", hServiceStatus);
838
839 RpcTryExcept
840 {
841 /* Call to services.exe using RPC */
842 dwError = RSetServiceStatus((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
843 lpServiceStatus);
844 }
845 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
846 {
847 dwError = ScmRpcStatusToWinError(RpcExceptionCode());
848 }
849 RpcEndExcept;
850
851 if (dwError != ERROR_SUCCESS)
852 {
853 ERR("ScmrSetServiceStatus() failed (Error %lu)\n", dwError);
854 SetLastError(dwError);
855 return FALSE;
856 }
857
858 TRACE("SetServiceStatus() done (ret %lu)\n", dwError);
859
860 return TRUE;
861 }
862
863
864 /**********************************************************************
865 * StartServiceCtrlDispatcherA
866 *
867 * @implemented
868 */
869 BOOL WINAPI
870 StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA *lpServiceStartTable)
871 {
872 ULONG i;
873 HANDLE hPipe;
874 DWORD dwError;
875 PSCM_CONTROL_PACKET ControlPacket;
876 DWORD dwBufSize;
877 BOOL bRet = TRUE;
878
879 TRACE("StartServiceCtrlDispatcherA() called\n");
880
881 i = 0;
882 while (lpServiceStartTable[i].lpServiceProc != NULL)
883 {
884 i++;
885 }
886
887 dwActiveServiceCount = i;
888 lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
889 HEAP_ZERO_MEMORY,
890 dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
891 if (lpActiveServices == NULL)
892 {
893 return FALSE;
894 }
895
896 /* Copy service names and start procedure */
897 for (i = 0; i < dwActiveServiceCount; i++)
898 {
899 RtlCreateUnicodeStringFromAsciiz(&lpActiveServices[i].ServiceName,
900 lpServiceStartTable[i].lpServiceName);
901 lpActiveServices[i].ThreadParams.A.lpServiceMain = lpServiceStartTable[i].lpServiceProc;
902 lpActiveServices[i].hServiceStatus = 0;
903 lpActiveServices[i].bUnicode = FALSE;
904 lpActiveServices[i].bOwnProcess = FALSE;
905 }
906
907 dwError = ScConnectControlPipe(&hPipe);
908 if (dwError != ERROR_SUCCESS)
909 {
910 bRet = FALSE;
911 goto done;
912 }
913
914 dwBufSize = sizeof(SCM_CONTROL_PACKET) +
915 (MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR);
916
917 ControlPacket = RtlAllocateHeap(RtlGetProcessHeap(),
918 HEAP_ZERO_MEMORY,
919 dwBufSize);
920 if (ControlPacket == NULL)
921 {
922 bRet = FALSE;
923 goto done;
924 }
925
926 ScCreateStatusBinding();
927
928 ScServiceDispatcher(hPipe, ControlPacket, dwBufSize);
929
930 ScDestroyStatusBinding();
931
932 CloseHandle(hPipe);
933
934 /* Free the control packet */
935 RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket);
936
937 done:
938 /* Free the service table */
939 for (i = 0; i < dwActiveServiceCount; i++)
940 {
941 RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
942 }
943 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
944 lpActiveServices = NULL;
945 dwActiveServiceCount = 0;
946
947 return bRet;
948 }
949
950
951 /**********************************************************************
952 * StartServiceCtrlDispatcherW
953 *
954 * @implemented
955 */
956 BOOL WINAPI
957 StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW *lpServiceStartTable)
958 {
959 ULONG i;
960 HANDLE hPipe;
961 DWORD dwError;
962 PSCM_CONTROL_PACKET ControlPacket;
963 DWORD dwBufSize;
964 BOOL bRet = TRUE;
965
966 TRACE("StartServiceCtrlDispatcherW() called\n");
967
968 i = 0;
969 while (lpServiceStartTable[i].lpServiceProc != NULL)
970 {
971 i++;
972 }
973
974 dwActiveServiceCount = i;
975 lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
976 HEAP_ZERO_MEMORY,
977 dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
978 if (lpActiveServices == NULL)
979 {
980 return FALSE;
981 }
982
983 /* Copy service names and start procedure */
984 for (i = 0; i < dwActiveServiceCount; i++)
985 {
986 RtlCreateUnicodeString(&lpActiveServices[i].ServiceName,
987 lpServiceStartTable[i].lpServiceName);
988 lpActiveServices[i].ThreadParams.W.lpServiceMain = lpServiceStartTable[i].lpServiceProc;
989 lpActiveServices[i].hServiceStatus = 0;
990 lpActiveServices[i].bUnicode = TRUE;
991 lpActiveServices[i].bOwnProcess = FALSE;
992 }
993
994 dwError = ScConnectControlPipe(&hPipe);
995 if (dwError != ERROR_SUCCESS)
996 {
997 bRet = FALSE;
998 goto done;
999 }
1000
1001 dwBufSize = sizeof(SCM_CONTROL_PACKET) +
1002 (MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR);
1003
1004 ControlPacket = RtlAllocateHeap(RtlGetProcessHeap(),
1005 HEAP_ZERO_MEMORY,
1006 dwBufSize);
1007 if (ControlPacket == NULL)
1008 {
1009 bRet = FALSE;
1010 goto done;
1011 }
1012
1013 ScCreateStatusBinding();
1014
1015 ScServiceDispatcher(hPipe, ControlPacket, dwBufSize);
1016
1017 ScDestroyStatusBinding();
1018
1019 CloseHandle(hPipe);
1020
1021 /* Free the control packet */
1022 RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket);
1023
1024 done:
1025 /* Free the service table */
1026 for (i = 0; i < dwActiveServiceCount; i++)
1027 {
1028 RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
1029 }
1030 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
1031 lpActiveServices = NULL;
1032 dwActiveServiceCount = 0;
1033
1034 return bRet;
1035 }
1036
1037 /* EOF */