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