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
,
101 /* FUNCTIONS ***************************************************************/
104 ScmStartRpcServer(VOID
)
108 DPRINT("ScmStartRpcServer() called\n");
110 Status
= RpcServerUseProtseqEpW(L
"ncacn_np",
114 if (Status
!= RPC_S_OK
)
116 DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status
);
120 Status
= RpcServerRegisterIf(svcctl_v2_0_s_ifspec
,
123 if (Status
!= RPC_S_OK
)
125 DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status
);
129 Status
= RpcServerListen(1, 20, TRUE
);
130 if (Status
!= RPC_S_OK
)
132 DPRINT1("RpcServerListen() failed (Status %lx)\n", Status
);
136 DPRINT("ScmStartRpcServer() done\n");
141 ScmCreateManagerHandle(LPWSTR lpDatabaseName
,
146 if (lpDatabaseName
== NULL
)
147 lpDatabaseName
= SERVICES_ACTIVE_DATABASEW
;
149 if (_wcsicmp(lpDatabaseName
, SERVICES_FAILED_DATABASEW
) == 0)
151 DPRINT("Database %S, does not exist\n", lpDatabaseName
);
152 return ERROR_DATABASE_DOES_NOT_EXIST
;
154 else if (_wcsicmp(lpDatabaseName
, SERVICES_ACTIVE_DATABASEW
) != 0)
156 DPRINT("Invalid Database name %S.\n", lpDatabaseName
);
157 return ERROR_INVALID_NAME
;
160 Ptr
= HeapAlloc(GetProcessHeap(),
162 FIELD_OFFSET(MANAGER_HANDLE
, DatabaseName
[wcslen(lpDatabaseName
) + 1]));
164 return ERROR_NOT_ENOUGH_MEMORY
;
166 Ptr
->Handle
.Tag
= MANAGER_TAG
;
168 wcscpy(Ptr
->DatabaseName
, lpDatabaseName
);
170 *Handle
= (SC_HANDLE
)Ptr
;
172 return ERROR_SUCCESS
;
177 ScmCreateServiceHandle(PSERVICE lpServiceEntry
,
182 Ptr
= HeapAlloc(GetProcessHeap(),
184 sizeof(SERVICE_HANDLE
));
186 return ERROR_NOT_ENOUGH_MEMORY
;
188 Ptr
->Handle
.Tag
= SERVICE_TAG
;
190 Ptr
->ServiceEntry
= lpServiceEntry
;
192 *Handle
= (SC_HANDLE
)Ptr
;
194 return ERROR_SUCCESS
;
198 static PMANAGER_HANDLE
199 ScmGetServiceManagerFromHandle(SC_RPC_HANDLE Handle
)
201 PMANAGER_HANDLE pManager
= NULL
;
205 if (((PMANAGER_HANDLE
)Handle
)->Handle
.Tag
== MANAGER_TAG
)
206 pManager
= (PMANAGER_HANDLE
)Handle
;
208 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
210 DPRINT1("Exception: Invalid Service Manager handle!\n");
218 static PSERVICE_HANDLE
219 ScmGetServiceFromHandle(SC_RPC_HANDLE Handle
)
221 PSERVICE_HANDLE pService
= NULL
;
225 if (((PSERVICE_HANDLE
)Handle
)->Handle
.Tag
== SERVICE_TAG
)
226 pService
= (PSERVICE_HANDLE
)Handle
;
228 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
230 DPRINT1("Exception: Invalid Service handle!\n");
239 ScmCheckAccess(SC_HANDLE Handle
,
240 DWORD dwDesiredAccess
)
242 PMANAGER_HANDLE hMgr
;
244 hMgr
= (PMANAGER_HANDLE
)Handle
;
245 if (hMgr
->Handle
.Tag
== MANAGER_TAG
)
247 RtlMapGenericMask(&dwDesiredAccess
,
250 hMgr
->Handle
.DesiredAccess
= dwDesiredAccess
;
252 return ERROR_SUCCESS
;
254 else if (hMgr
->Handle
.Tag
== SERVICE_TAG
)
256 RtlMapGenericMask(&dwDesiredAccess
,
259 hMgr
->Handle
.DesiredAccess
= dwDesiredAccess
;
261 return ERROR_SUCCESS
;
264 return ERROR_INVALID_HANDLE
;
269 ScmAssignNewTag(PSERVICE lpService
)
273 DWORD dwGroupTagCount
= 0;
274 PDWORD pdwGroupTags
= NULL
;
276 DWORD dwTagUsedBase
= 1;
277 BOOLEAN TagUsed
[TAG_ARRAY_SIZE
];
281 PLIST_ENTRY ServiceEntry
;
282 PSERVICE CurrentService
;
284 ASSERT(lpService
!= NULL
);
285 ASSERT(lpService
->lpGroup
!= NULL
);
287 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
288 L
"System\\CurrentControlSet\\Control\\GroupOrderList",
293 if (dwError
!= ERROR_SUCCESS
)
296 /* query value length */
298 dwError
= RegQueryValueExW(hKey
,
299 lpService
->lpGroup
->szGroupName
,
305 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_MORE_DATA
)
308 pdwGroupTags
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, cbDataSize
);
311 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
315 dwError
= RegQueryValueExW(hKey
,
316 lpService
->lpGroup
->szGroupName
,
319 (LPBYTE
)pdwGroupTags
,
322 if (dwError
!= ERROR_SUCCESS
)
325 if (cbDataSize
< sizeof(pdwGroupTags
[0]))
328 dwGroupTagCount
= min(pdwGroupTags
[0], cbDataSize
/ sizeof(pdwGroupTags
[0]) - 1);
333 /* mark all tags as unused */
334 for (i
= 0; i
< TAG_ARRAY_SIZE
; i
++)
337 /* mark tags in GroupOrderList as used */
338 for (i
= 1; i
<= dwGroupTagCount
; i
++)
340 nTagOffset
= pdwGroupTags
[i
] - dwTagUsedBase
;
341 if (nTagOffset
>= 0 && nTagOffset
< TAG_ARRAY_SIZE
)
342 TagUsed
[nTagOffset
] = TRUE
;
345 /* mark tags in service list as used */
346 ServiceEntry
= lpService
->ServiceListEntry
.Flink
;
347 while (ServiceEntry
!= &lpService
->ServiceListEntry
)
349 ASSERT(ServiceEntry
!= NULL
);
350 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
351 if (CurrentService
->lpGroup
== lpService
->lpGroup
)
353 nTagOffset
= CurrentService
->dwTag
- dwTagUsedBase
;
354 if (nTagOffset
>= 0 && nTagOffset
< TAG_ARRAY_SIZE
)
355 TagUsed
[nTagOffset
] = TRUE
;
358 ServiceEntry
= ServiceEntry
->Flink
;
361 /* find unused tag, if any */
362 for (i
= 0; i
< TAG_ARRAY_SIZE
; i
++)
366 dwFreeTag
= dwTagUsedBase
+ i
;
371 dwTagUsedBase
+= TAG_ARRAY_SIZE
;
372 } while (!dwFreeTag
);
376 HeapFree(GetProcessHeap(), 0, pdwGroupTags
);
383 lpService
->dwTag
= dwFreeTag
;
384 DPRINT("Assigning new tag %lu to service %S in group %S\n",
385 lpService
->dwTag
, lpService
->lpServiceName
, lpService
->lpGroup
->szGroupName
);
386 dwError
= ERROR_SUCCESS
;
390 DPRINT1("Failed to assign new tag to service %S, error=%lu\n",
391 lpService
->lpServiceName
, dwError
);
398 /* Create a path suitable for the bootloader out of the full path */
400 ScmConvertToBootPathName(wchar_t *CanonName
, wchar_t **RelativeName
)
402 SIZE_T ServiceNameLen
, ExpandedLen
;
406 UNICODE_STRING NtPathName
, SystemRoot
, LinkTarget
;
407 OBJECT_ATTRIBUTES ObjectAttributes
;
409 HANDLE SymbolicLinkHandle
;
411 DPRINT("ScmConvertToBootPathName %S\n", CanonName
);
414 return ERROR_INVALID_PARAMETER
;
416 *RelativeName
= NULL
;
418 ServiceNameLen
= wcslen(CanonName
);
420 /* First check, if it's already good */
421 if (ServiceNameLen
> 12 &&
422 !_wcsnicmp(L
"\\SystemRoot\\", CanonName
, 12))
424 *RelativeName
= HeapAlloc(GetProcessHeap(),
426 (ServiceNameLen
+ 1) * sizeof(WCHAR
));
427 if (*RelativeName
== NULL
)
429 DPRINT("Error allocating memory for boot driver name!\n");
430 return ERROR_NOT_ENOUGH_MEMORY
;
434 wcscpy(*RelativeName
, CanonName
);
436 DPRINT("Bootdriver name %S\n", *RelativeName
);
437 return ERROR_SUCCESS
;
440 /* If it has %SystemRoot% prefix, substitute it to \System*/
441 if (ServiceNameLen
> 13 &&
442 !_wcsnicmp(L
"%SystemRoot%\\", CanonName
, 13))
444 /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */
445 *RelativeName
= HeapAlloc(GetProcessHeap(),
447 ServiceNameLen
* sizeof(WCHAR
));
449 if (*RelativeName
== NULL
)
451 DPRINT("Error allocating memory for boot driver name!\n");
452 return ERROR_NOT_ENOUGH_MEMORY
;
456 wcscpy(*RelativeName
, L
"\\SystemRoot\\");
457 wcscat(*RelativeName
, CanonName
+ 13);
459 DPRINT("Bootdriver name %S\n", *RelativeName
);
460 return ERROR_SUCCESS
;
463 /* Get buffer size needed for expanding env strings */
464 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
))
1499 return ERROR_INVALID_PARAMETER
;
1501 if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR
)lpSecurityDescriptor
))
1502 return ERROR_INVALID_PARAMETER
;
1504 if (dwSecurityInformation
& SACL_SECURITY_INFORMATION
)
1505 DesiredAccess
|= ACCESS_SYSTEM_SECURITY
;
1507 if (dwSecurityInformation
& DACL_SECURITY_INFORMATION
)
1508 DesiredAccess
|= WRITE_DAC
;
1510 if (dwSecurityInformation
& (OWNER_SECURITY_INFORMATION
| GROUP_SECURITY_INFORMATION
))
1511 DesiredAccess
|= WRITE_OWNER
;
1513 if ((dwSecurityInformation
& OWNER_SECURITY_INFORMATION
) &&
1514 (((PISECURITY_DESCRIPTOR
)lpSecurityDescriptor
)->Owner
== NULL
))
1515 return ERROR_INVALID_PARAMETER
;
1517 if ((dwSecurityInformation
& GROUP_SECURITY_INFORMATION
) &&
1518 (((PISECURITY_DESCRIPTOR
)lpSecurityDescriptor
)->Group
== NULL
))
1519 return ERROR_INVALID_PARAMETER
;
1521 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1524 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1525 return ERROR_ACCESS_DENIED
;
1528 lpService
= hSvc
->ServiceEntry
;
1529 if (lpService
== NULL
)
1531 DPRINT1("lpService == NULL!\n");
1532 return ERROR_INVALID_HANDLE
;
1535 if (lpService
->bDeleted
)
1536 return ERROR_SERVICE_MARKED_FOR_DELETE
;
1539 RpcImpersonateClient(NULL
);
1541 Status
= NtOpenThreadToken(NtCurrentThread(),
1545 if (!NT_SUCCESS(Status
))
1546 return RtlNtStatusToDosError(Status
);
1551 /* Build the new security descriptor */
1552 Status
= RtlSetSecurityObject(dwSecurityInformation
,
1553 (PSECURITY_DESCRIPTOR
)lpSecurityDescriptor
,
1554 &lpService
->pSecurityDescriptor
,
1557 if (!NT_SUCCESS(Status
))
1559 dwError
= RtlNtStatusToDosError(Status
);
1563 /* Lock the service database exclusive */
1564 ScmLockDatabaseExclusive();
1565 bDatabaseLocked
= TRUE
;
1567 /* Open the service key */
1568 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
1569 READ_CONTROL
| KEY_CREATE_SUB_KEY
| KEY_SET_VALUE
,
1571 if (dwError
!= ERROR_SUCCESS
)
1574 /* Store the new security descriptor */
1575 dwError
= ScmWriteSecurityDescriptor(hServiceKey
,
1576 lpService
->pSecurityDescriptor
);
1578 RegFlushKey(hServiceKey
);
1581 if (hServiceKey
!= NULL
)
1582 RegCloseKey(hServiceKey
);
1584 /* Unlock service database */
1585 if (bDatabaseLocked
== TRUE
)
1586 ScmUnlockDatabase();
1591 DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError
);
1600 RQueryServiceStatus(
1601 SC_RPC_HANDLE hService
,
1602 LPSERVICE_STATUS lpServiceStatus
)
1604 PSERVICE_HANDLE hSvc
;
1607 DPRINT("RQueryServiceStatus() called\n");
1610 return ERROR_SHUTDOWN_IN_PROGRESS
;
1612 hSvc
= ScmGetServiceFromHandle(hService
);
1615 DPRINT1("Invalid service handle!\n");
1616 return ERROR_INVALID_HANDLE
;
1619 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1620 SERVICE_QUERY_STATUS
))
1622 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1623 return ERROR_ACCESS_DENIED
;
1626 lpService
= hSvc
->ServiceEntry
;
1627 if (lpService
== NULL
)
1629 DPRINT("lpService == NULL!\n");
1630 return ERROR_INVALID_HANDLE
;
1633 /* Lock the service database shared */
1634 ScmLockDatabaseShared();
1636 /* Return service status information */
1637 RtlCopyMemory(lpServiceStatus
,
1639 sizeof(SERVICE_STATUS
));
1641 /* Unlock the service database */
1642 ScmUnlockDatabase();
1644 return ERROR_SUCCESS
;
1649 ScmIsValidServiceState(DWORD dwCurrentState
)
1651 switch (dwCurrentState
)
1653 case SERVICE_STOPPED
:
1654 case SERVICE_START_PENDING
:
1655 case SERVICE_STOP_PENDING
:
1656 case SERVICE_RUNNING
:
1657 case SERVICE_CONTINUE_PENDING
:
1658 case SERVICE_PAUSE_PENDING
:
1659 case SERVICE_PAUSED
:
1672 RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
1673 LPSERVICE_STATUS lpServiceStatus
)
1676 DWORD dwPreviousState
;
1677 DWORD dwPreviousType
;
1678 LPCWSTR lpLogStrings
[2];
1679 WCHAR szLogBuffer
[80];
1682 DPRINT("RSetServiceStatus() called\n");
1683 DPRINT("hServiceStatus = %lu\n", hServiceStatus
);
1684 DPRINT("dwServiceType = 0x%lx\n", lpServiceStatus
->dwServiceType
);
1685 DPRINT("dwCurrentState = %lu\n", lpServiceStatus
->dwCurrentState
);
1686 DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus
->dwControlsAccepted
);
1687 DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus
->dwWin32ExitCode
);
1688 DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus
->dwServiceSpecificExitCode
);
1689 DPRINT("dwCheckPoint = %lu\n", lpServiceStatus
->dwCheckPoint
);
1690 DPRINT("dwWaitHint = %lu\n", lpServiceStatus
->dwWaitHint
);
1692 if (hServiceStatus
== 0)
1694 DPRINT("hServiceStatus == NULL!\n");
1695 return ERROR_INVALID_HANDLE
;
1698 lpService
= (PSERVICE
)hServiceStatus
;
1700 /* Check current state */
1701 if (!ScmIsValidServiceState(lpServiceStatus
->dwCurrentState
))
1703 DPRINT("Invalid service state!\n");
1704 return ERROR_INVALID_DATA
;
1707 /* Check service type */
1708 if (!(lpServiceStatus
->dwServiceType
& SERVICE_WIN32
) &&
1709 (lpServiceStatus
->dwServiceType
& SERVICE_DRIVER
))
1711 DPRINT("Invalid service type!\n");
1712 return ERROR_INVALID_DATA
;
1715 /* Check accepted controls */
1716 if (lpServiceStatus
->dwControlsAccepted
& ~0xFF)
1718 DPRINT("Invalid controls accepted!\n");
1719 return ERROR_INVALID_DATA
;
1722 /* Set the wait hint and check point only if the service is in a pending state,
1723 otherwise they should be 0 */
1724 if (lpServiceStatus
->dwCurrentState
== SERVICE_STOPPED
||
1725 lpServiceStatus
->dwCurrentState
== SERVICE_PAUSED
||
1726 lpServiceStatus
->dwCurrentState
== SERVICE_RUNNING
)
1728 lpServiceStatus
->dwWaitHint
= 0;
1729 lpServiceStatus
->dwCheckPoint
= 0;
1732 /* Lock the service database exclusively */
1733 ScmLockDatabaseExclusive();
1735 /* Save the current service state */
1736 dwPreviousState
= lpService
->Status
.dwCurrentState
;
1738 /* Save the current service type */
1739 dwPreviousType
= lpService
->Status
.dwServiceType
;
1741 /* Update the service status */
1742 RtlCopyMemory(&lpService
->Status
,
1744 sizeof(SERVICE_STATUS
));
1746 /* Restore the previous service type */
1747 lpService
->Status
.dwServiceType
= dwPreviousType
;
1749 /* Dereference a stopped service */
1750 if ((lpServiceStatus
->dwServiceType
& SERVICE_WIN32
) &&
1751 (lpServiceStatus
->dwCurrentState
== SERVICE_STOPPED
))
1753 /* Decrement the image run counter */
1754 lpService
->lpImage
->dwImageRunCount
--;
1756 /* If we just stopped the last running service... */
1757 if (lpService
->lpImage
->dwImageRunCount
== 0)
1759 /* Stop the dispatcher thread */
1760 ScmControlService(lpService
->lpImage
->hControlPipe
,
1762 (SERVICE_STATUS_HANDLE
)lpService
,
1763 SERVICE_CONTROL_STOP
);
1765 /* Remove the service image */
1766 ScmRemoveServiceImage(lpService
->lpImage
);
1767 lpService
->lpImage
= NULL
;
1771 /* Unlock the service database */
1772 ScmUnlockDatabase();
1774 if ((lpServiceStatus
->dwCurrentState
== SERVICE_STOPPED
) &&
1775 (dwPreviousState
!= SERVICE_STOPPED
) &&
1776 (lpServiceStatus
->dwWin32ExitCode
!= ERROR_SUCCESS
))
1778 /* Log a failed service stop */
1779 StringCchPrintfW(szLogBuffer
, ARRAYSIZE(szLogBuffer
),
1780 L
"%lu", lpServiceStatus
->dwWin32ExitCode
);
1781 lpLogStrings
[0] = lpService
->lpDisplayName
;
1782 lpLogStrings
[1] = szLogBuffer
;
1784 ScmLogEvent(EVENT_SERVICE_EXIT_FAILED
,
1785 EVENTLOG_ERROR_TYPE
,
1789 else if (lpServiceStatus
->dwCurrentState
!= dwPreviousState
&&
1790 (lpServiceStatus
->dwCurrentState
== SERVICE_STOPPED
||
1791 lpServiceStatus
->dwCurrentState
== SERVICE_RUNNING
||
1792 lpServiceStatus
->dwCurrentState
== SERVICE_PAUSED
))
1794 /* Log a successful service status change */
1795 switch(lpServiceStatus
->dwCurrentState
)
1797 case SERVICE_STOPPED
:
1798 uID
= IDS_SERVICE_STOPPED
;
1801 case SERVICE_RUNNING
:
1802 uID
= IDS_SERVICE_RUNNING
;
1805 case SERVICE_PAUSED
:
1806 uID
= IDS_SERVICE_PAUSED
;
1810 LoadStringW(GetModuleHandle(NULL
), uID
, szLogBuffer
, ARRAYSIZE(szLogBuffer
));
1811 lpLogStrings
[0] = lpService
->lpDisplayName
;
1812 lpLogStrings
[1] = szLogBuffer
;
1814 ScmLogEvent(EVENT_SERVICE_STATUS_SUCCESS
,
1815 EVENTLOG_INFORMATION_TYPE
,
1820 DPRINT("Set %S to %lu\n", lpService
->lpDisplayName
, lpService
->Status
.dwCurrentState
);
1821 DPRINT("RSetServiceStatus() done\n");
1823 return ERROR_SUCCESS
;
1830 RUnlockServiceDatabase(
1833 DPRINT("RUnlockServiceDatabase(%p)\n", Lock
);
1834 return ScmReleaseServiceStartLock(Lock
);
1841 RNotifyBootConfigStatus(
1842 SVCCTL_HANDLEW lpMachineName
,
1843 DWORD BootAcceptable
)
1845 DPRINT1("RNotifyBootConfigStatus(%p %lu) called\n", lpMachineName
, BootAcceptable
);
1846 return ERROR_SUCCESS
;
1849 // return ERROR_CALL_NOT_IMPLEMENTED;
1856 RI_ScSetServiceBitsW(
1857 RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
1858 DWORD dwServiceBits
,
1860 int bUpdateImmediately
,
1864 return ERROR_CALL_NOT_IMPLEMENTED
;
1871 RChangeServiceConfigW(
1872 SC_RPC_HANDLE hService
,
1873 DWORD dwServiceType
,
1875 DWORD dwErrorControl
,
1876 LPWSTR lpBinaryPathName
,
1877 LPWSTR lpLoadOrderGroup
,
1879 LPBYTE lpDependencies
,
1881 LPWSTR lpServiceStartName
,
1884 LPWSTR lpDisplayName
)
1886 DWORD dwError
= ERROR_SUCCESS
;
1887 PSERVICE_HANDLE hSvc
;
1888 PSERVICE lpService
= NULL
;
1889 HKEY hServiceKey
= NULL
;
1890 LPWSTR lpDisplayNameW
= NULL
;
1891 LPWSTR lpImagePathW
= NULL
;
1893 DPRINT("RChangeServiceConfigW() called\n");
1894 DPRINT("dwServiceType = 0x%lx\n", dwServiceType
);
1895 DPRINT("dwStartType = %lu\n", dwStartType
);
1896 DPRINT("dwErrorControl = %lu\n", dwErrorControl
);
1897 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName
);
1898 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup
);
1899 DPRINT("lpDisplayName = %S\n", lpDisplayName
);
1902 return ERROR_SHUTDOWN_IN_PROGRESS
;
1904 hSvc
= ScmGetServiceFromHandle(hService
);
1907 DPRINT1("Invalid service handle!\n");
1908 return ERROR_INVALID_HANDLE
;
1911 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1912 SERVICE_CHANGE_CONFIG
))
1914 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1915 return ERROR_ACCESS_DENIED
;
1918 /* Check for invalid service type value */
1919 if ((dwServiceType
!= SERVICE_NO_CHANGE
) &&
1920 (dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
1921 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
) &&
1922 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
1923 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
))
1924 return ERROR_INVALID_PARAMETER
;
1926 /* Check for invalid start type value */
1927 if ((dwStartType
!= SERVICE_NO_CHANGE
) &&
1928 (dwStartType
!= SERVICE_BOOT_START
) &&
1929 (dwStartType
!= SERVICE_SYSTEM_START
) &&
1930 (dwStartType
!= SERVICE_AUTO_START
) &&
1931 (dwStartType
!= SERVICE_DEMAND_START
) &&
1932 (dwStartType
!= SERVICE_DISABLED
))
1933 return ERROR_INVALID_PARAMETER
;
1935 /* Only drivers can be boot start or system start services */
1936 if ((dwStartType
== SERVICE_BOOT_START
) ||
1937 (dwStartType
== SERVICE_SYSTEM_START
))
1939 if ((dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
1940 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
1941 return ERROR_INVALID_PARAMETER
;
1944 /* Check for invalid error control value */
1945 if ((dwErrorControl
!= SERVICE_NO_CHANGE
) &&
1946 (dwErrorControl
!= SERVICE_ERROR_IGNORE
) &&
1947 (dwErrorControl
!= SERVICE_ERROR_NORMAL
) &&
1948 (dwErrorControl
!= SERVICE_ERROR_SEVERE
) &&
1949 (dwErrorControl
!= SERVICE_ERROR_CRITICAL
))
1950 return ERROR_INVALID_PARAMETER
;
1952 lpService
= hSvc
->ServiceEntry
;
1953 if (lpService
== NULL
)
1955 DPRINT("lpService == NULL!\n");
1956 return ERROR_INVALID_HANDLE
;
1959 /* Lock the service database exclusively */
1960 ScmLockDatabaseExclusive();
1962 if (lpService
->bDeleted
)
1964 DPRINT("The service has already been marked for delete!\n");
1965 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
1969 /* Open the service key */
1970 dwError
= ScmOpenServiceKey(lpService
->szServiceName
,
1973 if (dwError
!= ERROR_SUCCESS
)
1976 /* Write service data to the registry */
1977 /* Set the display name */
1978 if (lpDisplayName
!= NULL
&& *lpDisplayName
!= 0)
1980 RegSetValueExW(hServiceKey
,
1984 (LPBYTE
)lpDisplayName
,
1985 (DWORD
)((wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
)));
1987 /* Update the display name */
1988 lpDisplayNameW
= HeapAlloc(GetProcessHeap(),
1990 (wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
));
1991 if (lpDisplayNameW
== NULL
)
1993 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
1997 wcscpy(lpDisplayNameW
, lpDisplayName
);
1998 if (lpService
->lpDisplayName
!= lpService
->lpServiceName
)
1999 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
2001 lpService
->lpDisplayName
= lpDisplayNameW
;
2004 if (dwServiceType
!= SERVICE_NO_CHANGE
)
2006 /* Set the service type */
2007 dwError
= RegSetValueExW(hServiceKey
,
2011 (LPBYTE
)&dwServiceType
,
2013 if (dwError
!= ERROR_SUCCESS
)
2016 lpService
->Status
.dwServiceType
= dwServiceType
;
2019 if (dwStartType
!= SERVICE_NO_CHANGE
)
2021 /* Set the start value */
2022 dwError
= RegSetValueExW(hServiceKey
,
2026 (LPBYTE
)&dwStartType
,
2028 if (dwError
!= ERROR_SUCCESS
)
2031 lpService
->dwStartType
= dwStartType
;
2034 if (dwErrorControl
!= SERVICE_NO_CHANGE
)
2036 /* Set the error control value */
2037 dwError
= RegSetValueExW(hServiceKey
,
2041 (LPBYTE
)&dwErrorControl
,
2043 if (dwError
!= ERROR_SUCCESS
)
2046 lpService
->dwErrorControl
= dwErrorControl
;
2049 if (lpBinaryPathName
!= NULL
&& *lpBinaryPathName
!= 0)
2051 /* Set the image path */
2052 lpImagePathW
= lpBinaryPathName
;
2054 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
2056 dwError
= ScmCanonDriverImagePath(lpService
->dwStartType
,
2060 if (dwError
!= ERROR_SUCCESS
)
2064 dwError
= RegSetValueExW(hServiceKey
,
2068 (LPBYTE
)lpImagePathW
,
2069 (DWORD
)((wcslen(lpImagePathW
) + 1) * sizeof(WCHAR
)));
2071 if (lpImagePathW
!= lpBinaryPathName
)
2072 HeapFree(GetProcessHeap(), 0, lpImagePathW
);
2074 if (dwError
!= ERROR_SUCCESS
)
2078 /* Set the group name */
2079 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
2081 dwError
= RegSetValueExW(hServiceKey
,
2085 (LPBYTE
)lpLoadOrderGroup
,
2086 (DWORD
)((wcslen(lpLoadOrderGroup
) + 1) * sizeof(WCHAR
)));
2087 if (dwError
!= ERROR_SUCCESS
)
2090 dwError
= ScmSetServiceGroup(lpService
,
2092 if (dwError
!= ERROR_SUCCESS
)
2097 if (lpdwTagId
!= NULL
)
2099 dwError
= ScmAssignNewTag(lpService
);
2100 if (dwError
!= ERROR_SUCCESS
)
2103 dwError
= RegSetValueExW(hServiceKey
,
2107 (LPBYTE
)&lpService
->dwTag
,
2109 if (dwError
!= ERROR_SUCCESS
)
2112 *lpdwTagId
= lpService
->dwTag
;
2115 /* Write dependencies */
2116 if (lpDependencies
!= NULL
&& *lpDependencies
!= 0)
2118 dwError
= ScmWriteDependencies(hServiceKey
,
2119 (LPWSTR
)lpDependencies
,
2121 if (dwError
!= ERROR_SUCCESS
)
2125 if (lpPassword
!= NULL
)
2127 if (wcslen((LPWSTR
)lpPassword
) != 0)
2129 /* FIXME: Decrypt the password */
2131 /* Write the password */
2132 dwError
= ScmSetServicePassword(lpService
->szServiceName
,
2133 (LPCWSTR
)lpPassword
);
2134 if (dwError
!= ERROR_SUCCESS
)
2139 /* Delete the password */
2140 dwError
= ScmSetServicePassword(lpService
->szServiceName
,
2142 if (dwError
== ERROR_FILE_NOT_FOUND
)
2143 dwError
= ERROR_SUCCESS
;
2145 if (dwError
!= ERROR_SUCCESS
)
2151 if (hServiceKey
!= NULL
)
2152 RegCloseKey(hServiceKey
);
2154 /* Unlock the service database */
2155 ScmUnlockDatabase();
2157 DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError
);
2167 SC_RPC_HANDLE hSCManager
,
2168 LPCWSTR lpServiceName
,
2169 LPCWSTR lpDisplayName
,
2170 DWORD dwDesiredAccess
,
2171 DWORD dwServiceType
,
2173 DWORD dwErrorControl
,
2174 LPCWSTR lpBinaryPathName
,
2175 LPCWSTR lpLoadOrderGroup
,
2177 LPBYTE lpDependencies
,
2179 LPCWSTR lpServiceStartName
,
2182 LPSC_RPC_HANDLE lpServiceHandle
)
2184 PMANAGER_HANDLE hManager
;
2185 DWORD dwError
= ERROR_SUCCESS
;
2186 PSERVICE lpService
= NULL
;
2187 SC_HANDLE hServiceHandle
= NULL
;
2188 LPWSTR lpImagePath
= NULL
;
2189 HKEY hServiceKey
= NULL
;
2190 LPWSTR lpObjectName
;
2192 DPRINT("RCreateServiceW() called\n");
2193 DPRINT("lpServiceName = %S\n", lpServiceName
);
2194 DPRINT("lpDisplayName = %S\n", lpDisplayName
);
2195 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess
);
2196 DPRINT("dwServiceType = 0x%lx\n", dwServiceType
);
2197 DPRINT("dwStartType = %lu\n", dwStartType
);
2198 DPRINT("dwErrorControl = %lu\n", dwErrorControl
);
2199 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName
);
2200 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup
);
2201 DPRINT("lpdwTagId = %p\n", lpdwTagId
);
2204 return ERROR_SHUTDOWN_IN_PROGRESS
;
2206 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
2207 if (hManager
== NULL
)
2209 DPRINT1("Invalid service manager handle!\n");
2210 return ERROR_INVALID_HANDLE
;
2213 /* Check access rights */
2214 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
2215 SC_MANAGER_CREATE_SERVICE
))
2217 DPRINT("Insufficient access rights! 0x%lx\n",
2218 hManager
->Handle
.DesiredAccess
);
2219 return ERROR_ACCESS_DENIED
;
2222 if (wcslen(lpServiceName
) == 0)
2224 return ERROR_INVALID_NAME
;
2227 if (wcslen(lpBinaryPathName
) == 0)
2229 return ERROR_INVALID_PARAMETER
;
2232 /* Check for invalid service type value */
2233 if ((dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
2234 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
) &&
2235 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
2236 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
))
2237 return ERROR_INVALID_PARAMETER
;
2239 /* Check for invalid start type value */
2240 if ((dwStartType
!= SERVICE_BOOT_START
) &&
2241 (dwStartType
!= SERVICE_SYSTEM_START
) &&
2242 (dwStartType
!= SERVICE_AUTO_START
) &&
2243 (dwStartType
!= SERVICE_DEMAND_START
) &&
2244 (dwStartType
!= SERVICE_DISABLED
))
2245 return ERROR_INVALID_PARAMETER
;
2247 /* Only drivers can be boot start or system start services */
2248 if ((dwStartType
== SERVICE_BOOT_START
) ||
2249 (dwStartType
== SERVICE_SYSTEM_START
))
2251 if ((dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
2252 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
2253 return ERROR_INVALID_PARAMETER
;
2256 /* Check for invalid error control value */
2257 if ((dwErrorControl
!= SERVICE_ERROR_IGNORE
) &&
2258 (dwErrorControl
!= SERVICE_ERROR_NORMAL
) &&
2259 (dwErrorControl
!= SERVICE_ERROR_SEVERE
) &&
2260 (dwErrorControl
!= SERVICE_ERROR_CRITICAL
))
2261 return ERROR_INVALID_PARAMETER
;
2263 if ((dwServiceType
== (SERVICE_WIN32_OWN_PROCESS
| SERVICE_INTERACTIVE_PROCESS
)) &&
2264 (lpServiceStartName
))
2266 /* We allow LocalSystem to run interactive. */
2267 if (wcsicmp(lpServiceStartName
, L
"LocalSystem"))
2269 return ERROR_INVALID_PARAMETER
;
2273 if (lpdwTagId
&& (!lpLoadOrderGroup
|| !*lpLoadOrderGroup
))
2275 return ERROR_INVALID_PARAMETER
;
2278 /* Lock the service database exclusively */
2279 ScmLockDatabaseExclusive();
2281 lpService
= ScmGetServiceEntryByName(lpServiceName
);
2284 /* Unlock the service database */
2285 ScmUnlockDatabase();
2287 /* Check if it is marked for deletion */
2288 if (lpService
->bDeleted
)
2289 return ERROR_SERVICE_MARKED_FOR_DELETE
;
2291 /* Return Error exist */
2292 return ERROR_SERVICE_EXISTS
;
2295 if (lpDisplayName
!= NULL
&&
2296 ScmGetServiceEntryByDisplayName(lpDisplayName
) != NULL
)
2298 /* Unlock the service database */
2299 ScmUnlockDatabase();
2301 return ERROR_DUPLICATE_SERVICE_NAME
;
2304 if (dwServiceType
& SERVICE_DRIVER
)
2306 dwError
= ScmCanonDriverImagePath(dwStartType
,
2309 if (dwError
!= ERROR_SUCCESS
)
2314 if (dwStartType
== SERVICE_BOOT_START
||
2315 dwStartType
== SERVICE_SYSTEM_START
)
2317 /* Unlock the service database */
2318 ScmUnlockDatabase();
2320 return ERROR_INVALID_PARAMETER
;
2324 /* Allocate a new service entry */
2325 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
2329 if (dwError
!= ERROR_SUCCESS
)
2332 /* Fill the new service entry */
2333 lpService
->dwErrorControl
= dwErrorControl
;
2335 /* Fill the display name */
2336 if (lpDisplayName
!= NULL
&&
2337 *lpDisplayName
!= 0 &&
2338 _wcsicmp(lpService
->lpDisplayName
, lpDisplayName
) != 0)
2340 lpService
->lpDisplayName
= HeapAlloc(GetProcessHeap(),
2342 (wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
));
2343 if (lpService
->lpDisplayName
== NULL
)
2345 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
2348 wcscpy(lpService
->lpDisplayName
, lpDisplayName
);
2351 /* Assign the service to a group */
2352 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
2354 dwError
= ScmSetServiceGroup(lpService
,
2356 if (dwError
!= ERROR_SUCCESS
)
2360 /* Assign a new tag */
2361 if (lpdwTagId
!= NULL
)
2363 dwError
= ScmAssignNewTag(lpService
);
2364 if (dwError
!= ERROR_SUCCESS
)
2368 /* Assign the default security descriptor */
2369 if (dwServiceType
& SERVICE_WIN32
)
2371 dwError
= ScmCreateDefaultServiceSD(&lpService
->pSecurityDescriptor
);
2372 if (dwError
!= ERROR_SUCCESS
)
2376 /* Write service data to the registry */
2377 /* Create the service key */
2378 dwError
= ScmCreateServiceKey(lpServiceName
,
2381 if (dwError
!= ERROR_SUCCESS
)
2384 /* Set the display name */
2385 if (lpDisplayName
!= NULL
&& *lpDisplayName
!= 0)
2387 RegSetValueExW(hServiceKey
,
2391 (LPBYTE
)lpDisplayName
,
2392 (DWORD
)((wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
)));
2395 /* Set the service type */
2396 dwError
= RegSetValueExW(hServiceKey
,
2400 (LPBYTE
)&dwServiceType
,
2402 if (dwError
!= ERROR_SUCCESS
)
2405 /* Set the start value */
2406 dwError
= RegSetValueExW(hServiceKey
,
2410 (LPBYTE
)&dwStartType
,
2412 if (dwError
!= ERROR_SUCCESS
)
2415 /* Set the error control value */
2416 dwError
= RegSetValueExW(hServiceKey
,
2420 (LPBYTE
)&dwErrorControl
,
2422 if (dwError
!= ERROR_SUCCESS
)
2425 /* Set the image path */
2426 if (dwServiceType
& SERVICE_WIN32
)
2428 dwError
= RegSetValueExW(hServiceKey
,
2432 (LPBYTE
)lpBinaryPathName
,
2433 (DWORD
)((wcslen(lpBinaryPathName
) + 1) * sizeof(WCHAR
)));
2434 if (dwError
!= ERROR_SUCCESS
)
2437 else if (dwServiceType
& SERVICE_DRIVER
)
2439 dwError
= RegSetValueExW(hServiceKey
,
2443 (LPBYTE
)lpImagePath
,
2444 (DWORD
)((wcslen(lpImagePath
) + 1) * sizeof(WCHAR
)));
2445 if (dwError
!= ERROR_SUCCESS
)
2449 /* Set the group name */
2450 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
2452 dwError
= RegSetValueExW(hServiceKey
,
2456 (LPBYTE
)lpLoadOrderGroup
,
2457 (DWORD
)((wcslen(lpLoadOrderGroup
) + 1) * sizeof(WCHAR
)));
2458 if (dwError
!= ERROR_SUCCESS
)
2462 /* Set the service tag */
2463 if (lpdwTagId
!= NULL
)
2465 dwError
= RegSetValueExW(hServiceKey
,
2469 (LPBYTE
)&lpService
->dwTag
,
2471 if (dwError
!= ERROR_SUCCESS
)
2475 /* Write dependencies */
2476 if (lpDependencies
!= NULL
&& *lpDependencies
!= 0)
2478 dwError
= ScmWriteDependencies(hServiceKey
,
2479 (LPCWSTR
)lpDependencies
,
2481 if (dwError
!= ERROR_SUCCESS
)
2485 /* Start name and password are only used by Win32 services */
2486 if (dwServiceType
& SERVICE_WIN32
)
2488 /* Write service start name */
2489 lpObjectName
= (lpServiceStartName
!= NULL
) ? (LPWSTR
)lpServiceStartName
: L
"LocalSystem";
2490 dwError
= RegSetValueExW(hServiceKey
,
2494 (LPBYTE
)lpObjectName
,
2495 (DWORD
)((wcslen(lpObjectName
) + 1) * sizeof(WCHAR
)));
2496 if (dwError
!= ERROR_SUCCESS
)
2499 if (lpPassword
!= NULL
&& wcslen((LPWSTR
)lpPassword
) != 0)
2501 /* FIXME: Decrypt the password */
2503 /* Write the password */
2504 dwError
= ScmSetServicePassword(lpServiceName
,
2505 (LPCWSTR
)lpPassword
);
2506 if (dwError
!= ERROR_SUCCESS
)
2511 /* Write the security descriptor */
2512 dwError
= ScmWriteSecurityDescriptor(hServiceKey
,
2513 lpService
->pSecurityDescriptor
);
2514 if (dwError
!= ERROR_SUCCESS
)
2518 dwError
= ScmCreateServiceHandle(lpService
,
2520 if (dwError
!= ERROR_SUCCESS
)
2523 dwError
= ScmCheckAccess(hServiceHandle
,
2525 if (dwError
!= ERROR_SUCCESS
)
2528 lpService
->dwRefCount
= 1;
2529 DPRINT("CreateService - lpService->dwRefCount %u\n", lpService
->dwRefCount
);
2532 /* Unlock the service database */
2533 ScmUnlockDatabase();
2535 if (hServiceKey
!= NULL
)
2536 RegCloseKey(hServiceKey
);
2538 if (dwError
== ERROR_SUCCESS
)
2540 DPRINT("hService %p\n", hServiceHandle
);
2541 *lpServiceHandle
= (SC_RPC_HANDLE
)hServiceHandle
;
2543 if (lpdwTagId
!= NULL
)
2544 *lpdwTagId
= lpService
->dwTag
;
2548 if (lpService
!= NULL
&&
2549 lpService
->lpServiceName
!= NULL
)
2551 /* Release the display name buffer */
2552 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
2557 /* Remove the service handle */
2558 HeapFree(GetProcessHeap(), 0, hServiceHandle
);
2561 if (lpService
!= NULL
)
2563 /* FIXME: remove the service entry */
2567 if (lpImagePath
!= NULL
)
2568 HeapFree(GetProcessHeap(), 0, lpImagePath
);
2570 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError
);
2579 REnumDependentServicesW(
2580 SC_RPC_HANDLE hService
,
2581 DWORD dwServiceState
,
2584 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
2585 LPBOUNDED_DWORD_256K lpServicesReturned
)
2587 DWORD dwError
= ERROR_SUCCESS
;
2588 DWORD dwServicesReturned
= 0;
2589 DWORD dwServiceCount
;
2590 HKEY hServicesKey
= NULL
;
2591 PSERVICE_HANDLE hSvc
;
2592 PSERVICE lpService
= NULL
;
2593 PSERVICE
*lpServicesArray
= NULL
;
2594 LPENUM_SERVICE_STATUSW lpServicesPtr
= NULL
;
2597 *pcbBytesNeeded
= 0;
2598 *lpServicesReturned
= 0;
2600 DPRINT("REnumDependentServicesW() called\n");
2602 hSvc
= ScmGetServiceFromHandle(hService
);
2605 DPRINT1("Invalid service handle!\n");
2606 return ERROR_INVALID_HANDLE
;
2609 lpService
= hSvc
->ServiceEntry
;
2611 /* Check access rights */
2612 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
2613 SC_MANAGER_ENUMERATE_SERVICE
))
2615 DPRINT("Insufficient access rights! 0x%lx\n",
2616 hSvc
->Handle
.DesiredAccess
);
2617 return ERROR_ACCESS_DENIED
;
2620 /* Open the Services Reg key */
2621 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2622 L
"System\\CurrentControlSet\\Services",
2626 if (dwError
!= ERROR_SUCCESS
)
2629 /* First determine the bytes needed and get the number of dependent services */
2630 dwError
= Int_EnumDependentServicesW(hServicesKey
,
2635 &dwServicesReturned
);
2636 if (dwError
!= ERROR_SUCCESS
)
2639 /* If buffer size is less than the bytes needed or pointer is null */
2640 if ((!lpServices
) || (cbBufSize
< *pcbBytesNeeded
))
2642 dwError
= ERROR_MORE_DATA
;
2646 /* Allocate memory for array of service pointers */
2647 lpServicesArray
= HeapAlloc(GetProcessHeap(),
2649 (dwServicesReturned
+ 1) * sizeof(PSERVICE
));
2650 if (!lpServicesArray
)
2652 DPRINT1("Could not allocate a buffer!!\n");
2653 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
2657 dwServicesReturned
= 0;
2658 *pcbBytesNeeded
= 0;
2660 dwError
= Int_EnumDependentServicesW(hServicesKey
,
2665 &dwServicesReturned
);
2666 if (dwError
!= ERROR_SUCCESS
)
2671 lpServicesPtr
= (LPENUM_SERVICE_STATUSW
)lpServices
;
2672 lpStr
= (LPWSTR
)(lpServices
+ (dwServicesReturned
* sizeof(ENUM_SERVICE_STATUSW
)));
2674 /* Copy EnumDepenedentService to Buffer */
2675 for (dwServiceCount
= 0; dwServiceCount
< dwServicesReturned
; dwServiceCount
++)
2677 lpService
= lpServicesArray
[dwServiceCount
];
2679 /* Copy status info */
2680 memcpy(&lpServicesPtr
->ServiceStatus
,
2682 sizeof(SERVICE_STATUS
));
2684 /* Copy display name */
2685 wcscpy(lpStr
, lpService
->lpDisplayName
);
2686 lpServicesPtr
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
2687 lpStr
+= (wcslen(lpService
->lpDisplayName
) + 1);
2689 /* Copy service name */
2690 wcscpy(lpStr
, lpService
->lpServiceName
);
2691 lpServicesPtr
->lpServiceName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
2692 lpStr
+= (wcslen(lpService
->lpServiceName
) + 1);
2697 *lpServicesReturned
= dwServicesReturned
;
2700 if (lpServicesArray
!= NULL
)
2701 HeapFree(GetProcessHeap(), 0, lpServicesArray
);
2703 RegCloseKey(hServicesKey
);
2705 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError
);
2714 REnumServicesStatusW(
2715 SC_RPC_HANDLE hSCManager
,
2716 DWORD dwServiceType
,
2717 DWORD dwServiceState
,
2720 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
2721 LPBOUNDED_DWORD_256K lpServicesReturned
,
2722 LPBOUNDED_DWORD_256K lpResumeHandle
)
2724 /* Enumerate all the services, not regarding of their group */
2725 return REnumServiceGroupW(hSCManager
,
2741 LPWSTR lpMachineName
,
2742 LPWSTR lpDatabaseName
,
2743 DWORD dwDesiredAccess
,
2744 LPSC_RPC_HANDLE lpScHandle
)
2749 DPRINT("ROpenSCManagerW() called\n");
2750 DPRINT("lpMachineName = %p\n", lpMachineName
);
2751 DPRINT("lpMachineName: %S\n", lpMachineName
);
2752 DPRINT("lpDataBaseName = %p\n", lpDatabaseName
);
2753 DPRINT("lpDataBaseName: %S\n", lpDatabaseName
);
2754 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess
);
2757 return ERROR_SHUTDOWN_IN_PROGRESS
;
2760 return ERROR_INVALID_PARAMETER
;
2762 dwError
= ScmCreateManagerHandle(lpDatabaseName
,
2764 if (dwError
!= ERROR_SUCCESS
)
2766 DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError
);
2770 /* Check the desired access */
2771 dwError
= ScmCheckAccess(hHandle
,
2772 dwDesiredAccess
| SC_MANAGER_CONNECT
);
2773 if (dwError
!= ERROR_SUCCESS
)
2775 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError
);
2776 HeapFree(GetProcessHeap(), 0, hHandle
);
2780 *lpScHandle
= (SC_RPC_HANDLE
)hHandle
;
2781 DPRINT("*hScm = %p\n", *lpScHandle
);
2783 DPRINT("ROpenSCManagerW() done\n");
2785 return ERROR_SUCCESS
;
2793 SC_RPC_HANDLE hSCManager
,
2794 LPWSTR lpServiceName
,
2795 DWORD dwDesiredAccess
,
2796 LPSC_RPC_HANDLE lpServiceHandle
)
2799 PMANAGER_HANDLE hManager
;
2801 DWORD dwError
= ERROR_SUCCESS
;
2803 DPRINT("ROpenServiceW() called\n");
2804 DPRINT("hSCManager = %p\n", hSCManager
);
2805 DPRINT("lpServiceName = %p\n", lpServiceName
);
2806 DPRINT("lpServiceName: %S\n", lpServiceName
);
2807 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess
);
2810 return ERROR_SHUTDOWN_IN_PROGRESS
;
2812 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
2813 if (hManager
== NULL
)
2815 DPRINT1("Invalid service manager handle!\n");
2816 return ERROR_INVALID_HANDLE
;
2819 if (!lpServiceHandle
)
2820 return ERROR_INVALID_PARAMETER
;
2823 return ERROR_INVALID_ADDRESS
;
2825 /* Lock the service database exclusive */
2826 ScmLockDatabaseExclusive();
2828 /* Get service database entry */
2829 lpService
= ScmGetServiceEntryByName(lpServiceName
);
2830 if (lpService
== NULL
)
2832 DPRINT("Could not find a service!\n");
2833 dwError
= ERROR_SERVICE_DOES_NOT_EXIST
;
2837 /* Create a service handle */
2838 dwError
= ScmCreateServiceHandle(lpService
,
2840 if (dwError
!= ERROR_SUCCESS
)
2842 DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError
);
2846 /* Check the desired access */
2847 dwError
= ScmCheckAccess(hHandle
,
2849 if (dwError
!= ERROR_SUCCESS
)
2851 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError
);
2852 HeapFree(GetProcessHeap(), 0, hHandle
);
2856 lpService
->dwRefCount
++;
2857 DPRINT("OpenService - lpService->dwRefCount %u\n",lpService
->dwRefCount
);
2859 *lpServiceHandle
= (SC_RPC_HANDLE
)hHandle
;
2860 DPRINT("*hService = %p\n", *lpServiceHandle
);
2863 /* Unlock the service database */
2864 ScmUnlockDatabase();
2866 DPRINT("ROpenServiceW() done\n");
2875 RQueryServiceConfigW(
2876 SC_RPC_HANDLE hService
,
2877 LPBYTE lpBuf
, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2879 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
2881 LPQUERY_SERVICE_CONFIGW lpServiceConfig
= (LPQUERY_SERVICE_CONFIGW
)lpBuf
;
2882 DWORD dwError
= ERROR_SUCCESS
;
2883 PSERVICE_HANDLE hSvc
;
2884 PSERVICE lpService
= NULL
;
2885 HKEY hServiceKey
= NULL
;
2886 LPWSTR lpImagePath
= NULL
;
2887 LPWSTR lpServiceStartName
= NULL
;
2888 LPWSTR lpDependencies
= NULL
;
2889 DWORD dwDependenciesLength
= 0;
2890 DWORD dwRequiredSize
;
2891 WCHAR lpEmptyString
[] = {0,0};
2894 DPRINT("RQueryServiceConfigW() called\n");
2897 return ERROR_SHUTDOWN_IN_PROGRESS
;
2899 hSvc
= ScmGetServiceFromHandle(hService
);
2902 DPRINT1("Invalid service handle!\n");
2903 return ERROR_INVALID_HANDLE
;
2906 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
2907 SERVICE_QUERY_CONFIG
))
2909 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
2910 return ERROR_ACCESS_DENIED
;
2913 lpService
= hSvc
->ServiceEntry
;
2914 if (lpService
== NULL
)
2916 DPRINT("lpService == NULL!\n");
2917 return ERROR_INVALID_HANDLE
;
2920 /* Lock the service database shared */
2921 ScmLockDatabaseShared();
2923 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
2926 if (dwError
!= ERROR_SUCCESS
)
2929 /* Read the image path */
2930 dwError
= ScmReadString(hServiceKey
,
2933 if (dwError
!= ERROR_SUCCESS
)
2936 /* Read the service start name */
2937 ScmReadString(hServiceKey
,
2939 &lpServiceStartName
);
2941 /* Read the dependencies */
2942 ScmReadDependencies(hServiceKey
,
2944 &dwDependenciesLength
);
2946 dwRequiredSize
= sizeof(QUERY_SERVICE_CONFIGW
);
2948 if (lpImagePath
!= NULL
)
2949 dwRequiredSize
+= (DWORD
)((wcslen(lpImagePath
) + 1) * sizeof(WCHAR
));
2951 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2953 if ((lpService
->lpGroup
!= NULL
) && (lpService
->lpGroup
->lpGroupName
!= NULL
))
2954 dwRequiredSize
+= (DWORD
)((wcslen(lpService
->lpGroup
->lpGroupName
) + 1) * sizeof(WCHAR
));
2956 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2958 if (lpDependencies
!= NULL
)
2959 dwRequiredSize
+= dwDependenciesLength
* sizeof(WCHAR
);
2961 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2963 if (lpServiceStartName
!= NULL
)
2964 dwRequiredSize
+= (DWORD
)((wcslen(lpServiceStartName
) + 1) * sizeof(WCHAR
));
2966 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2968 if (lpService
->lpDisplayName
!= NULL
)
2969 dwRequiredSize
+= (DWORD
)((wcslen(lpService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
2971 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2973 if (lpServiceConfig
== NULL
|| cbBufSize
< dwRequiredSize
)
2975 dwError
= ERROR_INSUFFICIENT_BUFFER
;
2979 lpServiceConfig
->dwServiceType
= lpService
->Status
.dwServiceType
;
2980 lpServiceConfig
->dwStartType
= lpService
->dwStartType
;
2981 lpServiceConfig
->dwErrorControl
= lpService
->dwErrorControl
;
2982 lpServiceConfig
->dwTagId
= lpService
->dwTag
;
2984 lpStr
= (LPWSTR
)(lpServiceConfig
+ 1);
2986 /* Append the image path */
2987 if (lpImagePath
!= NULL
)
2989 wcscpy(lpStr
, lpImagePath
);
2993 wcscpy(lpStr
, lpEmptyString
);
2996 lpServiceConfig
->lpBinaryPathName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2997 lpStr
+= (wcslen(lpStr
) + 1);
2999 /* Append the group name */
3000 if ((lpService
->lpGroup
!= NULL
) && (lpService
->lpGroup
->lpGroupName
!= NULL
))
3002 wcscpy(lpStr
, lpService
->lpGroup
->lpGroupName
);
3006 wcscpy(lpStr
, lpEmptyString
);
3009 lpServiceConfig
->lpLoadOrderGroup
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
3010 lpStr
+= (wcslen(lpStr
) + 1);
3012 /* Append Dependencies */
3013 if (lpDependencies
!= NULL
)
3017 dwDependenciesLength
* sizeof(WCHAR
));
3021 wcscpy(lpStr
, lpEmptyString
);
3024 lpServiceConfig
->lpDependencies
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
3025 if (lpDependencies
!= NULL
)
3026 lpStr
+= dwDependenciesLength
;
3028 lpStr
+= (wcslen(lpStr
) + 1);
3030 /* Append the service start name */
3031 if (lpServiceStartName
!= NULL
)
3033 wcscpy(lpStr
, lpServiceStartName
);
3037 wcscpy(lpStr
, lpEmptyString
);
3040 lpServiceConfig
->lpServiceStartName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
3041 lpStr
+= (wcslen(lpStr
) + 1);
3043 /* Append the display name */
3044 if (lpService
->lpDisplayName
!= NULL
)
3046 wcscpy(lpStr
, lpService
->lpDisplayName
);
3050 wcscpy(lpStr
, lpEmptyString
);
3053 lpServiceConfig
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
3056 if (pcbBytesNeeded
!= NULL
)
3057 *pcbBytesNeeded
= dwRequiredSize
;
3060 /* Unlock the service database */
3061 ScmUnlockDatabase();
3063 if (lpImagePath
!= NULL
)
3064 HeapFree(GetProcessHeap(), 0, lpImagePath
);
3066 if (lpServiceStartName
!= NULL
)
3067 HeapFree(GetProcessHeap(), 0, lpServiceStartName
);
3069 if (lpDependencies
!= NULL
)
3070 HeapFree(GetProcessHeap(), 0, lpDependencies
);
3072 if (hServiceKey
!= NULL
)
3073 RegCloseKey(hServiceKey
);
3075 DPRINT("RQueryServiceConfigW() done\n");
3084 RQueryServiceLockStatusW(
3085 SC_RPC_HANDLE hSCManager
,
3086 LPBYTE lpBuf
, // LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
3088 LPBOUNDED_DWORD_4K pcbBytesNeeded
)
3090 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
= (LPQUERY_SERVICE_LOCK_STATUSW
)lpBuf
;
3091 PMANAGER_HANDLE hMgr
;
3092 DWORD dwRequiredSize
;
3094 if (!lpLockStatus
|| !pcbBytesNeeded
)
3095 return ERROR_INVALID_PARAMETER
;
3097 hMgr
= ScmGetServiceManagerFromHandle(hSCManager
);
3100 DPRINT1("Invalid service manager handle!\n");
3101 return ERROR_INVALID_HANDLE
;
3104 if (!RtlAreAllAccessesGranted(hMgr
->Handle
.DesiredAccess
,
3105 SC_MANAGER_QUERY_LOCK_STATUS
))
3107 DPRINT("Insufficient access rights! 0x%lx\n", hMgr
->Handle
.DesiredAccess
);
3108 return ERROR_ACCESS_DENIED
;
3111 /* FIXME: we need to compute instead the real length of the owner name */
3112 dwRequiredSize
= sizeof(QUERY_SERVICE_LOCK_STATUSW
) + sizeof(WCHAR
);
3113 *pcbBytesNeeded
= dwRequiredSize
;
3115 if (cbBufSize
< dwRequiredSize
)
3116 return ERROR_INSUFFICIENT_BUFFER
;
3118 ScmQueryServiceLockStatusW(lpLockStatus
);
3120 return ERROR_SUCCESS
;
3128 SC_RPC_HANDLE hService
,
3130 LPSTRING_PTRSW argv
)
3132 DWORD dwError
= ERROR_SUCCESS
;
3133 PSERVICE_HANDLE hSvc
;
3134 PSERVICE lpService
= NULL
;
3139 DPRINT("RStartServiceW(%p %lu %p) called\n", hService
, argc
, argv
);
3140 DPRINT(" argc: %lu\n", argc
);
3143 for (i
= 0; i
< argc
; i
++)
3145 DPRINT(" argv[%lu]: %S\n", i
, argv
[i
].StringPtr
);
3151 return ERROR_SHUTDOWN_IN_PROGRESS
;
3153 hSvc
= ScmGetServiceFromHandle(hService
);
3156 DPRINT1("Invalid service handle!\n");
3157 return ERROR_INVALID_HANDLE
;
3160 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3163 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
3164 return ERROR_ACCESS_DENIED
;
3167 lpService
= hSvc
->ServiceEntry
;
3168 if (lpService
== NULL
)
3170 DPRINT("lpService == NULL!\n");
3171 return ERROR_INVALID_HANDLE
;
3174 if (lpService
->dwStartType
== SERVICE_DISABLED
)
3175 return ERROR_SERVICE_DISABLED
;
3177 if (lpService
->bDeleted
)
3178 return ERROR_SERVICE_MARKED_FOR_DELETE
;
3180 /* Start the service */
3181 dwError
= ScmStartService(lpService
, argc
, (LPWSTR
*)argv
);
3190 RGetServiceDisplayNameW(
3191 SC_RPC_HANDLE hSCManager
,
3192 LPCWSTR lpServiceName
,
3193 LPWSTR lpDisplayName
,
3196 // PMANAGER_HANDLE hManager;
3201 DPRINT("RGetServiceDisplayNameW() called\n");
3202 DPRINT("hSCManager = %p\n", hSCManager
);
3203 DPRINT("lpServiceName: %S\n", lpServiceName
);
3204 DPRINT("lpDisplayName: %p\n", lpDisplayName
);
3205 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
3207 // hManager = (PMANAGER_HANDLE)hSCManager;
3208 // if (hManager->Handle.Tag != MANAGER_TAG)
3210 // DPRINT("Invalid manager handle!\n");
3211 // return ERROR_INVALID_HANDLE;
3214 /* Get service database entry */
3215 lpService
= ScmGetServiceEntryByName(lpServiceName
);
3216 if (lpService
== NULL
)
3218 DPRINT("Could not find a service!\n");
3220 /* If the service could not be found and lpcchBuffer is less than 2, windows
3221 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3222 if (*lpcchBuffer
< 2)
3225 if (lpDisplayName
!= NULL
)
3231 return ERROR_SERVICE_DOES_NOT_EXIST
;
3234 if (!lpService
->lpDisplayName
)
3236 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
3238 if (lpDisplayName
!= NULL
&&
3239 *lpcchBuffer
> dwLength
)
3241 wcscpy(lpDisplayName
, lpService
->lpServiceName
);
3246 dwLength
= (DWORD
)wcslen(lpService
->lpDisplayName
);
3248 if (lpDisplayName
!= NULL
&&
3249 *lpcchBuffer
> dwLength
)
3251 wcscpy(lpDisplayName
, lpService
->lpDisplayName
);
3255 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
3257 *lpcchBuffer
= dwLength
;
3266 RGetServiceKeyNameW(
3267 SC_RPC_HANDLE hSCManager
,
3268 LPCWSTR lpDisplayName
,
3269 LPWSTR lpServiceName
,
3272 // PMANAGER_HANDLE hManager;
3277 DPRINT("RGetServiceKeyNameW() called\n");
3278 DPRINT("hSCManager = %p\n", hSCManager
);
3279 DPRINT("lpDisplayName: %S\n", lpDisplayName
);
3280 DPRINT("lpServiceName: %p\n", lpServiceName
);
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
= ScmGetServiceEntryByDisplayName(lpDisplayName
);
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
< 2)
3301 if (lpServiceName
!= NULL
)
3307 return ERROR_SERVICE_DOES_NOT_EXIST
;
3310 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
3312 if (lpServiceName
!= NULL
&&
3313 *lpcchBuffer
> dwLength
)
3315 wcscpy(lpServiceName
, lpService
->lpServiceName
);
3316 *lpcchBuffer
= dwLength
;
3317 return ERROR_SUCCESS
;
3320 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
3322 *lpcchBuffer
= dwLength
;
3331 RI_ScSetServiceBitsA(
3332 RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
3333 DWORD dwServiceBits
,
3335 int bUpdateImmediately
,
3339 return ERROR_CALL_NOT_IMPLEMENTED
;
3346 RChangeServiceConfigA(
3347 SC_RPC_HANDLE hService
,
3348 DWORD dwServiceType
,
3350 DWORD dwErrorControl
,
3351 LPSTR lpBinaryPathName
,
3352 LPSTR lpLoadOrderGroup
,
3354 LPBYTE lpDependencies
,
3356 LPSTR lpServiceStartName
,
3359 LPSTR lpDisplayName
)
3361 DWORD dwError
= ERROR_SUCCESS
;
3362 PSERVICE_HANDLE hSvc
;
3363 PSERVICE lpService
= NULL
;
3364 HKEY hServiceKey
= NULL
;
3365 LPWSTR lpDisplayNameW
= NULL
;
3366 LPWSTR lpBinaryPathNameW
= NULL
;
3367 LPWSTR lpCanonicalImagePathW
= NULL
;
3368 LPWSTR lpLoadOrderGroupW
= NULL
;
3369 LPWSTR lpDependenciesW
= NULL
;
3371 DPRINT("RChangeServiceConfigA() called\n");
3372 DPRINT("dwServiceType = %lu\n", dwServiceType
);
3373 DPRINT("dwStartType = %lu\n", dwStartType
);
3374 DPRINT("dwErrorControl = %lu\n", dwErrorControl
);
3375 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName
);
3376 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup
);
3377 DPRINT("lpDisplayName = %s\n", lpDisplayName
);
3380 return ERROR_SHUTDOWN_IN_PROGRESS
;
3382 hSvc
= ScmGetServiceFromHandle(hService
);
3385 DPRINT1("Invalid service handle!\n");
3386 return ERROR_INVALID_HANDLE
;
3389 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3390 SERVICE_CHANGE_CONFIG
))
3392 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
3393 return ERROR_ACCESS_DENIED
;
3396 lpService
= hSvc
->ServiceEntry
;
3397 if (lpService
== NULL
)
3399 DPRINT("lpService == NULL!\n");
3400 return ERROR_INVALID_HANDLE
;
3403 /* Lock the service database exclusively */
3404 ScmLockDatabaseExclusive();
3406 if (lpService
->bDeleted
)
3408 DPRINT("The service has already been marked for delete!\n");
3409 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
3413 /* Open the service key */
3414 dwError
= ScmOpenServiceKey(lpService
->szServiceName
,
3417 if (dwError
!= ERROR_SUCCESS
)
3420 /* Write service data to the registry */
3422 if (lpDisplayName
!= NULL
&& *lpDisplayName
!= 0)
3424 /* Set the display name */
3425 lpDisplayNameW
= HeapAlloc(GetProcessHeap(),
3427 (strlen(lpDisplayName
) + 1) * sizeof(WCHAR
));
3428 if (lpDisplayNameW
== NULL
)
3430 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3434 MultiByteToWideChar(CP_ACP
,
3439 (int)(strlen(lpDisplayName
) + 1));
3441 RegSetValueExW(hServiceKey
,
3445 (LPBYTE
)lpDisplayNameW
,
3446 (DWORD
)((wcslen(lpDisplayNameW
) + 1) * sizeof(WCHAR
)));
3448 /* Update lpService->lpDisplayName */
3449 if (lpService
->lpDisplayName
)
3450 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
3452 lpService
->lpDisplayName
= lpDisplayNameW
;
3455 if (dwServiceType
!= SERVICE_NO_CHANGE
)
3457 /* Set the service type */
3458 dwError
= RegSetValueExW(hServiceKey
,
3462 (LPBYTE
)&dwServiceType
,
3464 if (dwError
!= ERROR_SUCCESS
)
3467 lpService
->Status
.dwServiceType
= dwServiceType
;
3470 if (dwStartType
!= SERVICE_NO_CHANGE
)
3472 /* Set the start value */
3473 dwError
= RegSetValueExW(hServiceKey
,
3477 (LPBYTE
)&dwStartType
,
3479 if (dwError
!= ERROR_SUCCESS
)
3482 lpService
->dwStartType
= dwStartType
;
3485 if (dwErrorControl
!= SERVICE_NO_CHANGE
)
3487 /* Set the error control value */
3488 dwError
= RegSetValueExW(hServiceKey
,
3492 (LPBYTE
)&dwErrorControl
,
3494 if (dwError
!= ERROR_SUCCESS
)
3497 lpService
->dwErrorControl
= dwErrorControl
;
3500 if (lpBinaryPathName
!= NULL
&& *lpBinaryPathName
!= 0)
3502 /* Set the image path */
3503 lpBinaryPathNameW
= HeapAlloc(GetProcessHeap(),
3505 (strlen(lpBinaryPathName
) + 1) * sizeof(WCHAR
));
3506 if (lpBinaryPathNameW
== NULL
)
3508 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3512 MultiByteToWideChar(CP_ACP
,
3517 (int)(strlen(lpBinaryPathName
) + 1));
3519 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
3521 dwError
= ScmCanonDriverImagePath(lpService
->dwStartType
,
3523 &lpCanonicalImagePathW
);
3525 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW
);
3527 if (dwError
!= ERROR_SUCCESS
)
3530 lpBinaryPathNameW
= lpCanonicalImagePathW
;
3533 dwError
= RegSetValueExW(hServiceKey
,
3537 (LPBYTE
)lpBinaryPathNameW
,
3538 (DWORD
)((wcslen(lpBinaryPathNameW
) + 1) * sizeof(WCHAR
)));
3540 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW
);
3542 if (dwError
!= ERROR_SUCCESS
)
3546 /* Set the group name */
3547 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
3549 lpLoadOrderGroupW
= HeapAlloc(GetProcessHeap(),
3551 (strlen(lpLoadOrderGroup
) + 1) * sizeof(WCHAR
));
3552 if (lpLoadOrderGroupW
== NULL
)
3554 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3558 MultiByteToWideChar(CP_ACP
,
3563 (int)(strlen(lpLoadOrderGroup
) + 1));
3565 dwError
= RegSetValueExW(hServiceKey
,
3569 (LPBYTE
)lpLoadOrderGroupW
,
3570 (DWORD
)((wcslen(lpLoadOrderGroupW
) + 1) * sizeof(WCHAR
)));
3571 if (dwError
!= ERROR_SUCCESS
)
3573 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3577 dwError
= ScmSetServiceGroup(lpService
,
3580 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3582 if (dwError
!= ERROR_SUCCESS
)
3586 if (lpdwTagId
!= NULL
)
3588 dwError
= ScmAssignNewTag(lpService
);
3589 if (dwError
!= ERROR_SUCCESS
)
3592 dwError
= RegSetValueExW(hServiceKey
,
3596 (LPBYTE
)&lpService
->dwTag
,
3598 if (dwError
!= ERROR_SUCCESS
)
3601 *lpdwTagId
= lpService
->dwTag
;
3604 /* Write dependencies */
3605 if (lpDependencies
!= NULL
&& *lpDependencies
!= 0)
3607 lpDependenciesW
= HeapAlloc(GetProcessHeap(),
3609 (strlen((LPSTR
)lpDependencies
) + 1) * sizeof(WCHAR
));
3610 if (lpDependenciesW
== NULL
)
3612 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3616 MultiByteToWideChar(CP_ACP
,
3618 (LPSTR
)lpDependencies
,
3621 (int)(strlen((LPSTR
)lpDependencies
) + 1));
3623 dwError
= ScmWriteDependencies(hServiceKey
,
3624 (LPWSTR
)lpDependenciesW
,
3627 HeapFree(GetProcessHeap(), 0, lpDependenciesW
);
3629 if (dwError
!= ERROR_SUCCESS
)
3633 if (lpPassword
!= NULL
)
3635 if (wcslen((LPWSTR
)lpPassword
) != 0)
3637 /* FIXME: Decrypt the password */
3639 /* Write the password */
3640 dwError
= ScmSetServicePassword(lpService
->szServiceName
,
3641 (LPCWSTR
)lpPassword
);
3642 if (dwError
!= ERROR_SUCCESS
)
3647 /* Delete the password */
3648 dwError
= ScmSetServicePassword(lpService
->szServiceName
,
3650 if (dwError
== ERROR_FILE_NOT_FOUND
)
3651 dwError
= ERROR_SUCCESS
;
3653 if (dwError
!= ERROR_SUCCESS
)
3659 /* Unlock the service database */
3660 ScmUnlockDatabase();
3662 if (hServiceKey
!= NULL
)
3663 RegCloseKey(hServiceKey
);
3665 DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError
);
3675 SC_RPC_HANDLE hSCManager
,
3676 LPSTR lpServiceName
,
3677 LPSTR lpDisplayName
,
3678 DWORD dwDesiredAccess
,
3679 DWORD dwServiceType
,
3681 DWORD dwErrorControl
,
3682 LPSTR lpBinaryPathName
,
3683 LPSTR lpLoadOrderGroup
,
3685 LPBYTE lpDependencies
,
3687 LPSTR lpServiceStartName
,
3690 LPSC_RPC_HANDLE lpServiceHandle
)
3692 DWORD dwError
= ERROR_SUCCESS
;
3693 LPWSTR lpServiceNameW
= NULL
;
3694 LPWSTR lpDisplayNameW
= NULL
;
3695 LPWSTR lpBinaryPathNameW
= NULL
;
3696 LPWSTR lpLoadOrderGroupW
= NULL
;
3697 LPWSTR lpDependenciesW
= NULL
;
3698 LPWSTR lpServiceStartNameW
= NULL
;
3699 DWORD dwDependenciesLength
= 0;
3706 len
= MultiByteToWideChar(CP_ACP
, 0, lpServiceName
, -1, NULL
, 0);
3707 lpServiceNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3708 if (!lpServiceNameW
)
3710 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3713 MultiByteToWideChar(CP_ACP
, 0, lpServiceName
, -1, lpServiceNameW
, len
);
3718 len
= MultiByteToWideChar(CP_ACP
, 0, lpDisplayName
, -1, NULL
, 0);
3719 lpDisplayNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3720 if (!lpDisplayNameW
)
3722 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3725 MultiByteToWideChar(CP_ACP
, 0, lpDisplayName
, -1, lpDisplayNameW
, len
);
3728 if (lpBinaryPathName
)
3730 len
= MultiByteToWideChar(CP_ACP
, 0, lpBinaryPathName
, -1, NULL
, 0);
3731 lpBinaryPathNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3732 if (!lpBinaryPathNameW
)
3734 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3737 MultiByteToWideChar(CP_ACP
, 0, lpBinaryPathName
, -1, lpBinaryPathNameW
, len
);
3740 if (lpLoadOrderGroup
)
3742 len
= MultiByteToWideChar(CP_ACP
, 0, lpLoadOrderGroup
, -1, NULL
, 0);
3743 lpLoadOrderGroupW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3744 if (!lpLoadOrderGroupW
)
3746 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3749 MultiByteToWideChar(CP_ACP
, 0, lpLoadOrderGroup
, -1, lpLoadOrderGroupW
, len
);
3754 lpStr
= (LPCSTR
)lpDependencies
;
3757 cchLength
= strlen(lpStr
) + 1;
3758 dwDependenciesLength
+= (DWORD
)cchLength
;
3759 lpStr
= lpStr
+ cchLength
;
3761 dwDependenciesLength
++;
3763 lpDependenciesW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwDependenciesLength
* sizeof(WCHAR
));
3764 if (!lpDependenciesW
)
3766 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3769 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)lpDependencies
, dwDependenciesLength
, lpDependenciesW
, dwDependenciesLength
);
3772 if (lpServiceStartName
)
3774 len
= MultiByteToWideChar(CP_ACP
, 0, lpServiceStartName
, -1, NULL
, 0);
3775 lpServiceStartNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3776 if (!lpServiceStartNameW
)
3778 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3781 MultiByteToWideChar(CP_ACP
, 0, lpServiceStartName
, -1, lpServiceStartNameW
, len
);
3784 dwError
= RCreateServiceW(hSCManager
,
3794 (LPBYTE
)lpDependenciesW
,
3795 dwDependenciesLength
,
3796 lpServiceStartNameW
,
3802 if (lpServiceNameW
!=NULL
)
3803 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
3805 if (lpDisplayNameW
!= NULL
)
3806 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
3808 if (lpBinaryPathNameW
!= NULL
)
3809 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW
);
3811 if (lpLoadOrderGroupW
!= NULL
)
3812 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3814 if (lpDependenciesW
!= NULL
)
3815 HeapFree(GetProcessHeap(), 0, lpDependenciesW
);
3817 if (lpServiceStartNameW
!= NULL
)
3818 HeapFree(GetProcessHeap(), 0, lpServiceStartNameW
);
3827 REnumDependentServicesA(
3828 SC_RPC_HANDLE hService
,
3829 DWORD dwServiceState
,
3832 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
3833 LPBOUNDED_DWORD_256K lpServicesReturned
)
3835 DWORD dwError
= ERROR_SUCCESS
;
3836 DWORD dwServicesReturned
= 0;
3837 DWORD dwServiceCount
;
3838 HKEY hServicesKey
= NULL
;
3839 PSERVICE_HANDLE hSvc
;
3840 PSERVICE lpService
= NULL
;
3841 PSERVICE
*lpServicesArray
= NULL
;
3842 LPENUM_SERVICE_STATUSA lpServicesPtr
= NULL
;
3845 *pcbBytesNeeded
= 0;
3846 *lpServicesReturned
= 0;
3848 DPRINT("REnumDependentServicesA() called\n");
3850 hSvc
= ScmGetServiceFromHandle(hService
);
3853 DPRINT1("Invalid service handle!\n");
3854 return ERROR_INVALID_HANDLE
;
3857 lpService
= hSvc
->ServiceEntry
;
3859 /* Check access rights */
3860 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3861 SC_MANAGER_ENUMERATE_SERVICE
))
3863 DPRINT("Insufficient access rights! 0x%lx\n",
3864 hSvc
->Handle
.DesiredAccess
);
3865 return ERROR_ACCESS_DENIED
;
3868 /* Open the Services Reg key */
3869 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
3870 L
"System\\CurrentControlSet\\Services",
3875 if (dwError
!= ERROR_SUCCESS
)
3878 /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3879 both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3880 are the same for both. Verified in WINXP. */
3882 /* First determine the bytes needed and get the number of dependent services*/
3883 dwError
= Int_EnumDependentServicesW(hServicesKey
,
3888 &dwServicesReturned
);
3889 if (dwError
!= ERROR_SUCCESS
)
3892 /* If buffer size is less than the bytes needed or pointer is null*/
3893 if ((!lpServices
) || (cbBufSize
< *pcbBytesNeeded
))
3895 dwError
= ERROR_MORE_DATA
;
3899 /* Allocate memory for array of service pointers */
3900 lpServicesArray
= HeapAlloc(GetProcessHeap(),
3902 (dwServicesReturned
+ 1) * sizeof(PSERVICE
));
3903 if (!lpServicesArray
)
3905 DPRINT("Could not allocate a buffer!!\n");
3906 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3910 dwServicesReturned
= 0;
3911 *pcbBytesNeeded
= 0;
3913 dwError
= Int_EnumDependentServicesW(hServicesKey
,
3918 &dwServicesReturned
);
3919 if (dwError
!= ERROR_SUCCESS
)
3924 lpServicesPtr
= (LPENUM_SERVICE_STATUSA
)lpServices
;
3925 lpStr
= (LPSTR
)(lpServices
+ (dwServicesReturned
* sizeof(ENUM_SERVICE_STATUSA
)));
3927 /* Copy EnumDepenedentService to Buffer */
3928 for (dwServiceCount
= 0; dwServiceCount
< dwServicesReturned
; dwServiceCount
++)
3930 lpService
= lpServicesArray
[dwServiceCount
];
3932 /* Copy the status info */
3933 memcpy(&lpServicesPtr
->ServiceStatus
,
3935 sizeof(SERVICE_STATUS
));
3937 /* Copy display name */
3938 WideCharToMultiByte(CP_ACP
,
3940 lpService
->lpDisplayName
,
3943 (int)wcslen(lpService
->lpDisplayName
),
3946 lpServicesPtr
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
3947 lpStr
+= strlen(lpStr
) + 1;
3949 /* Copy service name */
3950 WideCharToMultiByte(CP_ACP
,
3952 lpService
->lpServiceName
,
3955 (int)wcslen(lpService
->lpServiceName
),
3958 lpServicesPtr
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
3959 lpStr
+= strlen(lpStr
) + 1;
3964 *lpServicesReturned
= dwServicesReturned
;
3967 if (lpServicesArray
)
3968 HeapFree(GetProcessHeap(), 0, lpServicesArray
);
3970 RegCloseKey(hServicesKey
);
3972 DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError
);
3981 REnumServicesStatusA(
3982 SC_RPC_HANDLE hSCManager
,
3983 DWORD dwServiceType
,
3984 DWORD dwServiceState
,
3987 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
3988 LPBOUNDED_DWORD_256K lpServicesReturned
,
3989 LPBOUNDED_DWORD_256K lpResumeHandle
)
3991 LPENUM_SERVICE_STATUSW lpStatusPtrW
= NULL
;
3992 LPENUM_SERVICE_STATUSW lpStatusPtrIncrW
;
3993 LPENUM_SERVICE_STATUSA lpStatusPtrA
= NULL
;
3994 LPWSTR lpStringPtrW
;
3997 DWORD dwServiceCount
;
3999 DPRINT("REnumServicesStatusA() called\n");
4001 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
4003 return ERROR_INVALID_ADDRESS
;
4006 if ((dwBufSize
> 0) && (lpBuffer
))
4008 lpStatusPtrW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwBufSize
);
4011 DPRINT("Failed to allocate buffer!\n");
4012 return ERROR_NOT_ENOUGH_MEMORY
;
4016 dwError
= REnumServicesStatusW(hSCManager
,
4019 (LPBYTE
)lpStatusPtrW
,
4025 /* if no services were returned then we are Done */
4026 if (*lpServicesReturned
== 0)
4029 lpStatusPtrIncrW
= lpStatusPtrW
;
4030 lpStatusPtrA
= (LPENUM_SERVICE_STATUSA
)lpBuffer
;
4031 lpStringPtrA
= (LPSTR
)((ULONG_PTR
)lpBuffer
+
4032 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUSA
));
4033 lpStringPtrW
= (LPWSTR
)((ULONG_PTR
)lpStatusPtrW
+
4034 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUSW
));
4036 for (dwServiceCount
= 0; dwServiceCount
< *lpServicesReturned
; dwServiceCount
++)
4038 /* Copy the service name */
4039 WideCharToMultiByte(CP_ACP
,
4044 (int)wcslen(lpStringPtrW
),
4048 lpStatusPtrA
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
4049 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
4050 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
4052 /* Copy the display name */
4053 WideCharToMultiByte(CP_ACP
,
4058 (int)wcslen(lpStringPtrW
),
4062 lpStatusPtrA
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
4063 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
4064 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
4066 /* Copy the status information */
4067 memcpy(&lpStatusPtrA
->ServiceStatus
,
4068 &lpStatusPtrIncrW
->ServiceStatus
,
4069 sizeof(SERVICE_STATUS
));
4077 HeapFree(GetProcessHeap(), 0, lpStatusPtrW
);
4079 DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError
);
4089 LPSTR lpMachineName
,
4090 LPSTR lpDatabaseName
,
4091 DWORD dwDesiredAccess
,
4092 LPSC_RPC_HANDLE lpScHandle
)
4094 UNICODE_STRING MachineName
;
4095 UNICODE_STRING DatabaseName
;
4098 DPRINT("ROpenSCManagerA() called\n");
4101 RtlCreateUnicodeStringFromAsciiz(&MachineName
,
4105 RtlCreateUnicodeStringFromAsciiz(&DatabaseName
,
4108 dwError
= ROpenSCManagerW(lpMachineName
? MachineName
.Buffer
: NULL
,
4109 lpDatabaseName
? DatabaseName
.Buffer
: NULL
,
4114 RtlFreeUnicodeString(&MachineName
);
4117 RtlFreeUnicodeString(&DatabaseName
);
4127 SC_RPC_HANDLE hSCManager
,
4128 LPSTR lpServiceName
,
4129 DWORD dwDesiredAccess
,
4130 LPSC_RPC_HANDLE lpServiceHandle
)
4132 UNICODE_STRING ServiceName
;
4135 DPRINT("ROpenServiceA() called\n");
4138 RtlCreateUnicodeStringFromAsciiz(&ServiceName
,
4141 dwError
= ROpenServiceW(hSCManager
,
4142 lpServiceName
? ServiceName
.Buffer
: NULL
,
4147 RtlFreeUnicodeString(&ServiceName
);
4156 RQueryServiceConfigA(
4157 SC_RPC_HANDLE hService
,
4158 LPBYTE lpBuf
, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
4160 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
4162 LPQUERY_SERVICE_CONFIGA lpServiceConfig
= (LPQUERY_SERVICE_CONFIGA
)lpBuf
;
4163 DWORD dwError
= ERROR_SUCCESS
;
4164 PSERVICE_HANDLE hSvc
;
4165 PSERVICE lpService
= NULL
;
4166 HKEY hServiceKey
= NULL
;
4167 LPWSTR lpImagePath
= NULL
;
4168 LPWSTR lpServiceStartName
= NULL
;
4169 LPWSTR lpDependencies
= NULL
;
4170 DWORD dwDependenciesLength
= 0;
4171 DWORD dwRequiredSize
;
4172 CHAR lpEmptyString
[]={0,0};
4175 DPRINT("RQueryServiceConfigA() called\n");
4178 return ERROR_SHUTDOWN_IN_PROGRESS
;
4180 hSvc
= ScmGetServiceFromHandle(hService
);
4183 DPRINT1("Invalid service handle!\n");
4184 return ERROR_INVALID_HANDLE
;
4187 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
4188 SERVICE_QUERY_CONFIG
))
4190 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
4191 return ERROR_ACCESS_DENIED
;
4194 lpService
= hSvc
->ServiceEntry
;
4195 if (lpService
== NULL
)
4197 DPRINT("lpService == NULL!\n");
4198 return ERROR_INVALID_HANDLE
;
4201 /* Lock the service database shared */
4202 ScmLockDatabaseShared();
4204 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
4207 if (dwError
!= ERROR_SUCCESS
)
4210 /* Read the image path */
4211 dwError
= ScmReadString(hServiceKey
,
4214 if (dwError
!= ERROR_SUCCESS
)
4217 /* Read the service start name */
4218 ScmReadString(hServiceKey
,
4220 &lpServiceStartName
);
4222 /* Read the dependencies */
4223 ScmReadDependencies(hServiceKey
,
4225 &dwDependenciesLength
);
4227 dwRequiredSize
= sizeof(QUERY_SERVICE_CONFIGA
);
4229 if (lpImagePath
!= NULL
)
4230 dwRequiredSize
+= (DWORD
)(wcslen(lpImagePath
) + 1);
4232 dwRequiredSize
+= 2;
4234 if ((lpService
->lpGroup
!= NULL
) && (lpService
->lpGroup
->lpGroupName
!= NULL
))
4235 dwRequiredSize
+= (DWORD
)(wcslen(lpService
->lpGroup
->lpGroupName
) + 1);
4237 dwRequiredSize
+= 2;
4239 /* Add Dependencies length */
4240 if (lpDependencies
!= NULL
)
4241 dwRequiredSize
+= dwDependenciesLength
;
4243 dwRequiredSize
+= 2;
4245 if (lpServiceStartName
!= NULL
)
4246 dwRequiredSize
+= (DWORD
)(wcslen(lpServiceStartName
) + 1);
4248 dwRequiredSize
+= 2;
4250 if (lpService
->lpDisplayName
!= NULL
)
4251 dwRequiredSize
+= (DWORD
)(wcslen(lpService
->lpDisplayName
) + 1);
4253 dwRequiredSize
+= 2;
4255 if (lpServiceConfig
== NULL
|| cbBufSize
< dwRequiredSize
)
4257 dwError
= ERROR_INSUFFICIENT_BUFFER
;
4261 lpServiceConfig
->dwServiceType
= lpService
->Status
.dwServiceType
;
4262 lpServiceConfig
->dwStartType
= lpService
->dwStartType
;
4263 lpServiceConfig
->dwErrorControl
= lpService
->dwErrorControl
;
4264 lpServiceConfig
->dwTagId
= lpService
->dwTag
;
4266 lpStr
= (LPSTR
)(lpServiceConfig
+ 1);
4268 /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
4269 Verified in WINXP */
4273 WideCharToMultiByte(CP_ACP
,
4278 (int)(wcslen(lpImagePath
) + 1),
4284 strcpy(lpStr
, lpEmptyString
);
4287 lpServiceConfig
->lpBinaryPathName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4288 lpStr
+= (strlen((LPSTR
)lpStr
) + 1);
4290 if (lpService
->lpGroup
&& lpService
->lpGroup
->lpGroupName
)
4292 WideCharToMultiByte(CP_ACP
,
4294 lpService
->lpGroup
->lpGroupName
,
4297 (int)(wcslen(lpService
->lpGroup
->lpGroupName
) + 1),
4303 strcpy(lpStr
, lpEmptyString
);
4306 lpServiceConfig
->lpLoadOrderGroup
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4307 lpStr
+= (strlen(lpStr
) + 1);
4309 /* Append Dependencies */
4312 WideCharToMultiByte(CP_ACP
,
4315 dwDependenciesLength
,
4317 dwDependenciesLength
,
4323 strcpy(lpStr
, lpEmptyString
);
4326 lpServiceConfig
->lpDependencies
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4328 lpStr
+= dwDependenciesLength
;
4330 lpStr
+= (strlen(lpStr
) + 1);
4332 if (lpServiceStartName
)
4334 WideCharToMultiByte(CP_ACP
,
4339 (int)(wcslen(lpServiceStartName
) + 1),
4345 strcpy(lpStr
, lpEmptyString
);
4348 lpServiceConfig
->lpServiceStartName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4349 lpStr
+= (strlen(lpStr
) + 1);
4351 if (lpService
->lpDisplayName
)
4353 WideCharToMultiByte(CP_ACP
,
4355 lpService
->lpDisplayName
,
4358 (int)(wcslen(lpService
->lpDisplayName
) + 1),
4364 strcpy(lpStr
, lpEmptyString
);
4367 lpServiceConfig
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4370 if (pcbBytesNeeded
!= NULL
)
4371 *pcbBytesNeeded
= dwRequiredSize
;
4374 /* Unlock the service database */
4375 ScmUnlockDatabase();
4377 if (lpImagePath
!= NULL
)
4378 HeapFree(GetProcessHeap(), 0, lpImagePath
);
4380 if (lpServiceStartName
!= NULL
)
4381 HeapFree(GetProcessHeap(), 0, lpServiceStartName
);
4383 if (lpDependencies
!= NULL
)
4384 HeapFree(GetProcessHeap(), 0, lpDependencies
);
4386 if (hServiceKey
!= NULL
)
4387 RegCloseKey(hServiceKey
);
4389 DPRINT("RQueryServiceConfigA() done\n");
4398 RQueryServiceLockStatusA(
4399 SC_RPC_HANDLE hSCManager
,
4400 LPBYTE lpBuf
, // LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
4402 LPBOUNDED_DWORD_4K pcbBytesNeeded
)
4404 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
= (LPQUERY_SERVICE_LOCK_STATUSA
)lpBuf
;
4405 PMANAGER_HANDLE hMgr
;
4406 DWORD dwRequiredSize
;
4408 if (!lpLockStatus
|| !pcbBytesNeeded
)
4409 return ERROR_INVALID_PARAMETER
;
4411 hMgr
= ScmGetServiceManagerFromHandle(hSCManager
);
4414 DPRINT1("Invalid service manager handle!\n");
4415 return ERROR_INVALID_HANDLE
;
4418 if (!RtlAreAllAccessesGranted(hMgr
->Handle
.DesiredAccess
,
4419 SC_MANAGER_QUERY_LOCK_STATUS
))
4421 DPRINT("Insufficient access rights! 0x%lx\n", hMgr
->Handle
.DesiredAccess
);
4422 return ERROR_ACCESS_DENIED
;
4425 /* FIXME: we need to compute instead the real length of the owner name */
4426 dwRequiredSize
= sizeof(QUERY_SERVICE_LOCK_STATUSA
) + sizeof(CHAR
);
4427 *pcbBytesNeeded
= dwRequiredSize
;
4429 if (cbBufSize
< dwRequiredSize
)
4430 return ERROR_INSUFFICIENT_BUFFER
;
4432 ScmQueryServiceLockStatusA(lpLockStatus
);
4434 return ERROR_SUCCESS
;
4442 SC_RPC_HANDLE hService
,
4444 LPSTRING_PTRSA argv
)
4446 DWORD dwError
= ERROR_SUCCESS
;
4447 PSERVICE_HANDLE hSvc
;
4448 PSERVICE lpService
= NULL
;
4449 LPWSTR
*lpVector
= NULL
;
4453 DPRINT("RStartServiceA() called\n");
4456 return ERROR_SHUTDOWN_IN_PROGRESS
;
4458 hSvc
= ScmGetServiceFromHandle(hService
);
4461 DPRINT1("Invalid service handle!\n");
4462 return ERROR_INVALID_HANDLE
;
4465 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
4468 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
4469 return ERROR_ACCESS_DENIED
;
4472 lpService
= hSvc
->ServiceEntry
;
4473 if (lpService
== NULL
)
4475 DPRINT("lpService == NULL!\n");
4476 return ERROR_INVALID_HANDLE
;
4479 if (lpService
->dwStartType
== SERVICE_DISABLED
)
4480 return ERROR_SERVICE_DISABLED
;
4482 if (lpService
->bDeleted
)
4483 return ERROR_SERVICE_MARKED_FOR_DELETE
;
4485 /* Build a Unicode argument vector */
4488 lpVector
= HeapAlloc(GetProcessHeap(),
4490 argc
* sizeof(LPWSTR
));
4491 if (lpVector
== NULL
)
4492 return ERROR_NOT_ENOUGH_MEMORY
;
4494 for (i
= 0; i
< argc
; i
++)
4496 dwLength
= MultiByteToWideChar(CP_ACP
,
4503 lpVector
[i
] = HeapAlloc(GetProcessHeap(),
4505 dwLength
* sizeof(WCHAR
));
4506 if (lpVector
[i
] == NULL
)
4508 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
4512 MultiByteToWideChar(CP_ACP
,
4521 /* Start the service */
4522 dwError
= ScmStartService(lpService
, argc
, lpVector
);
4525 /* Free the Unicode argument vector */
4526 if (lpVector
!= NULL
)
4528 for (i
= 0; i
< argc
; i
++)
4530 if (lpVector
[i
] != NULL
)
4531 HeapFree(GetProcessHeap(), 0, lpVector
[i
]);
4533 HeapFree(GetProcessHeap(), 0, lpVector
);
4543 RGetServiceDisplayNameA(
4544 SC_RPC_HANDLE hSCManager
,
4545 LPCSTR lpServiceName
,
4546 LPSTR lpDisplayName
,
4547 LPBOUNDED_DWORD_4K lpcchBuffer
)
4549 // PMANAGER_HANDLE hManager;
4550 PSERVICE lpService
= NULL
;
4553 LPWSTR lpServiceNameW
;
4555 DPRINT("RGetServiceDisplayNameA() called\n");
4556 DPRINT("hSCManager = %p\n", hSCManager
);
4557 DPRINT("lpServiceName: %s\n", lpServiceName
);
4558 DPRINT("lpDisplayName: %p\n", lpDisplayName
);
4559 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
4561 // hManager = (PMANAGER_HANDLE)hSCManager;
4562 // if (hManager->Handle.Tag != MANAGER_TAG)
4564 // DPRINT("Invalid manager handle!\n");
4565 // return ERROR_INVALID_HANDLE;
4568 if (lpServiceName
!= NULL
)
4570 dwLength
= (DWORD
)(strlen(lpServiceName
) + 1);
4571 lpServiceNameW
= HeapAlloc(GetProcessHeap(),
4573 dwLength
* sizeof(WCHAR
));
4574 if (!lpServiceNameW
)
4575 return ERROR_NOT_ENOUGH_MEMORY
;
4577 MultiByteToWideChar(CP_ACP
,
4584 lpService
= ScmGetServiceEntryByName(lpServiceNameW
);
4586 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
4589 if (lpService
== NULL
)
4591 DPRINT("Could not find a service!\n");
4593 /* If the service could not be found and lpcchBuffer is 0, windows
4594 puts null in lpDisplayName and puts 1 in lpcchBuffer */
4595 if (*lpcchBuffer
== 0)
4598 if (lpDisplayName
!= NULL
)
4603 return ERROR_SERVICE_DOES_NOT_EXIST
;
4606 if (!lpService
->lpDisplayName
)
4608 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
4609 if (lpDisplayName
!= NULL
&&
4610 *lpcchBuffer
> dwLength
)
4612 WideCharToMultiByte(CP_ACP
,
4614 lpService
->lpServiceName
,
4615 (int)wcslen(lpService
->lpServiceName
),
4620 return ERROR_SUCCESS
;
4625 dwLength
= (DWORD
)wcslen(lpService
->lpDisplayName
);
4626 if (lpDisplayName
!= NULL
&&
4627 *lpcchBuffer
> dwLength
)
4629 WideCharToMultiByte(CP_ACP
,
4631 lpService
->lpDisplayName
,
4632 (int)wcslen(lpService
->lpDisplayName
),
4637 return ERROR_SUCCESS
;
4641 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
4643 *lpcchBuffer
= dwLength
* 2;
4652 RGetServiceKeyNameA(
4653 SC_RPC_HANDLE hSCManager
,
4654 LPCSTR lpDisplayName
,
4655 LPSTR lpServiceName
,
4656 LPBOUNDED_DWORD_4K lpcchBuffer
)
4661 LPWSTR lpDisplayNameW
;
4663 DPRINT("RGetServiceKeyNameA() called\n");
4664 DPRINT("hSCManager = %p\n", hSCManager
);
4665 DPRINT("lpDisplayName: %s\n", lpDisplayName
);
4666 DPRINT("lpServiceName: %p\n", lpServiceName
);
4667 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
4669 dwLength
= (DWORD
)(strlen(lpDisplayName
) + 1);
4670 lpDisplayNameW
= HeapAlloc(GetProcessHeap(),
4672 dwLength
* sizeof(WCHAR
));
4673 if (!lpDisplayNameW
)
4674 return ERROR_NOT_ENOUGH_MEMORY
;
4676 MultiByteToWideChar(CP_ACP
,
4683 lpService
= ScmGetServiceEntryByDisplayName(lpDisplayNameW
);
4685 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
4687 if (lpService
== NULL
)
4689 DPRINT("Could not find the service!\n");
4691 /* If the service could not be found and lpcchBuffer is 0,
4692 put null in lpDisplayName and puts 1 in lpcchBuffer, verified WINXP. */
4693 if (*lpcchBuffer
== 0)
4696 if (lpServiceName
!= NULL
)
4702 return ERROR_SERVICE_DOES_NOT_EXIST
;
4705 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
4706 if (lpServiceName
!= NULL
&&
4707 *lpcchBuffer
> dwLength
)
4709 WideCharToMultiByte(CP_ACP
,
4711 lpService
->lpServiceName
,
4712 (int)wcslen(lpService
->lpServiceName
),
4717 return ERROR_SUCCESS
;
4720 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
4722 *lpcchBuffer
= dwLength
* 2;
4731 RI_ScGetCurrentGroupStateW(
4732 SC_RPC_HANDLE hSCManager
,
4733 LPWSTR lpLoadOrderGroup
,
4736 PMANAGER_HANDLE hManager
;
4737 PSERVICE_GROUP pServiceGroup
;
4738 DWORD dwError
= ERROR_SUCCESS
;
4740 DPRINT("RI_ScGetCurrentGroupStateW() called\n");
4743 return ERROR_SHUTDOWN_IN_PROGRESS
;
4745 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
4746 if (hManager
== NULL
)
4748 DPRINT1("Invalid service manager handle!\n");
4749 return ERROR_INVALID_HANDLE
;
4752 /* Check for SC_MANAGER_ENUMERATE_SERVICE access right */
4753 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
4754 SC_MANAGER_ENUMERATE_SERVICE
))
4756 DPRINT("Insufficient access rights! 0x%lx\n",
4757 hManager
->Handle
.DesiredAccess
);
4758 return ERROR_ACCESS_DENIED
;
4761 /* Lock the service database shared */
4762 ScmLockDatabaseShared();
4764 /* Get the group list entry */
4765 pServiceGroup
= ScmGetServiceGroupByName(lpLoadOrderGroup
);
4766 if (pServiceGroup
== NULL
)
4768 dwError
= ERROR_SERVICE_DOES_NOT_EXIST
;
4772 /* FIXME: Return the group state */
4776 /* Unlock the service database */
4777 ScmUnlockDatabase();
4779 DPRINT("RI_ScGetCurrentGroupStateW() done (Error %lu)\n", dwError
);
4789 SC_RPC_HANDLE hSCManager
,
4790 DWORD dwServiceType
,
4791 DWORD dwServiceState
,
4794 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
4795 LPBOUNDED_DWORD_256K lpServicesReturned
,
4796 LPBOUNDED_DWORD_256K lpResumeIndex
,
4797 LPCWSTR pszGroupName
)
4799 PMANAGER_HANDLE hManager
;
4801 DWORD dwError
= ERROR_SUCCESS
;
4802 PLIST_ENTRY ServiceEntry
;
4803 PSERVICE CurrentService
;
4805 DWORD dwRequiredSize
;
4806 DWORD dwServiceCount
;
4808 DWORD dwLastResumeCount
= 0;
4809 LPENUM_SERVICE_STATUSW lpStatusPtr
;
4812 DPRINT("REnumServiceGroupW() called\n");
4815 return ERROR_SHUTDOWN_IN_PROGRESS
;
4817 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
4818 if (hManager
== NULL
)
4820 DPRINT1("Invalid service manager handle!\n");
4821 return ERROR_INVALID_HANDLE
;
4824 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
4826 return ERROR_INVALID_ADDRESS
;
4829 *pcbBytesNeeded
= 0;
4830 *lpServicesReturned
= 0;
4832 if ((dwServiceType
== 0) ||
4833 ((dwServiceType
& ~SERVICE_TYPE_ALL
) != 0))
4835 DPRINT("Not a valid Service Type!\n");
4836 return ERROR_INVALID_PARAMETER
;
4839 if ((dwServiceState
== 0) ||
4840 ((dwServiceState
& ~SERVICE_STATE_ALL
) != 0))
4842 DPRINT("Not a valid Service State!\n");
4843 return ERROR_INVALID_PARAMETER
;
4846 /* Check access rights */
4847 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
4848 SC_MANAGER_ENUMERATE_SERVICE
))
4850 DPRINT("Insufficient access rights! 0x%lx\n",
4851 hManager
->Handle
.DesiredAccess
);
4852 return ERROR_ACCESS_DENIED
;
4856 dwLastResumeCount
= *lpResumeIndex
;
4858 /* Lock the service database shared */
4859 ScmLockDatabaseShared();
4861 lpService
= ScmGetServiceEntryByResumeCount(dwLastResumeCount
);
4862 if (lpService
== NULL
)
4864 dwError
= ERROR_SUCCESS
;
4871 for (ServiceEntry
= &lpService
->ServiceListEntry
;
4872 ServiceEntry
!= &ServiceListHead
;
4873 ServiceEntry
= ServiceEntry
->Flink
)
4875 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
4879 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
4882 dwState
= SERVICE_ACTIVE
;
4883 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
4884 dwState
= SERVICE_INACTIVE
;
4886 if ((dwState
& dwServiceState
) == 0)
4891 if (*pszGroupName
== 0)
4893 if (CurrentService
->lpGroup
!= NULL
)
4898 if ((CurrentService
->lpGroup
== NULL
) ||
4899 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
4904 dwSize
= sizeof(ENUM_SERVICE_STATUSW
) +
4905 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
4906 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
4908 if (dwRequiredSize
+ dwSize
> cbBufSize
)
4910 DPRINT("Service name: %S no fit\n", CurrentService
->lpServiceName
);
4914 DPRINT("Service name: %S fit\n", CurrentService
->lpServiceName
);
4915 dwRequiredSize
+= dwSize
;
4917 dwLastResumeCount
= CurrentService
->dwResumeCount
;
4920 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize
);
4921 DPRINT("dwServiceCount: %lu\n", dwServiceCount
);
4924 ServiceEntry
!= &ServiceListHead
;
4925 ServiceEntry
= ServiceEntry
->Flink
)
4927 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
4931 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
4934 dwState
= SERVICE_ACTIVE
;
4935 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
4936 dwState
= SERVICE_INACTIVE
;
4938 if ((dwState
& dwServiceState
) == 0)
4943 if (*pszGroupName
== 0)
4945 if (CurrentService
->lpGroup
!= NULL
)
4950 if ((CurrentService
->lpGroup
== NULL
) ||
4951 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
4956 dwRequiredSize
+= (sizeof(ENUM_SERVICE_STATUSW
) +
4957 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
4958 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
)));
4960 dwError
= ERROR_MORE_DATA
;
4963 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize
);
4966 *lpResumeIndex
= dwLastResumeCount
;
4968 *lpServicesReturned
= dwServiceCount
;
4969 *pcbBytesNeeded
= dwRequiredSize
;
4971 lpStatusPtr
= (LPENUM_SERVICE_STATUSW
)lpBuffer
;
4972 lpStringPtr
= (LPWSTR
)((ULONG_PTR
)lpBuffer
+
4973 dwServiceCount
* sizeof(ENUM_SERVICE_STATUSW
));
4976 for (ServiceEntry
= &lpService
->ServiceListEntry
;
4977 ServiceEntry
!= &ServiceListHead
;
4978 ServiceEntry
= ServiceEntry
->Flink
)
4980 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
4984 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
4987 dwState
= SERVICE_ACTIVE
;
4988 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
4989 dwState
= SERVICE_INACTIVE
;
4991 if ((dwState
& dwServiceState
) == 0)
4996 if (*pszGroupName
== 0)
4998 if (CurrentService
->lpGroup
!= NULL
)
5003 if ((CurrentService
->lpGroup
== NULL
) ||
5004 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
5009 dwSize
= sizeof(ENUM_SERVICE_STATUSW
) +
5010 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
5011 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
5013 if (dwRequiredSize
+ dwSize
> cbBufSize
)
5016 /* Copy the service name */
5017 wcscpy(lpStringPtr
, CurrentService
->lpServiceName
);
5018 lpStatusPtr
->lpServiceName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
5019 lpStringPtr
+= (wcslen(CurrentService
->lpServiceName
) + 1);
5021 /* Copy the display name */
5022 wcscpy(lpStringPtr
, CurrentService
->lpDisplayName
);
5023 lpStatusPtr
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
5024 lpStringPtr
+= (wcslen(CurrentService
->lpDisplayName
) + 1);
5026 /* Copy the status information */
5027 memcpy(&lpStatusPtr
->ServiceStatus
,
5028 &CurrentService
->Status
,
5029 sizeof(SERVICE_STATUS
));
5032 dwRequiredSize
+= dwSize
;
5035 if (dwError
== ERROR_SUCCESS
)
5037 *pcbBytesNeeded
= 0;
5038 if (lpResumeIndex
) *lpResumeIndex
= 0;
5042 /* Unlock the service database */
5043 ScmUnlockDatabase();
5045 DPRINT("REnumServiceGroupW() done (Error %lu)\n", dwError
);
5054 RChangeServiceConfig2A(
5055 SC_RPC_HANDLE hService
,
5056 SC_RPC_CONFIG_INFOA Info
)
5058 SC_RPC_CONFIG_INFOW InfoW
;
5059 DWORD dwRet
, dwLength
;
5062 DPRINT("RChangeServiceConfig2A() called\n");
5063 DPRINT("dwInfoLevel = %lu\n", Info
.dwInfoLevel
);
5065 InfoW
.dwInfoLevel
= Info
.dwInfoLevel
;
5067 if (InfoW
.dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
5069 LPSERVICE_DESCRIPTIONW lpServiceDescriptionW
;
5070 LPSERVICE_DESCRIPTIONA lpServiceDescriptionA
;
5072 lpServiceDescriptionA
= Info
.psd
;
5074 if (lpServiceDescriptionA
&&
5075 lpServiceDescriptionA
->lpDescription
)
5077 dwLength
= (DWORD
)((strlen(lpServiceDescriptionA
->lpDescription
) + 1) * sizeof(WCHAR
));
5079 lpServiceDescriptionW
= HeapAlloc(GetProcessHeap(),
5081 dwLength
+ sizeof(SERVICE_DESCRIPTIONW
));
5082 if (!lpServiceDescriptionW
)
5084 return ERROR_NOT_ENOUGH_MEMORY
;
5087 lpServiceDescriptionW
->lpDescription
= (LPWSTR
)(lpServiceDescriptionW
+ 1);
5089 MultiByteToWideChar(CP_ACP
,
5091 lpServiceDescriptionA
->lpDescription
,
5093 lpServiceDescriptionW
->lpDescription
,
5096 ptr
= lpServiceDescriptionW
;
5097 InfoW
.psd
= lpServiceDescriptionW
;
5100 else if (Info
.dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5102 LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW
;
5103 LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA
;
5104 DWORD dwRebootLen
= 0;
5105 DWORD dwCommandLen
= 0;
5106 DWORD dwActionArrayLen
= 0;
5107 LPWSTR lpStr
= NULL
;
5109 lpServiceFailureActionsA
= Info
.psfa
;
5111 if (lpServiceFailureActionsA
)
5114 * The following code is inspired by the
5115 * SERVICE_CONFIG_FAILURE_ACTIONS case of
5116 * the RQueryServiceConfig2W function.
5119 /* Retrieve the needed length for the two data strings */
5120 if (lpServiceFailureActionsA
->lpRebootMsg
)
5122 dwRebootLen
= (DWORD
)((strlen(lpServiceFailureActionsA
->lpRebootMsg
) + 1) * sizeof(WCHAR
));
5124 if (lpServiceFailureActionsA
->lpCommand
)
5126 dwCommandLen
= (DWORD
)((strlen(lpServiceFailureActionsA
->lpCommand
) + 1) * sizeof(WCHAR
));
5130 * Retrieve the size of the lpsaActions array if needed.
5131 * We will copy the lpsaActions array only if there is at
5132 * least one action AND that the original array is valid.
5134 if (lpServiceFailureActionsA
->cActions
> 0 && lpServiceFailureActionsA
->lpsaActions
)
5136 dwActionArrayLen
= lpServiceFailureActionsA
->cActions
* sizeof(SC_ACTION
);
5139 /* Compute the total length for the UNICODE structure, including data */
5140 dwLength
= sizeof(SERVICE_FAILURE_ACTIONSW
) +
5141 dwActionArrayLen
+ dwRebootLen
+ dwCommandLen
;
5143 /* Allocate the structure */
5144 lpServiceFailureActionsW
= HeapAlloc(GetProcessHeap(),
5147 if (!lpServiceFailureActionsW
)
5149 return ERROR_NOT_ENOUGH_MEMORY
;
5152 /* Copy the members */
5153 lpServiceFailureActionsW
->dwResetPeriod
= lpServiceFailureActionsA
->dwResetPeriod
;
5154 lpServiceFailureActionsW
->cActions
= lpServiceFailureActionsA
->cActions
;
5156 /* Copy the lpsaActions array if needed */
5157 if (dwActionArrayLen
> 0)
5159 /* The storage zone is just after the end of the SERVICE_FAILURE_ACTIONSW structure */
5160 lpServiceFailureActionsW
->lpsaActions
= (LPSC_ACTION
)((ULONG_PTR
)(lpServiceFailureActionsW
+ 1));
5162 /* dwActionArrayLen == lpServiceFailureActionsW->cActions * sizeof(SC_ACTION) */
5163 RtlCopyMemory(lpServiceFailureActionsW
->lpsaActions
,
5164 lpServiceFailureActionsA
->lpsaActions
,
5169 /* No lpsaActions array */
5170 lpServiceFailureActionsW
->lpsaActions
= NULL
;
5172 /* The data strings are stored just after the lpsaActions array */
5173 lpStr
= (LPWSTR
)((ULONG_PTR
)(lpServiceFailureActionsW
+ 1) + dwActionArrayLen
);
5176 * Convert the data strings to UNICODE
5179 lpServiceFailureActionsW
->lpRebootMsg
= NULL
;
5180 lpServiceFailureActionsW
->lpCommand
= NULL
;
5184 /* lpRebootMsg points just after the lpsaActions array */
5185 lpServiceFailureActionsW
->lpRebootMsg
= lpStr
;
5187 MultiByteToWideChar(CP_ACP
,
5189 lpServiceFailureActionsA
->lpRebootMsg
,
5191 lpServiceFailureActionsW
->lpRebootMsg
,
5194 lpStr
+= dwRebootLen
/ sizeof(WCHAR
);
5199 /* lpRebootMsg points just after the lpRebootMsg data string */
5200 lpServiceFailureActionsW
->lpCommand
= lpStr
;
5202 MultiByteToWideChar(CP_ACP
,
5204 lpServiceFailureActionsA
->lpCommand
,
5206 lpServiceFailureActionsW
->lpCommand
,
5210 /* Set the pointers */
5211 ptr
= lpServiceFailureActionsW
;
5212 InfoW
.psfa
= lpServiceFailureActionsW
;
5216 dwRet
= RChangeServiceConfig2W(hService
, InfoW
);
5218 HeapFree(GetProcessHeap(), 0, ptr
);
5225 ScmSetFailureActions(HKEY hServiceKey
,
5226 LPSERVICE_FAILURE_ACTIONSW lpFailureActions
)
5228 LPSERVICE_FAILURE_ACTIONSW lpReadBuffer
= NULL
;
5229 LPSERVICE_FAILURE_ACTIONSW lpWriteBuffer
= NULL
;
5230 DWORD dwRequiredSize
= 0;
5234 /* There is nothing to be done if we have no failure actions */
5235 if (lpFailureActions
== NULL
)
5236 return ERROR_SUCCESS
;
5239 * 1- Retrieve the original value of FailureActions.
5242 /* Query value length */
5243 dwError
= RegQueryValueExW(hServiceKey
,
5249 if (dwError
!= ERROR_SUCCESS
&&
5250 dwError
!= ERROR_MORE_DATA
&&
5251 dwError
!= ERROR_FILE_NOT_FOUND
)
5254 dwRequiredSize
= (dwType
== REG_BINARY
) ? max(sizeof(SERVICE_FAILURE_ACTIONSW
), dwRequiredSize
)
5255 : sizeof(SERVICE_FAILURE_ACTIONSW
);
5257 /* Initialize the read buffer */
5258 lpReadBuffer
= HeapAlloc(GetProcessHeap(),
5261 if (lpReadBuffer
== NULL
)
5262 return ERROR_NOT_ENOUGH_MEMORY
;
5264 /* Now we can fill the read buffer */
5265 if (dwError
!= ERROR_FILE_NOT_FOUND
&&
5266 dwType
== REG_BINARY
)
5268 dwError
= RegQueryValueExW(hServiceKey
,
5272 (LPBYTE
)lpReadBuffer
,
5274 if (dwError
!= ERROR_SUCCESS
&&
5275 dwError
!= ERROR_FILE_NOT_FOUND
)
5278 if (dwRequiredSize
< sizeof(SERVICE_FAILURE_ACTIONSW
))
5279 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSW
);
5284 * The value of the error doesn't really matter, the only
5285 * important thing is that it must be != ERROR_SUCCESS.
5287 dwError
= ERROR_INVALID_DATA
;
5290 if (dwError
== ERROR_SUCCESS
)
5292 lpReadBuffer
->cActions
= min(lpReadBuffer
->cActions
, (dwRequiredSize
- sizeof(SERVICE_FAILURE_ACTIONSW
)) / sizeof(SC_ACTION
));
5293 lpReadBuffer
->lpsaActions
= (lpReadBuffer
->cActions
> 0 ? (LPSC_ACTION
)(lpReadBuffer
+ 1) : NULL
);
5297 lpReadBuffer
->dwResetPeriod
= 0;
5298 lpReadBuffer
->cActions
= 0;
5299 lpReadBuffer
->lpsaActions
= NULL
;
5302 lpReadBuffer
->lpRebootMsg
= NULL
;
5303 lpReadBuffer
->lpCommand
= NULL
;
5306 * 2- Initialize the new value to set.
5309 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSW
);
5311 if (lpFailureActions
->lpsaActions
== NULL
)
5314 * lpFailureActions->cActions is ignored.
5315 * Therefore we use the original values
5316 * of cActions and lpsaActions.
5318 dwRequiredSize
+= lpReadBuffer
->cActions
* sizeof(SC_ACTION
);
5323 * The reset period and array of failure actions
5324 * are deleted if lpFailureActions->cActions == 0 .
5326 dwRequiredSize
+= lpFailureActions
->cActions
* sizeof(SC_ACTION
);
5329 lpWriteBuffer
= HeapAlloc(GetProcessHeap(),
5332 if (lpWriteBuffer
== NULL
)
5334 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
5338 /* Clean the pointers as they have no meaning when the structure is stored in the registry */
5339 lpWriteBuffer
->lpRebootMsg
= NULL
;
5340 lpWriteBuffer
->lpCommand
= NULL
;
5341 lpWriteBuffer
->lpsaActions
= NULL
;
5343 /* Set the members */
5344 if (lpFailureActions
->lpsaActions
== NULL
)
5347 * lpFailureActions->dwResetPeriod and lpFailureActions->cActions are ignored.
5348 * Therefore we use the original values of dwResetPeriod, cActions and lpsaActions.
5350 lpWriteBuffer
->dwResetPeriod
= lpReadBuffer
->dwResetPeriod
;
5351 lpWriteBuffer
->cActions
= lpReadBuffer
->cActions
;
5353 if (lpReadBuffer
->lpsaActions
!= NULL
)
5355 memmove(lpWriteBuffer
+ 1,
5356 lpReadBuffer
->lpsaActions
,
5357 lpReadBuffer
->cActions
* sizeof(SC_ACTION
));
5362 if (lpFailureActions
->cActions
> 0)
5364 lpWriteBuffer
->dwResetPeriod
= lpFailureActions
->dwResetPeriod
;
5365 lpWriteBuffer
->cActions
= lpFailureActions
->cActions
;
5367 memmove(lpWriteBuffer
+ 1,
5368 lpFailureActions
->lpsaActions
,
5369 lpFailureActions
->cActions
* sizeof(SC_ACTION
));
5373 /* The reset period and array of failure actions are deleted */
5374 lpWriteBuffer
->dwResetPeriod
= 0;
5375 lpWriteBuffer
->cActions
= 0;
5379 /* Save the new failure actions into the registry */
5380 dwError
= RegSetValueExW(hServiceKey
,
5384 (LPBYTE
)lpWriteBuffer
,
5387 /* We modify the strings only in case of success.*/
5388 if (dwError
== ERROR_SUCCESS
)
5390 /* Modify the Reboot Message value, if specified */
5391 if (lpFailureActions
->lpRebootMsg
!= NULL
)
5393 /* If the Reboot Message is "" then we delete it */
5394 if (*lpFailureActions
->lpRebootMsg
== 0)
5396 DPRINT("Delete Reboot Message value\n");
5397 RegDeleteValueW(hServiceKey
, L
"RebootMessage");
5401 DPRINT("Setting Reboot Message value %S\n", lpFailureActions
->lpRebootMsg
);
5402 RegSetValueExW(hServiceKey
,
5406 (LPBYTE
)lpFailureActions
->lpRebootMsg
,
5407 (DWORD
)((wcslen(lpFailureActions
->lpRebootMsg
) + 1) * sizeof(WCHAR
)));
5411 /* Modify the Failure Command value, if specified */
5412 if (lpFailureActions
->lpCommand
!= NULL
)
5414 /* If the FailureCommand string is an empty string, delete the value */
5415 if (*lpFailureActions
->lpCommand
== 0)
5417 DPRINT("Delete Failure Command value\n");
5418 RegDeleteValueW(hServiceKey
, L
"FailureCommand");
5422 DPRINT("Setting Failure Command value %S\n", lpFailureActions
->lpCommand
);
5423 RegSetValueExW(hServiceKey
,
5427 (LPBYTE
)lpFailureActions
->lpCommand
,
5428 (DWORD
)((wcslen(lpFailureActions
->lpCommand
) + 1) * sizeof(WCHAR
)));
5434 if (lpWriteBuffer
!= NULL
)
5435 HeapFree(GetProcessHeap(), 0, lpWriteBuffer
);
5437 if (lpReadBuffer
!= NULL
)
5438 HeapFree(GetProcessHeap(), 0, lpReadBuffer
);
5447 RChangeServiceConfig2W(
5448 SC_RPC_HANDLE hService
,
5449 SC_RPC_CONFIG_INFOW Info
)
5451 DWORD dwError
= ERROR_SUCCESS
;
5452 PSERVICE_HANDLE hSvc
;
5453 PSERVICE lpService
= NULL
;
5454 HKEY hServiceKey
= NULL
;
5455 ACCESS_MASK RequiredAccess
= SERVICE_CHANGE_CONFIG
;
5457 DPRINT("RChangeServiceConfig2W() called\n");
5458 DPRINT("dwInfoLevel = %lu\n", Info
.dwInfoLevel
);
5461 return ERROR_SHUTDOWN_IN_PROGRESS
;
5463 hSvc
= ScmGetServiceFromHandle(hService
);
5466 DPRINT("Invalid service handle!\n");
5467 return ERROR_INVALID_HANDLE
;
5470 if (Info
.dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5471 RequiredAccess
|= SERVICE_START
;
5473 /* Check the access rights */
5474 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5477 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5478 return ERROR_ACCESS_DENIED
;
5481 if (Info
.dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5483 /* FIXME: Check if the caller has the SE_SHUTDOWN_NAME privilege */
5487 lpService
= hSvc
->ServiceEntry
;
5488 if (lpService
== NULL
)
5490 DPRINT("lpService == NULL!\n");
5491 return ERROR_INVALID_HANDLE
;
5494 /* Failure actions can only be set for Win32 services, not for drivers */
5495 if (Info
.dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5497 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
5498 return ERROR_CANNOT_DETECT_DRIVER_FAILURE
;
5501 /* Lock the service database exclusively */
5502 ScmLockDatabaseExclusive();
5504 if (lpService
->bDeleted
)
5506 DPRINT("The service has already been marked for delete!\n");
5507 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
5511 /* Open the service key */
5512 dwError
= ScmOpenServiceKey(lpService
->szServiceName
,
5513 KEY_READ
| KEY_SET_VALUE
,
5515 if (dwError
!= ERROR_SUCCESS
)
5518 if (Info
.dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
5520 LPSERVICE_DESCRIPTIONW lpServiceDescription
= (LPSERVICE_DESCRIPTIONW
)Info
.psd
;
5522 /* Modify the service description, if specified */
5523 if (lpServiceDescription
!= NULL
&&
5524 lpServiceDescription
->lpDescription
!= NULL
)
5526 /* If the description is "" then we delete it */
5527 if (*lpServiceDescription
->lpDescription
== 0)
5529 DPRINT("Delete service description\n");
5530 dwError
= RegDeleteValueW(hServiceKey
, L
"Description");
5532 if (dwError
== ERROR_FILE_NOT_FOUND
)
5533 dwError
= ERROR_SUCCESS
;
5537 DPRINT("Setting service description value %S\n", lpServiceDescription
->lpDescription
);
5538 dwError
= RegSetValueExW(hServiceKey
,
5542 (LPBYTE
)lpServiceDescription
->lpDescription
,
5543 (DWORD
)((wcslen(lpServiceDescription
->lpDescription
) + 1) * sizeof(WCHAR
)));
5548 dwError
= ERROR_SUCCESS
;
5551 else if (Info
.dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5553 dwError
= ScmSetFailureActions(hServiceKey
,
5554 (LPSERVICE_FAILURE_ACTIONSW
)Info
.psfa
);
5558 if (hServiceKey
!= NULL
)
5559 RegCloseKey(hServiceKey
);
5561 /* Unlock the service database */
5562 ScmUnlockDatabase();
5564 DPRINT("RChangeServiceConfig2W() done (Error %lu)\n", dwError
);
5573 RQueryServiceConfig2A(
5574 SC_RPC_HANDLE hService
,
5578 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
5580 DWORD dwError
= ERROR_SUCCESS
;
5581 PSERVICE_HANDLE hSvc
;
5582 PSERVICE lpService
= NULL
;
5583 HKEY hServiceKey
= NULL
;
5584 DWORD dwRequiredSize
= 0;
5586 LPWSTR lpDescriptionW
= NULL
;
5587 LPWSTR lpRebootMessageW
= NULL
;
5588 LPWSTR lpFailureCommandW
= NULL
;
5590 DPRINT("RQueryServiceConfig2A() called hService %p dwInfoLevel %u, lpBuffer %p cbBufSize %u pcbBytesNeeded %p\n",
5591 hService
, dwInfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
5594 return ERROR_INVALID_ADDRESS
;
5597 return ERROR_SHUTDOWN_IN_PROGRESS
;
5599 hSvc
= ScmGetServiceFromHandle(hService
);
5602 DPRINT1("Invalid service handle!\n");
5603 return ERROR_INVALID_HANDLE
;
5606 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5607 SERVICE_QUERY_CONFIG
))
5609 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5610 return ERROR_ACCESS_DENIED
;
5613 lpService
= hSvc
->ServiceEntry
;
5614 if (lpService
== NULL
)
5616 DPRINT("lpService == NULL!\n");
5617 return ERROR_INVALID_HANDLE
;
5620 /* Lock the service database shared */
5621 ScmLockDatabaseShared();
5623 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
5626 if (dwError
!= ERROR_SUCCESS
)
5629 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
5631 LPSERVICE_DESCRIPTIONA lpServiceDescription
= (LPSERVICE_DESCRIPTIONA
)lpBuffer
;
5634 dwError
= ScmReadString(hServiceKey
,
5637 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5640 *pcbBytesNeeded
= sizeof(SERVICE_DESCRIPTIONA
);
5641 if (dwError
== ERROR_SUCCESS
)
5642 *pcbBytesNeeded
+= (DWORD
)((wcslen(lpDescriptionW
) + 1) * sizeof(WCHAR
));
5644 if (cbBufSize
< *pcbBytesNeeded
)
5646 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5650 if (dwError
== ERROR_SUCCESS
)
5652 lpStr
= (LPSTR
)(lpServiceDescription
+ 1);
5654 WideCharToMultiByte(CP_ACP
,
5659 (int)wcslen(lpDescriptionW
),
5662 lpServiceDescription
->lpDescription
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceDescription
);
5666 lpServiceDescription
->lpDescription
= NULL
;
5667 dwError
= ERROR_SUCCESS
;
5670 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5672 LPSERVICE_FAILURE_ACTIONSA lpFailureActions
= (LPSERVICE_FAILURE_ACTIONSA
)lpBuffer
;
5675 /* Query value length */
5676 dwError
= RegQueryValueExW(hServiceKey
,
5682 if (dwError
!= ERROR_SUCCESS
&&
5683 dwError
!= ERROR_MORE_DATA
&&
5684 dwError
!= ERROR_FILE_NOT_FOUND
)
5687 dwRequiredSize
= (dwType
== REG_BINARY
) ? max(sizeof(SERVICE_FAILURE_ACTIONSA
), dwRequiredSize
)
5688 : sizeof(SERVICE_FAILURE_ACTIONSA
);
5690 /* Get the strings */
5691 ScmReadString(hServiceKey
,
5693 &lpFailureCommandW
);
5695 ScmReadString(hServiceKey
,
5699 if (lpRebootMessageW
)
5700 dwRequiredSize
+= (DWORD
)((wcslen(lpRebootMessageW
) + 1) * sizeof(WCHAR
));
5702 if (lpFailureCommandW
)
5703 dwRequiredSize
+= (DWORD
)((wcslen(lpFailureCommandW
) + 1) * sizeof(WCHAR
));
5705 if (cbBufSize
< dwRequiredSize
)
5707 *pcbBytesNeeded
= dwRequiredSize
;
5708 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5712 /* Now we can fill the buffer */
5713 if (dwError
!= ERROR_FILE_NOT_FOUND
&& dwType
== REG_BINARY
)
5715 dwError
= RegQueryValueExW(hServiceKey
,
5719 (LPBYTE
)lpFailureActions
,
5721 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5724 if (dwRequiredSize
< sizeof(SERVICE_FAILURE_ACTIONSA
))
5725 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSA
);
5730 * The value of the error doesn't really matter, the only
5731 * important thing is that it must be != ERROR_SUCCESS .
5733 dwError
= ERROR_INVALID_DATA
;
5736 if (dwError
== ERROR_SUCCESS
)
5738 lpFailureActions
->cActions
= min(lpFailureActions
->cActions
, (dwRequiredSize
- sizeof(SERVICE_FAILURE_ACTIONSA
)) / sizeof(SC_ACTION
));
5740 /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */
5741 lpFailureActions
->lpsaActions
= (lpFailureActions
->cActions
> 0 ? (LPSC_ACTION
)(ULONG_PTR
)sizeof(SERVICE_FAILURE_ACTIONSA
) : NULL
);
5743 lpStr
= (LPSTR
)((ULONG_PTR
)(lpFailureActions
+ 1) + lpFailureActions
->cActions
* sizeof(SC_ACTION
));
5747 lpFailureActions
->dwResetPeriod
= 0;
5748 lpFailureActions
->cActions
= 0;
5749 lpFailureActions
->lpsaActions
= NULL
;
5750 lpStr
= (LPSTR
)(lpFailureActions
+ 1);
5753 lpFailureActions
->lpRebootMsg
= NULL
;
5754 lpFailureActions
->lpCommand
= NULL
;
5756 if (lpRebootMessageW
)
5758 WideCharToMultiByte(CP_ACP
,
5763 (int)wcslen(lpRebootMessageW
),
5766 lpFailureActions
->lpRebootMsg
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5767 lpStr
+= strlen(lpStr
) + 1;
5770 if (lpFailureCommandW
)
5772 WideCharToMultiByte(CP_ACP
,
5777 (int)wcslen(lpFailureCommandW
),
5780 lpFailureActions
->lpCommand
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5781 /* lpStr += strlen(lpStr) + 1; */
5784 dwError
= ERROR_SUCCESS
;
5788 /* Unlock the service database */
5789 ScmUnlockDatabase();
5791 if (lpDescriptionW
!= NULL
)
5792 HeapFree(GetProcessHeap(), 0, lpDescriptionW
);
5794 if (lpRebootMessageW
!= NULL
)
5795 HeapFree(GetProcessHeap(), 0, lpRebootMessageW
);
5797 if (lpFailureCommandW
!= NULL
)
5798 HeapFree(GetProcessHeap(), 0, lpFailureCommandW
);
5800 if (hServiceKey
!= NULL
)
5801 RegCloseKey(hServiceKey
);
5803 DPRINT("RQueryServiceConfig2A() done (Error %lu)\n", dwError
);
5812 RQueryServiceConfig2W(
5813 SC_RPC_HANDLE hService
,
5817 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
5819 DWORD dwError
= ERROR_SUCCESS
;
5820 PSERVICE_HANDLE hSvc
;
5821 PSERVICE lpService
= NULL
;
5822 HKEY hServiceKey
= NULL
;
5823 DWORD dwRequiredSize
= 0;
5825 LPWSTR lpDescription
= NULL
;
5826 LPWSTR lpRebootMessage
= NULL
;
5827 LPWSTR lpFailureCommand
= NULL
;
5829 DPRINT("RQueryServiceConfig2W() called\n");
5832 return ERROR_INVALID_ADDRESS
;
5835 return ERROR_SHUTDOWN_IN_PROGRESS
;
5837 hSvc
= ScmGetServiceFromHandle(hService
);
5840 DPRINT1("Invalid service handle!\n");
5841 return ERROR_INVALID_HANDLE
;
5844 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5845 SERVICE_QUERY_CONFIG
))
5847 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5848 return ERROR_ACCESS_DENIED
;
5851 lpService
= hSvc
->ServiceEntry
;
5852 if (lpService
== NULL
)
5854 DPRINT("lpService == NULL!\n");
5855 return ERROR_INVALID_HANDLE
;
5858 /* Lock the service database shared */
5859 ScmLockDatabaseShared();
5861 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
5864 if (dwError
!= ERROR_SUCCESS
)
5867 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
5869 LPSERVICE_DESCRIPTIONW lpServiceDescription
= (LPSERVICE_DESCRIPTIONW
)lpBuffer
;
5872 dwError
= ScmReadString(hServiceKey
,
5875 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5878 *pcbBytesNeeded
= sizeof(SERVICE_DESCRIPTIONW
);
5879 if (dwError
== ERROR_SUCCESS
)
5880 *pcbBytesNeeded
+= (DWORD
)((wcslen(lpDescription
) + 1) * sizeof(WCHAR
));
5882 if (cbBufSize
< *pcbBytesNeeded
)
5884 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5888 if (dwError
== ERROR_SUCCESS
)
5890 lpStr
= (LPWSTR
)(lpServiceDescription
+ 1);
5891 wcscpy(lpStr
, lpDescription
);
5892 lpServiceDescription
->lpDescription
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceDescription
);
5896 lpServiceDescription
->lpDescription
= NULL
;
5897 dwError
= ERROR_SUCCESS
;
5900 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5902 LPSERVICE_FAILURE_ACTIONSW lpFailureActions
= (LPSERVICE_FAILURE_ACTIONSW
)lpBuffer
;
5903 LPWSTR lpStr
= NULL
;
5905 /* Query value length */
5906 dwError
= RegQueryValueExW(hServiceKey
,
5912 if (dwError
!= ERROR_SUCCESS
&&
5913 dwError
!= ERROR_MORE_DATA
&&
5914 dwError
!= ERROR_FILE_NOT_FOUND
)
5917 dwRequiredSize
= (dwType
== REG_BINARY
) ? max(sizeof(SERVICE_FAILURE_ACTIONSW
), dwRequiredSize
)
5918 : sizeof(SERVICE_FAILURE_ACTIONSW
);
5920 /* Get the strings */
5921 ScmReadString(hServiceKey
,
5925 ScmReadString(hServiceKey
,
5929 if (lpRebootMessage
)
5930 dwRequiredSize
+= (DWORD
)((wcslen(lpRebootMessage
) + 1) * sizeof(WCHAR
));
5932 if (lpFailureCommand
)
5933 dwRequiredSize
+= (DWORD
)((wcslen(lpFailureCommand
) + 1) * sizeof(WCHAR
));
5935 if (cbBufSize
< dwRequiredSize
)
5937 *pcbBytesNeeded
= dwRequiredSize
;
5938 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5942 /* Now we can fill the buffer */
5943 if (dwError
!= ERROR_FILE_NOT_FOUND
&& dwType
== REG_BINARY
)
5945 dwError
= RegQueryValueExW(hServiceKey
,
5949 (LPBYTE
)lpFailureActions
,
5951 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5954 if (dwRequiredSize
< sizeof(SERVICE_FAILURE_ACTIONSW
))
5955 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSW
);
5960 * The value of the error doesn't really matter, the only
5961 * important thing is that it must be != ERROR_SUCCESS .
5963 dwError
= ERROR_INVALID_DATA
;
5966 if (dwError
== ERROR_SUCCESS
)
5968 lpFailureActions
->cActions
= min(lpFailureActions
->cActions
, (dwRequiredSize
- sizeof(SERVICE_FAILURE_ACTIONSW
)) / sizeof(SC_ACTION
));
5970 /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */
5971 lpFailureActions
->lpsaActions
= (lpFailureActions
->cActions
> 0 ? (LPSC_ACTION
)(ULONG_PTR
)sizeof(SERVICE_FAILURE_ACTIONSW
) : NULL
);
5973 lpStr
= (LPWSTR
)((ULONG_PTR
)(lpFailureActions
+ 1) + lpFailureActions
->cActions
* sizeof(SC_ACTION
));
5977 lpFailureActions
->dwResetPeriod
= 0;
5978 lpFailureActions
->cActions
= 0;
5979 lpFailureActions
->lpsaActions
= NULL
;
5980 lpStr
= (LPWSTR
)(lpFailureActions
+ 1);
5983 lpFailureActions
->lpRebootMsg
= NULL
;
5984 lpFailureActions
->lpCommand
= NULL
;
5986 if (lpRebootMessage
)
5988 wcscpy(lpStr
, lpRebootMessage
);
5989 lpFailureActions
->lpRebootMsg
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5990 lpStr
+= wcslen(lpStr
) + 1;
5993 if (lpFailureCommand
)
5995 wcscpy(lpStr
, lpFailureCommand
);
5996 lpFailureActions
->lpCommand
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5997 /* lpStr += wcslen(lpStr) + 1; */
6000 dwError
= ERROR_SUCCESS
;
6004 /* Unlock the service database */
6005 ScmUnlockDatabase();
6007 if (lpDescription
!= NULL
)
6008 HeapFree(GetProcessHeap(), 0, lpDescription
);
6010 if (lpRebootMessage
!= NULL
)
6011 HeapFree(GetProcessHeap(), 0, lpRebootMessage
);
6013 if (lpFailureCommand
!= NULL
)
6014 HeapFree(GetProcessHeap(), 0, lpFailureCommand
);
6016 if (hServiceKey
!= NULL
)
6017 RegCloseKey(hServiceKey
);
6019 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError
);
6028 RQueryServiceStatusEx(
6029 SC_RPC_HANDLE hService
,
6030 SC_STATUS_TYPE InfoLevel
,
6033 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
6035 LPSERVICE_STATUS_PROCESS lpStatus
;
6036 PSERVICE_HANDLE hSvc
;
6039 DPRINT("RQueryServiceStatusEx() called\n");
6042 return ERROR_SHUTDOWN_IN_PROGRESS
;
6044 if (InfoLevel
!= SC_STATUS_PROCESS_INFO
)
6045 return ERROR_INVALID_LEVEL
;
6047 *pcbBytesNeeded
= sizeof(SERVICE_STATUS_PROCESS
);
6049 if (cbBufSize
< sizeof(SERVICE_STATUS_PROCESS
))
6050 return ERROR_INSUFFICIENT_BUFFER
;
6052 hSvc
= ScmGetServiceFromHandle(hService
);
6055 DPRINT1("Invalid service handle!\n");
6056 return ERROR_INVALID_HANDLE
;
6059 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
6060 SERVICE_QUERY_STATUS
))
6062 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
6063 return ERROR_ACCESS_DENIED
;
6066 lpService
= hSvc
->ServiceEntry
;
6067 if (lpService
== NULL
)
6069 DPRINT("lpService == NULL!\n");
6070 return ERROR_INVALID_HANDLE
;
6073 /* Lock the service database shared */
6074 ScmLockDatabaseShared();
6076 lpStatus
= (LPSERVICE_STATUS_PROCESS
)lpBuffer
;
6078 /* Return service status information */
6079 RtlCopyMemory(lpStatus
,
6081 sizeof(SERVICE_STATUS
));
6083 /* Copy the service process ID */
6084 if ((lpService
->Status
.dwCurrentState
== SERVICE_STOPPED
) || (lpService
->lpImage
== NULL
))
6085 lpStatus
->dwProcessId
= 0;
6087 lpStatus
->dwProcessId
= lpService
->lpImage
->dwProcessId
;
6089 lpStatus
->dwServiceFlags
= 0; /* FIXME */
6091 /* Unlock the service database */
6092 ScmUnlockDatabase();
6094 return ERROR_SUCCESS
;
6101 REnumServicesStatusExA(
6102 SC_RPC_HANDLE hSCManager
,
6103 SC_ENUM_TYPE InfoLevel
,
6104 DWORD dwServiceType
,
6105 DWORD dwServiceState
,
6108 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
6109 LPBOUNDED_DWORD_256K lpServicesReturned
,
6110 LPBOUNDED_DWORD_256K lpResumeIndex
,
6111 LPCSTR pszGroupName
)
6113 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrW
= NULL
;
6114 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrIncrW
;
6115 LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtrA
= NULL
;
6116 LPWSTR lpStringPtrW
;
6118 LPWSTR pszGroupNameW
= NULL
;
6120 DWORD dwServiceCount
;
6122 DPRINT("REnumServicesStatusExA() called\n");
6124 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
6126 return ERROR_INVALID_ADDRESS
;
6131 pszGroupNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, (strlen(pszGroupName
) + 1) * sizeof(WCHAR
));
6134 DPRINT("Failed to allocate buffer!\n");
6135 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
6139 MultiByteToWideChar(CP_ACP
,
6144 (int)(strlen(pszGroupName
) + 1));
6147 if ((cbBufSize
> 0) && (lpBuffer
))
6149 lpStatusPtrW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, cbBufSize
);
6152 DPRINT("Failed to allocate buffer!\n");
6153 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
6158 dwError
= REnumServicesStatusExW(hSCManager
,
6162 (LPBYTE
)lpStatusPtrW
,
6169 /* if no services were returned then we are Done */
6170 if (*lpServicesReturned
== 0)
6173 lpStatusPtrIncrW
= lpStatusPtrW
;
6174 lpStatusPtrA
= (LPENUM_SERVICE_STATUS_PROCESSA
)lpBuffer
;
6175 lpStringPtrA
= (LPSTR
)((ULONG_PTR
)lpBuffer
+
6176 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUS_PROCESSA
));
6177 lpStringPtrW
= (LPWSTR
)((ULONG_PTR
)lpStatusPtrW
+
6178 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUS_PROCESSW
));
6180 for (dwServiceCount
= 0; dwServiceCount
< *lpServicesReturned
; dwServiceCount
++)
6182 /* Copy the service name */
6183 WideCharToMultiByte(CP_ACP
,
6188 (int)wcslen(lpStringPtrW
),
6192 lpStatusPtrA
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
6193 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
6194 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
6196 /* Copy the display name */
6197 WideCharToMultiByte(CP_ACP
,
6202 (int)wcslen(lpStringPtrW
),
6206 lpStatusPtrA
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
6207 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
6208 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
6210 /* Copy the status information */
6211 memcpy(&lpStatusPtrA
->ServiceStatusProcess
,
6212 &lpStatusPtrIncrW
->ServiceStatusProcess
,
6213 sizeof(SERVICE_STATUS
));
6215 /* Copy the service process ID */
6216 lpStatusPtrA
->ServiceStatusProcess
.dwProcessId
= lpStatusPtrIncrW
->ServiceStatusProcess
.dwProcessId
;
6218 lpStatusPtrA
->ServiceStatusProcess
.dwServiceFlags
= 0; /* FIXME */
6226 HeapFree(GetProcessHeap(), 0, pszGroupNameW
);
6229 HeapFree(GetProcessHeap(), 0, lpStatusPtrW
);
6231 DPRINT("REnumServicesStatusExA() done (Error %lu)\n", dwError
);
6240 REnumServicesStatusExW(
6241 SC_RPC_HANDLE hSCManager
,
6242 SC_ENUM_TYPE InfoLevel
,
6243 DWORD dwServiceType
,
6244 DWORD dwServiceState
,
6247 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
6248 LPBOUNDED_DWORD_256K lpServicesReturned
,
6249 LPBOUNDED_DWORD_256K lpResumeIndex
,
6250 LPCWSTR pszGroupName
)
6252 PMANAGER_HANDLE hManager
;
6254 DWORD dwError
= ERROR_SUCCESS
;
6255 PLIST_ENTRY ServiceEntry
;
6256 PSERVICE CurrentService
;
6258 DWORD dwRequiredSize
;
6259 DWORD dwServiceCount
;
6261 DWORD dwLastResumeCount
= 0;
6262 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr
;
6265 DPRINT("REnumServicesStatusExW() called\n");
6268 return ERROR_SHUTDOWN_IN_PROGRESS
;
6270 if (InfoLevel
!= SC_ENUM_PROCESS_INFO
)
6271 return ERROR_INVALID_LEVEL
;
6273 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
6274 if (hManager
== NULL
)
6276 DPRINT1("Invalid service manager handle!\n");
6277 return ERROR_INVALID_HANDLE
;
6280 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
6282 return ERROR_INVALID_ADDRESS
;
6285 *pcbBytesNeeded
= 0;
6286 *lpServicesReturned
= 0;
6288 if ((dwServiceType
== 0) ||
6289 ((dwServiceType
& ~SERVICE_TYPE_ALL
) != 0))
6291 DPRINT("Not a valid Service Type!\n");
6292 return ERROR_INVALID_PARAMETER
;
6295 if ((dwServiceState
== 0) ||
6296 ((dwServiceState
& ~SERVICE_STATE_ALL
) != 0))
6298 DPRINT("Not a valid Service State!\n");
6299 return ERROR_INVALID_PARAMETER
;
6302 /* Check access rights */
6303 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
6304 SC_MANAGER_ENUMERATE_SERVICE
))
6306 DPRINT("Insufficient access rights! 0x%lx\n",
6307 hManager
->Handle
.DesiredAccess
);
6308 return ERROR_ACCESS_DENIED
;
6312 dwLastResumeCount
= *lpResumeIndex
;
6314 /* Lock the service database shared */
6315 ScmLockDatabaseShared();
6317 lpService
= ScmGetServiceEntryByResumeCount(dwLastResumeCount
);
6318 if (lpService
== NULL
)
6320 dwError
= ERROR_SUCCESS
;
6327 for (ServiceEntry
= &lpService
->ServiceListEntry
;
6328 ServiceEntry
!= &ServiceListHead
;
6329 ServiceEntry
= ServiceEntry
->Flink
)
6331 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
6335 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
6338 dwState
= SERVICE_ACTIVE
;
6339 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
6340 dwState
= SERVICE_INACTIVE
;
6342 if ((dwState
& dwServiceState
) == 0)
6347 if (*pszGroupName
== 0)
6349 if (CurrentService
->lpGroup
!= NULL
)
6354 if ((CurrentService
->lpGroup
== NULL
) ||
6355 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
6360 dwSize
= sizeof(ENUM_SERVICE_STATUS_PROCESSW
) +
6361 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
6362 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
6364 if (dwRequiredSize
+ dwSize
<= cbBufSize
)
6366 DPRINT("Service name: %S fit\n", CurrentService
->lpServiceName
);
6367 dwRequiredSize
+= dwSize
;
6369 dwLastResumeCount
= CurrentService
->dwResumeCount
;
6373 DPRINT("Service name: %S no fit\n", CurrentService
->lpServiceName
);
6379 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize
);
6380 DPRINT("dwServiceCount: %lu\n", dwServiceCount
);
6383 ServiceEntry
!= &ServiceListHead
;
6384 ServiceEntry
= ServiceEntry
->Flink
)
6386 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
6390 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
6393 dwState
= SERVICE_ACTIVE
;
6394 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
6395 dwState
= SERVICE_INACTIVE
;
6397 if ((dwState
& dwServiceState
) == 0)
6402 if (*pszGroupName
== 0)
6404 if (CurrentService
->lpGroup
!= NULL
)
6409 if ((CurrentService
->lpGroup
== NULL
) ||
6410 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
6415 dwRequiredSize
+= (sizeof(ENUM_SERVICE_STATUS_PROCESSW
) +
6416 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
6417 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
)));
6419 dwError
= ERROR_MORE_DATA
;
6422 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize
);
6425 *lpResumeIndex
= dwLastResumeCount
;
6427 *lpServicesReturned
= dwServiceCount
;
6428 *pcbBytesNeeded
= dwRequiredSize
;
6430 /* If there was no services that matched */
6431 if ((!dwServiceCount
) && (dwError
!= ERROR_MORE_DATA
))
6433 dwError
= ERROR_SERVICE_DOES_NOT_EXIST
;
6437 lpStatusPtr
= (LPENUM_SERVICE_STATUS_PROCESSW
)lpBuffer
;
6438 lpStringPtr
= (LPWSTR
)((ULONG_PTR
)lpBuffer
+
6439 dwServiceCount
* sizeof(ENUM_SERVICE_STATUS_PROCESSW
));
6442 for (ServiceEntry
= &lpService
->ServiceListEntry
;
6443 ServiceEntry
!= &ServiceListHead
;
6444 ServiceEntry
= ServiceEntry
->Flink
)
6446 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
6450 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
6453 dwState
= SERVICE_ACTIVE
;
6454 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
6455 dwState
= SERVICE_INACTIVE
;
6457 if ((dwState
& dwServiceState
) == 0)
6462 if (*pszGroupName
== 0)
6464 if (CurrentService
->lpGroup
!= NULL
)
6469 if ((CurrentService
->lpGroup
== NULL
) ||
6470 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
6475 dwSize
= sizeof(ENUM_SERVICE_STATUS_PROCESSW
) +
6476 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
6477 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
6479 if (dwRequiredSize
+ dwSize
<= cbBufSize
)
6481 /* Copy the service name */
6483 CurrentService
->lpServiceName
);
6484 lpStatusPtr
->lpServiceName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
6485 lpStringPtr
+= (wcslen(CurrentService
->lpServiceName
) + 1);
6487 /* Copy the display name */
6489 CurrentService
->lpDisplayName
);
6490 lpStatusPtr
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
6491 lpStringPtr
+= (wcslen(CurrentService
->lpDisplayName
) + 1);
6493 /* Copy the status information */
6494 memcpy(&lpStatusPtr
->ServiceStatusProcess
,
6495 &CurrentService
->Status
,
6496 sizeof(SERVICE_STATUS
));
6498 /* Copy the service process ID */
6499 if ((CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
) || (CurrentService
->lpImage
== NULL
))
6500 lpStatusPtr
->ServiceStatusProcess
.dwProcessId
= 0;
6502 lpStatusPtr
->ServiceStatusProcess
.dwProcessId
= CurrentService
->lpImage
->dwProcessId
;
6504 lpStatusPtr
->ServiceStatusProcess
.dwServiceFlags
= 0; /* FIXME */
6507 dwRequiredSize
+= dwSize
;
6517 *pcbBytesNeeded
= 0;
6523 /* Unlock the service database */
6524 ScmUnlockDatabase();
6526 DPRINT("REnumServicesStatusExW() done (Error %lu)\n", dwError
);
6536 handle_t BindingHandle
) /* FIXME */
6539 return ERROR_CALL_NOT_IMPLEMENTED
;
6546 RCreateServiceWOW64A(
6547 handle_t BindingHandle
,
6548 LPSTR lpServiceName
,
6549 LPSTR lpDisplayName
,
6550 DWORD dwDesiredAccess
,
6551 DWORD dwServiceType
,
6553 DWORD dwErrorControl
,
6554 LPSTR lpBinaryPathName
,
6555 LPSTR lpLoadOrderGroup
,
6557 LPBYTE lpDependencies
,
6559 LPSTR lpServiceStartName
,
6562 LPSC_RPC_HANDLE lpServiceHandle
)
6565 return ERROR_CALL_NOT_IMPLEMENTED
;
6572 RCreateServiceWOW64W(
6573 handle_t BindingHandle
,
6574 LPWSTR lpServiceName
,
6575 LPWSTR lpDisplayName
,
6576 DWORD dwDesiredAccess
,
6577 DWORD dwServiceType
,
6579 DWORD dwErrorControl
,
6580 LPWSTR lpBinaryPathName
,
6581 LPWSTR lpLoadOrderGroup
,
6583 LPBYTE lpDependencies
,
6585 LPWSTR lpServiceStartName
,
6588 LPSC_RPC_HANDLE lpServiceHandle
)
6591 return ERROR_CALL_NOT_IMPLEMENTED
;
6598 RQueryServiceTagInfo(
6599 handle_t BindingHandle
) /* FIXME */
6602 return ERROR_CALL_NOT_IMPLEMENTED
;
6609 RNotifyServiceStatusChange(
6610 SC_RPC_HANDLE hService
,
6611 SC_RPC_NOTIFY_PARAMS NotifyParams
,
6612 GUID
*pClientProcessGuid
,
6613 GUID
*pSCMProcessGuid
,
6614 PBOOL pfCreateRemoteQueue
,
6615 LPSC_NOTIFY_RPC_HANDLE phNotify
)
6618 return ERROR_CALL_NOT_IMPLEMENTED
;
6626 SC_NOTIFY_RPC_HANDLE hNotify
,
6627 PSC_RPC_NOTIFY_PARAMS_LIST
*ppNotifyParams
)
6630 return ERROR_CALL_NOT_IMPLEMENTED
;
6638 LPSC_NOTIFY_RPC_HANDLE phNotify
,
6642 return ERROR_CALL_NOT_IMPLEMENTED
;
6650 SC_RPC_HANDLE hService
,
6655 return ERROR_CALL_NOT_IMPLEMENTED
;
6663 SC_RPC_HANDLE hService
,
6668 return ERROR_CALL_NOT_IMPLEMENTED
;
6676 handle_t BindingHandle
) /* FIXME */
6679 return ERROR_CALL_NOT_IMPLEMENTED
;
6686 RValidatePnPService(
6687 handle_t BindingHandle
) /* FIXME */
6690 return ERROR_CALL_NOT_IMPLEMENTED
;
6697 ROpenServiceStatusHandle(
6698 handle_t BindingHandle
) /* FIXME */
6701 return ERROR_CALL_NOT_IMPLEMENTED
;
6709 handle_t BindingHandle
) /* FIXME */
6712 return ERROR_CALL_NOT_IMPLEMENTED
;
6716 void __RPC_FAR
* __RPC_USER
midl_user_allocate(SIZE_T len
)
6718 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
);
6722 void __RPC_USER
midl_user_free(void __RPC_FAR
* ptr
)
6724 HeapFree(GetProcessHeap(), 0, ptr
);
6728 void __RPC_USER
SC_RPC_HANDLE_rundown(SC_RPC_HANDLE hSCObject
)
6730 /* Close the handle */
6731 RCloseServiceHandle(&hSCObject
);
6735 void __RPC_USER
SC_RPC_LOCK_rundown(SC_RPC_LOCK Lock
)
6737 /* Unlock the database */
6738 RUnlockServiceDatabase(&Lock
);
6742 void __RPC_USER
SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE hNotify
)