xref: /reactos/dll/win32/advapi32/service/scm.c (revision c2c66aff)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS system libraries
4  * FILE:            lib/advapi32/service/scm.c
5  * PURPOSE:         Service control manager functions
6  * PROGRAMMER:      Emanuele Aliberti
7  *                  Eric Kohl
8  * UPDATE HISTORY:
9  *  19990413 EA created
10  *  19990515 EA
11  */
12 
13 /* INCLUDES ******************************************************************/
14 
15 #include <advapi32.h>
16 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
17 
18 
19 /* FUNCTIONS *****************************************************************/
20 
21 handle_t __RPC_USER
22 SVCCTL_HANDLEA_bind(SVCCTL_HANDLEA szMachineName)
23 {
24     handle_t hBinding = NULL;
25     UCHAR *pszStringBinding;
26     RPC_STATUS status;
27 
28     TRACE("SVCCTL_HANDLEA_bind() called\n");
29 
30     status = RpcStringBindingComposeA(NULL,
31                                       (UCHAR *)"ncacn_np",
32                                       (UCHAR *)szMachineName,
33                                       (UCHAR *)"\\pipe\\ntsvcs",
34                                       NULL,
35                                       (UCHAR **)&pszStringBinding);
36     if (status != RPC_S_OK)
37     {
38         ERR("RpcStringBindingCompose returned 0x%x\n", status);
39         return NULL;
40     }
41 
42     /* Set the binding handle that will be used to bind to the server. */
43     status = RpcBindingFromStringBindingA(pszStringBinding,
44                                           &hBinding);
45     if (status != RPC_S_OK)
46     {
47         ERR("RpcBindingFromStringBinding returned 0x%x\n", status);
48     }
49 
50     status = RpcStringFreeA(&pszStringBinding);
51     if (status != RPC_S_OK)
52     {
53         ERR("RpcStringFree returned 0x%x\n", status);
54     }
55 
56     return hBinding;
57 }
58 
59 
60 void __RPC_USER
61 SVCCTL_HANDLEA_unbind(SVCCTL_HANDLEA szMachineName,
62                       handle_t hBinding)
63 {
64     RPC_STATUS status;
65 
66     TRACE("SVCCTL_HANDLEA_unbind() called\n");
67 
68     status = RpcBindingFree(&hBinding);
69     if (status != RPC_S_OK)
70     {
71         ERR("RpcBindingFree returned 0x%x\n", status);
72     }
73 }
74 
75 
76 handle_t __RPC_USER
77 SVCCTL_HANDLEW_bind(SVCCTL_HANDLEW szMachineName)
78 {
79     handle_t hBinding = NULL;
80     LPWSTR pszStringBinding;
81     RPC_STATUS status;
82 
83     TRACE("SVCCTL_HANDLEW_bind() called\n");
84 
85     status = RpcStringBindingComposeW(NULL,
86                                       L"ncacn_np",
87                                       szMachineName,
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 NULL;
95     }
96 
97     /* Set the binding handle that will be used to bind to the server. */
98     status = RpcBindingFromStringBindingW(pszStringBinding,
99                                           &hBinding);
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 hBinding;
112 }
113 
114 
115 void __RPC_USER
116 SVCCTL_HANDLEW_unbind(SVCCTL_HANDLEW szMachineName,
117                       handle_t hBinding)
118 {
119     RPC_STATUS status;
120 
121     TRACE("SVCCTL_HANDLEW_unbind() called\n");
122 
123     status = RpcBindingFree(&hBinding);
124     if (status != RPC_S_OK)
125     {
126         ERR("RpcBindingFree returned 0x%x\n", status);
127     }
128 }
129 
130 
131 DWORD
132 ScmRpcStatusToWinError(RPC_STATUS Status)
133 {
134     switch (Status)
135     {
136         case STATUS_ACCESS_VIOLATION:
137         case RPC_S_INVALID_BINDING:
138         case RPC_X_SS_IN_NULL_CONTEXT:
139             return ERROR_INVALID_HANDLE;
140 
141         case RPC_X_ENUM_VALUE_OUT_OF_RANGE:
142         case RPC_X_BYTE_COUNT_TOO_SMALL:
143             return ERROR_INVALID_PARAMETER;
144 
145         case RPC_X_NULL_REF_POINTER:
146             return ERROR_INVALID_ADDRESS;
147 
148         default:
149             return (DWORD)Status;
150     }
151 }
152 
153 
154 /**********************************************************************
155  *  ChangeServiceConfig2A
156  *
157  * @implemented
158  */
159 BOOL WINAPI
160 ChangeServiceConfig2A(SC_HANDLE hService,
161                       DWORD dwInfoLevel,
162                       LPVOID lpInfo)
163 {
164     SC_RPC_CONFIG_INFOA Info;
165     DWORD dwError;
166 
167     TRACE("ChangeServiceConfig2A() called\n");
168 
169     if (lpInfo == NULL) return TRUE;
170 
171     /* Fill relevant field of the Info structure */
172     Info.dwInfoLevel = dwInfoLevel;
173     switch (dwInfoLevel)
174     {
175         case SERVICE_CONFIG_DESCRIPTION:
176             Info.psd = lpInfo;
177             break;
178 
179         case SERVICE_CONFIG_FAILURE_ACTIONS:
180             Info.psfa = lpInfo;
181             break;
182 
183         default:
184             WARN("Unknown info level 0x%lx\n", dwInfoLevel);
185             SetLastError(ERROR_INVALID_PARAMETER);
186             return FALSE;
187     }
188 
189     RpcTryExcept
190     {
191         dwError = RChangeServiceConfig2A((SC_RPC_HANDLE)hService,
192                                          Info);
193     }
194     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
195     {
196         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
197     }
198     RpcEndExcept;
199 
200     if (dwError != ERROR_SUCCESS)
201     {
202         TRACE("RChangeServiceConfig2A() failed (Error %lu)\n", dwError);
203         SetLastError(dwError);
204         return FALSE;
205     }
206 
207     return TRUE;
208 }
209 
210 
211 /**********************************************************************
212  *  ChangeServiceConfig2W
213  *
214  * @implemented
215  */
216 BOOL WINAPI
217 ChangeServiceConfig2W(SC_HANDLE hService,
218                       DWORD dwInfoLevel,
219                       LPVOID lpInfo)
220 {
221     SC_RPC_CONFIG_INFOW Info;
222     DWORD dwError;
223 
224     TRACE("ChangeServiceConfig2W() called\n");
225 
226     if (lpInfo == NULL) return TRUE;
227 
228     /* Fill relevant field of the Info structure */
229     Info.dwInfoLevel = dwInfoLevel;
230     switch (dwInfoLevel)
231     {
232         case SERVICE_CONFIG_DESCRIPTION:
233             Info.psd = lpInfo;
234             break;
235 
236         case SERVICE_CONFIG_FAILURE_ACTIONS:
237             Info.psfa = lpInfo;
238             break;
239 
240         default:
241             WARN("Unknown info level 0x%lx\n", dwInfoLevel);
242             SetLastError(ERROR_INVALID_PARAMETER);
243             return FALSE;
244     }
245 
246     RpcTryExcept
247     {
248         dwError = RChangeServiceConfig2W((SC_RPC_HANDLE)hService,
249                                          Info);
250     }
251     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
252     {
253         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
254     }
255     RpcEndExcept;
256 
257     if (dwError != ERROR_SUCCESS)
258     {
259         TRACE("RChangeServiceConfig2W() failed (Error %lu)\n", dwError);
260         SetLastError(dwError);
261         return FALSE;
262     }
263 
264     return TRUE;
265 }
266 
267 
268 /**********************************************************************
269  *  ChangeServiceConfigA
270  *
271  * @implemented
272  */
273 BOOL WINAPI
274 ChangeServiceConfigA(SC_HANDLE hService,
275                      DWORD dwServiceType,
276                      DWORD dwStartType,
277                      DWORD dwErrorControl,
278                      LPCSTR lpBinaryPathName,
279                      LPCSTR lpLoadOrderGroup,
280                      LPDWORD lpdwTagId,
281                      LPCSTR lpDependencies,
282                      LPCSTR lpServiceStartName,
283                      LPCSTR lpPassword,
284                      LPCSTR lpDisplayName)
285 {
286     DWORD dwError;
287     DWORD dwDependenciesLength = 0;
288     SIZE_T cchLength;
289     LPCSTR lpStr;
290     DWORD dwPasswordLength = 0;
291     LPWSTR lpPasswordW = NULL;
292     LPBYTE lpEncryptedPassword = NULL;
293 
294     TRACE("ChangeServiceConfigA() called\n");
295 
296     /* Calculate the Dependencies length*/
297     if (lpDependencies != NULL)
298     {
299         lpStr = lpDependencies;
300         while (*lpStr)
301         {
302             cchLength = strlen(lpStr) + 1;
303             dwDependenciesLength += (DWORD)cchLength;
304             lpStr = lpStr + cchLength;
305         }
306         dwDependenciesLength++;
307     }
308 
309     if (lpPassword != NULL)
310     {
311         /* Convert the password to unicode */
312         lpPasswordW = HeapAlloc(GetProcessHeap(),
313                                 HEAP_ZERO_MEMORY,
314                                 (strlen(lpPassword) + 1) * sizeof(WCHAR));
315         if (lpPasswordW == NULL)
316         {
317             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
318             return FALSE;
319         }
320 
321         MultiByteToWideChar(CP_ACP,
322                             0,
323                             lpPassword,
324                             -1,
325                             lpPasswordW,
326                             (int)(strlen(lpPassword) + 1));
327 
328         /* FIXME: Encrypt the password */
329         lpEncryptedPassword = (LPBYTE)lpPasswordW;
330         dwPasswordLength = (wcslen(lpPasswordW) + 1) * sizeof(WCHAR);
331     }
332 
333     RpcTryExcept
334     {
335         /* Call to services.exe using RPC */
336         dwError = RChangeServiceConfigA((SC_RPC_HANDLE)hService,
337                                         dwServiceType,
338                                         dwStartType,
339                                         dwErrorControl,
340                                         (LPSTR)lpBinaryPathName,
341                                         (LPSTR)lpLoadOrderGroup,
342                                         lpdwTagId,
343                                         (LPBYTE)lpDependencies,
344                                         dwDependenciesLength,
345                                         (LPSTR)lpServiceStartName,
346                                         lpEncryptedPassword,
347                                         dwPasswordLength,
348                                         (LPSTR)lpDisplayName);
349     }
350     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
351     {
352         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
353     }
354     RpcEndExcept;
355 
356     if (lpPasswordW != NULL)
357         HeapFree(GetProcessHeap(), 0, lpPasswordW);
358 
359     if (dwError != ERROR_SUCCESS)
360     {
361         TRACE("RChangeServiceConfigA() failed (Error %lu)\n", dwError);
362         SetLastError(dwError);
363         return FALSE;
364     }
365 
366     return TRUE;
367 }
368 
369 
370 /**********************************************************************
371  *  ChangeServiceConfigW
372  *
373  * @implemented
374  */
375 BOOL WINAPI
376 ChangeServiceConfigW(SC_HANDLE hService,
377                      DWORD dwServiceType,
378                      DWORD dwStartType,
379                      DWORD dwErrorControl,
380                      LPCWSTR lpBinaryPathName,
381                      LPCWSTR lpLoadOrderGroup,
382                      LPDWORD lpdwTagId,
383                      LPCWSTR lpDependencies,
384                      LPCWSTR lpServiceStartName,
385                      LPCWSTR lpPassword,
386                      LPCWSTR lpDisplayName)
387 {
388     DWORD dwError;
389     DWORD dwDependenciesLength = 0;
390     SIZE_T cchLength;
391     LPCWSTR lpStr;
392     DWORD dwPasswordLength = 0;
393     LPBYTE lpEncryptedPassword = NULL;
394 
395     TRACE("ChangeServiceConfigW() called\n");
396 
397     /* Calculate the Dependencies length*/
398     if (lpDependencies != NULL)
399     {
400         lpStr = lpDependencies;
401         while (*lpStr)
402         {
403             cchLength = wcslen(lpStr) + 1;
404             dwDependenciesLength += (DWORD)cchLength;
405             lpStr = lpStr + cchLength;
406         }
407         dwDependenciesLength++;
408         dwDependenciesLength *= sizeof(WCHAR);
409     }
410 
411     if (lpPassword != NULL)
412     {
413         /* FIXME: Encrypt the password */
414         lpEncryptedPassword = (LPBYTE)lpPassword;
415         dwPasswordLength = (wcslen(lpPassword) + 1) * sizeof(WCHAR);
416     }
417 
418     RpcTryExcept
419     {
420         /* Call to services.exe using RPC */
421         dwError = RChangeServiceConfigW((SC_RPC_HANDLE)hService,
422                                         dwServiceType,
423                                         dwStartType,
424                                         dwErrorControl,
425                                         (LPWSTR)lpBinaryPathName,
426                                         (LPWSTR)lpLoadOrderGroup,
427                                         lpdwTagId,
428                                         (LPBYTE)lpDependencies,
429                                         dwDependenciesLength,
430                                         (LPWSTR)lpServiceStartName,
431                                         lpEncryptedPassword,
432                                         dwPasswordLength,
433                                         (LPWSTR)lpDisplayName);
434     }
435     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
436     {
437         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
438     }
439     RpcEndExcept;
440 
441     if (dwError != ERROR_SUCCESS)
442     {
443         TRACE("RChangeServiceConfigW() failed (Error %lu)\n", dwError);
444         SetLastError(dwError);
445         return FALSE;
446     }
447 
448     return TRUE;
449 }
450 
451 
452 /**********************************************************************
453  *  CloseServiceHandle
454  *
455  * @implemented
456  */
457 BOOL WINAPI
458 CloseServiceHandle(SC_HANDLE hSCObject)
459 {
460     DWORD dwError;
461 
462     TRACE("CloseServiceHandle() called\n");
463 
464     if (!hSCObject)
465     {
466         SetLastError(ERROR_INVALID_HANDLE);
467         return FALSE;
468     }
469 
470     RpcTryExcept
471     {
472         /* Call to services.exe using RPC */
473         dwError = RCloseServiceHandle((LPSC_RPC_HANDLE)&hSCObject);
474     }
475     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
476     {
477         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
478     }
479     RpcEndExcept;
480 
481     if (dwError)
482     {
483         TRACE("RCloseServiceHandle() failed (Error %lu)\n", dwError);
484         SetLastError(dwError);
485         return FALSE;
486     }
487 
488     TRACE("CloseServiceHandle() done\n");
489 
490     return TRUE;
491 }
492 
493 
494 /**********************************************************************
495  *  ControlService
496  *
497  * @implemented
498  */
499 BOOL WINAPI
500 ControlService(SC_HANDLE hService,
501                DWORD dwControl,
502                LPSERVICE_STATUS lpServiceStatus)
503 {
504     DWORD dwError;
505 
506     TRACE("ControlService(%x, %x, %p)\n",
507            hService, dwControl, lpServiceStatus);
508 
509     RpcTryExcept
510     {
511         /* Call to services.exe using RPC */
512         dwError = RControlService((SC_RPC_HANDLE)hService,
513                                   dwControl,
514                                   lpServiceStatus);
515     }
516     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
517     {
518         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
519     }
520     RpcEndExcept;
521 
522     if (dwError != ERROR_SUCCESS)
523     {
524         TRACE("RControlService() failed (Error %lu)\n", dwError);
525         SetLastError(dwError);
526         return FALSE;
527     }
528 
529     TRACE("ControlService() done\n");
530 
531     return TRUE;
532 }
533 
534 
535 /**********************************************************************
536  *  ControlServiceEx
537  *
538  * @unimplemented
539  */
540 BOOL WINAPI
541 ControlServiceEx(IN SC_HANDLE hService,
542                  IN DWORD dwControl,
543                  IN DWORD dwInfoLevel,
544                  IN OUT PVOID pControlParams)
545 {
546     FIXME("ControlServiceEx(0x%p, 0x%x, 0x%x, 0x%p) UNIMPLEMENTED!\n",
547             hService, dwControl, dwInfoLevel, pControlParams);
548     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
549     return FALSE;
550 }
551 
552 
553 /**********************************************************************
554  *  CreateServiceA
555  *
556  * @implemented
557  */
558 SC_HANDLE WINAPI
559 CreateServiceA(SC_HANDLE hSCManager,
560                LPCSTR lpServiceName,
561                LPCSTR lpDisplayName,
562                DWORD dwDesiredAccess,
563                DWORD dwServiceType,
564                DWORD dwStartType,
565                DWORD dwErrorControl,
566                LPCSTR lpBinaryPathName,
567                LPCSTR lpLoadOrderGroup,
568                LPDWORD lpdwTagId,
569                LPCSTR lpDependencies,
570                LPCSTR lpServiceStartName,
571                LPCSTR lpPassword)
572 {
573     SC_HANDLE hService = NULL;
574     DWORD dwDependenciesLength = 0;
575     DWORD dwError;
576     SIZE_T cchLength;
577     LPCSTR lpStr;
578     DWORD dwPasswordLength = 0;
579     LPWSTR lpPasswordW = NULL;
580     LPBYTE lpEncryptedPassword = NULL;
581 
582     TRACE("CreateServiceA() called\n");
583     TRACE("%p %s %s\n", hSCManager,
584           lpServiceName, lpDisplayName);
585 
586     if (!hSCManager)
587     {
588         SetLastError(ERROR_INVALID_HANDLE);
589         return NULL;
590     }
591 
592     /* Calculate the Dependencies length */
593     if (lpDependencies != NULL)
594     {
595         lpStr = lpDependencies;
596         while (*lpStr)
597         {
598             cchLength = strlen(lpStr) + 1;
599             dwDependenciesLength += (DWORD)cchLength;
600             lpStr = lpStr + cchLength;
601         }
602         dwDependenciesLength++;
603     }
604 
605     if (lpPassword != NULL)
606     {
607         /* Convert the password to unicode */
608         lpPasswordW = HeapAlloc(GetProcessHeap(),
609                                 HEAP_ZERO_MEMORY,
610                                 (strlen(lpPassword) + 1) * sizeof(WCHAR));
611         if (lpPasswordW == NULL)
612         {
613             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
614             return FALSE;
615         }
616 
617         MultiByteToWideChar(CP_ACP,
618                             0,
619                             lpPassword,
620                             -1,
621                             lpPasswordW,
622                             (int)(strlen(lpPassword) + 1));
623 
624         /* FIXME: Encrypt the password */
625         lpEncryptedPassword = (LPBYTE)lpPasswordW;
626         dwPasswordLength = (wcslen(lpPasswordW) + 1) * sizeof(WCHAR);
627     }
628 
629     RpcTryExcept
630     {
631         /* Call to services.exe using RPC */
632         dwError = RCreateServiceA((SC_RPC_HANDLE)hSCManager,
633                                   (LPSTR)lpServiceName,
634                                   (LPSTR)lpDisplayName,
635                                   dwDesiredAccess,
636                                   dwServiceType,
637                                   dwStartType,
638                                   dwErrorControl,
639                                   (LPSTR)lpBinaryPathName,
640                                   (LPSTR)lpLoadOrderGroup,
641                                   lpdwTagId,
642                                   (LPBYTE)lpDependencies,
643                                   dwDependenciesLength,
644                                   (LPSTR)lpServiceStartName,
645                                   lpEncryptedPassword,
646                                   dwPasswordLength,
647                                   (SC_RPC_HANDLE *)&hService);
648     }
649     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
650     {
651         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
652     }
653     RpcEndExcept;
654 
655     if (lpPasswordW != NULL)
656         HeapFree(GetProcessHeap(), 0, lpPasswordW);
657 
658     SetLastError(dwError);
659     if (dwError != ERROR_SUCCESS)
660     {
661         TRACE("RCreateServiceA() failed (Error %lu)\n", dwError);
662         return NULL;
663     }
664 
665     return hService;
666 }
667 
668 
669 /**********************************************************************
670  *  CreateServiceW
671  *
672  * @implemented
673  */
674 SC_HANDLE WINAPI
675 CreateServiceW(SC_HANDLE hSCManager,
676                LPCWSTR lpServiceName,
677                LPCWSTR lpDisplayName,
678                DWORD dwDesiredAccess,
679                DWORD dwServiceType,
680                DWORD dwStartType,
681                DWORD dwErrorControl,
682                LPCWSTR lpBinaryPathName,
683                LPCWSTR lpLoadOrderGroup,
684                LPDWORD lpdwTagId,
685                LPCWSTR lpDependencies,
686                LPCWSTR lpServiceStartName,
687                LPCWSTR lpPassword)
688 {
689     SC_HANDLE hService = NULL;
690     DWORD dwDependenciesLength = 0;
691     DWORD dwError;
692     SIZE_T cchLength;
693     LPCWSTR lpStr;
694     DWORD dwPasswordLength = 0;
695     LPBYTE lpEncryptedPassword = NULL;
696 
697     TRACE("CreateServiceW() called\n");
698     TRACE("%p %S %S\n", hSCManager,
699           lpServiceName, lpDisplayName);
700 
701     if (!hSCManager)
702     {
703         SetLastError(ERROR_INVALID_HANDLE);
704         return NULL;
705     }
706 
707     /* Calculate the Dependencies length */
708     if (lpDependencies != NULL)
709     {
710         lpStr = lpDependencies;
711         while (*lpStr)
712         {
713             cchLength = wcslen(lpStr) + 1;
714             dwDependenciesLength += (DWORD)cchLength;
715             lpStr = lpStr + cchLength;
716         }
717         dwDependenciesLength++;
718         dwDependenciesLength *= sizeof(WCHAR);
719     }
720 
721     if (lpPassword != NULL)
722     {
723         /* FIXME: Encrypt the password */
724         lpEncryptedPassword = (LPBYTE)lpPassword;
725         dwPasswordLength = (wcslen(lpPassword) + 1) * sizeof(WCHAR);
726     }
727 
728     RpcTryExcept
729     {
730         /* Call to services.exe using RPC */
731         dwError = RCreateServiceW((SC_RPC_HANDLE)hSCManager,
732                                   lpServiceName,
733                                   lpDisplayName,
734                                   dwDesiredAccess,
735                                   dwServiceType,
736                                   dwStartType,
737                                   dwErrorControl,
738                                   lpBinaryPathName,
739                                   lpLoadOrderGroup,
740                                   lpdwTagId,
741                                   (LPBYTE)lpDependencies,
742                                   dwDependenciesLength,
743                                   lpServiceStartName,
744                                   lpEncryptedPassword,
745                                   dwPasswordLength,
746                                   (SC_RPC_HANDLE *)&hService);
747     }
748     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
749     {
750         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
751     }
752     RpcEndExcept;
753 
754     SetLastError(dwError);
755     if (dwError != ERROR_SUCCESS)
756     {
757         TRACE("RCreateServiceW() failed (Error %lu)\n", dwError);
758         return NULL;
759     }
760 
761     return hService;
762 }
763 
764 
765 /**********************************************************************
766  *  DeleteService
767  *
768  * @implemented
769  */
770 BOOL WINAPI
771 DeleteService(SC_HANDLE hService)
772 {
773     DWORD dwError;
774 
775     TRACE("DeleteService(%x)\n", hService);
776 
777     RpcTryExcept
778     {
779         /* Call to services.exe using RPC */
780         dwError = RDeleteService((SC_RPC_HANDLE)hService);
781     }
782     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
783     {
784         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
785     }
786     RpcEndExcept;
787 
788     if (dwError != ERROR_SUCCESS)
789     {
790         TRACE("RDeleteService() failed (Error %lu)\n", dwError);
791         SetLastError(dwError);
792         return FALSE;
793     }
794 
795     return TRUE;
796 }
797 
798 
799 /**********************************************************************
800  *  EnumDependentServicesA
801  *
802  * @implemented
803  */
804 BOOL WINAPI
805 EnumDependentServicesA(SC_HANDLE hService,
806                        DWORD dwServiceState,
807                        LPENUM_SERVICE_STATUSA lpServices,
808                        DWORD cbBufSize,
809                        LPDWORD pcbBytesNeeded,
810                        LPDWORD lpServicesReturned)
811 {
812     ENUM_SERVICE_STATUSA ServiceStatus;
813     LPENUM_SERVICE_STATUSA lpStatusPtr;
814     DWORD dwBufferSize;
815     DWORD dwError;
816     DWORD dwCount;
817 
818     TRACE("EnumDependentServicesA() called\n");
819 
820     if (lpServices == NULL || cbBufSize < sizeof(ENUM_SERVICE_STATUSA))
821     {
822         lpStatusPtr = &ServiceStatus;
823         dwBufferSize = sizeof(ENUM_SERVICE_STATUSA);
824     }
825     else
826     {
827         lpStatusPtr = lpServices;
828         dwBufferSize = cbBufSize;
829     }
830 
831     RpcTryExcept
832     {
833         dwError = REnumDependentServicesA((SC_RPC_HANDLE)hService,
834                                           dwServiceState,
835                                           (LPBYTE)lpStatusPtr,
836                                           dwBufferSize,
837                                           pcbBytesNeeded,
838                                           lpServicesReturned);
839     }
840     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
841     {
842         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
843     }
844     RpcEndExcept;
845 
846     if (dwError == ERROR_SUCCESS || dwError == ERROR_MORE_DATA)
847     {
848         for (dwCount = 0; dwCount < *lpServicesReturned; dwCount++)
849         {
850             if (lpStatusPtr->lpServiceName)
851                 lpStatusPtr->lpServiceName =
852                     (LPSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpServiceName);
853 
854             if (lpStatusPtr->lpDisplayName)
855                 lpStatusPtr->lpDisplayName =
856                     (LPSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpDisplayName);
857 
858             lpStatusPtr++;
859         }
860     }
861 
862     if (dwError != ERROR_SUCCESS)
863     {
864         TRACE("REnumDependentServicesA() failed (Error %lu)\n", dwError);
865         SetLastError(dwError);
866         return FALSE;
867     }
868 
869     TRACE("EnumDependentServicesA() done\n");
870 
871     return TRUE;
872 }
873 
874 
875 /**********************************************************************
876  *  EnumDependentServicesW
877  *
878  * @implemented
879  */
880 BOOL WINAPI
881 EnumDependentServicesW(SC_HANDLE hService,
882                        DWORD dwServiceState,
883                        LPENUM_SERVICE_STATUSW lpServices,
884                        DWORD cbBufSize,
885                        LPDWORD pcbBytesNeeded,
886                        LPDWORD lpServicesReturned)
887 {
888     ENUM_SERVICE_STATUSW ServiceStatus;
889     LPENUM_SERVICE_STATUSW lpStatusPtr;
890     DWORD dwBufferSize;
891     DWORD dwError;
892     DWORD dwCount;
893 
894     TRACE("EnumDependentServicesW() called\n");
895 
896     if (lpServices == NULL || cbBufSize < sizeof(ENUM_SERVICE_STATUSW))
897     {
898         lpStatusPtr = &ServiceStatus;
899         dwBufferSize = sizeof(ENUM_SERVICE_STATUSW);
900     }
901     else
902     {
903         lpStatusPtr = lpServices;
904         dwBufferSize = cbBufSize;
905     }
906 
907     RpcTryExcept
908     {
909         dwError = REnumDependentServicesW((SC_RPC_HANDLE)hService,
910                                           dwServiceState,
911                                           (LPBYTE)lpStatusPtr,
912                                           dwBufferSize,
913                                           pcbBytesNeeded,
914                                           lpServicesReturned);
915     }
916     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
917     {
918         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
919     }
920     RpcEndExcept;
921 
922     if (dwError == ERROR_SUCCESS || dwError == ERROR_MORE_DATA)
923     {
924         for (dwCount = 0; dwCount < *lpServicesReturned; dwCount++)
925         {
926             if (lpStatusPtr->lpServiceName)
927                 lpStatusPtr->lpServiceName =
928                     (LPWSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpServiceName);
929 
930             if (lpStatusPtr->lpDisplayName)
931                 lpStatusPtr->lpDisplayName =
932                     (LPWSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpDisplayName);
933 
934             lpStatusPtr++;
935         }
936     }
937 
938     if (dwError != ERROR_SUCCESS)
939     {
940         TRACE("REnumDependentServicesW() failed (Error %lu)\n", dwError);
941         SetLastError(dwError);
942         return FALSE;
943     }
944 
945     TRACE("EnumDependentServicesW() done\n");
946 
947     return TRUE;
948 }
949 
950 
951 /**********************************************************************
952  *  EnumServiceGroupW
953  *
954  * @implemented
955  */
956 BOOL WINAPI
957 EnumServiceGroupW(SC_HANDLE hSCManager,
958                   DWORD dwServiceType,
959                   DWORD dwServiceState,
960                   LPENUM_SERVICE_STATUSW lpServices,
961                   DWORD cbBufSize,
962                   LPDWORD pcbBytesNeeded,
963                   LPDWORD lpServicesReturned,
964                   LPDWORD lpResumeHandle,
965                   LPCWSTR lpGroup)
966 {
967     ENUM_SERVICE_STATUSW ServiceStatus;
968     LPENUM_SERVICE_STATUSW lpStatusPtr;
969     DWORD dwBufferSize;
970     DWORD dwError;
971     DWORD dwCount;
972 
973     TRACE("EnumServiceGroupW() called\n");
974 
975     if (!hSCManager)
976     {
977         SetLastError(ERROR_INVALID_HANDLE);
978         return FALSE;
979     }
980 
981     if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
982     {
983         SetLastError(ERROR_INVALID_ADDRESS);
984         return FALSE;
985     }
986 
987     if (lpServices == NULL || cbBufSize < sizeof(ENUM_SERVICE_STATUSW))
988     {
989         lpStatusPtr = &ServiceStatus;
990         dwBufferSize = sizeof(ENUM_SERVICE_STATUSW);
991     }
992     else
993     {
994         lpStatusPtr = lpServices;
995         dwBufferSize = cbBufSize;
996     }
997 
998     RpcTryExcept
999     {
1000         if (lpGroup == NULL)
1001         {
1002             dwError = REnumServicesStatusW((SC_RPC_HANDLE)hSCManager,
1003                                            dwServiceType,
1004                                            dwServiceState,
1005                                            (LPBYTE)lpStatusPtr,
1006                                            dwBufferSize,
1007                                            pcbBytesNeeded,
1008                                            lpServicesReturned,
1009                                            lpResumeHandle);
1010         }
1011         else
1012         {
1013             dwError = REnumServiceGroupW((SC_RPC_HANDLE)hSCManager,
1014                                          dwServiceType,
1015                                          dwServiceState,
1016                                          (LPBYTE)lpStatusPtr,
1017                                          dwBufferSize,
1018                                          pcbBytesNeeded,
1019                                          lpServicesReturned,
1020                                          lpResumeHandle,
1021                                          lpGroup);
1022         }
1023     }
1024     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1025     {
1026         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1027     }
1028     RpcEndExcept;
1029 
1030     if (dwError == ERROR_SUCCESS || dwError == ERROR_MORE_DATA)
1031     {
1032         for (dwCount = 0; dwCount < *lpServicesReturned; dwCount++)
1033         {
1034             if (lpStatusPtr->lpServiceName)
1035                 lpStatusPtr->lpServiceName =
1036                     (LPWSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpServiceName);
1037 
1038             if (lpStatusPtr->lpDisplayName)
1039                 lpStatusPtr->lpDisplayName =
1040                     (LPWSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpDisplayName);
1041 
1042             lpStatusPtr++;
1043         }
1044     }
1045 
1046     if (dwError != ERROR_SUCCESS)
1047     {
1048         TRACE("REnumServiceGroupW() failed (Error %lu)\n", dwError);
1049         SetLastError(dwError);
1050         return FALSE;
1051     }
1052 
1053     TRACE("EnumServiceGroupW() done\n");
1054 
1055     return TRUE;
1056 }
1057 
1058 
1059 /**********************************************************************
1060  *  EnumServicesStatusA
1061  *
1062  * @implemented
1063  */
1064 BOOL WINAPI
1065 EnumServicesStatusA(SC_HANDLE hSCManager,
1066                     DWORD dwServiceType,
1067                     DWORD dwServiceState,
1068                     LPENUM_SERVICE_STATUSA lpServices,
1069                     DWORD cbBufSize,
1070                     LPDWORD pcbBytesNeeded,
1071                     LPDWORD lpServicesReturned,
1072                     LPDWORD lpResumeHandle)
1073 {
1074     ENUM_SERVICE_STATUSA ServiceStatus;
1075     LPENUM_SERVICE_STATUSA lpStatusPtr;
1076     DWORD dwBufferSize;
1077     DWORD dwError;
1078     DWORD dwCount;
1079 
1080     TRACE("EnumServicesStatusA() called\n");
1081 
1082     if (!hSCManager)
1083     {
1084         SetLastError(ERROR_INVALID_HANDLE);
1085         return FALSE;
1086     }
1087 
1088     if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
1089     {
1090         SetLastError(ERROR_INVALID_ADDRESS);
1091         return FALSE;
1092     }
1093 
1094     if (lpServices == NULL || cbBufSize < sizeof(ENUM_SERVICE_STATUSA))
1095     {
1096         lpStatusPtr = &ServiceStatus;
1097         dwBufferSize = sizeof(ENUM_SERVICE_STATUSA);
1098     }
1099     else
1100     {
1101         lpStatusPtr = lpServices;
1102         dwBufferSize = cbBufSize;
1103     }
1104 
1105     RpcTryExcept
1106     {
1107         dwError = REnumServicesStatusA((SC_RPC_HANDLE)hSCManager,
1108                                        dwServiceType,
1109                                        dwServiceState,
1110                                        (LPBYTE)lpStatusPtr,
1111                                        dwBufferSize,
1112                                        pcbBytesNeeded,
1113                                        lpServicesReturned,
1114                                        lpResumeHandle);
1115     }
1116     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1117     {
1118         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1119     }
1120     RpcEndExcept;
1121 
1122     if (dwError == ERROR_SUCCESS || dwError == ERROR_MORE_DATA)
1123     {
1124         for (dwCount = 0; dwCount < *lpServicesReturned; dwCount++)
1125         {
1126             if (lpStatusPtr->lpServiceName)
1127                 lpStatusPtr->lpServiceName =
1128                     (LPSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpServiceName);
1129 
1130             if (lpStatusPtr->lpDisplayName)
1131                 lpStatusPtr->lpDisplayName =
1132                     (LPSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpDisplayName);
1133 
1134             lpStatusPtr++;
1135         }
1136     }
1137 
1138     if (dwError != ERROR_SUCCESS)
1139     {
1140         TRACE("REnumServicesStatusA() failed (Error %lu)\n", dwError);
1141         SetLastError(dwError);
1142         return FALSE;
1143     }
1144 
1145     TRACE("EnumServicesStatusA() done\n");
1146 
1147     return TRUE;
1148 }
1149 
1150 
1151 /**********************************************************************
1152  *  EnumServicesStatusW
1153  *
1154  * @implemented
1155  */
1156 BOOL WINAPI
1157 EnumServicesStatusW(SC_HANDLE hSCManager,
1158                     DWORD dwServiceType,
1159                     DWORD dwServiceState,
1160                     LPENUM_SERVICE_STATUSW lpServices,
1161                     DWORD cbBufSize,
1162                     LPDWORD pcbBytesNeeded,
1163                     LPDWORD lpServicesReturned,
1164                     LPDWORD lpResumeHandle)
1165 {
1166     ENUM_SERVICE_STATUSW ServiceStatus;
1167     LPENUM_SERVICE_STATUSW lpStatusPtr;
1168     DWORD dwBufferSize;
1169     DWORD dwError;
1170     DWORD dwCount;
1171 
1172     TRACE("EnumServicesStatusW() called\n");
1173 
1174     if (!hSCManager)
1175     {
1176         SetLastError(ERROR_INVALID_HANDLE);
1177         return FALSE;
1178     }
1179 
1180     if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
1181     {
1182         SetLastError(ERROR_INVALID_ADDRESS);
1183         return FALSE;
1184     }
1185 
1186     if (lpServices == NULL || cbBufSize < sizeof(ENUM_SERVICE_STATUSW))
1187     {
1188         lpStatusPtr = &ServiceStatus;
1189         dwBufferSize = sizeof(ENUM_SERVICE_STATUSW);
1190     }
1191     else
1192     {
1193         lpStatusPtr = lpServices;
1194         dwBufferSize = cbBufSize;
1195     }
1196 
1197     RpcTryExcept
1198     {
1199         dwError = REnumServicesStatusW((SC_RPC_HANDLE)hSCManager,
1200                                        dwServiceType,
1201                                        dwServiceState,
1202                                        (LPBYTE)lpStatusPtr,
1203                                        dwBufferSize,
1204                                        pcbBytesNeeded,
1205                                        lpServicesReturned,
1206                                        lpResumeHandle);
1207     }
1208     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1209     {
1210         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1211     }
1212     RpcEndExcept;
1213 
1214     if (dwError == ERROR_SUCCESS || dwError == ERROR_MORE_DATA)
1215     {
1216         for (dwCount = 0; dwCount < *lpServicesReturned; dwCount++)
1217         {
1218             if (lpStatusPtr->lpServiceName)
1219                 lpStatusPtr->lpServiceName =
1220                     (LPWSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpServiceName);
1221 
1222             if (lpStatusPtr->lpDisplayName)
1223                 lpStatusPtr->lpDisplayName =
1224                     (LPWSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpDisplayName);
1225 
1226             lpStatusPtr++;
1227         }
1228     }
1229 
1230     if (dwError != ERROR_SUCCESS)
1231     {
1232         TRACE("REnumServicesStatusW() failed (Error %lu)\n", dwError);
1233         SetLastError(dwError);
1234         return FALSE;
1235     }
1236 
1237     TRACE("EnumServicesStatusW() done\n");
1238 
1239     return TRUE;
1240 }
1241 
1242 
1243 /**********************************************************************
1244  *  EnumServicesStatusExA
1245  *
1246  * @implemented
1247  */
1248 BOOL WINAPI
1249 EnumServicesStatusExA(SC_HANDLE hSCManager,
1250                       SC_ENUM_TYPE InfoLevel,
1251                       DWORD dwServiceType,
1252                       DWORD dwServiceState,
1253                       LPBYTE lpServices,
1254                       DWORD cbBufSize,
1255                       LPDWORD pcbBytesNeeded,
1256                       LPDWORD lpServicesReturned,
1257                       LPDWORD lpResumeHandle,
1258                       LPCSTR pszGroupName)
1259 {
1260     ENUM_SERVICE_STATUS_PROCESSA ServiceStatus;
1261     LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtr;
1262     DWORD dwBufferSize;
1263     DWORD dwError;
1264     DWORD dwCount;
1265 
1266     TRACE("EnumServicesStatusExA() called\n");
1267 
1268     if (InfoLevel != SC_ENUM_PROCESS_INFO)
1269     {
1270         SetLastError(ERROR_INVALID_LEVEL);
1271         return FALSE;
1272     }
1273 
1274     if (!hSCManager)
1275     {
1276         SetLastError(ERROR_INVALID_HANDLE);
1277         return FALSE;
1278     }
1279 
1280     if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
1281     {
1282         SetLastError(ERROR_INVALID_ADDRESS);
1283         return FALSE;
1284     }
1285 
1286     if (lpServices == NULL || cbBufSize < sizeof(ENUM_SERVICE_STATUS_PROCESSA))
1287     {
1288         lpStatusPtr = &ServiceStatus;
1289         dwBufferSize = sizeof(ENUM_SERVICE_STATUS_PROCESSA);
1290     }
1291     else
1292     {
1293         lpStatusPtr = (LPENUM_SERVICE_STATUS_PROCESSA)lpServices;
1294         dwBufferSize = cbBufSize;
1295     }
1296 
1297     RpcTryExcept
1298     {
1299         dwError = REnumServicesStatusExA((SC_RPC_HANDLE)hSCManager,
1300                                          InfoLevel,
1301                                          dwServiceType,
1302                                          dwServiceState,
1303                                          (LPBYTE)lpStatusPtr,
1304                                          dwBufferSize,
1305                                          pcbBytesNeeded,
1306                                          lpServicesReturned,
1307                                          lpResumeHandle,
1308                                          (LPSTR)pszGroupName);
1309     }
1310     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1311     {
1312         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1313     }
1314     RpcEndExcept;
1315 
1316     if (dwError == ERROR_SUCCESS || dwError == ERROR_MORE_DATA)
1317     {
1318         if (InfoLevel == SC_ENUM_PROCESS_INFO)
1319         {
1320             for (dwCount = 0; dwCount < *lpServicesReturned; dwCount++)
1321             {
1322                 if (lpStatusPtr->lpServiceName)
1323                     lpStatusPtr->lpServiceName =
1324                         (LPSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpServiceName);
1325 
1326                 if (lpStatusPtr->lpDisplayName)
1327                     lpStatusPtr->lpDisplayName =
1328                         (LPSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpDisplayName);
1329 
1330                 lpStatusPtr++;
1331             }
1332         }
1333     }
1334 
1335     if (dwError != ERROR_SUCCESS)
1336     {
1337         TRACE("REnumServicesStatusExA() failed (Error %lu)\n", dwError);
1338         SetLastError(dwError);
1339         return FALSE;
1340     }
1341 
1342     TRACE("EnumServicesStatusExA() done\n");
1343 
1344     return TRUE;
1345 }
1346 
1347 
1348 /**********************************************************************
1349  *  EnumServicesStatusExW
1350  *
1351  * @implemented
1352  */
1353 BOOL WINAPI
1354 EnumServicesStatusExW(SC_HANDLE hSCManager,
1355                       SC_ENUM_TYPE InfoLevel,
1356                       DWORD dwServiceType,
1357                       DWORD dwServiceState,
1358                       LPBYTE lpServices,
1359                       DWORD cbBufSize,
1360                       LPDWORD pcbBytesNeeded,
1361                       LPDWORD lpServicesReturned,
1362                       LPDWORD lpResumeHandle,
1363                       LPCWSTR pszGroupName)
1364 {
1365     ENUM_SERVICE_STATUS_PROCESSW ServiceStatus;
1366     LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr;
1367     DWORD dwBufferSize;
1368     DWORD dwError;
1369     DWORD dwCount;
1370 
1371     TRACE("EnumServicesStatusExW() called\n");
1372 
1373     if (InfoLevel != SC_ENUM_PROCESS_INFO)
1374     {
1375         SetLastError(ERROR_INVALID_LEVEL);
1376         return FALSE;
1377     }
1378 
1379     if (!hSCManager)
1380     {
1381         SetLastError(ERROR_INVALID_HANDLE);
1382         return FALSE;
1383     }
1384 
1385     if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
1386     {
1387         SetLastError(ERROR_INVALID_ADDRESS);
1388         return FALSE;
1389     }
1390 
1391     if (lpServices == NULL || cbBufSize < sizeof(ENUM_SERVICE_STATUS_PROCESSW))
1392     {
1393         lpStatusPtr = &ServiceStatus;
1394         dwBufferSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW);
1395     }
1396     else
1397     {
1398         lpStatusPtr = (LPENUM_SERVICE_STATUS_PROCESSW)lpServices;
1399         dwBufferSize = cbBufSize;
1400     }
1401 
1402     RpcTryExcept
1403     {
1404         dwError = REnumServicesStatusExW((SC_RPC_HANDLE)hSCManager,
1405                                          InfoLevel,
1406                                          dwServiceType,
1407                                          dwServiceState,
1408                                          (LPBYTE)lpStatusPtr,
1409                                          dwBufferSize,
1410                                          pcbBytesNeeded,
1411                                          lpServicesReturned,
1412                                          lpResumeHandle,
1413                                          (LPWSTR)pszGroupName);
1414     }
1415     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1416     {
1417         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1418     }
1419     RpcEndExcept;
1420 
1421     if (dwError == ERROR_SUCCESS || dwError == ERROR_MORE_DATA)
1422     {
1423         if (InfoLevel == SC_ENUM_PROCESS_INFO)
1424         {
1425             for (dwCount = 0; dwCount < *lpServicesReturned; dwCount++)
1426             {
1427                 if (lpStatusPtr->lpServiceName)
1428                     lpStatusPtr->lpServiceName =
1429                         (LPWSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpServiceName);
1430 
1431                 if (lpStatusPtr->lpDisplayName)
1432                     lpStatusPtr->lpDisplayName =
1433                         (LPWSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpDisplayName);
1434 
1435                 lpStatusPtr++;
1436             }
1437         }
1438     }
1439 
1440     if (dwError != ERROR_SUCCESS)
1441     {
1442         TRACE("REnumServicesStatusExW() failed (Error %lu)\n", dwError);
1443         SetLastError(dwError);
1444         return FALSE;
1445     }
1446 
1447     TRACE("EnumServicesStatusExW() done\n");
1448 
1449     return TRUE;
1450 }
1451 
1452 
1453 /**********************************************************************
1454  *  GetServiceDisplayNameA
1455  *
1456  * @implemented
1457  */
1458 BOOL WINAPI
1459 GetServiceDisplayNameA(SC_HANDLE hSCManager,
1460                        LPCSTR lpServiceName,
1461                        LPSTR lpDisplayName,
1462                        LPDWORD lpcchBuffer)
1463 {
1464     DWORD dwError;
1465     LPSTR lpNameBuffer;
1466     CHAR szEmptyName[] = "";
1467 
1468     TRACE("GetServiceDisplayNameA() called\n");
1469     TRACE("%p %s %p %p\n", hSCManager,
1470           debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1471 
1472     if (!hSCManager)
1473     {
1474         SetLastError(ERROR_INVALID_HANDLE);
1475         return FALSE;
1476     }
1477 
1478     if (!lpDisplayName || *lpcchBuffer < sizeof(CHAR))
1479     {
1480         lpNameBuffer = szEmptyName;
1481         *lpcchBuffer = sizeof(CHAR);
1482     }
1483     else
1484     {
1485         lpNameBuffer = lpDisplayName;
1486     }
1487 
1488     RpcTryExcept
1489     {
1490         dwError = RGetServiceDisplayNameA((SC_RPC_HANDLE)hSCManager,
1491                                           lpServiceName,
1492                                           lpNameBuffer,
1493                                           lpcchBuffer);
1494     }
1495     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1496     {
1497         /* HACK: because of a problem with rpcrt4, rpcserver is hacked to return 6 for ERROR_SERVICE_DOES_NOT_EXIST */
1498         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1499     }
1500     RpcEndExcept;
1501 
1502     if (dwError != ERROR_SUCCESS)
1503     {
1504         TRACE("RGetServiceDisplayNameA() failed (Error %lu)\n", dwError);
1505         SetLastError(dwError);
1506         return FALSE;
1507     }
1508 
1509     return TRUE;
1510 }
1511 
1512 
1513 /**********************************************************************
1514  *  GetServiceDisplayNameW
1515  *
1516  * @implemented
1517  */
1518 BOOL WINAPI
1519 GetServiceDisplayNameW(SC_HANDLE hSCManager,
1520                        LPCWSTR lpServiceName,
1521                        LPWSTR lpDisplayName,
1522                        LPDWORD lpcchBuffer)
1523 {
1524     DWORD dwError;
1525     LPWSTR lpNameBuffer;
1526     WCHAR szEmptyName[] = L"";
1527 
1528     TRACE("GetServiceDisplayNameW() called\n");
1529 
1530     if (!hSCManager)
1531     {
1532         SetLastError(ERROR_INVALID_HANDLE);
1533         return FALSE;
1534     }
1535 
1536     if (!lpDisplayName || *lpcchBuffer < sizeof(WCHAR))
1537     {
1538         lpNameBuffer = szEmptyName;
1539         *lpcchBuffer = sizeof(WCHAR);
1540     }
1541     else
1542     {
1543         lpNameBuffer = lpDisplayName;
1544     }
1545 
1546     RpcTryExcept
1547     {
1548         dwError = RGetServiceDisplayNameW((SC_RPC_HANDLE)hSCManager,
1549                                           lpServiceName,
1550                                           lpNameBuffer,
1551                                           lpcchBuffer);
1552     }
1553     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1554     {
1555         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1556     }
1557     RpcEndExcept;
1558 
1559     if (dwError != ERROR_SUCCESS)
1560     {
1561         TRACE("RGetServiceDisplayNameW() failed (Error %lu)\n", dwError);
1562         SetLastError(dwError);
1563         return FALSE;
1564     }
1565 
1566     return TRUE;
1567 }
1568 
1569 
1570 /**********************************************************************
1571  *  GetServiceKeyNameA
1572  *
1573  * @implemented
1574  */
1575 BOOL WINAPI
1576 GetServiceKeyNameA(SC_HANDLE hSCManager,
1577                    LPCSTR lpDisplayName,
1578                    LPSTR lpServiceName,
1579                    LPDWORD lpcchBuffer)
1580 {
1581     DWORD dwError;
1582     LPSTR lpNameBuffer;
1583     CHAR szEmptyName[] = "";
1584 
1585     TRACE("GetServiceKeyNameA() called\n");
1586 
1587     if (!hSCManager)
1588     {
1589         SetLastError(ERROR_INVALID_HANDLE);
1590         return FALSE;
1591     }
1592 
1593     if (!lpServiceName || *lpcchBuffer < sizeof(CHAR))
1594     {
1595         lpNameBuffer = szEmptyName;
1596         *lpcchBuffer = sizeof(CHAR);
1597     }
1598     else
1599     {
1600         lpNameBuffer = lpServiceName;
1601     }
1602 
1603     RpcTryExcept
1604     {
1605         dwError = RGetServiceKeyNameA((SC_RPC_HANDLE)hSCManager,
1606                                       lpDisplayName,
1607                                       lpNameBuffer,
1608                                       lpcchBuffer);
1609     }
1610     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1611     {
1612         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1613     }
1614     RpcEndExcept;
1615 
1616     if (dwError != ERROR_SUCCESS)
1617     {
1618         TRACE("RGetServiceKeyNameA() failed (Error %lu)\n", dwError);
1619         SetLastError(dwError);
1620         return FALSE;
1621     }
1622 
1623     return TRUE;
1624 }
1625 
1626 
1627 /**********************************************************************
1628  *  GetServiceKeyNameW
1629  *
1630  * @implemented
1631  */
1632 BOOL WINAPI
1633 GetServiceKeyNameW(SC_HANDLE hSCManager,
1634                    LPCWSTR lpDisplayName,
1635                    LPWSTR lpServiceName,
1636                    LPDWORD lpcchBuffer)
1637 {
1638     DWORD dwError;
1639     LPWSTR lpNameBuffer;
1640     WCHAR szEmptyName[] = L"";
1641 
1642     TRACE("GetServiceKeyNameW() called\n");
1643 
1644     if (!hSCManager)
1645     {
1646         SetLastError(ERROR_INVALID_HANDLE);
1647         return FALSE;
1648     }
1649 
1650     if (!lpServiceName || *lpcchBuffer < sizeof(WCHAR))
1651     {
1652         lpNameBuffer = szEmptyName;
1653         *lpcchBuffer = sizeof(WCHAR);
1654     }
1655     else
1656     {
1657         lpNameBuffer = lpServiceName;
1658     }
1659 
1660     RpcTryExcept
1661     {
1662         dwError = RGetServiceKeyNameW((SC_RPC_HANDLE)hSCManager,
1663                                       lpDisplayName,
1664                                       lpNameBuffer,
1665                                       lpcchBuffer);
1666     }
1667     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1668     {
1669         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1670     }
1671     RpcEndExcept;
1672 
1673     if (dwError != ERROR_SUCCESS)
1674     {
1675         TRACE("RGetServiceKeyNameW() failed (Error %lu)\n", dwError);
1676         SetLastError(dwError);
1677         return FALSE;
1678     }
1679 
1680     return TRUE;
1681 }
1682 
1683 
1684 /**********************************************************************
1685  *  I_ScGetCurrentGroupStateW
1686  *
1687  * @implemented
1688  */
1689 DWORD WINAPI
1690 I_ScGetCurrentGroupStateW(SC_HANDLE hSCManager,
1691                           LPWSTR pszGroupName,
1692                           LPDWORD pdwGroupState)
1693 {
1694     DWORD dwError;
1695 
1696     TRACE("I_ScGetCurrentGroupStateW() called\n");
1697 
1698     RpcTryExcept
1699     {
1700         dwError = RI_ScGetCurrentGroupStateW((SC_RPC_HANDLE)hSCManager,
1701                                              pszGroupName,
1702                                              pdwGroupState);
1703     }
1704     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1705     {
1706         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1707     }
1708     RpcEndExcept
1709 
1710     if (dwError != ERROR_SUCCESS)
1711     {
1712         TRACE("RI_ScGetCurrentGroupStateW() failed (Error %lu)\n", dwError);
1713         SetLastError(dwError);
1714     }
1715 
1716     return dwError;
1717 }
1718 
1719 
1720 /**********************************************************************
1721  *  LockServiceDatabase
1722  *
1723  * @implemented
1724  */
1725 SC_LOCK WINAPI
1726 LockServiceDatabase(SC_HANDLE hSCManager)
1727 {
1728     SC_LOCK hLock;
1729     DWORD dwError;
1730 
1731     TRACE("LockServiceDatabase(%x)\n", hSCManager);
1732 
1733     RpcTryExcept
1734     {
1735         /* Call to services.exe using RPC */
1736         dwError = RLockServiceDatabase((SC_RPC_HANDLE)hSCManager,
1737                                        (SC_RPC_LOCK *)&hLock);
1738     }
1739     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1740     {
1741         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1742     }
1743     RpcEndExcept;
1744 
1745     if (dwError != ERROR_SUCCESS)
1746     {
1747         TRACE("RLockServiceDatabase() failed (Error %lu)\n", dwError);
1748         SetLastError(dwError);
1749         return NULL;
1750     }
1751 
1752     TRACE("hLock = %p\n", hLock);
1753 
1754     return hLock;
1755 }
1756 
1757 
1758 static VOID
1759 WaitForSCManager(VOID)
1760 {
1761     HANDLE hEvent;
1762 
1763     TRACE("WaitForSCManager() called\n");
1764 
1765     /* Try to open the existing event */
1766     hEvent = OpenEventW(SYNCHRONIZE, FALSE, SCM_START_EVENT);
1767     if (hEvent == NULL)
1768     {
1769         if (GetLastError() != ERROR_FILE_NOT_FOUND) return;
1770 
1771         /* Try to create a new event */
1772         hEvent = CreateEventW(NULL, TRUE, FALSE, SCM_START_EVENT);
1773         if (hEvent == NULL) return;
1774     }
1775 
1776     /* Wait for 3 minutes */
1777     WaitForSingleObject(hEvent, 180000);
1778     CloseHandle(hEvent);
1779 
1780     TRACE("ScmWaitForSCManager() done\n");
1781 }
1782 
1783 
1784 /**********************************************************************
1785  *  OpenSCManagerA
1786  *
1787  * @implemented
1788  */
1789 SC_HANDLE WINAPI
1790 OpenSCManagerA(LPCSTR lpMachineName,
1791                LPCSTR lpDatabaseName,
1792                DWORD dwDesiredAccess)
1793 {
1794     SC_HANDLE hScm = NULL;
1795     DWORD dwError;
1796 
1797     TRACE("OpenSCManagerA(%s, %s, %lx)\n",
1798            lpMachineName, lpDatabaseName, dwDesiredAccess);
1799 
1800     WaitForSCManager();
1801 
1802     RpcTryExcept
1803     {
1804         /* Call to services.exe using RPC */
1805         dwError = ROpenSCManagerA((LPSTR)lpMachineName,
1806                                   (LPSTR)lpDatabaseName,
1807                                   dwDesiredAccess,
1808                                   (SC_RPC_HANDLE *)&hScm);
1809     }
1810     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1811     {
1812         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1813     }
1814     RpcEndExcept;
1815 
1816     if (dwError != ERROR_SUCCESS)
1817     {
1818         TRACE("ROpenSCManagerA() failed (Error %lu)\n", dwError);
1819         SetLastError(dwError);
1820         return NULL;
1821     }
1822 
1823     TRACE("hScm = %p\n", hScm);
1824 
1825     return hScm;
1826 }
1827 
1828 
1829 /**********************************************************************
1830  *  OpenSCManagerW
1831  *
1832  * @implemented
1833  */
1834 SC_HANDLE WINAPI
1835 OpenSCManagerW(LPCWSTR lpMachineName,
1836                LPCWSTR lpDatabaseName,
1837                DWORD dwDesiredAccess)
1838 {
1839     SC_HANDLE hScm = NULL;
1840     DWORD dwError;
1841 
1842     TRACE("OpenSCManagerW(%S, %S, %lx)\n",
1843            lpMachineName, lpDatabaseName, dwDesiredAccess);
1844 
1845     WaitForSCManager();
1846 
1847     RpcTryExcept
1848     {
1849         /* Call to services.exe using RPC */
1850         dwError = ROpenSCManagerW((LPWSTR)lpMachineName,
1851                                   (LPWSTR)lpDatabaseName,
1852                                   dwDesiredAccess,
1853                                   (SC_RPC_HANDLE *)&hScm);
1854     }
1855     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1856     {
1857         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1858     }
1859     RpcEndExcept;
1860 
1861     if (dwError != ERROR_SUCCESS)
1862     {
1863         TRACE("ROpenSCManagerW() failed (Error %lu)\n", dwError);
1864         SetLastError(dwError);
1865         return NULL;
1866     }
1867 
1868     TRACE("hScm = %p\n", hScm);
1869 
1870     return hScm;
1871 }
1872 
1873 
1874 /**********************************************************************
1875  *  OpenServiceA
1876  *
1877  * @implemented
1878  */
1879 SC_HANDLE WINAPI
1880 OpenServiceA(SC_HANDLE hSCManager,
1881              LPCSTR lpServiceName,
1882              DWORD dwDesiredAccess)
1883 {
1884     SC_HANDLE hService = NULL;
1885     DWORD dwError;
1886 
1887     TRACE("OpenServiceA(%p, %s, %lx)\n",
1888            hSCManager, lpServiceName, dwDesiredAccess);
1889 
1890     if (!hSCManager)
1891     {
1892         SetLastError(ERROR_INVALID_HANDLE);
1893         return NULL;
1894     }
1895 
1896     RpcTryExcept
1897     {
1898         /* Call to services.exe using RPC */
1899         dwError = ROpenServiceA((SC_RPC_HANDLE)hSCManager,
1900                                 (LPSTR)lpServiceName,
1901                                 dwDesiredAccess,
1902                                 (SC_RPC_HANDLE *)&hService);
1903     }
1904     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1905     {
1906         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1907     }
1908     RpcEndExcept;
1909 
1910     SetLastError(dwError);
1911     if (dwError != ERROR_SUCCESS)
1912     {
1913         TRACE("ROpenServiceA() failed (Error %lu)\n", dwError);
1914         return NULL;
1915     }
1916 
1917     TRACE("hService = %p\n", hService);
1918 
1919     return hService;
1920 }
1921 
1922 
1923 /**********************************************************************
1924  *  OpenServiceW
1925  *
1926  * @implemented
1927  */
1928 SC_HANDLE WINAPI
1929 OpenServiceW(SC_HANDLE hSCManager,
1930              LPCWSTR lpServiceName,
1931              DWORD dwDesiredAccess)
1932 {
1933     SC_HANDLE hService = NULL;
1934     DWORD dwError;
1935 
1936     TRACE("OpenServiceW(%p, %S, %lx)\n",
1937            hSCManager, lpServiceName, dwDesiredAccess);
1938 
1939     if (!hSCManager)
1940     {
1941         SetLastError(ERROR_INVALID_HANDLE);
1942         return NULL;
1943     }
1944 
1945     RpcTryExcept
1946     {
1947         /* Call to services.exe using RPC */
1948         dwError = ROpenServiceW((SC_RPC_HANDLE)hSCManager,
1949                                 (LPWSTR)lpServiceName,
1950                                 dwDesiredAccess,
1951                                 (SC_RPC_HANDLE *)&hService);
1952     }
1953     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1954     {
1955         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1956     }
1957     RpcEndExcept;
1958 
1959     SetLastError(dwError);
1960     if (dwError != ERROR_SUCCESS)
1961     {
1962         TRACE("ROpenServiceW() failed (Error %lu)\n", dwError);
1963         return NULL;
1964     }
1965 
1966     TRACE("hService = %p\n", hService);
1967 
1968     return hService;
1969 }
1970 
1971 
1972 /**********************************************************************
1973  *  QueryServiceConfigA
1974  *
1975  * @implemented
1976  */
1977 BOOL WINAPI
1978 QueryServiceConfigA(SC_HANDLE hService,
1979                     LPQUERY_SERVICE_CONFIGA lpServiceConfig,
1980                     DWORD cbBufSize,
1981                     LPDWORD pcbBytesNeeded)
1982 {
1983     QUERY_SERVICE_CONFIGA ServiceConfig;
1984     LPQUERY_SERVICE_CONFIGA lpConfigPtr;
1985     DWORD dwBufferSize;
1986     DWORD dwError;
1987 
1988     TRACE("QueryServiceConfigA(%p, %p, %lu, %p)\n",
1989            hService, lpServiceConfig, cbBufSize, pcbBytesNeeded);
1990 
1991     if (lpServiceConfig == NULL ||
1992         cbBufSize < sizeof(QUERY_SERVICE_CONFIGA))
1993     {
1994         lpConfigPtr = &ServiceConfig;
1995         dwBufferSize = sizeof(QUERY_SERVICE_CONFIGA);
1996     }
1997     else
1998     {
1999         lpConfigPtr = lpServiceConfig;
2000         dwBufferSize = cbBufSize;
2001     }
2002 
2003     RpcTryExcept
2004     {
2005         /* Call to services.exe using RPC */
2006         dwError = RQueryServiceConfigA((SC_RPC_HANDLE)hService,
2007                                        (LPBYTE)lpConfigPtr,
2008                                        dwBufferSize,
2009                                        pcbBytesNeeded);
2010     }
2011     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2012     {
2013         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2014     }
2015     RpcEndExcept;
2016 
2017     if (dwError != ERROR_SUCCESS)
2018     {
2019         TRACE("RQueryServiceConfigA() failed (Error %lu)\n", dwError);
2020         SetLastError(dwError);
2021         return FALSE;
2022     }
2023 
2024     /* Adjust the pointers */
2025     if (lpConfigPtr->lpBinaryPathName)
2026         lpConfigPtr->lpBinaryPathName =
2027             (LPSTR)((ULONG_PTR)lpConfigPtr +
2028                     (ULONG_PTR)lpConfigPtr->lpBinaryPathName);
2029 
2030     if (lpConfigPtr->lpLoadOrderGroup)
2031         lpConfigPtr->lpLoadOrderGroup =
2032             (LPSTR)((ULONG_PTR)lpConfigPtr +
2033                     (ULONG_PTR)lpConfigPtr->lpLoadOrderGroup);
2034 
2035     if (lpConfigPtr->lpDependencies)
2036         lpConfigPtr->lpDependencies =
2037             (LPSTR)((ULONG_PTR)lpConfigPtr +
2038                     (ULONG_PTR)lpConfigPtr->lpDependencies);
2039 
2040     if (lpConfigPtr->lpServiceStartName)
2041         lpConfigPtr->lpServiceStartName =
2042             (LPSTR)((ULONG_PTR)lpConfigPtr +
2043                     (ULONG_PTR)lpConfigPtr->lpServiceStartName);
2044 
2045     if (lpConfigPtr->lpDisplayName)
2046         lpConfigPtr->lpDisplayName =
2047            (LPSTR)((ULONG_PTR)lpConfigPtr +
2048                    (ULONG_PTR)lpConfigPtr->lpDisplayName);
2049 
2050     TRACE("QueryServiceConfigA() done\n");
2051 
2052     return TRUE;
2053 }
2054 
2055 
2056 /**********************************************************************
2057  *  QueryServiceConfigW
2058  *
2059  * @implemented
2060  */
2061 BOOL WINAPI
2062 QueryServiceConfigW(SC_HANDLE hService,
2063                     LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2064                     DWORD cbBufSize,
2065                     LPDWORD pcbBytesNeeded)
2066 {
2067     QUERY_SERVICE_CONFIGW ServiceConfig;
2068     LPQUERY_SERVICE_CONFIGW lpConfigPtr;
2069     DWORD dwBufferSize;
2070     DWORD dwError;
2071 
2072     TRACE("QueryServiceConfigW(%p, %p, %lu, %p)\n",
2073            hService, lpServiceConfig, cbBufSize, pcbBytesNeeded);
2074 
2075     if (lpServiceConfig == NULL ||
2076         cbBufSize < sizeof(QUERY_SERVICE_CONFIGW))
2077     {
2078         lpConfigPtr = &ServiceConfig;
2079         dwBufferSize = sizeof(QUERY_SERVICE_CONFIGW);
2080     }
2081     else
2082     {
2083         lpConfigPtr = lpServiceConfig;
2084         dwBufferSize = cbBufSize;
2085     }
2086 
2087     RpcTryExcept
2088     {
2089         /* Call to services.exe using RPC */
2090         dwError = RQueryServiceConfigW((SC_RPC_HANDLE)hService,
2091                                        (LPBYTE)lpConfigPtr,
2092                                        dwBufferSize,
2093                                        pcbBytesNeeded);
2094     }
2095     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2096     {
2097         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2098     }
2099     RpcEndExcept;
2100 
2101     if (dwError != ERROR_SUCCESS)
2102     {
2103         TRACE("RQueryServiceConfigW() failed (Error %lu)\n", dwError);
2104         SetLastError(dwError);
2105         return FALSE;
2106     }
2107 
2108     /* Adjust the pointers */
2109     if (lpConfigPtr->lpBinaryPathName)
2110         lpConfigPtr->lpBinaryPathName =
2111             (LPWSTR)((ULONG_PTR)lpConfigPtr +
2112                      (ULONG_PTR)lpConfigPtr->lpBinaryPathName);
2113 
2114     if (lpConfigPtr->lpLoadOrderGroup)
2115         lpConfigPtr->lpLoadOrderGroup =
2116             (LPWSTR)((ULONG_PTR)lpConfigPtr +
2117                      (ULONG_PTR)lpConfigPtr->lpLoadOrderGroup);
2118 
2119     if (lpConfigPtr->lpDependencies)
2120         lpConfigPtr->lpDependencies =
2121             (LPWSTR)((ULONG_PTR)lpConfigPtr +
2122                      (ULONG_PTR)lpConfigPtr->lpDependencies);
2123 
2124     if (lpConfigPtr->lpServiceStartName)
2125         lpConfigPtr->lpServiceStartName =
2126             (LPWSTR)((ULONG_PTR)lpConfigPtr +
2127                      (ULONG_PTR)lpConfigPtr->lpServiceStartName);
2128 
2129     if (lpConfigPtr->lpDisplayName)
2130         lpConfigPtr->lpDisplayName =
2131            (LPWSTR)((ULONG_PTR)lpConfigPtr +
2132                     (ULONG_PTR)lpConfigPtr->lpDisplayName);
2133 
2134     TRACE("QueryServiceConfigW() done\n");
2135 
2136     return TRUE;
2137 }
2138 
2139 
2140 /**********************************************************************
2141  *  QueryServiceConfig2A
2142  *
2143  * @implemented
2144  */
2145 BOOL WINAPI
2146 QueryServiceConfig2A(SC_HANDLE hService,
2147                      DWORD dwInfoLevel,
2148                      LPBYTE lpBuffer,
2149                      DWORD cbBufSize,
2150                      LPDWORD pcbBytesNeeded)
2151 {
2152     SERVICE_DESCRIPTIONA ServiceDescription;
2153     SERVICE_FAILURE_ACTIONSA ServiceFailureActions;
2154     LPBYTE lpTempBuffer;
2155     BOOL bUseTempBuffer = FALSE;
2156     DWORD dwBufferSize;
2157     DWORD dwError;
2158 
2159     TRACE("QueryServiceConfig2A(hService %p, dwInfoLevel %lu, lpBuffer %p, cbBufSize %lu, pcbBytesNeeded %p)\n",
2160           hService, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
2161 
2162     lpTempBuffer = lpBuffer;
2163     dwBufferSize = cbBufSize;
2164 
2165     switch (dwInfoLevel)
2166     {
2167         case SERVICE_CONFIG_DESCRIPTION:
2168             if ((lpBuffer == NULL) || (cbBufSize < sizeof(SERVICE_DESCRIPTIONA)))
2169             {
2170                 lpTempBuffer = (LPBYTE)&ServiceDescription;
2171                 dwBufferSize = sizeof(SERVICE_DESCRIPTIONA);
2172                 bUseTempBuffer = TRUE;
2173             }
2174             break;
2175 
2176         case SERVICE_CONFIG_FAILURE_ACTIONS:
2177             if ((lpBuffer == NULL) || (cbBufSize < sizeof(SERVICE_FAILURE_ACTIONSA)))
2178             {
2179                 lpTempBuffer = (LPBYTE)&ServiceFailureActions;
2180                 dwBufferSize = sizeof(SERVICE_FAILURE_ACTIONSA);
2181                 bUseTempBuffer = TRUE;
2182             }
2183             break;
2184 
2185         default:
2186             WARN("Unknown info level 0x%lx\n", dwInfoLevel);
2187             SetLastError(ERROR_INVALID_LEVEL);
2188             return FALSE;
2189     }
2190 
2191     RpcTryExcept
2192     {
2193         /* Call to services.exe using RPC */
2194         dwError = RQueryServiceConfig2A((SC_RPC_HANDLE)hService,
2195                                         dwInfoLevel,
2196                                         lpTempBuffer,
2197                                         dwBufferSize,
2198                                         pcbBytesNeeded);
2199     }
2200     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2201     {
2202         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2203     }
2204     RpcEndExcept;
2205 
2206     if (dwError != ERROR_SUCCESS)
2207     {
2208         TRACE("RQueryServiceConfig2A() failed (Error %lu)\n", dwError);
2209         SetLastError(dwError);
2210         return FALSE;
2211     }
2212 
2213     if (bUseTempBuffer != FALSE)
2214     {
2215         TRACE("RQueryServiceConfig2A() returns ERROR_INSUFFICIENT_BUFFER\n");
2216         *pcbBytesNeeded = dwBufferSize;
2217         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2218         return FALSE;
2219     }
2220 
2221     switch (dwInfoLevel)
2222     {
2223         case SERVICE_CONFIG_DESCRIPTION:
2224             {
2225                 LPSERVICE_DESCRIPTIONA lpPtr = (LPSERVICE_DESCRIPTIONA)lpTempBuffer;
2226 
2227                 if (lpPtr->lpDescription != NULL)
2228                     lpPtr->lpDescription =
2229                         (LPSTR)((ULONG_PTR)lpPtr + (ULONG_PTR)lpPtr->lpDescription);
2230             }
2231             break;
2232 
2233         case SERVICE_CONFIG_FAILURE_ACTIONS:
2234             {
2235                 LPSERVICE_FAILURE_ACTIONSA lpPtr = (LPSERVICE_FAILURE_ACTIONSA)lpTempBuffer;
2236 
2237                 if (lpPtr->lpRebootMsg != NULL)
2238                     lpPtr->lpRebootMsg =
2239                         (LPSTR)((ULONG_PTR)lpPtr + (ULONG_PTR)lpPtr->lpRebootMsg);
2240 
2241                 if (lpPtr->lpCommand != NULL)
2242                     lpPtr->lpCommand =
2243                         (LPSTR)((ULONG_PTR)lpPtr + (ULONG_PTR)lpPtr->lpCommand);
2244 
2245                 if (lpPtr->lpsaActions != NULL)
2246                     lpPtr->lpsaActions =
2247                         (LPSC_ACTION)((ULONG_PTR)lpPtr + (ULONG_PTR)lpPtr->lpsaActions);
2248             }
2249             break;
2250     }
2251 
2252     TRACE("QueryServiceConfig2A() done\n");
2253 
2254     return TRUE;
2255 }
2256 
2257 
2258 /**********************************************************************
2259  *  QueryServiceConfig2W
2260  *
2261  * @implemented
2262  */
2263 BOOL WINAPI
2264 QueryServiceConfig2W(SC_HANDLE hService,
2265                      DWORD dwInfoLevel,
2266                      LPBYTE lpBuffer,
2267                      DWORD cbBufSize,
2268                      LPDWORD pcbBytesNeeded)
2269 {
2270     SERVICE_DESCRIPTIONW ServiceDescription;
2271     SERVICE_FAILURE_ACTIONSW ServiceFailureActions;
2272     LPBYTE lpTempBuffer;
2273     BOOL bUseTempBuffer = FALSE;
2274     DWORD dwBufferSize;
2275     DWORD dwError;
2276 
2277     TRACE("QueryServiceConfig2W(%p, %lu, %p, %lu, %p)\n",
2278            hService, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
2279 
2280     lpTempBuffer = lpBuffer;
2281     dwBufferSize = cbBufSize;
2282 
2283     switch (dwInfoLevel)
2284     {
2285         case SERVICE_CONFIG_DESCRIPTION:
2286             if ((lpBuffer == NULL) || (cbBufSize < sizeof(SERVICE_DESCRIPTIONW)))
2287             {
2288                 lpTempBuffer = (LPBYTE)&ServiceDescription;
2289                 dwBufferSize = sizeof(SERVICE_DESCRIPTIONW);
2290                 bUseTempBuffer = TRUE;
2291             }
2292             break;
2293 
2294         case SERVICE_CONFIG_FAILURE_ACTIONS:
2295             if ((lpBuffer == NULL) || (cbBufSize < sizeof(SERVICE_FAILURE_ACTIONSW)))
2296             {
2297                 lpTempBuffer = (LPBYTE)&ServiceFailureActions;
2298                 dwBufferSize = sizeof(SERVICE_FAILURE_ACTIONSW);
2299                 bUseTempBuffer = TRUE;
2300             }
2301             break;
2302 
2303         default:
2304             WARN("Unknown info level 0x%lx\n", dwInfoLevel);
2305             SetLastError(ERROR_INVALID_LEVEL);
2306             return FALSE;
2307     }
2308 
2309     RpcTryExcept
2310     {
2311         /* Call to services.exe using RPC */
2312         dwError = RQueryServiceConfig2W((SC_RPC_HANDLE)hService,
2313                                         dwInfoLevel,
2314                                         lpTempBuffer,
2315                                         dwBufferSize,
2316                                         pcbBytesNeeded);
2317     }
2318     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2319     {
2320         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2321     }
2322     RpcEndExcept;
2323 
2324     if (dwError != ERROR_SUCCESS)
2325     {
2326         TRACE("RQueryServiceConfig2W() failed (Error %lu)\n", dwError);
2327         SetLastError(dwError);
2328         return FALSE;
2329     }
2330 
2331     if (bUseTempBuffer != FALSE)
2332     {
2333         TRACE("RQueryServiceConfig2W() returns ERROR_INSUFFICIENT_BUFFER\n");
2334         *pcbBytesNeeded = dwBufferSize;
2335         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2336         return FALSE;
2337     }
2338 
2339     switch (dwInfoLevel)
2340     {
2341         case SERVICE_CONFIG_DESCRIPTION:
2342             {
2343                 LPSERVICE_DESCRIPTIONW lpPtr = (LPSERVICE_DESCRIPTIONW)lpTempBuffer;
2344 
2345                 if (lpPtr->lpDescription != NULL)
2346                     lpPtr->lpDescription =
2347                         (LPWSTR)((ULONG_PTR)lpPtr + (ULONG_PTR)lpPtr->lpDescription);
2348             }
2349             break;
2350 
2351         case SERVICE_CONFIG_FAILURE_ACTIONS:
2352             {
2353                 LPSERVICE_FAILURE_ACTIONSW lpPtr = (LPSERVICE_FAILURE_ACTIONSW)lpTempBuffer;
2354 
2355                 if (lpPtr->lpRebootMsg != NULL)
2356                     lpPtr->lpRebootMsg =
2357                         (LPWSTR)((ULONG_PTR)lpPtr + (ULONG_PTR)lpPtr->lpRebootMsg);
2358 
2359                 if (lpPtr->lpCommand != NULL)
2360                     lpPtr->lpCommand =
2361                         (LPWSTR)((ULONG_PTR)lpPtr + (ULONG_PTR)lpPtr->lpCommand);
2362 
2363                 if (lpPtr->lpsaActions != NULL)
2364                     lpPtr->lpsaActions =
2365                         (LPSC_ACTION)((ULONG_PTR)lpPtr + (ULONG_PTR)lpPtr->lpsaActions);
2366             }
2367             break;
2368     }
2369 
2370     TRACE("QueryServiceConfig2W() done\n");
2371 
2372     return TRUE;
2373 }
2374 
2375 
2376 /**********************************************************************
2377  *  QueryServiceLockStatusA
2378  *
2379  * @implemented
2380  */
2381 BOOL WINAPI
2382 QueryServiceLockStatusA(SC_HANDLE hSCManager,
2383                         LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2384                         DWORD cbBufSize,
2385                         LPDWORD pcbBytesNeeded)
2386 {
2387     QUERY_SERVICE_LOCK_STATUSA LockStatus;
2388     LPQUERY_SERVICE_LOCK_STATUSA lpStatusPtr;
2389     DWORD dwBufferSize;
2390     DWORD dwError;
2391 
2392     TRACE("QueryServiceLockStatusA() called\n");
2393 
2394     if (lpLockStatus == NULL || cbBufSize < sizeof(QUERY_SERVICE_LOCK_STATUSA))
2395     {
2396         lpStatusPtr = &LockStatus;
2397         dwBufferSize = sizeof(QUERY_SERVICE_LOCK_STATUSA);
2398     }
2399     else
2400     {
2401         lpStatusPtr = lpLockStatus;
2402         dwBufferSize = cbBufSize;
2403     }
2404 
2405     RpcTryExcept
2406     {
2407         /* Call to services.exe using RPC */
2408         dwError = RQueryServiceLockStatusA((SC_RPC_HANDLE)hSCManager,
2409                                            (LPBYTE)lpStatusPtr,
2410                                            dwBufferSize,
2411                                            pcbBytesNeeded);
2412     }
2413     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2414     {
2415         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2416     }
2417     RpcEndExcept;
2418 
2419     if (dwError != ERROR_SUCCESS)
2420     {
2421         TRACE("RQueryServiceLockStatusA() failed (Error %lu)\n", dwError);
2422         SetLastError(dwError);
2423         return FALSE;
2424     }
2425 
2426     if (lpStatusPtr->lpLockOwner != NULL)
2427     {
2428         lpStatusPtr->lpLockOwner =
2429             (LPSTR)((ULONG_PTR)lpStatusPtr + (ULONG_PTR)lpStatusPtr->lpLockOwner);
2430     }
2431 
2432     TRACE("QueryServiceLockStatusA() done\n");
2433 
2434     return TRUE;
2435 }
2436 
2437 
2438 /**********************************************************************
2439  *  QueryServiceLockStatusW
2440  *
2441  * @implemented
2442  */
2443 BOOL WINAPI
2444 QueryServiceLockStatusW(SC_HANDLE hSCManager,
2445                         LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2446                         DWORD cbBufSize,
2447                         LPDWORD pcbBytesNeeded)
2448 {
2449     QUERY_SERVICE_LOCK_STATUSW LockStatus;
2450     LPQUERY_SERVICE_LOCK_STATUSW lpStatusPtr;
2451     DWORD dwBufferSize;
2452     DWORD dwError;
2453 
2454     TRACE("QueryServiceLockStatusW() called\n");
2455 
2456     if (lpLockStatus == NULL || cbBufSize < sizeof(QUERY_SERVICE_LOCK_STATUSW))
2457     {
2458         lpStatusPtr = &LockStatus;
2459         dwBufferSize = sizeof(QUERY_SERVICE_LOCK_STATUSW);
2460     }
2461     else
2462     {
2463         lpStatusPtr = lpLockStatus;
2464         dwBufferSize = cbBufSize;
2465     }
2466 
2467     RpcTryExcept
2468     {
2469         /* Call to services.exe using RPC */
2470         dwError = RQueryServiceLockStatusW((SC_RPC_HANDLE)hSCManager,
2471                                            (LPBYTE)lpStatusPtr,
2472                                            dwBufferSize,
2473                                            pcbBytesNeeded);
2474     }
2475     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2476     {
2477         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2478     }
2479     RpcEndExcept;
2480 
2481     if (dwError != ERROR_SUCCESS)
2482     {
2483         TRACE("RQueryServiceLockStatusW() failed (Error %lu)\n", dwError);
2484         SetLastError(dwError);
2485         return FALSE;
2486     }
2487 
2488     if (lpStatusPtr->lpLockOwner != NULL)
2489     {
2490         lpStatusPtr->lpLockOwner =
2491             (LPWSTR)((ULONG_PTR)lpStatusPtr + (ULONG_PTR)lpStatusPtr->lpLockOwner);
2492     }
2493 
2494     TRACE("QueryServiceLockStatusW() done\n");
2495 
2496     return TRUE;
2497 }
2498 
2499 
2500 /**********************************************************************
2501  *  QueryServiceObjectSecurity
2502  *
2503  * @implemented
2504  */
2505 BOOL WINAPI
2506 QueryServiceObjectSecurity(SC_HANDLE hService,
2507                            SECURITY_INFORMATION dwSecurityInformation,
2508                            PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2509                            DWORD cbBufSize,
2510                            LPDWORD pcbBytesNeeded)
2511 {
2512     DWORD dwError;
2513 
2514     TRACE("QueryServiceObjectSecurity(%p, %lu, %p)\n",
2515            hService, dwSecurityInformation, lpSecurityDescriptor);
2516 
2517     RpcTryExcept
2518     {
2519         /* Call to services.exe using RPC */
2520         dwError = RQueryServiceObjectSecurity((SC_RPC_HANDLE)hService,
2521                                               dwSecurityInformation,
2522                                               (LPBYTE)lpSecurityDescriptor,
2523                                               cbBufSize,
2524                                               pcbBytesNeeded);
2525     }
2526     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2527     {
2528         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2529     }
2530     RpcEndExcept;
2531 
2532     if (dwError != ERROR_SUCCESS)
2533     {
2534         TRACE("QueryServiceObjectSecurity() failed (Error %lu)\n", dwError);
2535         SetLastError(dwError);
2536         return FALSE;
2537     }
2538 
2539     return TRUE;
2540 }
2541 
2542 /**********************************************************************
2543  *  SetServiceObjectSecurity
2544  *
2545  * @implemented
2546  */
2547 BOOL WINAPI
2548 SetServiceObjectSecurity(SC_HANDLE hService,
2549                          SECURITY_INFORMATION dwSecurityInformation,
2550                          PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2551 {
2552     PSECURITY_DESCRIPTOR SelfRelativeSD = NULL;
2553     ULONG Length;
2554     NTSTATUS Status;
2555     DWORD dwError;
2556 
2557     Length = 0;
2558     Status = RtlMakeSelfRelativeSD(lpSecurityDescriptor,
2559                                    SelfRelativeSD,
2560                                    &Length);
2561     if (Status != STATUS_BUFFER_TOO_SMALL)
2562     {
2563         SetLastError(ERROR_INVALID_PARAMETER);
2564         return FALSE;
2565     }
2566 
2567     SelfRelativeSD = HeapAlloc(GetProcessHeap(), 0, Length);
2568     if (SelfRelativeSD == NULL)
2569     {
2570         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2571         return FALSE;
2572     }
2573 
2574     Status = RtlMakeSelfRelativeSD(lpSecurityDescriptor,
2575                                    SelfRelativeSD,
2576                                    &Length);
2577     if (!NT_SUCCESS(Status))
2578     {
2579         HeapFree(GetProcessHeap(), 0, SelfRelativeSD);
2580         SetLastError(RtlNtStatusToDosError(Status));
2581         return FALSE;
2582     }
2583 
2584     RpcTryExcept
2585     {
2586         /* Call to services.exe using RPC */
2587         dwError = RSetServiceObjectSecurity((SC_RPC_HANDLE)hService,
2588                                             dwSecurityInformation,
2589                                             (LPBYTE)SelfRelativeSD,
2590                                             Length);
2591     }
2592     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2593     {
2594         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2595     }
2596     RpcEndExcept;
2597 
2598     HeapFree(GetProcessHeap(), 0, SelfRelativeSD);
2599 
2600     if (dwError != ERROR_SUCCESS)
2601     {
2602         TRACE("RServiceObjectSecurity() failed (Error %lu)\n", dwError);
2603         SetLastError(dwError);
2604         return FALSE;
2605     }
2606 
2607     return TRUE;
2608 }
2609 
2610 
2611 /**********************************************************************
2612  *  QueryServiceStatus
2613  *
2614  * @implemented
2615  */
2616 BOOL WINAPI
2617 QueryServiceStatus(SC_HANDLE hService,
2618                    LPSERVICE_STATUS lpServiceStatus)
2619 {
2620     DWORD dwError;
2621 
2622     TRACE("QueryServiceStatus(%p, %p)\n",
2623            hService, lpServiceStatus);
2624 
2625     if (!hService)
2626     {
2627         SetLastError(ERROR_INVALID_HANDLE);
2628         return FALSE;
2629     }
2630 
2631     RpcTryExcept
2632     {
2633         /* Call to services.exe using RPC */
2634         dwError = RQueryServiceStatus((SC_RPC_HANDLE)hService,
2635                                       lpServiceStatus);
2636     }
2637     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2638     {
2639         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2640     }
2641     RpcEndExcept;
2642 
2643     if (dwError != ERROR_SUCCESS)
2644     {
2645         TRACE("RQueryServiceStatus() failed (Error %lu)\n", dwError);
2646         SetLastError(dwError);
2647         return FALSE;
2648     }
2649 
2650     return TRUE;
2651 }
2652 
2653 
2654 /**********************************************************************
2655  *  QueryServiceStatusEx
2656  *
2657  * @implemented
2658  */
2659 BOOL WINAPI
2660 QueryServiceStatusEx(SC_HANDLE hService,
2661                      SC_STATUS_TYPE InfoLevel,
2662                      LPBYTE lpBuffer,
2663                      DWORD cbBufSize,
2664                      LPDWORD pcbBytesNeeded)
2665 {
2666     DWORD dwError;
2667 
2668     TRACE("QueryServiceStatusEx() called\n");
2669 
2670     if (InfoLevel != SC_STATUS_PROCESS_INFO)
2671     {
2672         SetLastError(ERROR_INVALID_LEVEL);
2673         return FALSE;
2674     }
2675 
2676     if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
2677     {
2678         *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
2679         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2680         return FALSE;
2681     }
2682 
2683     RpcTryExcept
2684     {
2685         /* Call to services.exe using RPC */
2686         dwError = RQueryServiceStatusEx((SC_RPC_HANDLE)hService,
2687                                         InfoLevel,
2688                                         lpBuffer,
2689                                         cbBufSize,
2690                                         pcbBytesNeeded);
2691     }
2692     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2693     {
2694         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2695     }
2696     RpcEndExcept;
2697 
2698     if (dwError != ERROR_SUCCESS)
2699     {
2700         TRACE("RQueryServiceStatusEx() failed (Error %lu)\n", dwError);
2701         SetLastError(dwError);
2702         return FALSE;
2703     }
2704 
2705     return TRUE;
2706 }
2707 
2708 
2709 /**********************************************************************
2710  *  StartServiceA
2711  *
2712  * @implemented
2713  */
2714 BOOL WINAPI
2715 StartServiceA(SC_HANDLE hService,
2716               DWORD dwNumServiceArgs,
2717               LPCSTR *lpServiceArgVectors)
2718 {
2719     DWORD dwError;
2720 
2721     RpcTryExcept
2722     {
2723         dwError = RStartServiceA((SC_RPC_HANDLE)hService,
2724                                  dwNumServiceArgs,
2725                                  (LPSTRING_PTRSA)lpServiceArgVectors);
2726     }
2727     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2728     {
2729         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2730     }
2731     RpcEndExcept;
2732 
2733     if (dwError != ERROR_SUCCESS)
2734     {
2735         ERR("RStartServiceA() failed (Error %lu)\n", dwError);
2736         SetLastError(dwError);
2737         return FALSE;
2738     }
2739 
2740     return TRUE;
2741 }
2742 
2743 
2744 /**********************************************************************
2745  *  StartServiceW
2746  *
2747  * @implemented
2748  */
2749 BOOL WINAPI
2750 StartServiceW(SC_HANDLE hService,
2751               DWORD dwNumServiceArgs,
2752               LPCWSTR *lpServiceArgVectors)
2753 {
2754     DWORD dwError;
2755 
2756     RpcTryExcept
2757     {
2758         dwError = RStartServiceW((SC_RPC_HANDLE)hService,
2759                                  dwNumServiceArgs,
2760                                  (LPSTRING_PTRSW)lpServiceArgVectors);
2761     }
2762     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2763     {
2764         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2765     }
2766     RpcEndExcept;
2767 
2768     if (dwError != ERROR_SUCCESS)
2769     {
2770         ERR("RStartServiceW() failed (Error %lu)\n", dwError);
2771         SetLastError(dwError);
2772         return FALSE;
2773     }
2774 
2775     return TRUE;
2776 }
2777 
2778 
2779 /**********************************************************************
2780  *  UnlockServiceDatabase
2781  *
2782  * @implemented
2783  */
2784 BOOL WINAPI
2785 UnlockServiceDatabase(SC_LOCK ScLock)
2786 {
2787     DWORD dwError;
2788 
2789     TRACE("UnlockServiceDatabase(%x)\n", ScLock);
2790 
2791     RpcTryExcept
2792     {
2793         /* Call to services.exe using RPC */
2794         dwError = RUnlockServiceDatabase((LPSC_RPC_LOCK)&ScLock);
2795     }
2796     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2797     {
2798         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2799     }
2800     RpcEndExcept;
2801 
2802     if (dwError == ERROR_INVALID_HANDLE)
2803         dwError = ERROR_INVALID_SERVICE_LOCK;
2804 
2805     if (dwError != ERROR_SUCCESS)
2806     {
2807         TRACE("RUnlockServiceDatabase() failed (Error %lu)\n", dwError);
2808         SetLastError(dwError);
2809         return FALSE;
2810     }
2811 
2812     return TRUE;
2813 }
2814 
2815 
2816 /**********************************************************************
2817  *  NotifyBootConfigStatus
2818  *
2819  * @implemented
2820  */
2821 BOOL WINAPI
2822 NotifyBootConfigStatus(BOOL BootAcceptable)
2823 {
2824     DWORD dwError;
2825 
2826     TRACE("NotifyBootConfigStatus()\n");
2827 
2828     RpcTryExcept
2829     {
2830         /* Call to services.exe using RPC */
2831         dwError = RNotifyBootConfigStatus(NULL,
2832                                           BootAcceptable);
2833     }
2834     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2835     {
2836         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2837     }
2838     RpcEndExcept;
2839 
2840     if (dwError != ERROR_SUCCESS)
2841     {
2842         TRACE("NotifyBootConfigStatus() failed (Error %lu)\n", dwError);
2843         SetLastError(dwError);
2844         return FALSE;
2845     }
2846 
2847     return TRUE;
2848 }
2849 
2850 /* EOF */
2851