* Sync up to trunk head (r65426).
[reactos.git] / 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, 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(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 LPWSTR pszServiceName;
292 DWORD cbServiceName;
293 DWORD cbTotal;
294 DWORD i;
295
296 if (ControlPacket == NULL || lpArgCount == NULL || lpArgVector == NULL)
297 return ERROR_INVALID_PARAMETER;
298
299 *lpArgCount = 0;
300 *lpArgVector = NULL;
301
302 pszServiceName = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
303 cbServiceName = lstrlenW(pszServiceName) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
304
305 cbTotal = cbServiceName + sizeof(LPWSTR);
306 if (ControlPacket->dwArgumentsCount > 0)
307 cbTotal += ControlPacket->dwSize - ControlPacket->dwArgumentsOffset;
308
309 lpVector = HeapAlloc(GetProcessHeap(),
310 HEAP_ZERO_MEMORY,
311 cbTotal);
312 if (lpVector == NULL)
313 return ERROR_OUTOFMEMORY;
314
315 lpArg = lpVector;
316 *lpArg = (LPWSTR)(lpArg + 1);
317 lpArg++;
318
319 memcpy(lpArg, pszServiceName, cbServiceName);
320 lpArg = (LPWSTR*)((ULONG_PTR)lpArg + cbServiceName);
321
322 if (ControlPacket->dwArgumentsCount > 0)
323 {
324 memcpy(lpArg,
325 ((PBYTE)ControlPacket + ControlPacket->dwArgumentsOffset),
326 ControlPacket->dwSize - ControlPacket->dwArgumentsOffset);
327
328 for (i = 0; i < ControlPacket->dwArgumentsCount; i++)
329 {
330 *lpArg = (LPWSTR)((ULONG_PTR)lpArg + (ULONG_PTR)*lpArg);
331 lpArg++;
332 }
333 }
334
335 *lpArgCount = ControlPacket->dwArgumentsCount + 1;
336 *lpArgVector = lpVector;
337
338 return ERROR_SUCCESS;
339 }
340
341
342 static DWORD
343 ScBuildAnsiArgsVector(PSCM_CONTROL_PACKET ControlPacket,
344 LPDWORD lpArgCount,
345 LPSTR **lpArgVector)
346 {
347 LPSTR *lpVector;
348 LPSTR *lpPtr;
349 LPWSTR lpUnicodeString;
350 LPWSTR pszServiceName;
351 LPSTR lpAnsiString;
352 DWORD cbServiceName;
353 DWORD dwVectorSize;
354 DWORD dwUnicodeSize;
355 DWORD dwAnsiSize = 0;
356 DWORD dwAnsiNameSize = 0;
357 DWORD i;
358
359 if (ControlPacket == NULL || lpArgCount == NULL || lpArgVector == NULL)
360 return ERROR_INVALID_PARAMETER;
361
362 *lpArgCount = 0;
363 *lpArgVector = NULL;
364
365 pszServiceName = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
366 cbServiceName = lstrlenW(pszServiceName) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
367
368 dwAnsiNameSize = WideCharToMultiByte(CP_ACP,
369 0,
370 pszServiceName,
371 cbServiceName,
372 NULL,
373 0,
374 NULL,
375 NULL);
376
377 dwVectorSize = ControlPacket->dwArgumentsCount * sizeof(LPWSTR);
378 if (ControlPacket->dwArgumentsCount > 0)
379 {
380 lpUnicodeString = (LPWSTR)((PBYTE)ControlPacket +
381 ControlPacket->dwArgumentsOffset +
382 dwVectorSize);
383 dwUnicodeSize = (ControlPacket->dwSize -
384 ControlPacket->dwArgumentsOffset -
385 dwVectorSize) / sizeof(WCHAR);
386
387 dwAnsiSize = WideCharToMultiByte(CP_ACP,
388 0,
389 lpUnicodeString,
390 dwUnicodeSize,
391 NULL,
392 0,
393 NULL,
394 NULL);
395 }
396
397 dwVectorSize += sizeof(LPWSTR);
398
399 lpVector = HeapAlloc(GetProcessHeap(),
400 HEAP_ZERO_MEMORY,
401 dwVectorSize + dwAnsiNameSize + dwAnsiSize);
402 if (lpVector == NULL)
403 return ERROR_OUTOFMEMORY;
404
405 lpPtr = (LPSTR*)lpVector;
406 lpAnsiString = (LPSTR)((ULONG_PTR)lpVector + dwVectorSize);
407
408 WideCharToMultiByte(CP_ACP,
409 0,
410 pszServiceName,
411 cbServiceName,
412 lpAnsiString,
413 dwAnsiNameSize,
414 NULL,
415 NULL);
416
417 if (ControlPacket->dwArgumentsCount > 0)
418 {
419 lpAnsiString = (LPSTR)((ULONG_PTR)lpAnsiString + dwAnsiNameSize);
420
421 WideCharToMultiByte(CP_ACP,
422 0,
423 lpUnicodeString,
424 dwUnicodeSize,
425 lpAnsiString,
426 dwAnsiSize,
427 NULL,
428 NULL);
429 }
430
431 lpAnsiString = (LPSTR)((ULONG_PTR)lpVector + dwVectorSize);
432 for (i = 0; i < ControlPacket->dwArgumentsCount + 1; i++)
433 {
434 *lpPtr = lpAnsiString;
435
436 lpPtr++;
437 lpAnsiString += (strlen(lpAnsiString) + 1);
438 }
439
440 *lpArgCount = ControlPacket->dwArgumentsCount + 1;
441 *lpArgVector = lpVector;
442
443 return ERROR_SUCCESS;
444 }
445
446
447 static DWORD
448 ScStartService(PACTIVE_SERVICE lpService,
449 PSCM_CONTROL_PACKET ControlPacket)
450 {
451 HANDLE ThreadHandle;
452 DWORD ThreadId;
453 DWORD dwError;
454
455 if (lpService == NULL || ControlPacket == NULL)
456 return ERROR_INVALID_PARAMETER;
457
458 TRACE("ScStartService() called\n");
459 TRACE("Size: %lu\n", ControlPacket->dwSize);
460 TRACE("Service: %S\n", (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset));
461
462 /* Set the service status handle */
463 lpService->hServiceStatus = ControlPacket->hServiceStatus;
464
465 /* Build the arguments vector */
466 if (lpService->bUnicode == TRUE)
467 {
468 dwError = ScBuildUnicodeArgsVector(ControlPacket,
469 &lpService->ThreadParams.W.dwArgCount,
470 &lpService->ThreadParams.W.lpArgVector);
471 }
472 else
473 {
474 dwError = ScBuildAnsiArgsVector(ControlPacket,
475 &lpService->ThreadParams.A.dwArgCount,
476 &lpService->ThreadParams.A.lpArgVector);
477 }
478
479 if (dwError != ERROR_SUCCESS)
480 return dwError;
481
482 /* Invoke the services entry point and implement the command loop */
483 ThreadHandle = CreateThread(NULL,
484 0,
485 ScServiceMainStub,
486 lpService,
487 CREATE_SUSPENDED,
488 &ThreadId);
489 if (ThreadHandle == NULL)
490 {
491 /* Free the arguments vector */
492 if (lpService->bUnicode)
493 {
494 if (lpService->ThreadParams.W.lpArgVector != NULL)
495 {
496 HeapFree(GetProcessHeap(),
497 0,
498 lpService->ThreadParams.W.lpArgVector);
499 lpService->ThreadParams.W.lpArgVector = NULL;
500 lpService->ThreadParams.W.dwArgCount = 0;
501 }
502 }
503 else
504 {
505 if (lpService->ThreadParams.A.lpArgVector != NULL)
506 {
507 HeapFree(GetProcessHeap(),
508 0,
509 lpService->ThreadParams.A.lpArgVector);
510 lpService->ThreadParams.A.lpArgVector = NULL;
511 lpService->ThreadParams.A.dwArgCount = 0;
512 }
513 }
514
515 return ERROR_SERVICE_NO_THREAD;
516 }
517
518 ResumeThread(ThreadHandle);
519 CloseHandle(ThreadHandle);
520
521 return ERROR_SUCCESS;
522 }
523
524
525 static DWORD
526 ScControlService(PACTIVE_SERVICE lpService,
527 PSCM_CONTROL_PACKET ControlPacket)
528 {
529 if (lpService == NULL || ControlPacket == NULL)
530 return ERROR_INVALID_PARAMETER;
531
532 TRACE("ScControlService() called\n");
533 TRACE("Size: %lu\n", ControlPacket->dwSize);
534 TRACE("Service: %S\n", (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset));
535
536 if (lpService->HandlerFunction)
537 {
538 (lpService->HandlerFunction)(ControlPacket->dwControl);
539 }
540 else if (lpService->HandlerFunctionEx)
541 {
542 /* FIXME: send correct params */
543 (lpService->HandlerFunctionEx)(ControlPacket->dwControl, 0, NULL, NULL);
544 }
545
546 TRACE("ScControlService() done\n");
547
548 return ERROR_SUCCESS;
549 }
550
551
552 static BOOL
553 ScServiceDispatcher(HANDLE hPipe,
554 PSCM_CONTROL_PACKET ControlPacket,
555 DWORD dwBufferSize)
556 {
557 DWORD Count;
558 BOOL bResult;
559 DWORD dwRunningServices = 0;
560 LPWSTR lpServiceName;
561 PACTIVE_SERVICE lpService;
562 SCM_REPLY_PACKET ReplyPacket;
563 DWORD dwError;
564
565 TRACE("ScDispatcherLoop() called\n");
566
567 if (ControlPacket == NULL || dwBufferSize < sizeof(SCM_CONTROL_PACKET))
568 return FALSE;
569
570 while (TRUE)
571 {
572 /* Read command from the control pipe */
573 bResult = ReadFile(hPipe,
574 ControlPacket,
575 dwBufferSize,
576 &Count,
577 NULL);
578 if (bResult == FALSE)
579 {
580 ERR("Pipe read failed (Error: %lu)\n", GetLastError());
581 return FALSE;
582 }
583
584 lpServiceName = (LPWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
585 TRACE("Service: %S\n", lpServiceName);
586
587 if (ControlPacket->dwControl == SERVICE_CONTROL_START_OWN)
588 lpActiveServices[0].bOwnProcess = TRUE;
589
590 lpService = ScLookupServiceByServiceName(lpServiceName);
591 if (lpService != NULL)
592 {
593 /* Execute command */
594 switch (ControlPacket->dwControl)
595 {
596 case SERVICE_CONTROL_START_SHARE:
597 case SERVICE_CONTROL_START_OWN:
598 TRACE("Start command - received SERVICE_CONTROL_START\n");
599 dwError = ScStartService(lpService, ControlPacket);
600 if (dwError == ERROR_SUCCESS)
601 dwRunningServices++;
602 break;
603
604 case SERVICE_CONTROL_STOP:
605 TRACE("Stop command - received SERVICE_CONTROL_STOP\n");
606 dwError = ScControlService(lpService, ControlPacket);
607 if (dwError == ERROR_SUCCESS)
608 dwRunningServices--;
609 break;
610
611 default:
612 TRACE("Command %lu received", ControlPacket->dwControl);
613 dwError = ScControlService(lpService, ControlPacket);
614 break;
615 }
616 }
617 else
618 {
619 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
620 }
621
622 ReplyPacket.dwError = dwError;
623
624 /* Send the reply packet */
625 bResult = WriteFile(hPipe,
626 &ReplyPacket,
627 sizeof(ReplyPacket),
628 &Count,
629 NULL);
630 if (bResult == FALSE)
631 {
632 ERR("Pipe write failed (Error: %lu)\n", GetLastError());
633 return FALSE;
634 }
635
636 if (dwRunningServices == 0)
637 break;
638 }
639
640 return TRUE;
641 }
642
643
644 /**********************************************************************
645 * RegisterServiceCtrlHandlerA
646 *
647 * @implemented
648 */
649 SERVICE_STATUS_HANDLE WINAPI
650 RegisterServiceCtrlHandlerA(LPCSTR lpServiceName,
651 LPHANDLER_FUNCTION lpHandlerProc)
652 {
653 ANSI_STRING ServiceNameA;
654 UNICODE_STRING ServiceNameU;
655 SERVICE_STATUS_HANDLE SHandle;
656
657 RtlInitAnsiString(&ServiceNameA, (LPSTR)lpServiceName);
658 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
659 {
660 SetLastError(ERROR_OUTOFMEMORY);
661 return (SERVICE_STATUS_HANDLE)0;
662 }
663
664 SHandle = RegisterServiceCtrlHandlerW(ServiceNameU.Buffer,
665 lpHandlerProc);
666
667 RtlFreeUnicodeString(&ServiceNameU);
668
669 return SHandle;
670 }
671
672
673 /**********************************************************************
674 * RegisterServiceCtrlHandlerW
675 *
676 * @implemented
677 */
678 SERVICE_STATUS_HANDLE WINAPI
679 RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName,
680 LPHANDLER_FUNCTION lpHandlerProc)
681 {
682 PACTIVE_SERVICE Service;
683
684 Service = ScLookupServiceByServiceName((LPWSTR)lpServiceName);
685 if (Service == NULL)
686 {
687 return (SERVICE_STATUS_HANDLE)NULL;
688 }
689
690 Service->HandlerFunction = lpHandlerProc;
691 Service->HandlerFunctionEx = NULL;
692
693 TRACE("RegisterServiceCtrlHandler returning %lu\n", Service->hServiceStatus);
694
695 return Service->hServiceStatus;
696 }
697
698
699 /**********************************************************************
700 * RegisterServiceCtrlHandlerExA
701 *
702 * @implemented
703 */
704 SERVICE_STATUS_HANDLE WINAPI
705 RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName,
706 LPHANDLER_FUNCTION_EX lpHandlerProc,
707 LPVOID lpContext)
708 {
709 ANSI_STRING ServiceNameA;
710 UNICODE_STRING ServiceNameU;
711 SERVICE_STATUS_HANDLE SHandle;
712
713 RtlInitAnsiString(&ServiceNameA, (LPSTR)lpServiceName);
714 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
715 {
716 SetLastError(ERROR_OUTOFMEMORY);
717 return (SERVICE_STATUS_HANDLE)0;
718 }
719
720 SHandle = RegisterServiceCtrlHandlerExW(ServiceNameU.Buffer,
721 lpHandlerProc,
722 lpContext);
723
724 RtlFreeUnicodeString(&ServiceNameU);
725
726 return SHandle;
727 }
728
729
730 /**********************************************************************
731 * RegisterServiceCtrlHandlerExW
732 *
733 * @implemented
734 */
735 SERVICE_STATUS_HANDLE WINAPI
736 RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName,
737 LPHANDLER_FUNCTION_EX lpHandlerProc,
738 LPVOID lpContext)
739 {
740 PACTIVE_SERVICE Service;
741
742 Service = ScLookupServiceByServiceName(lpServiceName);
743 if (Service == NULL)
744 {
745 return (SERVICE_STATUS_HANDLE)NULL;
746 }
747
748 Service->HandlerFunction = NULL;
749 Service->HandlerFunctionEx = lpHandlerProc;
750 Service->HandlerContext = lpContext;
751
752 TRACE("RegisterServiceCtrlHandlerEx returning %lu\n", Service->hServiceStatus);
753
754 return Service->hServiceStatus;
755 }
756
757
758 /**********************************************************************
759 * I_ScSetServiceBitsA
760 *
761 * Undocumented
762 *
763 * @implemented
764 */
765 BOOL WINAPI
766 I_ScSetServiceBitsA(SERVICE_STATUS_HANDLE hServiceStatus,
767 DWORD dwServiceBits,
768 BOOL bSetBitsOn,
769 BOOL bUpdateImmediately,
770 LPSTR lpString)
771 {
772 BOOL bResult;
773
774 RpcTryExcept
775 {
776 /* Call to services.exe using RPC */
777 bResult = RI_ScSetServiceBitsA((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
778 dwServiceBits,
779 bSetBitsOn,
780 bUpdateImmediately,
781 lpString);
782 }
783 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
784 {
785 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
786 bResult = FALSE;
787 }
788 RpcEndExcept;
789
790 return bResult;
791 }
792
793
794 /**********************************************************************
795 * I_ScSetServiceBitsW
796 *
797 * Undocumented
798 *
799 * @implemented
800 */
801 BOOL WINAPI
802 I_ScSetServiceBitsW(SERVICE_STATUS_HANDLE hServiceStatus,
803 DWORD dwServiceBits,
804 BOOL bSetBitsOn,
805 BOOL bUpdateImmediately,
806 LPWSTR lpString)
807 {
808 BOOL bResult;
809
810 RpcTryExcept
811 {
812 /* Call to services.exe using RPC */
813 bResult = RI_ScSetServiceBitsW((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
814 dwServiceBits,
815 bSetBitsOn,
816 bUpdateImmediately,
817 lpString);
818 }
819 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
820 {
821 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
822 bResult = FALSE;
823 }
824 RpcEndExcept;
825
826 return bResult;
827 }
828
829
830 /**********************************************************************
831 * SetServiceBits
832 *
833 * @implemented
834 */
835 BOOL WINAPI
836 SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus,
837 DWORD dwServiceBits,
838 BOOL bSetBitsOn,
839 BOOL bUpdateImmediately)
840 {
841 return I_ScSetServiceBitsW(hServiceStatus,
842 dwServiceBits,
843 bSetBitsOn,
844 bUpdateImmediately,
845 NULL);
846 }
847
848
849 /**********************************************************************
850 * SetServiceStatus
851 *
852 * @implemented
853 */
854 BOOL WINAPI
855 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus,
856 LPSERVICE_STATUS lpServiceStatus)
857 {
858 DWORD dwError;
859
860 TRACE("SetServiceStatus() called\n");
861 TRACE("hServiceStatus %lu\n", hServiceStatus);
862
863 RpcTryExcept
864 {
865 /* Call to services.exe using RPC */
866 dwError = RSetServiceStatus((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
867 lpServiceStatus);
868 }
869 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
870 {
871 dwError = ScmRpcStatusToWinError(RpcExceptionCode());
872 }
873 RpcEndExcept;
874
875 if (dwError != ERROR_SUCCESS)
876 {
877 ERR("ScmrSetServiceStatus() failed (Error %lu)\n", dwError);
878 SetLastError(dwError);
879 return FALSE;
880 }
881
882 TRACE("SetServiceStatus() done (ret %lu)\n", dwError);
883
884 return TRUE;
885 }
886
887
888 /**********************************************************************
889 * StartServiceCtrlDispatcherA
890 *
891 * @implemented
892 */
893 BOOL WINAPI
894 StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA *lpServiceStartTable)
895 {
896 ULONG i;
897 HANDLE hPipe;
898 DWORD dwError;
899 PSCM_CONTROL_PACKET ControlPacket;
900 DWORD dwBufSize;
901 BOOL bRet = TRUE;
902
903 TRACE("StartServiceCtrlDispatcherA() called\n");
904
905 i = 0;
906 while (lpServiceStartTable[i].lpServiceProc != NULL)
907 {
908 i++;
909 }
910
911 dwActiveServiceCount = i;
912 lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
913 HEAP_ZERO_MEMORY,
914 dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
915 if (lpActiveServices == NULL)
916 {
917 return FALSE;
918 }
919
920 /* Copy service names and start procedure */
921 for (i = 0; i < dwActiveServiceCount; i++)
922 {
923 RtlCreateUnicodeStringFromAsciiz(&lpActiveServices[i].ServiceName,
924 lpServiceStartTable[i].lpServiceName);
925 lpActiveServices[i].ThreadParams.A.lpServiceMain = lpServiceStartTable[i].lpServiceProc;
926 lpActiveServices[i].hServiceStatus = 0;
927 lpActiveServices[i].bUnicode = FALSE;
928 lpActiveServices[i].bOwnProcess = FALSE;
929 }
930
931 dwError = ScConnectControlPipe(&hPipe);
932 if (dwError != ERROR_SUCCESS)
933 {
934 bRet = FALSE;
935 goto done;
936 }
937
938 dwBufSize = sizeof(SCM_CONTROL_PACKET) +
939 (MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR);
940
941 ControlPacket = RtlAllocateHeap(RtlGetProcessHeap(),
942 HEAP_ZERO_MEMORY,
943 dwBufSize);
944 if (ControlPacket == NULL)
945 {
946 bRet = FALSE;
947 goto done;
948 }
949
950 ScCreateStatusBinding();
951
952 ScServiceDispatcher(hPipe, ControlPacket, dwBufSize);
953
954 ScDestroyStatusBinding();
955
956 CloseHandle(hPipe);
957
958 /* Free the control packet */
959 RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket);
960
961 done:
962 /* Free the service table */
963 for (i = 0; i < dwActiveServiceCount; i++)
964 {
965 RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
966 }
967 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
968 lpActiveServices = NULL;
969 dwActiveServiceCount = 0;
970
971 return bRet;
972 }
973
974
975 /**********************************************************************
976 * StartServiceCtrlDispatcherW
977 *
978 * @implemented
979 */
980 BOOL WINAPI
981 StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW *lpServiceStartTable)
982 {
983 ULONG i;
984 HANDLE hPipe;
985 DWORD dwError;
986 PSCM_CONTROL_PACKET ControlPacket;
987 DWORD dwBufSize;
988 BOOL bRet = TRUE;
989
990 TRACE("StartServiceCtrlDispatcherW() called\n");
991
992 i = 0;
993 while (lpServiceStartTable[i].lpServiceProc != NULL)
994 {
995 i++;
996 }
997
998 dwActiveServiceCount = i;
999 lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
1000 HEAP_ZERO_MEMORY,
1001 dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
1002 if (lpActiveServices == NULL)
1003 {
1004 return FALSE;
1005 }
1006
1007 /* Copy service names and start procedure */
1008 for (i = 0; i < dwActiveServiceCount; i++)
1009 {
1010 RtlCreateUnicodeString(&lpActiveServices[i].ServiceName,
1011 lpServiceStartTable[i].lpServiceName);
1012 lpActiveServices[i].ThreadParams.W.lpServiceMain = lpServiceStartTable[i].lpServiceProc;
1013 lpActiveServices[i].hServiceStatus = 0;
1014 lpActiveServices[i].bUnicode = TRUE;
1015 lpActiveServices[i].bOwnProcess = FALSE;
1016 }
1017
1018 dwError = ScConnectControlPipe(&hPipe);
1019 if (dwError != ERROR_SUCCESS)
1020 {
1021 bRet = FALSE;
1022 goto done;
1023 }
1024
1025 dwBufSize = sizeof(SCM_CONTROL_PACKET) +
1026 (MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR);
1027
1028 ControlPacket = RtlAllocateHeap(RtlGetProcessHeap(),
1029 HEAP_ZERO_MEMORY,
1030 dwBufSize);
1031 if (ControlPacket == NULL)
1032 {
1033 bRet = FALSE;
1034 goto done;
1035 }
1036
1037 ScCreateStatusBinding();
1038
1039 ScServiceDispatcher(hPipe, ControlPacket, dwBufSize);
1040
1041 ScDestroyStatusBinding();
1042
1043 CloseHandle(hPipe);
1044
1045 /* Free the control packet */
1046 RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket);
1047
1048 done:
1049 /* Free the service table */
1050 for (i = 0; i < dwActiveServiceCount; i++)
1051 {
1052 RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
1053 }
1054 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
1055 lpActiveServices = NULL;
1056 dwActiveServiceCount = 0;
1057
1058 return bRet;
1059 }
1060
1061 /* EOF */