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