2 * PROJECT: ReactOS Service Control Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/system/services/rpcserver.c
5 * PURPOSE: RPC server interface for the advapi32 calls
6 * COPYRIGHT: Copyright 2005-2006 Eric Kohl
7 * Copyright 2006-2007 Hervé Poussineau <hpoussin@reactos.org>
8 * Copyright 2007 Ged Murphy <gedmurphy@reactos.org>
11 /* INCLUDES ****************************************************************/
20 /* GLOBALS *****************************************************************/
22 #define MANAGER_TAG 0x72674D68 /* 'hMgr' */
23 #define SERVICE_TAG 0x63765368 /* 'hSvc' */
24 #define INVALID_TAG 0xAABBCCDD
26 typedef struct _SCMGR_HANDLE
33 typedef struct _MANAGER_HANDLE
36 WCHAR DatabaseName
[1];
37 } MANAGER_HANDLE
, *PMANAGER_HANDLE
;
40 typedef struct _SERVICE_HANDLE
43 PSERVICE ServiceEntry
;
44 } SERVICE_HANDLE
, *PSERVICE_HANDLE
;
47 #define SC_MANAGER_READ \
48 (STANDARD_RIGHTS_READ | \
49 SC_MANAGER_QUERY_LOCK_STATUS | \
50 SC_MANAGER_ENUMERATE_SERVICE)
52 #define SC_MANAGER_WRITE \
53 (STANDARD_RIGHTS_WRITE | \
54 SC_MANAGER_MODIFY_BOOT_CONFIG | \
55 SC_MANAGER_CREATE_SERVICE)
57 #define SC_MANAGER_EXECUTE \
58 (STANDARD_RIGHTS_EXECUTE | \
60 SC_MANAGER_ENUMERATE_SERVICE | \
61 SC_MANAGER_CONNECT | \
62 SC_MANAGER_CREATE_SERVICE)
65 #define SERVICE_READ \
66 (STANDARD_RIGHTS_READ | \
67 SERVICE_INTERROGATE | \
68 SERVICE_ENUMERATE_DEPENDENTS | \
69 SERVICE_QUERY_STATUS | \
72 #define SERVICE_WRITE \
73 (STANDARD_RIGHTS_WRITE | \
74 SERVICE_CHANGE_CONFIG)
76 #define SERVICE_EXECUTE \
77 (STANDARD_RIGHTS_EXECUTE | \
78 SERVICE_USER_DEFINED_CONTROL | \
79 SERVICE_PAUSE_CONTINUE | \
83 #define TAG_ARRAY_SIZE 32
85 /* VARIABLES ***************************************************************/
87 static GENERIC_MAPPING
88 ScmManagerMapping
= {SC_MANAGER_READ
,
91 SC_MANAGER_ALL_ACCESS
};
93 static GENERIC_MAPPING
94 ScmServiceMapping
= {SERVICE_READ
,
100 /* FUNCTIONS ***************************************************************/
103 ScmStartRpcServer(VOID
)
107 DPRINT("ScmStartRpcServer() called\n");
109 Status
= RpcServerUseProtseqEpW(L
"ncacn_np",
113 if (Status
!= RPC_S_OK
)
115 DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status
);
119 Status
= RpcServerRegisterIf(svcctl_v2_0_s_ifspec
,
122 if (Status
!= RPC_S_OK
)
124 DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status
);
128 Status
= RpcServerListen(1, 20, TRUE
);
129 if (Status
!= RPC_S_OK
)
131 DPRINT1("RpcServerListen() failed (Status %lx)\n", Status
);
135 DPRINT("ScmStartRpcServer() done\n");
140 ScmCreateManagerHandle(LPWSTR lpDatabaseName
,
145 if (lpDatabaseName
== NULL
)
146 lpDatabaseName
= SERVICES_ACTIVE_DATABASEW
;
148 if (_wcsicmp(lpDatabaseName
, SERVICES_FAILED_DATABASEW
) == 0)
150 DPRINT("Database %S, does not exist\n", lpDatabaseName
);
151 return ERROR_DATABASE_DOES_NOT_EXIST
;
153 else if (_wcsicmp(lpDatabaseName
, SERVICES_ACTIVE_DATABASEW
) != 0)
155 DPRINT("Invalid Database name %S.\n", lpDatabaseName
);
156 return ERROR_INVALID_NAME
;
159 Ptr
= HeapAlloc(GetProcessHeap(),
161 FIELD_OFFSET(MANAGER_HANDLE
, DatabaseName
[wcslen(lpDatabaseName
) + 1]));
163 return ERROR_NOT_ENOUGH_MEMORY
;
165 Ptr
->Handle
.Tag
= MANAGER_TAG
;
167 wcscpy(Ptr
->DatabaseName
, lpDatabaseName
);
169 *Handle
= (SC_HANDLE
)Ptr
;
171 return ERROR_SUCCESS
;
176 ScmCreateServiceHandle(PSERVICE lpServiceEntry
,
181 Ptr
= HeapAlloc(GetProcessHeap(),
183 sizeof(SERVICE_HANDLE
));
185 return ERROR_NOT_ENOUGH_MEMORY
;
187 Ptr
->Handle
.Tag
= SERVICE_TAG
;
189 Ptr
->ServiceEntry
= lpServiceEntry
;
191 *Handle
= (SC_HANDLE
)Ptr
;
193 return ERROR_SUCCESS
;
197 static PMANAGER_HANDLE
198 ScmGetServiceManagerFromHandle(SC_RPC_HANDLE Handle
)
200 PMANAGER_HANDLE pManager
= NULL
;
204 if (((PMANAGER_HANDLE
)Handle
)->Handle
.Tag
== MANAGER_TAG
)
205 pManager
= (PMANAGER_HANDLE
)Handle
;
207 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
209 DPRINT1("Exception: Invalid Service Manager handle!\n");
217 static PSERVICE_HANDLE
218 ScmGetServiceFromHandle(SC_RPC_HANDLE Handle
)
220 PSERVICE_HANDLE pService
= NULL
;
224 if (((PSERVICE_HANDLE
)Handle
)->Handle
.Tag
== SERVICE_TAG
)
225 pService
= (PSERVICE_HANDLE
)Handle
;
227 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
229 DPRINT1("Exception: Invalid Service handle!\n");
238 ScmCheckAccess(SC_HANDLE Handle
,
239 DWORD dwDesiredAccess
)
241 PMANAGER_HANDLE hMgr
;
243 hMgr
= (PMANAGER_HANDLE
)Handle
;
244 if (hMgr
->Handle
.Tag
== MANAGER_TAG
)
246 RtlMapGenericMask(&dwDesiredAccess
,
249 hMgr
->Handle
.DesiredAccess
= dwDesiredAccess
;
251 return ERROR_SUCCESS
;
253 else if (hMgr
->Handle
.Tag
== SERVICE_TAG
)
255 RtlMapGenericMask(&dwDesiredAccess
,
258 hMgr
->Handle
.DesiredAccess
= dwDesiredAccess
;
260 return ERROR_SUCCESS
;
263 return ERROR_INVALID_HANDLE
;
268 ScmAssignNewTag(PSERVICE lpService
)
272 DWORD dwGroupTagCount
= 0;
273 PDWORD pdwGroupTags
= NULL
;
275 DWORD dwTagUsedBase
= 1;
276 BOOLEAN TagUsed
[TAG_ARRAY_SIZE
];
280 PLIST_ENTRY ServiceEntry
;
281 PSERVICE CurrentService
;
283 ASSERT(lpService
!= NULL
);
284 ASSERT(lpService
->lpGroup
!= NULL
);
286 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
287 L
"System\\CurrentControlSet\\Control\\GroupOrderList",
292 if (dwError
!= ERROR_SUCCESS
)
295 /* query value length */
297 dwError
= RegQueryValueExW(hKey
,
298 lpService
->lpGroup
->szGroupName
,
304 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_MORE_DATA
)
307 pdwGroupTags
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, cbDataSize
);
310 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
314 dwError
= RegQueryValueExW(hKey
,
315 lpService
->lpGroup
->szGroupName
,
318 (LPBYTE
)pdwGroupTags
,
321 if (dwError
!= ERROR_SUCCESS
)
324 if (cbDataSize
< sizeof(pdwGroupTags
[0]))
327 dwGroupTagCount
= min(pdwGroupTags
[0], cbDataSize
/ sizeof(pdwGroupTags
[0]) - 1);
332 /* mark all tags as unused */
333 for (i
= 0; i
< TAG_ARRAY_SIZE
; i
++)
336 /* mark tags in GroupOrderList as used */
337 for (i
= 1; i
<= dwGroupTagCount
; i
++)
339 nTagOffset
= pdwGroupTags
[i
] - dwTagUsedBase
;
340 if (nTagOffset
>= 0 && nTagOffset
< TAG_ARRAY_SIZE
)
341 TagUsed
[nTagOffset
] = TRUE
;
344 /* mark tags in service list as used */
345 ServiceEntry
= lpService
->ServiceListEntry
.Flink
;
346 while (ServiceEntry
!= &lpService
->ServiceListEntry
)
348 ASSERT(ServiceEntry
!= NULL
);
349 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
350 if (CurrentService
->lpGroup
== lpService
->lpGroup
)
352 nTagOffset
= CurrentService
->dwTag
- dwTagUsedBase
;
353 if (nTagOffset
>= 0 && nTagOffset
< TAG_ARRAY_SIZE
)
354 TagUsed
[nTagOffset
] = TRUE
;
357 ServiceEntry
= ServiceEntry
->Flink
;
360 /* find unused tag, if any */
361 for (i
= 0; i
< TAG_ARRAY_SIZE
; i
++)
365 dwFreeTag
= dwTagUsedBase
+ i
;
370 dwTagUsedBase
+= TAG_ARRAY_SIZE
;
371 } while (!dwFreeTag
);
375 HeapFree(GetProcessHeap(), 0, pdwGroupTags
);
382 lpService
->dwTag
= dwFreeTag
;
383 DPRINT("Assigning new tag %lu to service %S in group %S\n",
384 lpService
->dwTag
, lpService
->lpServiceName
, lpService
->lpGroup
->szGroupName
);
385 dwError
= ERROR_SUCCESS
;
389 DPRINT1("Failed to assign new tag to service %S, error=%lu\n",
390 lpService
->lpServiceName
, dwError
);
397 /* Create a path suitable for the bootloader out of the full path */
399 ScmConvertToBootPathName(wchar_t *CanonName
, wchar_t **RelativeName
)
401 SIZE_T ServiceNameLen
, ExpandedLen
;
405 UNICODE_STRING NtPathName
, SystemRoot
, LinkTarget
;
406 OBJECT_ATTRIBUTES ObjectAttributes
;
408 HANDLE SymbolicLinkHandle
;
410 DPRINT("ScmConvertToBootPathName %S\n", CanonName
);
413 return ERROR_INVALID_PARAMETER
;
415 *RelativeName
= NULL
;
417 ServiceNameLen
= wcslen(CanonName
);
419 /* First check, if it's already good */
420 if (ServiceNameLen
> 12 &&
421 !_wcsnicmp(L
"\\SystemRoot\\", CanonName
, 12))
423 *RelativeName
= HeapAlloc(GetProcessHeap(),
425 (ServiceNameLen
+ 1) * sizeof(WCHAR
));
426 if (*RelativeName
== NULL
)
428 DPRINT("Error allocating memory for boot driver name!\n");
429 return ERROR_NOT_ENOUGH_MEMORY
;
433 wcscpy(*RelativeName
, CanonName
);
435 DPRINT("Bootdriver name %S\n", *RelativeName
);
436 return ERROR_SUCCESS
;
439 /* If it has %SystemRoot% prefix, substitute it to \System*/
440 if (ServiceNameLen
> 13 &&
441 !_wcsnicmp(L
"%SystemRoot%\\", CanonName
, 13))
443 /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */
444 *RelativeName
= HeapAlloc(GetProcessHeap(),
446 ServiceNameLen
* sizeof(WCHAR
));
448 if (*RelativeName
== NULL
)
450 DPRINT("Error allocating memory for boot driver name!\n");
451 return ERROR_NOT_ENOUGH_MEMORY
;
455 wcscpy(*RelativeName
, L
"\\SystemRoot\\");
456 wcscat(*RelativeName
, CanonName
+ 13);
458 DPRINT("Bootdriver name %S\n", *RelativeName
);
459 return ERROR_SUCCESS
;
462 /* Get buffer size needed for expanding env strings */
463 BufferSize
= ExpandEnvironmentStringsW(L
"%SystemRoot%\\", &Dest
, 1);
467 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
468 return ERROR_INVALID_ENVIRONMENT
;
471 /* Allocate memory, since the size is known now */
472 Expanded
= HeapAlloc(GetProcessHeap(),
474 (BufferSize
+ 1) * sizeof(WCHAR
));
477 DPRINT("Error allocating memory for boot driver name!\n");
478 return ERROR_NOT_ENOUGH_MEMORY
;
482 if (ExpandEnvironmentStringsW(L
"%SystemRoot%\\", Expanded
, BufferSize
) >
485 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
486 HeapFree(GetProcessHeap(), 0, Expanded
);
487 return ERROR_NOT_ENOUGH_MEMORY
;
490 /* Convert to NT-style path */
491 if (!RtlDosPathNameToNtPathName_U(Expanded
, &NtPathName
, NULL
, NULL
))
493 DPRINT("Error during a call to RtlDosPathNameToNtPathName_U()\n");
494 return ERROR_INVALID_ENVIRONMENT
;
497 DPRINT("Converted to NT-style %wZ\n", &NtPathName
);
499 /* No need to keep the dos-path anymore */
500 HeapFree(GetProcessHeap(), 0, Expanded
);
502 /* Copy it to the allocated place */
503 Expanded
= HeapAlloc(GetProcessHeap(),
505 NtPathName
.Length
+ sizeof(UNICODE_NULL
));
508 DPRINT("Error allocating memory for boot driver name!\n");
509 RtlFreeUnicodeString(&NtPathName
);
510 return ERROR_NOT_ENOUGH_MEMORY
;
513 ExpandedLen
= NtPathName
.Length
/ sizeof(WCHAR
);
514 wcsncpy(Expanded
, NtPathName
.Buffer
, ExpandedLen
);
515 Expanded
[ExpandedLen
] = UNICODE_NULL
;
516 RtlFreeUnicodeString(&NtPathName
);
518 if (ServiceNameLen
> ExpandedLen
&&
519 !_wcsnicmp(Expanded
, CanonName
, ExpandedLen
))
521 HeapFree(GetProcessHeap(), 0, Expanded
);
523 /* Only \SystemRoot\ is missing */
524 *RelativeName
= HeapAlloc(GetProcessHeap(),
526 (ServiceNameLen
- ExpandedLen
) * sizeof(WCHAR
) + 13*sizeof(WCHAR
));
527 if (*RelativeName
== NULL
)
529 DPRINT("Error allocating memory for boot driver name!\n");
530 return ERROR_NOT_ENOUGH_MEMORY
;
533 wcscpy(*RelativeName
, L
"\\SystemRoot\\");
534 wcscat(*RelativeName
, CanonName
+ ExpandedLen
);
536 return ERROR_SUCCESS
;
539 /* No longer need this */
540 HeapFree(GetProcessHeap(), 0, Expanded
);
542 /* The most complex case starts here */
543 RtlInitUnicodeString(&SystemRoot
, L
"\\SystemRoot");
544 InitializeObjectAttributes(&ObjectAttributes
,
546 OBJ_CASE_INSENSITIVE
,
550 /* Open this symlink */
551 Status
= NtOpenSymbolicLinkObject(&SymbolicLinkHandle
, SYMBOLIC_LINK_QUERY
, &ObjectAttributes
);
552 if (NT_SUCCESS(Status
))
554 DPRINT("Opened symbolic link object\n");
556 RtlInitEmptyUnicodeString(&LinkTarget
, NULL
, 0);
557 Status
= NtQuerySymbolicLinkObject(SymbolicLinkHandle
, &LinkTarget
, &BufferSize
);
558 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_TOO_SMALL
)
560 /* Check if required buffer size is sane */
561 if (BufferSize
> UNICODE_STRING_MAX_BYTES
- sizeof(UNICODE_NULL
))
563 DPRINT("Too large buffer required\n");
565 NtClose(SymbolicLinkHandle
);
566 return ERROR_NOT_ENOUGH_MEMORY
;
569 /* Alloc the string */
570 LinkTarget
.Length
= (USHORT
)BufferSize
;
571 LinkTarget
.MaximumLength
= LinkTarget
.Length
+ sizeof(UNICODE_NULL
);
572 LinkTarget
.Buffer
= HeapAlloc(GetProcessHeap(),
574 LinkTarget
.MaximumLength
);
575 if (!LinkTarget
.Buffer
)
577 DPRINT("Unable to alloc buffer\n");
578 NtClose(SymbolicLinkHandle
);
579 return ERROR_NOT_ENOUGH_MEMORY
;
582 /* Do a real query now */
583 Status
= NtQuerySymbolicLinkObject(SymbolicLinkHandle
, &LinkTarget
, &BufferSize
);
584 NtClose(SymbolicLinkHandle
);
585 if (NT_SUCCESS(Status
))
587 DPRINT("LinkTarget: %wZ\n", &LinkTarget
);
589 ExpandedLen
= LinkTarget
.Length
/ sizeof(WCHAR
);
590 if ((ServiceNameLen
> ExpandedLen
) &&
591 !_wcsnicmp(LinkTarget
.Buffer
, CanonName
, ExpandedLen
))
593 *RelativeName
= HeapAlloc(GetProcessHeap(),
595 (ServiceNameLen
- ExpandedLen
) * sizeof(WCHAR
) + 13*sizeof(WCHAR
));
597 if (*RelativeName
== NULL
)
599 DPRINT("Unable to alloc buffer\n");
600 return ERROR_NOT_ENOUGH_MEMORY
;
603 /* Copy it over, substituting the first part
605 wcscpy(*RelativeName
, L
"\\SystemRoot\\");
606 wcscat(*RelativeName
, CanonName
+ExpandedLen
+1);
609 return ERROR_SUCCESS
;
613 return ERROR_INVALID_PARAMETER
;
618 DPRINT("Error, Status = %08X\n", Status
);
619 return ERROR_INVALID_PARAMETER
;
624 DPRINT("Error, Status = %08X\n", Status
);
625 NtClose(SymbolicLinkHandle
);
626 return ERROR_INVALID_PARAMETER
;
632 DPRINT("Error, Status = %08X\n", Status
);
633 return ERROR_INVALID_PARAMETER
;
639 ScmCanonDriverImagePath(DWORD dwStartType
,
640 const wchar_t *lpServiceName
,
641 wchar_t **lpCanonName
)
644 SIZE_T ServiceNameLen
;
645 UNICODE_STRING NtServiceName
;
647 const WCHAR
*SourceName
= lpServiceName
;
649 /* Calculate the length of the service's name */
650 ServiceNameLen
= wcslen(lpServiceName
);
652 /* 12 is wcslen(L"\\SystemRoot\\") */
653 if (ServiceNameLen
> 12 &&
654 !_wcsnicmp(L
"\\SystemRoot\\", lpServiceName
, 12))
656 /* SystemRoot prefix is already included */
657 *lpCanonName
= HeapAlloc(GetProcessHeap(),
659 (ServiceNameLen
+ 1) * sizeof(WCHAR
));
661 if (*lpCanonName
== NULL
)
663 DPRINT("Error allocating memory for canonized service name!\n");
664 return ERROR_NOT_ENOUGH_MEMORY
;
667 /* If it's a boot-time driver, it must be systemroot relative */
668 if (dwStartType
== SERVICE_BOOT_START
)
672 wcscpy(*lpCanonName
, SourceName
);
674 DPRINT("Canonicalized name %S\n", *lpCanonName
);
678 /* Check if it has %SystemRoot% (len=13) */
679 if (ServiceNameLen
> 13 &&
680 !_wcsnicmp(L
"%SystemRoot%\\", lpServiceName
, 13))
682 /* Substitute %SystemRoot% with \\SystemRoot\\ */
683 *lpCanonName
= HeapAlloc(GetProcessHeap(),
685 (ServiceNameLen
+ 1) * sizeof(WCHAR
));
687 if (*lpCanonName
== NULL
)
689 DPRINT("Error allocating memory for canonized service name!\n");
690 return ERROR_NOT_ENOUGH_MEMORY
;
693 /* If it's a boot-time driver, it must be systemroot relative */
694 if (dwStartType
== SERVICE_BOOT_START
)
695 wcscpy(*lpCanonName
, L
"\\SystemRoot\\");
697 wcscat(*lpCanonName
, lpServiceName
+ 13);
699 DPRINT("Canonicalized name %S\n", *lpCanonName
);
703 /* Check if it's a relative path name */
704 if (lpServiceName
[0] != L
'\\' && lpServiceName
[1] != L
':')
706 *lpCanonName
= HeapAlloc(GetProcessHeap(),
708 (ServiceNameLen
+ 1) * sizeof(WCHAR
));
710 if (*lpCanonName
== NULL
)
712 DPRINT("Error allocating memory for canonized service name!\n");
713 return ERROR_NOT_ENOUGH_MEMORY
;
716 /* Just copy it over without changing */
717 wcscpy(*lpCanonName
, lpServiceName
);
722 /* It seems to be a DOS path, convert it */
723 if (!RtlDosPathNameToNtPathName_U(lpServiceName
, &NtServiceName
, NULL
, NULL
))
725 DPRINT("RtlDosPathNameToNtPathName_U() failed!\n");
726 return ERROR_INVALID_PARAMETER
;
729 *lpCanonName
= HeapAlloc(GetProcessHeap(),
731 NtServiceName
.Length
+ sizeof(WCHAR
));
733 if (*lpCanonName
== NULL
)
735 DPRINT("Error allocating memory for canonized service name!\n");
736 RtlFreeUnicodeString(&NtServiceName
);
737 return ERROR_NOT_ENOUGH_MEMORY
;
740 /* Copy the string */
741 wcsncpy(*lpCanonName
, NtServiceName
.Buffer
, NtServiceName
.Length
/ sizeof(WCHAR
));
743 /* The unicode string is not needed anymore */
744 RtlFreeUnicodeString(&NtServiceName
);
746 if (dwStartType
!= SERVICE_BOOT_START
)
748 DPRINT("Canonicalized name %S\n", *lpCanonName
);
752 /* The service is boot-started, so must be relative */
753 Result
= ScmConvertToBootPathName(*lpCanonName
, &RelativeName
);
756 /* There is a problem, free name and return */
757 HeapFree(GetProcessHeap(), 0, *lpCanonName
);
758 DPRINT("Error converting named!\n");
762 ASSERT(RelativeName
);
764 /* Copy that string */
765 wcscpy(*lpCanonName
, RelativeName
+ 12);
767 /* Free the allocated buffer */
768 HeapFree(GetProcessHeap(), 0, RelativeName
);
770 DPRINT("Canonicalized name %S\n", *lpCanonName
);
777 /* Internal recursive function */
778 /* Need to search for every dependency on every service */
780 Int_EnumDependentServicesW(HKEY hServicesKey
,
782 DWORD dwServiceState
,
783 PSERVICE
*lpServices
,
784 LPDWORD pcbBytesNeeded
,
785 LPDWORD lpServicesReturned
)
787 DWORD dwError
= ERROR_SUCCESS
;
788 WCHAR szNameBuf
[MAX_PATH
];
789 WCHAR szValueBuf
[MAX_PATH
];
790 WCHAR
*lpszNameBuf
= szNameBuf
;
791 WCHAR
*lpszValueBuf
= szValueBuf
;
795 PSERVICE lpCurrentService
;
796 HKEY hServiceEnumKey
;
797 DWORD dwCurrentServiceState
= SERVICE_ACTIVE
;
798 DWORD dwDependServiceStrPtr
= 0;
799 DWORD dwRequiredSize
= 0;
801 /* Get the number of service keys */
802 dwError
= RegQueryInfoKeyW(hServicesKey
,
814 if (dwError
!= ERROR_SUCCESS
)
816 DPRINT("ERROR! Unable to get number of services keys.\n");
820 /* Iterate the service keys to see if another service depends on the this service */
821 for (dwIteration
= 0; dwIteration
< dwNumSubKeys
; dwIteration
++)
824 dwError
= RegEnumKeyExW(hServicesKey
,
832 if (dwError
!= ERROR_SUCCESS
)
835 /* Open the Service key */
836 dwError
= RegOpenKeyExW(hServicesKey
,
841 if (dwError
!= ERROR_SUCCESS
)
846 /* Check for the DependOnService Value */
847 dwError
= RegQueryValueExW(hServiceEnumKey
,
851 (LPBYTE
)lpszValueBuf
,
854 /* FIXME: Handle load order. */
856 /* If the service found has a DependOnService value */
857 if (dwError
== ERROR_SUCCESS
)
859 dwDependServiceStrPtr
= 0;
861 /* Can be more than one Dependencies in the DependOnService string */
862 while (wcslen(lpszValueBuf
+ dwDependServiceStrPtr
) > 0)
864 if (_wcsicmp(lpszValueBuf
+ dwDependServiceStrPtr
, lpService
->lpServiceName
) == 0)
866 /* Get the current enumed service pointer */
867 lpCurrentService
= ScmGetServiceEntryByName(lpszNameBuf
);
869 /* Check for valid Service */
870 if (!lpCurrentService
)
872 /* This should never happen! */
873 DPRINT("This should not happen at this point, report to Developer\n");
874 return ERROR_NOT_FOUND
;
877 /* Determine state the service is in */
878 if (lpCurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
879 dwCurrentServiceState
= SERVICE_INACTIVE
;
881 /* If the ServiceState matches that requested or searching for SERVICE_STATE_ALL */
882 if ((dwCurrentServiceState
== dwServiceState
) ||
883 (dwServiceState
== SERVICE_STATE_ALL
))
885 /* Calculate the required size */
886 dwRequiredSize
+= sizeof(SERVICE_STATUS
);
887 dwRequiredSize
+= (DWORD
)((wcslen(lpCurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
));
888 dwRequiredSize
+= (DWORD
)((wcslen(lpCurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
890 /* Add the size for service name and display name pointers */
891 dwRequiredSize
+= (2 * sizeof(PVOID
));
893 /* increase the BytesNeeded size */
894 *pcbBytesNeeded
= *pcbBytesNeeded
+ dwRequiredSize
;
896 /* Don't fill callers buffer yet, as MSDN read that the last service with dependency
899 /* Recursive call to check for its dependencies */
900 Int_EnumDependentServicesW(hServicesKey
,
907 /* If the lpServices is valid set the service pointer */
909 lpServices
[*lpServicesReturned
] = lpCurrentService
;
911 *lpServicesReturned
= *lpServicesReturned
+ 1;
915 dwDependServiceStrPtr
+= (DWORD
)(wcslen(lpszValueBuf
+ dwDependServiceStrPtr
) + 1);
918 else if (*pcbBytesNeeded
)
920 dwError
= ERROR_SUCCESS
;
923 RegCloseKey(hServiceEnumKey
);
931 DWORD
RCloseServiceHandle(
932 LPSC_RPC_HANDLE hSCObject
)
934 PMANAGER_HANDLE hManager
;
935 PSERVICE_HANDLE hService
;
939 DWORD pcbBytesNeeded
= 0;
940 DWORD dwServicesReturned
= 0;
942 DPRINT("RCloseServiceHandle() called\n");
944 DPRINT("hSCObject = %p\n", *hSCObject
);
947 return ERROR_INVALID_HANDLE
;
949 hManager
= ScmGetServiceManagerFromHandle(*hSCObject
);
950 hService
= ScmGetServiceFromHandle(*hSCObject
);
952 if (hManager
!= NULL
)
954 DPRINT("Found manager handle\n");
956 /* Make sure we don't access stale memory if someone tries to use this handle again. */
957 hManager
->Handle
.Tag
= INVALID_TAG
;
959 HeapFree(GetProcessHeap(), 0, hManager
);
964 DPRINT("RCloseServiceHandle() done\n");
965 return ERROR_SUCCESS
;
967 else if (hService
!= NULL
)
969 DPRINT("Found service handle\n");
971 /* Lock the service database exlusively */
972 ScmLockDatabaseExclusive();
974 /* Get the pointer to the service record */
975 lpService
= hService
->ServiceEntry
;
977 /* Make sure we don't access stale memory if someone tries to use this handle again. */
978 hService
->Handle
.Tag
= INVALID_TAG
;
980 /* Free the handle */
981 HeapFree(GetProcessHeap(), 0, hService
);
984 ASSERT(lpService
->dwRefCount
> 0);
986 lpService
->dwRefCount
--;
987 DPRINT("CloseServiceHandle - lpService->dwRefCount %u\n",
988 lpService
->dwRefCount
);
990 if (lpService
->dwRefCount
== 0)
992 /* If this service has been marked for deletion */
993 if (lpService
->bDeleted
)
995 /* Open the Services Reg key */
996 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
997 L
"System\\CurrentControlSet\\Services",
999 KEY_SET_VALUE
| KEY_READ
,
1001 if (dwError
!= ERROR_SUCCESS
)
1003 DPRINT("Failed to open services key\n");
1004 ScmUnlockDatabase();
1008 /* Call the internal function with NULL, just to get bytes we need */
1009 Int_EnumDependentServicesW(hServicesKey
,
1014 &dwServicesReturned
);
1016 /* if pcbBytesNeeded returned a value then there are services running that are dependent on this service */
1019 DPRINT("Deletion failed due to running dependencies.\n");
1020 RegCloseKey(hServicesKey
);
1021 ScmUnlockDatabase();
1022 return ERROR_SUCCESS
;
1025 /* There are no references and no runnning dependencies,
1026 it is now safe to delete the service */
1028 /* Delete the Service Key */
1029 dwError
= RegDeleteKeyW(hServicesKey
,
1030 lpService
->lpServiceName
);
1032 RegCloseKey(hServicesKey
);
1034 if (dwError
!= ERROR_SUCCESS
)
1036 DPRINT("Failed to Delete the Service Registry key\n");
1037 ScmUnlockDatabase();
1041 /* Delete the Service */
1042 ScmDeleteServiceRecord(lpService
);
1046 ScmUnlockDatabase();
1050 DPRINT("RCloseServiceHandle() done\n");
1051 return ERROR_SUCCESS
;
1054 DPRINT("Invalid handle tag (Tag %lx)\n", hManager
->Handle
.Tag
);
1056 return ERROR_INVALID_HANDLE
;
1061 DWORD
RControlService(
1062 SC_RPC_HANDLE hService
,
1064 LPSERVICE_STATUS lpServiceStatus
)
1066 PSERVICE_HANDLE hSvc
;
1068 ACCESS_MASK DesiredAccess
;
1069 DWORD dwError
= ERROR_SUCCESS
;
1070 DWORD pcbBytesNeeded
= 0;
1071 DWORD dwServicesReturned
= 0;
1072 DWORD dwControlsAccepted
;
1073 DWORD dwCurrentState
;
1074 HKEY hServicesKey
= NULL
;
1075 LPCWSTR lpLogStrings
[2];
1076 WCHAR szLogBuffer
[80];
1079 DPRINT("RControlService() called\n");
1082 return ERROR_SHUTDOWN_IN_PROGRESS
;
1084 /* Check the service handle */
1085 hSvc
= ScmGetServiceFromHandle(hService
);
1088 DPRINT1("Invalid service handle!\n");
1089 return ERROR_INVALID_HANDLE
;
1092 /* Check the service entry point */
1093 lpService
= hSvc
->ServiceEntry
;
1094 if (lpService
== NULL
)
1096 DPRINT1("lpService == NULL!\n");
1097 return ERROR_INVALID_HANDLE
;
1100 /* Check access rights */
1103 case SERVICE_CONTROL_STOP
:
1104 DesiredAccess
= SERVICE_STOP
;
1107 case SERVICE_CONTROL_PAUSE
:
1108 case SERVICE_CONTROL_CONTINUE
:
1109 DesiredAccess
= SERVICE_PAUSE_CONTINUE
;
1112 case SERVICE_CONTROL_INTERROGATE
:
1113 DesiredAccess
= SERVICE_INTERROGATE
;
1117 if (dwControl
>= 128 && dwControl
<= 255)
1118 DesiredAccess
= SERVICE_USER_DEFINED_CONTROL
;
1120 return ERROR_INVALID_PARAMETER
;
1124 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1126 return ERROR_ACCESS_DENIED
;
1128 /* Return the current service status information */
1129 RtlCopyMemory(lpServiceStatus
,
1131 sizeof(SERVICE_STATUS
));
1133 if (dwControl
== SERVICE_CONTROL_STOP
)
1135 /* Check if the service has dependencies running as windows
1136 doesn't stop a service that does */
1138 /* Open the Services Reg key */
1139 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1140 L
"System\\CurrentControlSet\\Services",
1144 if (dwError
!= ERROR_SUCCESS
)
1146 DPRINT("Failed to open services key\n");
1150 /* Call the internal function with NULL, just to get bytes we need */
1151 Int_EnumDependentServicesW(hServicesKey
,
1156 &dwServicesReturned
);
1158 RegCloseKey(hServicesKey
);
1160 /* If pcbBytesNeeded is not zero then there are services running that
1161 are dependent on this service */
1162 if (pcbBytesNeeded
!= 0)
1164 DPRINT("Service has running dependencies. Failed to stop service.\n");
1165 return ERROR_DEPENDENT_SERVICES_RUNNING
;
1169 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
1171 /* Send control code to the driver */
1172 dwError
= ScmControlDriver(lpService
,
1178 dwControlsAccepted
= lpService
->Status
.dwControlsAccepted
;
1179 dwCurrentState
= lpService
->Status
.dwCurrentState
;
1181 /* Return ERROR_SERVICE_NOT_ACTIVE if the service has not been started */
1182 if (lpService
->lpImage
== NULL
|| dwCurrentState
== SERVICE_STOPPED
)
1183 return ERROR_SERVICE_NOT_ACTIVE
;
1185 /* Check the current state before sending a control request */
1186 switch (dwCurrentState
)
1188 case SERVICE_STOP_PENDING
:
1189 case SERVICE_STOPPED
:
1190 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL
;
1192 case SERVICE_START_PENDING
:
1195 case SERVICE_CONTROL_STOP
:
1198 case SERVICE_CONTROL_INTERROGATE
:
1199 RtlCopyMemory(lpServiceStatus
,
1201 sizeof(SERVICE_STATUS
));
1202 return ERROR_SUCCESS
;
1205 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL
;
1210 /* Check if the control code is acceptable to the service */
1213 case SERVICE_CONTROL_STOP
:
1214 if ((dwControlsAccepted
& SERVICE_ACCEPT_STOP
) == 0)
1215 return ERROR_INVALID_SERVICE_CONTROL
;
1218 case SERVICE_CONTROL_PAUSE
:
1219 case SERVICE_CONTROL_CONTINUE
:
1220 if ((dwControlsAccepted
& SERVICE_ACCEPT_PAUSE_CONTINUE
) == 0)
1221 return ERROR_INVALID_SERVICE_CONTROL
;
1225 /* Send control code to the service */
1226 dwError
= ScmControlService(lpService
,
1229 /* Return service status information */
1230 RtlCopyMemory(lpServiceStatus
,
1232 sizeof(SERVICE_STATUS
));
1235 if (dwError
== ERROR_SUCCESS
)
1237 if (dwControl
== SERVICE_CONTROL_STOP
||
1238 dwControl
== SERVICE_CONTROL_PAUSE
||
1239 dwControl
== SERVICE_CONTROL_CONTINUE
)
1241 /* Log a sucessful send control */
1245 case SERVICE_CONTROL_STOP
:
1246 uID
= IDS_SERVICE_STOP
;
1249 case SERVICE_CONTROL_PAUSE
:
1250 uID
= IDS_SERVICE_PAUSE
;
1253 case SERVICE_CONTROL_CONTINUE
:
1254 uID
= IDS_SERVICE_RESUME
;
1257 LoadStringW(GetModuleHandle(NULL
), uID
, szLogBuffer
, 80);
1259 lpLogStrings
[0] = lpService
->lpDisplayName
;
1260 lpLogStrings
[1] = szLogBuffer
;
1262 ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS
,
1263 EVENTLOG_INFORMATION_TYPE
,
1274 DWORD
RDeleteService(
1275 SC_RPC_HANDLE hService
)
1277 PSERVICE_HANDLE hSvc
;
1281 DPRINT("RDeleteService() called\n");
1284 return ERROR_SHUTDOWN_IN_PROGRESS
;
1286 hSvc
= ScmGetServiceFromHandle(hService
);
1289 DPRINT1("Invalid service handle!\n");
1290 return ERROR_INVALID_HANDLE
;
1293 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1295 return ERROR_ACCESS_DENIED
;
1297 lpService
= hSvc
->ServiceEntry
;
1298 if (lpService
== NULL
)
1300 DPRINT("lpService == NULL!\n");
1301 return ERROR_INVALID_HANDLE
;
1304 /* Lock the service database exclusively */
1305 ScmLockDatabaseExclusive();
1307 if (lpService
->bDeleted
)
1309 DPRINT("The service has already been marked for delete!\n");
1310 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
1314 /* Mark service for delete */
1315 lpService
->bDeleted
= TRUE
;
1317 dwError
= ScmMarkServiceForDelete(lpService
);
1320 /* Unlock the service database */
1321 ScmUnlockDatabase();
1323 DPRINT("RDeleteService() done\n");
1330 DWORD
RLockServiceDatabase(
1331 SC_RPC_HANDLE hSCManager
,
1332 LPSC_RPC_LOCK lpLock
)
1334 PMANAGER_HANDLE hMgr
;
1336 DPRINT("RLockServiceDatabase() called\n");
1340 hMgr
= ScmGetServiceManagerFromHandle(hSCManager
);
1343 DPRINT1("Invalid service manager handle!\n");
1344 return ERROR_INVALID_HANDLE
;
1347 if (!RtlAreAllAccessesGranted(hMgr
->Handle
.DesiredAccess
,
1349 return ERROR_ACCESS_DENIED
;
1351 return ScmAcquireServiceStartLock(FALSE
, lpLock
);
1356 DWORD
RQueryServiceObjectSecurity(
1357 SC_RPC_HANDLE hService
,
1358 SECURITY_INFORMATION dwSecurityInformation
,
1359 LPBYTE lpSecurityDescriptor
,
1361 LPBOUNDED_DWORD_256K pcbBytesNeeded
)
1363 PSERVICE_HANDLE hSvc
;
1365 ULONG DesiredAccess
= 0;
1367 DWORD dwBytesNeeded
;
1370 DPRINT("RQueryServiceObjectSecurity() called\n");
1372 hSvc
= ScmGetServiceFromHandle(hService
);
1375 DPRINT1("Invalid service handle!\n");
1376 return ERROR_INVALID_HANDLE
;
1379 if (dwSecurityInformation
& (DACL_SECURITY_INFORMATION
|
1380 GROUP_SECURITY_INFORMATION
|
1381 OWNER_SECURITY_INFORMATION
))
1382 DesiredAccess
|= READ_CONTROL
;
1384 if (dwSecurityInformation
& SACL_SECURITY_INFORMATION
)
1385 DesiredAccess
|= ACCESS_SYSTEM_SECURITY
;
1387 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1390 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1391 return ERROR_ACCESS_DENIED
;
1394 lpService
= hSvc
->ServiceEntry
;
1395 if (lpService
== NULL
)
1397 DPRINT("lpService == NULL!\n");
1398 return ERROR_INVALID_HANDLE
;
1401 /* Lock the service database */
1402 ScmLockDatabaseShared();
1404 /* Retrieve the security descriptor */
1405 Status
= RtlQuerySecurityObject(lpService
->pSecurityDescriptor
,
1406 dwSecurityInformation
,
1407 (PSECURITY_DESCRIPTOR
)lpSecurityDescriptor
,
1411 /* Unlock the service database */
1412 ScmUnlockDatabase();
1414 if (NT_SUCCESS(Status
))
1416 *pcbBytesNeeded
= dwBytesNeeded
;
1417 dwError
= STATUS_SUCCESS
;
1419 else if (Status
== STATUS_BUFFER_TOO_SMALL
)
1421 *pcbBytesNeeded
= dwBytesNeeded
;
1422 dwError
= ERROR_INSUFFICIENT_BUFFER
;
1424 else if (Status
== STATUS_BAD_DESCRIPTOR_FORMAT
)
1426 dwError
= ERROR_GEN_FAILURE
;
1430 dwError
= RtlNtStatusToDosError(Status
);
1438 DWORD
RSetServiceObjectSecurity(
1439 SC_RPC_HANDLE hService
,
1440 DWORD dwSecurityInformation
,
1441 LPBYTE lpSecurityDescriptor
,
1442 DWORD dwSecuityDescriptorSize
)
1444 PSERVICE_HANDLE hSvc
;
1446 ULONG DesiredAccess
= 0;
1447 HANDLE hToken
= NULL
;
1448 HKEY hServiceKey
= NULL
;
1449 BOOL bDatabaseLocked
= FALSE
;
1453 DPRINT("RSetServiceObjectSecurity() called\n");
1455 hSvc
= ScmGetServiceFromHandle(hService
);
1458 DPRINT1("Invalid service handle!\n");
1459 return ERROR_INVALID_HANDLE
;
1462 if (dwSecurityInformation
== 0 ||
1463 dwSecurityInformation
& ~(OWNER_SECURITY_INFORMATION
| GROUP_SECURITY_INFORMATION
1464 | DACL_SECURITY_INFORMATION
| SACL_SECURITY_INFORMATION
))
1465 return ERROR_INVALID_PARAMETER
;
1467 if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR
)lpSecurityDescriptor
))
1468 return ERROR_INVALID_PARAMETER
;
1470 if (dwSecurityInformation
& SACL_SECURITY_INFORMATION
)
1471 DesiredAccess
|= ACCESS_SYSTEM_SECURITY
;
1473 if (dwSecurityInformation
& DACL_SECURITY_INFORMATION
)
1474 DesiredAccess
|= WRITE_DAC
;
1476 if (dwSecurityInformation
& (OWNER_SECURITY_INFORMATION
| GROUP_SECURITY_INFORMATION
))
1477 DesiredAccess
|= WRITE_OWNER
;
1479 if ((dwSecurityInformation
& OWNER_SECURITY_INFORMATION
) &&
1480 (((PISECURITY_DESCRIPTOR
)lpSecurityDescriptor
)->Owner
== NULL
))
1481 return ERROR_INVALID_PARAMETER
;
1483 if ((dwSecurityInformation
& GROUP_SECURITY_INFORMATION
) &&
1484 (((PISECURITY_DESCRIPTOR
)lpSecurityDescriptor
)->Group
== NULL
))
1485 return ERROR_INVALID_PARAMETER
;
1487 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1490 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1491 return ERROR_ACCESS_DENIED
;
1494 lpService
= hSvc
->ServiceEntry
;
1495 if (lpService
== NULL
)
1497 DPRINT1("lpService == NULL!\n");
1498 return ERROR_INVALID_HANDLE
;
1501 if (lpService
->bDeleted
)
1502 return ERROR_SERVICE_MARKED_FOR_DELETE
;
1505 RpcImpersonateClient(NULL
);
1507 Status
= NtOpenThreadToken(NtCurrentThread(),
1511 if (!NT_SUCCESS(Status
))
1512 return RtlNtStatusToDosError(Status
);
1517 /* Build the new security descriptor */
1518 Status
= RtlSetSecurityObject(dwSecurityInformation
,
1519 (PSECURITY_DESCRIPTOR
)lpSecurityDescriptor
,
1520 &lpService
->pSecurityDescriptor
,
1523 if (!NT_SUCCESS(Status
))
1525 dwError
= RtlNtStatusToDosError(Status
);
1529 /* Lock the service database exclusive */
1530 ScmLockDatabaseExclusive();
1531 bDatabaseLocked
= TRUE
;
1533 /* Open the service key */
1534 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
1535 READ_CONTROL
| KEY_CREATE_SUB_KEY
| KEY_SET_VALUE
,
1537 if (dwError
!= ERROR_SUCCESS
)
1540 /* Store the new security descriptor */
1541 dwError
= ScmWriteSecurityDescriptor(hServiceKey
,
1542 lpService
->pSecurityDescriptor
);
1544 RegFlushKey(hServiceKey
);
1547 if (hServiceKey
!= NULL
)
1548 RegCloseKey(hServiceKey
);
1550 /* Unlock service database */
1551 if (bDatabaseLocked
== TRUE
)
1552 ScmUnlockDatabase();
1557 DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError
);
1564 DWORD
RQueryServiceStatus(
1565 SC_RPC_HANDLE hService
,
1566 LPSERVICE_STATUS lpServiceStatus
)
1568 PSERVICE_HANDLE hSvc
;
1571 DPRINT("RQueryServiceStatus() called\n");
1574 return ERROR_SHUTDOWN_IN_PROGRESS
;
1576 hSvc
= ScmGetServiceFromHandle(hService
);
1579 DPRINT1("Invalid service handle!\n");
1580 return ERROR_INVALID_HANDLE
;
1583 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1584 SERVICE_QUERY_STATUS
))
1586 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1587 return ERROR_ACCESS_DENIED
;
1590 lpService
= hSvc
->ServiceEntry
;
1591 if (lpService
== NULL
)
1593 DPRINT("lpService == NULL!\n");
1594 return ERROR_INVALID_HANDLE
;
1597 /* Lock the service database shared */
1598 ScmLockDatabaseShared();
1600 /* Return service status information */
1601 RtlCopyMemory(lpServiceStatus
,
1603 sizeof(SERVICE_STATUS
));
1605 /* Unlock the service database */
1606 ScmUnlockDatabase();
1608 return ERROR_SUCCESS
;
1613 ScmIsValidServiceState(DWORD dwCurrentState
)
1615 switch (dwCurrentState
)
1617 case SERVICE_STOPPED
:
1618 case SERVICE_START_PENDING
:
1619 case SERVICE_STOP_PENDING
:
1620 case SERVICE_RUNNING
:
1621 case SERVICE_CONTINUE_PENDING
:
1622 case SERVICE_PAUSE_PENDING
:
1623 case SERVICE_PAUSED
:
1633 DWORD
RSetServiceStatus(
1634 RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
1635 LPSERVICE_STATUS lpServiceStatus
)
1638 DWORD dwPreviousState
;
1639 DWORD dwPreviousType
;
1640 LPCWSTR lpLogStrings
[2];
1641 WCHAR szLogBuffer
[80];
1644 DPRINT("RSetServiceStatus() called\n");
1645 DPRINT("hServiceStatus = %lu\n", hServiceStatus
);
1646 DPRINT("dwServiceType = 0x%lx\n", lpServiceStatus
->dwServiceType
);
1647 DPRINT("dwCurrentState = %lu\n", lpServiceStatus
->dwCurrentState
);
1648 DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus
->dwControlsAccepted
);
1649 DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus
->dwWin32ExitCode
);
1650 DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus
->dwServiceSpecificExitCode
);
1651 DPRINT("dwCheckPoint = %lu\n", lpServiceStatus
->dwCheckPoint
);
1652 DPRINT("dwWaitHint = %lu\n", lpServiceStatus
->dwWaitHint
);
1654 if (hServiceStatus
== 0)
1656 DPRINT("hServiceStatus == NULL!\n");
1657 return ERROR_INVALID_HANDLE
;
1660 lpService
= (PSERVICE
)hServiceStatus
;
1662 /* Check current state */
1663 if (!ScmIsValidServiceState(lpServiceStatus
->dwCurrentState
))
1665 DPRINT("Invalid service state!\n");
1666 return ERROR_INVALID_DATA
;
1669 /* Check service type */
1670 if (!(lpServiceStatus
->dwServiceType
& SERVICE_WIN32
) &&
1671 (lpServiceStatus
->dwServiceType
& SERVICE_DRIVER
))
1673 DPRINT("Invalid service type!\n");
1674 return ERROR_INVALID_DATA
;
1677 /* Check accepted controls */
1678 if (lpServiceStatus
->dwControlsAccepted
& ~0xFF)
1680 DPRINT("Invalid controls accepted!\n");
1681 return ERROR_INVALID_DATA
;
1684 /* Set the wait hint and check point only if the service is in a pending state,
1685 otherwise they should be 0 */
1686 if (lpServiceStatus
->dwCurrentState
== SERVICE_STOPPED
||
1687 lpServiceStatus
->dwCurrentState
== SERVICE_PAUSED
||
1688 lpServiceStatus
->dwCurrentState
== SERVICE_RUNNING
)
1690 lpServiceStatus
->dwWaitHint
= 0;
1691 lpServiceStatus
->dwCheckPoint
= 0;
1694 /* Lock the service database exclusively */
1695 ScmLockDatabaseExclusive();
1697 /* Save the current service state */
1698 dwPreviousState
= lpService
->Status
.dwCurrentState
;
1700 /* Save the current service type */
1701 dwPreviousType
= lpService
->Status
.dwServiceType
;
1703 /* Update the service status */
1704 RtlCopyMemory(&lpService
->Status
,
1706 sizeof(SERVICE_STATUS
));
1708 /* Restore the previous service type */
1709 lpService
->Status
.dwServiceType
= dwPreviousType
;
1711 /* Unlock the service database */
1712 ScmUnlockDatabase();
1714 if ((lpServiceStatus
->dwCurrentState
== SERVICE_STOPPED
) &&
1715 (dwPreviousState
!= SERVICE_STOPPED
) &&
1716 (lpServiceStatus
->dwWin32ExitCode
!= ERROR_SUCCESS
))
1718 /* Log a failed service stop */
1719 swprintf(szLogBuffer
, L
"%lu", lpServiceStatus
->dwWin32ExitCode
);
1720 lpLogStrings
[0] = lpService
->lpDisplayName
;
1721 lpLogStrings
[1] = szLogBuffer
;
1723 ScmLogEvent(EVENT_SERVICE_EXIT_FAILED
,
1724 EVENTLOG_ERROR_TYPE
,
1728 else if (lpServiceStatus
->dwCurrentState
!= dwPreviousState
&&
1729 (lpServiceStatus
->dwCurrentState
== SERVICE_STOPPED
||
1730 lpServiceStatus
->dwCurrentState
== SERVICE_RUNNING
||
1731 lpServiceStatus
->dwCurrentState
== SERVICE_PAUSED
))
1733 /* Log a successful service status change */
1734 switch(lpServiceStatus
->dwCurrentState
)
1736 case SERVICE_STOPPED
:
1737 uID
= IDS_SERVICE_STOPPED
;
1740 case SERVICE_RUNNING
:
1741 uID
= IDS_SERVICE_RUNNING
;
1744 case SERVICE_PAUSED
:
1745 uID
= IDS_SERVICE_PAUSED
;
1749 LoadStringW(GetModuleHandle(NULL
), uID
, szLogBuffer
, 80);
1750 lpLogStrings
[0] = lpService
->lpDisplayName
;
1751 lpLogStrings
[1] = szLogBuffer
;
1753 ScmLogEvent(EVENT_SERVICE_STATUS_SUCCESS
,
1754 EVENTLOG_INFORMATION_TYPE
,
1759 DPRINT("Set %S to %lu\n", lpService
->lpDisplayName
, lpService
->Status
.dwCurrentState
);
1760 DPRINT("RSetServiceStatus() done\n");
1762 return ERROR_SUCCESS
;
1767 DWORD
RUnlockServiceDatabase(
1770 DPRINT("RUnlockServiceDatabase(%p)\n", Lock
);
1771 return ScmReleaseServiceStartLock(Lock
);
1776 DWORD
RNotifyBootConfigStatus(
1777 SVCCTL_HANDLEW lpMachineName
,
1778 DWORD BootAcceptable
)
1780 DPRINT1("RNotifyBootConfigStatus(%p %lu) called\n", lpMachineName
, BootAcceptable
);
1781 return ERROR_SUCCESS
;
1784 // return ERROR_CALL_NOT_IMPLEMENTED;
1789 DWORD
RI_ScSetServiceBitsW(
1790 RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
1791 DWORD dwServiceBits
,
1793 int bUpdateImmediately
,
1797 return ERROR_CALL_NOT_IMPLEMENTED
;
1802 DWORD
RChangeServiceConfigW(
1803 SC_RPC_HANDLE hService
,
1804 DWORD dwServiceType
,
1806 DWORD dwErrorControl
,
1807 LPWSTR lpBinaryPathName
,
1808 LPWSTR lpLoadOrderGroup
,
1810 LPBYTE lpDependencies
,
1812 LPWSTR lpServiceStartName
,
1815 LPWSTR lpDisplayName
)
1817 DWORD dwError
= ERROR_SUCCESS
;
1818 PSERVICE_HANDLE hSvc
;
1819 PSERVICE lpService
= NULL
;
1820 HKEY hServiceKey
= NULL
;
1821 LPWSTR lpDisplayNameW
= NULL
;
1822 LPWSTR lpImagePathW
= NULL
;
1824 DPRINT("RChangeServiceConfigW() called\n");
1825 DPRINT("dwServiceType = 0x%lx\n", dwServiceType
);
1826 DPRINT("dwStartType = %lu\n", dwStartType
);
1827 DPRINT("dwErrorControl = %lu\n", dwErrorControl
);
1828 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName
);
1829 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup
);
1830 DPRINT("lpDisplayName = %S\n", lpDisplayName
);
1833 return ERROR_SHUTDOWN_IN_PROGRESS
;
1835 hSvc
= ScmGetServiceFromHandle(hService
);
1838 DPRINT1("Invalid service handle!\n");
1839 return ERROR_INVALID_HANDLE
;
1842 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1843 SERVICE_CHANGE_CONFIG
))
1845 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1846 return ERROR_ACCESS_DENIED
;
1849 lpService
= hSvc
->ServiceEntry
;
1850 if (lpService
== NULL
)
1852 DPRINT("lpService == NULL!\n");
1853 return ERROR_INVALID_HANDLE
;
1856 /* Lock the service database exclusively */
1857 ScmLockDatabaseExclusive();
1859 if (lpService
->bDeleted
)
1861 DPRINT("The service has already been marked for delete!\n");
1862 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
1866 /* Open the service key */
1867 dwError
= ScmOpenServiceKey(lpService
->szServiceName
,
1870 if (dwError
!= ERROR_SUCCESS
)
1873 /* Write service data to the registry */
1874 /* Set the display name */
1875 if (lpDisplayName
!= NULL
&& *lpDisplayName
!= 0)
1877 RegSetValueExW(hServiceKey
,
1881 (LPBYTE
)lpDisplayName
,
1882 (DWORD
)((wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
)));
1884 /* Update the display name */
1885 lpDisplayNameW
= HeapAlloc(GetProcessHeap(),
1887 (wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
));
1888 if (lpDisplayNameW
== NULL
)
1890 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
1894 wcscpy(lpDisplayNameW
, lpDisplayName
);
1895 if (lpService
->lpDisplayName
!= lpService
->lpServiceName
)
1896 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
1898 lpService
->lpDisplayName
= lpDisplayNameW
;
1901 if (dwServiceType
!= SERVICE_NO_CHANGE
)
1903 /* Set the service type */
1904 dwError
= RegSetValueExW(hServiceKey
,
1908 (LPBYTE
)&dwServiceType
,
1910 if (dwError
!= ERROR_SUCCESS
)
1913 lpService
->Status
.dwServiceType
= dwServiceType
;
1916 if (dwStartType
!= SERVICE_NO_CHANGE
)
1918 /* Set the start value */
1919 dwError
= RegSetValueExW(hServiceKey
,
1923 (LPBYTE
)&dwStartType
,
1925 if (dwError
!= ERROR_SUCCESS
)
1928 lpService
->dwStartType
= dwStartType
;
1931 if (dwErrorControl
!= SERVICE_NO_CHANGE
)
1933 /* Set the error control value */
1934 dwError
= RegSetValueExW(hServiceKey
,
1938 (LPBYTE
)&dwErrorControl
,
1940 if (dwError
!= ERROR_SUCCESS
)
1943 lpService
->dwErrorControl
= dwErrorControl
;
1946 if (lpBinaryPathName
!= NULL
&& *lpBinaryPathName
!= 0)
1948 /* Set the image path */
1949 lpImagePathW
= lpBinaryPathName
;
1951 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
1953 dwError
= ScmCanonDriverImagePath(lpService
->dwStartType
,
1957 if (dwError
!= ERROR_SUCCESS
)
1961 dwError
= RegSetValueExW(hServiceKey
,
1965 (LPBYTE
)lpImagePathW
,
1966 (DWORD
)((wcslen(lpImagePathW
) + 1) * sizeof(WCHAR
)));
1968 if (lpImagePathW
!= lpBinaryPathName
)
1969 HeapFree(GetProcessHeap(), 0, lpImagePathW
);
1971 if (dwError
!= ERROR_SUCCESS
)
1975 /* Set the group name */
1976 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
1978 dwError
= RegSetValueExW(hServiceKey
,
1982 (LPBYTE
)lpLoadOrderGroup
,
1983 (DWORD
)((wcslen(lpLoadOrderGroup
) + 1) * sizeof(WCHAR
)));
1984 if (dwError
!= ERROR_SUCCESS
)
1987 dwError
= ScmSetServiceGroup(lpService
,
1989 if (dwError
!= ERROR_SUCCESS
)
1994 if (lpdwTagId
!= NULL
)
1996 dwError
= ScmAssignNewTag(lpService
);
1997 if (dwError
!= ERROR_SUCCESS
)
2000 dwError
= RegSetValueExW(hServiceKey
,
2004 (LPBYTE
)&lpService
->dwTag
,
2006 if (dwError
!= ERROR_SUCCESS
)
2009 *lpdwTagId
= lpService
->dwTag
;
2012 /* Write dependencies */
2013 if (lpDependencies
!= NULL
&& *lpDependencies
!= 0)
2015 dwError
= ScmWriteDependencies(hServiceKey
,
2016 (LPWSTR
)lpDependencies
,
2018 if (dwError
!= ERROR_SUCCESS
)
2022 if (lpPassword
!= NULL
)
2024 if (wcslen((LPWSTR
)lpPassword
) != 0)
2026 /* FIXME: Decrypt the password */
2028 /* Write the password */
2029 dwError
= ScmSetServicePassword(lpService
->szServiceName
,
2030 (LPCWSTR
)lpPassword
);
2031 if (dwError
!= ERROR_SUCCESS
)
2036 /* Delete the password */
2037 dwError
= ScmSetServicePassword(lpService
->szServiceName
,
2039 if (dwError
== ERROR_FILE_NOT_FOUND
)
2040 dwError
= ERROR_SUCCESS
;
2042 if (dwError
!= ERROR_SUCCESS
)
2048 if (hServiceKey
!= NULL
)
2049 RegCloseKey(hServiceKey
);
2051 /* Unlock the service database */
2052 ScmUnlockDatabase();
2054 DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError
);
2061 DWORD
RCreateServiceW(
2062 SC_RPC_HANDLE hSCManager
,
2063 LPCWSTR lpServiceName
,
2064 LPCWSTR lpDisplayName
,
2065 DWORD dwDesiredAccess
,
2066 DWORD dwServiceType
,
2068 DWORD dwErrorControl
,
2069 LPCWSTR lpBinaryPathName
,
2070 LPCWSTR lpLoadOrderGroup
,
2072 LPBYTE lpDependencies
,
2074 LPCWSTR lpServiceStartName
,
2077 LPSC_RPC_HANDLE lpServiceHandle
)
2079 PMANAGER_HANDLE hManager
;
2080 DWORD dwError
= ERROR_SUCCESS
;
2081 PSERVICE lpService
= NULL
;
2082 SC_HANDLE hServiceHandle
= NULL
;
2083 LPWSTR lpImagePath
= NULL
;
2084 HKEY hServiceKey
= NULL
;
2085 LPWSTR lpObjectName
;
2087 DPRINT("RCreateServiceW() called\n");
2088 DPRINT("lpServiceName = %S\n", lpServiceName
);
2089 DPRINT("lpDisplayName = %S\n", lpDisplayName
);
2090 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess
);
2091 DPRINT("dwServiceType = 0x%lx\n", dwServiceType
);
2092 DPRINT("dwStartType = %lu\n", dwStartType
);
2093 DPRINT("dwErrorControl = %lu\n", dwErrorControl
);
2094 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName
);
2095 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup
);
2096 DPRINT("lpdwTagId = %p\n", lpdwTagId
);
2099 return ERROR_SHUTDOWN_IN_PROGRESS
;
2101 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
2102 if (hManager
== NULL
)
2104 DPRINT1("Invalid service manager handle!\n");
2105 return ERROR_INVALID_HANDLE
;
2108 /* Check access rights */
2109 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
2110 SC_MANAGER_CREATE_SERVICE
))
2112 DPRINT("Insufficient access rights! 0x%lx\n",
2113 hManager
->Handle
.DesiredAccess
);
2114 return ERROR_ACCESS_DENIED
;
2117 if (wcslen(lpServiceName
) == 0)
2119 return ERROR_INVALID_NAME
;
2122 if (wcslen(lpBinaryPathName
) == 0)
2124 return ERROR_INVALID_PARAMETER
;
2127 /* Check for invalid service type value */
2128 if ((dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
2129 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
) &&
2130 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
2131 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
))
2132 return ERROR_INVALID_PARAMETER
;
2134 /* Check for invalid start type value */
2135 if ((dwStartType
!= SERVICE_BOOT_START
) &&
2136 (dwStartType
!= SERVICE_SYSTEM_START
) &&
2137 (dwStartType
!= SERVICE_AUTO_START
) &&
2138 (dwStartType
!= SERVICE_DEMAND_START
) &&
2139 (dwStartType
!= SERVICE_DISABLED
))
2140 return ERROR_INVALID_PARAMETER
;
2142 /* Only drivers can be boot start or system start services */
2143 if ((dwStartType
== SERVICE_BOOT_START
) ||
2144 (dwStartType
== SERVICE_SYSTEM_START
))
2146 if ((dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
2147 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
2148 return ERROR_INVALID_PARAMETER
;
2151 /* Check for invalid error control value */
2152 if ((dwErrorControl
!= SERVICE_ERROR_IGNORE
) &&
2153 (dwErrorControl
!= SERVICE_ERROR_NORMAL
) &&
2154 (dwErrorControl
!= SERVICE_ERROR_SEVERE
) &&
2155 (dwErrorControl
!= SERVICE_ERROR_CRITICAL
))
2156 return ERROR_INVALID_PARAMETER
;
2158 if ((dwServiceType
== (SERVICE_WIN32_OWN_PROCESS
| SERVICE_INTERACTIVE_PROCESS
)) &&
2159 (lpServiceStartName
))
2161 return ERROR_INVALID_PARAMETER
;
2164 if (lpdwTagId
&& (!lpLoadOrderGroup
|| !*lpLoadOrderGroup
))
2166 return ERROR_INVALID_PARAMETER
;
2169 /* Lock the service database exclusively */
2170 ScmLockDatabaseExclusive();
2172 lpService
= ScmGetServiceEntryByName(lpServiceName
);
2175 /* Unlock the service database */
2176 ScmUnlockDatabase();
2178 /* Check if it is marked for deletion */
2179 if (lpService
->bDeleted
)
2180 return ERROR_SERVICE_MARKED_FOR_DELETE
;
2182 /* Return Error exist */
2183 return ERROR_SERVICE_EXISTS
;
2186 if (lpDisplayName
!= NULL
&&
2187 ScmGetServiceEntryByDisplayName(lpDisplayName
) != NULL
)
2189 /* Unlock the service database */
2190 ScmUnlockDatabase();
2192 return ERROR_DUPLICATE_SERVICE_NAME
;
2195 if (dwServiceType
& SERVICE_DRIVER
)
2197 dwError
= ScmCanonDriverImagePath(dwStartType
,
2200 if (dwError
!= ERROR_SUCCESS
)
2205 if (dwStartType
== SERVICE_BOOT_START
||
2206 dwStartType
== SERVICE_SYSTEM_START
)
2208 /* Unlock the service database */
2209 ScmUnlockDatabase();
2211 return ERROR_INVALID_PARAMETER
;
2215 /* Allocate a new service entry */
2216 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
2218 if (dwError
!= ERROR_SUCCESS
)
2221 /* Fill the new service entry */
2222 lpService
->Status
.dwServiceType
= dwServiceType
;
2223 lpService
->dwStartType
= dwStartType
;
2224 lpService
->dwErrorControl
= dwErrorControl
;
2226 /* Fill the display name */
2227 if (lpDisplayName
!= NULL
&&
2228 *lpDisplayName
!= 0 &&
2229 _wcsicmp(lpService
->lpDisplayName
, lpDisplayName
) != 0)
2231 lpService
->lpDisplayName
= HeapAlloc(GetProcessHeap(),
2233 (wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
));
2234 if (lpService
->lpDisplayName
== NULL
)
2236 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
2239 wcscpy(lpService
->lpDisplayName
, lpDisplayName
);
2242 /* Assign the service to a group */
2243 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
2245 dwError
= ScmSetServiceGroup(lpService
,
2247 if (dwError
!= ERROR_SUCCESS
)
2251 /* Assign a new tag */
2252 if (lpdwTagId
!= NULL
)
2254 dwError
= ScmAssignNewTag(lpService
);
2255 if (dwError
!= ERROR_SUCCESS
)
2259 /* Assign the default security descriptor */
2260 if (dwServiceType
& SERVICE_WIN32
)
2262 dwError
= ScmCreateDefaultServiceSD(&lpService
->pSecurityDescriptor
);
2263 if (dwError
!= ERROR_SUCCESS
)
2267 /* Write service data to the registry */
2268 /* Create the service key */
2269 dwError
= ScmCreateServiceKey(lpServiceName
,
2272 if (dwError
!= ERROR_SUCCESS
)
2275 /* Set the display name */
2276 if (lpDisplayName
!= NULL
&& *lpDisplayName
!= 0)
2278 RegSetValueExW(hServiceKey
,
2282 (LPBYTE
)lpDisplayName
,
2283 (DWORD
)((wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
)));
2286 /* Set the service type */
2287 dwError
= RegSetValueExW(hServiceKey
,
2291 (LPBYTE
)&dwServiceType
,
2293 if (dwError
!= ERROR_SUCCESS
)
2296 /* Set the start value */
2297 dwError
= RegSetValueExW(hServiceKey
,
2301 (LPBYTE
)&dwStartType
,
2303 if (dwError
!= ERROR_SUCCESS
)
2306 /* Set the error control value */
2307 dwError
= RegSetValueExW(hServiceKey
,
2311 (LPBYTE
)&dwErrorControl
,
2313 if (dwError
!= ERROR_SUCCESS
)
2316 /* Set the image path */
2317 if (dwServiceType
& SERVICE_WIN32
)
2319 dwError
= RegSetValueExW(hServiceKey
,
2323 (LPBYTE
)lpBinaryPathName
,
2324 (DWORD
)((wcslen(lpBinaryPathName
) + 1) * sizeof(WCHAR
)));
2325 if (dwError
!= ERROR_SUCCESS
)
2328 else if (dwServiceType
& SERVICE_DRIVER
)
2330 dwError
= RegSetValueExW(hServiceKey
,
2334 (LPBYTE
)lpImagePath
,
2335 (DWORD
)((wcslen(lpImagePath
) + 1) * sizeof(WCHAR
)));
2336 if (dwError
!= ERROR_SUCCESS
)
2340 /* Set the group name */
2341 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
2343 dwError
= RegSetValueExW(hServiceKey
,
2347 (LPBYTE
)lpLoadOrderGroup
,
2348 (DWORD
)((wcslen(lpLoadOrderGroup
) + 1) * sizeof(WCHAR
)));
2349 if (dwError
!= ERROR_SUCCESS
)
2353 /* Set the service tag */
2354 if (lpdwTagId
!= NULL
)
2356 dwError
= RegSetValueExW(hServiceKey
,
2360 (LPBYTE
)&lpService
->dwTag
,
2362 if (dwError
!= ERROR_SUCCESS
)
2366 /* Write dependencies */
2367 if (lpDependencies
!= NULL
&& *lpDependencies
!= 0)
2369 dwError
= ScmWriteDependencies(hServiceKey
,
2370 (LPCWSTR
)lpDependencies
,
2372 if (dwError
!= ERROR_SUCCESS
)
2376 /* Start name and password are only used by Win32 services */
2377 if (dwServiceType
& SERVICE_WIN32
)
2379 /* Write service start name */
2380 lpObjectName
= (lpServiceStartName
!= NULL
) ? (LPWSTR
)lpServiceStartName
: L
"LocalSystem";
2381 dwError
= RegSetValueExW(hServiceKey
,
2385 (LPBYTE
)lpObjectName
,
2386 (DWORD
)((wcslen(lpObjectName
) + 1) * sizeof(WCHAR
)));
2387 if (dwError
!= ERROR_SUCCESS
)
2390 if (lpPassword
!= NULL
&& wcslen((LPWSTR
)lpPassword
) != 0)
2392 /* FIXME: Decrypt the password */
2394 /* Write the password */
2395 dwError
= ScmSetServicePassword(lpServiceName
,
2396 (LPCWSTR
)lpPassword
);
2397 if (dwError
!= ERROR_SUCCESS
)
2402 /* Write the security descriptor */
2403 dwError
= ScmWriteSecurityDescriptor(hServiceKey
,
2404 lpService
->pSecurityDescriptor
);
2405 if (dwError
!= ERROR_SUCCESS
)
2409 dwError
= ScmCreateServiceHandle(lpService
,
2411 if (dwError
!= ERROR_SUCCESS
)
2414 dwError
= ScmCheckAccess(hServiceHandle
,
2416 if (dwError
!= ERROR_SUCCESS
)
2419 lpService
->dwRefCount
= 1;
2420 DPRINT("CreateService - lpService->dwRefCount %u\n", lpService
->dwRefCount
);
2423 /* Unlock the service database */
2424 ScmUnlockDatabase();
2426 if (hServiceKey
!= NULL
)
2427 RegCloseKey(hServiceKey
);
2429 if (dwError
== ERROR_SUCCESS
)
2431 DPRINT("hService %p\n", hServiceHandle
);
2432 *lpServiceHandle
= (SC_RPC_HANDLE
)hServiceHandle
;
2434 if (lpdwTagId
!= NULL
)
2435 *lpdwTagId
= lpService
->dwTag
;
2439 if (lpService
!= NULL
&&
2440 lpService
->lpServiceName
!= NULL
)
2442 /* Release the display name buffer */
2443 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
2448 /* Remove the service handle */
2449 HeapFree(GetProcessHeap(), 0, hServiceHandle
);
2452 if (lpService
!= NULL
)
2454 /* FIXME: remove the service entry */
2458 if (lpImagePath
!= NULL
)
2459 HeapFree(GetProcessHeap(), 0, lpImagePath
);
2461 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError
);
2468 DWORD
REnumDependentServicesW(
2469 SC_RPC_HANDLE hService
,
2470 DWORD dwServiceState
,
2473 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
2474 LPBOUNDED_DWORD_256K lpServicesReturned
)
2476 DWORD dwError
= ERROR_SUCCESS
;
2477 DWORD dwServicesReturned
= 0;
2478 DWORD dwServiceCount
;
2479 HKEY hServicesKey
= NULL
;
2480 PSERVICE_HANDLE hSvc
;
2481 PSERVICE lpService
= NULL
;
2482 PSERVICE
*lpServicesArray
= NULL
;
2483 LPENUM_SERVICE_STATUSW lpServicesPtr
= NULL
;
2486 *pcbBytesNeeded
= 0;
2487 *lpServicesReturned
= 0;
2489 DPRINT("REnumDependentServicesW() called\n");
2491 hSvc
= ScmGetServiceFromHandle(hService
);
2494 DPRINT1("Invalid service handle!\n");
2495 return ERROR_INVALID_HANDLE
;
2498 lpService
= hSvc
->ServiceEntry
;
2500 /* Check access rights */
2501 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
2502 SC_MANAGER_ENUMERATE_SERVICE
))
2504 DPRINT("Insufficient access rights! 0x%lx\n",
2505 hSvc
->Handle
.DesiredAccess
);
2506 return ERROR_ACCESS_DENIED
;
2509 /* Open the Services Reg key */
2510 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2511 L
"System\\CurrentControlSet\\Services",
2515 if (dwError
!= ERROR_SUCCESS
)
2518 /* First determine the bytes needed and get the number of dependent services */
2519 dwError
= Int_EnumDependentServicesW(hServicesKey
,
2524 &dwServicesReturned
);
2525 if (dwError
!= ERROR_SUCCESS
)
2528 /* If buffer size is less than the bytes needed or pointer is null */
2529 if ((!lpServices
) || (cbBufSize
< *pcbBytesNeeded
))
2531 dwError
= ERROR_MORE_DATA
;
2535 /* Allocate memory for array of service pointers */
2536 lpServicesArray
= HeapAlloc(GetProcessHeap(),
2538 (dwServicesReturned
+ 1) * sizeof(PSERVICE
));
2539 if (!lpServicesArray
)
2541 DPRINT1("Could not allocate a buffer!!\n");
2542 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
2546 dwServicesReturned
= 0;
2547 *pcbBytesNeeded
= 0;
2549 dwError
= Int_EnumDependentServicesW(hServicesKey
,
2554 &dwServicesReturned
);
2555 if (dwError
!= ERROR_SUCCESS
)
2560 lpServicesPtr
= (LPENUM_SERVICE_STATUSW
)lpServices
;
2561 lpStr
= (LPWSTR
)(lpServices
+ (dwServicesReturned
* sizeof(ENUM_SERVICE_STATUSW
)));
2563 /* Copy EnumDepenedentService to Buffer */
2564 for (dwServiceCount
= 0; dwServiceCount
< dwServicesReturned
; dwServiceCount
++)
2566 lpService
= lpServicesArray
[dwServiceCount
];
2568 /* Copy status info */
2569 memcpy(&lpServicesPtr
->ServiceStatus
,
2571 sizeof(SERVICE_STATUS
));
2573 /* Copy display name */
2574 wcscpy(lpStr
, lpService
->lpDisplayName
);
2575 lpServicesPtr
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
2576 lpStr
+= (wcslen(lpService
->lpDisplayName
) + 1);
2578 /* Copy service name */
2579 wcscpy(lpStr
, lpService
->lpServiceName
);
2580 lpServicesPtr
->lpServiceName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
2581 lpStr
+= (wcslen(lpService
->lpServiceName
) + 1);
2586 *lpServicesReturned
= dwServicesReturned
;
2589 if (lpServicesArray
!= NULL
)
2590 HeapFree(GetProcessHeap(), 0, lpServicesArray
);
2592 RegCloseKey(hServicesKey
);
2594 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError
);
2601 DWORD
REnumServicesStatusW(
2602 SC_RPC_HANDLE hSCManager
,
2603 DWORD dwServiceType
,
2604 DWORD dwServiceState
,
2607 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
2608 LPBOUNDED_DWORD_256K lpServicesReturned
,
2609 LPBOUNDED_DWORD_256K lpResumeHandle
)
2611 /* Enumerate all the services, not regarding of their group */
2612 return REnumServiceGroupW(hSCManager
,
2625 DWORD
ROpenSCManagerW(
2626 LPWSTR lpMachineName
,
2627 LPWSTR lpDatabaseName
,
2628 DWORD dwDesiredAccess
,
2629 LPSC_RPC_HANDLE lpScHandle
)
2634 DPRINT("ROpenSCManagerW() called\n");
2635 DPRINT("lpMachineName = %p\n", lpMachineName
);
2636 DPRINT("lpMachineName: %S\n", lpMachineName
);
2637 DPRINT("lpDataBaseName = %p\n", lpDatabaseName
);
2638 DPRINT("lpDataBaseName: %S\n", lpDatabaseName
);
2639 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess
);
2642 return ERROR_SHUTDOWN_IN_PROGRESS
;
2645 return ERROR_INVALID_PARAMETER
;
2647 dwError
= ScmCreateManagerHandle(lpDatabaseName
,
2649 if (dwError
!= ERROR_SUCCESS
)
2651 DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError
);
2655 /* Check the desired access */
2656 dwError
= ScmCheckAccess(hHandle
,
2657 dwDesiredAccess
| SC_MANAGER_CONNECT
);
2658 if (dwError
!= ERROR_SUCCESS
)
2660 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError
);
2661 HeapFree(GetProcessHeap(), 0, hHandle
);
2665 *lpScHandle
= (SC_RPC_HANDLE
)hHandle
;
2666 DPRINT("*hScm = %p\n", *lpScHandle
);
2668 DPRINT("ROpenSCManagerW() done\n");
2670 return ERROR_SUCCESS
;
2675 DWORD
ROpenServiceW(
2676 SC_RPC_HANDLE hSCManager
,
2677 LPWSTR lpServiceName
,
2678 DWORD dwDesiredAccess
,
2679 LPSC_RPC_HANDLE lpServiceHandle
)
2682 PMANAGER_HANDLE hManager
;
2684 DWORD dwError
= ERROR_SUCCESS
;
2686 DPRINT("ROpenServiceW() called\n");
2687 DPRINT("hSCManager = %p\n", hSCManager
);
2688 DPRINT("lpServiceName = %p\n", lpServiceName
);
2689 DPRINT("lpServiceName: %S\n", lpServiceName
);
2690 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess
);
2693 return ERROR_SHUTDOWN_IN_PROGRESS
;
2695 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
2696 if (hManager
== NULL
)
2698 DPRINT1("Invalid service manager handle!\n");
2699 return ERROR_INVALID_HANDLE
;
2702 if (!lpServiceHandle
)
2703 return ERROR_INVALID_PARAMETER
;
2706 return ERROR_INVALID_ADDRESS
;
2708 /* Lock the service database exclusive */
2709 ScmLockDatabaseExclusive();
2711 /* Get service database entry */
2712 lpService
= ScmGetServiceEntryByName(lpServiceName
);
2713 if (lpService
== NULL
)
2715 DPRINT("Could not find a service!\n");
2716 dwError
= ERROR_SERVICE_DOES_NOT_EXIST
;
2720 /* Create a service handle */
2721 dwError
= ScmCreateServiceHandle(lpService
,
2723 if (dwError
!= ERROR_SUCCESS
)
2725 DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError
);
2729 /* Check the desired access */
2730 dwError
= ScmCheckAccess(hHandle
,
2732 if (dwError
!= ERROR_SUCCESS
)
2734 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError
);
2735 HeapFree(GetProcessHeap(), 0, hHandle
);
2739 lpService
->dwRefCount
++;
2740 DPRINT("OpenService - lpService->dwRefCount %u\n",lpService
->dwRefCount
);
2742 *lpServiceHandle
= (SC_RPC_HANDLE
)hHandle
;
2743 DPRINT("*hService = %p\n", *lpServiceHandle
);
2746 /* Unlock the service database */
2747 ScmUnlockDatabase();
2749 DPRINT("ROpenServiceW() done\n");
2756 DWORD
RQueryServiceConfigW(
2757 SC_RPC_HANDLE hService
,
2758 LPBYTE lpBuf
, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2760 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
2762 LPQUERY_SERVICE_CONFIGW lpServiceConfig
= (LPQUERY_SERVICE_CONFIGW
)lpBuf
;
2763 DWORD dwError
= ERROR_SUCCESS
;
2764 PSERVICE_HANDLE hSvc
;
2765 PSERVICE lpService
= NULL
;
2766 HKEY hServiceKey
= NULL
;
2767 LPWSTR lpImagePath
= NULL
;
2768 LPWSTR lpServiceStartName
= NULL
;
2769 LPWSTR lpDependencies
= NULL
;
2770 DWORD dwDependenciesLength
= 0;
2771 DWORD dwRequiredSize
;
2772 WCHAR lpEmptyString
[] = {0,0};
2775 DPRINT("RQueryServiceConfigW() called\n");
2778 return ERROR_SHUTDOWN_IN_PROGRESS
;
2780 hSvc
= ScmGetServiceFromHandle(hService
);
2783 DPRINT1("Invalid service handle!\n");
2784 return ERROR_INVALID_HANDLE
;
2787 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
2788 SERVICE_QUERY_CONFIG
))
2790 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
2791 return ERROR_ACCESS_DENIED
;
2794 lpService
= hSvc
->ServiceEntry
;
2795 if (lpService
== NULL
)
2797 DPRINT("lpService == NULL!\n");
2798 return ERROR_INVALID_HANDLE
;
2801 /* Lock the service database shared */
2802 ScmLockDatabaseShared();
2804 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
2807 if (dwError
!= ERROR_SUCCESS
)
2810 /* Read the image path */
2811 dwError
= ScmReadString(hServiceKey
,
2814 if (dwError
!= ERROR_SUCCESS
)
2817 /* Read the service start name */
2818 ScmReadString(hServiceKey
,
2820 &lpServiceStartName
);
2822 /* Read the dependencies */
2823 ScmReadDependencies(hServiceKey
,
2825 &dwDependenciesLength
);
2827 dwRequiredSize
= sizeof(QUERY_SERVICE_CONFIGW
);
2829 if (lpImagePath
!= NULL
)
2830 dwRequiredSize
+= (DWORD
)((wcslen(lpImagePath
) + 1) * sizeof(WCHAR
));
2832 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2834 if ((lpService
->lpGroup
!= NULL
) && (lpService
->lpGroup
->lpGroupName
!= NULL
))
2835 dwRequiredSize
+= (DWORD
)((wcslen(lpService
->lpGroup
->lpGroupName
) + 1) * sizeof(WCHAR
));
2837 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2839 if (lpDependencies
!= NULL
)
2840 dwRequiredSize
+= dwDependenciesLength
* sizeof(WCHAR
);
2842 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2844 if (lpServiceStartName
!= NULL
)
2845 dwRequiredSize
+= (DWORD
)((wcslen(lpServiceStartName
) + 1) * sizeof(WCHAR
));
2847 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2849 if (lpService
->lpDisplayName
!= NULL
)
2850 dwRequiredSize
+= (DWORD
)((wcslen(lpService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
2852 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2854 if (lpServiceConfig
== NULL
|| cbBufSize
< dwRequiredSize
)
2856 dwError
= ERROR_INSUFFICIENT_BUFFER
;
2860 lpServiceConfig
->dwServiceType
= lpService
->Status
.dwServiceType
;
2861 lpServiceConfig
->dwStartType
= lpService
->dwStartType
;
2862 lpServiceConfig
->dwErrorControl
= lpService
->dwErrorControl
;
2863 lpServiceConfig
->dwTagId
= lpService
->dwTag
;
2865 lpStr
= (LPWSTR
)(lpServiceConfig
+ 1);
2867 /* Append the image path */
2868 if (lpImagePath
!= NULL
)
2870 wcscpy(lpStr
, lpImagePath
);
2874 wcscpy(lpStr
, lpEmptyString
);
2877 lpServiceConfig
->lpBinaryPathName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2878 lpStr
+= (wcslen(lpStr
) + 1);
2880 /* Append the group name */
2881 if ((lpService
->lpGroup
!= NULL
) && (lpService
->lpGroup
->lpGroupName
!= NULL
))
2883 wcscpy(lpStr
, lpService
->lpGroup
->lpGroupName
);
2887 wcscpy(lpStr
, lpEmptyString
);
2890 lpServiceConfig
->lpLoadOrderGroup
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2891 lpStr
+= (wcslen(lpStr
) + 1);
2893 /* Append Dependencies */
2894 if (lpDependencies
!= NULL
)
2898 dwDependenciesLength
* sizeof(WCHAR
));
2902 wcscpy(lpStr
, lpEmptyString
);
2905 lpServiceConfig
->lpDependencies
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2906 if (lpDependencies
!= NULL
)
2907 lpStr
+= dwDependenciesLength
;
2909 lpStr
+= (wcslen(lpStr
) + 1);
2911 /* Append the service start name */
2912 if (lpServiceStartName
!= NULL
)
2914 wcscpy(lpStr
, lpServiceStartName
);
2918 wcscpy(lpStr
, lpEmptyString
);
2921 lpServiceConfig
->lpServiceStartName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2922 lpStr
+= (wcslen(lpStr
) + 1);
2924 /* Append the display name */
2925 if (lpService
->lpDisplayName
!= NULL
)
2927 wcscpy(lpStr
, lpService
->lpDisplayName
);
2931 wcscpy(lpStr
, lpEmptyString
);
2934 lpServiceConfig
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2937 if (pcbBytesNeeded
!= NULL
)
2938 *pcbBytesNeeded
= dwRequiredSize
;
2941 /* Unlock the service database */
2942 ScmUnlockDatabase();
2944 if (lpImagePath
!= NULL
)
2945 HeapFree(GetProcessHeap(), 0, lpImagePath
);
2947 if (lpServiceStartName
!= NULL
)
2948 HeapFree(GetProcessHeap(), 0, lpServiceStartName
);
2950 if (lpDependencies
!= NULL
)
2951 HeapFree(GetProcessHeap(), 0, lpDependencies
);
2953 if (hServiceKey
!= NULL
)
2954 RegCloseKey(hServiceKey
);
2956 DPRINT("RQueryServiceConfigW() done\n");
2963 DWORD
RQueryServiceLockStatusW(
2964 SC_RPC_HANDLE hSCManager
,
2965 LPBYTE lpBuf
, // LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2967 LPBOUNDED_DWORD_4K pcbBytesNeeded
)
2969 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
= (LPQUERY_SERVICE_LOCK_STATUSW
)lpBuf
;
2970 PMANAGER_HANDLE hMgr
;
2971 DWORD dwRequiredSize
;
2973 if (!lpLockStatus
|| !pcbBytesNeeded
)
2974 return ERROR_INVALID_PARAMETER
;
2976 hMgr
= ScmGetServiceManagerFromHandle(hSCManager
);
2979 DPRINT1("Invalid service manager handle!\n");
2980 return ERROR_INVALID_HANDLE
;
2983 if (!RtlAreAllAccessesGranted(hMgr
->Handle
.DesiredAccess
,
2984 SC_MANAGER_QUERY_LOCK_STATUS
))
2986 DPRINT("Insufficient access rights! 0x%lx\n", hMgr
->Handle
.DesiredAccess
);
2987 return ERROR_ACCESS_DENIED
;
2990 /* FIXME: we need to compute instead the real length of the owner name */
2991 dwRequiredSize
= sizeof(QUERY_SERVICE_LOCK_STATUSW
) + sizeof(WCHAR
);
2992 *pcbBytesNeeded
= dwRequiredSize
;
2994 if (cbBufSize
< dwRequiredSize
)
2995 return ERROR_INSUFFICIENT_BUFFER
;
2997 ScmQueryServiceLockStatusW(lpLockStatus
);
2999 return ERROR_SUCCESS
;
3004 DWORD
RStartServiceW(
3005 SC_RPC_HANDLE hService
,
3007 LPSTRING_PTRSW argv
)
3009 DWORD dwError
= ERROR_SUCCESS
;
3010 PSERVICE_HANDLE hSvc
;
3011 PSERVICE lpService
= NULL
;
3016 DPRINT("RStartServiceW(%p %lu %p) called\n", hService
, argc
, argv
);
3017 DPRINT(" argc: %lu\n", argc
);
3020 for (i
= 0; i
< argc
; i
++)
3022 DPRINT(" argv[%lu]: %S\n", i
, argv
[i
].StringPtr
);
3028 return ERROR_SHUTDOWN_IN_PROGRESS
;
3030 hSvc
= ScmGetServiceFromHandle(hService
);
3033 DPRINT1("Invalid service handle!\n");
3034 return ERROR_INVALID_HANDLE
;
3037 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3040 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
3041 return ERROR_ACCESS_DENIED
;
3044 lpService
= hSvc
->ServiceEntry
;
3045 if (lpService
== NULL
)
3047 DPRINT("lpService == NULL!\n");
3048 return ERROR_INVALID_HANDLE
;
3051 if (lpService
->dwStartType
== SERVICE_DISABLED
)
3052 return ERROR_SERVICE_DISABLED
;
3054 if (lpService
->bDeleted
)
3055 return ERROR_SERVICE_MARKED_FOR_DELETE
;
3057 /* Start the service */
3058 dwError
= ScmStartService(lpService
, argc
, (LPWSTR
*)argv
);
3065 DWORD
RGetServiceDisplayNameW(
3066 SC_RPC_HANDLE hSCManager
,
3067 LPCWSTR lpServiceName
,
3068 LPWSTR lpDisplayName
,
3071 // PMANAGER_HANDLE hManager;
3076 DPRINT("RGetServiceDisplayNameW() called\n");
3077 DPRINT("hSCManager = %p\n", hSCManager
);
3078 DPRINT("lpServiceName: %S\n", lpServiceName
);
3079 DPRINT("lpDisplayName: %p\n", lpDisplayName
);
3080 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
3082 // hManager = (PMANAGER_HANDLE)hSCManager;
3083 // if (hManager->Handle.Tag != MANAGER_TAG)
3085 // DPRINT("Invalid manager handle!\n");
3086 // return ERROR_INVALID_HANDLE;
3089 /* Get service database entry */
3090 lpService
= ScmGetServiceEntryByName(lpServiceName
);
3091 if (lpService
== NULL
)
3093 DPRINT("Could not find a service!\n");
3095 /* If the service could not be found and lpcchBuffer is less than 2, windows
3096 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3097 if (*lpcchBuffer
< 2)
3100 if (lpDisplayName
!= NULL
)
3106 return ERROR_SERVICE_DOES_NOT_EXIST
;
3109 if (!lpService
->lpDisplayName
)
3111 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
3113 if (lpDisplayName
!= NULL
&&
3114 *lpcchBuffer
> dwLength
)
3116 wcscpy(lpDisplayName
, lpService
->lpServiceName
);
3121 dwLength
= (DWORD
)wcslen(lpService
->lpDisplayName
);
3123 if (lpDisplayName
!= NULL
&&
3124 *lpcchBuffer
> dwLength
)
3126 wcscpy(lpDisplayName
, lpService
->lpDisplayName
);
3130 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
3132 *lpcchBuffer
= dwLength
;
3139 DWORD
RGetServiceKeyNameW(
3140 SC_RPC_HANDLE hSCManager
,
3141 LPCWSTR lpDisplayName
,
3142 LPWSTR lpServiceName
,
3145 // PMANAGER_HANDLE hManager;
3150 DPRINT("RGetServiceKeyNameW() called\n");
3151 DPRINT("hSCManager = %p\n", hSCManager
);
3152 DPRINT("lpDisplayName: %S\n", lpDisplayName
);
3153 DPRINT("lpServiceName: %p\n", lpServiceName
);
3154 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
3156 // hManager = (PMANAGER_HANDLE)hSCManager;
3157 // if (hManager->Handle.Tag != MANAGER_TAG)
3159 // DPRINT("Invalid manager handle!\n");
3160 // return ERROR_INVALID_HANDLE;
3163 /* Get service database entry */
3164 lpService
= ScmGetServiceEntryByDisplayName(lpDisplayName
);
3165 if (lpService
== NULL
)
3167 DPRINT("Could not find a service!\n");
3169 /* If the service could not be found and lpcchBuffer is less than 2, windows
3170 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3171 if (*lpcchBuffer
< 2)
3174 if (lpServiceName
!= NULL
)
3180 return ERROR_SERVICE_DOES_NOT_EXIST
;
3183 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
3185 if (lpServiceName
!= NULL
&&
3186 *lpcchBuffer
> dwLength
)
3188 wcscpy(lpServiceName
, lpService
->lpServiceName
);
3189 *lpcchBuffer
= dwLength
;
3190 return ERROR_SUCCESS
;
3193 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
3195 *lpcchBuffer
= dwLength
;
3202 DWORD
RI_ScSetServiceBitsA(
3203 RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
3204 DWORD dwServiceBits
,
3206 int bUpdateImmediately
,
3210 return ERROR_CALL_NOT_IMPLEMENTED
;
3215 DWORD
RChangeServiceConfigA(
3216 SC_RPC_HANDLE hService
,
3217 DWORD dwServiceType
,
3219 DWORD dwErrorControl
,
3220 LPSTR lpBinaryPathName
,
3221 LPSTR lpLoadOrderGroup
,
3223 LPBYTE lpDependencies
,
3225 LPSTR lpServiceStartName
,
3228 LPSTR lpDisplayName
)
3230 DWORD dwError
= ERROR_SUCCESS
;
3231 PSERVICE_HANDLE hSvc
;
3232 PSERVICE lpService
= NULL
;
3233 HKEY hServiceKey
= NULL
;
3234 LPWSTR lpDisplayNameW
= NULL
;
3235 LPWSTR lpBinaryPathNameW
= NULL
;
3236 LPWSTR lpCanonicalImagePathW
= NULL
;
3237 LPWSTR lpLoadOrderGroupW
= NULL
;
3238 LPWSTR lpDependenciesW
= NULL
;
3240 DPRINT("RChangeServiceConfigA() called\n");
3241 DPRINT("dwServiceType = %lu\n", dwServiceType
);
3242 DPRINT("dwStartType = %lu\n", dwStartType
);
3243 DPRINT("dwErrorControl = %lu\n", dwErrorControl
);
3244 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName
);
3245 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup
);
3246 DPRINT("lpDisplayName = %s\n", lpDisplayName
);
3249 return ERROR_SHUTDOWN_IN_PROGRESS
;
3251 hSvc
= ScmGetServiceFromHandle(hService
);
3254 DPRINT1("Invalid service handle!\n");
3255 return ERROR_INVALID_HANDLE
;
3258 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3259 SERVICE_CHANGE_CONFIG
))
3261 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
3262 return ERROR_ACCESS_DENIED
;
3265 lpService
= hSvc
->ServiceEntry
;
3266 if (lpService
== NULL
)
3268 DPRINT("lpService == NULL!\n");
3269 return ERROR_INVALID_HANDLE
;
3272 /* Lock the service database exclusively */
3273 ScmLockDatabaseExclusive();
3275 if (lpService
->bDeleted
)
3277 DPRINT("The service has already been marked for delete!\n");
3278 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
3282 /* Open the service key */
3283 dwError
= ScmOpenServiceKey(lpService
->szServiceName
,
3286 if (dwError
!= ERROR_SUCCESS
)
3289 /* Write service data to the registry */
3291 if (lpDisplayName
!= NULL
&& *lpDisplayName
!= 0)
3293 /* Set the display name */
3294 lpDisplayNameW
= HeapAlloc(GetProcessHeap(),
3296 (strlen(lpDisplayName
) + 1) * sizeof(WCHAR
));
3297 if (lpDisplayNameW
== NULL
)
3299 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3303 MultiByteToWideChar(CP_ACP
,
3308 (int)(strlen(lpDisplayName
) + 1));
3310 RegSetValueExW(hServiceKey
,
3314 (LPBYTE
)lpDisplayNameW
,
3315 (DWORD
)((wcslen(lpDisplayNameW
) + 1) * sizeof(WCHAR
)));
3317 /* Update lpService->lpDisplayName */
3318 if (lpService
->lpDisplayName
)
3319 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
3321 lpService
->lpDisplayName
= lpDisplayNameW
;
3324 if (dwServiceType
!= SERVICE_NO_CHANGE
)
3326 /* Set the service type */
3327 dwError
= RegSetValueExW(hServiceKey
,
3331 (LPBYTE
)&dwServiceType
,
3333 if (dwError
!= ERROR_SUCCESS
)
3336 lpService
->Status
.dwServiceType
= dwServiceType
;
3339 if (dwStartType
!= SERVICE_NO_CHANGE
)
3341 /* Set the start value */
3342 dwError
= RegSetValueExW(hServiceKey
,
3346 (LPBYTE
)&dwStartType
,
3348 if (dwError
!= ERROR_SUCCESS
)
3351 lpService
->dwStartType
= dwStartType
;
3354 if (dwErrorControl
!= SERVICE_NO_CHANGE
)
3356 /* Set the error control value */
3357 dwError
= RegSetValueExW(hServiceKey
,
3361 (LPBYTE
)&dwErrorControl
,
3363 if (dwError
!= ERROR_SUCCESS
)
3366 lpService
->dwErrorControl
= dwErrorControl
;
3369 if (lpBinaryPathName
!= NULL
&& *lpBinaryPathName
!= 0)
3371 /* Set the image path */
3372 lpBinaryPathNameW
= HeapAlloc(GetProcessHeap(),
3374 (strlen(lpBinaryPathName
) + 1) * sizeof(WCHAR
));
3375 if (lpBinaryPathNameW
== NULL
)
3377 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3381 MultiByteToWideChar(CP_ACP
,
3386 (int)(strlen(lpBinaryPathName
) + 1));
3388 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
3390 dwError
= ScmCanonDriverImagePath(lpService
->dwStartType
,
3392 &lpCanonicalImagePathW
);
3394 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW
);
3396 if (dwError
!= ERROR_SUCCESS
)
3399 lpBinaryPathNameW
= lpCanonicalImagePathW
;
3402 dwError
= RegSetValueExW(hServiceKey
,
3406 (LPBYTE
)lpBinaryPathNameW
,
3407 (DWORD
)((wcslen(lpBinaryPathNameW
) + 1) * sizeof(WCHAR
)));
3409 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW
);
3411 if (dwError
!= ERROR_SUCCESS
)
3415 /* Set the group name */
3416 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
3418 lpLoadOrderGroupW
= HeapAlloc(GetProcessHeap(),
3420 (strlen(lpLoadOrderGroup
) + 1) * sizeof(WCHAR
));
3421 if (lpLoadOrderGroupW
== NULL
)
3423 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3427 MultiByteToWideChar(CP_ACP
,
3432 (int)(strlen(lpLoadOrderGroup
) + 1));
3434 dwError
= RegSetValueExW(hServiceKey
,
3438 (LPBYTE
)lpLoadOrderGroupW
,
3439 (DWORD
)((wcslen(lpLoadOrderGroupW
) + 1) * sizeof(WCHAR
)));
3440 if (dwError
!= ERROR_SUCCESS
)
3442 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3446 dwError
= ScmSetServiceGroup(lpService
,
3449 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3451 if (dwError
!= ERROR_SUCCESS
)
3455 if (lpdwTagId
!= NULL
)
3457 dwError
= ScmAssignNewTag(lpService
);
3458 if (dwError
!= ERROR_SUCCESS
)
3461 dwError
= RegSetValueExW(hServiceKey
,
3465 (LPBYTE
)&lpService
->dwTag
,
3467 if (dwError
!= ERROR_SUCCESS
)
3470 *lpdwTagId
= lpService
->dwTag
;
3473 /* Write dependencies */
3474 if (lpDependencies
!= NULL
&& *lpDependencies
!= 0)
3476 lpDependenciesW
= HeapAlloc(GetProcessHeap(),
3478 (strlen((LPSTR
)lpDependencies
) + 1) * sizeof(WCHAR
));
3479 if (lpDependenciesW
== NULL
)
3481 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3485 MultiByteToWideChar(CP_ACP
,
3487 (LPSTR
)lpDependencies
,
3490 (int)(strlen((LPSTR
)lpDependencies
) + 1));
3492 dwError
= ScmWriteDependencies(hServiceKey
,
3493 (LPWSTR
)lpDependenciesW
,
3496 HeapFree(GetProcessHeap(), 0, lpDependenciesW
);
3498 if (dwError
!= ERROR_SUCCESS
)
3502 if (lpPassword
!= NULL
)
3504 if (wcslen((LPWSTR
)lpPassword
) != 0)
3506 /* FIXME: Decrypt the password */
3508 /* Write the password */
3509 dwError
= ScmSetServicePassword(lpService
->szServiceName
,
3510 (LPCWSTR
)lpPassword
);
3511 if (dwError
!= ERROR_SUCCESS
)
3516 /* Delete the password */
3517 dwError
= ScmSetServicePassword(lpService
->szServiceName
,
3519 if (dwError
== ERROR_FILE_NOT_FOUND
)
3520 dwError
= ERROR_SUCCESS
;
3522 if (dwError
!= ERROR_SUCCESS
)
3528 /* Unlock the service database */
3529 ScmUnlockDatabase();
3531 if (hServiceKey
!= NULL
)
3532 RegCloseKey(hServiceKey
);
3534 DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError
);
3541 DWORD
RCreateServiceA(
3542 SC_RPC_HANDLE hSCManager
,
3543 LPSTR lpServiceName
,
3544 LPSTR lpDisplayName
,
3545 DWORD dwDesiredAccess
,
3546 DWORD dwServiceType
,
3548 DWORD dwErrorControl
,
3549 LPSTR lpBinaryPathName
,
3550 LPSTR lpLoadOrderGroup
,
3552 LPBYTE lpDependencies
,
3554 LPSTR lpServiceStartName
,
3557 LPSC_RPC_HANDLE lpServiceHandle
)
3559 DWORD dwError
= ERROR_SUCCESS
;
3560 LPWSTR lpServiceNameW
= NULL
;
3561 LPWSTR lpDisplayNameW
= NULL
;
3562 LPWSTR lpBinaryPathNameW
= NULL
;
3563 LPWSTR lpLoadOrderGroupW
= NULL
;
3564 LPWSTR lpDependenciesW
= NULL
;
3565 LPWSTR lpServiceStartNameW
= NULL
;
3566 DWORD dwDependenciesLength
= 0;
3573 len
= MultiByteToWideChar(CP_ACP
, 0, lpServiceName
, -1, NULL
, 0);
3574 lpServiceNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3575 if (!lpServiceNameW
)
3577 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3580 MultiByteToWideChar(CP_ACP
, 0, lpServiceName
, -1, lpServiceNameW
, len
);
3585 len
= MultiByteToWideChar(CP_ACP
, 0, lpDisplayName
, -1, NULL
, 0);
3586 lpDisplayNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3587 if (!lpDisplayNameW
)
3589 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3592 MultiByteToWideChar(CP_ACP
, 0, lpDisplayName
, -1, lpDisplayNameW
, len
);
3595 if (lpBinaryPathName
)
3597 len
= MultiByteToWideChar(CP_ACP
, 0, lpBinaryPathName
, -1, NULL
, 0);
3598 lpBinaryPathNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3599 if (!lpBinaryPathNameW
)
3601 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3604 MultiByteToWideChar(CP_ACP
, 0, lpBinaryPathName
, -1, lpBinaryPathNameW
, len
);
3607 if (lpLoadOrderGroup
)
3609 len
= MultiByteToWideChar(CP_ACP
, 0, lpLoadOrderGroup
, -1, NULL
, 0);
3610 lpLoadOrderGroupW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3611 if (!lpLoadOrderGroupW
)
3613 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3616 MultiByteToWideChar(CP_ACP
, 0, lpLoadOrderGroup
, -1, lpLoadOrderGroupW
, len
);
3621 lpStr
= (LPCSTR
)lpDependencies
;
3624 cchLength
= strlen(lpStr
) + 1;
3625 dwDependenciesLength
+= (DWORD
)cchLength
;
3626 lpStr
= lpStr
+ cchLength
;
3628 dwDependenciesLength
++;
3630 lpDependenciesW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwDependenciesLength
* sizeof(WCHAR
));
3631 if (!lpDependenciesW
)
3633 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3636 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)lpDependencies
, dwDependenciesLength
, lpDependenciesW
, dwDependenciesLength
);
3639 if (lpServiceStartName
)
3641 len
= MultiByteToWideChar(CP_ACP
, 0, lpServiceStartName
, -1, NULL
, 0);
3642 lpServiceStartNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3643 if (!lpServiceStartNameW
)
3645 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3648 MultiByteToWideChar(CP_ACP
, 0, lpServiceStartName
, -1, lpServiceStartNameW
, len
);
3651 dwError
= RCreateServiceW(hSCManager
,
3661 (LPBYTE
)lpDependenciesW
,
3662 dwDependenciesLength
,
3663 lpServiceStartNameW
,
3669 if (lpServiceNameW
!=NULL
)
3670 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
3672 if (lpDisplayNameW
!= NULL
)
3673 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
3675 if (lpBinaryPathNameW
!= NULL
)
3676 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW
);
3678 if (lpLoadOrderGroupW
!= NULL
)
3679 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3681 if (lpDependenciesW
!= NULL
)
3682 HeapFree(GetProcessHeap(), 0, lpDependenciesW
);
3684 if (lpServiceStartNameW
!= NULL
)
3685 HeapFree(GetProcessHeap(), 0, lpServiceStartNameW
);
3692 DWORD
REnumDependentServicesA(
3693 SC_RPC_HANDLE hService
,
3694 DWORD dwServiceState
,
3697 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
3698 LPBOUNDED_DWORD_256K lpServicesReturned
)
3700 DWORD dwError
= ERROR_SUCCESS
;
3701 DWORD dwServicesReturned
= 0;
3702 DWORD dwServiceCount
;
3703 HKEY hServicesKey
= NULL
;
3704 PSERVICE_HANDLE hSvc
;
3705 PSERVICE lpService
= NULL
;
3706 PSERVICE
*lpServicesArray
= NULL
;
3707 LPENUM_SERVICE_STATUSA lpServicesPtr
= NULL
;
3710 *pcbBytesNeeded
= 0;
3711 *lpServicesReturned
= 0;
3713 DPRINT("REnumDependentServicesA() called\n");
3715 hSvc
= ScmGetServiceFromHandle(hService
);
3718 DPRINT1("Invalid service handle!\n");
3719 return ERROR_INVALID_HANDLE
;
3722 lpService
= hSvc
->ServiceEntry
;
3724 /* Check access rights */
3725 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3726 SC_MANAGER_ENUMERATE_SERVICE
))
3728 DPRINT("Insufficient access rights! 0x%lx\n",
3729 hSvc
->Handle
.DesiredAccess
);
3730 return ERROR_ACCESS_DENIED
;
3733 /* Open the Services Reg key */
3734 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
3735 L
"System\\CurrentControlSet\\Services",
3740 if (dwError
!= ERROR_SUCCESS
)
3743 /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3744 both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3745 are the same for both. Verified in WINXP. */
3747 /* First determine the bytes needed and get the number of dependent services*/
3748 dwError
= Int_EnumDependentServicesW(hServicesKey
,
3753 &dwServicesReturned
);
3754 if (dwError
!= ERROR_SUCCESS
)
3757 /* If buffer size is less than the bytes needed or pointer is null*/
3758 if ((!lpServices
) || (cbBufSize
< *pcbBytesNeeded
))
3760 dwError
= ERROR_MORE_DATA
;
3764 /* Allocate memory for array of service pointers */
3765 lpServicesArray
= HeapAlloc(GetProcessHeap(),
3767 (dwServicesReturned
+ 1) * sizeof(PSERVICE
));
3768 if (!lpServicesArray
)
3770 DPRINT("Could not allocate a buffer!!\n");
3771 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3775 dwServicesReturned
= 0;
3776 *pcbBytesNeeded
= 0;
3778 dwError
= Int_EnumDependentServicesW(hServicesKey
,
3783 &dwServicesReturned
);
3784 if (dwError
!= ERROR_SUCCESS
)
3789 lpServicesPtr
= (LPENUM_SERVICE_STATUSA
)lpServices
;
3790 lpStr
= (LPSTR
)(lpServices
+ (dwServicesReturned
* sizeof(ENUM_SERVICE_STATUSA
)));
3792 /* Copy EnumDepenedentService to Buffer */
3793 for (dwServiceCount
= 0; dwServiceCount
< dwServicesReturned
; dwServiceCount
++)
3795 lpService
= lpServicesArray
[dwServiceCount
];
3797 /* Copy the status info */
3798 memcpy(&lpServicesPtr
->ServiceStatus
,
3800 sizeof(SERVICE_STATUS
));
3802 /* Copy display name */
3803 WideCharToMultiByte(CP_ACP
,
3805 lpService
->lpDisplayName
,
3808 (int)wcslen(lpService
->lpDisplayName
),
3811 lpServicesPtr
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
3812 lpStr
+= strlen(lpStr
) + 1;
3814 /* Copy service name */
3815 WideCharToMultiByte(CP_ACP
,
3817 lpService
->lpServiceName
,
3820 (int)wcslen(lpService
->lpServiceName
),
3823 lpServicesPtr
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
3824 lpStr
+= strlen(lpStr
) + 1;
3829 *lpServicesReturned
= dwServicesReturned
;
3832 if (lpServicesArray
)
3833 HeapFree(GetProcessHeap(), 0, lpServicesArray
);
3835 RegCloseKey(hServicesKey
);
3837 DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError
);
3844 DWORD
REnumServicesStatusA(
3845 SC_RPC_HANDLE hSCManager
,
3846 DWORD dwServiceType
,
3847 DWORD dwServiceState
,
3850 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
3851 LPBOUNDED_DWORD_256K lpServicesReturned
,
3852 LPBOUNDED_DWORD_256K lpResumeHandle
)
3854 LPENUM_SERVICE_STATUSW lpStatusPtrW
= NULL
;
3855 LPENUM_SERVICE_STATUSW lpStatusPtrIncrW
;
3856 LPENUM_SERVICE_STATUSA lpStatusPtrA
= NULL
;
3857 LPWSTR lpStringPtrW
;
3860 DWORD dwServiceCount
;
3862 DPRINT("REnumServicesStatusA() called\n");
3864 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
3866 return ERROR_INVALID_ADDRESS
;
3869 if ((dwBufSize
> 0) && (lpBuffer
))
3871 lpStatusPtrW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwBufSize
);
3874 DPRINT("Failed to allocate buffer!\n");
3875 return ERROR_NOT_ENOUGH_MEMORY
;
3879 dwError
= REnumServicesStatusW(hSCManager
,
3882 (LPBYTE
)lpStatusPtrW
,
3888 /* if no services were returned then we are Done */
3889 if (*lpServicesReturned
== 0)
3892 lpStatusPtrIncrW
= lpStatusPtrW
;
3893 lpStatusPtrA
= (LPENUM_SERVICE_STATUSA
)lpBuffer
;
3894 lpStringPtrA
= (LPSTR
)((ULONG_PTR
)lpBuffer
+
3895 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUSA
));
3896 lpStringPtrW
= (LPWSTR
)((ULONG_PTR
)lpStatusPtrW
+
3897 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUSW
));
3899 for (dwServiceCount
= 0; dwServiceCount
< *lpServicesReturned
; dwServiceCount
++)
3901 /* Copy the service name */
3902 WideCharToMultiByte(CP_ACP
,
3907 (int)wcslen(lpStringPtrW
),
3911 lpStatusPtrA
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
3912 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
3913 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
3915 /* Copy the display name */
3916 WideCharToMultiByte(CP_ACP
,
3921 (int)wcslen(lpStringPtrW
),
3925 lpStatusPtrA
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
3926 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
3927 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
3929 /* Copy the status information */
3930 memcpy(&lpStatusPtrA
->ServiceStatus
,
3931 &lpStatusPtrIncrW
->ServiceStatus
,
3932 sizeof(SERVICE_STATUS
));
3940 HeapFree(GetProcessHeap(), 0, lpStatusPtrW
);
3942 DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError
);
3949 DWORD
ROpenSCManagerA(
3950 LPSTR lpMachineName
,
3951 LPSTR lpDatabaseName
,
3952 DWORD dwDesiredAccess
,
3953 LPSC_RPC_HANDLE lpScHandle
)
3955 UNICODE_STRING MachineName
;
3956 UNICODE_STRING DatabaseName
;
3959 DPRINT("ROpenSCManagerA() called\n");
3962 RtlCreateUnicodeStringFromAsciiz(&MachineName
,
3966 RtlCreateUnicodeStringFromAsciiz(&DatabaseName
,
3969 dwError
= ROpenSCManagerW(lpMachineName
? MachineName
.Buffer
: NULL
,
3970 lpDatabaseName
? DatabaseName
.Buffer
: NULL
,
3975 RtlFreeUnicodeString(&MachineName
);
3978 RtlFreeUnicodeString(&DatabaseName
);
3985 DWORD
ROpenServiceA(
3986 SC_RPC_HANDLE hSCManager
,
3987 LPSTR lpServiceName
,
3988 DWORD dwDesiredAccess
,
3989 LPSC_RPC_HANDLE lpServiceHandle
)
3991 UNICODE_STRING ServiceName
;
3994 DPRINT("ROpenServiceA() called\n");
3997 RtlCreateUnicodeStringFromAsciiz(&ServiceName
,
4000 dwError
= ROpenServiceW(hSCManager
,
4001 lpServiceName
? ServiceName
.Buffer
: NULL
,
4006 RtlFreeUnicodeString(&ServiceName
);
4013 DWORD
RQueryServiceConfigA(
4014 SC_RPC_HANDLE hService
,
4015 LPBYTE lpBuf
, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
4017 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
4019 LPQUERY_SERVICE_CONFIGA lpServiceConfig
= (LPQUERY_SERVICE_CONFIGA
)lpBuf
;
4020 DWORD dwError
= ERROR_SUCCESS
;
4021 PSERVICE_HANDLE hSvc
;
4022 PSERVICE lpService
= NULL
;
4023 HKEY hServiceKey
= NULL
;
4024 LPWSTR lpImagePath
= NULL
;
4025 LPWSTR lpServiceStartName
= NULL
;
4026 LPWSTR lpDependencies
= NULL
;
4027 DWORD dwDependenciesLength
= 0;
4028 DWORD dwRequiredSize
;
4029 CHAR lpEmptyString
[]={0,0};
4032 DPRINT("RQueryServiceConfigA() called\n");
4035 return ERROR_SHUTDOWN_IN_PROGRESS
;
4037 hSvc
= ScmGetServiceFromHandle(hService
);
4040 DPRINT1("Invalid service handle!\n");
4041 return ERROR_INVALID_HANDLE
;
4044 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
4045 SERVICE_QUERY_CONFIG
))
4047 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
4048 return ERROR_ACCESS_DENIED
;
4051 lpService
= hSvc
->ServiceEntry
;
4052 if (lpService
== NULL
)
4054 DPRINT("lpService == NULL!\n");
4055 return ERROR_INVALID_HANDLE
;
4058 /* Lock the service database shared */
4059 ScmLockDatabaseShared();
4061 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
4064 if (dwError
!= ERROR_SUCCESS
)
4067 /* Read the image path */
4068 dwError
= ScmReadString(hServiceKey
,
4071 if (dwError
!= ERROR_SUCCESS
)
4074 /* Read the service start name */
4075 ScmReadString(hServiceKey
,
4077 &lpServiceStartName
);
4079 /* Read the dependencies */
4080 ScmReadDependencies(hServiceKey
,
4082 &dwDependenciesLength
);
4084 dwRequiredSize
= sizeof(QUERY_SERVICE_CONFIGA
);
4086 if (lpImagePath
!= NULL
)
4087 dwRequiredSize
+= (DWORD
)(wcslen(lpImagePath
) + 1);
4089 dwRequiredSize
+= 2;
4091 if ((lpService
->lpGroup
!= NULL
) && (lpService
->lpGroup
->lpGroupName
!= NULL
))
4092 dwRequiredSize
+= (DWORD
)(wcslen(lpService
->lpGroup
->lpGroupName
) + 1);
4094 dwRequiredSize
+= 2;
4096 /* Add Dependencies length */
4097 if (lpDependencies
!= NULL
)
4098 dwRequiredSize
+= dwDependenciesLength
;
4100 dwRequiredSize
+= 2;
4102 if (lpServiceStartName
!= NULL
)
4103 dwRequiredSize
+= (DWORD
)(wcslen(lpServiceStartName
) + 1);
4105 dwRequiredSize
+= 2;
4107 if (lpService
->lpDisplayName
!= NULL
)
4108 dwRequiredSize
+= (DWORD
)(wcslen(lpService
->lpDisplayName
) + 1);
4110 dwRequiredSize
+= 2;
4112 if (lpServiceConfig
== NULL
|| cbBufSize
< dwRequiredSize
)
4114 dwError
= ERROR_INSUFFICIENT_BUFFER
;
4118 lpServiceConfig
->dwServiceType
= lpService
->Status
.dwServiceType
;
4119 lpServiceConfig
->dwStartType
= lpService
->dwStartType
;
4120 lpServiceConfig
->dwErrorControl
= lpService
->dwErrorControl
;
4121 lpServiceConfig
->dwTagId
= lpService
->dwTag
;
4123 lpStr
= (LPSTR
)(lpServiceConfig
+ 1);
4125 /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
4126 Verified in WINXP */
4130 WideCharToMultiByte(CP_ACP
,
4135 (int)(wcslen(lpImagePath
) + 1),
4141 strcpy(lpStr
, lpEmptyString
);
4144 lpServiceConfig
->lpBinaryPathName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4145 lpStr
+= (strlen((LPSTR
)lpStr
) + 1);
4147 if (lpService
->lpGroup
&& lpService
->lpGroup
->lpGroupName
)
4149 WideCharToMultiByte(CP_ACP
,
4151 lpService
->lpGroup
->lpGroupName
,
4154 (int)(wcslen(lpService
->lpGroup
->lpGroupName
) + 1),
4160 strcpy(lpStr
, lpEmptyString
);
4163 lpServiceConfig
->lpLoadOrderGroup
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4164 lpStr
+= (strlen(lpStr
) + 1);
4166 /* Append Dependencies */
4169 WideCharToMultiByte(CP_ACP
,
4172 dwDependenciesLength
,
4174 dwDependenciesLength
,
4180 strcpy(lpStr
, lpEmptyString
);
4183 lpServiceConfig
->lpDependencies
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4185 lpStr
+= dwDependenciesLength
;
4187 lpStr
+= (strlen(lpStr
) + 1);
4189 if (lpServiceStartName
)
4191 WideCharToMultiByte(CP_ACP
,
4196 (int)(wcslen(lpServiceStartName
) + 1),
4202 strcpy(lpStr
, lpEmptyString
);
4205 lpServiceConfig
->lpServiceStartName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4206 lpStr
+= (strlen(lpStr
) + 1);
4208 if (lpService
->lpDisplayName
)
4210 WideCharToMultiByte(CP_ACP
,
4212 lpService
->lpDisplayName
,
4215 (int)(wcslen(lpService
->lpDisplayName
) + 1),
4221 strcpy(lpStr
, lpEmptyString
);
4224 lpServiceConfig
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4227 if (pcbBytesNeeded
!= NULL
)
4228 *pcbBytesNeeded
= dwRequiredSize
;
4231 /* Unlock the service database */
4232 ScmUnlockDatabase();
4234 if (lpImagePath
!= NULL
)
4235 HeapFree(GetProcessHeap(), 0, lpImagePath
);
4237 if (lpServiceStartName
!= NULL
)
4238 HeapFree(GetProcessHeap(), 0, lpServiceStartName
);
4240 if (lpDependencies
!= NULL
)
4241 HeapFree(GetProcessHeap(), 0, lpDependencies
);
4243 if (hServiceKey
!= NULL
)
4244 RegCloseKey(hServiceKey
);
4246 DPRINT("RQueryServiceConfigA() done\n");
4253 DWORD
RQueryServiceLockStatusA(
4254 SC_RPC_HANDLE hSCManager
,
4255 LPBYTE lpBuf
, // LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
4257 LPBOUNDED_DWORD_4K pcbBytesNeeded
)
4259 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
= (LPQUERY_SERVICE_LOCK_STATUSA
)lpBuf
;
4260 PMANAGER_HANDLE hMgr
;
4261 DWORD dwRequiredSize
;
4263 if (!lpLockStatus
|| !pcbBytesNeeded
)
4264 return ERROR_INVALID_PARAMETER
;
4266 hMgr
= ScmGetServiceManagerFromHandle(hSCManager
);
4269 DPRINT1("Invalid service manager handle!\n");
4270 return ERROR_INVALID_HANDLE
;
4273 if (!RtlAreAllAccessesGranted(hMgr
->Handle
.DesiredAccess
,
4274 SC_MANAGER_QUERY_LOCK_STATUS
))
4276 DPRINT("Insufficient access rights! 0x%lx\n", hMgr
->Handle
.DesiredAccess
);
4277 return ERROR_ACCESS_DENIED
;
4280 /* FIXME: we need to compute instead the real length of the owner name */
4281 dwRequiredSize
= sizeof(QUERY_SERVICE_LOCK_STATUSA
) + sizeof(CHAR
);
4282 *pcbBytesNeeded
= dwRequiredSize
;
4284 if (cbBufSize
< dwRequiredSize
)
4285 return ERROR_INSUFFICIENT_BUFFER
;
4287 ScmQueryServiceLockStatusA(lpLockStatus
);
4289 return ERROR_SUCCESS
;
4294 DWORD
RStartServiceA(
4295 SC_RPC_HANDLE hService
,
4297 LPSTRING_PTRSA argv
)
4299 DWORD dwError
= ERROR_SUCCESS
;
4300 PSERVICE_HANDLE hSvc
;
4301 PSERVICE lpService
= NULL
;
4302 LPWSTR
*lpVector
= NULL
;
4306 DPRINT("RStartServiceA() called\n");
4309 return ERROR_SHUTDOWN_IN_PROGRESS
;
4311 hSvc
= ScmGetServiceFromHandle(hService
);
4314 DPRINT1("Invalid service handle!\n");
4315 return ERROR_INVALID_HANDLE
;
4318 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
4321 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
4322 return ERROR_ACCESS_DENIED
;
4325 lpService
= hSvc
->ServiceEntry
;
4326 if (lpService
== NULL
)
4328 DPRINT("lpService == NULL!\n");
4329 return ERROR_INVALID_HANDLE
;
4332 if (lpService
->dwStartType
== SERVICE_DISABLED
)
4333 return ERROR_SERVICE_DISABLED
;
4335 if (lpService
->bDeleted
)
4336 return ERROR_SERVICE_MARKED_FOR_DELETE
;
4338 /* Build a Unicode argument vector */
4341 lpVector
= HeapAlloc(GetProcessHeap(),
4343 argc
* sizeof(LPWSTR
));
4344 if (lpVector
== NULL
)
4345 return ERROR_NOT_ENOUGH_MEMORY
;
4347 for (i
= 0; i
< argc
; i
++)
4349 dwLength
= MultiByteToWideChar(CP_ACP
,
4356 lpVector
[i
] = HeapAlloc(GetProcessHeap(),
4358 dwLength
* sizeof(WCHAR
));
4359 if (lpVector
[i
] == NULL
)
4361 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
4365 MultiByteToWideChar(CP_ACP
,
4374 /* Start the service */
4375 dwError
= ScmStartService(lpService
, argc
, lpVector
);
4378 /* Free the Unicode argument vector */
4379 if (lpVector
!= NULL
)
4381 for (i
= 0; i
< argc
; i
++)
4383 if (lpVector
[i
] != NULL
)
4384 HeapFree(GetProcessHeap(), 0, lpVector
[i
]);
4386 HeapFree(GetProcessHeap(), 0, lpVector
);
4394 DWORD
RGetServiceDisplayNameA(
4395 SC_RPC_HANDLE hSCManager
,
4396 LPCSTR lpServiceName
,
4397 LPSTR lpDisplayName
,
4398 LPBOUNDED_DWORD_4K lpcchBuffer
)
4400 // PMANAGER_HANDLE hManager;
4401 PSERVICE lpService
= NULL
;
4404 LPWSTR lpServiceNameW
;
4406 DPRINT("RGetServiceDisplayNameA() called\n");
4407 DPRINT("hSCManager = %p\n", hSCManager
);
4408 DPRINT("lpServiceName: %s\n", lpServiceName
);
4409 DPRINT("lpDisplayName: %p\n", lpDisplayName
);
4410 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
4412 // hManager = (PMANAGER_HANDLE)hSCManager;
4413 // if (hManager->Handle.Tag != MANAGER_TAG)
4415 // DPRINT("Invalid manager handle!\n");
4416 // return ERROR_INVALID_HANDLE;
4419 if (lpServiceName
!= NULL
)
4421 dwLength
= (DWORD
)(strlen(lpServiceName
) + 1);
4422 lpServiceNameW
= HeapAlloc(GetProcessHeap(),
4424 dwLength
* sizeof(WCHAR
));
4425 if (!lpServiceNameW
)
4426 return ERROR_NOT_ENOUGH_MEMORY
;
4428 MultiByteToWideChar(CP_ACP
,
4435 lpService
= ScmGetServiceEntryByName(lpServiceNameW
);
4437 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
4440 if (lpService
== NULL
)
4442 DPRINT("Could not find a service!\n");
4444 /* If the service could not be found and lpcchBuffer is 0, windows
4445 puts null in lpDisplayName and puts 1 in lpcchBuffer */
4446 if (*lpcchBuffer
== 0)
4449 if (lpDisplayName
!= NULL
)
4454 return ERROR_SERVICE_DOES_NOT_EXIST
;
4457 if (!lpService
->lpDisplayName
)
4459 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
4460 if (lpDisplayName
!= NULL
&&
4461 *lpcchBuffer
> dwLength
)
4463 WideCharToMultiByte(CP_ACP
,
4465 lpService
->lpServiceName
,
4466 (int)wcslen(lpService
->lpServiceName
),
4471 return ERROR_SUCCESS
;
4476 dwLength
= (DWORD
)wcslen(lpService
->lpDisplayName
);
4477 if (lpDisplayName
!= NULL
&&
4478 *lpcchBuffer
> dwLength
)
4480 WideCharToMultiByte(CP_ACP
,
4482 lpService
->lpDisplayName
,
4483 (int)wcslen(lpService
->lpDisplayName
),
4488 return ERROR_SUCCESS
;
4492 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
4494 *lpcchBuffer
= dwLength
* 2;
4501 DWORD
RGetServiceKeyNameA(
4502 SC_RPC_HANDLE hSCManager
,
4503 LPCSTR lpDisplayName
,
4504 LPSTR lpServiceName
,
4505 LPBOUNDED_DWORD_4K lpcchBuffer
)
4510 LPWSTR lpDisplayNameW
;
4512 DPRINT("RGetServiceKeyNameA() called\n");
4513 DPRINT("hSCManager = %p\n", hSCManager
);
4514 DPRINT("lpDisplayName: %s\n", lpDisplayName
);
4515 DPRINT("lpServiceName: %p\n", lpServiceName
);
4516 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
4518 dwLength
= (DWORD
)(strlen(lpDisplayName
) + 1);
4519 lpDisplayNameW
= HeapAlloc(GetProcessHeap(),
4521 dwLength
* sizeof(WCHAR
));
4522 if (!lpDisplayNameW
)
4523 return ERROR_NOT_ENOUGH_MEMORY
;
4525 MultiByteToWideChar(CP_ACP
,
4532 lpService
= ScmGetServiceEntryByDisplayName(lpDisplayNameW
);
4534 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
4536 if (lpService
== NULL
)
4538 DPRINT("Could not find the service!\n");
4540 /* If the service could not be found and lpcchBuffer is 0,
4541 put null in lpDisplayName and puts 1 in lpcchBuffer, verified WINXP. */
4542 if (*lpcchBuffer
== 0)
4545 if (lpServiceName
!= NULL
)
4551 return ERROR_SERVICE_DOES_NOT_EXIST
;
4554 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
4555 if (lpServiceName
!= NULL
&&
4556 *lpcchBuffer
> dwLength
)
4558 WideCharToMultiByte(CP_ACP
,
4560 lpService
->lpServiceName
,
4561 (int)wcslen(lpService
->lpServiceName
),
4566 return ERROR_SUCCESS
;
4569 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
4571 *lpcchBuffer
= dwLength
* 2;
4578 DWORD
RI_ScGetCurrentGroupStateW(
4579 SC_RPC_HANDLE hSCManager
,
4580 LPWSTR lpLoadOrderGroup
,
4584 return ERROR_CALL_NOT_IMPLEMENTED
;
4589 DWORD
REnumServiceGroupW(
4590 SC_RPC_HANDLE hSCManager
,
4591 DWORD dwServiceType
,
4592 DWORD dwServiceState
,
4595 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
4596 LPBOUNDED_DWORD_256K lpServicesReturned
,
4597 LPBOUNDED_DWORD_256K lpResumeIndex
,
4598 LPCWSTR pszGroupName
)
4600 PMANAGER_HANDLE hManager
;
4602 DWORD dwError
= ERROR_SUCCESS
;
4603 PLIST_ENTRY ServiceEntry
;
4604 PSERVICE CurrentService
;
4606 DWORD dwRequiredSize
;
4607 DWORD dwServiceCount
;
4609 DWORD dwLastResumeCount
= 0;
4610 LPENUM_SERVICE_STATUSW lpStatusPtr
;
4613 DPRINT("REnumServiceGroupW() called\n");
4616 return ERROR_SHUTDOWN_IN_PROGRESS
;
4618 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
4619 if (hManager
== NULL
)
4621 DPRINT1("Invalid service manager handle!\n");
4622 return ERROR_INVALID_HANDLE
;
4625 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
4627 return ERROR_INVALID_ADDRESS
;
4630 *pcbBytesNeeded
= 0;
4631 *lpServicesReturned
= 0;
4633 if ((dwServiceType
== 0) ||
4634 ((dwServiceType
& ~SERVICE_TYPE_ALL
) != 0))
4636 DPRINT("Not a valid Service Type!\n");
4637 return ERROR_INVALID_PARAMETER
;
4640 if ((dwServiceState
== 0) ||
4641 ((dwServiceState
& ~SERVICE_STATE_ALL
) != 0))
4643 DPRINT("Not a valid Service State!\n");
4644 return ERROR_INVALID_PARAMETER
;
4647 /* Check access rights */
4648 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
4649 SC_MANAGER_ENUMERATE_SERVICE
))
4651 DPRINT("Insufficient access rights! 0x%lx\n",
4652 hManager
->Handle
.DesiredAccess
);
4653 return ERROR_ACCESS_DENIED
;
4657 dwLastResumeCount
= *lpResumeIndex
;
4659 /* Lock the service database shared */
4660 ScmLockDatabaseShared();
4662 lpService
= ScmGetServiceEntryByResumeCount(dwLastResumeCount
);
4663 if (lpService
== NULL
)
4665 dwError
= ERROR_SUCCESS
;
4672 for (ServiceEntry
= &lpService
->ServiceListEntry
;
4673 ServiceEntry
!= &ServiceListHead
;
4674 ServiceEntry
= ServiceEntry
->Flink
)
4676 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
4680 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
4683 dwState
= SERVICE_ACTIVE
;
4684 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
4685 dwState
= SERVICE_INACTIVE
;
4687 if ((dwState
& dwServiceState
) == 0)
4692 if (*pszGroupName
== 0)
4694 if (CurrentService
->lpGroup
!= NULL
)
4699 if ((CurrentService
->lpGroup
== NULL
) ||
4700 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
4705 dwSize
= sizeof(ENUM_SERVICE_STATUSW
) +
4706 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
4707 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
4709 if (dwRequiredSize
+ dwSize
> cbBufSize
)
4711 DPRINT("Service name: %S no fit\n", CurrentService
->lpServiceName
);
4715 DPRINT("Service name: %S fit\n", CurrentService
->lpServiceName
);
4716 dwRequiredSize
+= dwSize
;
4718 dwLastResumeCount
= CurrentService
->dwResumeCount
;
4721 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize
);
4722 DPRINT("dwServiceCount: %lu\n", dwServiceCount
);
4725 ServiceEntry
!= &ServiceListHead
;
4726 ServiceEntry
= ServiceEntry
->Flink
)
4728 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
4732 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
4735 dwState
= SERVICE_ACTIVE
;
4736 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
4737 dwState
= SERVICE_INACTIVE
;
4739 if ((dwState
& dwServiceState
) == 0)
4744 if (*pszGroupName
== 0)
4746 if (CurrentService
->lpGroup
!= NULL
)
4751 if ((CurrentService
->lpGroup
== NULL
) ||
4752 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
4757 dwRequiredSize
+= (sizeof(ENUM_SERVICE_STATUSW
) +
4758 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
4759 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
)));
4761 dwError
= ERROR_MORE_DATA
;
4764 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize
);
4767 *lpResumeIndex
= dwLastResumeCount
;
4769 *lpServicesReturned
= dwServiceCount
;
4770 *pcbBytesNeeded
= dwRequiredSize
;
4772 lpStatusPtr
= (LPENUM_SERVICE_STATUSW
)lpBuffer
;
4773 lpStringPtr
= (LPWSTR
)((ULONG_PTR
)lpBuffer
+
4774 dwServiceCount
* sizeof(ENUM_SERVICE_STATUSW
));
4777 for (ServiceEntry
= &lpService
->ServiceListEntry
;
4778 ServiceEntry
!= &ServiceListHead
;
4779 ServiceEntry
= ServiceEntry
->Flink
)
4781 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
4785 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
4788 dwState
= SERVICE_ACTIVE
;
4789 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
4790 dwState
= SERVICE_INACTIVE
;
4792 if ((dwState
& dwServiceState
) == 0)
4797 if (*pszGroupName
== 0)
4799 if (CurrentService
->lpGroup
!= NULL
)
4804 if ((CurrentService
->lpGroup
== NULL
) ||
4805 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
4810 dwSize
= sizeof(ENUM_SERVICE_STATUSW
) +
4811 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
4812 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
4814 if (dwRequiredSize
+ dwSize
> cbBufSize
)
4817 /* Copy the service name */
4818 wcscpy(lpStringPtr
, CurrentService
->lpServiceName
);
4819 lpStatusPtr
->lpServiceName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
4820 lpStringPtr
+= (wcslen(CurrentService
->lpServiceName
) + 1);
4822 /* Copy the display name */
4823 wcscpy(lpStringPtr
, CurrentService
->lpDisplayName
);
4824 lpStatusPtr
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
4825 lpStringPtr
+= (wcslen(CurrentService
->lpDisplayName
) + 1);
4827 /* Copy the status information */
4828 memcpy(&lpStatusPtr
->ServiceStatus
,
4829 &CurrentService
->Status
,
4830 sizeof(SERVICE_STATUS
));
4833 dwRequiredSize
+= dwSize
;
4836 if (dwError
== ERROR_SUCCESS
)
4838 *pcbBytesNeeded
= 0;
4839 if (lpResumeIndex
) *lpResumeIndex
= 0;
4843 /* Unlock the service database */
4844 ScmUnlockDatabase();
4846 DPRINT("REnumServiceGroupW() done (Error %lu)\n", dwError
);
4853 DWORD
RChangeServiceConfig2A(
4854 SC_RPC_HANDLE hService
,
4855 SC_RPC_CONFIG_INFOA Info
)
4857 SC_RPC_CONFIG_INFOW InfoW
;
4858 DWORD dwRet
, dwLength
;
4861 DPRINT("RChangeServiceConfig2A() called\n");
4862 DPRINT("dwInfoLevel = %lu\n", Info
.dwInfoLevel
);
4864 InfoW
.dwInfoLevel
= Info
.dwInfoLevel
;
4866 if (InfoW
.dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
4868 LPSERVICE_DESCRIPTIONW lpServiceDescriptionW
;
4869 LPSERVICE_DESCRIPTIONA lpServiceDescriptionA
;
4871 lpServiceDescriptionA
= Info
.psd
;
4873 if (lpServiceDescriptionA
&&
4874 lpServiceDescriptionA
->lpDescription
)
4876 dwLength
= (DWORD
)((strlen(lpServiceDescriptionA
->lpDescription
) + 1) * sizeof(WCHAR
));
4878 lpServiceDescriptionW
= HeapAlloc(GetProcessHeap(),
4880 dwLength
+ sizeof(SERVICE_DESCRIPTIONW
));
4881 if (!lpServiceDescriptionW
)
4883 return ERROR_NOT_ENOUGH_MEMORY
;
4886 lpServiceDescriptionW
->lpDescription
= (LPWSTR
)(lpServiceDescriptionW
+ 1);
4888 MultiByteToWideChar(CP_ACP
,
4890 lpServiceDescriptionA
->lpDescription
,
4892 lpServiceDescriptionW
->lpDescription
,
4895 ptr
= lpServiceDescriptionW
;
4896 InfoW
.psd
= lpServiceDescriptionW
;
4899 else if (Info
.dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
4901 LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW
;
4902 LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA
;
4903 DWORD dwRebootLen
= 0;
4904 DWORD dwCommandLen
= 0;
4905 DWORD dwActionArrayLen
= 0;
4906 LPWSTR lpStr
= NULL
;
4908 lpServiceFailureActionsA
= Info
.psfa
;
4910 if (lpServiceFailureActionsA
)
4913 * The following code is inspired by the
4914 * SERVICE_CONFIG_FAILURE_ACTIONS case of
4915 * the RQueryServiceConfig2W function.
4918 /* Retrieve the needed length for the two data strings */
4919 if (lpServiceFailureActionsA
->lpRebootMsg
)
4921 dwRebootLen
= (DWORD
)((strlen(lpServiceFailureActionsA
->lpRebootMsg
) + 1) * sizeof(WCHAR
));
4923 if (lpServiceFailureActionsA
->lpCommand
)
4925 dwCommandLen
= (DWORD
)((strlen(lpServiceFailureActionsA
->lpCommand
) + 1) * sizeof(WCHAR
));
4929 * Retrieve the size of the lpsaActions array if needed.
4930 * We will copy the lpsaActions array only if there is at
4931 * least one action AND that the original array is valid.
4933 if (lpServiceFailureActionsA
->cActions
> 0 && lpServiceFailureActionsA
->lpsaActions
)
4935 dwActionArrayLen
= lpServiceFailureActionsA
->cActions
* sizeof(SC_ACTION
);
4938 /* Compute the total length for the UNICODE structure, including data */
4939 dwLength
= sizeof(SERVICE_FAILURE_ACTIONSW
) +
4940 dwActionArrayLen
+ dwRebootLen
+ dwCommandLen
;
4942 /* Allocate the structure */
4943 lpServiceFailureActionsW
= HeapAlloc(GetProcessHeap(),
4946 if (!lpServiceFailureActionsW
)
4948 return ERROR_NOT_ENOUGH_MEMORY
;
4951 /* Copy the members */
4952 lpServiceFailureActionsW
->dwResetPeriod
= lpServiceFailureActionsA
->dwResetPeriod
;
4953 lpServiceFailureActionsW
->cActions
= lpServiceFailureActionsA
->cActions
;
4955 /* Copy the lpsaActions array if needed */
4956 if (dwActionArrayLen
> 0)
4958 /* The storage zone is just after the end of the SERVICE_FAILURE_ACTIONSW structure */
4959 lpServiceFailureActionsW
->lpsaActions
= (LPSC_ACTION
)((ULONG_PTR
)(lpServiceFailureActionsW
+ 1));
4961 /* dwActionArrayLen == lpServiceFailureActionsW->cActions * sizeof(SC_ACTION) */
4962 RtlCopyMemory(lpServiceFailureActionsW
->lpsaActions
,
4963 lpServiceFailureActionsA
->lpsaActions
,
4968 /* No lpsaActions array */
4969 lpServiceFailureActionsW
->lpsaActions
= NULL
;
4971 /* The data strings are stored just after the lpsaActions array */
4972 lpStr
= (LPWSTR
)((ULONG_PTR
)(lpServiceFailureActionsW
+ 1) + dwActionArrayLen
);
4975 * Convert the data strings to UNICODE
4978 lpServiceFailureActionsW
->lpRebootMsg
= NULL
;
4979 lpServiceFailureActionsW
->lpCommand
= NULL
;
4983 /* lpRebootMsg points just after the lpsaActions array */
4984 lpServiceFailureActionsW
->lpRebootMsg
= lpStr
;
4986 MultiByteToWideChar(CP_ACP
,
4988 lpServiceFailureActionsA
->lpRebootMsg
,
4990 lpServiceFailureActionsW
->lpRebootMsg
,
4993 lpStr
+= dwRebootLen
/ sizeof(WCHAR
);
4998 /* lpRebootMsg points just after the lpRebootMsg data string */
4999 lpServiceFailureActionsW
->lpCommand
= lpStr
;
5001 MultiByteToWideChar(CP_ACP
,
5003 lpServiceFailureActionsA
->lpCommand
,
5005 lpServiceFailureActionsW
->lpCommand
,
5009 /* Set the pointers */
5010 ptr
= lpServiceFailureActionsW
;
5011 InfoW
.psfa
= lpServiceFailureActionsW
;
5015 dwRet
= RChangeServiceConfig2W(hService
, InfoW
);
5017 HeapFree(GetProcessHeap(), 0, ptr
);
5024 ScmSetFailureActions(HKEY hServiceKey
,
5025 LPSERVICE_FAILURE_ACTIONSW lpFailureActions
)
5027 LPSERVICE_FAILURE_ACTIONSW lpReadBuffer
= NULL
;
5028 LPSERVICE_FAILURE_ACTIONSW lpWriteBuffer
= NULL
;
5029 DWORD dwRequiredSize
= 0;
5033 /* There is nothing to be done if we have no failure actions */
5034 if (lpFailureActions
== NULL
)
5035 return ERROR_SUCCESS
;
5038 * 1- Retrieve the original value of FailureActions.
5041 /* Query value length */
5042 dwError
= RegQueryValueExW(hServiceKey
,
5048 if (dwError
!= ERROR_SUCCESS
&&
5049 dwError
!= ERROR_MORE_DATA
&&
5050 dwError
!= ERROR_FILE_NOT_FOUND
)
5053 dwRequiredSize
= (dwType
== REG_BINARY
) ? max(sizeof(SERVICE_FAILURE_ACTIONSW
), dwRequiredSize
)
5054 : sizeof(SERVICE_FAILURE_ACTIONSW
);
5056 /* Initialize the read buffer */
5057 lpReadBuffer
= HeapAlloc(GetProcessHeap(),
5060 if (lpReadBuffer
== NULL
)
5061 return ERROR_NOT_ENOUGH_MEMORY
;
5063 /* Now we can fill the read buffer */
5064 if (dwError
!= ERROR_FILE_NOT_FOUND
&&
5065 dwType
== REG_BINARY
)
5067 dwError
= RegQueryValueExW(hServiceKey
,
5071 (LPBYTE
)lpReadBuffer
,
5073 if (dwError
!= ERROR_SUCCESS
&&
5074 dwError
!= ERROR_FILE_NOT_FOUND
)
5077 if (dwRequiredSize
< sizeof(SERVICE_FAILURE_ACTIONSW
))
5078 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSW
);
5083 * The value of the error doesn't really matter, the only
5084 * important thing is that it must be != ERROR_SUCCESS.
5086 dwError
= ERROR_INVALID_DATA
;
5089 if (dwError
== ERROR_SUCCESS
)
5091 lpReadBuffer
->cActions
= min(lpReadBuffer
->cActions
, (dwRequiredSize
- sizeof(SERVICE_FAILURE_ACTIONSW
)) / sizeof(SC_ACTION
));
5092 lpReadBuffer
->lpsaActions
= (lpReadBuffer
->cActions
> 0 ? (LPSC_ACTION
)(lpReadBuffer
+ 1) : NULL
);
5096 lpReadBuffer
->dwResetPeriod
= 0;
5097 lpReadBuffer
->cActions
= 0;
5098 lpReadBuffer
->lpsaActions
= NULL
;
5101 lpReadBuffer
->lpRebootMsg
= NULL
;
5102 lpReadBuffer
->lpCommand
= NULL
;
5105 * 2- Initialize the new value to set.
5108 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSW
);
5110 if (lpFailureActions
->lpsaActions
== NULL
)
5113 * lpFailureActions->cActions is ignored.
5114 * Therefore we use the original values
5115 * of cActions and lpsaActions.
5117 dwRequiredSize
+= lpReadBuffer
->cActions
* sizeof(SC_ACTION
);
5122 * The reset period and array of failure actions
5123 * are deleted if lpFailureActions->cActions == 0 .
5125 dwRequiredSize
+= lpFailureActions
->cActions
* sizeof(SC_ACTION
);
5128 lpWriteBuffer
= HeapAlloc(GetProcessHeap(),
5131 if (lpWriteBuffer
== NULL
)
5133 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
5137 /* Clean the pointers as they have no meaning when the structure is stored in the registry */
5138 lpWriteBuffer
->lpRebootMsg
= NULL
;
5139 lpWriteBuffer
->lpCommand
= NULL
;
5140 lpWriteBuffer
->lpsaActions
= NULL
;
5142 /* Set the members */
5143 if (lpFailureActions
->lpsaActions
== NULL
)
5146 * lpFailureActions->dwResetPeriod and lpFailureActions->cActions are ignored.
5147 * Therefore we use the original values of dwResetPeriod, cActions and lpsaActions.
5149 lpWriteBuffer
->dwResetPeriod
= lpReadBuffer
->dwResetPeriod
;
5150 lpWriteBuffer
->cActions
= lpReadBuffer
->cActions
;
5152 if (lpReadBuffer
->lpsaActions
!= NULL
)
5154 memmove(lpWriteBuffer
+ 1,
5155 lpReadBuffer
->lpsaActions
,
5156 lpReadBuffer
->cActions
* sizeof(SC_ACTION
));
5161 if (lpFailureActions
->cActions
> 0)
5163 lpWriteBuffer
->dwResetPeriod
= lpFailureActions
->dwResetPeriod
;
5164 lpWriteBuffer
->cActions
= lpFailureActions
->cActions
;
5166 memmove(lpWriteBuffer
+ 1,
5167 lpFailureActions
->lpsaActions
,
5168 lpFailureActions
->cActions
* sizeof(SC_ACTION
));
5172 /* The reset period and array of failure actions are deleted */
5173 lpWriteBuffer
->dwResetPeriod
= 0;
5174 lpWriteBuffer
->cActions
= 0;
5178 /* Save the new failure actions into the registry */
5179 dwError
= RegSetValueExW(hServiceKey
,
5183 (LPBYTE
)lpWriteBuffer
,
5186 /* We modify the strings only in case of success.*/
5187 if (dwError
== ERROR_SUCCESS
)
5189 /* Modify the Reboot Message value, if specified */
5190 if (lpFailureActions
->lpRebootMsg
!= NULL
)
5192 /* If the Reboot Message is "" then we delete it */
5193 if (*lpFailureActions
->lpRebootMsg
== 0)
5195 DPRINT("Delete Reboot Message value\n");
5196 RegDeleteValueW(hServiceKey
, L
"RebootMessage");
5200 DPRINT("Setting Reboot Message value %S\n", lpFailureActions
->lpRebootMsg
);
5201 RegSetValueExW(hServiceKey
,
5205 (LPBYTE
)lpFailureActions
->lpRebootMsg
,
5206 (DWORD
)((wcslen(lpFailureActions
->lpRebootMsg
) + 1) * sizeof(WCHAR
)));
5210 /* Modify the Failure Command value, if specified */
5211 if (lpFailureActions
->lpCommand
!= NULL
)
5213 /* If the FailureCommand string is an empty string, delete the value */
5214 if (*lpFailureActions
->lpCommand
== 0)
5216 DPRINT("Delete Failure Command value\n");
5217 RegDeleteValueW(hServiceKey
, L
"FailureCommand");
5221 DPRINT("Setting Failure Command value %S\n", lpFailureActions
->lpCommand
);
5222 RegSetValueExW(hServiceKey
,
5226 (LPBYTE
)lpFailureActions
->lpCommand
,
5227 (DWORD
)((wcslen(lpFailureActions
->lpCommand
) + 1) * sizeof(WCHAR
)));
5233 if (lpWriteBuffer
!= NULL
)
5234 HeapFree(GetProcessHeap(), 0, lpWriteBuffer
);
5236 if (lpReadBuffer
!= NULL
)
5237 HeapFree(GetProcessHeap(), 0, lpReadBuffer
);
5244 DWORD
RChangeServiceConfig2W(
5245 SC_RPC_HANDLE hService
,
5246 SC_RPC_CONFIG_INFOW Info
)
5248 DWORD dwError
= ERROR_SUCCESS
;
5249 PSERVICE_HANDLE hSvc
;
5250 PSERVICE lpService
= NULL
;
5251 HKEY hServiceKey
= NULL
;
5252 ACCESS_MASK RequiredAccess
= SERVICE_CHANGE_CONFIG
;
5254 DPRINT("RChangeServiceConfig2W() called\n");
5255 DPRINT("dwInfoLevel = %lu\n", Info
.dwInfoLevel
);
5258 return ERROR_SHUTDOWN_IN_PROGRESS
;
5260 hSvc
= ScmGetServiceFromHandle(hService
);
5263 DPRINT("Invalid service handle!\n");
5264 return ERROR_INVALID_HANDLE
;
5267 if (Info
.dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5268 RequiredAccess
|= SERVICE_START
;
5270 /* Check the access rights */
5271 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5274 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5275 return ERROR_ACCESS_DENIED
;
5278 if (Info
.dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5280 /* FIXME: Check if the caller has the SE_SHUTDOWN_NAME privilege */
5284 lpService
= hSvc
->ServiceEntry
;
5285 if (lpService
== NULL
)
5287 DPRINT("lpService == NULL!\n");
5288 return ERROR_INVALID_HANDLE
;
5291 /* Failure actions can only be set for Win32 services, not for drivers */
5292 if (Info
.dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5294 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
5295 return ERROR_CANNOT_DETECT_DRIVER_FAILURE
;
5298 /* Lock the service database exclusively */
5299 ScmLockDatabaseExclusive();
5301 if (lpService
->bDeleted
)
5303 DPRINT("The service has already been marked for delete!\n");
5304 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
5308 /* Open the service key */
5309 dwError
= ScmOpenServiceKey(lpService
->szServiceName
,
5310 KEY_READ
| KEY_SET_VALUE
,
5312 if (dwError
!= ERROR_SUCCESS
)
5315 if (Info
.dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
5317 LPSERVICE_DESCRIPTIONW lpServiceDescription
= (LPSERVICE_DESCRIPTIONW
)Info
.psd
;
5319 /* Modify the service description, if specified */
5320 if (lpServiceDescription
!= NULL
&&
5321 lpServiceDescription
->lpDescription
!= NULL
)
5323 /* If the description is "" then we delete it */
5324 if (*lpServiceDescription
->lpDescription
== 0)
5326 DPRINT("Delete service description\n");
5327 dwError
= RegDeleteValueW(hServiceKey
, L
"Description");
5329 if (dwError
== ERROR_FILE_NOT_FOUND
)
5330 dwError
= ERROR_SUCCESS
;
5334 DPRINT("Setting service description value %S\n", lpServiceDescription
->lpDescription
);
5335 dwError
= RegSetValueExW(hServiceKey
,
5339 (LPBYTE
)lpServiceDescription
->lpDescription
,
5340 (DWORD
)((wcslen(lpServiceDescription
->lpDescription
) + 1) * sizeof(WCHAR
)));
5345 dwError
= ERROR_SUCCESS
;
5348 else if (Info
.dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5350 dwError
= ScmSetFailureActions(hServiceKey
,
5351 (LPSERVICE_FAILURE_ACTIONSW
)Info
.psfa
);
5355 if (hServiceKey
!= NULL
)
5356 RegCloseKey(hServiceKey
);
5358 /* Unlock the service database */
5359 ScmUnlockDatabase();
5361 DPRINT("RChangeServiceConfig2W() done (Error %lu)\n", dwError
);
5368 DWORD
RQueryServiceConfig2A(
5369 SC_RPC_HANDLE hService
,
5373 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
5375 DWORD dwError
= ERROR_SUCCESS
;
5376 PSERVICE_HANDLE hSvc
;
5377 PSERVICE lpService
= NULL
;
5378 HKEY hServiceKey
= NULL
;
5379 DWORD dwRequiredSize
= 0;
5381 LPWSTR lpDescriptionW
= NULL
;
5382 LPWSTR lpRebootMessageW
= NULL
;
5383 LPWSTR lpFailureCommandW
= NULL
;
5385 DPRINT("RQueryServiceConfig2A() called hService %p dwInfoLevel %u, lpBuffer %p cbBufSize %u pcbBytesNeeded %p\n",
5386 hService
, dwInfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
5389 return ERROR_INVALID_ADDRESS
;
5392 return ERROR_SHUTDOWN_IN_PROGRESS
;
5394 hSvc
= ScmGetServiceFromHandle(hService
);
5397 DPRINT1("Invalid service handle!\n");
5398 return ERROR_INVALID_HANDLE
;
5401 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5402 SERVICE_QUERY_CONFIG
))
5404 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5405 return ERROR_ACCESS_DENIED
;
5408 lpService
= hSvc
->ServiceEntry
;
5409 if (lpService
== NULL
)
5411 DPRINT("lpService == NULL!\n");
5412 return ERROR_INVALID_HANDLE
;
5415 /* Lock the service database shared */
5416 ScmLockDatabaseShared();
5418 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
5421 if (dwError
!= ERROR_SUCCESS
)
5424 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
5426 LPSERVICE_DESCRIPTIONA lpServiceDescription
= (LPSERVICE_DESCRIPTIONA
)lpBuffer
;
5429 dwError
= ScmReadString(hServiceKey
,
5432 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5435 *pcbBytesNeeded
= sizeof(SERVICE_DESCRIPTIONA
);
5436 if (dwError
== ERROR_SUCCESS
)
5437 *pcbBytesNeeded
+= (DWORD
)((wcslen(lpDescriptionW
) + 1) * sizeof(WCHAR
));
5439 if (cbBufSize
< *pcbBytesNeeded
)
5441 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5445 if (dwError
== ERROR_SUCCESS
)
5447 lpStr
= (LPSTR
)(lpServiceDescription
+ 1);
5449 WideCharToMultiByte(CP_ACP
,
5454 (int)wcslen(lpDescriptionW
),
5457 lpServiceDescription
->lpDescription
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceDescription
);
5461 lpServiceDescription
->lpDescription
= NULL
;
5462 dwError
= ERROR_SUCCESS
;
5465 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5467 LPSERVICE_FAILURE_ACTIONSA lpFailureActions
= (LPSERVICE_FAILURE_ACTIONSA
)lpBuffer
;
5470 /* Query value length */
5471 dwError
= RegQueryValueExW(hServiceKey
,
5477 if (dwError
!= ERROR_SUCCESS
&&
5478 dwError
!= ERROR_MORE_DATA
&&
5479 dwError
!= ERROR_FILE_NOT_FOUND
)
5482 dwRequiredSize
= (dwType
== REG_BINARY
) ? max(sizeof(SERVICE_FAILURE_ACTIONSA
), dwRequiredSize
)
5483 : sizeof(SERVICE_FAILURE_ACTIONSA
);
5485 /* Get the strings */
5486 ScmReadString(hServiceKey
,
5488 &lpFailureCommandW
);
5490 ScmReadString(hServiceKey
,
5494 if (lpRebootMessageW
)
5495 dwRequiredSize
+= (DWORD
)((wcslen(lpRebootMessageW
) + 1) * sizeof(WCHAR
));
5497 if (lpFailureCommandW
)
5498 dwRequiredSize
+= (DWORD
)((wcslen(lpFailureCommandW
) + 1) * sizeof(WCHAR
));
5500 if (cbBufSize
< dwRequiredSize
)
5502 *pcbBytesNeeded
= dwRequiredSize
;
5503 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5507 /* Now we can fill the buffer */
5508 if (dwError
!= ERROR_FILE_NOT_FOUND
&& dwType
== REG_BINARY
)
5510 dwError
= RegQueryValueExW(hServiceKey
,
5514 (LPBYTE
)lpFailureActions
,
5516 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5519 if (dwRequiredSize
< sizeof(SERVICE_FAILURE_ACTIONSA
))
5520 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSA
);
5525 * The value of the error doesn't really matter, the only
5526 * important thing is that it must be != ERROR_SUCCESS .
5528 dwError
= ERROR_INVALID_DATA
;
5531 if (dwError
== ERROR_SUCCESS
)
5533 lpFailureActions
->cActions
= min(lpFailureActions
->cActions
, (dwRequiredSize
- sizeof(SERVICE_FAILURE_ACTIONSA
)) / sizeof(SC_ACTION
));
5535 /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */
5536 lpFailureActions
->lpsaActions
= (lpFailureActions
->cActions
> 0 ? (LPSC_ACTION
)(ULONG_PTR
)sizeof(SERVICE_FAILURE_ACTIONSA
) : NULL
);
5538 lpStr
= (LPSTR
)((ULONG_PTR
)(lpFailureActions
+ 1) + lpFailureActions
->cActions
* sizeof(SC_ACTION
));
5542 lpFailureActions
->dwResetPeriod
= 0;
5543 lpFailureActions
->cActions
= 0;
5544 lpFailureActions
->lpsaActions
= NULL
;
5545 lpStr
= (LPSTR
)(lpFailureActions
+ 1);
5548 lpFailureActions
->lpRebootMsg
= NULL
;
5549 lpFailureActions
->lpCommand
= NULL
;
5551 if (lpRebootMessageW
)
5553 WideCharToMultiByte(CP_ACP
,
5558 (int)wcslen(lpRebootMessageW
),
5561 lpFailureActions
->lpRebootMsg
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5562 lpStr
+= strlen(lpStr
) + 1;
5565 if (lpFailureCommandW
)
5567 WideCharToMultiByte(CP_ACP
,
5572 (int)wcslen(lpFailureCommandW
),
5575 lpFailureActions
->lpCommand
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5576 /* lpStr += strlen(lpStr) + 1; */
5579 dwError
= ERROR_SUCCESS
;
5583 /* Unlock the service database */
5584 ScmUnlockDatabase();
5586 if (lpDescriptionW
!= NULL
)
5587 HeapFree(GetProcessHeap(), 0, lpDescriptionW
);
5589 if (lpRebootMessageW
!= NULL
)
5590 HeapFree(GetProcessHeap(), 0, lpRebootMessageW
);
5592 if (lpFailureCommandW
!= NULL
)
5593 HeapFree(GetProcessHeap(), 0, lpFailureCommandW
);
5595 if (hServiceKey
!= NULL
)
5596 RegCloseKey(hServiceKey
);
5598 DPRINT("RQueryServiceConfig2A() done (Error %lu)\n", dwError
);
5605 DWORD
RQueryServiceConfig2W(
5606 SC_RPC_HANDLE hService
,
5610 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
5612 DWORD dwError
= ERROR_SUCCESS
;
5613 PSERVICE_HANDLE hSvc
;
5614 PSERVICE lpService
= NULL
;
5615 HKEY hServiceKey
= NULL
;
5616 DWORD dwRequiredSize
= 0;
5618 LPWSTR lpDescription
= NULL
;
5619 LPWSTR lpRebootMessage
= NULL
;
5620 LPWSTR lpFailureCommand
= NULL
;
5622 DPRINT("RQueryServiceConfig2W() called\n");
5625 return ERROR_INVALID_ADDRESS
;
5628 return ERROR_SHUTDOWN_IN_PROGRESS
;
5630 hSvc
= ScmGetServiceFromHandle(hService
);
5633 DPRINT1("Invalid service handle!\n");
5634 return ERROR_INVALID_HANDLE
;
5637 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5638 SERVICE_QUERY_CONFIG
))
5640 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5641 return ERROR_ACCESS_DENIED
;
5644 lpService
= hSvc
->ServiceEntry
;
5645 if (lpService
== NULL
)
5647 DPRINT("lpService == NULL!\n");
5648 return ERROR_INVALID_HANDLE
;
5651 /* Lock the service database shared */
5652 ScmLockDatabaseShared();
5654 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
5657 if (dwError
!= ERROR_SUCCESS
)
5660 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
5662 LPSERVICE_DESCRIPTIONW lpServiceDescription
= (LPSERVICE_DESCRIPTIONW
)lpBuffer
;
5665 dwError
= ScmReadString(hServiceKey
,
5668 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5671 *pcbBytesNeeded
= sizeof(SERVICE_DESCRIPTIONW
);
5672 if (dwError
== ERROR_SUCCESS
)
5673 *pcbBytesNeeded
+= (DWORD
)((wcslen(lpDescription
) + 1) * sizeof(WCHAR
));
5675 if (cbBufSize
< *pcbBytesNeeded
)
5677 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5681 if (dwError
== ERROR_SUCCESS
)
5683 lpStr
= (LPWSTR
)(lpServiceDescription
+ 1);
5684 wcscpy(lpStr
, lpDescription
);
5685 lpServiceDescription
->lpDescription
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceDescription
);
5689 lpServiceDescription
->lpDescription
= NULL
;
5690 dwError
= ERROR_SUCCESS
;
5693 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5695 LPSERVICE_FAILURE_ACTIONSW lpFailureActions
= (LPSERVICE_FAILURE_ACTIONSW
)lpBuffer
;
5696 LPWSTR lpStr
= NULL
;
5698 /* Query value length */
5699 dwError
= RegQueryValueExW(hServiceKey
,
5705 if (dwError
!= ERROR_SUCCESS
&&
5706 dwError
!= ERROR_MORE_DATA
&&
5707 dwError
!= ERROR_FILE_NOT_FOUND
)
5710 dwRequiredSize
= (dwType
== REG_BINARY
) ? max(sizeof(SERVICE_FAILURE_ACTIONSW
), dwRequiredSize
)
5711 : sizeof(SERVICE_FAILURE_ACTIONSW
);
5713 /* Get the strings */
5714 ScmReadString(hServiceKey
,
5718 ScmReadString(hServiceKey
,
5722 if (lpRebootMessage
)
5723 dwRequiredSize
+= (DWORD
)((wcslen(lpRebootMessage
) + 1) * sizeof(WCHAR
));
5725 if (lpFailureCommand
)
5726 dwRequiredSize
+= (DWORD
)((wcslen(lpFailureCommand
) + 1) * sizeof(WCHAR
));
5728 if (cbBufSize
< dwRequiredSize
)
5730 *pcbBytesNeeded
= dwRequiredSize
;
5731 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5735 /* Now we can fill the buffer */
5736 if (dwError
!= ERROR_FILE_NOT_FOUND
&& dwType
== REG_BINARY
)
5738 dwError
= RegQueryValueExW(hServiceKey
,
5742 (LPBYTE
)lpFailureActions
,
5744 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5747 if (dwRequiredSize
< sizeof(SERVICE_FAILURE_ACTIONSW
))
5748 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSW
);
5753 * The value of the error doesn't really matter, the only
5754 * important thing is that it must be != ERROR_SUCCESS .
5756 dwError
= ERROR_INVALID_DATA
;
5759 if (dwError
== ERROR_SUCCESS
)
5761 lpFailureActions
->cActions
= min(lpFailureActions
->cActions
, (dwRequiredSize
- sizeof(SERVICE_FAILURE_ACTIONSW
)) / sizeof(SC_ACTION
));
5763 /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */
5764 lpFailureActions
->lpsaActions
= (lpFailureActions
->cActions
> 0 ? (LPSC_ACTION
)(ULONG_PTR
)sizeof(SERVICE_FAILURE_ACTIONSW
) : NULL
);
5766 lpStr
= (LPWSTR
)((ULONG_PTR
)(lpFailureActions
+ 1) + lpFailureActions
->cActions
* sizeof(SC_ACTION
));
5770 lpFailureActions
->dwResetPeriod
= 0;
5771 lpFailureActions
->cActions
= 0;
5772 lpFailureActions
->lpsaActions
= NULL
;
5773 lpStr
= (LPWSTR
)(lpFailureActions
+ 1);
5776 lpFailureActions
->lpRebootMsg
= NULL
;
5777 lpFailureActions
->lpCommand
= NULL
;
5779 if (lpRebootMessage
)
5781 wcscpy(lpStr
, lpRebootMessage
);
5782 lpFailureActions
->lpRebootMsg
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5783 lpStr
+= wcslen(lpStr
) + 1;
5786 if (lpFailureCommand
)
5788 wcscpy(lpStr
, lpFailureCommand
);
5789 lpFailureActions
->lpCommand
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5790 /* lpStr += wcslen(lpStr) + 1; */
5793 dwError
= ERROR_SUCCESS
;
5797 /* Unlock the service database */
5798 ScmUnlockDatabase();
5800 if (lpDescription
!= NULL
)
5801 HeapFree(GetProcessHeap(), 0, lpDescription
);
5803 if (lpRebootMessage
!= NULL
)
5804 HeapFree(GetProcessHeap(), 0, lpRebootMessage
);
5806 if (lpFailureCommand
!= NULL
)
5807 HeapFree(GetProcessHeap(), 0, lpFailureCommand
);
5809 if (hServiceKey
!= NULL
)
5810 RegCloseKey(hServiceKey
);
5812 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError
);
5819 DWORD
RQueryServiceStatusEx(
5820 SC_RPC_HANDLE hService
,
5821 SC_STATUS_TYPE InfoLevel
,
5824 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
5826 LPSERVICE_STATUS_PROCESS lpStatus
;
5827 PSERVICE_HANDLE hSvc
;
5830 DPRINT("RQueryServiceStatusEx() called\n");
5833 return ERROR_SHUTDOWN_IN_PROGRESS
;
5835 if (InfoLevel
!= SC_STATUS_PROCESS_INFO
)
5836 return ERROR_INVALID_LEVEL
;
5838 *pcbBytesNeeded
= sizeof(SERVICE_STATUS_PROCESS
);
5840 if (cbBufSize
< sizeof(SERVICE_STATUS_PROCESS
))
5841 return ERROR_INSUFFICIENT_BUFFER
;
5843 hSvc
= ScmGetServiceFromHandle(hService
);
5846 DPRINT1("Invalid service handle!\n");
5847 return ERROR_INVALID_HANDLE
;
5850 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5851 SERVICE_QUERY_STATUS
))
5853 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5854 return ERROR_ACCESS_DENIED
;
5857 lpService
= hSvc
->ServiceEntry
;
5858 if (lpService
== NULL
)
5860 DPRINT("lpService == NULL!\n");
5861 return ERROR_INVALID_HANDLE
;
5864 /* Lock the service database shared */
5865 ScmLockDatabaseShared();
5867 lpStatus
= (LPSERVICE_STATUS_PROCESS
)lpBuffer
;
5869 /* Return service status information */
5870 RtlCopyMemory(lpStatus
,
5872 sizeof(SERVICE_STATUS
));
5874 lpStatus
->dwProcessId
= (lpService
->lpImage
!= NULL
) ? lpService
->lpImage
->dwProcessId
: 0; /* FIXME */
5875 lpStatus
->dwServiceFlags
= 0; /* FIXME */
5877 /* Unlock the service database */
5878 ScmUnlockDatabase();
5880 return ERROR_SUCCESS
;
5885 DWORD
REnumServicesStatusExA(
5886 SC_RPC_HANDLE hSCManager
,
5887 SC_ENUM_TYPE InfoLevel
,
5888 DWORD dwServiceType
,
5889 DWORD dwServiceState
,
5892 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
5893 LPBOUNDED_DWORD_256K lpServicesReturned
,
5894 LPBOUNDED_DWORD_256K lpResumeIndex
,
5895 LPCSTR pszGroupName
)
5897 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrW
= NULL
;
5898 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrIncrW
;
5899 LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtrA
= NULL
;
5900 LPWSTR lpStringPtrW
;
5902 LPWSTR pszGroupNameW
= NULL
;
5904 DWORD dwServiceCount
;
5906 DPRINT("REnumServicesStatusExA() called\n");
5908 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
5910 return ERROR_INVALID_ADDRESS
;
5915 pszGroupNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, (strlen(pszGroupName
) + 1) * sizeof(WCHAR
));
5918 DPRINT("Failed to allocate buffer!\n");
5919 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
5923 MultiByteToWideChar(CP_ACP
,
5928 (int)(strlen(pszGroupName
) + 1));
5931 if ((cbBufSize
> 0) && (lpBuffer
))
5933 lpStatusPtrW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, cbBufSize
);
5936 DPRINT("Failed to allocate buffer!\n");
5937 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
5942 dwError
= REnumServicesStatusExW(hSCManager
,
5946 (LPBYTE
)lpStatusPtrW
,
5953 /* if no services were returned then we are Done */
5954 if (*lpServicesReturned
== 0)
5957 lpStatusPtrIncrW
= lpStatusPtrW
;
5958 lpStatusPtrA
= (LPENUM_SERVICE_STATUS_PROCESSA
)lpBuffer
;
5959 lpStringPtrA
= (LPSTR
)((ULONG_PTR
)lpBuffer
+
5960 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUS_PROCESSA
));
5961 lpStringPtrW
= (LPWSTR
)((ULONG_PTR
)lpStatusPtrW
+
5962 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUS_PROCESSW
));
5964 for (dwServiceCount
= 0; dwServiceCount
< *lpServicesReturned
; dwServiceCount
++)
5966 /* Copy the service name */
5967 WideCharToMultiByte(CP_ACP
,
5972 (int)wcslen(lpStringPtrW
),
5976 lpStatusPtrA
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
5977 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
5978 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
5980 /* Copy the display name */
5981 WideCharToMultiByte(CP_ACP
,
5986 (int)wcslen(lpStringPtrW
),
5990 lpStatusPtrA
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
5991 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
5992 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
5994 /* Copy the status information */
5995 memcpy(&lpStatusPtrA
->ServiceStatusProcess
,
5996 &lpStatusPtrIncrW
->ServiceStatusProcess
,
5997 sizeof(SERVICE_STATUS
));
5999 lpStatusPtrA
->ServiceStatusProcess
.dwProcessId
= lpStatusPtrIncrW
->ServiceStatusProcess
.dwProcessId
; /* FIXME */
6000 lpStatusPtrA
->ServiceStatusProcess
.dwServiceFlags
= 0; /* FIXME */
6008 HeapFree(GetProcessHeap(), 0, pszGroupNameW
);
6011 HeapFree(GetProcessHeap(), 0, lpStatusPtrW
);
6013 DPRINT("REnumServicesStatusExA() done (Error %lu)\n", dwError
);
6020 DWORD
REnumServicesStatusExW(
6021 SC_RPC_HANDLE hSCManager
,
6022 SC_ENUM_TYPE InfoLevel
,
6023 DWORD dwServiceType
,
6024 DWORD dwServiceState
,
6027 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
6028 LPBOUNDED_DWORD_256K lpServicesReturned
,
6029 LPBOUNDED_DWORD_256K lpResumeIndex
,
6030 LPCWSTR pszGroupName
)
6032 PMANAGER_HANDLE hManager
;
6034 DWORD dwError
= ERROR_SUCCESS
;
6035 PLIST_ENTRY ServiceEntry
;
6036 PSERVICE CurrentService
;
6038 DWORD dwRequiredSize
;
6039 DWORD dwServiceCount
;
6041 DWORD dwLastResumeCount
= 0;
6042 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr
;
6045 DPRINT("REnumServicesStatusExW() called\n");
6048 return ERROR_SHUTDOWN_IN_PROGRESS
;
6050 if (InfoLevel
!= SC_ENUM_PROCESS_INFO
)
6051 return ERROR_INVALID_LEVEL
;
6053 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
6054 if (hManager
== NULL
)
6056 DPRINT1("Invalid service manager handle!\n");
6057 return ERROR_INVALID_HANDLE
;
6060 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
6062 return ERROR_INVALID_ADDRESS
;
6065 *pcbBytesNeeded
= 0;
6066 *lpServicesReturned
= 0;
6068 if ((dwServiceType
== 0) ||
6069 ((dwServiceType
& ~SERVICE_TYPE_ALL
) != 0))
6071 DPRINT("Not a valid Service Type!\n");
6072 return ERROR_INVALID_PARAMETER
;
6075 if ((dwServiceState
== 0) ||
6076 ((dwServiceState
& ~SERVICE_STATE_ALL
) != 0))
6078 DPRINT("Not a valid Service State!\n");
6079 return ERROR_INVALID_PARAMETER
;
6082 /* Check access rights */
6083 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
6084 SC_MANAGER_ENUMERATE_SERVICE
))
6086 DPRINT("Insufficient access rights! 0x%lx\n",
6087 hManager
->Handle
.DesiredAccess
);
6088 return ERROR_ACCESS_DENIED
;
6092 dwLastResumeCount
= *lpResumeIndex
;
6094 /* Lock the service database shared */
6095 ScmLockDatabaseShared();
6097 lpService
= ScmGetServiceEntryByResumeCount(dwLastResumeCount
);
6098 if (lpService
== NULL
)
6100 dwError
= ERROR_SUCCESS
;
6107 for (ServiceEntry
= &lpService
->ServiceListEntry
;
6108 ServiceEntry
!= &ServiceListHead
;
6109 ServiceEntry
= ServiceEntry
->Flink
)
6111 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
6115 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
6118 dwState
= SERVICE_ACTIVE
;
6119 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
6120 dwState
= SERVICE_INACTIVE
;
6122 if ((dwState
& dwServiceState
) == 0)
6127 if (*pszGroupName
== 0)
6129 if (CurrentService
->lpGroup
!= NULL
)
6134 if ((CurrentService
->lpGroup
== NULL
) ||
6135 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
6140 dwSize
= sizeof(ENUM_SERVICE_STATUS_PROCESSW
) +
6141 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
6142 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
6144 if (dwRequiredSize
+ dwSize
<= cbBufSize
)
6146 DPRINT("Service name: %S fit\n", CurrentService
->lpServiceName
);
6147 dwRequiredSize
+= dwSize
;
6149 dwLastResumeCount
= CurrentService
->dwResumeCount
;
6153 DPRINT("Service name: %S no fit\n", CurrentService
->lpServiceName
);
6159 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize
);
6160 DPRINT("dwServiceCount: %lu\n", dwServiceCount
);
6163 ServiceEntry
!= &ServiceListHead
;
6164 ServiceEntry
= ServiceEntry
->Flink
)
6166 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
6170 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
6173 dwState
= SERVICE_ACTIVE
;
6174 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
6175 dwState
= SERVICE_INACTIVE
;
6177 if ((dwState
& dwServiceState
) == 0)
6182 if (*pszGroupName
== 0)
6184 if (CurrentService
->lpGroup
!= NULL
)
6189 if ((CurrentService
->lpGroup
== NULL
) ||
6190 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
6195 dwRequiredSize
+= (sizeof(ENUM_SERVICE_STATUS_PROCESSW
) +
6196 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
6197 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
)));
6199 dwError
= ERROR_MORE_DATA
;
6202 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize
);
6205 *lpResumeIndex
= dwLastResumeCount
;
6207 *lpServicesReturned
= dwServiceCount
;
6208 *pcbBytesNeeded
= dwRequiredSize
;
6210 /* If there was no services that matched */
6211 if ((!dwServiceCount
) && (dwError
!= ERROR_MORE_DATA
))
6213 dwError
= ERROR_SERVICE_DOES_NOT_EXIST
;
6217 lpStatusPtr
= (LPENUM_SERVICE_STATUS_PROCESSW
)lpBuffer
;
6218 lpStringPtr
= (LPWSTR
)((ULONG_PTR
)lpBuffer
+
6219 dwServiceCount
* sizeof(ENUM_SERVICE_STATUS_PROCESSW
));
6222 for (ServiceEntry
= &lpService
->ServiceListEntry
;
6223 ServiceEntry
!= &ServiceListHead
;
6224 ServiceEntry
= ServiceEntry
->Flink
)
6226 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
6230 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
6233 dwState
= SERVICE_ACTIVE
;
6234 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
6235 dwState
= SERVICE_INACTIVE
;
6237 if ((dwState
& dwServiceState
) == 0)
6242 if (*pszGroupName
== 0)
6244 if (CurrentService
->lpGroup
!= NULL
)
6249 if ((CurrentService
->lpGroup
== NULL
) ||
6250 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
6255 dwSize
= sizeof(ENUM_SERVICE_STATUS_PROCESSW
) +
6256 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
6257 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
6259 if (dwRequiredSize
+ dwSize
<= cbBufSize
)
6261 /* Copy the service name */
6263 CurrentService
->lpServiceName
);
6264 lpStatusPtr
->lpServiceName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
6265 lpStringPtr
+= (wcslen(CurrentService
->lpServiceName
) + 1);
6267 /* Copy the display name */
6269 CurrentService
->lpDisplayName
);
6270 lpStatusPtr
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
6271 lpStringPtr
+= (wcslen(CurrentService
->lpDisplayName
) + 1);
6273 /* Copy the status information */
6274 memcpy(&lpStatusPtr
->ServiceStatusProcess
,
6275 &CurrentService
->Status
,
6276 sizeof(SERVICE_STATUS
));
6277 lpStatusPtr
->ServiceStatusProcess
.dwProcessId
=
6278 (CurrentService
->lpImage
!= NULL
) ? CurrentService
->lpImage
->dwProcessId
: 0; /* FIXME */
6279 lpStatusPtr
->ServiceStatusProcess
.dwServiceFlags
= 0; /* FIXME */
6282 dwRequiredSize
+= dwSize
;
6292 *pcbBytesNeeded
= 0;
6298 /* Unlock the service database */
6299 ScmUnlockDatabase();
6301 DPRINT("REnumServicesStatusExW() done (Error %lu)\n", dwError
);
6308 DWORD
RSendTSMessage(
6309 handle_t BindingHandle
) /* FIXME */
6312 return ERROR_CALL_NOT_IMPLEMENTED
;
6317 DWORD
RCreateServiceWOW64A(
6318 handle_t BindingHandle
,
6319 LPSTR lpServiceName
,
6320 LPSTR lpDisplayName
,
6321 DWORD dwDesiredAccess
,
6322 DWORD dwServiceType
,
6324 DWORD dwErrorControl
,
6325 LPSTR lpBinaryPathName
,
6326 LPSTR lpLoadOrderGroup
,
6328 LPBYTE lpDependencies
,
6330 LPSTR lpServiceStartName
,
6333 LPSC_RPC_HANDLE lpServiceHandle
)
6336 return ERROR_CALL_NOT_IMPLEMENTED
;
6341 DWORD
RCreateServiceWOW64W(
6342 handle_t BindingHandle
,
6343 LPWSTR lpServiceName
,
6344 LPWSTR lpDisplayName
,
6345 DWORD dwDesiredAccess
,
6346 DWORD dwServiceType
,
6348 DWORD dwErrorControl
,
6349 LPWSTR lpBinaryPathName
,
6350 LPWSTR lpLoadOrderGroup
,
6352 LPBYTE lpDependencies
,
6354 LPWSTR lpServiceStartName
,
6357 LPSC_RPC_HANDLE lpServiceHandle
)
6360 return ERROR_CALL_NOT_IMPLEMENTED
;
6365 DWORD
RQueryServiceTagInfo(
6366 handle_t BindingHandle
) /* FIXME */
6369 return ERROR_CALL_NOT_IMPLEMENTED
;
6374 DWORD
RNotifyServiceStatusChange(
6375 SC_RPC_HANDLE hService
,
6376 SC_RPC_NOTIFY_PARAMS NotifyParams
,
6377 GUID
*pClientProcessGuid
,
6378 GUID
*pSCMProcessGuid
,
6379 PBOOL pfCreateRemoteQueue
,
6380 LPSC_NOTIFY_RPC_HANDLE phNotify
)
6383 return ERROR_CALL_NOT_IMPLEMENTED
;
6388 DWORD
RGetNotifyResults(
6389 SC_NOTIFY_RPC_HANDLE hNotify
,
6390 PSC_RPC_NOTIFY_PARAMS_LIST
*ppNotifyParams
)
6393 return ERROR_CALL_NOT_IMPLEMENTED
;
6398 DWORD
RCloseNotifyHandle(
6399 LPSC_NOTIFY_RPC_HANDLE phNotify
,
6403 return ERROR_CALL_NOT_IMPLEMENTED
;
6408 DWORD
RControlServiceExA(
6409 SC_RPC_HANDLE hService
,
6414 return ERROR_CALL_NOT_IMPLEMENTED
;
6419 DWORD
RControlServiceExW(
6420 SC_RPC_HANDLE hService
,
6425 return ERROR_CALL_NOT_IMPLEMENTED
;
6430 DWORD
RSendPnPMessage(
6431 handle_t BindingHandle
) /* FIXME */
6434 return ERROR_CALL_NOT_IMPLEMENTED
;
6439 DWORD
RValidatePnPService(
6440 handle_t BindingHandle
) /* FIXME */
6443 return ERROR_CALL_NOT_IMPLEMENTED
;
6448 DWORD
ROpenServiceStatusHandle(
6449 handle_t BindingHandle
) /* FIXME */
6452 return ERROR_CALL_NOT_IMPLEMENTED
;
6458 handle_t BindingHandle
) /* FIXME */
6461 return ERROR_CALL_NOT_IMPLEMENTED
;
6465 void __RPC_FAR
* __RPC_USER
midl_user_allocate(SIZE_T len
)
6467 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
);
6471 void __RPC_USER
midl_user_free(void __RPC_FAR
* ptr
)
6473 HeapFree(GetProcessHeap(), 0, ptr
);
6477 void __RPC_USER
SC_RPC_HANDLE_rundown(SC_RPC_HANDLE hSCObject
)
6479 /* Close the handle */
6480 RCloseServiceHandle(&hSCObject
);
6484 void __RPC_USER
SC_RPC_LOCK_rundown(SC_RPC_LOCK Lock
)
6486 /* Unlock the database */
6487 RUnlockServiceDatabase(&Lock
);
6491 void __RPC_USER
SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE hNotify
)