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 ****************************************************************/
21 /* GLOBALS *****************************************************************/
23 #define MANAGER_TAG 0x72674D68 /* 'hMgr' */
24 #define SERVICE_TAG 0x63765368 /* 'hSvc' */
25 #define INVALID_TAG 0xAABBCCDD
27 typedef struct _SCMGR_HANDLE
34 typedef struct _MANAGER_HANDLE
37 WCHAR DatabaseName
[1];
38 } MANAGER_HANDLE
, *PMANAGER_HANDLE
;
41 typedef struct _SERVICE_HANDLE
44 PSERVICE ServiceEntry
;
45 } SERVICE_HANDLE
, *PSERVICE_HANDLE
;
48 #define SC_MANAGER_READ \
49 (STANDARD_RIGHTS_READ | \
50 SC_MANAGER_QUERY_LOCK_STATUS | \
51 SC_MANAGER_ENUMERATE_SERVICE)
53 #define SC_MANAGER_WRITE \
54 (STANDARD_RIGHTS_WRITE | \
55 SC_MANAGER_MODIFY_BOOT_CONFIG | \
56 SC_MANAGER_CREATE_SERVICE)
58 #define SC_MANAGER_EXECUTE \
59 (STANDARD_RIGHTS_EXECUTE | \
61 SC_MANAGER_ENUMERATE_SERVICE | \
62 SC_MANAGER_CONNECT | \
63 SC_MANAGER_CREATE_SERVICE)
66 #define SERVICE_READ \
67 (STANDARD_RIGHTS_READ | \
68 SERVICE_INTERROGATE | \
69 SERVICE_ENUMERATE_DEPENDENTS | \
70 SERVICE_QUERY_STATUS | \
73 #define SERVICE_WRITE \
74 (STANDARD_RIGHTS_WRITE | \
75 SERVICE_CHANGE_CONFIG)
77 #define SERVICE_EXECUTE \
78 (STANDARD_RIGHTS_EXECUTE | \
79 SERVICE_USER_DEFINED_CONTROL | \
80 SERVICE_PAUSE_CONTINUE | \
84 #define TAG_ARRAY_SIZE 32
86 /* VARIABLES ***************************************************************/
88 static GENERIC_MAPPING
89 ScmManagerMapping
= {SC_MANAGER_READ
,
92 SC_MANAGER_ALL_ACCESS
};
94 static GENERIC_MAPPING
95 ScmServiceMapping
= {SERVICE_READ
,
100 DWORD g_dwServiceBits
= 0;
102 /* FUNCTIONS ***************************************************************/
105 ScmStartRpcServer(VOID
)
109 DPRINT("ScmStartRpcServer() called\n");
111 Status
= RpcServerUseProtseqEpW(L
"ncacn_np",
115 if (Status
!= RPC_S_OK
)
117 DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status
);
121 Status
= RpcServerRegisterIf(svcctl_v2_0_s_ifspec
,
124 if (Status
!= RPC_S_OK
)
126 DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status
);
130 Status
= RpcServerListen(1, 20, TRUE
);
131 if (Status
!= RPC_S_OK
)
133 DPRINT1("RpcServerListen() failed (Status %lx)\n", Status
);
137 DPRINT("ScmStartRpcServer() done\n");
142 ScmCreateManagerHandle(LPWSTR lpDatabaseName
,
147 if (lpDatabaseName
== NULL
)
148 lpDatabaseName
= SERVICES_ACTIVE_DATABASEW
;
150 if (_wcsicmp(lpDatabaseName
, SERVICES_FAILED_DATABASEW
) == 0)
152 DPRINT("Database %S, does not exist\n", lpDatabaseName
);
153 return ERROR_DATABASE_DOES_NOT_EXIST
;
155 else if (_wcsicmp(lpDatabaseName
, SERVICES_ACTIVE_DATABASEW
) != 0)
157 DPRINT("Invalid Database name %S.\n", lpDatabaseName
);
158 return ERROR_INVALID_NAME
;
161 Ptr
= HeapAlloc(GetProcessHeap(),
163 FIELD_OFFSET(MANAGER_HANDLE
, DatabaseName
[wcslen(lpDatabaseName
) + 1]));
165 return ERROR_NOT_ENOUGH_MEMORY
;
167 Ptr
->Handle
.Tag
= MANAGER_TAG
;
169 wcscpy(Ptr
->DatabaseName
, lpDatabaseName
);
171 *Handle
= (SC_HANDLE
)Ptr
;
173 return ERROR_SUCCESS
;
178 ScmCreateServiceHandle(PSERVICE lpServiceEntry
,
183 Ptr
= HeapAlloc(GetProcessHeap(),
185 sizeof(SERVICE_HANDLE
));
187 return ERROR_NOT_ENOUGH_MEMORY
;
189 Ptr
->Handle
.Tag
= SERVICE_TAG
;
191 Ptr
->ServiceEntry
= lpServiceEntry
;
193 *Handle
= (SC_HANDLE
)Ptr
;
195 return ERROR_SUCCESS
;
199 static PMANAGER_HANDLE
200 ScmGetServiceManagerFromHandle(SC_RPC_HANDLE Handle
)
202 PMANAGER_HANDLE pManager
= NULL
;
206 if (((PMANAGER_HANDLE
)Handle
)->Handle
.Tag
== MANAGER_TAG
)
207 pManager
= (PMANAGER_HANDLE
)Handle
;
209 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
211 DPRINT1("Exception: Invalid Service Manager handle!\n");
219 static PSERVICE_HANDLE
220 ScmGetServiceFromHandle(SC_RPC_HANDLE Handle
)
222 PSERVICE_HANDLE pService
= NULL
;
226 if (((PSERVICE_HANDLE
)Handle
)->Handle
.Tag
== SERVICE_TAG
)
227 pService
= (PSERVICE_HANDLE
)Handle
;
229 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
231 DPRINT1("Exception: Invalid Service handle!\n");
240 ScmCheckAccess(SC_HANDLE Handle
,
241 DWORD dwDesiredAccess
)
243 PMANAGER_HANDLE hMgr
;
245 hMgr
= (PMANAGER_HANDLE
)Handle
;
246 if (hMgr
->Handle
.Tag
== MANAGER_TAG
)
248 RtlMapGenericMask(&dwDesiredAccess
,
251 hMgr
->Handle
.DesiredAccess
= dwDesiredAccess
;
253 return ERROR_SUCCESS
;
255 else if (hMgr
->Handle
.Tag
== SERVICE_TAG
)
257 RtlMapGenericMask(&dwDesiredAccess
,
260 hMgr
->Handle
.DesiredAccess
= dwDesiredAccess
;
262 return ERROR_SUCCESS
;
265 return ERROR_INVALID_HANDLE
;
270 ScmAssignNewTag(PSERVICE lpService
)
274 DWORD dwGroupTagCount
= 0;
275 PDWORD pdwGroupTags
= NULL
;
277 DWORD dwTagUsedBase
= 1;
278 BOOLEAN TagUsed
[TAG_ARRAY_SIZE
];
282 PLIST_ENTRY ServiceEntry
;
283 PSERVICE CurrentService
;
285 ASSERT(lpService
!= NULL
);
286 ASSERT(lpService
->lpGroup
!= NULL
);
288 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
289 L
"System\\CurrentControlSet\\Control\\GroupOrderList",
294 if (dwError
!= ERROR_SUCCESS
)
297 /* query value length */
299 dwError
= RegQueryValueExW(hKey
,
300 lpService
->lpGroup
->szGroupName
,
306 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_MORE_DATA
)
309 pdwGroupTags
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, cbDataSize
);
312 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
316 dwError
= RegQueryValueExW(hKey
,
317 lpService
->lpGroup
->szGroupName
,
320 (LPBYTE
)pdwGroupTags
,
323 if (dwError
!= ERROR_SUCCESS
)
326 if (cbDataSize
< sizeof(pdwGroupTags
[0]))
329 dwGroupTagCount
= min(pdwGroupTags
[0], cbDataSize
/ sizeof(pdwGroupTags
[0]) - 1);
334 /* mark all tags as unused */
335 for (i
= 0; i
< TAG_ARRAY_SIZE
; i
++)
338 /* mark tags in GroupOrderList as used */
339 for (i
= 1; i
<= dwGroupTagCount
; i
++)
341 nTagOffset
= pdwGroupTags
[i
] - dwTagUsedBase
;
342 if (nTagOffset
>= 0 && nTagOffset
< TAG_ARRAY_SIZE
)
343 TagUsed
[nTagOffset
] = TRUE
;
346 /* mark tags in service list as used */
347 ServiceEntry
= lpService
->ServiceListEntry
.Flink
;
348 while (ServiceEntry
!= &lpService
->ServiceListEntry
)
350 ASSERT(ServiceEntry
!= NULL
);
351 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
352 if (CurrentService
->lpGroup
== lpService
->lpGroup
)
354 nTagOffset
= CurrentService
->dwTag
- dwTagUsedBase
;
355 if (nTagOffset
>= 0 && nTagOffset
< TAG_ARRAY_SIZE
)
356 TagUsed
[nTagOffset
] = TRUE
;
359 ServiceEntry
= ServiceEntry
->Flink
;
362 /* find unused tag, if any */
363 for (i
= 0; i
< TAG_ARRAY_SIZE
; i
++)
367 dwFreeTag
= dwTagUsedBase
+ i
;
372 dwTagUsedBase
+= TAG_ARRAY_SIZE
;
373 } while (!dwFreeTag
);
377 HeapFree(GetProcessHeap(), 0, pdwGroupTags
);
384 lpService
->dwTag
= dwFreeTag
;
385 DPRINT("Assigning new tag %lu to service %S in group %S\n",
386 lpService
->dwTag
, lpService
->lpServiceName
, lpService
->lpGroup
->szGroupName
);
387 dwError
= ERROR_SUCCESS
;
391 DPRINT1("Failed to assign new tag to service %S, error=%lu\n",
392 lpService
->lpServiceName
, dwError
);
399 /* Create a path suitable for the bootloader out of the full path */
401 ScmConvertToBootPathName(wchar_t *CanonName
, wchar_t **RelativeName
)
403 SIZE_T ServiceNameLen
, ExpandedLen
;
407 UNICODE_STRING NtPathName
, SystemRoot
, LinkTarget
;
408 OBJECT_ATTRIBUTES ObjectAttributes
;
410 HANDLE SymbolicLinkHandle
;
412 DPRINT("ScmConvertToBootPathName %S\n", CanonName
);
415 return ERROR_INVALID_PARAMETER
;
417 *RelativeName
= NULL
;
419 ServiceNameLen
= wcslen(CanonName
);
421 /* First check, if it's already good */
422 if (ServiceNameLen
> 12 &&
423 !_wcsnicmp(L
"\\SystemRoot\\", CanonName
, 12))
425 *RelativeName
= HeapAlloc(GetProcessHeap(),
427 (ServiceNameLen
+ 1) * sizeof(WCHAR
));
428 if (*RelativeName
== NULL
)
430 DPRINT("Error allocating memory for boot driver name!\n");
431 return ERROR_NOT_ENOUGH_MEMORY
;
435 wcscpy(*RelativeName
, CanonName
);
437 DPRINT("Bootdriver name %S\n", *RelativeName
);
438 return ERROR_SUCCESS
;
441 /* If it has %SystemRoot% prefix, substitute it to \System*/
442 if (ServiceNameLen
> 13 &&
443 !_wcsnicmp(L
"%SystemRoot%\\", CanonName
, 13))
445 /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */
446 *RelativeName
= HeapAlloc(GetProcessHeap(),
448 ServiceNameLen
* sizeof(WCHAR
));
450 if (*RelativeName
== NULL
)
452 DPRINT("Error allocating memory for boot driver name!\n");
453 return ERROR_NOT_ENOUGH_MEMORY
;
457 wcscpy(*RelativeName
, L
"\\SystemRoot\\");
458 wcscat(*RelativeName
, CanonName
+ 13);
460 DPRINT("Bootdriver name %S\n", *RelativeName
);
461 return ERROR_SUCCESS
;
464 /* Get buffer size needed for expanding env strings */
465 BufferSize
= ExpandEnvironmentStringsW(L
"%SystemRoot%\\", &Dest
, 1);
468 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
469 return ERROR_INVALID_ENVIRONMENT
;
472 /* Allocate memory, since the size is known now */
473 Expanded
= HeapAlloc(GetProcessHeap(),
475 (BufferSize
+ 1) * sizeof(WCHAR
));
478 DPRINT("Error allocating memory for boot driver name!\n");
479 return ERROR_NOT_ENOUGH_MEMORY
;
483 if (ExpandEnvironmentStringsW(L
"%SystemRoot%\\", Expanded
, BufferSize
) >
486 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
487 HeapFree(GetProcessHeap(), 0, Expanded
);
488 return ERROR_NOT_ENOUGH_MEMORY
;
491 /* Convert to NT-style path */
492 if (!RtlDosPathNameToNtPathName_U(Expanded
, &NtPathName
, NULL
, NULL
))
494 DPRINT("Error during a call to RtlDosPathNameToNtPathName_U()\n");
495 return ERROR_INVALID_ENVIRONMENT
;
498 DPRINT("Converted to NT-style %wZ\n", &NtPathName
);
500 /* No need to keep the dos-path anymore */
501 HeapFree(GetProcessHeap(), 0, Expanded
);
503 /* Copy it to the allocated place */
504 Expanded
= HeapAlloc(GetProcessHeap(),
506 NtPathName
.Length
+ sizeof(UNICODE_NULL
));
509 DPRINT("Error allocating memory for boot driver name!\n");
510 RtlFreeUnicodeString(&NtPathName
);
511 return ERROR_NOT_ENOUGH_MEMORY
;
514 ExpandedLen
= NtPathName
.Length
/ sizeof(WCHAR
);
515 wcsncpy(Expanded
, NtPathName
.Buffer
, ExpandedLen
);
516 Expanded
[ExpandedLen
] = UNICODE_NULL
;
517 RtlFreeUnicodeString(&NtPathName
);
519 if (ServiceNameLen
> ExpandedLen
&&
520 !_wcsnicmp(Expanded
, CanonName
, ExpandedLen
))
522 HeapFree(GetProcessHeap(), 0, Expanded
);
524 /* Only \SystemRoot\ is missing */
525 *RelativeName
= HeapAlloc(GetProcessHeap(),
527 (ServiceNameLen
- ExpandedLen
) * sizeof(WCHAR
) + 13*sizeof(WCHAR
));
528 if (*RelativeName
== NULL
)
530 DPRINT("Error allocating memory for boot driver name!\n");
531 return ERROR_NOT_ENOUGH_MEMORY
;
534 wcscpy(*RelativeName
, L
"\\SystemRoot\\");
535 wcscat(*RelativeName
, CanonName
+ ExpandedLen
);
537 return ERROR_SUCCESS
;
540 /* No longer need this */
541 HeapFree(GetProcessHeap(), 0, Expanded
);
543 /* The most complex case starts here */
544 RtlInitUnicodeString(&SystemRoot
, L
"\\SystemRoot");
545 InitializeObjectAttributes(&ObjectAttributes
,
547 OBJ_CASE_INSENSITIVE
,
551 /* Open this symlink */
552 Status
= NtOpenSymbolicLinkObject(&SymbolicLinkHandle
, SYMBOLIC_LINK_QUERY
, &ObjectAttributes
);
553 if (NT_SUCCESS(Status
))
555 DPRINT("Opened symbolic link object\n");
557 RtlInitEmptyUnicodeString(&LinkTarget
, NULL
, 0);
558 Status
= NtQuerySymbolicLinkObject(SymbolicLinkHandle
, &LinkTarget
, &BufferSize
);
559 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_TOO_SMALL
)
561 /* Check if required buffer size is sane */
562 if (BufferSize
> UNICODE_STRING_MAX_BYTES
- sizeof(UNICODE_NULL
))
564 DPRINT("Too large buffer required\n");
566 NtClose(SymbolicLinkHandle
);
567 return ERROR_NOT_ENOUGH_MEMORY
;
570 /* Alloc the string */
571 LinkTarget
.Length
= (USHORT
)BufferSize
;
572 LinkTarget
.MaximumLength
= LinkTarget
.Length
+ sizeof(UNICODE_NULL
);
573 LinkTarget
.Buffer
= HeapAlloc(GetProcessHeap(),
575 LinkTarget
.MaximumLength
);
576 if (!LinkTarget
.Buffer
)
578 DPRINT("Unable to alloc buffer\n");
579 NtClose(SymbolicLinkHandle
);
580 return ERROR_NOT_ENOUGH_MEMORY
;
583 /* Do a real query now */
584 Status
= NtQuerySymbolicLinkObject(SymbolicLinkHandle
, &LinkTarget
, &BufferSize
);
585 NtClose(SymbolicLinkHandle
);
586 if (NT_SUCCESS(Status
))
588 DPRINT("LinkTarget: %wZ\n", &LinkTarget
);
590 ExpandedLen
= LinkTarget
.Length
/ sizeof(WCHAR
);
591 if ((ServiceNameLen
> ExpandedLen
) &&
592 !_wcsnicmp(LinkTarget
.Buffer
, CanonName
, ExpandedLen
))
594 *RelativeName
= HeapAlloc(GetProcessHeap(),
596 (ServiceNameLen
- ExpandedLen
) * sizeof(WCHAR
) + 13*sizeof(WCHAR
));
598 if (*RelativeName
== NULL
)
600 DPRINT("Unable to alloc buffer\n");
601 return ERROR_NOT_ENOUGH_MEMORY
;
604 /* Copy it over, substituting the first part
606 wcscpy(*RelativeName
, L
"\\SystemRoot\\");
607 wcscat(*RelativeName
, CanonName
+ExpandedLen
+1);
610 return ERROR_SUCCESS
;
614 return ERROR_INVALID_PARAMETER
;
619 DPRINT("Error, Status = %08X\n", Status
);
620 return ERROR_INVALID_PARAMETER
;
625 DPRINT("Error, Status = %08X\n", Status
);
626 NtClose(SymbolicLinkHandle
);
627 return ERROR_INVALID_PARAMETER
;
633 DPRINT("Error, Status = %08X\n", Status
);
634 return ERROR_INVALID_PARAMETER
;
640 ScmCanonDriverImagePath(DWORD dwStartType
,
641 const wchar_t *lpServiceName
,
642 wchar_t **lpCanonName
)
645 SIZE_T ServiceNameLen
;
646 UNICODE_STRING NtServiceName
;
648 const WCHAR
*SourceName
= lpServiceName
;
650 /* Calculate the length of the service's name */
651 ServiceNameLen
= wcslen(lpServiceName
);
653 /* 12 is wcslen(L"\\SystemRoot\\") */
654 if (ServiceNameLen
> 12 &&
655 !_wcsnicmp(L
"\\SystemRoot\\", lpServiceName
, 12))
657 /* SystemRoot prefix is already included */
658 *lpCanonName
= HeapAlloc(GetProcessHeap(),
660 (ServiceNameLen
+ 1) * sizeof(WCHAR
));
662 if (*lpCanonName
== NULL
)
664 DPRINT("Error allocating memory for canonized service name!\n");
665 return ERROR_NOT_ENOUGH_MEMORY
;
668 /* If it's a boot-time driver, it must be systemroot relative */
669 if (dwStartType
== SERVICE_BOOT_START
)
673 wcscpy(*lpCanonName
, SourceName
);
675 DPRINT("Canonicalized name %S\n", *lpCanonName
);
679 /* Check if it has %SystemRoot% (len=13) */
680 if (ServiceNameLen
> 13 &&
681 !_wcsnicmp(L
"%SystemRoot%\\", lpServiceName
, 13))
683 /* Substitute %SystemRoot% with \\SystemRoot\\ */
684 *lpCanonName
= HeapAlloc(GetProcessHeap(),
686 (ServiceNameLen
+ 1) * sizeof(WCHAR
));
688 if (*lpCanonName
== NULL
)
690 DPRINT("Error allocating memory for canonized service name!\n");
691 return ERROR_NOT_ENOUGH_MEMORY
;
694 /* If it's a boot-time driver, it must be systemroot relative */
695 if (dwStartType
== SERVICE_BOOT_START
)
696 wcscpy(*lpCanonName
, L
"\\SystemRoot\\");
698 wcscat(*lpCanonName
, lpServiceName
+ 13);
700 DPRINT("Canonicalized name %S\n", *lpCanonName
);
704 /* Check if it's a relative path name */
705 if (lpServiceName
[0] != L
'\\' && lpServiceName
[1] != L
':')
707 *lpCanonName
= HeapAlloc(GetProcessHeap(),
709 (ServiceNameLen
+ 1) * sizeof(WCHAR
));
711 if (*lpCanonName
== NULL
)
713 DPRINT("Error allocating memory for canonized service name!\n");
714 return ERROR_NOT_ENOUGH_MEMORY
;
717 /* Just copy it over without changing */
718 wcscpy(*lpCanonName
, lpServiceName
);
723 /* It seems to be a DOS path, convert it */
724 if (!RtlDosPathNameToNtPathName_U(lpServiceName
, &NtServiceName
, NULL
, NULL
))
726 DPRINT("RtlDosPathNameToNtPathName_U() failed!\n");
727 return ERROR_INVALID_PARAMETER
;
730 *lpCanonName
= HeapAlloc(GetProcessHeap(),
732 NtServiceName
.Length
+ sizeof(WCHAR
));
734 if (*lpCanonName
== NULL
)
736 DPRINT("Error allocating memory for canonized service name!\n");
737 RtlFreeUnicodeString(&NtServiceName
);
738 return ERROR_NOT_ENOUGH_MEMORY
;
741 /* Copy the string */
742 wcsncpy(*lpCanonName
, NtServiceName
.Buffer
, NtServiceName
.Length
/ sizeof(WCHAR
));
744 /* The unicode string is not needed anymore */
745 RtlFreeUnicodeString(&NtServiceName
);
747 if (dwStartType
!= SERVICE_BOOT_START
)
749 DPRINT("Canonicalized name %S\n", *lpCanonName
);
753 /* The service is boot-started, so must be relative */
754 Result
= ScmConvertToBootPathName(*lpCanonName
, &RelativeName
);
757 /* There is a problem, free name and return */
758 HeapFree(GetProcessHeap(), 0, *lpCanonName
);
759 DPRINT("Error converting named!\n");
763 ASSERT(RelativeName
);
765 /* Copy that string */
766 wcscpy(*lpCanonName
, RelativeName
+ 12);
768 /* Free the allocated buffer */
769 HeapFree(GetProcessHeap(), 0, RelativeName
);
771 DPRINT("Canonicalized name %S\n", *lpCanonName
);
778 /* Internal recursive function */
779 /* Need to search for every dependency on every service */
781 Int_EnumDependentServicesW(HKEY hServicesKey
,
783 DWORD dwServiceState
,
784 PSERVICE
*lpServices
,
785 LPDWORD pcbBytesNeeded
,
786 LPDWORD lpServicesReturned
)
788 DWORD dwError
= ERROR_SUCCESS
;
789 WCHAR szNameBuf
[MAX_PATH
];
790 WCHAR szValueBuf
[MAX_PATH
];
791 WCHAR
*lpszNameBuf
= szNameBuf
;
792 WCHAR
*lpszValueBuf
= szValueBuf
;
796 PSERVICE lpCurrentService
;
797 HKEY hServiceEnumKey
;
798 DWORD dwCurrentServiceState
= SERVICE_ACTIVE
;
799 DWORD dwDependServiceStrPtr
= 0;
800 DWORD dwRequiredSize
= 0;
802 /* Get the number of service keys */
803 dwError
= RegQueryInfoKeyW(hServicesKey
,
815 if (dwError
!= ERROR_SUCCESS
)
817 DPRINT("ERROR! Unable to get number of services keys.\n");
821 /* Iterate the service keys to see if another service depends on the this service */
822 for (dwIteration
= 0; dwIteration
< dwNumSubKeys
; dwIteration
++)
825 dwError
= RegEnumKeyExW(hServicesKey
,
833 if (dwError
!= ERROR_SUCCESS
)
836 /* Open the Service key */
837 dwError
= RegOpenKeyExW(hServicesKey
,
842 if (dwError
!= ERROR_SUCCESS
)
845 dwSize
= MAX_PATH
* sizeof(WCHAR
);
847 /* Check for the DependOnService Value */
848 dwError
= RegQueryValueExW(hServiceEnumKey
,
852 (LPBYTE
)lpszValueBuf
,
855 /* FIXME: Handle load order. */
857 /* If the service found has a DependOnService value */
858 if (dwError
== ERROR_SUCCESS
)
860 dwDependServiceStrPtr
= 0;
862 /* Can be more than one Dependencies in the DependOnService string */
863 while (wcslen(lpszValueBuf
+ dwDependServiceStrPtr
) > 0)
865 if (_wcsicmp(lpszValueBuf
+ dwDependServiceStrPtr
, lpService
->lpServiceName
) == 0)
867 /* Get the current enumed service pointer */
868 lpCurrentService
= ScmGetServiceEntryByName(lpszNameBuf
);
870 /* Check for valid Service */
871 if (!lpCurrentService
)
873 /* This should never happen! */
874 DPRINT("This should not happen at this point, report to Developer\n");
875 return ERROR_NOT_FOUND
;
878 /* Determine state the service is in */
879 if (lpCurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
880 dwCurrentServiceState
= SERVICE_INACTIVE
;
882 /* If the ServiceState matches that requested or searching for SERVICE_STATE_ALL */
883 if ((dwCurrentServiceState
== dwServiceState
) ||
884 (dwServiceState
== SERVICE_STATE_ALL
))
886 /* Calculate the required size */
887 dwRequiredSize
+= sizeof(SERVICE_STATUS
);
888 dwRequiredSize
+= (DWORD
)((wcslen(lpCurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
));
889 dwRequiredSize
+= (DWORD
)((wcslen(lpCurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
891 /* Add the size for service name and display name pointers */
892 dwRequiredSize
+= (2 * sizeof(PVOID
));
894 /* increase the BytesNeeded size */
895 *pcbBytesNeeded
= *pcbBytesNeeded
+ dwRequiredSize
;
897 /* Don't fill callers buffer yet, as MSDN read that the last service with dependency
900 /* Recursive call to check for its dependencies */
901 Int_EnumDependentServicesW(hServicesKey
,
908 /* If the lpServices is valid set the service pointer */
910 lpServices
[*lpServicesReturned
] = lpCurrentService
;
912 *lpServicesReturned
= *lpServicesReturned
+ 1;
916 dwDependServiceStrPtr
+= (DWORD
)(wcslen(lpszValueBuf
+ dwDependServiceStrPtr
) + 1);
919 else if (*pcbBytesNeeded
)
921 dwError
= ERROR_SUCCESS
;
924 RegCloseKey(hServiceEnumKey
);
935 LPSC_RPC_HANDLE hSCObject
)
937 PMANAGER_HANDLE hManager
;
938 PSERVICE_HANDLE hService
;
942 DWORD pcbBytesNeeded
= 0;
943 DWORD dwServicesReturned
= 0;
945 DPRINT("RCloseServiceHandle() called\n");
947 DPRINT("hSCObject = %p\n", *hSCObject
);
950 return ERROR_INVALID_HANDLE
;
952 hManager
= ScmGetServiceManagerFromHandle(*hSCObject
);
953 hService
= ScmGetServiceFromHandle(*hSCObject
);
955 if (hManager
!= NULL
)
957 DPRINT("Found manager handle\n");
959 /* Make sure we don't access stale memory if someone tries to use this handle again. */
960 hManager
->Handle
.Tag
= INVALID_TAG
;
962 HeapFree(GetProcessHeap(), 0, hManager
);
967 DPRINT("RCloseServiceHandle() done\n");
968 return ERROR_SUCCESS
;
970 else if (hService
!= NULL
)
972 DPRINT("Found service handle\n");
974 /* Lock the service database exclusively */
975 ScmLockDatabaseExclusive();
977 /* Get the pointer to the service record */
978 lpService
= hService
->ServiceEntry
;
980 /* Make sure we don't access stale memory if someone tries to use this handle again. */
981 hService
->Handle
.Tag
= INVALID_TAG
;
983 /* Free the handle */
984 HeapFree(GetProcessHeap(), 0, hService
);
987 ASSERT(lpService
->dwRefCount
> 0);
989 lpService
->dwRefCount
--;
990 DPRINT("CloseServiceHandle - lpService->dwRefCount %u\n",
991 lpService
->dwRefCount
);
993 if (lpService
->dwRefCount
== 0)
995 /* If this service has been marked for deletion */
996 if (lpService
->bDeleted
&&
997 lpService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
999 /* Open the Services Reg key */
1000 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1001 L
"System\\CurrentControlSet\\Services",
1003 KEY_SET_VALUE
| KEY_READ
,
1005 if (dwError
!= ERROR_SUCCESS
)
1007 DPRINT("Failed to open services key\n");
1008 ScmUnlockDatabase();
1012 /* Call the internal function with NULL, just to get bytes we need */
1013 Int_EnumDependentServicesW(hServicesKey
,
1018 &dwServicesReturned
);
1020 /* If pcbBytesNeeded returned a value then there are services running that are dependent on this service */
1023 DPRINT("Deletion failed due to running dependencies.\n");
1024 RegCloseKey(hServicesKey
);
1025 ScmUnlockDatabase();
1026 return ERROR_SUCCESS
;
1029 /* There are no references and no running dependencies,
1030 it is now safe to delete the service */
1032 /* Delete the Service Key */
1033 dwError
= ScmDeleteRegKey(hServicesKey
,
1034 lpService
->lpServiceName
);
1036 RegCloseKey(hServicesKey
);
1038 if (dwError
!= ERROR_SUCCESS
)
1040 DPRINT("Failed to Delete the Service Registry key\n");
1041 ScmUnlockDatabase();
1045 /* Delete the Service */
1046 ScmDeleteServiceRecord(lpService
);
1050 ScmUnlockDatabase();
1054 DPRINT("RCloseServiceHandle() done\n");
1055 return ERROR_SUCCESS
;
1058 DPRINT("Invalid handle tag (Tag %lx)\n", hManager
->Handle
.Tag
);
1060 return ERROR_INVALID_HANDLE
;
1068 SC_RPC_HANDLE hService
,
1070 LPSERVICE_STATUS lpServiceStatus
)
1072 PSERVICE_HANDLE hSvc
;
1074 ACCESS_MASK DesiredAccess
;
1075 DWORD dwError
= ERROR_SUCCESS
;
1076 DWORD pcbBytesNeeded
= 0;
1077 DWORD dwServicesReturned
= 0;
1078 DWORD dwControlsAccepted
;
1079 DWORD dwCurrentState
;
1080 HKEY hServicesKey
= NULL
;
1081 LPCWSTR lpLogStrings
[2];
1082 WCHAR szLogBuffer
[80];
1085 DPRINT("RControlService() called\n");
1088 return ERROR_SHUTDOWN_IN_PROGRESS
;
1090 /* Check the service handle */
1091 hSvc
= ScmGetServiceFromHandle(hService
);
1094 DPRINT1("Invalid service handle!\n");
1095 return ERROR_INVALID_HANDLE
;
1098 /* Check the service entry point */
1099 lpService
= hSvc
->ServiceEntry
;
1100 if (lpService
== NULL
)
1102 DPRINT1("lpService == NULL!\n");
1103 return ERROR_INVALID_HANDLE
;
1106 /* Check access rights */
1109 case SERVICE_CONTROL_STOP
:
1110 DesiredAccess
= SERVICE_STOP
;
1113 case SERVICE_CONTROL_PAUSE
:
1114 case SERVICE_CONTROL_CONTINUE
:
1115 case SERVICE_CONTROL_PARAMCHANGE
:
1116 case SERVICE_CONTROL_NETBINDADD
:
1117 case SERVICE_CONTROL_NETBINDREMOVE
:
1118 case SERVICE_CONTROL_NETBINDENABLE
:
1119 case SERVICE_CONTROL_NETBINDDISABLE
:
1120 DesiredAccess
= SERVICE_PAUSE_CONTINUE
;
1123 case SERVICE_CONTROL_INTERROGATE
:
1124 DesiredAccess
= SERVICE_INTERROGATE
;
1128 if (dwControl
>= 128 && dwControl
<= 255)
1129 DesiredAccess
= SERVICE_USER_DEFINED_CONTROL
;
1131 return ERROR_INVALID_PARAMETER
;
1135 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1137 return ERROR_ACCESS_DENIED
;
1139 /* Return the current service status information */
1140 RtlCopyMemory(lpServiceStatus
,
1142 sizeof(SERVICE_STATUS
));
1144 if (dwControl
== SERVICE_CONTROL_STOP
)
1146 /* Check if the service has dependencies running as windows
1147 doesn't stop a service that does */
1149 /* Open the Services Reg key */
1150 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1151 L
"System\\CurrentControlSet\\Services",
1155 if (dwError
!= ERROR_SUCCESS
)
1157 DPRINT("Failed to open services key\n");
1161 /* Call the internal function with NULL, just to get bytes we need */
1162 Int_EnumDependentServicesW(hServicesKey
,
1167 &dwServicesReturned
);
1169 RegCloseKey(hServicesKey
);
1171 /* If pcbBytesNeeded is not zero then there are services running that
1172 are dependent on this service */
1173 if (pcbBytesNeeded
!= 0)
1175 DPRINT("Service has running dependencies. Failed to stop service.\n");
1176 return ERROR_DEPENDENT_SERVICES_RUNNING
;
1180 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
1182 /* Send control code to the driver */
1183 dwError
= ScmControlDriver(lpService
,
1189 dwControlsAccepted
= lpService
->Status
.dwControlsAccepted
;
1190 dwCurrentState
= lpService
->Status
.dwCurrentState
;
1192 /* Return ERROR_SERVICE_NOT_ACTIVE if the service has not been started */
1193 if (lpService
->lpImage
== NULL
|| dwCurrentState
== SERVICE_STOPPED
)
1194 return ERROR_SERVICE_NOT_ACTIVE
;
1196 /* Check the current state before sending a control request */
1197 switch (dwCurrentState
)
1199 case SERVICE_STOP_PENDING
:
1200 case SERVICE_STOPPED
:
1201 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL
;
1203 case SERVICE_START_PENDING
:
1206 case SERVICE_CONTROL_STOP
:
1209 case SERVICE_CONTROL_INTERROGATE
:
1210 RtlCopyMemory(lpServiceStatus
,
1212 sizeof(SERVICE_STATUS
));
1213 return ERROR_SUCCESS
;
1216 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL
;
1221 /* Check if the control code is acceptable to the service */
1224 case SERVICE_CONTROL_STOP
:
1225 if ((dwControlsAccepted
& SERVICE_ACCEPT_STOP
) == 0)
1226 return ERROR_INVALID_SERVICE_CONTROL
;
1229 case SERVICE_CONTROL_PAUSE
:
1230 case SERVICE_CONTROL_CONTINUE
:
1231 if ((dwControlsAccepted
& SERVICE_ACCEPT_PAUSE_CONTINUE
) == 0)
1232 return ERROR_INVALID_SERVICE_CONTROL
;
1235 case SERVICE_CONTROL_PARAMCHANGE
:
1236 if ((dwControlsAccepted
& SERVICE_ACCEPT_PARAMCHANGE
) == 0)
1237 return ERROR_INVALID_SERVICE_CONTROL
;
1240 case SERVICE_CONTROL_NETBINDADD
:
1241 case SERVICE_CONTROL_NETBINDREMOVE
:
1242 case SERVICE_CONTROL_NETBINDENABLE
:
1243 case SERVICE_CONTROL_NETBINDDISABLE
:
1244 if ((dwControlsAccepted
& SERVICE_ACCEPT_NETBINDCHANGE
) == 0)
1245 return ERROR_INVALID_SERVICE_CONTROL
;
1249 /* Send control code to the service */
1250 dwError
= ScmControlService(lpService
->lpImage
->hControlPipe
,
1251 lpService
->lpServiceName
,
1252 (SERVICE_STATUS_HANDLE
)lpService
,
1255 /* Return service status information */
1256 RtlCopyMemory(lpServiceStatus
,
1258 sizeof(SERVICE_STATUS
));
1261 if (dwError
== ERROR_SUCCESS
)
1263 if (dwControl
== SERVICE_CONTROL_STOP
||
1264 dwControl
== SERVICE_CONTROL_PAUSE
||
1265 dwControl
== SERVICE_CONTROL_CONTINUE
)
1267 /* Log a successful send control */
1271 case SERVICE_CONTROL_STOP
:
1272 uID
= IDS_SERVICE_STOP
;
1275 case SERVICE_CONTROL_PAUSE
:
1276 uID
= IDS_SERVICE_PAUSE
;
1279 case SERVICE_CONTROL_CONTINUE
:
1280 uID
= IDS_SERVICE_RESUME
;
1283 LoadStringW(GetModuleHandle(NULL
), uID
, szLogBuffer
, ARRAYSIZE(szLogBuffer
));
1285 lpLogStrings
[0] = lpService
->lpDisplayName
;
1286 lpLogStrings
[1] = szLogBuffer
;
1288 ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS
,
1289 EVENTLOG_INFORMATION_TYPE
,
1303 SC_RPC_HANDLE hService
)
1305 PSERVICE_HANDLE hSvc
;
1309 DPRINT("RDeleteService() called\n");
1312 return ERROR_SHUTDOWN_IN_PROGRESS
;
1314 hSvc
= ScmGetServiceFromHandle(hService
);
1317 DPRINT1("Invalid service handle!\n");
1318 return ERROR_INVALID_HANDLE
;
1321 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1323 return ERROR_ACCESS_DENIED
;
1325 lpService
= hSvc
->ServiceEntry
;
1326 if (lpService
== NULL
)
1328 DPRINT("lpService == NULL!\n");
1329 return ERROR_INVALID_HANDLE
;
1332 /* Lock the service database exclusively */
1333 ScmLockDatabaseExclusive();
1335 if (lpService
->bDeleted
)
1337 DPRINT("The service has already been marked for delete!\n");
1338 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
1342 /* Mark service for delete */
1343 lpService
->bDeleted
= TRUE
;
1345 dwError
= ScmMarkServiceForDelete(lpService
);
1348 /* Unlock the service database */
1349 ScmUnlockDatabase();
1351 DPRINT("RDeleteService() done\n");
1360 RLockServiceDatabase(
1361 SC_RPC_HANDLE hSCManager
,
1362 LPSC_RPC_LOCK lpLock
)
1364 PMANAGER_HANDLE hMgr
;
1366 DPRINT("RLockServiceDatabase() called\n");
1370 hMgr
= ScmGetServiceManagerFromHandle(hSCManager
);
1373 DPRINT1("Invalid service manager handle!\n");
1374 return ERROR_INVALID_HANDLE
;
1377 if (!RtlAreAllAccessesGranted(hMgr
->Handle
.DesiredAccess
,
1379 return ERROR_ACCESS_DENIED
;
1381 return ScmAcquireServiceStartLock(FALSE
, lpLock
);
1388 RQueryServiceObjectSecurity(
1389 SC_RPC_HANDLE hService
,
1390 SECURITY_INFORMATION dwSecurityInformation
,
1391 LPBYTE lpSecurityDescriptor
,
1393 LPBOUNDED_DWORD_256K pcbBytesNeeded
)
1395 PSERVICE_HANDLE hSvc
;
1397 ULONG DesiredAccess
= 0;
1399 DWORD dwBytesNeeded
;
1402 DPRINT("RQueryServiceObjectSecurity() called\n");
1404 hSvc
= ScmGetServiceFromHandle(hService
);
1407 DPRINT1("Invalid service handle!\n");
1408 return ERROR_INVALID_HANDLE
;
1411 if (dwSecurityInformation
& (DACL_SECURITY_INFORMATION
|
1412 GROUP_SECURITY_INFORMATION
|
1413 OWNER_SECURITY_INFORMATION
))
1414 DesiredAccess
|= READ_CONTROL
;
1416 if (dwSecurityInformation
& SACL_SECURITY_INFORMATION
)
1417 DesiredAccess
|= ACCESS_SYSTEM_SECURITY
;
1419 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1422 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1423 return ERROR_ACCESS_DENIED
;
1426 lpService
= hSvc
->ServiceEntry
;
1427 if (lpService
== NULL
)
1429 DPRINT("lpService == NULL!\n");
1430 return ERROR_INVALID_HANDLE
;
1433 /* Lock the service database */
1434 ScmLockDatabaseShared();
1436 /* Retrieve the security descriptor */
1437 Status
= RtlQuerySecurityObject(lpService
->pSecurityDescriptor
,
1438 dwSecurityInformation
,
1439 (PSECURITY_DESCRIPTOR
)lpSecurityDescriptor
,
1443 /* Unlock the service database */
1444 ScmUnlockDatabase();
1446 if (NT_SUCCESS(Status
))
1448 *pcbBytesNeeded
= dwBytesNeeded
;
1449 dwError
= STATUS_SUCCESS
;
1451 else if (Status
== STATUS_BUFFER_TOO_SMALL
)
1453 *pcbBytesNeeded
= dwBytesNeeded
;
1454 dwError
= ERROR_INSUFFICIENT_BUFFER
;
1456 else if (Status
== STATUS_BAD_DESCRIPTOR_FORMAT
)
1458 dwError
= ERROR_GEN_FAILURE
;
1462 dwError
= RtlNtStatusToDosError(Status
);
1472 RSetServiceObjectSecurity(
1473 SC_RPC_HANDLE hService
,
1474 DWORD dwSecurityInformation
,
1475 LPBYTE lpSecurityDescriptor
,
1476 DWORD dwSecurityDescriptorSize
)
1478 PSERVICE_HANDLE hSvc
;
1480 ACCESS_MASK DesiredAccess
= 0;
1481 HANDLE hToken
= NULL
;
1482 HKEY hServiceKey
= NULL
;
1483 BOOL bDatabaseLocked
= FALSE
;
1487 DPRINT("RSetServiceObjectSecurity() called\n");
1489 hSvc
= ScmGetServiceFromHandle(hService
);
1492 DPRINT1("Invalid service handle!\n");
1493 return ERROR_INVALID_HANDLE
;
1496 if (dwSecurityInformation
== 0 ||
1497 dwSecurityInformation
& ~(OWNER_SECURITY_INFORMATION
| GROUP_SECURITY_INFORMATION
1498 | DACL_SECURITY_INFORMATION
| SACL_SECURITY_INFORMATION
))
1500 return ERROR_INVALID_PARAMETER
;
1503 if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR
)lpSecurityDescriptor
))
1504 return ERROR_INVALID_PARAMETER
;
1506 if (dwSecurityInformation
& SACL_SECURITY_INFORMATION
)
1507 DesiredAccess
|= ACCESS_SYSTEM_SECURITY
;
1509 if (dwSecurityInformation
& DACL_SECURITY_INFORMATION
)
1510 DesiredAccess
|= WRITE_DAC
;
1512 if (dwSecurityInformation
& (OWNER_SECURITY_INFORMATION
| GROUP_SECURITY_INFORMATION
))
1513 DesiredAccess
|= WRITE_OWNER
;
1515 if ((dwSecurityInformation
& OWNER_SECURITY_INFORMATION
) &&
1516 (((PISECURITY_DESCRIPTOR
)lpSecurityDescriptor
)->Owner
== NULL
))
1518 return ERROR_INVALID_PARAMETER
;
1521 if ((dwSecurityInformation
& GROUP_SECURITY_INFORMATION
) &&
1522 (((PISECURITY_DESCRIPTOR
)lpSecurityDescriptor
)->Group
== NULL
))
1524 return ERROR_INVALID_PARAMETER
;
1527 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1530 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1531 return ERROR_ACCESS_DENIED
;
1534 lpService
= hSvc
->ServiceEntry
;
1535 if (lpService
== NULL
)
1537 DPRINT1("lpService == NULL!\n");
1538 return ERROR_INVALID_HANDLE
;
1541 if (lpService
->bDeleted
)
1542 return ERROR_SERVICE_MARKED_FOR_DELETE
;
1545 RpcImpersonateClient(NULL
);
1547 Status
= NtOpenThreadToken(NtCurrentThread(),
1551 if (!NT_SUCCESS(Status
))
1552 return RtlNtStatusToDosError(Status
);
1557 /* Build the new security descriptor */
1558 Status
= RtlSetSecurityObject(dwSecurityInformation
,
1559 (PSECURITY_DESCRIPTOR
)lpSecurityDescriptor
,
1560 &lpService
->pSecurityDescriptor
,
1563 if (!NT_SUCCESS(Status
))
1565 dwError
= RtlNtStatusToDosError(Status
);
1569 /* Lock the service database exclusive */
1570 ScmLockDatabaseExclusive();
1571 bDatabaseLocked
= TRUE
;
1573 /* Open the service key */
1574 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
1575 READ_CONTROL
| KEY_CREATE_SUB_KEY
| KEY_SET_VALUE
,
1577 if (dwError
!= ERROR_SUCCESS
)
1580 /* Store the new security descriptor */
1581 dwError
= ScmWriteSecurityDescriptor(hServiceKey
,
1582 lpService
->pSecurityDescriptor
);
1584 RegFlushKey(hServiceKey
);
1587 if (hServiceKey
!= NULL
)
1588 RegCloseKey(hServiceKey
);
1590 /* Unlock service database */
1591 if (bDatabaseLocked
== TRUE
)
1592 ScmUnlockDatabase();
1597 DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError
);
1606 RQueryServiceStatus(
1607 SC_RPC_HANDLE hService
,
1608 LPSERVICE_STATUS lpServiceStatus
)
1610 PSERVICE_HANDLE hSvc
;
1613 DPRINT("RQueryServiceStatus() called\n");
1616 return ERROR_SHUTDOWN_IN_PROGRESS
;
1618 hSvc
= ScmGetServiceFromHandle(hService
);
1621 DPRINT1("Invalid service handle!\n");
1622 return ERROR_INVALID_HANDLE
;
1625 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1626 SERVICE_QUERY_STATUS
))
1628 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1629 return ERROR_ACCESS_DENIED
;
1632 lpService
= hSvc
->ServiceEntry
;
1633 if (lpService
== NULL
)
1635 DPRINT("lpService == NULL!\n");
1636 return ERROR_INVALID_HANDLE
;
1639 /* Lock the service database shared */
1640 ScmLockDatabaseShared();
1642 /* Return service status information */
1643 RtlCopyMemory(lpServiceStatus
,
1645 sizeof(SERVICE_STATUS
));
1647 /* Unlock the service database */
1648 ScmUnlockDatabase();
1650 return ERROR_SUCCESS
;
1655 ScmIsValidServiceState(DWORD dwCurrentState
)
1657 switch (dwCurrentState
)
1659 case SERVICE_STOPPED
:
1660 case SERVICE_START_PENDING
:
1661 case SERVICE_STOP_PENDING
:
1662 case SERVICE_RUNNING
:
1663 case SERVICE_CONTINUE_PENDING
:
1664 case SERVICE_PAUSE_PENDING
:
1665 case SERVICE_PAUSED
:
1678 RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
1679 LPSERVICE_STATUS lpServiceStatus
)
1682 DWORD dwPreviousState
;
1683 DWORD dwPreviousType
;
1684 LPCWSTR lpLogStrings
[2];
1685 WCHAR szLogBuffer
[80];
1688 DPRINT("RSetServiceStatus() called\n");
1689 DPRINT("hServiceStatus = %lu\n", hServiceStatus
);
1690 DPRINT("dwServiceType = 0x%lx\n", lpServiceStatus
->dwServiceType
);
1691 DPRINT("dwCurrentState = %lu\n", lpServiceStatus
->dwCurrentState
);
1692 DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus
->dwControlsAccepted
);
1693 DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus
->dwWin32ExitCode
);
1694 DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus
->dwServiceSpecificExitCode
);
1695 DPRINT("dwCheckPoint = %lu\n", lpServiceStatus
->dwCheckPoint
);
1696 DPRINT("dwWaitHint = %lu\n", lpServiceStatus
->dwWaitHint
);
1698 if (hServiceStatus
== 0)
1700 DPRINT("hServiceStatus == NULL!\n");
1701 return ERROR_INVALID_HANDLE
;
1704 lpService
= (PSERVICE
)hServiceStatus
;
1706 /* Check current state */
1707 if (!ScmIsValidServiceState(lpServiceStatus
->dwCurrentState
))
1709 DPRINT("Invalid service state!\n");
1710 return ERROR_INVALID_DATA
;
1713 /* Check service type */
1714 if (!(lpServiceStatus
->dwServiceType
& SERVICE_WIN32
) &&
1715 (lpServiceStatus
->dwServiceType
& SERVICE_DRIVER
))
1717 DPRINT("Invalid service type!\n");
1718 return ERROR_INVALID_DATA
;
1721 /* Check accepted controls */
1722 if (lpServiceStatus
->dwControlsAccepted
& ~0xFF)
1724 DPRINT("Invalid controls accepted!\n");
1725 return ERROR_INVALID_DATA
;
1728 /* Set the wait hint and check point only if the service is in a pending state,
1729 otherwise they should be 0 */
1730 if (lpServiceStatus
->dwCurrentState
== SERVICE_STOPPED
||
1731 lpServiceStatus
->dwCurrentState
== SERVICE_PAUSED
||
1732 lpServiceStatus
->dwCurrentState
== SERVICE_RUNNING
)
1734 lpServiceStatus
->dwWaitHint
= 0;
1735 lpServiceStatus
->dwCheckPoint
= 0;
1738 /* Lock the service database exclusively */
1739 ScmLockDatabaseExclusive();
1741 /* Save the current service state */
1742 dwPreviousState
= lpService
->Status
.dwCurrentState
;
1744 /* Save the current service type */
1745 dwPreviousType
= lpService
->Status
.dwServiceType
;
1747 /* Update the service status */
1748 RtlCopyMemory(&lpService
->Status
,
1750 sizeof(SERVICE_STATUS
));
1752 /* Restore the previous service type */
1753 lpService
->Status
.dwServiceType
= dwPreviousType
;
1755 /* Dereference a stopped service */
1756 if ((lpServiceStatus
->dwServiceType
& SERVICE_WIN32
) &&
1757 (lpServiceStatus
->dwCurrentState
== SERVICE_STOPPED
))
1759 /* Decrement the image run counter */
1760 lpService
->lpImage
->dwImageRunCount
--;
1762 /* If we just stopped the last running service... */
1763 if (lpService
->lpImage
->dwImageRunCount
== 0)
1765 /* Stop the dispatcher thread */
1766 ScmControlService(lpService
->lpImage
->hControlPipe
,
1768 (SERVICE_STATUS_HANDLE
)lpService
,
1769 SERVICE_CONTROL_STOP
);
1771 /* Remove the service image */
1772 ScmRemoveServiceImage(lpService
->lpImage
);
1773 lpService
->lpImage
= NULL
;
1777 /* Unlock the service database */
1778 ScmUnlockDatabase();
1780 if ((lpServiceStatus
->dwCurrentState
== SERVICE_STOPPED
) &&
1781 (dwPreviousState
!= SERVICE_STOPPED
) &&
1782 (lpServiceStatus
->dwWin32ExitCode
!= ERROR_SUCCESS
))
1784 /* Log a failed service stop */
1785 StringCchPrintfW(szLogBuffer
, ARRAYSIZE(szLogBuffer
),
1786 L
"%lu", lpServiceStatus
->dwWin32ExitCode
);
1787 lpLogStrings
[0] = lpService
->lpDisplayName
;
1788 lpLogStrings
[1] = szLogBuffer
;
1790 ScmLogEvent(EVENT_SERVICE_EXIT_FAILED
,
1791 EVENTLOG_ERROR_TYPE
,
1795 else if (lpServiceStatus
->dwCurrentState
!= dwPreviousState
&&
1796 (lpServiceStatus
->dwCurrentState
== SERVICE_STOPPED
||
1797 lpServiceStatus
->dwCurrentState
== SERVICE_RUNNING
||
1798 lpServiceStatus
->dwCurrentState
== SERVICE_PAUSED
))
1800 /* Log a successful service status change */
1801 switch(lpServiceStatus
->dwCurrentState
)
1803 case SERVICE_STOPPED
:
1804 uID
= IDS_SERVICE_STOPPED
;
1807 case SERVICE_RUNNING
:
1808 uID
= IDS_SERVICE_RUNNING
;
1811 case SERVICE_PAUSED
:
1812 uID
= IDS_SERVICE_PAUSED
;
1816 LoadStringW(GetModuleHandle(NULL
), uID
, szLogBuffer
, ARRAYSIZE(szLogBuffer
));
1817 lpLogStrings
[0] = lpService
->lpDisplayName
;
1818 lpLogStrings
[1] = szLogBuffer
;
1820 ScmLogEvent(EVENT_SERVICE_STATUS_SUCCESS
,
1821 EVENTLOG_INFORMATION_TYPE
,
1826 DPRINT("Set %S to %lu\n", lpService
->lpDisplayName
, lpService
->Status
.dwCurrentState
);
1827 DPRINT("RSetServiceStatus() done\n");
1829 return ERROR_SUCCESS
;
1836 RUnlockServiceDatabase(
1839 DPRINT("RUnlockServiceDatabase(%p)\n", Lock
);
1840 return ScmReleaseServiceStartLock(Lock
);
1847 RNotifyBootConfigStatus(
1848 SVCCTL_HANDLEW lpMachineName
,
1849 DWORD BootAcceptable
)
1851 DPRINT1("RNotifyBootConfigStatus(%p %lu) called\n", lpMachineName
, BootAcceptable
);
1852 return ERROR_SUCCESS
;
1855 // return ERROR_CALL_NOT_IMPLEMENTED;
1862 RI_ScSetServiceBitsW(
1863 RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
1864 DWORD dwServiceBits
,
1866 int bUpdateImmediately
,
1871 DPRINT("RI_ScSetServiceBitsW(%p %lx %d %d %S)\n",
1872 hServiceStatus
, dwServiceBits
, bSetBitsOn
,
1873 bUpdateImmediately
, lpString
);
1876 return ERROR_SHUTDOWN_IN_PROGRESS
;
1878 if (lpString
!= NULL
)
1879 return ERROR_INVALID_PARAMETER
;
1881 if (hServiceStatus
== 0)
1883 DPRINT("hServiceStatus == NULL!\n");
1884 return ERROR_INVALID_HANDLE
;
1887 // FIXME: Validate the status handle
1888 pService
= (PSERVICE
)hServiceStatus
;
1892 DPRINT("Old service bits: %08lx\n", pService
->dwServiceBits
);
1893 DPRINT("Old global service bits: %08lx\n", g_dwServiceBits
);
1894 pService
->dwServiceBits
|= dwServiceBits
;
1895 g_dwServiceBits
|= dwServiceBits
;
1896 DPRINT("New service bits: %08lx\n", pService
->dwServiceBits
);
1897 DPRINT("New global service bits: %08lx\n", g_dwServiceBits
);
1901 DPRINT("Old service bits: %08lx\n", pService
->dwServiceBits
);
1902 DPRINT("Old global service bits: %08lx\n", g_dwServiceBits
);
1903 pService
->dwServiceBits
&= ~dwServiceBits
;
1904 g_dwServiceBits
&= ~dwServiceBits
;
1905 DPRINT("New service bits: %08lx\n", pService
->dwServiceBits
);
1906 DPRINT("New global service bits: %08lx\n", g_dwServiceBits
);
1909 return ERROR_SUCCESS
;
1916 RChangeServiceConfigW(
1917 SC_RPC_HANDLE hService
,
1918 DWORD dwServiceType
,
1920 DWORD dwErrorControl
,
1921 LPWSTR lpBinaryPathName
,
1922 LPWSTR lpLoadOrderGroup
,
1924 LPBYTE lpDependencies
,
1926 LPWSTR lpServiceStartName
,
1929 LPWSTR lpDisplayName
)
1931 DWORD dwError
= ERROR_SUCCESS
;
1932 PSERVICE_HANDLE hSvc
;
1933 PSERVICE lpService
= NULL
;
1934 HKEY hServiceKey
= NULL
;
1935 LPWSTR lpDisplayNameW
= NULL
;
1936 LPWSTR lpImagePathW
= NULL
;
1938 DPRINT("RChangeServiceConfigW() called\n");
1939 DPRINT("dwServiceType = 0x%lx\n", dwServiceType
);
1940 DPRINT("dwStartType = %lu\n", dwStartType
);
1941 DPRINT("dwErrorControl = %lu\n", dwErrorControl
);
1942 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName
);
1943 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup
);
1944 DPRINT("lpDisplayName = %S\n", lpDisplayName
);
1947 return ERROR_SHUTDOWN_IN_PROGRESS
;
1949 hSvc
= ScmGetServiceFromHandle(hService
);
1952 DPRINT1("Invalid service handle!\n");
1953 return ERROR_INVALID_HANDLE
;
1956 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1957 SERVICE_CHANGE_CONFIG
))
1959 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1960 return ERROR_ACCESS_DENIED
;
1963 /* Check for invalid service type value */
1964 if ((dwServiceType
!= SERVICE_NO_CHANGE
) &&
1965 (dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
1966 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
) &&
1967 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
1968 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
))
1970 return ERROR_INVALID_PARAMETER
;
1973 /* Check for invalid start type value */
1974 if ((dwStartType
!= SERVICE_NO_CHANGE
) &&
1975 (dwStartType
!= SERVICE_BOOT_START
) &&
1976 (dwStartType
!= SERVICE_SYSTEM_START
) &&
1977 (dwStartType
!= SERVICE_AUTO_START
) &&
1978 (dwStartType
!= SERVICE_DEMAND_START
) &&
1979 (dwStartType
!= SERVICE_DISABLED
))
1981 return ERROR_INVALID_PARAMETER
;
1984 /* Only drivers can be boot start or system start services */
1985 if ((dwStartType
== SERVICE_BOOT_START
) ||
1986 (dwStartType
== SERVICE_SYSTEM_START
))
1988 if ((dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
1989 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
1990 return ERROR_INVALID_PARAMETER
;
1993 /* Check for invalid error control value */
1994 if ((dwErrorControl
!= SERVICE_NO_CHANGE
) &&
1995 (dwErrorControl
!= SERVICE_ERROR_IGNORE
) &&
1996 (dwErrorControl
!= SERVICE_ERROR_NORMAL
) &&
1997 (dwErrorControl
!= SERVICE_ERROR_SEVERE
) &&
1998 (dwErrorControl
!= SERVICE_ERROR_CRITICAL
))
2000 return ERROR_INVALID_PARAMETER
;
2003 if (lpdwTagId
&& (!lpLoadOrderGroup
|| !*lpLoadOrderGroup
))
2005 return ERROR_INVALID_PARAMETER
;
2008 lpService
= hSvc
->ServiceEntry
;
2009 if (lpService
== NULL
)
2011 DPRINT("lpService == NULL!\n");
2012 return ERROR_INVALID_HANDLE
;
2015 /* Lock the service database exclusively */
2016 ScmLockDatabaseExclusive();
2018 if (lpService
->bDeleted
)
2020 DPRINT("The service has already been marked for delete!\n");
2021 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
2025 /* Open the service key */
2026 dwError
= ScmOpenServiceKey(lpService
->szServiceName
,
2029 if (dwError
!= ERROR_SUCCESS
)
2032 /* Write service data to the registry */
2034 /* Set the display name */
2035 if (lpDisplayName
!= NULL
&& *lpDisplayName
!= 0)
2037 RegSetValueExW(hServiceKey
,
2041 (LPBYTE
)lpDisplayName
,
2042 (DWORD
)((wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
)));
2044 /* Update the display name */
2045 lpDisplayNameW
= HeapAlloc(GetProcessHeap(),
2047 (wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
));
2048 if (lpDisplayNameW
== NULL
)
2050 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
2054 wcscpy(lpDisplayNameW
, lpDisplayName
);
2055 if (lpService
->lpDisplayName
!= lpService
->lpServiceName
)
2056 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
2058 lpService
->lpDisplayName
= lpDisplayNameW
;
2061 if (dwServiceType
!= SERVICE_NO_CHANGE
)
2063 /* Set the service type */
2064 dwError
= RegSetValueExW(hServiceKey
,
2068 (LPBYTE
)&dwServiceType
,
2070 if (dwError
!= ERROR_SUCCESS
)
2073 lpService
->Status
.dwServiceType
= dwServiceType
;
2076 if (dwStartType
!= SERVICE_NO_CHANGE
)
2078 /* Set the start value */
2079 dwError
= RegSetValueExW(hServiceKey
,
2083 (LPBYTE
)&dwStartType
,
2085 if (dwError
!= ERROR_SUCCESS
)
2088 lpService
->dwStartType
= dwStartType
;
2091 if (dwErrorControl
!= SERVICE_NO_CHANGE
)
2093 /* Set the error control value */
2094 dwError
= RegSetValueExW(hServiceKey
,
2098 (LPBYTE
)&dwErrorControl
,
2100 if (dwError
!= ERROR_SUCCESS
)
2103 lpService
->dwErrorControl
= dwErrorControl
;
2106 if (lpBinaryPathName
!= NULL
&& *lpBinaryPathName
!= 0)
2108 /* Set the image path */
2109 lpImagePathW
= lpBinaryPathName
;
2111 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
2113 dwError
= ScmCanonDriverImagePath(lpService
->dwStartType
,
2117 if (dwError
!= ERROR_SUCCESS
)
2121 dwError
= RegSetValueExW(hServiceKey
,
2125 (LPBYTE
)lpImagePathW
,
2126 (DWORD
)((wcslen(lpImagePathW
) + 1) * sizeof(WCHAR
)));
2128 if (lpImagePathW
!= lpBinaryPathName
)
2129 HeapFree(GetProcessHeap(), 0, lpImagePathW
);
2131 if (dwError
!= ERROR_SUCCESS
)
2135 /* Set the group name */
2136 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
2138 dwError
= RegSetValueExW(hServiceKey
,
2142 (LPBYTE
)lpLoadOrderGroup
,
2143 (DWORD
)((wcslen(lpLoadOrderGroup
) + 1) * sizeof(WCHAR
)));
2144 if (dwError
!= ERROR_SUCCESS
)
2147 dwError
= ScmSetServiceGroup(lpService
,
2149 if (dwError
!= ERROR_SUCCESS
)
2154 if (lpdwTagId
!= NULL
)
2156 dwError
= ScmAssignNewTag(lpService
);
2157 if (dwError
!= ERROR_SUCCESS
)
2160 dwError
= RegSetValueExW(hServiceKey
,
2164 (LPBYTE
)&lpService
->dwTag
,
2166 if (dwError
!= ERROR_SUCCESS
)
2169 *lpdwTagId
= lpService
->dwTag
;
2172 /* Write dependencies */
2173 if (lpDependencies
!= NULL
&& *lpDependencies
!= 0)
2175 dwError
= ScmWriteDependencies(hServiceKey
,
2176 (LPWSTR
)lpDependencies
,
2178 if (dwError
!= ERROR_SUCCESS
)
2182 /* Start name and password are only used by Win32 services */
2183 if (lpService
->Status
.dwServiceType
& SERVICE_WIN32
)
2185 /* Write service start name */
2186 if (lpServiceStartName
!= NULL
&& *lpServiceStartName
!= 0)
2188 dwError
= RegSetValueExW(hServiceKey
,
2192 (LPBYTE
)lpServiceStartName
,
2193 (DWORD
)((wcslen(lpServiceStartName
) + 1) * sizeof(WCHAR
)));
2194 if (dwError
!= ERROR_SUCCESS
)
2198 if (lpPassword
!= NULL
)
2200 if (*(LPWSTR
)lpPassword
!= 0)
2202 /* FIXME: Decrypt the password */
2204 /* Write the password */
2205 dwError
= ScmSetServicePassword(lpService
->szServiceName
,
2206 (LPCWSTR
)lpPassword
);
2207 if (dwError
!= ERROR_SUCCESS
)
2212 /* Delete the password */
2213 dwError
= ScmSetServicePassword(lpService
->szServiceName
,
2215 if (dwError
== ERROR_FILE_NOT_FOUND
)
2216 dwError
= ERROR_SUCCESS
;
2218 if (dwError
!= ERROR_SUCCESS
)
2225 if (hServiceKey
!= NULL
)
2226 RegCloseKey(hServiceKey
);
2228 /* Unlock the service database */
2229 ScmUnlockDatabase();
2231 DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError
);
2241 SC_RPC_HANDLE hSCManager
,
2242 LPCWSTR lpServiceName
,
2243 LPCWSTR lpDisplayName
,
2244 DWORD dwDesiredAccess
,
2245 DWORD dwServiceType
,
2247 DWORD dwErrorControl
,
2248 LPCWSTR lpBinaryPathName
,
2249 LPCWSTR lpLoadOrderGroup
,
2251 LPBYTE lpDependencies
,
2253 LPCWSTR lpServiceStartName
,
2256 LPSC_RPC_HANDLE lpServiceHandle
)
2258 PMANAGER_HANDLE hManager
;
2259 DWORD dwError
= ERROR_SUCCESS
;
2260 PSERVICE lpService
= NULL
;
2261 SC_HANDLE hServiceHandle
= NULL
;
2262 LPWSTR lpImagePath
= NULL
;
2263 HKEY hServiceKey
= NULL
;
2264 LPWSTR lpObjectName
;
2266 DPRINT("RCreateServiceW() called\n");
2267 DPRINT("lpServiceName = %S\n", lpServiceName
);
2268 DPRINT("lpDisplayName = %S\n", lpDisplayName
);
2269 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess
);
2270 DPRINT("dwServiceType = 0x%lx\n", dwServiceType
);
2271 DPRINT("dwStartType = %lu\n", dwStartType
);
2272 DPRINT("dwErrorControl = %lu\n", dwErrorControl
);
2273 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName
);
2274 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup
);
2275 DPRINT("lpdwTagId = %p\n", lpdwTagId
);
2278 return ERROR_SHUTDOWN_IN_PROGRESS
;
2280 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
2281 if (hManager
== NULL
)
2283 DPRINT1("Invalid service manager handle!\n");
2284 return ERROR_INVALID_HANDLE
;
2287 /* Check access rights */
2288 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
2289 SC_MANAGER_CREATE_SERVICE
))
2291 DPRINT("Insufficient access rights! 0x%lx\n",
2292 hManager
->Handle
.DesiredAccess
);
2293 return ERROR_ACCESS_DENIED
;
2296 if (*lpServiceName
== 0)
2297 return ERROR_INVALID_NAME
;
2299 if (*lpBinaryPathName
== 0)
2300 return ERROR_INVALID_PARAMETER
;
2302 /* Check for invalid service type value */
2303 if ((dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
2304 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
) &&
2305 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
2306 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
))
2308 return ERROR_INVALID_PARAMETER
;
2311 /* Check for invalid start type value */
2312 if ((dwStartType
!= SERVICE_BOOT_START
) &&
2313 (dwStartType
!= SERVICE_SYSTEM_START
) &&
2314 (dwStartType
!= SERVICE_AUTO_START
) &&
2315 (dwStartType
!= SERVICE_DEMAND_START
) &&
2316 (dwStartType
!= SERVICE_DISABLED
))
2318 return ERROR_INVALID_PARAMETER
;
2321 /* Only drivers can be boot start or system start services */
2322 if ((dwStartType
== SERVICE_BOOT_START
) ||
2323 (dwStartType
== SERVICE_SYSTEM_START
))
2325 if ((dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
2326 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
2328 return ERROR_INVALID_PARAMETER
;
2332 /* Check for invalid error control value */
2333 if ((dwErrorControl
!= SERVICE_ERROR_IGNORE
) &&
2334 (dwErrorControl
!= SERVICE_ERROR_NORMAL
) &&
2335 (dwErrorControl
!= SERVICE_ERROR_SEVERE
) &&
2336 (dwErrorControl
!= SERVICE_ERROR_CRITICAL
))
2338 return ERROR_INVALID_PARAMETER
;
2341 if ((dwServiceType
== (SERVICE_WIN32_OWN_PROCESS
| SERVICE_INTERACTIVE_PROCESS
)) &&
2342 (lpServiceStartName
))
2344 /* We allow LocalSystem to run interactive. */
2345 if (wcsicmp(lpServiceStartName
, L
"LocalSystem"))
2347 return ERROR_INVALID_PARAMETER
;
2351 if (lpdwTagId
&& (!lpLoadOrderGroup
|| !*lpLoadOrderGroup
))
2353 return ERROR_INVALID_PARAMETER
;
2356 /* Lock the service database exclusively */
2357 ScmLockDatabaseExclusive();
2359 lpService
= ScmGetServiceEntryByName(lpServiceName
);
2362 /* Unlock the service database */
2363 ScmUnlockDatabase();
2365 /* Check if it is marked for deletion */
2366 if (lpService
->bDeleted
)
2367 return ERROR_SERVICE_MARKED_FOR_DELETE
;
2369 /* Return service-exists error */
2370 return ERROR_SERVICE_EXISTS
;
2373 if (lpDisplayName
!= NULL
&&
2374 ScmGetServiceEntryByDisplayName(lpDisplayName
) != NULL
)
2376 /* Unlock the service database */
2377 ScmUnlockDatabase();
2379 return ERROR_DUPLICATE_SERVICE_NAME
;
2382 if (dwServiceType
& SERVICE_DRIVER
)
2384 dwError
= ScmCanonDriverImagePath(dwStartType
,
2387 if (dwError
!= ERROR_SUCCESS
)
2392 if (dwStartType
== SERVICE_BOOT_START
||
2393 dwStartType
== SERVICE_SYSTEM_START
)
2395 /* Unlock the service database */
2396 ScmUnlockDatabase();
2398 return ERROR_INVALID_PARAMETER
;
2402 /* Allocate a new service entry */
2403 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
2407 if (dwError
!= ERROR_SUCCESS
)
2410 /* Fill the new service entry */
2411 lpService
->dwErrorControl
= dwErrorControl
;
2413 /* Fill the display name */
2414 if (lpDisplayName
!= NULL
&&
2415 *lpDisplayName
!= 0 &&
2416 _wcsicmp(lpService
->lpDisplayName
, lpDisplayName
) != 0)
2418 lpService
->lpDisplayName
= HeapAlloc(GetProcessHeap(),
2420 (wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
));
2421 if (lpService
->lpDisplayName
== NULL
)
2423 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
2426 wcscpy(lpService
->lpDisplayName
, lpDisplayName
);
2429 /* Assign the service to a group */
2430 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
2432 dwError
= ScmSetServiceGroup(lpService
,
2434 if (dwError
!= ERROR_SUCCESS
)
2438 /* Assign a new tag */
2439 if (lpdwTagId
!= NULL
)
2441 dwError
= ScmAssignNewTag(lpService
);
2442 if (dwError
!= ERROR_SUCCESS
)
2446 /* Assign the default security descriptor */
2447 if (dwServiceType
& SERVICE_WIN32
)
2449 dwError
= ScmCreateDefaultServiceSD(&lpService
->pSecurityDescriptor
);
2450 if (dwError
!= ERROR_SUCCESS
)
2454 /* Write service data to the registry */
2455 /* Create the service key */
2456 dwError
= ScmCreateServiceKey(lpServiceName
,
2459 if (dwError
!= ERROR_SUCCESS
)
2462 /* Set the display name */
2463 if (lpDisplayName
!= NULL
&& *lpDisplayName
!= 0)
2465 RegSetValueExW(hServiceKey
,
2469 (LPBYTE
)lpDisplayName
,
2470 (DWORD
)((wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
)));
2473 /* Set the service type */
2474 dwError
= RegSetValueExW(hServiceKey
,
2478 (LPBYTE
)&dwServiceType
,
2480 if (dwError
!= ERROR_SUCCESS
)
2483 /* Set the start value */
2484 dwError
= RegSetValueExW(hServiceKey
,
2488 (LPBYTE
)&dwStartType
,
2490 if (dwError
!= ERROR_SUCCESS
)
2493 /* Set the error control value */
2494 dwError
= RegSetValueExW(hServiceKey
,
2498 (LPBYTE
)&dwErrorControl
,
2500 if (dwError
!= ERROR_SUCCESS
)
2503 /* Set the image path */
2504 if (dwServiceType
& SERVICE_WIN32
)
2506 dwError
= RegSetValueExW(hServiceKey
,
2510 (LPBYTE
)lpBinaryPathName
,
2511 (DWORD
)((wcslen(lpBinaryPathName
) + 1) * sizeof(WCHAR
)));
2512 if (dwError
!= ERROR_SUCCESS
)
2515 else if (dwServiceType
& SERVICE_DRIVER
)
2517 dwError
= RegSetValueExW(hServiceKey
,
2521 (LPBYTE
)lpImagePath
,
2522 (DWORD
)((wcslen(lpImagePath
) + 1) * sizeof(WCHAR
)));
2523 if (dwError
!= ERROR_SUCCESS
)
2527 /* Set the group name */
2528 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
2530 dwError
= RegSetValueExW(hServiceKey
,
2534 (LPBYTE
)lpLoadOrderGroup
,
2535 (DWORD
)((wcslen(lpLoadOrderGroup
) + 1) * sizeof(WCHAR
)));
2536 if (dwError
!= ERROR_SUCCESS
)
2540 /* Set the service tag */
2541 if (lpdwTagId
!= NULL
)
2543 dwError
= RegSetValueExW(hServiceKey
,
2547 (LPBYTE
)&lpService
->dwTag
,
2549 if (dwError
!= ERROR_SUCCESS
)
2553 /* Write dependencies */
2554 if (lpDependencies
!= NULL
&& *lpDependencies
!= 0)
2556 dwError
= ScmWriteDependencies(hServiceKey
,
2557 (LPCWSTR
)lpDependencies
,
2559 if (dwError
!= ERROR_SUCCESS
)
2563 /* Start name and password are only used by Win32 services */
2564 if (dwServiceType
& SERVICE_WIN32
)
2566 /* Write service start name */
2567 lpObjectName
= (lpServiceStartName
!= NULL
) ? (LPWSTR
)lpServiceStartName
: L
"LocalSystem";
2568 dwError
= RegSetValueExW(hServiceKey
,
2572 (LPBYTE
)lpObjectName
,
2573 (DWORD
)((wcslen(lpObjectName
) + 1) * sizeof(WCHAR
)));
2574 if (dwError
!= ERROR_SUCCESS
)
2577 if (lpPassword
!= NULL
&& *(LPWSTR
)lpPassword
!= 0)
2579 /* FIXME: Decrypt the password */
2581 /* Write the password */
2582 dwError
= ScmSetServicePassword(lpServiceName
,
2583 (LPCWSTR
)lpPassword
);
2584 if (dwError
!= ERROR_SUCCESS
)
2588 /* Write the security descriptor */
2589 dwError
= ScmWriteSecurityDescriptor(hServiceKey
,
2590 lpService
->pSecurityDescriptor
);
2591 if (dwError
!= ERROR_SUCCESS
)
2595 dwError
= ScmCreateServiceHandle(lpService
,
2597 if (dwError
!= ERROR_SUCCESS
)
2600 dwError
= ScmCheckAccess(hServiceHandle
,
2602 if (dwError
!= ERROR_SUCCESS
)
2605 lpService
->dwRefCount
= 1;
2606 DPRINT("CreateService - lpService->dwRefCount %u\n", lpService
->dwRefCount
);
2609 /* Unlock the service database */
2610 ScmUnlockDatabase();
2612 if (hServiceKey
!= NULL
)
2613 RegCloseKey(hServiceKey
);
2615 if (dwError
== ERROR_SUCCESS
)
2617 DPRINT("hService %p\n", hServiceHandle
);
2618 *lpServiceHandle
= (SC_RPC_HANDLE
)hServiceHandle
;
2620 if (lpdwTagId
!= NULL
)
2621 *lpdwTagId
= lpService
->dwTag
;
2625 if (lpService
!= NULL
&&
2626 lpService
->lpServiceName
!= NULL
)
2628 /* Release the display name buffer */
2629 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
2634 /* Remove the service handle */
2635 HeapFree(GetProcessHeap(), 0, hServiceHandle
);
2638 if (lpService
!= NULL
)
2640 /* FIXME: remove the service entry */
2644 if (lpImagePath
!= NULL
)
2645 HeapFree(GetProcessHeap(), 0, lpImagePath
);
2647 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError
);
2656 REnumDependentServicesW(
2657 SC_RPC_HANDLE hService
,
2658 DWORD dwServiceState
,
2661 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
2662 LPBOUNDED_DWORD_256K lpServicesReturned
)
2664 DWORD dwError
= ERROR_SUCCESS
;
2665 DWORD dwServicesReturned
= 0;
2666 DWORD dwServiceCount
;
2667 HKEY hServicesKey
= NULL
;
2668 PSERVICE_HANDLE hSvc
;
2669 PSERVICE lpService
= NULL
;
2670 PSERVICE
*lpServicesArray
= NULL
;
2671 LPENUM_SERVICE_STATUSW lpServicesPtr
= NULL
;
2674 *pcbBytesNeeded
= 0;
2675 *lpServicesReturned
= 0;
2677 DPRINT("REnumDependentServicesW() called\n");
2679 hSvc
= ScmGetServiceFromHandle(hService
);
2682 DPRINT1("Invalid service handle!\n");
2683 return ERROR_INVALID_HANDLE
;
2686 lpService
= hSvc
->ServiceEntry
;
2688 /* Check access rights */
2689 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
2690 SC_MANAGER_ENUMERATE_SERVICE
))
2692 DPRINT("Insufficient access rights! 0x%lx\n",
2693 hSvc
->Handle
.DesiredAccess
);
2694 return ERROR_ACCESS_DENIED
;
2697 /* Open the Services Reg key */
2698 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2699 L
"System\\CurrentControlSet\\Services",
2703 if (dwError
!= ERROR_SUCCESS
)
2706 /* First determine the bytes needed and get the number of dependent services */
2707 dwError
= Int_EnumDependentServicesW(hServicesKey
,
2712 &dwServicesReturned
);
2713 if (dwError
!= ERROR_SUCCESS
)
2716 /* If buffer size is less than the bytes needed or pointer is null */
2717 if ((!lpServices
) || (cbBufSize
< *pcbBytesNeeded
))
2719 dwError
= ERROR_MORE_DATA
;
2723 /* Allocate memory for array of service pointers */
2724 lpServicesArray
= HeapAlloc(GetProcessHeap(),
2726 (dwServicesReturned
+ 1) * sizeof(PSERVICE
));
2727 if (!lpServicesArray
)
2729 DPRINT1("Could not allocate a buffer!!\n");
2730 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
2734 dwServicesReturned
= 0;
2735 *pcbBytesNeeded
= 0;
2737 dwError
= Int_EnumDependentServicesW(hServicesKey
,
2742 &dwServicesReturned
);
2743 if (dwError
!= ERROR_SUCCESS
)
2748 lpServicesPtr
= (LPENUM_SERVICE_STATUSW
)lpServices
;
2749 lpStr
= (LPWSTR
)(lpServices
+ (dwServicesReturned
* sizeof(ENUM_SERVICE_STATUSW
)));
2751 /* Copy EnumDepenedentService to Buffer */
2752 for (dwServiceCount
= 0; dwServiceCount
< dwServicesReturned
; dwServiceCount
++)
2754 lpService
= lpServicesArray
[dwServiceCount
];
2756 /* Copy status info */
2757 memcpy(&lpServicesPtr
->ServiceStatus
,
2759 sizeof(SERVICE_STATUS
));
2761 /* Copy display name */
2762 wcscpy(lpStr
, lpService
->lpDisplayName
);
2763 lpServicesPtr
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
2764 lpStr
+= (wcslen(lpService
->lpDisplayName
) + 1);
2766 /* Copy service name */
2767 wcscpy(lpStr
, lpService
->lpServiceName
);
2768 lpServicesPtr
->lpServiceName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
2769 lpStr
+= (wcslen(lpService
->lpServiceName
) + 1);
2774 *lpServicesReturned
= dwServicesReturned
;
2777 if (lpServicesArray
!= NULL
)
2778 HeapFree(GetProcessHeap(), 0, lpServicesArray
);
2780 RegCloseKey(hServicesKey
);
2782 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError
);
2791 REnumServicesStatusW(
2792 SC_RPC_HANDLE hSCManager
,
2793 DWORD dwServiceType
,
2794 DWORD dwServiceState
,
2797 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
2798 LPBOUNDED_DWORD_256K lpServicesReturned
,
2799 LPBOUNDED_DWORD_256K lpResumeHandle
)
2801 /* Enumerate all the services, not regarding of their group */
2802 return REnumServiceGroupW(hSCManager
,
2818 LPWSTR lpMachineName
,
2819 LPWSTR lpDatabaseName
,
2820 DWORD dwDesiredAccess
,
2821 LPSC_RPC_HANDLE lpScHandle
)
2826 DPRINT("ROpenSCManagerW() called\n");
2827 DPRINT("lpMachineName = %p\n", lpMachineName
);
2828 DPRINT("lpMachineName: %S\n", lpMachineName
);
2829 DPRINT("lpDataBaseName = %p\n", lpDatabaseName
);
2830 DPRINT("lpDataBaseName: %S\n", lpDatabaseName
);
2831 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess
);
2834 return ERROR_SHUTDOWN_IN_PROGRESS
;
2837 return ERROR_INVALID_PARAMETER
;
2839 dwError
= ScmCreateManagerHandle(lpDatabaseName
,
2841 if (dwError
!= ERROR_SUCCESS
)
2843 DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError
);
2847 /* Check the desired access */
2848 dwError
= ScmCheckAccess(hHandle
,
2849 dwDesiredAccess
| SC_MANAGER_CONNECT
);
2850 if (dwError
!= ERROR_SUCCESS
)
2852 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError
);
2853 HeapFree(GetProcessHeap(), 0, hHandle
);
2857 *lpScHandle
= (SC_RPC_HANDLE
)hHandle
;
2858 DPRINT("*hScm = %p\n", *lpScHandle
);
2860 DPRINT("ROpenSCManagerW() done\n");
2862 return ERROR_SUCCESS
;
2870 SC_RPC_HANDLE hSCManager
,
2871 LPWSTR lpServiceName
,
2872 DWORD dwDesiredAccess
,
2873 LPSC_RPC_HANDLE lpServiceHandle
)
2876 PMANAGER_HANDLE hManager
;
2878 DWORD dwError
= ERROR_SUCCESS
;
2880 DPRINT("ROpenServiceW() called\n");
2881 DPRINT("hSCManager = %p\n", hSCManager
);
2882 DPRINT("lpServiceName = %p\n", lpServiceName
);
2883 DPRINT("lpServiceName: %S\n", lpServiceName
);
2884 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess
);
2887 return ERROR_SHUTDOWN_IN_PROGRESS
;
2889 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
2890 if (hManager
== NULL
)
2892 DPRINT1("Invalid service manager handle!\n");
2893 return ERROR_INVALID_HANDLE
;
2896 if (!lpServiceHandle
)
2897 return ERROR_INVALID_PARAMETER
;
2900 return ERROR_INVALID_ADDRESS
;
2902 /* Lock the service database exclusive */
2903 ScmLockDatabaseExclusive();
2905 /* Get service database entry */
2906 lpService
= ScmGetServiceEntryByName(lpServiceName
);
2907 if (lpService
== NULL
)
2909 DPRINT("Could not find a service!\n");
2910 dwError
= ERROR_SERVICE_DOES_NOT_EXIST
;
2914 /* Create a service handle */
2915 dwError
= ScmCreateServiceHandle(lpService
,
2917 if (dwError
!= ERROR_SUCCESS
)
2919 DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError
);
2923 /* Check the desired access */
2924 dwError
= ScmCheckAccess(hHandle
,
2926 if (dwError
!= ERROR_SUCCESS
)
2928 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError
);
2929 HeapFree(GetProcessHeap(), 0, hHandle
);
2933 lpService
->dwRefCount
++;
2934 DPRINT("OpenService - lpService->dwRefCount %u\n",lpService
->dwRefCount
);
2936 *lpServiceHandle
= (SC_RPC_HANDLE
)hHandle
;
2937 DPRINT("*hService = %p\n", *lpServiceHandle
);
2940 /* Unlock the service database */
2941 ScmUnlockDatabase();
2943 DPRINT("ROpenServiceW() done\n");
2952 RQueryServiceConfigW(
2953 SC_RPC_HANDLE hService
,
2954 LPBYTE lpBuf
, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2956 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
2958 LPQUERY_SERVICE_CONFIGW lpServiceConfig
= (LPQUERY_SERVICE_CONFIGW
)lpBuf
;
2959 DWORD dwError
= ERROR_SUCCESS
;
2960 PSERVICE_HANDLE hSvc
;
2961 PSERVICE lpService
= NULL
;
2962 HKEY hServiceKey
= NULL
;
2963 LPWSTR lpImagePath
= NULL
;
2964 LPWSTR lpServiceStartName
= NULL
;
2965 LPWSTR lpDependencies
= NULL
;
2966 DWORD dwDependenciesLength
= 0;
2967 DWORD dwRequiredSize
;
2970 DPRINT("RQueryServiceConfigW() called\n");
2973 return ERROR_SHUTDOWN_IN_PROGRESS
;
2975 hSvc
= ScmGetServiceFromHandle(hService
);
2978 DPRINT1("Invalid service handle!\n");
2979 return ERROR_INVALID_HANDLE
;
2982 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
2983 SERVICE_QUERY_CONFIG
))
2985 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
2986 return ERROR_ACCESS_DENIED
;
2989 lpService
= hSvc
->ServiceEntry
;
2990 if (lpService
== NULL
)
2992 DPRINT("lpService == NULL!\n");
2993 return ERROR_INVALID_HANDLE
;
2996 /* Lock the service database shared */
2997 ScmLockDatabaseShared();
2999 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
3002 if (dwError
!= ERROR_SUCCESS
)
3005 /* Read the image path */
3006 dwError
= ScmReadString(hServiceKey
,
3009 if (dwError
!= ERROR_SUCCESS
)
3012 /* Read the service start name */
3013 ScmReadString(hServiceKey
,
3015 &lpServiceStartName
);
3017 /* Read the dependencies */
3018 ScmReadDependencies(hServiceKey
,
3020 &dwDependenciesLength
);
3022 dwRequiredSize
= sizeof(QUERY_SERVICE_CONFIGW
);
3024 if (lpImagePath
!= NULL
)
3025 dwRequiredSize
+= (DWORD
)((wcslen(lpImagePath
) + 1) * sizeof(WCHAR
));
3027 dwRequiredSize
+= 2 * sizeof(WCHAR
);
3029 if ((lpService
->lpGroup
!= NULL
) && (lpService
->lpGroup
->lpGroupName
!= NULL
))
3030 dwRequiredSize
+= (DWORD
)((wcslen(lpService
->lpGroup
->lpGroupName
) + 1) * sizeof(WCHAR
));
3032 dwRequiredSize
+= 2 * sizeof(WCHAR
);
3034 if (lpDependencies
!= NULL
)
3035 dwRequiredSize
+= dwDependenciesLength
* sizeof(WCHAR
);
3037 dwRequiredSize
+= 2 * sizeof(WCHAR
);
3039 if (lpServiceStartName
!= NULL
)
3040 dwRequiredSize
+= (DWORD
)((wcslen(lpServiceStartName
) + 1) * sizeof(WCHAR
));
3042 dwRequiredSize
+= 2 * sizeof(WCHAR
);
3044 if (lpService
->lpDisplayName
!= NULL
)
3045 dwRequiredSize
+= (DWORD
)((wcslen(lpService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
3047 dwRequiredSize
+= 2 * sizeof(WCHAR
);
3049 if (lpServiceConfig
== NULL
|| cbBufSize
< dwRequiredSize
)
3051 dwError
= ERROR_INSUFFICIENT_BUFFER
;
3055 lpServiceConfig
->dwServiceType
= lpService
->Status
.dwServiceType
;
3056 lpServiceConfig
->dwStartType
= lpService
->dwStartType
;
3057 lpServiceConfig
->dwErrorControl
= lpService
->dwErrorControl
;
3058 lpServiceConfig
->dwTagId
= lpService
->dwTag
;
3060 lpStr
= (LPWSTR
)(lpServiceConfig
+ 1);
3062 /* Append the image path */
3063 if (lpImagePath
!= NULL
)
3065 wcscpy(lpStr
, lpImagePath
);
3072 lpServiceConfig
->lpBinaryPathName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
3073 lpStr
+= (wcslen(lpStr
) + 1);
3075 /* Append the group name */
3076 if ((lpService
->lpGroup
!= NULL
) && (lpService
->lpGroup
->lpGroupName
!= NULL
))
3078 wcscpy(lpStr
, lpService
->lpGroup
->lpGroupName
);
3085 lpServiceConfig
->lpLoadOrderGroup
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
3086 lpStr
+= (wcslen(lpStr
) + 1);
3088 /* Append Dependencies */
3089 if (lpDependencies
!= NULL
)
3093 dwDependenciesLength
* sizeof(WCHAR
));
3100 lpServiceConfig
->lpDependencies
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
3101 if (lpDependencies
!= NULL
)
3102 lpStr
+= dwDependenciesLength
;
3104 lpStr
+= (wcslen(lpStr
) + 1);
3106 /* Append the service start name */
3107 if (lpServiceStartName
!= NULL
)
3109 wcscpy(lpStr
, lpServiceStartName
);
3116 lpServiceConfig
->lpServiceStartName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
3117 lpStr
+= (wcslen(lpStr
) + 1);
3119 /* Append the display name */
3120 if (lpService
->lpDisplayName
!= NULL
)
3122 wcscpy(lpStr
, lpService
->lpDisplayName
);
3129 lpServiceConfig
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
3132 if (pcbBytesNeeded
!= NULL
)
3133 *pcbBytesNeeded
= dwRequiredSize
;
3136 /* Unlock the service database */
3137 ScmUnlockDatabase();
3139 if (lpImagePath
!= NULL
)
3140 HeapFree(GetProcessHeap(), 0, lpImagePath
);
3142 if (lpServiceStartName
!= NULL
)
3143 HeapFree(GetProcessHeap(), 0, lpServiceStartName
);
3145 if (lpDependencies
!= NULL
)
3146 HeapFree(GetProcessHeap(), 0, lpDependencies
);
3148 if (hServiceKey
!= NULL
)
3149 RegCloseKey(hServiceKey
);
3151 DPRINT("RQueryServiceConfigW() done\n");
3160 RQueryServiceLockStatusW(
3161 SC_RPC_HANDLE hSCManager
,
3162 LPBYTE lpBuf
, // LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
3164 LPBOUNDED_DWORD_4K pcbBytesNeeded
)
3166 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
= (LPQUERY_SERVICE_LOCK_STATUSW
)lpBuf
;
3167 PMANAGER_HANDLE hMgr
;
3168 DWORD dwRequiredSize
;
3170 if (!lpLockStatus
|| !pcbBytesNeeded
)
3171 return ERROR_INVALID_PARAMETER
;
3173 hMgr
= ScmGetServiceManagerFromHandle(hSCManager
);
3176 DPRINT1("Invalid service manager handle!\n");
3177 return ERROR_INVALID_HANDLE
;
3180 if (!RtlAreAllAccessesGranted(hMgr
->Handle
.DesiredAccess
,
3181 SC_MANAGER_QUERY_LOCK_STATUS
))
3183 DPRINT("Insufficient access rights! 0x%lx\n", hMgr
->Handle
.DesiredAccess
);
3184 return ERROR_ACCESS_DENIED
;
3187 /* FIXME: we need to compute instead the real length of the owner name */
3188 dwRequiredSize
= sizeof(QUERY_SERVICE_LOCK_STATUSW
) + sizeof(WCHAR
);
3189 *pcbBytesNeeded
= dwRequiredSize
;
3191 if (cbBufSize
< dwRequiredSize
)
3192 return ERROR_INSUFFICIENT_BUFFER
;
3194 ScmQueryServiceLockStatusW(lpLockStatus
);
3196 return ERROR_SUCCESS
;
3204 SC_RPC_HANDLE hService
,
3206 LPSTRING_PTRSW argv
)
3208 DWORD dwError
= ERROR_SUCCESS
;
3209 PSERVICE_HANDLE hSvc
;
3210 PSERVICE lpService
= NULL
;
3215 DPRINT("RStartServiceW(%p %lu %p) called\n", hService
, argc
, argv
);
3216 DPRINT(" argc: %lu\n", argc
);
3219 for (i
= 0; i
< argc
; i
++)
3221 DPRINT(" argv[%lu]: %S\n", i
, argv
[i
].StringPtr
);
3227 return ERROR_SHUTDOWN_IN_PROGRESS
;
3229 hSvc
= ScmGetServiceFromHandle(hService
);
3232 DPRINT1("Invalid service handle!\n");
3233 return ERROR_INVALID_HANDLE
;
3236 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3239 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
3240 return ERROR_ACCESS_DENIED
;
3243 lpService
= hSvc
->ServiceEntry
;
3244 if (lpService
== NULL
)
3246 DPRINT("lpService == NULL!\n");
3247 return ERROR_INVALID_HANDLE
;
3250 if (lpService
->dwStartType
== SERVICE_DISABLED
)
3251 return ERROR_SERVICE_DISABLED
;
3253 if (lpService
->bDeleted
)
3254 return ERROR_SERVICE_MARKED_FOR_DELETE
;
3256 /* Start the service */
3257 dwError
= ScmStartService(lpService
, argc
, (LPWSTR
*)argv
);
3266 RGetServiceDisplayNameW(
3267 SC_RPC_HANDLE hSCManager
,
3268 LPCWSTR lpServiceName
,
3269 LPWSTR lpDisplayName
,
3272 // PMANAGER_HANDLE hManager;
3277 DPRINT("RGetServiceDisplayNameW() called\n");
3278 DPRINT("hSCManager = %p\n", hSCManager
);
3279 DPRINT("lpServiceName: %S\n", lpServiceName
);
3280 DPRINT("lpDisplayName: %p\n", lpDisplayName
);
3281 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
3283 // hManager = (PMANAGER_HANDLE)hSCManager;
3284 // if (hManager->Handle.Tag != MANAGER_TAG)
3286 // DPRINT("Invalid manager handle!\n");
3287 // return ERROR_INVALID_HANDLE;
3290 /* Get service database entry */
3291 lpService
= ScmGetServiceEntryByName(lpServiceName
);
3292 if (lpService
== NULL
)
3294 DPRINT("Could not find a service!\n");
3296 /* If the service could not be found and lpcchBuffer is less than 2, windows
3297 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3298 if (*lpcchBuffer
< sizeof(WCHAR
))
3300 *lpcchBuffer
= sizeof(WCHAR
);
3301 if (lpDisplayName
!= NULL
)
3307 return ERROR_SERVICE_DOES_NOT_EXIST
;
3310 if (!lpService
->lpDisplayName
)
3312 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
3314 if (lpDisplayName
!= NULL
&&
3315 *lpcchBuffer
> dwLength
)
3317 wcscpy(lpDisplayName
, lpService
->lpServiceName
);
3322 dwLength
= (DWORD
)wcslen(lpService
->lpDisplayName
);
3324 if (lpDisplayName
!= NULL
&&
3325 *lpcchBuffer
> dwLength
)
3327 wcscpy(lpDisplayName
, lpService
->lpDisplayName
);
3331 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
3333 *lpcchBuffer
= dwLength
;
3342 RGetServiceKeyNameW(
3343 SC_RPC_HANDLE hSCManager
,
3344 LPCWSTR lpDisplayName
,
3345 LPWSTR lpServiceName
,
3348 // PMANAGER_HANDLE hManager;
3353 DPRINT("RGetServiceKeyNameW() called\n");
3354 DPRINT("hSCManager = %p\n", hSCManager
);
3355 DPRINT("lpDisplayName: %S\n", lpDisplayName
);
3356 DPRINT("lpServiceName: %p\n", lpServiceName
);
3357 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
3359 // hManager = (PMANAGER_HANDLE)hSCManager;
3360 // if (hManager->Handle.Tag != MANAGER_TAG)
3362 // DPRINT("Invalid manager handle!\n");
3363 // return ERROR_INVALID_HANDLE;
3366 /* Get service database entry */
3367 lpService
= ScmGetServiceEntryByDisplayName(lpDisplayName
);
3368 if (lpService
== NULL
)
3370 DPRINT("Could not find a service!\n");
3372 /* If the service could not be found and lpcchBuffer is less than 2, windows
3373 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3374 if (*lpcchBuffer
< sizeof(WCHAR
))
3376 *lpcchBuffer
= sizeof(WCHAR
);
3377 if (lpServiceName
!= NULL
)
3383 return ERROR_SERVICE_DOES_NOT_EXIST
;
3386 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
3388 if (lpServiceName
!= NULL
&&
3389 *lpcchBuffer
> dwLength
)
3391 wcscpy(lpServiceName
, lpService
->lpServiceName
);
3392 *lpcchBuffer
= dwLength
;
3393 return ERROR_SUCCESS
;
3396 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
3398 *lpcchBuffer
= dwLength
;
3407 RI_ScSetServiceBitsA(
3408 RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
3409 DWORD dwServiceBits
,
3411 int bUpdateImmediately
,
3415 return ERROR_SHUTDOWN_IN_PROGRESS
;
3417 if (lpString
!= NULL
)
3418 return ERROR_INVALID_PARAMETER
;
3420 return RI_ScSetServiceBitsW(hServiceStatus
,
3431 RChangeServiceConfigA(
3432 SC_RPC_HANDLE hService
,
3433 DWORD dwServiceType
,
3435 DWORD dwErrorControl
,
3436 LPSTR lpBinaryPathName
,
3437 LPSTR lpLoadOrderGroup
,
3439 LPBYTE lpDependencies
,
3441 LPSTR lpServiceStartName
,
3444 LPSTR lpDisplayName
)
3446 DWORD dwError
= ERROR_SUCCESS
;
3447 LPWSTR lpBinaryPathNameW
= NULL
;
3448 LPWSTR lpLoadOrderGroupW
= NULL
;
3449 LPWSTR lpDependenciesW
= NULL
;
3450 LPWSTR lpServiceStartNameW
= NULL
;
3451 LPWSTR lpDisplayNameW
= NULL
;
3452 DWORD dwDependenciesLength
= 0;
3457 if (lpBinaryPathName
)
3459 len
= MultiByteToWideChar(CP_ACP
, 0, lpBinaryPathName
, -1, NULL
, 0);
3460 lpBinaryPathNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3461 if (!lpBinaryPathNameW
)
3463 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3466 MultiByteToWideChar(CP_ACP
, 0, lpBinaryPathName
, -1, lpBinaryPathNameW
, len
);
3469 if (lpLoadOrderGroup
)
3471 len
= MultiByteToWideChar(CP_ACP
, 0, lpLoadOrderGroup
, -1, NULL
, 0);
3472 lpLoadOrderGroupW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3473 if (!lpLoadOrderGroupW
)
3475 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3478 MultiByteToWideChar(CP_ACP
, 0, lpLoadOrderGroup
, -1, lpLoadOrderGroupW
, len
);
3483 lpStr
= (LPCSTR
)lpDependencies
;
3486 cchLength
= strlen(lpStr
) + 1;
3487 dwDependenciesLength
+= (DWORD
)cchLength
;
3488 lpStr
= lpStr
+ cchLength
;
3490 dwDependenciesLength
++;
3492 lpDependenciesW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwDependenciesLength
* sizeof(WCHAR
));
3493 if (!lpDependenciesW
)
3495 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3498 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)lpDependencies
, dwDependenciesLength
, lpDependenciesW
, dwDependenciesLength
);
3501 if (lpServiceStartName
)
3503 len
= MultiByteToWideChar(CP_ACP
, 0, lpServiceStartName
, -1, NULL
, 0);
3504 lpServiceStartNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3505 if (!lpServiceStartNameW
)
3507 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3510 MultiByteToWideChar(CP_ACP
, 0, lpServiceStartName
, -1, lpServiceStartNameW
, len
);
3515 len
= MultiByteToWideChar(CP_ACP
, 0, lpDisplayName
, -1, NULL
, 0);
3516 lpDisplayNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3517 if (!lpDisplayNameW
)
3519 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3522 MultiByteToWideChar(CP_ACP
, 0, lpDisplayName
, -1, lpDisplayNameW
, len
);
3525 dwError
= RChangeServiceConfigW(hService
,
3532 (LPBYTE
)lpDependenciesW
,
3533 dwDependenciesLength
,
3534 lpServiceStartNameW
,
3540 if (lpBinaryPathNameW
!= NULL
)
3541 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW
);
3543 if (lpLoadOrderGroupW
!= NULL
)
3544 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3546 if (lpDependenciesW
!= NULL
)
3547 HeapFree(GetProcessHeap(), 0, lpDependenciesW
);
3549 if (lpServiceStartNameW
!= NULL
)
3550 HeapFree(GetProcessHeap(), 0, lpServiceStartNameW
);
3552 if (lpDisplayNameW
!= NULL
)
3553 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
3563 SC_RPC_HANDLE hSCManager
,
3564 LPSTR lpServiceName
,
3565 LPSTR lpDisplayName
,
3566 DWORD dwDesiredAccess
,
3567 DWORD dwServiceType
,
3569 DWORD dwErrorControl
,
3570 LPSTR lpBinaryPathName
,
3571 LPSTR lpLoadOrderGroup
,
3573 LPBYTE lpDependencies
,
3575 LPSTR lpServiceStartName
,
3578 LPSC_RPC_HANDLE lpServiceHandle
)
3580 DWORD dwError
= ERROR_SUCCESS
;
3581 LPWSTR lpServiceNameW
= NULL
;
3582 LPWSTR lpDisplayNameW
= NULL
;
3583 LPWSTR lpBinaryPathNameW
= NULL
;
3584 LPWSTR lpLoadOrderGroupW
= NULL
;
3585 LPWSTR lpDependenciesW
= NULL
;
3586 LPWSTR lpServiceStartNameW
= NULL
;
3587 DWORD dwDependenciesLength
= 0;
3594 len
= MultiByteToWideChar(CP_ACP
, 0, lpServiceName
, -1, NULL
, 0);
3595 lpServiceNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3596 if (!lpServiceNameW
)
3598 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3601 MultiByteToWideChar(CP_ACP
, 0, lpServiceName
, -1, lpServiceNameW
, len
);
3606 len
= MultiByteToWideChar(CP_ACP
, 0, lpDisplayName
, -1, NULL
, 0);
3607 lpDisplayNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3608 if (!lpDisplayNameW
)
3610 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3613 MultiByteToWideChar(CP_ACP
, 0, lpDisplayName
, -1, lpDisplayNameW
, len
);
3616 if (lpBinaryPathName
)
3618 len
= MultiByteToWideChar(CP_ACP
, 0, lpBinaryPathName
, -1, NULL
, 0);
3619 lpBinaryPathNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3620 if (!lpBinaryPathNameW
)
3622 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3625 MultiByteToWideChar(CP_ACP
, 0, lpBinaryPathName
, -1, lpBinaryPathNameW
, len
);
3628 if (lpLoadOrderGroup
)
3630 len
= MultiByteToWideChar(CP_ACP
, 0, lpLoadOrderGroup
, -1, NULL
, 0);
3631 lpLoadOrderGroupW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3632 if (!lpLoadOrderGroupW
)
3634 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3637 MultiByteToWideChar(CP_ACP
, 0, lpLoadOrderGroup
, -1, lpLoadOrderGroupW
, len
);
3642 lpStr
= (LPCSTR
)lpDependencies
;
3645 cchLength
= strlen(lpStr
) + 1;
3646 dwDependenciesLength
+= (DWORD
)cchLength
;
3647 lpStr
= lpStr
+ cchLength
;
3649 dwDependenciesLength
++;
3651 lpDependenciesW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwDependenciesLength
* sizeof(WCHAR
));
3652 if (!lpDependenciesW
)
3654 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3657 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)lpDependencies
, dwDependenciesLength
, lpDependenciesW
, dwDependenciesLength
);
3660 if (lpServiceStartName
)
3662 len
= MultiByteToWideChar(CP_ACP
, 0, lpServiceStartName
, -1, NULL
, 0);
3663 lpServiceStartNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3664 if (!lpServiceStartNameW
)
3666 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3669 MultiByteToWideChar(CP_ACP
, 0, lpServiceStartName
, -1, lpServiceStartNameW
, len
);
3672 dwError
= RCreateServiceW(hSCManager
,
3682 (LPBYTE
)lpDependenciesW
,
3683 dwDependenciesLength
,
3684 lpServiceStartNameW
,
3690 if (lpServiceNameW
!=NULL
)
3691 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
3693 if (lpDisplayNameW
!= NULL
)
3694 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
3696 if (lpBinaryPathNameW
!= NULL
)
3697 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW
);
3699 if (lpLoadOrderGroupW
!= NULL
)
3700 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3702 if (lpDependenciesW
!= NULL
)
3703 HeapFree(GetProcessHeap(), 0, lpDependenciesW
);
3705 if (lpServiceStartNameW
!= NULL
)
3706 HeapFree(GetProcessHeap(), 0, lpServiceStartNameW
);
3715 REnumDependentServicesA(
3716 SC_RPC_HANDLE hService
,
3717 DWORD dwServiceState
,
3720 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
3721 LPBOUNDED_DWORD_256K lpServicesReturned
)
3723 DWORD dwError
= ERROR_SUCCESS
;
3724 DWORD dwServicesReturned
= 0;
3725 DWORD dwServiceCount
;
3726 HKEY hServicesKey
= NULL
;
3727 PSERVICE_HANDLE hSvc
;
3728 PSERVICE lpService
= NULL
;
3729 PSERVICE
*lpServicesArray
= NULL
;
3730 LPENUM_SERVICE_STATUSA lpServicesPtr
= NULL
;
3733 *pcbBytesNeeded
= 0;
3734 *lpServicesReturned
= 0;
3736 DPRINT("REnumDependentServicesA() called\n");
3738 hSvc
= ScmGetServiceFromHandle(hService
);
3741 DPRINT1("Invalid service handle!\n");
3742 return ERROR_INVALID_HANDLE
;
3745 lpService
= hSvc
->ServiceEntry
;
3747 /* Check access rights */
3748 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3749 SC_MANAGER_ENUMERATE_SERVICE
))
3751 DPRINT("Insufficient access rights! 0x%lx\n",
3752 hSvc
->Handle
.DesiredAccess
);
3753 return ERROR_ACCESS_DENIED
;
3756 /* Open the Services Reg key */
3757 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
3758 L
"System\\CurrentControlSet\\Services",
3763 if (dwError
!= ERROR_SUCCESS
)
3766 /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3767 both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3768 are the same for both. Verified in WINXP. */
3770 /* First determine the bytes needed and get the number of dependent services*/
3771 dwError
= Int_EnumDependentServicesW(hServicesKey
,
3776 &dwServicesReturned
);
3777 if (dwError
!= ERROR_SUCCESS
)
3780 /* If buffer size is less than the bytes needed or pointer is null*/
3781 if ((!lpServices
) || (cbBufSize
< *pcbBytesNeeded
))
3783 dwError
= ERROR_MORE_DATA
;
3787 /* Allocate memory for array of service pointers */
3788 lpServicesArray
= HeapAlloc(GetProcessHeap(),
3790 (dwServicesReturned
+ 1) * sizeof(PSERVICE
));
3791 if (!lpServicesArray
)
3793 DPRINT("Could not allocate a buffer!!\n");
3794 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3798 dwServicesReturned
= 0;
3799 *pcbBytesNeeded
= 0;
3801 dwError
= Int_EnumDependentServicesW(hServicesKey
,
3806 &dwServicesReturned
);
3807 if (dwError
!= ERROR_SUCCESS
)
3812 lpServicesPtr
= (LPENUM_SERVICE_STATUSA
)lpServices
;
3813 lpStr
= (LPSTR
)(lpServices
+ (dwServicesReturned
* sizeof(ENUM_SERVICE_STATUSA
)));
3815 /* Copy EnumDepenedentService to Buffer */
3816 for (dwServiceCount
= 0; dwServiceCount
< dwServicesReturned
; dwServiceCount
++)
3818 lpService
= lpServicesArray
[dwServiceCount
];
3820 /* Copy the status info */
3821 memcpy(&lpServicesPtr
->ServiceStatus
,
3823 sizeof(SERVICE_STATUS
));
3825 /* Copy display name */
3826 WideCharToMultiByte(CP_ACP
,
3828 lpService
->lpDisplayName
,
3831 (int)wcslen(lpService
->lpDisplayName
),
3834 lpServicesPtr
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
3835 lpStr
+= strlen(lpStr
) + 1;
3837 /* Copy service name */
3838 WideCharToMultiByte(CP_ACP
,
3840 lpService
->lpServiceName
,
3843 (int)wcslen(lpService
->lpServiceName
),
3846 lpServicesPtr
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
3847 lpStr
+= strlen(lpStr
) + 1;
3852 *lpServicesReturned
= dwServicesReturned
;
3855 if (lpServicesArray
)
3856 HeapFree(GetProcessHeap(), 0, lpServicesArray
);
3858 RegCloseKey(hServicesKey
);
3860 DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError
);
3869 REnumServicesStatusA(
3870 SC_RPC_HANDLE hSCManager
,
3871 DWORD dwServiceType
,
3872 DWORD dwServiceState
,
3875 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
3876 LPBOUNDED_DWORD_256K lpServicesReturned
,
3877 LPBOUNDED_DWORD_256K lpResumeHandle
)
3879 LPENUM_SERVICE_STATUSW lpStatusPtrW
= NULL
;
3880 LPENUM_SERVICE_STATUSW lpStatusPtrIncrW
;
3881 LPENUM_SERVICE_STATUSA lpStatusPtrA
= NULL
;
3882 LPWSTR lpStringPtrW
;
3885 DWORD dwServiceCount
;
3887 DPRINT("REnumServicesStatusA() called\n");
3889 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
3891 return ERROR_INVALID_ADDRESS
;
3894 if ((dwBufSize
> 0) && (lpBuffer
))
3896 lpStatusPtrW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwBufSize
);
3899 DPRINT("Failed to allocate buffer!\n");
3900 return ERROR_NOT_ENOUGH_MEMORY
;
3904 dwError
= REnumServicesStatusW(hSCManager
,
3907 (LPBYTE
)lpStatusPtrW
,
3913 /* if no services were returned then we are Done */
3914 if (*lpServicesReturned
== 0)
3917 lpStatusPtrIncrW
= lpStatusPtrW
;
3918 lpStatusPtrA
= (LPENUM_SERVICE_STATUSA
)lpBuffer
;
3919 lpStringPtrA
= (LPSTR
)((ULONG_PTR
)lpBuffer
+
3920 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUSA
));
3921 lpStringPtrW
= (LPWSTR
)((ULONG_PTR
)lpStatusPtrW
+
3922 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUSW
));
3924 for (dwServiceCount
= 0; dwServiceCount
< *lpServicesReturned
; dwServiceCount
++)
3926 /* Copy the service name */
3927 WideCharToMultiByte(CP_ACP
,
3932 (int)wcslen(lpStringPtrW
),
3936 lpStatusPtrA
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
3937 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
3938 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
3940 /* Copy the display name */
3941 WideCharToMultiByte(CP_ACP
,
3946 (int)wcslen(lpStringPtrW
),
3950 lpStatusPtrA
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
3951 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
3952 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
3954 /* Copy the status information */
3955 memcpy(&lpStatusPtrA
->ServiceStatus
,
3956 &lpStatusPtrIncrW
->ServiceStatus
,
3957 sizeof(SERVICE_STATUS
));
3965 HeapFree(GetProcessHeap(), 0, lpStatusPtrW
);
3967 DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError
);
3977 LPSTR lpMachineName
,
3978 LPSTR lpDatabaseName
,
3979 DWORD dwDesiredAccess
,
3980 LPSC_RPC_HANDLE lpScHandle
)
3982 UNICODE_STRING MachineName
;
3983 UNICODE_STRING DatabaseName
;
3986 DPRINT("ROpenSCManagerA() called\n");
3989 RtlCreateUnicodeStringFromAsciiz(&MachineName
,
3993 RtlCreateUnicodeStringFromAsciiz(&DatabaseName
,
3996 dwError
= ROpenSCManagerW(lpMachineName
? MachineName
.Buffer
: NULL
,
3997 lpDatabaseName
? DatabaseName
.Buffer
: NULL
,
4002 RtlFreeUnicodeString(&MachineName
);
4005 RtlFreeUnicodeString(&DatabaseName
);
4015 SC_RPC_HANDLE hSCManager
,
4016 LPSTR lpServiceName
,
4017 DWORD dwDesiredAccess
,
4018 LPSC_RPC_HANDLE lpServiceHandle
)
4020 UNICODE_STRING ServiceName
;
4023 DPRINT("ROpenServiceA() called\n");
4026 RtlCreateUnicodeStringFromAsciiz(&ServiceName
,
4029 dwError
= ROpenServiceW(hSCManager
,
4030 lpServiceName
? ServiceName
.Buffer
: NULL
,
4035 RtlFreeUnicodeString(&ServiceName
);
4044 RQueryServiceConfigA(
4045 SC_RPC_HANDLE hService
,
4046 LPBYTE lpBuf
, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
4048 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
4050 LPQUERY_SERVICE_CONFIGA lpServiceConfig
= (LPQUERY_SERVICE_CONFIGA
)lpBuf
;
4051 DWORD dwError
= ERROR_SUCCESS
;
4052 PSERVICE_HANDLE hSvc
;
4053 PSERVICE lpService
= NULL
;
4054 HKEY hServiceKey
= NULL
;
4055 LPWSTR lpImagePath
= NULL
;
4056 LPWSTR lpServiceStartName
= NULL
;
4057 LPWSTR lpDependencies
= NULL
;
4058 DWORD dwDependenciesLength
= 0;
4059 DWORD dwRequiredSize
;
4062 DPRINT("RQueryServiceConfigA() called\n");
4065 return ERROR_SHUTDOWN_IN_PROGRESS
;
4067 hSvc
= ScmGetServiceFromHandle(hService
);
4070 DPRINT1("Invalid service handle!\n");
4071 return ERROR_INVALID_HANDLE
;
4074 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
4075 SERVICE_QUERY_CONFIG
))
4077 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
4078 return ERROR_ACCESS_DENIED
;
4081 lpService
= hSvc
->ServiceEntry
;
4082 if (lpService
== NULL
)
4084 DPRINT("lpService == NULL!\n");
4085 return ERROR_INVALID_HANDLE
;
4088 /* Lock the service database shared */
4089 ScmLockDatabaseShared();
4091 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
4094 if (dwError
!= ERROR_SUCCESS
)
4097 /* Read the image path */
4098 dwError
= ScmReadString(hServiceKey
,
4101 if (dwError
!= ERROR_SUCCESS
)
4104 /* Read the service start name */
4105 ScmReadString(hServiceKey
,
4107 &lpServiceStartName
);
4109 /* Read the dependencies */
4110 ScmReadDependencies(hServiceKey
,
4112 &dwDependenciesLength
);
4114 dwRequiredSize
= sizeof(QUERY_SERVICE_CONFIGA
);
4116 if (lpImagePath
!= NULL
)
4117 dwRequiredSize
+= (DWORD
)(wcslen(lpImagePath
) + 1);
4119 dwRequiredSize
+= 2 * sizeof(CHAR
);
4121 if ((lpService
->lpGroup
!= NULL
) && (lpService
->lpGroup
->lpGroupName
!= NULL
))
4122 dwRequiredSize
+= (DWORD
)(wcslen(lpService
->lpGroup
->lpGroupName
) + 1);
4124 dwRequiredSize
+= 2 * sizeof(CHAR
);
4126 /* Add Dependencies length */
4127 if (lpDependencies
!= NULL
)
4128 dwRequiredSize
+= dwDependenciesLength
;
4130 dwRequiredSize
+= 2 * sizeof(CHAR
);
4132 if (lpServiceStartName
!= NULL
)
4133 dwRequiredSize
+= (DWORD
)(wcslen(lpServiceStartName
) + 1);
4135 dwRequiredSize
+= 2 * sizeof(CHAR
);
4137 if (lpService
->lpDisplayName
!= NULL
)
4138 dwRequiredSize
+= (DWORD
)(wcslen(lpService
->lpDisplayName
) + 1);
4140 dwRequiredSize
+= 2 * sizeof(CHAR
);
4142 if (lpServiceConfig
== NULL
|| cbBufSize
< dwRequiredSize
)
4144 dwError
= ERROR_INSUFFICIENT_BUFFER
;
4148 lpServiceConfig
->dwServiceType
= lpService
->Status
.dwServiceType
;
4149 lpServiceConfig
->dwStartType
= lpService
->dwStartType
;
4150 lpServiceConfig
->dwErrorControl
= lpService
->dwErrorControl
;
4151 lpServiceConfig
->dwTagId
= lpService
->dwTag
;
4153 lpStr
= (LPSTR
)(lpServiceConfig
+ 1);
4155 /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
4156 Verified in WINXP */
4160 WideCharToMultiByte(CP_ACP
,
4165 (int)(wcslen(lpImagePath
) + 1),
4174 lpServiceConfig
->lpBinaryPathName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4175 lpStr
+= (strlen((LPSTR
)lpStr
) + 1);
4177 if (lpService
->lpGroup
&& lpService
->lpGroup
->lpGroupName
)
4179 WideCharToMultiByte(CP_ACP
,
4181 lpService
->lpGroup
->lpGroupName
,
4184 (int)(wcslen(lpService
->lpGroup
->lpGroupName
) + 1),
4193 lpServiceConfig
->lpLoadOrderGroup
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4194 lpStr
+= (strlen(lpStr
) + 1);
4196 /* Append Dependencies */
4199 WideCharToMultiByte(CP_ACP
,
4202 dwDependenciesLength
,
4204 dwDependenciesLength
,
4213 lpServiceConfig
->lpDependencies
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4215 lpStr
+= dwDependenciesLength
;
4217 lpStr
+= (strlen(lpStr
) + 1);
4219 if (lpServiceStartName
)
4221 WideCharToMultiByte(CP_ACP
,
4226 (int)(wcslen(lpServiceStartName
) + 1),
4235 lpServiceConfig
->lpServiceStartName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4236 lpStr
+= (strlen(lpStr
) + 1);
4238 if (lpService
->lpDisplayName
)
4240 WideCharToMultiByte(CP_ACP
,
4242 lpService
->lpDisplayName
,
4245 (int)(wcslen(lpService
->lpDisplayName
) + 1),
4254 lpServiceConfig
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4257 if (pcbBytesNeeded
!= NULL
)
4258 *pcbBytesNeeded
= dwRequiredSize
;
4261 /* Unlock the service database */
4262 ScmUnlockDatabase();
4264 if (lpImagePath
!= NULL
)
4265 HeapFree(GetProcessHeap(), 0, lpImagePath
);
4267 if (lpServiceStartName
!= NULL
)
4268 HeapFree(GetProcessHeap(), 0, lpServiceStartName
);
4270 if (lpDependencies
!= NULL
)
4271 HeapFree(GetProcessHeap(), 0, lpDependencies
);
4273 if (hServiceKey
!= NULL
)
4274 RegCloseKey(hServiceKey
);
4276 DPRINT("RQueryServiceConfigA() done\n");
4285 RQueryServiceLockStatusA(
4286 SC_RPC_HANDLE hSCManager
,
4287 LPBYTE lpBuf
, // LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
4289 LPBOUNDED_DWORD_4K pcbBytesNeeded
)
4291 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
= (LPQUERY_SERVICE_LOCK_STATUSA
)lpBuf
;
4292 PMANAGER_HANDLE hMgr
;
4293 DWORD dwRequiredSize
;
4295 if (!lpLockStatus
|| !pcbBytesNeeded
)
4296 return ERROR_INVALID_PARAMETER
;
4298 hMgr
= ScmGetServiceManagerFromHandle(hSCManager
);
4301 DPRINT1("Invalid service manager handle!\n");
4302 return ERROR_INVALID_HANDLE
;
4305 if (!RtlAreAllAccessesGranted(hMgr
->Handle
.DesiredAccess
,
4306 SC_MANAGER_QUERY_LOCK_STATUS
))
4308 DPRINT("Insufficient access rights! 0x%lx\n", hMgr
->Handle
.DesiredAccess
);
4309 return ERROR_ACCESS_DENIED
;
4312 /* FIXME: we need to compute instead the real length of the owner name */
4313 dwRequiredSize
= sizeof(QUERY_SERVICE_LOCK_STATUSA
) + sizeof(CHAR
);
4314 *pcbBytesNeeded
= dwRequiredSize
;
4316 if (cbBufSize
< dwRequiredSize
)
4317 return ERROR_INSUFFICIENT_BUFFER
;
4319 ScmQueryServiceLockStatusA(lpLockStatus
);
4321 return ERROR_SUCCESS
;
4329 SC_RPC_HANDLE hService
,
4331 LPSTRING_PTRSA argv
)
4333 DWORD dwError
= ERROR_SUCCESS
;
4334 PSERVICE_HANDLE hSvc
;
4335 PSERVICE lpService
= NULL
;
4336 LPWSTR
*lpVector
= NULL
;
4340 DPRINT("RStartServiceA() called\n");
4343 return ERROR_SHUTDOWN_IN_PROGRESS
;
4345 hSvc
= ScmGetServiceFromHandle(hService
);
4348 DPRINT1("Invalid service handle!\n");
4349 return ERROR_INVALID_HANDLE
;
4352 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
4355 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
4356 return ERROR_ACCESS_DENIED
;
4359 lpService
= hSvc
->ServiceEntry
;
4360 if (lpService
== NULL
)
4362 DPRINT("lpService == NULL!\n");
4363 return ERROR_INVALID_HANDLE
;
4366 if (lpService
->dwStartType
== SERVICE_DISABLED
)
4367 return ERROR_SERVICE_DISABLED
;
4369 if (lpService
->bDeleted
)
4370 return ERROR_SERVICE_MARKED_FOR_DELETE
;
4372 /* Build a Unicode argument vector */
4375 lpVector
= HeapAlloc(GetProcessHeap(),
4377 argc
* sizeof(LPWSTR
));
4378 if (lpVector
== NULL
)
4379 return ERROR_NOT_ENOUGH_MEMORY
;
4381 for (i
= 0; i
< argc
; i
++)
4383 dwLength
= MultiByteToWideChar(CP_ACP
,
4390 lpVector
[i
] = HeapAlloc(GetProcessHeap(),
4392 dwLength
* sizeof(WCHAR
));
4393 if (lpVector
[i
] == NULL
)
4395 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
4399 MultiByteToWideChar(CP_ACP
,
4408 /* Start the service */
4409 dwError
= ScmStartService(lpService
, argc
, lpVector
);
4412 /* Free the Unicode argument vector */
4413 if (lpVector
!= NULL
)
4415 for (i
= 0; i
< argc
; i
++)
4417 if (lpVector
[i
] != NULL
)
4418 HeapFree(GetProcessHeap(), 0, lpVector
[i
]);
4420 HeapFree(GetProcessHeap(), 0, lpVector
);
4430 RGetServiceDisplayNameA(
4431 SC_RPC_HANDLE hSCManager
,
4432 LPCSTR lpServiceName
,
4433 LPSTR lpDisplayName
,
4434 LPBOUNDED_DWORD_4K lpcchBuffer
)
4436 // PMANAGER_HANDLE hManager;
4437 PSERVICE lpService
= NULL
;
4440 LPWSTR lpServiceNameW
;
4442 DPRINT("RGetServiceDisplayNameA() called\n");
4443 DPRINT("hSCManager = %p\n", hSCManager
);
4444 DPRINT("lpServiceName: %s\n", lpServiceName
);
4445 DPRINT("lpDisplayName: %p\n", lpDisplayName
);
4446 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
4448 // hManager = (PMANAGER_HANDLE)hSCManager;
4449 // if (hManager->Handle.Tag != MANAGER_TAG)
4451 // DPRINT("Invalid manager handle!\n");
4452 // return ERROR_INVALID_HANDLE;
4455 if (lpServiceName
!= NULL
)
4457 dwLength
= (DWORD
)(strlen(lpServiceName
) + 1);
4458 lpServiceNameW
= HeapAlloc(GetProcessHeap(),
4460 dwLength
* sizeof(WCHAR
));
4461 if (!lpServiceNameW
)
4462 return ERROR_NOT_ENOUGH_MEMORY
;
4464 MultiByteToWideChar(CP_ACP
,
4471 lpService
= ScmGetServiceEntryByName(lpServiceNameW
);
4473 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
4476 if (lpService
== NULL
)
4478 DPRINT("Could not find a service!\n");
4480 /* If the service could not be found and lpcchBuffer is 0, windows
4481 puts null in lpDisplayName and puts 1 in lpcchBuffer */
4482 if (*lpcchBuffer
== 0)
4484 *lpcchBuffer
= sizeof(CHAR
);
4485 if (lpDisplayName
!= NULL
)
4490 return ERROR_SERVICE_DOES_NOT_EXIST
;
4493 if (!lpService
->lpDisplayName
)
4495 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
4496 if (lpDisplayName
!= NULL
&&
4497 *lpcchBuffer
> dwLength
)
4499 WideCharToMultiByte(CP_ACP
,
4501 lpService
->lpServiceName
,
4502 (int)wcslen(lpService
->lpServiceName
),
4507 return ERROR_SUCCESS
;
4512 dwLength
= (DWORD
)wcslen(lpService
->lpDisplayName
);
4513 if (lpDisplayName
!= NULL
&&
4514 *lpcchBuffer
> dwLength
)
4516 WideCharToMultiByte(CP_ACP
,
4518 lpService
->lpDisplayName
,
4519 (int)wcslen(lpService
->lpDisplayName
),
4524 return ERROR_SUCCESS
;
4528 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
4530 *lpcchBuffer
= dwLength
* 2;
4539 RGetServiceKeyNameA(
4540 SC_RPC_HANDLE hSCManager
,
4541 LPCSTR lpDisplayName
,
4542 LPSTR lpServiceName
,
4543 LPBOUNDED_DWORD_4K lpcchBuffer
)
4548 LPWSTR lpDisplayNameW
;
4550 DPRINT("RGetServiceKeyNameA() called\n");
4551 DPRINT("hSCManager = %p\n", hSCManager
);
4552 DPRINT("lpDisplayName: %s\n", lpDisplayName
);
4553 DPRINT("lpServiceName: %p\n", lpServiceName
);
4554 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
4556 dwLength
= (DWORD
)(strlen(lpDisplayName
) + 1);
4557 lpDisplayNameW
= HeapAlloc(GetProcessHeap(),
4559 dwLength
* sizeof(WCHAR
));
4560 if (!lpDisplayNameW
)
4561 return ERROR_NOT_ENOUGH_MEMORY
;
4563 MultiByteToWideChar(CP_ACP
,
4570 lpService
= ScmGetServiceEntryByDisplayName(lpDisplayNameW
);
4572 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
4574 if (lpService
== NULL
)
4576 DPRINT("Could not find the service!\n");
4578 /* If the service could not be found and lpcchBuffer is 0,
4579 put null in lpDisplayName and puts 1 in lpcchBuffer, verified WINXP. */
4580 if (*lpcchBuffer
== 0)
4582 *lpcchBuffer
= sizeof(CHAR
);
4583 if (lpServiceName
!= NULL
)
4589 return ERROR_SERVICE_DOES_NOT_EXIST
;
4592 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
4593 if (lpServiceName
!= NULL
&&
4594 *lpcchBuffer
> dwLength
)
4596 WideCharToMultiByte(CP_ACP
,
4598 lpService
->lpServiceName
,
4599 (int)wcslen(lpService
->lpServiceName
),
4604 return ERROR_SUCCESS
;
4607 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
4609 *lpcchBuffer
= dwLength
* 2;
4618 RI_ScGetCurrentGroupStateW(
4619 SC_RPC_HANDLE hSCManager
,
4620 LPWSTR lpLoadOrderGroup
,
4623 PMANAGER_HANDLE hManager
;
4624 PSERVICE_GROUP pServiceGroup
;
4625 DWORD dwError
= ERROR_SUCCESS
;
4627 DPRINT("RI_ScGetCurrentGroupStateW() called\n");
4630 return ERROR_SHUTDOWN_IN_PROGRESS
;
4632 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
4633 if (hManager
== NULL
)
4635 DPRINT1("Invalid service manager handle!\n");
4636 return ERROR_INVALID_HANDLE
;
4639 /* Check for SC_MANAGER_ENUMERATE_SERVICE access right */
4640 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
4641 SC_MANAGER_ENUMERATE_SERVICE
))
4643 DPRINT("Insufficient access rights! 0x%lx\n",
4644 hManager
->Handle
.DesiredAccess
);
4645 return ERROR_ACCESS_DENIED
;
4648 /* Lock the service database shared */
4649 ScmLockDatabaseShared();
4651 /* Get the group list entry */
4652 pServiceGroup
= ScmGetServiceGroupByName(lpLoadOrderGroup
);
4653 if (pServiceGroup
== NULL
)
4655 dwError
= ERROR_SERVICE_DOES_NOT_EXIST
;
4659 /* FIXME: Return the group state */
4663 /* Unlock the service database */
4664 ScmUnlockDatabase();
4666 DPRINT("RI_ScGetCurrentGroupStateW() done (Error %lu)\n", dwError
);
4676 SC_RPC_HANDLE hSCManager
,
4677 DWORD dwServiceType
,
4678 DWORD dwServiceState
,
4681 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
4682 LPBOUNDED_DWORD_256K lpServicesReturned
,
4683 LPBOUNDED_DWORD_256K lpResumeIndex
,
4684 LPCWSTR pszGroupName
)
4686 PMANAGER_HANDLE hManager
;
4688 DWORD dwError
= ERROR_SUCCESS
;
4689 PLIST_ENTRY ServiceEntry
;
4690 PSERVICE CurrentService
;
4692 DWORD dwRequiredSize
;
4693 DWORD dwServiceCount
;
4695 DWORD dwLastResumeCount
= 0;
4696 LPENUM_SERVICE_STATUSW lpStatusPtr
;
4699 DPRINT("REnumServiceGroupW() called\n");
4702 return ERROR_SHUTDOWN_IN_PROGRESS
;
4704 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
4705 if (hManager
== NULL
)
4707 DPRINT1("Invalid service manager handle!\n");
4708 return ERROR_INVALID_HANDLE
;
4711 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
4713 return ERROR_INVALID_ADDRESS
;
4716 *pcbBytesNeeded
= 0;
4717 *lpServicesReturned
= 0;
4719 if ((dwServiceType
== 0) ||
4720 ((dwServiceType
& ~SERVICE_TYPE_ALL
) != 0))
4722 DPRINT("Not a valid Service Type!\n");
4723 return ERROR_INVALID_PARAMETER
;
4726 if ((dwServiceState
== 0) ||
4727 ((dwServiceState
& ~SERVICE_STATE_ALL
) != 0))
4729 DPRINT("Not a valid Service State!\n");
4730 return ERROR_INVALID_PARAMETER
;
4733 /* Check access rights */
4734 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
4735 SC_MANAGER_ENUMERATE_SERVICE
))
4737 DPRINT("Insufficient access rights! 0x%lx\n",
4738 hManager
->Handle
.DesiredAccess
);
4739 return ERROR_ACCESS_DENIED
;
4743 dwLastResumeCount
= *lpResumeIndex
;
4745 /* Lock the service database shared */
4746 ScmLockDatabaseShared();
4748 lpService
= ScmGetServiceEntryByResumeCount(dwLastResumeCount
);
4749 if (lpService
== NULL
)
4751 dwError
= ERROR_SUCCESS
;
4758 for (ServiceEntry
= &lpService
->ServiceListEntry
;
4759 ServiceEntry
!= &ServiceListHead
;
4760 ServiceEntry
= ServiceEntry
->Flink
)
4762 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
4766 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
4769 dwState
= SERVICE_ACTIVE
;
4770 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
4771 dwState
= SERVICE_INACTIVE
;
4773 if ((dwState
& dwServiceState
) == 0)
4778 if (*pszGroupName
== 0)
4780 if (CurrentService
->lpGroup
!= NULL
)
4785 if ((CurrentService
->lpGroup
== NULL
) ||
4786 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
4791 dwSize
= sizeof(ENUM_SERVICE_STATUSW
) +
4792 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
4793 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
4795 if (dwRequiredSize
+ dwSize
> cbBufSize
)
4797 DPRINT("Service name: %S no fit\n", CurrentService
->lpServiceName
);
4801 DPRINT("Service name: %S fit\n", CurrentService
->lpServiceName
);
4802 dwRequiredSize
+= dwSize
;
4804 dwLastResumeCount
= CurrentService
->dwResumeCount
;
4807 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize
);
4808 DPRINT("dwServiceCount: %lu\n", dwServiceCount
);
4811 ServiceEntry
!= &ServiceListHead
;
4812 ServiceEntry
= ServiceEntry
->Flink
)
4814 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
4818 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
4821 dwState
= SERVICE_ACTIVE
;
4822 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
4823 dwState
= SERVICE_INACTIVE
;
4825 if ((dwState
& dwServiceState
) == 0)
4830 if (*pszGroupName
== 0)
4832 if (CurrentService
->lpGroup
!= NULL
)
4837 if ((CurrentService
->lpGroup
== NULL
) ||
4838 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
4843 dwRequiredSize
+= (sizeof(ENUM_SERVICE_STATUSW
) +
4844 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
4845 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
)));
4847 dwError
= ERROR_MORE_DATA
;
4850 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize
);
4853 *lpResumeIndex
= dwLastResumeCount
;
4855 *lpServicesReturned
= dwServiceCount
;
4856 *pcbBytesNeeded
= dwRequiredSize
;
4858 lpStatusPtr
= (LPENUM_SERVICE_STATUSW
)lpBuffer
;
4859 lpStringPtr
= (LPWSTR
)((ULONG_PTR
)lpBuffer
+
4860 dwServiceCount
* sizeof(ENUM_SERVICE_STATUSW
));
4863 for (ServiceEntry
= &lpService
->ServiceListEntry
;
4864 ServiceEntry
!= &ServiceListHead
;
4865 ServiceEntry
= ServiceEntry
->Flink
)
4867 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
4871 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
4874 dwState
= SERVICE_ACTIVE
;
4875 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
4876 dwState
= SERVICE_INACTIVE
;
4878 if ((dwState
& dwServiceState
) == 0)
4883 if (*pszGroupName
== 0)
4885 if (CurrentService
->lpGroup
!= NULL
)
4890 if ((CurrentService
->lpGroup
== NULL
) ||
4891 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
4896 dwSize
= sizeof(ENUM_SERVICE_STATUSW
) +
4897 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
4898 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
4900 if (dwRequiredSize
+ dwSize
> cbBufSize
)
4903 /* Copy the service name */
4904 wcscpy(lpStringPtr
, CurrentService
->lpServiceName
);
4905 lpStatusPtr
->lpServiceName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
4906 lpStringPtr
+= (wcslen(CurrentService
->lpServiceName
) + 1);
4908 /* Copy the display name */
4909 wcscpy(lpStringPtr
, CurrentService
->lpDisplayName
);
4910 lpStatusPtr
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
4911 lpStringPtr
+= (wcslen(CurrentService
->lpDisplayName
) + 1);
4913 /* Copy the status information */
4914 memcpy(&lpStatusPtr
->ServiceStatus
,
4915 &CurrentService
->Status
,
4916 sizeof(SERVICE_STATUS
));
4919 dwRequiredSize
+= dwSize
;
4922 if (dwError
== ERROR_SUCCESS
)
4924 *pcbBytesNeeded
= 0;
4925 if (lpResumeIndex
) *lpResumeIndex
= 0;
4929 /* Unlock the service database */
4930 ScmUnlockDatabase();
4932 DPRINT("REnumServiceGroupW() done (Error %lu)\n", dwError
);
4941 RChangeServiceConfig2A(
4942 SC_RPC_HANDLE hService
,
4943 SC_RPC_CONFIG_INFOA Info
)
4945 SC_RPC_CONFIG_INFOW InfoW
= { 0 };
4946 DWORD dwRet
, dwLength
;
4949 DPRINT("RChangeServiceConfig2A() called\n");
4950 DPRINT("dwInfoLevel = %lu\n", Info
.dwInfoLevel
);
4952 if ((Info
.dwInfoLevel
< SERVICE_CONFIG_DESCRIPTION
) ||
4953 (Info
.dwInfoLevel
> SERVICE_CONFIG_FAILURE_ACTIONS
))
4955 return ERROR_INVALID_LEVEL
;
4958 InfoW
.dwInfoLevel
= Info
.dwInfoLevel
;
4960 if (InfoW
.dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
4962 LPSERVICE_DESCRIPTIONW lpServiceDescriptionW
;
4963 LPSERVICE_DESCRIPTIONA lpServiceDescriptionA
;
4965 lpServiceDescriptionA
= Info
.psd
;
4967 if (lpServiceDescriptionA
&&
4968 lpServiceDescriptionA
->lpDescription
)
4970 dwLength
= (DWORD
)((strlen(lpServiceDescriptionA
->lpDescription
) + 1) * sizeof(WCHAR
));
4972 lpServiceDescriptionW
= HeapAlloc(GetProcessHeap(),
4974 dwLength
+ sizeof(SERVICE_DESCRIPTIONW
));
4975 if (!lpServiceDescriptionW
)
4977 return ERROR_NOT_ENOUGH_MEMORY
;
4980 lpServiceDescriptionW
->lpDescription
= (LPWSTR
)(lpServiceDescriptionW
+ 1);
4982 MultiByteToWideChar(CP_ACP
,
4984 lpServiceDescriptionA
->lpDescription
,
4986 lpServiceDescriptionW
->lpDescription
,
4989 ptr
= lpServiceDescriptionW
;
4990 InfoW
.psd
= lpServiceDescriptionW
;
4993 else if (Info
.dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
4995 LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW
;
4996 LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA
;
4997 DWORD dwRebootLen
= 0;
4998 DWORD dwCommandLen
= 0;
4999 DWORD dwActionArrayLen
= 0;
5000 LPWSTR lpStr
= NULL
;
5002 lpServiceFailureActionsA
= Info
.psfa
;
5004 if (lpServiceFailureActionsA
)
5007 * The following code is inspired by the
5008 * SERVICE_CONFIG_FAILURE_ACTIONS case of
5009 * the RQueryServiceConfig2W function.
5012 /* Retrieve the needed length for the two data strings */
5013 if (lpServiceFailureActionsA
->lpRebootMsg
)
5015 dwRebootLen
= (DWORD
)((strlen(lpServiceFailureActionsA
->lpRebootMsg
) + 1) * sizeof(WCHAR
));
5017 if (lpServiceFailureActionsA
->lpCommand
)
5019 dwCommandLen
= (DWORD
)((strlen(lpServiceFailureActionsA
->lpCommand
) + 1) * sizeof(WCHAR
));
5023 * Retrieve the size of the lpsaActions array if needed.
5024 * We will copy the lpsaActions array only if there is at
5025 * least one action AND that the original array is valid.
5027 if (lpServiceFailureActionsA
->cActions
> 0 && lpServiceFailureActionsA
->lpsaActions
)
5029 dwActionArrayLen
= lpServiceFailureActionsA
->cActions
* sizeof(SC_ACTION
);
5032 /* Compute the total length for the UNICODE structure, including data */
5033 dwLength
= sizeof(SERVICE_FAILURE_ACTIONSW
) +
5034 dwActionArrayLen
+ dwRebootLen
+ dwCommandLen
;
5036 /* Allocate the structure */
5037 lpServiceFailureActionsW
= HeapAlloc(GetProcessHeap(),
5040 if (!lpServiceFailureActionsW
)
5042 return ERROR_NOT_ENOUGH_MEMORY
;
5045 /* Copy the members */
5046 lpServiceFailureActionsW
->dwResetPeriod
= lpServiceFailureActionsA
->dwResetPeriod
;
5047 lpServiceFailureActionsW
->cActions
= lpServiceFailureActionsA
->cActions
;
5049 /* Copy the lpsaActions array if needed */
5050 if (dwActionArrayLen
> 0)
5052 /* The storage zone is just after the end of the SERVICE_FAILURE_ACTIONSW structure */
5053 lpServiceFailureActionsW
->lpsaActions
= (LPSC_ACTION
)((ULONG_PTR
)(lpServiceFailureActionsW
+ 1));
5055 /* dwActionArrayLen == lpServiceFailureActionsW->cActions * sizeof(SC_ACTION) */
5056 RtlCopyMemory(lpServiceFailureActionsW
->lpsaActions
,
5057 lpServiceFailureActionsA
->lpsaActions
,
5062 /* No lpsaActions array */
5063 lpServiceFailureActionsW
->lpsaActions
= NULL
;
5065 /* The data strings are stored just after the lpsaActions array */
5066 lpStr
= (LPWSTR
)((ULONG_PTR
)(lpServiceFailureActionsW
+ 1) + dwActionArrayLen
);
5069 * Convert the data strings to UNICODE
5072 lpServiceFailureActionsW
->lpRebootMsg
= NULL
;
5073 lpServiceFailureActionsW
->lpCommand
= NULL
;
5077 /* lpRebootMsg points just after the lpsaActions array */
5078 lpServiceFailureActionsW
->lpRebootMsg
= lpStr
;
5080 MultiByteToWideChar(CP_ACP
,
5082 lpServiceFailureActionsA
->lpRebootMsg
,
5084 lpServiceFailureActionsW
->lpRebootMsg
,
5087 lpStr
+= dwRebootLen
/ sizeof(WCHAR
);
5092 /* lpRebootMsg points just after the lpRebootMsg data string */
5093 lpServiceFailureActionsW
->lpCommand
= lpStr
;
5095 MultiByteToWideChar(CP_ACP
,
5097 lpServiceFailureActionsA
->lpCommand
,
5099 lpServiceFailureActionsW
->lpCommand
,
5103 /* Set the pointers */
5104 ptr
= lpServiceFailureActionsW
;
5105 InfoW
.psfa
= lpServiceFailureActionsW
;
5109 dwRet
= RChangeServiceConfig2W(hService
, InfoW
);
5111 HeapFree(GetProcessHeap(), 0, ptr
);
5118 ScmSetFailureActions(HKEY hServiceKey
,
5119 LPSERVICE_FAILURE_ACTIONSW lpFailureActions
)
5121 LPSERVICE_FAILURE_ACTIONSW lpReadBuffer
= NULL
;
5122 LPSERVICE_FAILURE_ACTIONSW lpWriteBuffer
= NULL
;
5123 DWORD dwRequiredSize
= 0;
5127 /* There is nothing to be done if we have no failure actions */
5128 if (lpFailureActions
== NULL
)
5129 return ERROR_SUCCESS
;
5132 * 1- Retrieve the original value of FailureActions.
5135 /* Query value length */
5136 dwError
= RegQueryValueExW(hServiceKey
,
5142 if (dwError
!= ERROR_SUCCESS
&&
5143 dwError
!= ERROR_MORE_DATA
&&
5144 dwError
!= ERROR_FILE_NOT_FOUND
)
5149 dwRequiredSize
= (dwType
== REG_BINARY
) ? max(sizeof(SERVICE_FAILURE_ACTIONSW
), dwRequiredSize
)
5150 : sizeof(SERVICE_FAILURE_ACTIONSW
);
5152 /* Initialize the read buffer */
5153 lpReadBuffer
= HeapAlloc(GetProcessHeap(),
5156 if (lpReadBuffer
== NULL
)
5157 return ERROR_NOT_ENOUGH_MEMORY
;
5159 /* Now we can fill the read buffer */
5160 if (dwError
!= ERROR_FILE_NOT_FOUND
&&
5161 dwType
== REG_BINARY
)
5163 dwError
= RegQueryValueExW(hServiceKey
,
5167 (LPBYTE
)lpReadBuffer
,
5169 if (dwError
!= ERROR_SUCCESS
&&
5170 dwError
!= ERROR_FILE_NOT_FOUND
)
5173 if (dwRequiredSize
< sizeof(SERVICE_FAILURE_ACTIONSW
))
5174 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSW
);
5179 * The value of the error doesn't really matter, the only
5180 * important thing is that it must be != ERROR_SUCCESS.
5182 dwError
= ERROR_INVALID_DATA
;
5185 if (dwError
== ERROR_SUCCESS
)
5187 lpReadBuffer
->cActions
= min(lpReadBuffer
->cActions
, (dwRequiredSize
- sizeof(SERVICE_FAILURE_ACTIONSW
)) / sizeof(SC_ACTION
));
5188 lpReadBuffer
->lpsaActions
= (lpReadBuffer
->cActions
> 0 ? (LPSC_ACTION
)(lpReadBuffer
+ 1) : NULL
);
5192 lpReadBuffer
->dwResetPeriod
= 0;
5193 lpReadBuffer
->cActions
= 0;
5194 lpReadBuffer
->lpsaActions
= NULL
;
5197 lpReadBuffer
->lpRebootMsg
= NULL
;
5198 lpReadBuffer
->lpCommand
= NULL
;
5201 * 2- Initialize the new value to set.
5204 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSW
);
5206 if (lpFailureActions
->lpsaActions
== NULL
)
5209 * lpFailureActions->cActions is ignored.
5210 * Therefore we use the original values
5211 * of cActions and lpsaActions.
5213 dwRequiredSize
+= lpReadBuffer
->cActions
* sizeof(SC_ACTION
);
5218 * The reset period and array of failure actions
5219 * are deleted if lpFailureActions->cActions == 0 .
5221 dwRequiredSize
+= lpFailureActions
->cActions
* sizeof(SC_ACTION
);
5224 lpWriteBuffer
= HeapAlloc(GetProcessHeap(),
5227 if (lpWriteBuffer
== NULL
)
5229 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
5233 /* Clean the pointers as they have no meaning when the structure is stored in the registry */
5234 lpWriteBuffer
->lpRebootMsg
= NULL
;
5235 lpWriteBuffer
->lpCommand
= NULL
;
5236 lpWriteBuffer
->lpsaActions
= NULL
;
5238 /* Set the members */
5239 if (lpFailureActions
->lpsaActions
== NULL
)
5242 * lpFailureActions->dwResetPeriod and lpFailureActions->cActions are ignored.
5243 * Therefore we use the original values of dwResetPeriod, cActions and lpsaActions.
5245 lpWriteBuffer
->dwResetPeriod
= lpReadBuffer
->dwResetPeriod
;
5246 lpWriteBuffer
->cActions
= lpReadBuffer
->cActions
;
5248 if (lpReadBuffer
->lpsaActions
!= NULL
)
5250 memmove(lpWriteBuffer
+ 1,
5251 lpReadBuffer
->lpsaActions
,
5252 lpReadBuffer
->cActions
* sizeof(SC_ACTION
));
5257 if (lpFailureActions
->cActions
> 0)
5259 lpWriteBuffer
->dwResetPeriod
= lpFailureActions
->dwResetPeriod
;
5260 lpWriteBuffer
->cActions
= lpFailureActions
->cActions
;
5262 memmove(lpWriteBuffer
+ 1,
5263 lpFailureActions
->lpsaActions
,
5264 lpFailureActions
->cActions
* sizeof(SC_ACTION
));
5268 /* The reset period and array of failure actions are deleted */
5269 lpWriteBuffer
->dwResetPeriod
= 0;
5270 lpWriteBuffer
->cActions
= 0;
5274 /* Save the new failure actions into the registry */
5275 dwError
= RegSetValueExW(hServiceKey
,
5279 (LPBYTE
)lpWriteBuffer
,
5282 /* We modify the strings only in case of success.*/
5283 if (dwError
== ERROR_SUCCESS
)
5285 /* Modify the Reboot Message value, if specified */
5286 if (lpFailureActions
->lpRebootMsg
!= NULL
)
5288 /* If the Reboot Message is "" then we delete it */
5289 if (*lpFailureActions
->lpRebootMsg
== 0)
5291 DPRINT("Delete Reboot Message value\n");
5292 RegDeleteValueW(hServiceKey
, L
"RebootMessage");
5296 DPRINT("Setting Reboot Message value %S\n", lpFailureActions
->lpRebootMsg
);
5297 RegSetValueExW(hServiceKey
,
5301 (LPBYTE
)lpFailureActions
->lpRebootMsg
,
5302 (DWORD
)((wcslen(lpFailureActions
->lpRebootMsg
) + 1) * sizeof(WCHAR
)));
5306 /* Modify the Failure Command value, if specified */
5307 if (lpFailureActions
->lpCommand
!= NULL
)
5309 /* If the FailureCommand string is an empty string, delete the value */
5310 if (*lpFailureActions
->lpCommand
== 0)
5312 DPRINT("Delete Failure Command value\n");
5313 RegDeleteValueW(hServiceKey
, L
"FailureCommand");
5317 DPRINT("Setting Failure Command value %S\n", lpFailureActions
->lpCommand
);
5318 RegSetValueExW(hServiceKey
,
5322 (LPBYTE
)lpFailureActions
->lpCommand
,
5323 (DWORD
)((wcslen(lpFailureActions
->lpCommand
) + 1) * sizeof(WCHAR
)));
5329 if (lpWriteBuffer
!= NULL
)
5330 HeapFree(GetProcessHeap(), 0, lpWriteBuffer
);
5332 if (lpReadBuffer
!= NULL
)
5333 HeapFree(GetProcessHeap(), 0, lpReadBuffer
);
5342 RChangeServiceConfig2W(
5343 SC_RPC_HANDLE hService
,
5344 SC_RPC_CONFIG_INFOW Info
)
5346 DWORD dwError
= ERROR_SUCCESS
;
5347 PSERVICE_HANDLE hSvc
;
5348 PSERVICE lpService
= NULL
;
5349 HKEY hServiceKey
= NULL
;
5350 ACCESS_MASK RequiredAccess
= SERVICE_CHANGE_CONFIG
;
5352 DPRINT("RChangeServiceConfig2W() called\n");
5353 DPRINT("dwInfoLevel = %lu\n", Info
.dwInfoLevel
);
5356 return ERROR_SHUTDOWN_IN_PROGRESS
;
5358 if ((Info
.dwInfoLevel
< SERVICE_CONFIG_DESCRIPTION
) ||
5359 (Info
.dwInfoLevel
> SERVICE_CONFIG_FAILURE_ACTIONS
))
5361 return ERROR_INVALID_LEVEL
;
5364 hSvc
= ScmGetServiceFromHandle(hService
);
5367 DPRINT("Invalid service handle!\n");
5368 return ERROR_INVALID_HANDLE
;
5371 if (Info
.dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5372 RequiredAccess
|= SERVICE_START
;
5374 /* Check the access rights */
5375 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5378 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5379 return ERROR_ACCESS_DENIED
;
5382 if (Info
.dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5384 /* FIXME: Check if the caller has the SE_SHUTDOWN_NAME privilege */
5388 lpService
= hSvc
->ServiceEntry
;
5389 if (lpService
== NULL
)
5391 DPRINT("lpService == NULL!\n");
5392 return ERROR_INVALID_HANDLE
;
5395 /* Failure actions can only be set for Win32 services, not for drivers */
5396 if (Info
.dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5398 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
5399 return ERROR_CANNOT_DETECT_DRIVER_FAILURE
;
5402 /* Lock the service database exclusively */
5403 ScmLockDatabaseExclusive();
5405 if (lpService
->bDeleted
)
5407 DPRINT("The service has already been marked for delete!\n");
5408 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
5412 /* Open the service key */
5413 dwError
= ScmOpenServiceKey(lpService
->szServiceName
,
5414 KEY_READ
| KEY_SET_VALUE
,
5416 if (dwError
!= ERROR_SUCCESS
)
5419 if (Info
.dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
5421 LPSERVICE_DESCRIPTIONW lpServiceDescription
= (LPSERVICE_DESCRIPTIONW
)Info
.psd
;
5423 /* Modify the service description, if specified */
5424 if (lpServiceDescription
!= NULL
&&
5425 lpServiceDescription
->lpDescription
!= NULL
)
5427 /* If the description is "" then we delete it */
5428 if (*lpServiceDescription
->lpDescription
== 0)
5430 DPRINT("Delete service description\n");
5431 dwError
= RegDeleteValueW(hServiceKey
, L
"Description");
5433 if (dwError
== ERROR_FILE_NOT_FOUND
)
5434 dwError
= ERROR_SUCCESS
;
5438 DPRINT("Setting service description value %S\n", lpServiceDescription
->lpDescription
);
5439 dwError
= RegSetValueExW(hServiceKey
,
5443 (LPBYTE
)lpServiceDescription
->lpDescription
,
5444 (DWORD
)((wcslen(lpServiceDescription
->lpDescription
) + 1) * sizeof(WCHAR
)));
5449 dwError
= ERROR_SUCCESS
;
5452 else if (Info
.dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5454 dwError
= ScmSetFailureActions(hServiceKey
,
5455 (LPSERVICE_FAILURE_ACTIONSW
)Info
.psfa
);
5459 if (hServiceKey
!= NULL
)
5460 RegCloseKey(hServiceKey
);
5462 /* Unlock the service database */
5463 ScmUnlockDatabase();
5465 DPRINT("RChangeServiceConfig2W() done (Error %lu)\n", dwError
);
5474 RQueryServiceConfig2A(
5475 SC_RPC_HANDLE hService
,
5479 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
5481 DWORD dwError
= ERROR_SUCCESS
;
5482 PSERVICE_HANDLE hSvc
;
5483 PSERVICE lpService
= NULL
;
5484 HKEY hServiceKey
= NULL
;
5485 DWORD dwRequiredSize
= 0;
5487 LPWSTR lpDescriptionW
= NULL
;
5488 LPWSTR lpRebootMessageW
= NULL
;
5489 LPWSTR lpFailureCommandW
= NULL
;
5491 DPRINT("RQueryServiceConfig2A() called hService %p dwInfoLevel %u, lpBuffer %p cbBufSize %u pcbBytesNeeded %p\n",
5492 hService
, dwInfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
5495 return ERROR_INVALID_ADDRESS
;
5498 return ERROR_SHUTDOWN_IN_PROGRESS
;
5500 if ((dwInfoLevel
< SERVICE_CONFIG_DESCRIPTION
) ||
5501 (dwInfoLevel
> SERVICE_CONFIG_FAILURE_ACTIONS
))
5503 return ERROR_INVALID_LEVEL
;
5506 hSvc
= ScmGetServiceFromHandle(hService
);
5509 DPRINT1("Invalid service handle!\n");
5510 return ERROR_INVALID_HANDLE
;
5513 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5514 SERVICE_QUERY_CONFIG
))
5516 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5517 return ERROR_ACCESS_DENIED
;
5520 lpService
= hSvc
->ServiceEntry
;
5521 if (lpService
== NULL
)
5523 DPRINT("lpService == NULL!\n");
5524 return ERROR_INVALID_HANDLE
;
5527 /* Lock the service database shared */
5528 ScmLockDatabaseShared();
5530 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
5533 if (dwError
!= ERROR_SUCCESS
)
5536 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
5538 LPSERVICE_DESCRIPTIONA lpServiceDescription
= (LPSERVICE_DESCRIPTIONA
)lpBuffer
;
5541 dwError
= ScmReadString(hServiceKey
,
5544 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5547 *pcbBytesNeeded
= sizeof(SERVICE_DESCRIPTIONA
);
5548 if (dwError
== ERROR_SUCCESS
)
5549 *pcbBytesNeeded
+= (DWORD
)((wcslen(lpDescriptionW
) + 1) * sizeof(WCHAR
));
5551 if (cbBufSize
< *pcbBytesNeeded
)
5553 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5557 if (dwError
== ERROR_SUCCESS
)
5559 lpStr
= (LPSTR
)(lpServiceDescription
+ 1);
5561 WideCharToMultiByte(CP_ACP
,
5566 (int)wcslen(lpDescriptionW
),
5569 lpServiceDescription
->lpDescription
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceDescription
);
5573 lpServiceDescription
->lpDescription
= NULL
;
5574 dwError
= ERROR_SUCCESS
;
5577 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5579 LPSERVICE_FAILURE_ACTIONSA lpFailureActions
= (LPSERVICE_FAILURE_ACTIONSA
)lpBuffer
;
5582 /* Query value length */
5583 dwError
= RegQueryValueExW(hServiceKey
,
5589 if (dwError
!= ERROR_SUCCESS
&&
5590 dwError
!= ERROR_MORE_DATA
&&
5591 dwError
!= ERROR_FILE_NOT_FOUND
)
5596 dwRequiredSize
= (dwType
== REG_BINARY
) ? max(sizeof(SERVICE_FAILURE_ACTIONSA
), dwRequiredSize
)
5597 : sizeof(SERVICE_FAILURE_ACTIONSA
);
5599 /* Get the strings */
5600 ScmReadString(hServiceKey
,
5602 &lpFailureCommandW
);
5604 ScmReadString(hServiceKey
,
5608 if (lpRebootMessageW
)
5609 dwRequiredSize
+= (DWORD
)((wcslen(lpRebootMessageW
) + 1) * sizeof(WCHAR
));
5611 if (lpFailureCommandW
)
5612 dwRequiredSize
+= (DWORD
)((wcslen(lpFailureCommandW
) + 1) * sizeof(WCHAR
));
5614 if (cbBufSize
< dwRequiredSize
)
5616 *pcbBytesNeeded
= dwRequiredSize
;
5617 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5621 /* Now we can fill the buffer */
5622 if (dwError
!= ERROR_FILE_NOT_FOUND
&& dwType
== REG_BINARY
)
5624 dwError
= RegQueryValueExW(hServiceKey
,
5628 (LPBYTE
)lpFailureActions
,
5630 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5633 if (dwRequiredSize
< sizeof(SERVICE_FAILURE_ACTIONSA
))
5634 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSA
);
5639 * The value of the error doesn't really matter, the only
5640 * important thing is that it must be != ERROR_SUCCESS .
5642 dwError
= ERROR_INVALID_DATA
;
5645 if (dwError
== ERROR_SUCCESS
)
5647 lpFailureActions
->cActions
= min(lpFailureActions
->cActions
, (dwRequiredSize
- sizeof(SERVICE_FAILURE_ACTIONSA
)) / sizeof(SC_ACTION
));
5649 /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */
5650 lpFailureActions
->lpsaActions
= (lpFailureActions
->cActions
> 0 ? (LPSC_ACTION
)(ULONG_PTR
)sizeof(SERVICE_FAILURE_ACTIONSA
) : NULL
);
5652 lpStr
= (LPSTR
)((ULONG_PTR
)(lpFailureActions
+ 1) + lpFailureActions
->cActions
* sizeof(SC_ACTION
));
5656 lpFailureActions
->dwResetPeriod
= 0;
5657 lpFailureActions
->cActions
= 0;
5658 lpFailureActions
->lpsaActions
= NULL
;
5659 lpStr
= (LPSTR
)(lpFailureActions
+ 1);
5662 lpFailureActions
->lpRebootMsg
= NULL
;
5663 lpFailureActions
->lpCommand
= NULL
;
5665 if (lpRebootMessageW
)
5667 WideCharToMultiByte(CP_ACP
,
5672 (int)wcslen(lpRebootMessageW
),
5675 lpFailureActions
->lpRebootMsg
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5676 lpStr
+= strlen(lpStr
) + 1;
5679 if (lpFailureCommandW
)
5681 WideCharToMultiByte(CP_ACP
,
5686 (int)wcslen(lpFailureCommandW
),
5689 lpFailureActions
->lpCommand
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5690 /* lpStr += strlen(lpStr) + 1; */
5693 dwError
= ERROR_SUCCESS
;
5697 /* Unlock the service database */
5698 ScmUnlockDatabase();
5700 if (lpDescriptionW
!= NULL
)
5701 HeapFree(GetProcessHeap(), 0, lpDescriptionW
);
5703 if (lpRebootMessageW
!= NULL
)
5704 HeapFree(GetProcessHeap(), 0, lpRebootMessageW
);
5706 if (lpFailureCommandW
!= NULL
)
5707 HeapFree(GetProcessHeap(), 0, lpFailureCommandW
);
5709 if (hServiceKey
!= NULL
)
5710 RegCloseKey(hServiceKey
);
5712 DPRINT("RQueryServiceConfig2A() done (Error %lu)\n", dwError
);
5721 RQueryServiceConfig2W(
5722 SC_RPC_HANDLE hService
,
5726 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
5728 DWORD dwError
= ERROR_SUCCESS
;
5729 PSERVICE_HANDLE hSvc
;
5730 PSERVICE lpService
= NULL
;
5731 HKEY hServiceKey
= NULL
;
5732 DWORD dwRequiredSize
= 0;
5734 LPWSTR lpDescription
= NULL
;
5735 LPWSTR lpRebootMessage
= NULL
;
5736 LPWSTR lpFailureCommand
= NULL
;
5738 DPRINT("RQueryServiceConfig2W() called\n");
5741 return ERROR_INVALID_ADDRESS
;
5744 return ERROR_SHUTDOWN_IN_PROGRESS
;
5746 if ((dwInfoLevel
< SERVICE_CONFIG_DESCRIPTION
) ||
5747 (dwInfoLevel
> SERVICE_CONFIG_FAILURE_ACTIONS
))
5749 return ERROR_INVALID_LEVEL
;
5752 hSvc
= ScmGetServiceFromHandle(hService
);
5755 DPRINT1("Invalid service handle!\n");
5756 return ERROR_INVALID_HANDLE
;
5759 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5760 SERVICE_QUERY_CONFIG
))
5762 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5763 return ERROR_ACCESS_DENIED
;
5766 lpService
= hSvc
->ServiceEntry
;
5767 if (lpService
== NULL
)
5769 DPRINT("lpService == NULL!\n");
5770 return ERROR_INVALID_HANDLE
;
5773 /* Lock the service database shared */
5774 ScmLockDatabaseShared();
5776 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
5779 if (dwError
!= ERROR_SUCCESS
)
5782 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
5784 LPSERVICE_DESCRIPTIONW lpServiceDescription
= (LPSERVICE_DESCRIPTIONW
)lpBuffer
;
5787 dwError
= ScmReadString(hServiceKey
,
5790 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5793 *pcbBytesNeeded
= sizeof(SERVICE_DESCRIPTIONW
);
5794 if (dwError
== ERROR_SUCCESS
)
5795 *pcbBytesNeeded
+= (DWORD
)((wcslen(lpDescription
) + 1) * sizeof(WCHAR
));
5797 if (cbBufSize
< *pcbBytesNeeded
)
5799 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5803 if (dwError
== ERROR_SUCCESS
)
5805 lpStr
= (LPWSTR
)(lpServiceDescription
+ 1);
5806 wcscpy(lpStr
, lpDescription
);
5807 lpServiceDescription
->lpDescription
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceDescription
);
5811 lpServiceDescription
->lpDescription
= NULL
;
5812 dwError
= ERROR_SUCCESS
;
5815 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5817 LPSERVICE_FAILURE_ACTIONSW lpFailureActions
= (LPSERVICE_FAILURE_ACTIONSW
)lpBuffer
;
5818 LPWSTR lpStr
= NULL
;
5820 /* Query value length */
5821 dwError
= RegQueryValueExW(hServiceKey
,
5827 if (dwError
!= ERROR_SUCCESS
&&
5828 dwError
!= ERROR_MORE_DATA
&&
5829 dwError
!= ERROR_FILE_NOT_FOUND
)
5834 dwRequiredSize
= (dwType
== REG_BINARY
) ? max(sizeof(SERVICE_FAILURE_ACTIONSW
), dwRequiredSize
)
5835 : sizeof(SERVICE_FAILURE_ACTIONSW
);
5837 /* Get the strings */
5838 ScmReadString(hServiceKey
,
5842 ScmReadString(hServiceKey
,
5846 if (lpRebootMessage
)
5847 dwRequiredSize
+= (DWORD
)((wcslen(lpRebootMessage
) + 1) * sizeof(WCHAR
));
5849 if (lpFailureCommand
)
5850 dwRequiredSize
+= (DWORD
)((wcslen(lpFailureCommand
) + 1) * sizeof(WCHAR
));
5852 if (cbBufSize
< dwRequiredSize
)
5854 *pcbBytesNeeded
= dwRequiredSize
;
5855 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5859 /* Now we can fill the buffer */
5860 if (dwError
!= ERROR_FILE_NOT_FOUND
&& dwType
== REG_BINARY
)
5862 dwError
= RegQueryValueExW(hServiceKey
,
5866 (LPBYTE
)lpFailureActions
,
5868 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5871 if (dwRequiredSize
< sizeof(SERVICE_FAILURE_ACTIONSW
))
5872 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSW
);
5877 * The value of the error doesn't really matter, the only
5878 * important thing is that it must be != ERROR_SUCCESS .
5880 dwError
= ERROR_INVALID_DATA
;
5883 if (dwError
== ERROR_SUCCESS
)
5885 lpFailureActions
->cActions
= min(lpFailureActions
->cActions
, (dwRequiredSize
- sizeof(SERVICE_FAILURE_ACTIONSW
)) / sizeof(SC_ACTION
));
5887 /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */
5888 lpFailureActions
->lpsaActions
= (lpFailureActions
->cActions
> 0 ? (LPSC_ACTION
)(ULONG_PTR
)sizeof(SERVICE_FAILURE_ACTIONSW
) : NULL
);
5890 lpStr
= (LPWSTR
)((ULONG_PTR
)(lpFailureActions
+ 1) + lpFailureActions
->cActions
* sizeof(SC_ACTION
));
5894 lpFailureActions
->dwResetPeriod
= 0;
5895 lpFailureActions
->cActions
= 0;
5896 lpFailureActions
->lpsaActions
= NULL
;
5897 lpStr
= (LPWSTR
)(lpFailureActions
+ 1);
5900 lpFailureActions
->lpRebootMsg
= NULL
;
5901 lpFailureActions
->lpCommand
= NULL
;
5903 if (lpRebootMessage
)
5905 wcscpy(lpStr
, lpRebootMessage
);
5906 lpFailureActions
->lpRebootMsg
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5907 lpStr
+= wcslen(lpStr
) + 1;
5910 if (lpFailureCommand
)
5912 wcscpy(lpStr
, lpFailureCommand
);
5913 lpFailureActions
->lpCommand
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5914 /* lpStr += wcslen(lpStr) + 1; */
5917 dwError
= ERROR_SUCCESS
;
5921 /* Unlock the service database */
5922 ScmUnlockDatabase();
5924 if (lpDescription
!= NULL
)
5925 HeapFree(GetProcessHeap(), 0, lpDescription
);
5927 if (lpRebootMessage
!= NULL
)
5928 HeapFree(GetProcessHeap(), 0, lpRebootMessage
);
5930 if (lpFailureCommand
!= NULL
)
5931 HeapFree(GetProcessHeap(), 0, lpFailureCommand
);
5933 if (hServiceKey
!= NULL
)
5934 RegCloseKey(hServiceKey
);
5936 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError
);
5945 RQueryServiceStatusEx(
5946 SC_RPC_HANDLE hService
,
5947 SC_STATUS_TYPE InfoLevel
,
5950 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
5952 LPSERVICE_STATUS_PROCESS lpStatus
;
5953 PSERVICE_HANDLE hSvc
;
5956 DPRINT("RQueryServiceStatusEx() called\n");
5959 return ERROR_SHUTDOWN_IN_PROGRESS
;
5961 if (InfoLevel
!= SC_STATUS_PROCESS_INFO
)
5962 return ERROR_INVALID_LEVEL
;
5964 *pcbBytesNeeded
= sizeof(SERVICE_STATUS_PROCESS
);
5966 if (cbBufSize
< sizeof(SERVICE_STATUS_PROCESS
))
5967 return ERROR_INSUFFICIENT_BUFFER
;
5969 hSvc
= ScmGetServiceFromHandle(hService
);
5972 DPRINT1("Invalid service handle!\n");
5973 return ERROR_INVALID_HANDLE
;
5976 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5977 SERVICE_QUERY_STATUS
))
5979 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5980 return ERROR_ACCESS_DENIED
;
5983 lpService
= hSvc
->ServiceEntry
;
5984 if (lpService
== NULL
)
5986 DPRINT("lpService == NULL!\n");
5987 return ERROR_INVALID_HANDLE
;
5990 /* Lock the service database shared */
5991 ScmLockDatabaseShared();
5993 lpStatus
= (LPSERVICE_STATUS_PROCESS
)lpBuffer
;
5995 /* Return service status information */
5996 RtlCopyMemory(lpStatus
,
5998 sizeof(SERVICE_STATUS
));
6000 /* Copy the service process ID */
6001 if ((lpService
->Status
.dwCurrentState
== SERVICE_STOPPED
) || (lpService
->lpImage
== NULL
))
6002 lpStatus
->dwProcessId
= 0;
6004 lpStatus
->dwProcessId
= lpService
->lpImage
->dwProcessId
;
6006 lpStatus
->dwServiceFlags
= 0; /* FIXME */
6008 /* Unlock the service database */
6009 ScmUnlockDatabase();
6011 return ERROR_SUCCESS
;
6018 REnumServicesStatusExA(
6019 SC_RPC_HANDLE hSCManager
,
6020 SC_ENUM_TYPE InfoLevel
,
6021 DWORD dwServiceType
,
6022 DWORD dwServiceState
,
6025 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
6026 LPBOUNDED_DWORD_256K lpServicesReturned
,
6027 LPBOUNDED_DWORD_256K lpResumeIndex
,
6028 LPCSTR pszGroupName
)
6030 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrW
= NULL
;
6031 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrIncrW
;
6032 LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtrA
= NULL
;
6033 LPWSTR lpStringPtrW
;
6035 LPWSTR pszGroupNameW
= NULL
;
6037 DWORD dwServiceCount
;
6039 DPRINT("REnumServicesStatusExA() called\n");
6041 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
6043 return ERROR_INVALID_ADDRESS
;
6048 pszGroupNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, (strlen(pszGroupName
) + 1) * sizeof(WCHAR
));
6051 DPRINT("Failed to allocate buffer!\n");
6052 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
6056 MultiByteToWideChar(CP_ACP
,
6061 (int)(strlen(pszGroupName
) + 1));
6064 if ((cbBufSize
> 0) && (lpBuffer
))
6066 lpStatusPtrW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, cbBufSize
);
6069 DPRINT("Failed to allocate buffer!\n");
6070 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
6075 dwError
= REnumServicesStatusExW(hSCManager
,
6079 (LPBYTE
)lpStatusPtrW
,
6086 /* if no services were returned then we are Done */
6087 if (*lpServicesReturned
== 0)
6090 lpStatusPtrIncrW
= lpStatusPtrW
;
6091 lpStatusPtrA
= (LPENUM_SERVICE_STATUS_PROCESSA
)lpBuffer
;
6092 lpStringPtrA
= (LPSTR
)((ULONG_PTR
)lpBuffer
+
6093 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUS_PROCESSA
));
6094 lpStringPtrW
= (LPWSTR
)((ULONG_PTR
)lpStatusPtrW
+
6095 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUS_PROCESSW
));
6097 for (dwServiceCount
= 0; dwServiceCount
< *lpServicesReturned
; dwServiceCount
++)
6099 /* Copy the service name */
6100 WideCharToMultiByte(CP_ACP
,
6105 (int)wcslen(lpStringPtrW
),
6109 lpStatusPtrA
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
6110 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
6111 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
6113 /* Copy the display name */
6114 WideCharToMultiByte(CP_ACP
,
6119 (int)wcslen(lpStringPtrW
),
6123 lpStatusPtrA
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
6124 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
6125 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
6127 /* Copy the status information */
6128 memcpy(&lpStatusPtrA
->ServiceStatusProcess
,
6129 &lpStatusPtrIncrW
->ServiceStatusProcess
,
6130 sizeof(SERVICE_STATUS
));
6132 /* Copy the service process ID */
6133 lpStatusPtrA
->ServiceStatusProcess
.dwProcessId
= lpStatusPtrIncrW
->ServiceStatusProcess
.dwProcessId
;
6135 lpStatusPtrA
->ServiceStatusProcess
.dwServiceFlags
= 0; /* FIXME */
6143 HeapFree(GetProcessHeap(), 0, pszGroupNameW
);
6146 HeapFree(GetProcessHeap(), 0, lpStatusPtrW
);
6148 DPRINT("REnumServicesStatusExA() done (Error %lu)\n", dwError
);
6157 REnumServicesStatusExW(
6158 SC_RPC_HANDLE hSCManager
,
6159 SC_ENUM_TYPE InfoLevel
,
6160 DWORD dwServiceType
,
6161 DWORD dwServiceState
,
6164 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
6165 LPBOUNDED_DWORD_256K lpServicesReturned
,
6166 LPBOUNDED_DWORD_256K lpResumeIndex
,
6167 LPCWSTR pszGroupName
)
6169 PMANAGER_HANDLE hManager
;
6171 DWORD dwError
= ERROR_SUCCESS
;
6172 PLIST_ENTRY ServiceEntry
;
6173 PSERVICE CurrentService
;
6175 DWORD dwRequiredSize
;
6176 DWORD dwServiceCount
;
6178 DWORD dwLastResumeCount
= 0;
6179 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr
;
6182 DPRINT("REnumServicesStatusExW() called\n");
6185 return ERROR_SHUTDOWN_IN_PROGRESS
;
6187 if (InfoLevel
!= SC_ENUM_PROCESS_INFO
)
6188 return ERROR_INVALID_LEVEL
;
6190 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
6191 if (hManager
== NULL
)
6193 DPRINT1("Invalid service manager handle!\n");
6194 return ERROR_INVALID_HANDLE
;
6197 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
6199 return ERROR_INVALID_ADDRESS
;
6202 *pcbBytesNeeded
= 0;
6203 *lpServicesReturned
= 0;
6205 if ((dwServiceType
== 0) ||
6206 ((dwServiceType
& ~SERVICE_TYPE_ALL
) != 0))
6208 DPRINT("Not a valid Service Type!\n");
6209 return ERROR_INVALID_PARAMETER
;
6212 if ((dwServiceState
== 0) ||
6213 ((dwServiceState
& ~SERVICE_STATE_ALL
) != 0))
6215 DPRINT("Not a valid Service State!\n");
6216 return ERROR_INVALID_PARAMETER
;
6219 /* Check access rights */
6220 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
6221 SC_MANAGER_ENUMERATE_SERVICE
))
6223 DPRINT("Insufficient access rights! 0x%lx\n",
6224 hManager
->Handle
.DesiredAccess
);
6225 return ERROR_ACCESS_DENIED
;
6229 dwLastResumeCount
= *lpResumeIndex
;
6231 /* Lock the service database shared */
6232 ScmLockDatabaseShared();
6234 lpService
= ScmGetServiceEntryByResumeCount(dwLastResumeCount
);
6235 if (lpService
== NULL
)
6237 dwError
= ERROR_SUCCESS
;
6244 for (ServiceEntry
= &lpService
->ServiceListEntry
;
6245 ServiceEntry
!= &ServiceListHead
;
6246 ServiceEntry
= ServiceEntry
->Flink
)
6248 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
6252 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
6255 dwState
= SERVICE_ACTIVE
;
6256 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
6257 dwState
= SERVICE_INACTIVE
;
6259 if ((dwState
& dwServiceState
) == 0)
6264 if (*pszGroupName
== 0)
6266 if (CurrentService
->lpGroup
!= NULL
)
6271 if ((CurrentService
->lpGroup
== NULL
) ||
6272 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
6277 dwSize
= sizeof(ENUM_SERVICE_STATUS_PROCESSW
) +
6278 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
6279 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
6281 if (dwRequiredSize
+ dwSize
<= cbBufSize
)
6283 DPRINT("Service name: %S fit\n", CurrentService
->lpServiceName
);
6284 dwRequiredSize
+= dwSize
;
6286 dwLastResumeCount
= CurrentService
->dwResumeCount
;
6290 DPRINT("Service name: %S no fit\n", CurrentService
->lpServiceName
);
6296 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize
);
6297 DPRINT("dwServiceCount: %lu\n", dwServiceCount
);
6300 ServiceEntry
!= &ServiceListHead
;
6301 ServiceEntry
= ServiceEntry
->Flink
)
6303 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
6307 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
6310 dwState
= SERVICE_ACTIVE
;
6311 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
6312 dwState
= SERVICE_INACTIVE
;
6314 if ((dwState
& dwServiceState
) == 0)
6319 if (*pszGroupName
== 0)
6321 if (CurrentService
->lpGroup
!= NULL
)
6326 if ((CurrentService
->lpGroup
== NULL
) ||
6327 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
6332 dwRequiredSize
+= (sizeof(ENUM_SERVICE_STATUS_PROCESSW
) +
6333 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
6334 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
)));
6336 dwError
= ERROR_MORE_DATA
;
6339 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize
);
6342 *lpResumeIndex
= dwLastResumeCount
;
6344 *lpServicesReturned
= dwServiceCount
;
6345 *pcbBytesNeeded
= dwRequiredSize
;
6347 /* If there was no services that matched */
6348 if ((!dwServiceCount
) && (dwError
!= ERROR_MORE_DATA
))
6350 dwError
= ERROR_SERVICE_DOES_NOT_EXIST
;
6354 lpStatusPtr
= (LPENUM_SERVICE_STATUS_PROCESSW
)lpBuffer
;
6355 lpStringPtr
= (LPWSTR
)((ULONG_PTR
)lpBuffer
+
6356 dwServiceCount
* sizeof(ENUM_SERVICE_STATUS_PROCESSW
));
6359 for (ServiceEntry
= &lpService
->ServiceListEntry
;
6360 ServiceEntry
!= &ServiceListHead
;
6361 ServiceEntry
= ServiceEntry
->Flink
)
6363 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
6367 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
6370 dwState
= SERVICE_ACTIVE
;
6371 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
6372 dwState
= SERVICE_INACTIVE
;
6374 if ((dwState
& dwServiceState
) == 0)
6379 if (*pszGroupName
== 0)
6381 if (CurrentService
->lpGroup
!= NULL
)
6386 if ((CurrentService
->lpGroup
== NULL
) ||
6387 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
6392 dwSize
= sizeof(ENUM_SERVICE_STATUS_PROCESSW
) +
6393 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
6394 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
6396 if (dwRequiredSize
+ dwSize
<= cbBufSize
)
6398 /* Copy the service name */
6400 CurrentService
->lpServiceName
);
6401 lpStatusPtr
->lpServiceName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
6402 lpStringPtr
+= (wcslen(CurrentService
->lpServiceName
) + 1);
6404 /* Copy the display name */
6406 CurrentService
->lpDisplayName
);
6407 lpStatusPtr
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
6408 lpStringPtr
+= (wcslen(CurrentService
->lpDisplayName
) + 1);
6410 /* Copy the status information */
6411 memcpy(&lpStatusPtr
->ServiceStatusProcess
,
6412 &CurrentService
->Status
,
6413 sizeof(SERVICE_STATUS
));
6415 /* Copy the service process ID */
6416 if ((CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
) || (CurrentService
->lpImage
== NULL
))
6417 lpStatusPtr
->ServiceStatusProcess
.dwProcessId
= 0;
6419 lpStatusPtr
->ServiceStatusProcess
.dwProcessId
= CurrentService
->lpImage
->dwProcessId
;
6421 lpStatusPtr
->ServiceStatusProcess
.dwServiceFlags
= 0; /* FIXME */
6424 dwRequiredSize
+= dwSize
;
6434 *pcbBytesNeeded
= 0;
6440 /* Unlock the service database */
6441 ScmUnlockDatabase();
6443 DPRINT("REnumServicesStatusExW() done (Error %lu)\n", dwError
);
6453 handle_t BindingHandle
) /* FIXME */
6456 return ERROR_CALL_NOT_IMPLEMENTED
;
6463 RCreateServiceWOW64A(
6464 handle_t BindingHandle
,
6465 LPSTR lpServiceName
,
6466 LPSTR lpDisplayName
,
6467 DWORD dwDesiredAccess
,
6468 DWORD dwServiceType
,
6470 DWORD dwErrorControl
,
6471 LPSTR lpBinaryPathName
,
6472 LPSTR lpLoadOrderGroup
,
6474 LPBYTE lpDependencies
,
6476 LPSTR lpServiceStartName
,
6479 LPSC_RPC_HANDLE lpServiceHandle
)
6482 return ERROR_CALL_NOT_IMPLEMENTED
;
6489 RCreateServiceWOW64W(
6490 handle_t BindingHandle
,
6491 LPWSTR lpServiceName
,
6492 LPWSTR lpDisplayName
,
6493 DWORD dwDesiredAccess
,
6494 DWORD dwServiceType
,
6496 DWORD dwErrorControl
,
6497 LPWSTR lpBinaryPathName
,
6498 LPWSTR lpLoadOrderGroup
,
6500 LPBYTE lpDependencies
,
6502 LPWSTR lpServiceStartName
,
6505 LPSC_RPC_HANDLE lpServiceHandle
)
6508 return ERROR_CALL_NOT_IMPLEMENTED
;
6515 RQueryServiceTagInfo(
6516 handle_t BindingHandle
) /* FIXME */
6519 return ERROR_CALL_NOT_IMPLEMENTED
;
6526 RNotifyServiceStatusChange(
6527 SC_RPC_HANDLE hService
,
6528 SC_RPC_NOTIFY_PARAMS NotifyParams
,
6529 GUID
*pClientProcessGuid
,
6530 GUID
*pSCMProcessGuid
,
6531 PBOOL pfCreateRemoteQueue
,
6532 LPSC_NOTIFY_RPC_HANDLE phNotify
)
6535 return ERROR_CALL_NOT_IMPLEMENTED
;
6543 SC_NOTIFY_RPC_HANDLE hNotify
,
6544 PSC_RPC_NOTIFY_PARAMS_LIST
*ppNotifyParams
)
6547 return ERROR_CALL_NOT_IMPLEMENTED
;
6555 LPSC_NOTIFY_RPC_HANDLE phNotify
,
6559 return ERROR_CALL_NOT_IMPLEMENTED
;
6567 SC_RPC_HANDLE hService
,
6572 return ERROR_CALL_NOT_IMPLEMENTED
;
6580 SC_RPC_HANDLE hService
,
6585 return ERROR_CALL_NOT_IMPLEMENTED
;
6593 handle_t BindingHandle
) /* FIXME */
6596 return ERROR_CALL_NOT_IMPLEMENTED
;
6603 RValidatePnPService(
6604 handle_t BindingHandle
) /* FIXME */
6607 return ERROR_CALL_NOT_IMPLEMENTED
;
6614 ROpenServiceStatusHandle(
6615 handle_t BindingHandle
) /* FIXME */
6618 return ERROR_CALL_NOT_IMPLEMENTED
;
6626 handle_t BindingHandle
) /* FIXME */
6629 return ERROR_CALL_NOT_IMPLEMENTED
;
6633 void __RPC_FAR
* __RPC_USER
midl_user_allocate(SIZE_T len
)
6635 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
);
6639 void __RPC_USER
midl_user_free(void __RPC_FAR
* ptr
)
6641 HeapFree(GetProcessHeap(), 0, ptr
);
6645 void __RPC_USER
SC_RPC_HANDLE_rundown(SC_RPC_HANDLE hSCObject
)
6647 /* Close the handle */
6648 RCloseServiceHandle(&hSCObject
);
6652 void __RPC_USER
SC_RPC_LOCK_rundown(SC_RPC_LOCK Lock
)
6654 /* Unlock the database */
6655 RUnlockServiceDatabase(&Lock
);
6659 void __RPC_USER
SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE hNotify
)