2 * PROJECT: ReactOS Service Control Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/system/services/rpcserver.c
5 * PURPOSE: RPC server interface for the advapi32 calls
6 * COPYRIGHT: Copyright 2005-2006 Eric Kohl
7 * Copyright 2006-2007 Hervé Poussineau <hpoussin@reactos.org>
8 * Copyright 2007 Ged Murphy <gedmurphy@reactos.org>
11 /* INCLUDES ****************************************************************/
20 /* GLOBALS *****************************************************************/
22 #define MANAGER_TAG 0x72674D68 /* 'hMgr' */
23 #define SERVICE_TAG 0x63765368 /* 'hSvc' */
25 typedef struct _SCMGR_HANDLE
32 typedef struct _MANAGER_HANDLE
35 WCHAR DatabaseName
[1];
36 } MANAGER_HANDLE
, *PMANAGER_HANDLE
;
39 typedef struct _SERVICE_HANDLE
42 PSERVICE ServiceEntry
;
43 } SERVICE_HANDLE
, *PSERVICE_HANDLE
;
46 #define SC_MANAGER_READ \
47 (STANDARD_RIGHTS_READ | \
48 SC_MANAGER_QUERY_LOCK_STATUS | \
49 SC_MANAGER_ENUMERATE_SERVICE)
51 #define SC_MANAGER_WRITE \
52 (STANDARD_RIGHTS_WRITE | \
53 SC_MANAGER_MODIFY_BOOT_CONFIG | \
54 SC_MANAGER_CREATE_SERVICE)
56 #define SC_MANAGER_EXECUTE \
57 (STANDARD_RIGHTS_EXECUTE | \
59 SC_MANAGER_ENUMERATE_SERVICE | \
60 SC_MANAGER_CONNECT | \
61 SC_MANAGER_CREATE_SERVICE)
64 #define SERVICE_READ \
65 (STANDARD_RIGHTS_READ | \
66 SERVICE_INTERROGATE | \
67 SERVICE_ENUMERATE_DEPENDENTS | \
68 SERVICE_QUERY_STATUS | \
71 #define SERVICE_WRITE \
72 (STANDARD_RIGHTS_WRITE | \
73 SERVICE_CHANGE_CONFIG)
75 #define SERVICE_EXECUTE \
76 (STANDARD_RIGHTS_EXECUTE | \
77 SERVICE_USER_DEFINED_CONTROL | \
78 SERVICE_PAUSE_CONTINUE | \
82 #define TAG_ARRAY_SIZE 32
84 /* VARIABLES ***************************************************************/
86 static GENERIC_MAPPING
87 ScmManagerMapping
= {SC_MANAGER_READ
,
90 SC_MANAGER_ALL_ACCESS
};
92 static GENERIC_MAPPING
93 ScmServiceMapping
= {SERVICE_READ
,
99 /* FUNCTIONS ***************************************************************/
102 ScmStartRpcServer(VOID
)
106 DPRINT("ScmStartRpcServer() called\n");
108 Status
= RpcServerUseProtseqEpW(L
"ncacn_np",
112 if (Status
!= RPC_S_OK
)
114 DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status
);
118 Status
= RpcServerRegisterIf(svcctl_v2_0_s_ifspec
,
121 if (Status
!= RPC_S_OK
)
123 DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status
);
127 Status
= RpcServerListen(1, 20, TRUE
);
128 if (Status
!= RPC_S_OK
)
130 DPRINT1("RpcServerListen() failed (Status %lx)\n", Status
);
134 DPRINT("ScmStartRpcServer() done\n");
139 ScmCreateManagerHandle(LPWSTR lpDatabaseName
,
144 if (lpDatabaseName
== NULL
)
145 lpDatabaseName
= SERVICES_ACTIVE_DATABASEW
;
147 if (_wcsicmp(lpDatabaseName
, SERVICES_FAILED_DATABASEW
) == 0)
149 DPRINT("Database %S, does not exist\n", lpDatabaseName
);
150 return ERROR_DATABASE_DOES_NOT_EXIST
;
152 else if (_wcsicmp(lpDatabaseName
, SERVICES_ACTIVE_DATABASEW
) != 0)
154 DPRINT("Invalid Database name %S.\n", lpDatabaseName
);
155 return ERROR_INVALID_NAME
;
158 Ptr
= HeapAlloc(GetProcessHeap(),
160 FIELD_OFFSET(MANAGER_HANDLE
, DatabaseName
[wcslen(lpDatabaseName
) + 1]));
162 return ERROR_NOT_ENOUGH_MEMORY
;
164 Ptr
->Handle
.Tag
= MANAGER_TAG
;
166 wcscpy(Ptr
->DatabaseName
, lpDatabaseName
);
168 *Handle
= (SC_HANDLE
)Ptr
;
170 return ERROR_SUCCESS
;
175 ScmCreateServiceHandle(PSERVICE lpServiceEntry
,
180 Ptr
= HeapAlloc(GetProcessHeap(),
182 sizeof(SERVICE_HANDLE
));
184 return ERROR_NOT_ENOUGH_MEMORY
;
186 Ptr
->Handle
.Tag
= SERVICE_TAG
;
188 Ptr
->ServiceEntry
= lpServiceEntry
;
190 *Handle
= (SC_HANDLE
)Ptr
;
192 return ERROR_SUCCESS
;
196 static PMANAGER_HANDLE
197 ScmGetServiceManagerFromHandle(SC_RPC_HANDLE Handle
)
199 PMANAGER_HANDLE pManager
= NULL
;
203 if (((PMANAGER_HANDLE
)Handle
)->Handle
.Tag
== MANAGER_TAG
)
204 pManager
= (PMANAGER_HANDLE
)Handle
;
206 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
208 DPRINT1("Exception: Invalid Service Manager handle!\n");
216 static PSERVICE_HANDLE
217 ScmGetServiceFromHandle(SC_RPC_HANDLE Handle
)
219 PSERVICE_HANDLE pService
= NULL
;
223 if (((PSERVICE_HANDLE
)Handle
)->Handle
.Tag
== SERVICE_TAG
)
224 pService
= (PSERVICE_HANDLE
)Handle
;
226 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
228 DPRINT1("Exception: Invalid Service handle!\n");
237 ScmCheckAccess(SC_HANDLE Handle
,
238 DWORD dwDesiredAccess
)
240 PMANAGER_HANDLE hMgr
;
242 hMgr
= (PMANAGER_HANDLE
)Handle
;
243 if (hMgr
->Handle
.Tag
== MANAGER_TAG
)
245 RtlMapGenericMask(&dwDesiredAccess
,
248 hMgr
->Handle
.DesiredAccess
= dwDesiredAccess
;
250 return ERROR_SUCCESS
;
252 else if (hMgr
->Handle
.Tag
== SERVICE_TAG
)
254 RtlMapGenericMask(&dwDesiredAccess
,
257 hMgr
->Handle
.DesiredAccess
= dwDesiredAccess
;
259 return ERROR_SUCCESS
;
262 return ERROR_INVALID_HANDLE
;
267 ScmAssignNewTag(PSERVICE lpService
)
271 DWORD dwGroupTagCount
= 0;
272 PDWORD pdwGroupTags
= NULL
;
274 DWORD dwTagUsedBase
= 1;
275 BOOLEAN TagUsed
[TAG_ARRAY_SIZE
];
279 PLIST_ENTRY ServiceEntry
;
280 PSERVICE CurrentService
;
282 ASSERT(lpService
!= NULL
);
283 ASSERT(lpService
->lpGroup
!= NULL
);
285 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
286 L
"System\\CurrentControlSet\\Control\\GroupOrderList",
291 if (dwError
!= ERROR_SUCCESS
)
294 /* query value length */
296 dwError
= RegQueryValueExW(hKey
,
297 lpService
->lpGroup
->szGroupName
,
303 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_MORE_DATA
)
306 pdwGroupTags
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, cbDataSize
);
309 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
313 dwError
= RegQueryValueExW(hKey
,
314 lpService
->lpGroup
->szGroupName
,
317 (LPBYTE
)pdwGroupTags
,
320 if (dwError
!= ERROR_SUCCESS
)
323 if (cbDataSize
< sizeof(pdwGroupTags
[0]))
326 dwGroupTagCount
= min(pdwGroupTags
[0], cbDataSize
/ sizeof(pdwGroupTags
[0]) - 1);
331 /* mark all tags as unused */
332 for (i
= 0; i
< TAG_ARRAY_SIZE
; i
++)
335 /* mark tags in GroupOrderList as used */
336 for (i
= 1; i
<= dwGroupTagCount
; i
++)
338 nTagOffset
= pdwGroupTags
[i
] - dwTagUsedBase
;
339 if (nTagOffset
>= 0 && nTagOffset
< TAG_ARRAY_SIZE
)
340 TagUsed
[nTagOffset
] = TRUE
;
343 /* mark tags in service list as used */
344 ServiceEntry
= lpService
->ServiceListEntry
.Flink
;
345 while (ServiceEntry
!= &lpService
->ServiceListEntry
)
347 ASSERT(ServiceEntry
!= NULL
);
348 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
349 if (CurrentService
->lpGroup
== lpService
->lpGroup
)
351 nTagOffset
= CurrentService
->dwTag
- dwTagUsedBase
;
352 if (nTagOffset
>= 0 && nTagOffset
< TAG_ARRAY_SIZE
)
353 TagUsed
[nTagOffset
] = TRUE
;
356 ServiceEntry
= ServiceEntry
->Flink
;
359 /* find unused tag, if any */
360 for (i
= 0; i
< TAG_ARRAY_SIZE
; i
++)
364 dwFreeTag
= dwTagUsedBase
+ i
;
369 dwTagUsedBase
+= TAG_ARRAY_SIZE
;
370 } while (!dwFreeTag
);
374 HeapFree(GetProcessHeap(), 0, pdwGroupTags
);
381 lpService
->dwTag
= dwFreeTag
;
382 DPRINT("Assigning new tag %lu to service %S in group %S\n",
383 lpService
->dwTag
, lpService
->lpServiceName
, lpService
->lpGroup
->szGroupName
);
384 dwError
= ERROR_SUCCESS
;
388 DPRINT1("Failed to assign new tag to service %S, error=%lu\n",
389 lpService
->lpServiceName
, dwError
);
396 /* Create a path suitable for the bootloader out of the full path */
398 ScmConvertToBootPathName(wchar_t *CanonName
, wchar_t **RelativeName
)
400 SIZE_T ServiceNameLen
, ExpandedLen
;
404 UNICODE_STRING NtPathName
, SystemRoot
, LinkTarget
;
405 OBJECT_ATTRIBUTES ObjectAttributes
;
407 HANDLE SymbolicLinkHandle
;
409 DPRINT("ScmConvertToBootPathName %S\n", CanonName
);
412 return ERROR_INVALID_PARAMETER
;
414 *RelativeName
= NULL
;
416 ServiceNameLen
= wcslen(CanonName
);
418 /* First check, if it's already good */
419 if (ServiceNameLen
> 12 &&
420 !_wcsnicmp(L
"\\SystemRoot\\", CanonName
, 12))
422 *RelativeName
= HeapAlloc(GetProcessHeap(),
424 (ServiceNameLen
+ 1) * sizeof(WCHAR
));
425 if (*RelativeName
== NULL
)
427 DPRINT("Error allocating memory for boot driver name!\n");
428 return ERROR_NOT_ENOUGH_MEMORY
;
432 wcscpy(*RelativeName
, CanonName
);
434 DPRINT("Bootdriver name %S\n", *RelativeName
);
435 return ERROR_SUCCESS
;
438 /* If it has %SystemRoot% prefix, substitute it to \System*/
439 if (ServiceNameLen
> 13 &&
440 !_wcsnicmp(L
"%SystemRoot%\\", CanonName
, 13))
442 /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */
443 *RelativeName
= HeapAlloc(GetProcessHeap(),
445 ServiceNameLen
* sizeof(WCHAR
));
447 if (*RelativeName
== NULL
)
449 DPRINT("Error allocating memory for boot driver name!\n");
450 return ERROR_NOT_ENOUGH_MEMORY
;
454 wcscpy(*RelativeName
, L
"\\SystemRoot\\");
455 wcscat(*RelativeName
, CanonName
+ 13);
457 DPRINT("Bootdriver name %S\n", *RelativeName
);
458 return ERROR_SUCCESS
;
461 /* Get buffer size needed for expanding env strings */
462 BufferSize
= ExpandEnvironmentStringsW(L
"%SystemRoot%\\", &Dest
, 1);
466 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
467 return ERROR_INVALID_ENVIRONMENT
;
470 /* Allocate memory, since the size is known now */
471 Expanded
= HeapAlloc(GetProcessHeap(),
473 (BufferSize
+ 1) * sizeof(WCHAR
));
476 DPRINT("Error allocating memory for boot driver name!\n");
477 return ERROR_NOT_ENOUGH_MEMORY
;
481 if (ExpandEnvironmentStringsW(L
"%SystemRoot%\\", Expanded
, BufferSize
) >
484 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
485 HeapFree(GetProcessHeap(), 0, Expanded
);
486 return ERROR_NOT_ENOUGH_MEMORY
;
489 /* Convert to NT-style path */
490 if (!RtlDosPathNameToNtPathName_U(Expanded
, &NtPathName
, NULL
, NULL
))
492 DPRINT("Error during a call to RtlDosPathNameToNtPathName_U()\n");
493 return ERROR_INVALID_ENVIRONMENT
;
496 DPRINT("Converted to NT-style %wZ\n", &NtPathName
);
498 /* No need to keep the dos-path anymore */
499 HeapFree(GetProcessHeap(), 0, Expanded
);
501 /* Copy it to the allocated place */
502 Expanded
= HeapAlloc(GetProcessHeap(),
504 NtPathName
.Length
+ sizeof(UNICODE_NULL
));
507 DPRINT("Error allocating memory for boot driver name!\n");
508 return ERROR_NOT_ENOUGH_MEMORY
;
511 ExpandedLen
= NtPathName
.Length
/ sizeof(WCHAR
);
512 wcsncpy(Expanded
, NtPathName
.Buffer
, ExpandedLen
);
513 Expanded
[ExpandedLen
] = UNICODE_NULL
;
515 if (ServiceNameLen
> ExpandedLen
&&
516 !_wcsnicmp(Expanded
, CanonName
, ExpandedLen
))
518 /* Only \SystemRoot\ is missing */
519 *RelativeName
= HeapAlloc(GetProcessHeap(),
521 (ServiceNameLen
- ExpandedLen
) * sizeof(WCHAR
) + 13*sizeof(WCHAR
));
522 if (*RelativeName
== NULL
)
524 DPRINT("Error allocating memory for boot driver name!\n");
525 HeapFree(GetProcessHeap(), 0, Expanded
);
526 return ERROR_NOT_ENOUGH_MEMORY
;
529 wcscpy(*RelativeName
, L
"\\SystemRoot\\");
530 wcscat(*RelativeName
, CanonName
+ ExpandedLen
);
532 RtlFreeUnicodeString(&NtPathName
);
533 return ERROR_SUCCESS
;
536 /* The most complex case starts here */
537 RtlInitUnicodeString(&SystemRoot
, L
"\\SystemRoot");
538 InitializeObjectAttributes(&ObjectAttributes
,
540 OBJ_CASE_INSENSITIVE
,
544 /* Open this symlink */
545 Status
= NtOpenSymbolicLinkObject(&SymbolicLinkHandle
, SYMBOLIC_LINK_QUERY
, &ObjectAttributes
);
547 if (NT_SUCCESS(Status
))
549 LinkTarget
.Length
= 0;
550 LinkTarget
.MaximumLength
= 0;
552 DPRINT("Opened symbolic link object\n");
554 Status
= NtQuerySymbolicLinkObject(SymbolicLinkHandle
, &LinkTarget
, &BufferSize
);
555 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_TOO_SMALL
)
557 /* Check if required buffer size is sane */
558 if (BufferSize
> 0xFFFD)
560 DPRINT("Too large buffer required\n");
562 if (SymbolicLinkHandle
) NtClose(SymbolicLinkHandle
);
563 HeapFree(GetProcessHeap(), 0, Expanded
);
564 return ERROR_NOT_ENOUGH_MEMORY
;
567 /* Alloc the string */
568 LinkTarget
.Length
= (USHORT
)BufferSize
;
569 LinkTarget
.MaximumLength
= LinkTarget
.Length
+ sizeof(UNICODE_NULL
);
570 LinkTarget
.Buffer
= HeapAlloc(GetProcessHeap(),
572 LinkTarget
.MaximumLength
);
573 if (!LinkTarget
.Buffer
)
575 DPRINT("Unable to alloc buffer\n");
576 if (SymbolicLinkHandle
) NtClose(SymbolicLinkHandle
);
577 HeapFree(GetProcessHeap(), 0, Expanded
);
578 return ERROR_NOT_ENOUGH_MEMORY
;
581 /* Do a real query now */
582 Status
= NtQuerySymbolicLinkObject(SymbolicLinkHandle
, &LinkTarget
, &BufferSize
);
583 if (NT_SUCCESS(Status
))
585 DPRINT("LinkTarget: %wZ\n", &LinkTarget
);
587 ExpandedLen
= LinkTarget
.Length
/ sizeof(WCHAR
);
588 if ((ServiceNameLen
> ExpandedLen
) &&
589 !_wcsnicmp(LinkTarget
.Buffer
, CanonName
, ExpandedLen
))
591 *RelativeName
= HeapAlloc(GetProcessHeap(),
593 (ServiceNameLen
- ExpandedLen
) * sizeof(WCHAR
) + 13*sizeof(WCHAR
));
595 if (*RelativeName
== NULL
)
597 DPRINT("Unable to alloc buffer\n");
598 if (SymbolicLinkHandle
) NtClose(SymbolicLinkHandle
);
599 HeapFree(GetProcessHeap(), 0, Expanded
);
600 RtlFreeUnicodeString(&NtPathName
);
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 if (SymbolicLinkHandle
) NtClose(SymbolicLinkHandle
);
611 HeapFree(GetProcessHeap(), 0, Expanded
);
612 RtlFreeUnicodeString(&NtPathName
);
615 return ERROR_SUCCESS
;
619 if (SymbolicLinkHandle
) NtClose(SymbolicLinkHandle
);
620 HeapFree(GetProcessHeap(), 0, Expanded
);
621 RtlFreeUnicodeString(&NtPathName
);
622 return ERROR_INVALID_PARAMETER
;
627 DPRINT("Error, Status = %08X\n", Status
);
628 if (SymbolicLinkHandle
) NtClose(SymbolicLinkHandle
);
629 HeapFree(GetProcessHeap(), 0, Expanded
);
630 RtlFreeUnicodeString(&NtPathName
);
631 return ERROR_INVALID_PARAMETER
;
636 DPRINT("Error, Status = %08X\n", Status
);
637 if (SymbolicLinkHandle
) NtClose(SymbolicLinkHandle
);
638 HeapFree(GetProcessHeap(), 0, Expanded
);
639 RtlFreeUnicodeString(&NtPathName
);
640 return ERROR_INVALID_PARAMETER
;
646 DPRINT("Error, Status = %08X\n", Status
);
647 HeapFree(GetProcessHeap(), 0, Expanded
);
648 return ERROR_INVALID_PARAMETER
;
654 ScmCanonDriverImagePath(DWORD dwStartType
,
655 const wchar_t *lpServiceName
,
656 wchar_t **lpCanonName
)
659 SIZE_T ServiceNameLen
;
660 UNICODE_STRING NtServiceName
;
662 const WCHAR
*SourceName
= lpServiceName
;
664 /* Calculate the length of the service's name */
665 ServiceNameLen
= wcslen(lpServiceName
);
667 /* 12 is wcslen(L"\\SystemRoot\\") */
668 if (ServiceNameLen
> 12 &&
669 !_wcsnicmp(L
"\\SystemRoot\\", lpServiceName
, 12))
671 /* SystemRoot prefix is already included */
672 *lpCanonName
= HeapAlloc(GetProcessHeap(),
674 (ServiceNameLen
+ 1) * sizeof(WCHAR
));
676 if (*lpCanonName
== NULL
)
678 DPRINT("Error allocating memory for canonized service name!\n");
679 return ERROR_NOT_ENOUGH_MEMORY
;
682 /* If it's a boot-time driver, it must be systemroot relative */
683 if (dwStartType
== SERVICE_BOOT_START
)
687 wcscpy(*lpCanonName
, SourceName
);
689 DPRINT("Canonicalized name %S\n", *lpCanonName
);
693 /* Check if it has %SystemRoot% (len=13) */
694 if (ServiceNameLen
> 13 &&
695 !_wcsnicmp(L
"%SystemRoot%\\", lpServiceName
, 13))
697 /* Substitute %SystemRoot% with \\SystemRoot\\ */
698 *lpCanonName
= HeapAlloc(GetProcessHeap(),
700 (ServiceNameLen
+ 1) * sizeof(WCHAR
));
702 if (*lpCanonName
== NULL
)
704 DPRINT("Error allocating memory for canonized service name!\n");
705 return ERROR_NOT_ENOUGH_MEMORY
;
708 /* If it's a boot-time driver, it must be systemroot relative */
709 if (dwStartType
== SERVICE_BOOT_START
)
710 wcscpy(*lpCanonName
, L
"\\SystemRoot\\");
712 wcscat(*lpCanonName
, lpServiceName
+ 13);
714 DPRINT("Canonicalized name %S\n", *lpCanonName
);
718 /* Check if it's a relative path name */
719 if (lpServiceName
[0] != L
'\\' && lpServiceName
[1] != L
':')
721 *lpCanonName
= HeapAlloc(GetProcessHeap(),
723 (ServiceNameLen
+ 1) * sizeof(WCHAR
));
725 if (*lpCanonName
== NULL
)
727 DPRINT("Error allocating memory for canonized service name!\n");
728 return ERROR_NOT_ENOUGH_MEMORY
;
731 /* Just copy it over without changing */
732 wcscpy(*lpCanonName
, lpServiceName
);
737 /* It seems to be a DOS path, convert it */
738 if (!RtlDosPathNameToNtPathName_U(lpServiceName
, &NtServiceName
, NULL
, NULL
))
740 DPRINT("RtlDosPathNameToNtPathName_U() failed!\n");
741 return ERROR_INVALID_PARAMETER
;
744 *lpCanonName
= HeapAlloc(GetProcessHeap(),
746 NtServiceName
.Length
+ sizeof(WCHAR
));
748 if (*lpCanonName
== NULL
)
750 DPRINT("Error allocating memory for canonized service name!\n");
751 RtlFreeUnicodeString(&NtServiceName
);
752 return ERROR_NOT_ENOUGH_MEMORY
;
755 /* Copy the string */
756 wcsncpy(*lpCanonName
, NtServiceName
.Buffer
, NtServiceName
.Length
/ sizeof(WCHAR
));
758 /* The unicode string is not needed anymore */
759 RtlFreeUnicodeString(&NtServiceName
);
761 if (dwStartType
!= SERVICE_BOOT_START
)
763 DPRINT("Canonicalized name %S\n", *lpCanonName
);
767 /* The service is boot-started, so must be relative */
768 Result
= ScmConvertToBootPathName(*lpCanonName
, &RelativeName
);
771 /* There is a problem, free name and return */
772 HeapFree(GetProcessHeap(), 0, *lpCanonName
);
773 DPRINT("Error converting named!\n");
777 ASSERT(RelativeName
);
779 /* Copy that string */
780 wcscpy(*lpCanonName
, RelativeName
+ 12);
782 /* Free the allocated buffer */
783 HeapFree(GetProcessHeap(), 0, RelativeName
);
785 DPRINT("Canonicalized name %S\n", *lpCanonName
);
792 /* Internal recursive function */
793 /* Need to search for every dependency on every service */
795 Int_EnumDependentServicesW(HKEY hServicesKey
,
797 DWORD dwServiceState
,
798 PSERVICE
*lpServices
,
799 LPDWORD pcbBytesNeeded
,
800 LPDWORD lpServicesReturned
)
802 DWORD dwError
= ERROR_SUCCESS
;
803 WCHAR szNameBuf
[MAX_PATH
];
804 WCHAR szValueBuf
[MAX_PATH
];
805 WCHAR
*lpszNameBuf
= szNameBuf
;
806 WCHAR
*lpszValueBuf
= szValueBuf
;
810 PSERVICE lpCurrentService
;
811 HKEY hServiceEnumKey
;
812 DWORD dwCurrentServiceState
= SERVICE_ACTIVE
;
813 DWORD dwDependServiceStrPtr
= 0;
814 DWORD dwRequiredSize
= 0;
816 /* Get the number of service keys */
817 dwError
= RegQueryInfoKeyW(hServicesKey
,
829 if (dwError
!= ERROR_SUCCESS
)
831 DPRINT("ERROR! Unable to get number of services keys.\n");
835 /* Iterate the service keys to see if another service depends on the this service */
836 for (dwIteration
= 0; dwIteration
< dwNumSubKeys
; dwIteration
++)
839 dwError
= RegEnumKeyExW(hServicesKey
,
847 if (dwError
!= ERROR_SUCCESS
)
850 /* Open the Service key */
851 dwError
= RegOpenKeyExW(hServicesKey
,
856 if (dwError
!= ERROR_SUCCESS
)
861 /* Check for the DependOnService Value */
862 dwError
= RegQueryValueExW(hServiceEnumKey
,
866 (LPBYTE
)lpszValueBuf
,
869 /* FIXME: Handle load order. */
871 /* If the service found has a DependOnService value */
872 if (dwError
== ERROR_SUCCESS
)
874 dwDependServiceStrPtr
= 0;
876 /* Can be more than one Dependencies in the DependOnService string */
877 while (wcslen(lpszValueBuf
+ dwDependServiceStrPtr
) > 0)
879 if (_wcsicmp(lpszValueBuf
+ dwDependServiceStrPtr
, lpService
->lpServiceName
) == 0)
881 /* Get the current enumed service pointer */
882 lpCurrentService
= ScmGetServiceEntryByName(lpszNameBuf
);
884 /* Check for valid Service */
885 if (!lpCurrentService
)
887 /* This should never happen! */
888 DPRINT("This should not happen at this point, report to Developer\n");
889 return ERROR_NOT_FOUND
;
892 /* Determine state the service is in */
893 if (lpCurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
894 dwCurrentServiceState
= SERVICE_INACTIVE
;
896 /* If the ServiceState matches that requested or searching for SERVICE_STATE_ALL */
897 if ((dwCurrentServiceState
== dwServiceState
) ||
898 (dwServiceState
== SERVICE_STATE_ALL
))
900 /* Calculate the required size */
901 dwRequiredSize
+= sizeof(SERVICE_STATUS
);
902 dwRequiredSize
+= (DWORD
)((wcslen(lpCurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
));
903 dwRequiredSize
+= (DWORD
)((wcslen(lpCurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
905 /* Add the size for service name and display name pointers */
906 dwRequiredSize
+= (2 * sizeof(PVOID
));
908 /* increase the BytesNeeded size */
909 *pcbBytesNeeded
= *pcbBytesNeeded
+ dwRequiredSize
;
911 /* Don't fill callers buffer yet, as MSDN read that the last service with dependency
914 /* Recursive call to check for its dependencies */
915 Int_EnumDependentServicesW(hServicesKey
,
922 /* If the lpServices is valid set the service pointer */
924 lpServices
[*lpServicesReturned
] = lpCurrentService
;
926 *lpServicesReturned
= *lpServicesReturned
+ 1;
930 dwDependServiceStrPtr
+= (DWORD
)(wcslen(lpszValueBuf
+ dwDependServiceStrPtr
) + 1);
933 else if (*pcbBytesNeeded
)
935 dwError
= ERROR_SUCCESS
;
938 RegCloseKey(hServiceEnumKey
);
946 DWORD
RCloseServiceHandle(
947 LPSC_RPC_HANDLE hSCObject
)
949 PMANAGER_HANDLE hManager
;
950 PSERVICE_HANDLE hService
;
954 DWORD pcbBytesNeeded
= 0;
955 DWORD dwServicesReturned
= 0;
957 DPRINT("RCloseServiceHandle() called\n");
959 DPRINT("hSCObject = %p\n", *hSCObject
);
962 return ERROR_INVALID_HANDLE
;
964 hManager
= ScmGetServiceManagerFromHandle(*hSCObject
);
965 hService
= ScmGetServiceFromHandle(*hSCObject
);
967 if (hManager
!= NULL
)
969 DPRINT("Found manager handle\n");
971 /* FIXME: add handle cleanup code */
973 HeapFree(GetProcessHeap(), 0, hManager
);
978 DPRINT("RCloseServiceHandle() done\n");
979 return ERROR_SUCCESS
;
981 else if (hService
!= NULL
)
983 DPRINT("Found service handle\n");
985 /* Lock the service database exlusively */
986 ScmLockDatabaseExclusive();
988 /* Get the pointer to the service record */
989 lpService
= hService
->ServiceEntry
;
991 /* FIXME: add handle cleanup code */
993 /* Free the handle */
994 HeapFree(GetProcessHeap(), 0, hService
);
997 ASSERT(lpService
->dwRefCount
> 0);
999 lpService
->dwRefCount
--;
1000 DPRINT("CloseServiceHandle - lpService->dwRefCount %u\n",
1001 lpService
->dwRefCount
);
1003 if (lpService
->dwRefCount
== 0)
1005 /* If this service has been marked for deletion */
1006 if (lpService
->bDeleted
)
1008 /* Open the Services Reg key */
1009 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1010 L
"System\\CurrentControlSet\\Services",
1012 KEY_SET_VALUE
| KEY_READ
,
1014 if (dwError
!= ERROR_SUCCESS
)
1016 DPRINT("Failed to open services key\n");
1017 ScmUnlockDatabase();
1021 /* Call the internal function with NULL, just to get bytes we need */
1022 Int_EnumDependentServicesW(hServicesKey
,
1027 &dwServicesReturned
);
1029 /* if pcbBytesNeeded returned a value then there are services running that are dependent on this service */
1032 DPRINT("Deletion failed due to running dependencies.\n");
1033 RegCloseKey(hServicesKey
);
1034 ScmUnlockDatabase();
1035 return ERROR_SUCCESS
;
1038 /* There are no references and no runnning dependencies,
1039 it is now safe to delete the service */
1041 /* Delete the Service Key */
1042 dwError
= RegDeleteKeyW(hServicesKey
,
1043 lpService
->lpServiceName
);
1045 RegCloseKey(hServicesKey
);
1047 if (dwError
!= ERROR_SUCCESS
)
1049 DPRINT("Failed to Delete the Service Registry key\n");
1050 ScmUnlockDatabase();
1054 /* Delete the Service */
1055 ScmDeleteServiceRecord(lpService
);
1059 ScmUnlockDatabase();
1063 DPRINT("RCloseServiceHandle() done\n");
1064 return ERROR_SUCCESS
;
1067 DPRINT("Invalid handle tag (Tag %lx)\n", hManager
->Handle
.Tag
);
1069 return ERROR_INVALID_HANDLE
;
1074 DWORD
RControlService(
1075 SC_RPC_HANDLE hService
,
1077 LPSERVICE_STATUS lpServiceStatus
)
1079 PSERVICE_HANDLE hSvc
;
1081 ACCESS_MASK DesiredAccess
;
1082 DWORD dwError
= ERROR_SUCCESS
;
1083 DWORD pcbBytesNeeded
= 0;
1084 DWORD dwServicesReturned
= 0;
1085 DWORD dwControlsAccepted
;
1086 DWORD dwCurrentState
;
1087 HKEY hServicesKey
= NULL
;
1089 DPRINT("RControlService() called\n");
1092 return ERROR_SHUTDOWN_IN_PROGRESS
;
1094 /* Check the service handle */
1095 hSvc
= ScmGetServiceFromHandle(hService
);
1098 DPRINT1("Invalid service handle!\n");
1099 return ERROR_INVALID_HANDLE
;
1102 /* Check the service entry point */
1103 lpService
= hSvc
->ServiceEntry
;
1104 if (lpService
== NULL
)
1106 DPRINT1("lpService == NULL!\n");
1107 return ERROR_INVALID_HANDLE
;
1110 /* Check access rights */
1113 case SERVICE_CONTROL_STOP
:
1114 DesiredAccess
= SERVICE_STOP
;
1117 case SERVICE_CONTROL_PAUSE
:
1118 case SERVICE_CONTROL_CONTINUE
:
1119 DesiredAccess
= SERVICE_PAUSE_CONTINUE
;
1122 case SERVICE_CONTROL_INTERROGATE
:
1123 DesiredAccess
= SERVICE_INTERROGATE
;
1127 if (dwControl
>= 128 && dwControl
<= 255)
1128 DesiredAccess
= SERVICE_USER_DEFINED_CONTROL
;
1130 return ERROR_INVALID_PARAMETER
;
1134 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1136 return ERROR_ACCESS_DENIED
;
1138 /* Return the current service status information */
1139 RtlCopyMemory(lpServiceStatus
,
1141 sizeof(SERVICE_STATUS
));
1143 if (dwControl
== SERVICE_CONTROL_STOP
)
1145 /* Check if the service has dependencies running as windows
1146 doesn't stop a service that does */
1148 /* Open the Services Reg key */
1149 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1150 L
"System\\CurrentControlSet\\Services",
1154 if (dwError
!= ERROR_SUCCESS
)
1156 DPRINT("Failed to open services key\n");
1160 /* Call the internal function with NULL, just to get bytes we need */
1161 Int_EnumDependentServicesW(hServicesKey
,
1166 &dwServicesReturned
);
1168 RegCloseKey(hServicesKey
);
1170 /* If pcbBytesNeeded is not zero then there are services running that
1171 are dependent on this service */
1172 if (pcbBytesNeeded
!= 0)
1174 DPRINT("Service has running dependencies. Failed to stop service.\n");
1175 return ERROR_DEPENDENT_SERVICES_RUNNING
;
1179 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
1181 /* Send control code to the driver */
1182 dwError
= ScmControlDriver(lpService
,
1188 dwControlsAccepted
= lpService
->Status
.dwControlsAccepted
;
1189 dwCurrentState
= lpService
->Status
.dwCurrentState
;
1191 /* Return ERROR_SERVICE_NOT_ACTIVE if the service has not been started */
1192 if (lpService
->lpImage
== NULL
|| dwCurrentState
== SERVICE_STOPPED
)
1193 return ERROR_SERVICE_NOT_ACTIVE
;
1195 /* Check the current state before sending a control request */
1196 switch (dwCurrentState
)
1198 case SERVICE_STOP_PENDING
:
1199 case SERVICE_STOPPED
:
1200 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL
;
1202 case SERVICE_START_PENDING
:
1205 case SERVICE_CONTROL_STOP
:
1208 case SERVICE_CONTROL_INTERROGATE
:
1209 RtlCopyMemory(lpServiceStatus
,
1211 sizeof(SERVICE_STATUS
));
1212 return ERROR_SUCCESS
;
1215 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL
;
1220 /* Check if the control code is acceptable to the service */
1223 case SERVICE_CONTROL_STOP
:
1224 if ((dwControlsAccepted
& SERVICE_ACCEPT_STOP
) == 0)
1225 return ERROR_INVALID_SERVICE_CONTROL
;
1228 case SERVICE_CONTROL_PAUSE
:
1229 case SERVICE_CONTROL_CONTINUE
:
1230 if ((dwControlsAccepted
& SERVICE_ACCEPT_PAUSE_CONTINUE
) == 0)
1231 return ERROR_INVALID_SERVICE_CONTROL
;
1235 /* Send control code to the service */
1236 dwError
= ScmControlService(lpService
,
1239 /* Return service status information */
1240 RtlCopyMemory(lpServiceStatus
,
1242 sizeof(SERVICE_STATUS
));
1250 DWORD
RDeleteService(
1251 SC_RPC_HANDLE hService
)
1253 PSERVICE_HANDLE hSvc
;
1257 DPRINT("RDeleteService() called\n");
1260 return ERROR_SHUTDOWN_IN_PROGRESS
;
1262 hSvc
= ScmGetServiceFromHandle(hService
);
1265 DPRINT1("Invalid service handle!\n");
1266 return ERROR_INVALID_HANDLE
;
1269 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1271 return ERROR_ACCESS_DENIED
;
1273 lpService
= hSvc
->ServiceEntry
;
1274 if (lpService
== NULL
)
1276 DPRINT("lpService == NULL!\n");
1277 return ERROR_INVALID_HANDLE
;
1280 /* Lock the service database exclusively */
1281 ScmLockDatabaseExclusive();
1283 if (lpService
->bDeleted
)
1285 DPRINT("The service has already been marked for delete!\n");
1286 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
1290 /* Mark service for delete */
1291 lpService
->bDeleted
= TRUE
;
1293 dwError
= ScmMarkServiceForDelete(lpService
);
1296 /* Unlock the service database */
1297 ScmUnlockDatabase();
1299 DPRINT("RDeleteService() done\n");
1306 DWORD
RLockServiceDatabase(
1307 SC_RPC_HANDLE hSCManager
,
1308 LPSC_RPC_LOCK lpLock
)
1310 PMANAGER_HANDLE hMgr
;
1312 DPRINT("RLockServiceDatabase() called\n");
1316 hMgr
= ScmGetServiceManagerFromHandle(hSCManager
);
1319 DPRINT1("Invalid service manager handle!\n");
1320 return ERROR_INVALID_HANDLE
;
1323 if (!RtlAreAllAccessesGranted(hMgr
->Handle
.DesiredAccess
,
1325 return ERROR_ACCESS_DENIED
;
1327 return ScmAcquireServiceStartLock(FALSE
, lpLock
);
1332 DWORD
RQueryServiceObjectSecurity(
1333 SC_RPC_HANDLE hService
,
1334 SECURITY_INFORMATION dwSecurityInformation
,
1335 LPBYTE lpSecurityDescriptor
,
1337 LPBOUNDED_DWORD_256K pcbBytesNeeded
)
1339 PSERVICE_HANDLE hSvc
;
1341 ULONG DesiredAccess
= 0;
1343 DWORD dwBytesNeeded
;
1347 SECURITY_DESCRIPTOR ObjectDescriptor
;
1349 DPRINT("RQueryServiceObjectSecurity() called\n");
1351 hSvc
= ScmGetServiceFromHandle(hService
);
1354 DPRINT1("Invalid service handle!\n");
1355 return ERROR_INVALID_HANDLE
;
1358 if (dwSecurityInformation
& (DACL_SECURITY_INFORMATION
|
1359 GROUP_SECURITY_INFORMATION
|
1360 OWNER_SECURITY_INFORMATION
))
1361 DesiredAccess
|= READ_CONTROL
;
1363 if (dwSecurityInformation
& SACL_SECURITY_INFORMATION
)
1364 DesiredAccess
|= ACCESS_SYSTEM_SECURITY
;
1366 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1369 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1370 return ERROR_ACCESS_DENIED
;
1373 lpService
= hSvc
->ServiceEntry
;
1374 if (lpService
== NULL
)
1376 DPRINT("lpService == NULL!\n");
1377 return ERROR_INVALID_HANDLE
;
1380 /* Lock the service database */
1381 ScmLockDatabaseShared();
1385 Status
= RtlCreateSecurityDescriptor(&ObjectDescriptor
, SECURITY_DESCRIPTOR_REVISION
);
1387 Status
= RtlQuerySecurityObject(&ObjectDescriptor
/* lpService->lpSecurityDescriptor */,
1388 dwSecurityInformation
,
1389 (PSECURITY_DESCRIPTOR
)lpSecurityDescriptor
,
1393 /* Unlock the service database */
1394 ScmUnlockDatabase();
1396 if (NT_SUCCESS(Status
))
1398 *pcbBytesNeeded
= dwBytesNeeded
;
1399 dwError
= STATUS_SUCCESS
;
1401 else if (Status
== STATUS_BUFFER_TOO_SMALL
)
1403 *pcbBytesNeeded
= dwBytesNeeded
;
1404 dwError
= ERROR_INSUFFICIENT_BUFFER
;
1406 else if (Status
== STATUS_BAD_DESCRIPTOR_FORMAT
)
1408 dwError
= ERROR_GEN_FAILURE
;
1412 dwError
= RtlNtStatusToDosError(Status
);
1420 DWORD
RSetServiceObjectSecurity(
1421 SC_RPC_HANDLE hService
,
1422 DWORD dwSecurityInformation
,
1423 LPBYTE lpSecurityDescriptor
,
1424 DWORD dwSecuityDescriptorSize
)
1426 PSERVICE_HANDLE hSvc
;
1428 ULONG DesiredAccess
= 0;
1429 /* HANDLE hToken = NULL; */
1431 /* NTSTATUS Status; */
1434 DPRINT("RSetServiceObjectSecurity() called\n");
1436 hSvc
= ScmGetServiceFromHandle(hService
);
1439 DPRINT1("Invalid service handle!\n");
1440 return ERROR_INVALID_HANDLE
;
1443 if (dwSecurityInformation
== 0 ||
1444 dwSecurityInformation
& ~(OWNER_SECURITY_INFORMATION
| GROUP_SECURITY_INFORMATION
1445 | DACL_SECURITY_INFORMATION
| SACL_SECURITY_INFORMATION
))
1446 return ERROR_INVALID_PARAMETER
;
1448 if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR
)lpSecurityDescriptor
))
1449 return ERROR_INVALID_PARAMETER
;
1451 if (dwSecurityInformation
& SACL_SECURITY_INFORMATION
)
1452 DesiredAccess
|= ACCESS_SYSTEM_SECURITY
;
1454 if (dwSecurityInformation
& DACL_SECURITY_INFORMATION
)
1455 DesiredAccess
|= WRITE_DAC
;
1457 if (dwSecurityInformation
& (OWNER_SECURITY_INFORMATION
| GROUP_SECURITY_INFORMATION
))
1458 DesiredAccess
|= WRITE_OWNER
;
1460 if ((dwSecurityInformation
& OWNER_SECURITY_INFORMATION
) &&
1461 (((PISECURITY_DESCRIPTOR
)lpSecurityDescriptor
)->Owner
== NULL
))
1462 return ERROR_INVALID_PARAMETER
;
1464 if ((dwSecurityInformation
& GROUP_SECURITY_INFORMATION
) &&
1465 (((PISECURITY_DESCRIPTOR
)lpSecurityDescriptor
)->Group
== NULL
))
1466 return ERROR_INVALID_PARAMETER
;
1468 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1471 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1472 return ERROR_ACCESS_DENIED
;
1475 lpService
= hSvc
->ServiceEntry
;
1476 if (lpService
== NULL
)
1478 DPRINT("lpService == NULL!\n");
1479 return ERROR_INVALID_HANDLE
;
1482 if (lpService
->bDeleted
)
1483 return ERROR_SERVICE_MARKED_FOR_DELETE
;
1486 RpcImpersonateClient(NULL
);
1488 Status
= NtOpenThreadToken(NtCurrentThread(),
1492 if (!NT_SUCCESS(Status
))
1493 return RtlNtStatusToDosError(Status
);
1498 /* Lock the service database exclusive */
1499 ScmLockDatabaseExclusive();
1502 Status
= RtlSetSecurityObject(dwSecurityInformation
,
1503 (PSECURITY_DESCRIPTOR
)lpSecurityDescriptor
,
1504 &lpService
->lpSecurityDescriptor
,
1507 if (!NT_SUCCESS(Status
))
1509 dwError
= RtlNtStatusToDosError(Status
);
1514 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
1515 READ_CONTROL
| KEY_CREATE_SUB_KEY
| KEY_SET_VALUE
,
1517 if (dwError
!= ERROR_SUCCESS
)
1521 dwError
= ERROR_SUCCESS
;
1522 // dwError = ScmWriteSecurityDescriptor(hServiceKey,
1523 // lpService->lpSecurityDescriptor);
1525 RegFlushKey(hServiceKey
);
1526 RegCloseKey(hServiceKey
);
1535 /* Unlock service database */
1536 ScmUnlockDatabase();
1538 DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError
);
1545 DWORD
RQueryServiceStatus(
1546 SC_RPC_HANDLE hService
,
1547 LPSERVICE_STATUS lpServiceStatus
)
1549 PSERVICE_HANDLE hSvc
;
1552 DPRINT("RQueryServiceStatus() called\n");
1555 return ERROR_SHUTDOWN_IN_PROGRESS
;
1557 hSvc
= ScmGetServiceFromHandle(hService
);
1560 DPRINT1("Invalid service handle!\n");
1561 return ERROR_INVALID_HANDLE
;
1564 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1565 SERVICE_QUERY_STATUS
))
1567 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1568 return ERROR_ACCESS_DENIED
;
1571 lpService
= hSvc
->ServiceEntry
;
1572 if (lpService
== NULL
)
1574 DPRINT("lpService == NULL!\n");
1575 return ERROR_INVALID_HANDLE
;
1578 /* Lock the service database shared */
1579 ScmLockDatabaseShared();
1581 /* Return service status information */
1582 RtlCopyMemory(lpServiceStatus
,
1584 sizeof(SERVICE_STATUS
));
1586 /* Unlock the service database */
1587 ScmUnlockDatabase();
1589 return ERROR_SUCCESS
;
1594 ScmIsValidServiceState(DWORD dwCurrentState
)
1596 switch (dwCurrentState
)
1598 case SERVICE_STOPPED
:
1599 case SERVICE_START_PENDING
:
1600 case SERVICE_STOP_PENDING
:
1601 case SERVICE_RUNNING
:
1602 case SERVICE_CONTINUE_PENDING
:
1603 case SERVICE_PAUSE_PENDING
:
1604 case SERVICE_PAUSED
:
1614 DWORD
RSetServiceStatus(
1615 RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
1616 LPSERVICE_STATUS lpServiceStatus
)
1619 DWORD dwPreviousState
;
1620 DWORD dwPreviousType
;
1621 LPCWSTR lpErrorStrings
[2];
1622 WCHAR szErrorBuffer
[32];
1624 DPRINT("RSetServiceStatus() called\n");
1625 DPRINT("hServiceStatus = %lu\n", hServiceStatus
);
1626 DPRINT("dwServiceType = 0x%lx\n", lpServiceStatus
->dwServiceType
);
1627 DPRINT("dwCurrentState = %lu\n", lpServiceStatus
->dwCurrentState
);
1628 DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus
->dwControlsAccepted
);
1629 DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus
->dwWin32ExitCode
);
1630 DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus
->dwServiceSpecificExitCode
);
1631 DPRINT("dwCheckPoint = %lu\n", lpServiceStatus
->dwCheckPoint
);
1632 DPRINT("dwWaitHint = %lu\n", lpServiceStatus
->dwWaitHint
);
1634 if (hServiceStatus
== 0)
1636 DPRINT("hServiceStatus == NULL!\n");
1637 return ERROR_INVALID_HANDLE
;
1640 lpService
= (PSERVICE
)hServiceStatus
;
1642 /* Check current state */
1643 if (!ScmIsValidServiceState(lpServiceStatus
->dwCurrentState
))
1645 DPRINT("Invalid service state!\n");
1646 return ERROR_INVALID_DATA
;
1649 /* Check service type */
1650 if (!(lpServiceStatus
->dwServiceType
& SERVICE_WIN32
) &&
1651 (lpServiceStatus
->dwServiceType
& SERVICE_DRIVER
))
1653 DPRINT("Invalid service type!\n");
1654 return ERROR_INVALID_DATA
;
1657 /* Check accepted controls */
1658 if (lpServiceStatus
->dwControlsAccepted
& ~0xFF)
1660 DPRINT("Invalid controls accepted!\n");
1661 return ERROR_INVALID_DATA
;
1664 /* Set the wait hint and check point only if the service is in a pending state,
1665 otherwise they should be 0 */
1666 if (lpServiceStatus
->dwCurrentState
== SERVICE_STOPPED
||
1667 lpServiceStatus
->dwCurrentState
== SERVICE_PAUSED
||
1668 lpServiceStatus
->dwCurrentState
== SERVICE_RUNNING
)
1670 lpServiceStatus
->dwWaitHint
= 0;
1671 lpServiceStatus
->dwCheckPoint
= 0;
1674 /* Lock the service database exclusively */
1675 ScmLockDatabaseExclusive();
1677 /* Save the current service state */
1678 dwPreviousState
= lpService
->Status
.dwCurrentState
;
1680 /* Save the current service type */
1681 dwPreviousType
= lpService
->Status
.dwServiceType
;
1683 /* Update the service status */
1684 RtlCopyMemory(&lpService
->Status
,
1686 sizeof(SERVICE_STATUS
));
1688 /* Restore the previous service type */
1689 lpService
->Status
.dwServiceType
= dwPreviousType
;
1691 /* Unlock the service database */
1692 ScmUnlockDatabase();
1694 /* Log a failed service stop */
1695 if ((lpServiceStatus
->dwCurrentState
== SERVICE_STOPPED
) &&
1696 (dwPreviousState
!= SERVICE_STOPPED
))
1698 if (lpServiceStatus
->dwWin32ExitCode
!= ERROR_SUCCESS
)
1700 swprintf(szErrorBuffer
, L
"%lu", lpServiceStatus
->dwWin32ExitCode
);
1701 lpErrorStrings
[0] = lpService
->lpDisplayName
;
1702 lpErrorStrings
[1] = szErrorBuffer
;
1704 ScmLogError(EVENT_SERVICE_EXIT_FAILED
,
1710 DPRINT("Set %S to %lu\n", lpService
->lpDisplayName
, lpService
->Status
.dwCurrentState
);
1711 DPRINT("RSetServiceStatus() done\n");
1713 return ERROR_SUCCESS
;
1718 DWORD
RUnlockServiceDatabase(
1721 DPRINT("RUnlockServiceDatabase(%p)\n", Lock
);
1722 return ScmReleaseServiceStartLock(Lock
);
1727 DWORD
RNotifyBootConfigStatus(
1728 SVCCTL_HANDLEW lpMachineName
,
1729 DWORD BootAcceptable
)
1731 DPRINT1("RNotifyBootConfigStatus(%p %lu) called\n", lpMachineName
, BootAcceptable
);
1732 return ERROR_SUCCESS
;
1735 // return ERROR_CALL_NOT_IMPLEMENTED;
1740 DWORD
RI_ScSetServiceBitsW(
1741 RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
1742 DWORD dwServiceBits
,
1744 int bUpdateImmediately
,
1748 return ERROR_CALL_NOT_IMPLEMENTED
;
1753 DWORD
RChangeServiceConfigW(
1754 SC_RPC_HANDLE hService
,
1755 DWORD dwServiceType
,
1757 DWORD dwErrorControl
,
1758 LPWSTR lpBinaryPathName
,
1759 LPWSTR lpLoadOrderGroup
,
1761 LPBYTE lpDependencies
,
1763 LPWSTR lpServiceStartName
,
1766 LPWSTR lpDisplayName
)
1768 DWORD dwError
= ERROR_SUCCESS
;
1769 PSERVICE_HANDLE hSvc
;
1770 PSERVICE lpService
= NULL
;
1771 HKEY hServiceKey
= NULL
;
1772 LPWSTR lpDisplayNameW
= NULL
;
1773 LPWSTR lpImagePathW
= NULL
;
1775 DPRINT("RChangeServiceConfigW() called\n");
1776 DPRINT("dwServiceType = 0x%lx\n", dwServiceType
);
1777 DPRINT("dwStartType = %lu\n", dwStartType
);
1778 DPRINT("dwErrorControl = %lu\n", dwErrorControl
);
1779 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName
);
1780 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup
);
1781 DPRINT("lpDisplayName = %S\n", lpDisplayName
);
1784 return ERROR_SHUTDOWN_IN_PROGRESS
;
1786 hSvc
= ScmGetServiceFromHandle(hService
);
1789 DPRINT1("Invalid service handle!\n");
1790 return ERROR_INVALID_HANDLE
;
1793 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1794 SERVICE_CHANGE_CONFIG
))
1796 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1797 return ERROR_ACCESS_DENIED
;
1800 lpService
= hSvc
->ServiceEntry
;
1801 if (lpService
== NULL
)
1803 DPRINT("lpService == NULL!\n");
1804 return ERROR_INVALID_HANDLE
;
1807 /* Lock the service database exclusively */
1808 ScmLockDatabaseExclusive();
1810 if (lpService
->bDeleted
)
1812 DPRINT("The service has already been marked for delete!\n");
1813 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
1817 /* Open the service key */
1818 dwError
= ScmOpenServiceKey(lpService
->szServiceName
,
1821 if (dwError
!= ERROR_SUCCESS
)
1824 /* Write service data to the registry */
1825 /* Set the display name */
1826 if (lpDisplayName
!= NULL
&& *lpDisplayName
!= 0)
1828 RegSetValueExW(hServiceKey
,
1832 (LPBYTE
)lpDisplayName
,
1833 (DWORD
)((wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
)));
1835 /* Update the display name */
1836 lpDisplayNameW
= HeapAlloc(GetProcessHeap(),
1838 (wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
));
1839 if (lpDisplayNameW
== NULL
)
1841 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
1845 if (lpService
->lpDisplayName
!= lpService
->lpServiceName
)
1846 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
1848 lpService
->lpDisplayName
= lpDisplayNameW
;
1851 if (dwServiceType
!= SERVICE_NO_CHANGE
)
1853 /* Set the service type */
1854 dwError
= RegSetValueExW(hServiceKey
,
1858 (LPBYTE
)&dwServiceType
,
1860 if (dwError
!= ERROR_SUCCESS
)
1863 lpService
->Status
.dwServiceType
= dwServiceType
;
1866 if (dwStartType
!= SERVICE_NO_CHANGE
)
1868 /* Set the start value */
1869 dwError
= RegSetValueExW(hServiceKey
,
1873 (LPBYTE
)&dwStartType
,
1875 if (dwError
!= ERROR_SUCCESS
)
1878 lpService
->dwStartType
= dwStartType
;
1881 if (dwErrorControl
!= SERVICE_NO_CHANGE
)
1883 /* Set the error control value */
1884 dwError
= RegSetValueExW(hServiceKey
,
1888 (LPBYTE
)&dwErrorControl
,
1890 if (dwError
!= ERROR_SUCCESS
)
1893 lpService
->dwErrorControl
= dwErrorControl
;
1896 if (lpBinaryPathName
!= NULL
&& *lpBinaryPathName
!= 0)
1898 /* Set the image path */
1899 lpImagePathW
= lpBinaryPathName
;
1901 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
1903 dwError
= ScmCanonDriverImagePath(lpService
->dwStartType
,
1907 if (dwError
!= ERROR_SUCCESS
)
1911 dwError
= RegSetValueExW(hServiceKey
,
1915 (LPBYTE
)lpImagePathW
,
1916 (DWORD
)((wcslen(lpImagePathW
) + 1) * sizeof(WCHAR
)));
1918 if (lpImagePathW
!= lpBinaryPathName
)
1919 HeapFree(GetProcessHeap(), 0, lpImagePathW
);
1921 if (dwError
!= ERROR_SUCCESS
)
1925 /* Set the group name */
1926 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
1928 dwError
= RegSetValueExW(hServiceKey
,
1932 (LPBYTE
)lpLoadOrderGroup
,
1933 (DWORD
)((wcslen(lpLoadOrderGroup
) + 1) * sizeof(WCHAR
)));
1934 if (dwError
!= ERROR_SUCCESS
)
1937 dwError
= ScmSetServiceGroup(lpService
,
1939 if (dwError
!= ERROR_SUCCESS
)
1943 if (lpdwTagId
!= NULL
)
1945 dwError
= ScmAssignNewTag(lpService
);
1946 if (dwError
!= ERROR_SUCCESS
)
1949 dwError
= RegSetValueExW(hServiceKey
,
1953 (LPBYTE
)&lpService
->dwTag
,
1955 if (dwError
!= ERROR_SUCCESS
)
1958 *lpdwTagId
= lpService
->dwTag
;
1961 /* Write dependencies */
1962 if (lpDependencies
!= NULL
&& *lpDependencies
!= 0)
1964 dwError
= ScmWriteDependencies(hServiceKey
,
1965 (LPWSTR
)lpDependencies
,
1967 if (dwError
!= ERROR_SUCCESS
)
1971 if (lpPassword
!= NULL
)
1973 /* FIXME: Decrypt and write password */
1977 if (hServiceKey
!= NULL
)
1978 RegCloseKey(hServiceKey
);
1980 /* Unlock the service database */
1981 ScmUnlockDatabase();
1983 DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError
);
1990 DWORD
RCreateServiceW(
1991 SC_RPC_HANDLE hSCManager
,
1992 LPCWSTR lpServiceName
,
1993 LPCWSTR lpDisplayName
,
1994 DWORD dwDesiredAccess
,
1995 DWORD dwServiceType
,
1997 DWORD dwErrorControl
,
1998 LPCWSTR lpBinaryPathName
,
1999 LPCWSTR lpLoadOrderGroup
,
2001 LPBYTE lpDependencies
,
2003 LPCWSTR lpServiceStartName
,
2006 LPSC_RPC_HANDLE lpServiceHandle
)
2008 PMANAGER_HANDLE hManager
;
2009 DWORD dwError
= ERROR_SUCCESS
;
2010 PSERVICE lpService
= NULL
;
2011 SC_HANDLE hServiceHandle
= NULL
;
2012 LPWSTR lpImagePath
= NULL
;
2013 HKEY hServiceKey
= NULL
;
2014 LPWSTR lpObjectName
;
2016 DPRINT("RCreateServiceW() called\n");
2017 DPRINT("lpServiceName = %S\n", lpServiceName
);
2018 DPRINT("lpDisplayName = %S\n", lpDisplayName
);
2019 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess
);
2020 DPRINT("dwServiceType = 0x%lx\n", dwServiceType
);
2021 DPRINT("dwStartType = %lu\n", dwStartType
);
2022 DPRINT("dwErrorControl = %lu\n", dwErrorControl
);
2023 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName
);
2024 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup
);
2025 DPRINT("lpdwTagId = %p\n", lpdwTagId
);
2028 return ERROR_SHUTDOWN_IN_PROGRESS
;
2030 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
2031 if (hManager
== NULL
)
2033 DPRINT1("Invalid service manager handle!\n");
2034 return ERROR_INVALID_HANDLE
;
2037 /* Check access rights */
2038 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
2039 SC_MANAGER_CREATE_SERVICE
))
2041 DPRINT("Insufficient access rights! 0x%lx\n",
2042 hManager
->Handle
.DesiredAccess
);
2043 return ERROR_ACCESS_DENIED
;
2046 if (wcslen(lpServiceName
) == 0)
2048 return ERROR_INVALID_NAME
;
2051 if (wcslen(lpBinaryPathName
) == 0)
2053 return ERROR_INVALID_PARAMETER
;
2056 /* Check for invalid service type value */
2057 if ((dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
2058 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
) &&
2059 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
2060 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
))
2061 return ERROR_INVALID_PARAMETER
;
2063 /* Check for invalid start type value */
2064 if ((dwStartType
!= SERVICE_BOOT_START
) &&
2065 (dwStartType
!= SERVICE_SYSTEM_START
) &&
2066 (dwStartType
!= SERVICE_AUTO_START
) &&
2067 (dwStartType
!= SERVICE_DEMAND_START
) &&
2068 (dwStartType
!= SERVICE_DISABLED
))
2069 return ERROR_INVALID_PARAMETER
;
2071 /* Only drivers can be boot start or system start services */
2072 if ((dwStartType
== SERVICE_BOOT_START
) ||
2073 (dwStartType
== SERVICE_SYSTEM_START
))
2075 if ((dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
2076 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
2077 return ERROR_INVALID_PARAMETER
;
2080 /* Check for invalid error control value */
2081 if ((dwErrorControl
!= SERVICE_ERROR_IGNORE
) &&
2082 (dwErrorControl
!= SERVICE_ERROR_NORMAL
) &&
2083 (dwErrorControl
!= SERVICE_ERROR_SEVERE
) &&
2084 (dwErrorControl
!= SERVICE_ERROR_CRITICAL
))
2085 return ERROR_INVALID_PARAMETER
;
2087 if ((dwServiceType
== (SERVICE_WIN32_OWN_PROCESS
| SERVICE_INTERACTIVE_PROCESS
)) &&
2088 (lpServiceStartName
))
2090 return ERROR_INVALID_PARAMETER
;
2093 if (lpdwTagId
&& (!lpLoadOrderGroup
|| !*lpLoadOrderGroup
))
2095 return ERROR_INVALID_PARAMETER
;
2098 /* Lock the service database exclusively */
2099 ScmLockDatabaseExclusive();
2101 lpService
= ScmGetServiceEntryByName(lpServiceName
);
2104 /* Unlock the service database */
2105 ScmUnlockDatabase();
2107 /* Check if it is marked for deletion */
2108 if (lpService
->bDeleted
)
2109 return ERROR_SERVICE_MARKED_FOR_DELETE
;
2111 /* Return Error exist */
2112 return ERROR_SERVICE_EXISTS
;
2115 if (lpDisplayName
!= NULL
&&
2116 ScmGetServiceEntryByDisplayName(lpDisplayName
) != NULL
)
2118 /* Unlock the service database */
2119 ScmUnlockDatabase();
2121 return ERROR_DUPLICATE_SERVICE_NAME
;
2124 if (dwServiceType
& SERVICE_DRIVER
)
2126 dwError
= ScmCanonDriverImagePath(dwStartType
,
2129 if (dwError
!= ERROR_SUCCESS
)
2134 if (dwStartType
== SERVICE_BOOT_START
||
2135 dwStartType
== SERVICE_SYSTEM_START
)
2137 /* Unlock the service database */
2138 ScmUnlockDatabase();
2140 return ERROR_INVALID_PARAMETER
;
2144 /* Allocate a new service entry */
2145 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
2147 if (dwError
!= ERROR_SUCCESS
)
2150 /* Fill the new service entry */
2151 lpService
->Status
.dwServiceType
= dwServiceType
;
2152 lpService
->dwStartType
= dwStartType
;
2153 lpService
->dwErrorControl
= dwErrorControl
;
2155 /* Fill the display name */
2156 if (lpDisplayName
!= NULL
&&
2157 *lpDisplayName
!= 0 &&
2158 _wcsicmp(lpService
->lpDisplayName
, lpDisplayName
) != 0)
2160 lpService
->lpDisplayName
= HeapAlloc(GetProcessHeap(),
2162 (wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
));
2163 if (lpService
->lpDisplayName
== NULL
)
2165 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
2168 wcscpy(lpService
->lpDisplayName
, lpDisplayName
);
2171 /* Assign the service to a group */
2172 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
2174 dwError
= ScmSetServiceGroup(lpService
,
2176 if (dwError
!= ERROR_SUCCESS
)
2180 /* Assign a new tag */
2181 if (lpdwTagId
!= NULL
)
2183 dwError
= ScmAssignNewTag(lpService
);
2184 if (dwError
!= ERROR_SUCCESS
)
2188 /* Write service data to the registry */
2189 /* Create the service key */
2190 dwError
= ScmCreateServiceKey(lpServiceName
,
2193 if (dwError
!= ERROR_SUCCESS
)
2196 /* Set the display name */
2197 if (lpDisplayName
!= NULL
&& *lpDisplayName
!= 0)
2199 RegSetValueExW(hServiceKey
,
2203 (LPBYTE
)lpDisplayName
,
2204 (DWORD
)((wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
)));
2207 /* Set the service type */
2208 dwError
= RegSetValueExW(hServiceKey
,
2212 (LPBYTE
)&dwServiceType
,
2214 if (dwError
!= ERROR_SUCCESS
)
2217 /* Set the start value */
2218 dwError
= RegSetValueExW(hServiceKey
,
2222 (LPBYTE
)&dwStartType
,
2224 if (dwError
!= ERROR_SUCCESS
)
2227 /* Set the error control value */
2228 dwError
= RegSetValueExW(hServiceKey
,
2232 (LPBYTE
)&dwErrorControl
,
2234 if (dwError
!= ERROR_SUCCESS
)
2237 /* Set the image path */
2238 if (dwServiceType
& SERVICE_WIN32
)
2240 dwError
= RegSetValueExW(hServiceKey
,
2244 (LPBYTE
)lpBinaryPathName
,
2245 (DWORD
)((wcslen(lpBinaryPathName
) + 1) * sizeof(WCHAR
)));
2246 if (dwError
!= ERROR_SUCCESS
)
2249 else if (dwServiceType
& SERVICE_DRIVER
)
2251 dwError
= RegSetValueExW(hServiceKey
,
2255 (LPBYTE
)lpImagePath
,
2256 (DWORD
)((wcslen(lpImagePath
) + 1) * sizeof(WCHAR
)));
2257 if (dwError
!= ERROR_SUCCESS
)
2261 /* Set the group name */
2262 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
2264 dwError
= RegSetValueExW(hServiceKey
,
2268 (LPBYTE
)lpLoadOrderGroup
,
2269 (DWORD
)((wcslen(lpLoadOrderGroup
) + 1) * sizeof(WCHAR
)));
2270 if (dwError
!= ERROR_SUCCESS
)
2274 if (lpdwTagId
!= NULL
)
2276 dwError
= RegSetValueExW(hServiceKey
,
2280 (LPBYTE
)&lpService
->dwTag
,
2282 if (dwError
!= ERROR_SUCCESS
)
2286 /* Write dependencies */
2287 if (lpDependencies
!= NULL
&& *lpDependencies
!= 0)
2289 dwError
= ScmWriteDependencies(hServiceKey
,
2290 (LPCWSTR
)lpDependencies
,
2292 if (dwError
!= ERROR_SUCCESS
)
2296 /* Write service start name */
2297 if (dwServiceType
& SERVICE_WIN32
)
2299 lpObjectName
= (lpServiceStartName
!= NULL
) ? (LPWSTR
)lpServiceStartName
: L
"LocalSystem";
2300 dwError
= RegSetValueExW(hServiceKey
,
2304 (LPBYTE
)lpObjectName
,
2305 (DWORD
)((wcslen(lpObjectName
) + 1) * sizeof(WCHAR
)));
2306 if (dwError
!= ERROR_SUCCESS
)
2310 if (lpPassword
!= NULL
)
2312 /* FIXME: Decrypt and write password */
2315 dwError
= ScmCreateServiceHandle(lpService
,
2317 if (dwError
!= ERROR_SUCCESS
)
2320 dwError
= ScmCheckAccess(hServiceHandle
,
2322 if (dwError
!= ERROR_SUCCESS
)
2325 lpService
->dwRefCount
= 1;
2326 DPRINT("CreateService - lpService->dwRefCount %u\n", lpService
->dwRefCount
);
2329 /* Unlock the service database */
2330 ScmUnlockDatabase();
2332 if (hServiceKey
!= NULL
)
2333 RegCloseKey(hServiceKey
);
2335 if (dwError
== ERROR_SUCCESS
)
2337 DPRINT("hService %p\n", hServiceHandle
);
2338 *lpServiceHandle
= (SC_RPC_HANDLE
)hServiceHandle
;
2340 if (lpdwTagId
!= NULL
)
2341 *lpdwTagId
= lpService
->dwTag
;
2345 if (lpService
!= NULL
&&
2346 lpService
->lpServiceName
!= NULL
)
2348 /* Release the display name buffer */
2349 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
2354 /* Remove the service handle */
2355 HeapFree(GetProcessHeap(), 0, hServiceHandle
);
2358 if (lpService
!= NULL
)
2360 /* FIXME: remove the service entry */
2364 if (lpImagePath
!= NULL
)
2365 HeapFree(GetProcessHeap(), 0, lpImagePath
);
2367 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError
);
2374 DWORD
REnumDependentServicesW(
2375 SC_RPC_HANDLE hService
,
2376 DWORD dwServiceState
,
2379 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
2380 LPBOUNDED_DWORD_256K lpServicesReturned
)
2382 DWORD dwError
= ERROR_SUCCESS
;
2383 DWORD dwServicesReturned
= 0;
2384 DWORD dwServiceCount
;
2385 HKEY hServicesKey
= NULL
;
2386 PSERVICE_HANDLE hSvc
;
2387 PSERVICE lpService
= NULL
;
2388 PSERVICE
*lpServicesArray
= NULL
;
2389 LPENUM_SERVICE_STATUSW lpServicesPtr
= NULL
;
2392 *pcbBytesNeeded
= 0;
2393 *lpServicesReturned
= 0;
2395 DPRINT("REnumDependentServicesW() called\n");
2397 hSvc
= ScmGetServiceFromHandle(hService
);
2400 DPRINT1("Invalid service handle!\n");
2401 return ERROR_INVALID_HANDLE
;
2404 lpService
= hSvc
->ServiceEntry
;
2406 /* Check access rights */
2407 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
2408 SC_MANAGER_ENUMERATE_SERVICE
))
2410 DPRINT("Insufficient access rights! 0x%lx\n",
2411 hSvc
->Handle
.DesiredAccess
);
2412 return ERROR_ACCESS_DENIED
;
2415 /* Open the Services Reg key */
2416 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2417 L
"System\\CurrentControlSet\\Services",
2421 if (dwError
!= ERROR_SUCCESS
)
2424 /* First determine the bytes needed and get the number of dependent services */
2425 dwError
= Int_EnumDependentServicesW(hServicesKey
,
2430 &dwServicesReturned
);
2431 if (dwError
!= ERROR_SUCCESS
)
2434 /* If buffer size is less than the bytes needed or pointer is null */
2435 if ((!lpServices
) || (cbBufSize
< *pcbBytesNeeded
))
2437 dwError
= ERROR_MORE_DATA
;
2441 /* Allocate memory for array of service pointers */
2442 lpServicesArray
= HeapAlloc(GetProcessHeap(),
2444 (dwServicesReturned
+ 1) * sizeof(PSERVICE
));
2445 if (!lpServicesArray
)
2447 DPRINT1("Could not allocate a buffer!!\n");
2448 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
2452 dwServicesReturned
= 0;
2453 *pcbBytesNeeded
= 0;
2455 dwError
= Int_EnumDependentServicesW(hServicesKey
,
2460 &dwServicesReturned
);
2461 if (dwError
!= ERROR_SUCCESS
)
2466 lpServicesPtr
= (LPENUM_SERVICE_STATUSW
)lpServices
;
2467 lpStr
= (LPWSTR
)(lpServices
+ (dwServicesReturned
* sizeof(ENUM_SERVICE_STATUSW
)));
2469 /* Copy EnumDepenedentService to Buffer */
2470 for (dwServiceCount
= 0; dwServiceCount
< dwServicesReturned
; dwServiceCount
++)
2472 lpService
= lpServicesArray
[dwServiceCount
];
2474 /* Copy status info */
2475 memcpy(&lpServicesPtr
->ServiceStatus
,
2477 sizeof(SERVICE_STATUS
));
2479 /* Copy display name */
2480 wcscpy(lpStr
, lpService
->lpDisplayName
);
2481 lpServicesPtr
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
2482 lpStr
+= (wcslen(lpService
->lpDisplayName
) + 1);
2484 /* Copy service name */
2485 wcscpy(lpStr
, lpService
->lpServiceName
);
2486 lpServicesPtr
->lpServiceName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
2487 lpStr
+= (wcslen(lpService
->lpServiceName
) + 1);
2492 *lpServicesReturned
= dwServicesReturned
;
2495 if (lpServicesArray
!= NULL
)
2496 HeapFree(GetProcessHeap(), 0, lpServicesArray
);
2498 RegCloseKey(hServicesKey
);
2500 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError
);
2507 DWORD
REnumServicesStatusW(
2508 SC_RPC_HANDLE hSCManager
,
2509 DWORD dwServiceType
,
2510 DWORD dwServiceState
,
2513 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
2514 LPBOUNDED_DWORD_256K lpServicesReturned
,
2515 LPBOUNDED_DWORD_256K lpResumeHandle
)
2517 /* Enumerate all the services, not regarding of their group */
2518 return REnumServiceGroupW(hSCManager
,
2531 DWORD
ROpenSCManagerW(
2532 LPWSTR lpMachineName
,
2533 LPWSTR lpDatabaseName
,
2534 DWORD dwDesiredAccess
,
2535 LPSC_RPC_HANDLE lpScHandle
)
2540 DPRINT("ROpenSCManagerW() called\n");
2541 DPRINT("lpMachineName = %p\n", lpMachineName
);
2542 DPRINT("lpMachineName: %S\n", lpMachineName
);
2543 DPRINT("lpDataBaseName = %p\n", lpDatabaseName
);
2544 DPRINT("lpDataBaseName: %S\n", lpDatabaseName
);
2545 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess
);
2548 return ERROR_SHUTDOWN_IN_PROGRESS
;
2551 return ERROR_INVALID_PARAMETER
;
2553 dwError
= ScmCreateManagerHandle(lpDatabaseName
,
2555 if (dwError
!= ERROR_SUCCESS
)
2557 DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError
);
2561 /* Check the desired access */
2562 dwError
= ScmCheckAccess(hHandle
,
2563 dwDesiredAccess
| SC_MANAGER_CONNECT
);
2564 if (dwError
!= ERROR_SUCCESS
)
2566 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError
);
2567 HeapFree(GetProcessHeap(), 0, hHandle
);
2571 *lpScHandle
= (SC_RPC_HANDLE
)hHandle
;
2572 DPRINT("*hScm = %p\n", *lpScHandle
);
2574 DPRINT("ROpenSCManagerW() done\n");
2576 return ERROR_SUCCESS
;
2581 DWORD
ROpenServiceW(
2582 SC_RPC_HANDLE hSCManager
,
2583 LPWSTR lpServiceName
,
2584 DWORD dwDesiredAccess
,
2585 LPSC_RPC_HANDLE lpServiceHandle
)
2588 PMANAGER_HANDLE hManager
;
2590 DWORD dwError
= ERROR_SUCCESS
;
2592 DPRINT("ROpenServiceW() called\n");
2593 DPRINT("hSCManager = %p\n", hSCManager
);
2594 DPRINT("lpServiceName = %p\n", lpServiceName
);
2595 DPRINT("lpServiceName: %S\n", lpServiceName
);
2596 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess
);
2599 return ERROR_SHUTDOWN_IN_PROGRESS
;
2601 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
2602 if (hManager
== NULL
)
2604 DPRINT1("Invalid service manager handle!\n");
2605 return ERROR_INVALID_HANDLE
;
2608 if (!lpServiceHandle
)
2609 return ERROR_INVALID_PARAMETER
;
2612 return ERROR_INVALID_ADDRESS
;
2614 /* Lock the service database exclusive */
2615 ScmLockDatabaseExclusive();
2617 /* Get service database entry */
2618 lpService
= ScmGetServiceEntryByName(lpServiceName
);
2619 if (lpService
== NULL
)
2621 DPRINT("Could not find a service!\n");
2622 dwError
= ERROR_SERVICE_DOES_NOT_EXIST
;
2626 /* Create a service handle */
2627 dwError
= ScmCreateServiceHandle(lpService
,
2629 if (dwError
!= ERROR_SUCCESS
)
2631 DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError
);
2635 /* Check the desired access */
2636 dwError
= ScmCheckAccess(hHandle
,
2638 if (dwError
!= ERROR_SUCCESS
)
2640 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError
);
2641 HeapFree(GetProcessHeap(), 0, hHandle
);
2645 lpService
->dwRefCount
++;
2646 DPRINT("OpenService - lpService->dwRefCount %u\n",lpService
->dwRefCount
);
2648 *lpServiceHandle
= (SC_RPC_HANDLE
)hHandle
;
2649 DPRINT("*hService = %p\n", *lpServiceHandle
);
2652 /* Unlock the service database */
2653 ScmUnlockDatabase();
2655 DPRINT("ROpenServiceW() done\n");
2662 DWORD
RQueryServiceConfigW(
2663 SC_RPC_HANDLE hService
,
2664 LPBYTE lpBuf
, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2666 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
2668 LPQUERY_SERVICE_CONFIGW lpServiceConfig
= (LPQUERY_SERVICE_CONFIGW
)lpBuf
;
2669 DWORD dwError
= ERROR_SUCCESS
;
2670 PSERVICE_HANDLE hSvc
;
2671 PSERVICE lpService
= NULL
;
2672 HKEY hServiceKey
= NULL
;
2673 LPWSTR lpImagePath
= NULL
;
2674 LPWSTR lpServiceStartName
= NULL
;
2675 LPWSTR lpDependencies
= NULL
;
2676 DWORD dwDependenciesLength
= 0;
2677 DWORD dwRequiredSize
;
2678 WCHAR lpEmptyString
[] = {0,0};
2681 DPRINT("RQueryServiceConfigW() called\n");
2684 return ERROR_SHUTDOWN_IN_PROGRESS
;
2686 hSvc
= ScmGetServiceFromHandle(hService
);
2689 DPRINT1("Invalid service handle!\n");
2690 return ERROR_INVALID_HANDLE
;
2693 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
2694 SERVICE_QUERY_CONFIG
))
2696 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
2697 return ERROR_ACCESS_DENIED
;
2700 lpService
= hSvc
->ServiceEntry
;
2701 if (lpService
== NULL
)
2703 DPRINT("lpService == NULL!\n");
2704 return ERROR_INVALID_HANDLE
;
2707 /* Lock the service database shared */
2708 ScmLockDatabaseShared();
2710 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
2713 if (dwError
!= ERROR_SUCCESS
)
2716 /* Read the image path */
2717 dwError
= ScmReadString(hServiceKey
,
2720 if (dwError
!= ERROR_SUCCESS
)
2723 /* Read the service start name */
2724 ScmReadString(hServiceKey
,
2726 &lpServiceStartName
);
2728 /* Read the dependencies */
2729 ScmReadDependencies(hServiceKey
,
2731 &dwDependenciesLength
);
2733 dwRequiredSize
= sizeof(QUERY_SERVICE_CONFIGW
);
2735 if (lpImagePath
!= NULL
)
2736 dwRequiredSize
+= (DWORD
)((wcslen(lpImagePath
) + 1) * sizeof(WCHAR
));
2738 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2740 if ((lpService
->lpGroup
!= NULL
) && (lpService
->lpGroup
->lpGroupName
!= NULL
))
2741 dwRequiredSize
+= (DWORD
)((wcslen(lpService
->lpGroup
->lpGroupName
) + 1) * sizeof(WCHAR
));
2743 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2745 if (lpDependencies
!= NULL
)
2746 dwRequiredSize
+= dwDependenciesLength
* sizeof(WCHAR
);
2748 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2750 if (lpServiceStartName
!= NULL
)
2751 dwRequiredSize
+= (DWORD
)((wcslen(lpServiceStartName
) + 1) * sizeof(WCHAR
));
2753 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2755 if (lpService
->lpDisplayName
!= NULL
)
2756 dwRequiredSize
+= (DWORD
)((wcslen(lpService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
2758 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2760 if (lpServiceConfig
== NULL
|| cbBufSize
< dwRequiredSize
)
2762 dwError
= ERROR_INSUFFICIENT_BUFFER
;
2766 lpServiceConfig
->dwServiceType
= lpService
->Status
.dwServiceType
;
2767 lpServiceConfig
->dwStartType
= lpService
->dwStartType
;
2768 lpServiceConfig
->dwErrorControl
= lpService
->dwErrorControl
;
2769 lpServiceConfig
->dwTagId
= lpService
->dwTag
;
2771 lpStr
= (LPWSTR
)(lpServiceConfig
+ 1);
2773 /* Append the image path */
2774 if (lpImagePath
!= NULL
)
2776 wcscpy(lpStr
, lpImagePath
);
2780 wcscpy(lpStr
, lpEmptyString
);
2783 lpServiceConfig
->lpBinaryPathName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2784 lpStr
+= (wcslen(lpStr
) + 1);
2786 /* Append the group name */
2787 if ((lpService
->lpGroup
!= NULL
) && (lpService
->lpGroup
->lpGroupName
!= NULL
))
2789 wcscpy(lpStr
, lpService
->lpGroup
->lpGroupName
);
2793 wcscpy(lpStr
, lpEmptyString
);
2796 lpServiceConfig
->lpLoadOrderGroup
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2797 lpStr
+= (wcslen(lpStr
) + 1);
2799 /* Append Dependencies */
2800 if (lpDependencies
!= NULL
)
2804 dwDependenciesLength
* sizeof(WCHAR
));
2808 wcscpy(lpStr
, lpEmptyString
);
2811 lpServiceConfig
->lpDependencies
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2812 if (lpDependencies
!= NULL
)
2813 lpStr
+= dwDependenciesLength
;
2815 lpStr
+= (wcslen(lpStr
) + 1);
2817 /* Append the service start name */
2818 if (lpServiceStartName
!= NULL
)
2820 wcscpy(lpStr
, lpServiceStartName
);
2824 wcscpy(lpStr
, lpEmptyString
);
2827 lpServiceConfig
->lpServiceStartName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2828 lpStr
+= (wcslen(lpStr
) + 1);
2830 /* Append the display name */
2831 if (lpService
->lpDisplayName
!= NULL
)
2833 wcscpy(lpStr
, lpService
->lpDisplayName
);
2837 wcscpy(lpStr
, lpEmptyString
);
2840 lpServiceConfig
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2843 if (pcbBytesNeeded
!= NULL
)
2844 *pcbBytesNeeded
= dwRequiredSize
;
2847 /* Unlock the service database */
2848 ScmUnlockDatabase();
2850 if (lpImagePath
!= NULL
)
2851 HeapFree(GetProcessHeap(), 0, lpImagePath
);
2853 if (lpServiceStartName
!= NULL
)
2854 HeapFree(GetProcessHeap(), 0, lpServiceStartName
);
2856 if (lpDependencies
!= NULL
)
2857 HeapFree(GetProcessHeap(), 0, lpDependencies
);
2859 if (hServiceKey
!= NULL
)
2860 RegCloseKey(hServiceKey
);
2862 DPRINT("RQueryServiceConfigW() done\n");
2869 DWORD
RQueryServiceLockStatusW(
2870 SC_RPC_HANDLE hSCManager
,
2871 LPBYTE lpBuf
, // LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2873 LPBOUNDED_DWORD_4K pcbBytesNeeded
)
2875 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
= (LPQUERY_SERVICE_LOCK_STATUSW
)lpBuf
;
2876 PMANAGER_HANDLE hMgr
;
2877 DWORD dwRequiredSize
;
2879 if (!lpLockStatus
|| !pcbBytesNeeded
)
2880 return ERROR_INVALID_PARAMETER
;
2882 hMgr
= ScmGetServiceManagerFromHandle(hSCManager
);
2885 DPRINT1("Invalid service manager handle!\n");
2886 return ERROR_INVALID_HANDLE
;
2889 if (!RtlAreAllAccessesGranted(hMgr
->Handle
.DesiredAccess
,
2890 SC_MANAGER_QUERY_LOCK_STATUS
))
2892 DPRINT("Insufficient access rights! 0x%lx\n", hMgr
->Handle
.DesiredAccess
);
2893 return ERROR_ACCESS_DENIED
;
2896 /* FIXME: we need to compute instead the real length of the owner name */
2897 dwRequiredSize
= sizeof(QUERY_SERVICE_LOCK_STATUSW
) + sizeof(WCHAR
);
2898 *pcbBytesNeeded
= dwRequiredSize
;
2900 if (cbBufSize
< dwRequiredSize
)
2901 return ERROR_INSUFFICIENT_BUFFER
;
2903 ScmQueryServiceLockStatusW(lpLockStatus
);
2905 return ERROR_SUCCESS
;
2910 DWORD
RStartServiceW(
2911 SC_RPC_HANDLE hService
,
2913 LPSTRING_PTRSW argv
)
2915 DWORD dwError
= ERROR_SUCCESS
;
2916 PSERVICE_HANDLE hSvc
;
2917 PSERVICE lpService
= NULL
;
2922 DPRINT("RStartServiceW(%p %lu %p) called\n", hService
, argc
, argv
);
2923 DPRINT(" argc: %lu\n", argc
);
2926 for (i
= 0; i
< argc
; i
++)
2928 DPRINT(" argv[%lu]: %S\n", i
, argv
[i
].StringPtr
);
2934 return ERROR_SHUTDOWN_IN_PROGRESS
;
2936 hSvc
= ScmGetServiceFromHandle(hService
);
2939 DPRINT1("Invalid service handle!\n");
2940 return ERROR_INVALID_HANDLE
;
2943 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
2946 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
2947 return ERROR_ACCESS_DENIED
;
2950 lpService
= hSvc
->ServiceEntry
;
2951 if (lpService
== NULL
)
2953 DPRINT("lpService == NULL!\n");
2954 return ERROR_INVALID_HANDLE
;
2957 if (lpService
->dwStartType
== SERVICE_DISABLED
)
2958 return ERROR_SERVICE_DISABLED
;
2960 if (lpService
->bDeleted
)
2961 return ERROR_SERVICE_MARKED_FOR_DELETE
;
2963 /* Start the service */
2964 dwError
= ScmStartService(lpService
, argc
, (LPWSTR
*)argv
);
2971 DWORD
RGetServiceDisplayNameW(
2972 SC_RPC_HANDLE hSCManager
,
2973 LPCWSTR lpServiceName
,
2974 LPWSTR lpDisplayName
,
2977 // PMANAGER_HANDLE hManager;
2982 DPRINT("RGetServiceDisplayNameW() called\n");
2983 DPRINT("hSCManager = %p\n", hSCManager
);
2984 DPRINT("lpServiceName: %S\n", lpServiceName
);
2985 DPRINT("lpDisplayName: %p\n", lpDisplayName
);
2986 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
2988 // hManager = (PMANAGER_HANDLE)hSCManager;
2989 // if (hManager->Handle.Tag != MANAGER_TAG)
2991 // DPRINT("Invalid manager handle!\n");
2992 // return ERROR_INVALID_HANDLE;
2995 /* Get service database entry */
2996 lpService
= ScmGetServiceEntryByName(lpServiceName
);
2997 if (lpService
== NULL
)
2999 DPRINT("Could not find a service!\n");
3001 /* If the service could not be found and lpcchBuffer is less than 2, windows
3002 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3003 if (*lpcchBuffer
< 2)
3006 if (lpDisplayName
!= NULL
)
3012 return ERROR_SERVICE_DOES_NOT_EXIST
;
3015 if (!lpService
->lpDisplayName
)
3017 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
3019 if (lpDisplayName
!= NULL
&&
3020 *lpcchBuffer
> dwLength
)
3022 wcscpy(lpDisplayName
, lpService
->lpServiceName
);
3027 dwLength
= (DWORD
)wcslen(lpService
->lpDisplayName
);
3029 if (lpDisplayName
!= NULL
&&
3030 *lpcchBuffer
> dwLength
)
3032 wcscpy(lpDisplayName
, lpService
->lpDisplayName
);
3036 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
3038 *lpcchBuffer
= dwLength
;
3045 DWORD
RGetServiceKeyNameW(
3046 SC_RPC_HANDLE hSCManager
,
3047 LPCWSTR lpDisplayName
,
3048 LPWSTR lpServiceName
,
3051 // PMANAGER_HANDLE hManager;
3056 DPRINT("RGetServiceKeyNameW() called\n");
3057 DPRINT("hSCManager = %p\n", hSCManager
);
3058 DPRINT("lpDisplayName: %S\n", lpDisplayName
);
3059 DPRINT("lpServiceName: %p\n", lpServiceName
);
3060 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
3062 // hManager = (PMANAGER_HANDLE)hSCManager;
3063 // if (hManager->Handle.Tag != MANAGER_TAG)
3065 // DPRINT("Invalid manager handle!\n");
3066 // return ERROR_INVALID_HANDLE;
3069 /* Get service database entry */
3070 lpService
= ScmGetServiceEntryByDisplayName(lpDisplayName
);
3071 if (lpService
== NULL
)
3073 DPRINT("Could not find a service!\n");
3075 /* If the service could not be found and lpcchBuffer is less than 2, windows
3076 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3077 if (*lpcchBuffer
< 2)
3080 if (lpServiceName
!= NULL
)
3086 return ERROR_SERVICE_DOES_NOT_EXIST
;
3089 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
3091 if (lpServiceName
!= NULL
&&
3092 *lpcchBuffer
> dwLength
)
3094 wcscpy(lpServiceName
, lpService
->lpServiceName
);
3095 *lpcchBuffer
= dwLength
;
3096 return ERROR_SUCCESS
;
3099 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
3101 *lpcchBuffer
= dwLength
;
3108 DWORD
RI_ScSetServiceBitsA(
3109 RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
3110 DWORD dwServiceBits
,
3112 int bUpdateImmediately
,
3116 return ERROR_CALL_NOT_IMPLEMENTED
;
3121 DWORD
RChangeServiceConfigA(
3122 SC_RPC_HANDLE hService
,
3123 DWORD dwServiceType
,
3125 DWORD dwErrorControl
,
3126 LPSTR lpBinaryPathName
,
3127 LPSTR lpLoadOrderGroup
,
3129 LPBYTE lpDependencies
,
3131 LPSTR lpServiceStartName
,
3134 LPSTR lpDisplayName
)
3136 DWORD dwError
= ERROR_SUCCESS
;
3137 PSERVICE_HANDLE hSvc
;
3138 PSERVICE lpService
= NULL
;
3139 HKEY hServiceKey
= NULL
;
3140 LPWSTR lpDisplayNameW
= NULL
;
3141 LPWSTR lpBinaryPathNameW
= NULL
;
3142 LPWSTR lpCanonicalImagePathW
= NULL
;
3143 LPWSTR lpLoadOrderGroupW
= NULL
;
3144 LPWSTR lpDependenciesW
= NULL
;
3146 DPRINT("RChangeServiceConfigA() called\n");
3147 DPRINT("dwServiceType = %lu\n", dwServiceType
);
3148 DPRINT("dwStartType = %lu\n", dwStartType
);
3149 DPRINT("dwErrorControl = %lu\n", dwErrorControl
);
3150 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName
);
3151 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup
);
3152 DPRINT("lpDisplayName = %s\n", lpDisplayName
);
3155 return ERROR_SHUTDOWN_IN_PROGRESS
;
3157 hSvc
= ScmGetServiceFromHandle(hService
);
3160 DPRINT1("Invalid service handle!\n");
3161 return ERROR_INVALID_HANDLE
;
3164 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3165 SERVICE_CHANGE_CONFIG
))
3167 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
3168 return ERROR_ACCESS_DENIED
;
3171 lpService
= hSvc
->ServiceEntry
;
3172 if (lpService
== NULL
)
3174 DPRINT("lpService == NULL!\n");
3175 return ERROR_INVALID_HANDLE
;
3178 /* Lock the service database exclusively */
3179 ScmLockDatabaseExclusive();
3181 if (lpService
->bDeleted
)
3183 DPRINT("The service has already been marked for delete!\n");
3184 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
3188 /* Open the service key */
3189 dwError
= ScmOpenServiceKey(lpService
->szServiceName
,
3192 if (dwError
!= ERROR_SUCCESS
)
3195 /* Write service data to the registry */
3197 if (lpDisplayName
!= NULL
&& *lpDisplayName
!= 0)
3199 /* Set the display name */
3200 lpDisplayNameW
= HeapAlloc(GetProcessHeap(),
3202 (strlen(lpDisplayName
) + 1) * sizeof(WCHAR
));
3203 if (lpDisplayNameW
== NULL
)
3205 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3209 MultiByteToWideChar(CP_ACP
,
3214 (int)(strlen(lpDisplayName
) + 1));
3216 RegSetValueExW(hServiceKey
,
3220 (LPBYTE
)lpDisplayNameW
,
3221 (DWORD
)((wcslen(lpDisplayNameW
) + 1) * sizeof(WCHAR
)));
3223 /* Update lpService->lpDisplayName */
3224 if (lpService
->lpDisplayName
)
3225 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
3227 lpService
->lpDisplayName
= lpDisplayNameW
;
3230 if (dwServiceType
!= SERVICE_NO_CHANGE
)
3232 /* Set the service type */
3233 dwError
= RegSetValueExW(hServiceKey
,
3237 (LPBYTE
)&dwServiceType
,
3239 if (dwError
!= ERROR_SUCCESS
)
3242 lpService
->Status
.dwServiceType
= dwServiceType
;
3245 if (dwStartType
!= SERVICE_NO_CHANGE
)
3247 /* Set the start value */
3248 dwError
= RegSetValueExW(hServiceKey
,
3252 (LPBYTE
)&dwStartType
,
3254 if (dwError
!= ERROR_SUCCESS
)
3257 lpService
->dwStartType
= dwStartType
;
3260 if (dwErrorControl
!= SERVICE_NO_CHANGE
)
3262 /* Set the error control value */
3263 dwError
= RegSetValueExW(hServiceKey
,
3267 (LPBYTE
)&dwErrorControl
,
3269 if (dwError
!= ERROR_SUCCESS
)
3272 lpService
->dwErrorControl
= dwErrorControl
;
3275 if (lpBinaryPathName
!= NULL
&& *lpBinaryPathName
!= 0)
3277 /* Set the image path */
3278 lpBinaryPathNameW
= HeapAlloc(GetProcessHeap(),
3280 (strlen(lpBinaryPathName
) + 1) * sizeof(WCHAR
));
3281 if (lpBinaryPathNameW
== NULL
)
3283 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3287 MultiByteToWideChar(CP_ACP
,
3292 (int)(strlen(lpBinaryPathName
) + 1));
3294 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
3296 dwError
= ScmCanonDriverImagePath(lpService
->dwStartType
,
3298 &lpCanonicalImagePathW
);
3300 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW
);
3302 if (dwError
!= ERROR_SUCCESS
)
3305 lpBinaryPathNameW
= lpCanonicalImagePathW
;
3308 dwError
= RegSetValueExW(hServiceKey
,
3312 (LPBYTE
)lpBinaryPathNameW
,
3313 (DWORD
)((wcslen(lpBinaryPathNameW
) + 1) * sizeof(WCHAR
)));
3315 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW
);
3317 if (dwError
!= ERROR_SUCCESS
)
3321 /* Set the group name */
3322 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
3324 lpLoadOrderGroupW
= HeapAlloc(GetProcessHeap(),
3326 (strlen(lpLoadOrderGroup
) + 1) * sizeof(WCHAR
));
3327 if (lpLoadOrderGroupW
== NULL
)
3329 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3333 MultiByteToWideChar(CP_ACP
,
3338 (int)(strlen(lpLoadOrderGroup
) + 1));
3340 dwError
= RegSetValueExW(hServiceKey
,
3344 (LPBYTE
)lpLoadOrderGroupW
,
3345 (DWORD
)((wcslen(lpLoadOrderGroupW
) + 1) * sizeof(WCHAR
)));
3346 if (dwError
!= ERROR_SUCCESS
)
3348 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3352 dwError
= ScmSetServiceGroup(lpService
,
3355 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3357 if (dwError
!= ERROR_SUCCESS
)
3361 if (lpdwTagId
!= NULL
)
3363 dwError
= ScmAssignNewTag(lpService
);
3364 if (dwError
!= ERROR_SUCCESS
)
3367 dwError
= RegSetValueExW(hServiceKey
,
3371 (LPBYTE
)&lpService
->dwTag
,
3373 if (dwError
!= ERROR_SUCCESS
)
3376 *lpdwTagId
= lpService
->dwTag
;
3379 /* Write dependencies */
3380 if (lpDependencies
!= NULL
&& *lpDependencies
!= 0)
3382 lpDependenciesW
= HeapAlloc(GetProcessHeap(),
3384 (strlen((LPSTR
)lpDependencies
) + 1) * sizeof(WCHAR
));
3385 if (lpDependenciesW
== NULL
)
3387 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3391 MultiByteToWideChar(CP_ACP
,
3393 (LPSTR
)lpDependencies
,
3396 (int)(strlen((LPSTR
)lpDependencies
) + 1));
3398 dwError
= ScmWriteDependencies(hServiceKey
,
3399 (LPWSTR
)lpDependenciesW
,
3402 HeapFree(GetProcessHeap(), 0, lpDependenciesW
);
3405 if (lpPassword
!= NULL
)
3407 /* FIXME: Decrypt and write password */
3411 /* Unlock the service database */
3412 ScmUnlockDatabase();
3414 if (hServiceKey
!= NULL
)
3415 RegCloseKey(hServiceKey
);
3417 DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError
);
3424 DWORD
RCreateServiceA(
3425 SC_RPC_HANDLE hSCManager
,
3426 LPSTR lpServiceName
,
3427 LPSTR lpDisplayName
,
3428 DWORD dwDesiredAccess
,
3429 DWORD dwServiceType
,
3431 DWORD dwErrorControl
,
3432 LPSTR lpBinaryPathName
,
3433 LPSTR lpLoadOrderGroup
,
3435 LPBYTE lpDependencies
,
3437 LPSTR lpServiceStartName
,
3440 LPSC_RPC_HANDLE lpServiceHandle
)
3442 DWORD dwError
= ERROR_SUCCESS
;
3443 LPWSTR lpServiceNameW
= NULL
;
3444 LPWSTR lpDisplayNameW
= NULL
;
3445 LPWSTR lpBinaryPathNameW
= NULL
;
3446 LPWSTR lpLoadOrderGroupW
= NULL
;
3447 LPWSTR lpDependenciesW
= NULL
;
3448 LPWSTR lpServiceStartNameW
= NULL
;
3449 DWORD dwDependenciesLength
= 0;
3456 len
= MultiByteToWideChar(CP_ACP
, 0, lpServiceName
, -1, NULL
, 0);
3457 lpServiceNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3458 if (!lpServiceNameW
)
3460 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3463 MultiByteToWideChar(CP_ACP
, 0, lpServiceName
, -1, lpServiceNameW
, len
);
3468 len
= MultiByteToWideChar(CP_ACP
, 0, lpDisplayName
, -1, NULL
, 0);
3469 lpDisplayNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3470 if (!lpDisplayNameW
)
3472 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3475 MultiByteToWideChar(CP_ACP
, 0, lpDisplayName
, -1, lpDisplayNameW
, len
);
3478 if (lpBinaryPathName
)
3480 len
= MultiByteToWideChar(CP_ACP
, 0, lpBinaryPathName
, -1, NULL
, 0);
3481 lpBinaryPathNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3482 if (!lpBinaryPathNameW
)
3484 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3487 MultiByteToWideChar(CP_ACP
, 0, lpBinaryPathName
, -1, lpBinaryPathNameW
, len
);
3490 if (lpLoadOrderGroup
)
3492 len
= MultiByteToWideChar(CP_ACP
, 0, lpLoadOrderGroup
, -1, NULL
, 0);
3493 lpLoadOrderGroupW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3494 if (!lpLoadOrderGroupW
)
3496 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3499 MultiByteToWideChar(CP_ACP
, 0, lpLoadOrderGroup
, -1, lpLoadOrderGroupW
, len
);
3504 lpStr
= (LPCSTR
)lpDependencies
;
3507 cchLength
= strlen(lpStr
) + 1;
3508 dwDependenciesLength
+= (DWORD
)cchLength
;
3509 lpStr
= lpStr
+ cchLength
;
3511 dwDependenciesLength
++;
3513 lpDependenciesW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwDependenciesLength
* sizeof(WCHAR
));
3514 if (!lpDependenciesW
)
3516 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3519 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)lpDependencies
, dwDependenciesLength
, lpDependenciesW
, dwDependenciesLength
);
3522 if (lpServiceStartName
)
3524 len
= MultiByteToWideChar(CP_ACP
, 0, lpServiceStartName
, -1, NULL
, 0);
3525 lpServiceStartNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3526 if (!lpServiceStartNameW
)
3528 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3531 MultiByteToWideChar(CP_ACP
, 0, lpServiceStartName
, -1, lpServiceStartNameW
, len
);
3534 dwError
= RCreateServiceW(hSCManager
,
3544 (LPBYTE
)lpDependenciesW
,
3545 dwDependenciesLength
,
3546 lpServiceStartNameW
,
3552 if (lpServiceNameW
!=NULL
)
3553 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
3555 if (lpDisplayNameW
!= NULL
)
3556 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
3558 if (lpBinaryPathNameW
!= NULL
)
3559 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW
);
3561 if (lpLoadOrderGroupW
!= NULL
)
3562 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3564 if (lpDependenciesW
!= NULL
)
3565 HeapFree(GetProcessHeap(), 0, lpDependenciesW
);
3567 if (lpServiceStartNameW
!= NULL
)
3568 HeapFree(GetProcessHeap(), 0, lpServiceStartNameW
);
3575 DWORD
REnumDependentServicesA(
3576 SC_RPC_HANDLE hService
,
3577 DWORD dwServiceState
,
3580 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
3581 LPBOUNDED_DWORD_256K lpServicesReturned
)
3583 DWORD dwError
= ERROR_SUCCESS
;
3584 DWORD dwServicesReturned
= 0;
3585 DWORD dwServiceCount
;
3586 HKEY hServicesKey
= NULL
;
3587 PSERVICE_HANDLE hSvc
;
3588 PSERVICE lpService
= NULL
;
3589 PSERVICE
*lpServicesArray
= NULL
;
3590 LPENUM_SERVICE_STATUSA lpServicesPtr
= NULL
;
3593 *pcbBytesNeeded
= 0;
3594 *lpServicesReturned
= 0;
3596 DPRINT("REnumDependentServicesA() called\n");
3598 hSvc
= ScmGetServiceFromHandle(hService
);
3601 DPRINT1("Invalid service handle!\n");
3602 return ERROR_INVALID_HANDLE
;
3605 lpService
= hSvc
->ServiceEntry
;
3607 /* Check access rights */
3608 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3609 SC_MANAGER_ENUMERATE_SERVICE
))
3611 DPRINT("Insufficient access rights! 0x%lx\n",
3612 hSvc
->Handle
.DesiredAccess
);
3613 return ERROR_ACCESS_DENIED
;
3616 /* Open the Services Reg key */
3617 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
3618 L
"System\\CurrentControlSet\\Services",
3623 if (dwError
!= ERROR_SUCCESS
)
3626 /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3627 both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3628 are the same for both. Verified in WINXP. */
3630 /* First determine the bytes needed and get the number of dependent services*/
3631 dwError
= Int_EnumDependentServicesW(hServicesKey
,
3636 &dwServicesReturned
);
3637 if (dwError
!= ERROR_SUCCESS
)
3640 /* If buffer size is less than the bytes needed or pointer is null*/
3641 if ((!lpServices
) || (cbBufSize
< *pcbBytesNeeded
))
3643 dwError
= ERROR_MORE_DATA
;
3647 /* Allocate memory for array of service pointers */
3648 lpServicesArray
= HeapAlloc(GetProcessHeap(),
3650 (dwServicesReturned
+ 1) * sizeof(PSERVICE
));
3651 if (!lpServicesArray
)
3653 DPRINT("Could not allocate a buffer!!\n");
3654 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3658 dwServicesReturned
= 0;
3659 *pcbBytesNeeded
= 0;
3661 dwError
= Int_EnumDependentServicesW(hServicesKey
,
3666 &dwServicesReturned
);
3667 if (dwError
!= ERROR_SUCCESS
)
3672 lpServicesPtr
= (LPENUM_SERVICE_STATUSA
)lpServices
;
3673 lpStr
= (LPSTR
)(lpServices
+ (dwServicesReturned
* sizeof(ENUM_SERVICE_STATUSA
)));
3675 /* Copy EnumDepenedentService to Buffer */
3676 for (dwServiceCount
= 0; dwServiceCount
< dwServicesReturned
; dwServiceCount
++)
3678 lpService
= lpServicesArray
[dwServiceCount
];
3680 /* Copy the status info */
3681 memcpy(&lpServicesPtr
->ServiceStatus
,
3683 sizeof(SERVICE_STATUS
));
3685 /* Copy display name */
3686 WideCharToMultiByte(CP_ACP
,
3688 lpService
->lpDisplayName
,
3691 (int)wcslen(lpService
->lpDisplayName
),
3694 lpServicesPtr
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
3695 lpStr
+= strlen(lpStr
) + 1;
3697 /* Copy service name */
3698 WideCharToMultiByte(CP_ACP
,
3700 lpService
->lpServiceName
,
3703 (int)wcslen(lpService
->lpServiceName
),
3706 lpServicesPtr
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
3707 lpStr
+= strlen(lpStr
) + 1;
3712 *lpServicesReturned
= dwServicesReturned
;
3715 if (lpServicesArray
)
3716 HeapFree(GetProcessHeap(), 0, lpServicesArray
);
3718 RegCloseKey(hServicesKey
);
3720 DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError
);
3727 DWORD
REnumServicesStatusA(
3728 SC_RPC_HANDLE hSCManager
,
3729 DWORD dwServiceType
,
3730 DWORD dwServiceState
,
3733 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
3734 LPBOUNDED_DWORD_256K lpServicesReturned
,
3735 LPBOUNDED_DWORD_256K lpResumeHandle
)
3737 LPENUM_SERVICE_STATUSW lpStatusPtrW
= NULL
;
3738 LPENUM_SERVICE_STATUSW lpStatusPtrIncrW
;
3739 LPENUM_SERVICE_STATUSA lpStatusPtrA
= NULL
;
3740 LPWSTR lpStringPtrW
;
3743 DWORD dwServiceCount
;
3745 DPRINT("REnumServicesStatusA() called\n");
3747 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
3749 return ERROR_INVALID_ADDRESS
;
3752 if ((dwBufSize
> 0) && (lpBuffer
))
3754 lpStatusPtrW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwBufSize
);
3757 DPRINT("Failed to allocate buffer!\n");
3758 return ERROR_NOT_ENOUGH_MEMORY
;
3762 dwError
= REnumServicesStatusW(hSCManager
,
3765 (LPBYTE
)lpStatusPtrW
,
3771 /* if no services were returned then we are Done */
3772 if (*lpServicesReturned
== 0)
3775 lpStatusPtrIncrW
= lpStatusPtrW
;
3776 lpStatusPtrA
= (LPENUM_SERVICE_STATUSA
)lpBuffer
;
3777 lpStringPtrA
= (LPSTR
)((ULONG_PTR
)lpBuffer
+
3778 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUSA
));
3779 lpStringPtrW
= (LPWSTR
)((ULONG_PTR
)lpStatusPtrW
+
3780 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUSW
));
3782 for (dwServiceCount
= 0; dwServiceCount
< *lpServicesReturned
; dwServiceCount
++)
3784 /* Copy the service name */
3785 WideCharToMultiByte(CP_ACP
,
3790 (int)wcslen(lpStringPtrW
),
3794 lpStatusPtrA
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
3795 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
3796 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
3798 /* Copy the display name */
3799 WideCharToMultiByte(CP_ACP
,
3804 (int)wcslen(lpStringPtrW
),
3808 lpStatusPtrA
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
3809 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
3810 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
3812 /* Copy the status information */
3813 memcpy(&lpStatusPtrA
->ServiceStatus
,
3814 &lpStatusPtrIncrW
->ServiceStatus
,
3815 sizeof(SERVICE_STATUS
));
3823 HeapFree(GetProcessHeap(), 0, lpStatusPtrW
);
3825 DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError
);
3832 DWORD
ROpenSCManagerA(
3833 LPSTR lpMachineName
,
3834 LPSTR lpDatabaseName
,
3835 DWORD dwDesiredAccess
,
3836 LPSC_RPC_HANDLE lpScHandle
)
3838 UNICODE_STRING MachineName
;
3839 UNICODE_STRING DatabaseName
;
3842 DPRINT("ROpenSCManagerA() called\n");
3845 RtlCreateUnicodeStringFromAsciiz(&MachineName
,
3849 RtlCreateUnicodeStringFromAsciiz(&DatabaseName
,
3852 dwError
= ROpenSCManagerW(lpMachineName
? MachineName
.Buffer
: NULL
,
3853 lpDatabaseName
? DatabaseName
.Buffer
: NULL
,
3858 RtlFreeUnicodeString(&MachineName
);
3861 RtlFreeUnicodeString(&DatabaseName
);
3868 DWORD
ROpenServiceA(
3869 SC_RPC_HANDLE hSCManager
,
3870 LPSTR lpServiceName
,
3871 DWORD dwDesiredAccess
,
3872 LPSC_RPC_HANDLE lpServiceHandle
)
3874 UNICODE_STRING ServiceName
;
3877 DPRINT("ROpenServiceA() called\n");
3880 RtlCreateUnicodeStringFromAsciiz(&ServiceName
,
3883 dwError
= ROpenServiceW(hSCManager
,
3884 lpServiceName
? ServiceName
.Buffer
: NULL
,
3889 RtlFreeUnicodeString(&ServiceName
);
3896 DWORD
RQueryServiceConfigA(
3897 SC_RPC_HANDLE hService
,
3898 LPBYTE lpBuf
, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
3900 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
3902 LPQUERY_SERVICE_CONFIGA lpServiceConfig
= (LPQUERY_SERVICE_CONFIGA
)lpBuf
;
3903 DWORD dwError
= ERROR_SUCCESS
;
3904 PSERVICE_HANDLE hSvc
;
3905 PSERVICE lpService
= NULL
;
3906 HKEY hServiceKey
= NULL
;
3907 LPWSTR lpImagePath
= NULL
;
3908 LPWSTR lpServiceStartName
= NULL
;
3909 LPWSTR lpDependencies
= NULL
;
3910 DWORD dwDependenciesLength
= 0;
3911 DWORD dwRequiredSize
;
3912 CHAR lpEmptyString
[]={0,0};
3915 DPRINT("RQueryServiceConfigA() called\n");
3918 return ERROR_SHUTDOWN_IN_PROGRESS
;
3920 hSvc
= ScmGetServiceFromHandle(hService
);
3923 DPRINT1("Invalid service handle!\n");
3924 return ERROR_INVALID_HANDLE
;
3927 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3928 SERVICE_QUERY_CONFIG
))
3930 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
3931 return ERROR_ACCESS_DENIED
;
3934 lpService
= hSvc
->ServiceEntry
;
3935 if (lpService
== NULL
)
3937 DPRINT("lpService == NULL!\n");
3938 return ERROR_INVALID_HANDLE
;
3941 /* Lock the service database shared */
3942 ScmLockDatabaseShared();
3944 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
3947 if (dwError
!= ERROR_SUCCESS
)
3950 /* Read the image path */
3951 dwError
= ScmReadString(hServiceKey
,
3954 if (dwError
!= ERROR_SUCCESS
)
3957 /* Read the service start name */
3958 ScmReadString(hServiceKey
,
3960 &lpServiceStartName
);
3962 /* Read the dependencies */
3963 ScmReadDependencies(hServiceKey
,
3965 &dwDependenciesLength
);
3967 dwRequiredSize
= sizeof(QUERY_SERVICE_CONFIGA
);
3969 if (lpImagePath
!= NULL
)
3970 dwRequiredSize
+= (DWORD
)(wcslen(lpImagePath
) + 1);
3972 dwRequiredSize
+= 2;
3974 if ((lpService
->lpGroup
!= NULL
) && (lpService
->lpGroup
->lpGroupName
!= NULL
))
3975 dwRequiredSize
+= (DWORD
)(wcslen(lpService
->lpGroup
->lpGroupName
) + 1);
3977 dwRequiredSize
+= 2;
3979 /* Add Dependencies length */
3980 if (lpDependencies
!= NULL
)
3981 dwRequiredSize
+= dwDependenciesLength
;
3983 dwRequiredSize
+= 2;
3985 if (lpServiceStartName
!= NULL
)
3986 dwRequiredSize
+= (DWORD
)(wcslen(lpServiceStartName
) + 1);
3988 dwRequiredSize
+= 2;
3990 if (lpService
->lpDisplayName
!= NULL
)
3991 dwRequiredSize
+= (DWORD
)(wcslen(lpService
->lpDisplayName
) + 1);
3993 dwRequiredSize
+= 2;
3995 if (lpServiceConfig
== NULL
|| cbBufSize
< dwRequiredSize
)
3997 dwError
= ERROR_INSUFFICIENT_BUFFER
;
4001 lpServiceConfig
->dwServiceType
= lpService
->Status
.dwServiceType
;
4002 lpServiceConfig
->dwStartType
= lpService
->dwStartType
;
4003 lpServiceConfig
->dwErrorControl
= lpService
->dwErrorControl
;
4004 lpServiceConfig
->dwTagId
= lpService
->dwTag
;
4006 lpStr
= (LPSTR
)(lpServiceConfig
+ 1);
4008 /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
4009 Verified in WINXP */
4013 WideCharToMultiByte(CP_ACP
,
4018 (int)(wcslen(lpImagePath
) + 1),
4024 strcpy(lpStr
, lpEmptyString
);
4027 lpServiceConfig
->lpBinaryPathName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4028 lpStr
+= (strlen((LPSTR
)lpStr
) + 1);
4030 if (lpService
->lpGroup
&& lpService
->lpGroup
->lpGroupName
)
4032 WideCharToMultiByte(CP_ACP
,
4034 lpService
->lpGroup
->lpGroupName
,
4037 (int)(wcslen(lpService
->lpGroup
->lpGroupName
) + 1),
4043 strcpy(lpStr
, lpEmptyString
);
4046 lpServiceConfig
->lpLoadOrderGroup
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4047 lpStr
+= (strlen(lpStr
) + 1);
4049 /* Append Dependencies */
4052 WideCharToMultiByte(CP_ACP
,
4055 dwDependenciesLength
,
4057 dwDependenciesLength
,
4063 strcpy(lpStr
, lpEmptyString
);
4066 lpServiceConfig
->lpDependencies
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4068 lpStr
+= dwDependenciesLength
;
4070 lpStr
+= (strlen(lpStr
) + 1);
4072 if (lpServiceStartName
)
4074 WideCharToMultiByte(CP_ACP
,
4079 (int)(wcslen(lpServiceStartName
) + 1),
4085 strcpy(lpStr
, lpEmptyString
);
4088 lpServiceConfig
->lpServiceStartName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4089 lpStr
+= (strlen(lpStr
) + 1);
4091 if (lpService
->lpDisplayName
)
4093 WideCharToMultiByte(CP_ACP
,
4095 lpService
->lpDisplayName
,
4098 (int)(wcslen(lpService
->lpDisplayName
) + 1),
4104 strcpy(lpStr
, lpEmptyString
);
4107 lpServiceConfig
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4110 if (pcbBytesNeeded
!= NULL
)
4111 *pcbBytesNeeded
= dwRequiredSize
;
4114 /* Unlock the service database */
4115 ScmUnlockDatabase();
4117 if (lpImagePath
!= NULL
)
4118 HeapFree(GetProcessHeap(), 0, lpImagePath
);
4120 if (lpServiceStartName
!= NULL
)
4121 HeapFree(GetProcessHeap(), 0, lpServiceStartName
);
4123 if (lpDependencies
!= NULL
)
4124 HeapFree(GetProcessHeap(), 0, lpDependencies
);
4126 if (hServiceKey
!= NULL
)
4127 RegCloseKey(hServiceKey
);
4129 DPRINT("RQueryServiceConfigA() done\n");
4136 DWORD
RQueryServiceLockStatusA(
4137 SC_RPC_HANDLE hSCManager
,
4138 LPBYTE lpBuf
, // LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
4140 LPBOUNDED_DWORD_4K pcbBytesNeeded
)
4142 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
= (LPQUERY_SERVICE_LOCK_STATUSA
)lpBuf
;
4143 PMANAGER_HANDLE hMgr
;
4144 DWORD dwRequiredSize
;
4146 if (!lpLockStatus
|| !pcbBytesNeeded
)
4147 return ERROR_INVALID_PARAMETER
;
4149 hMgr
= ScmGetServiceManagerFromHandle(hSCManager
);
4152 DPRINT1("Invalid service manager handle!\n");
4153 return ERROR_INVALID_HANDLE
;
4156 if (!RtlAreAllAccessesGranted(hMgr
->Handle
.DesiredAccess
,
4157 SC_MANAGER_QUERY_LOCK_STATUS
))
4159 DPRINT("Insufficient access rights! 0x%lx\n", hMgr
->Handle
.DesiredAccess
);
4160 return ERROR_ACCESS_DENIED
;
4163 /* FIXME: we need to compute instead the real length of the owner name */
4164 dwRequiredSize
= sizeof(QUERY_SERVICE_LOCK_STATUSA
) + sizeof(CHAR
);
4165 *pcbBytesNeeded
= dwRequiredSize
;
4167 if (cbBufSize
< dwRequiredSize
)
4168 return ERROR_INSUFFICIENT_BUFFER
;
4170 ScmQueryServiceLockStatusA(lpLockStatus
);
4172 return ERROR_SUCCESS
;
4177 DWORD
RStartServiceA(
4178 SC_RPC_HANDLE hService
,
4180 LPSTRING_PTRSA argv
)
4182 DWORD dwError
= ERROR_SUCCESS
;
4183 PSERVICE_HANDLE hSvc
;
4184 PSERVICE lpService
= NULL
;
4185 LPWSTR
*lpVector
= NULL
;
4189 DPRINT("RStartServiceA() called\n");
4192 return ERROR_SHUTDOWN_IN_PROGRESS
;
4194 hSvc
= ScmGetServiceFromHandle(hService
);
4197 DPRINT1("Invalid service handle!\n");
4198 return ERROR_INVALID_HANDLE
;
4201 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
4204 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
4205 return ERROR_ACCESS_DENIED
;
4208 lpService
= hSvc
->ServiceEntry
;
4209 if (lpService
== NULL
)
4211 DPRINT("lpService == NULL!\n");
4212 return ERROR_INVALID_HANDLE
;
4215 if (lpService
->dwStartType
== SERVICE_DISABLED
)
4216 return ERROR_SERVICE_DISABLED
;
4218 if (lpService
->bDeleted
)
4219 return ERROR_SERVICE_MARKED_FOR_DELETE
;
4221 /* Build a Unicode argument vector */
4224 lpVector
= HeapAlloc(GetProcessHeap(),
4226 argc
* sizeof(LPWSTR
));
4227 if (lpVector
== NULL
)
4228 return ERROR_NOT_ENOUGH_MEMORY
;
4230 for (i
= 0; i
< argc
; i
++)
4232 dwLength
= MultiByteToWideChar(CP_ACP
,
4239 lpVector
[i
] = HeapAlloc(GetProcessHeap(),
4241 dwLength
* sizeof(WCHAR
));
4242 if (lpVector
[i
] == NULL
)
4244 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
4248 MultiByteToWideChar(CP_ACP
,
4257 /* Start the service */
4258 dwError
= ScmStartService(lpService
, argc
, lpVector
);
4261 /* Free the Unicode argument vector */
4262 if (lpVector
!= NULL
)
4264 for (i
= 0; i
< argc
; i
++)
4266 if (lpVector
[i
] != NULL
)
4267 HeapFree(GetProcessHeap(), 0, lpVector
[i
]);
4269 HeapFree(GetProcessHeap(), 0, lpVector
);
4277 DWORD
RGetServiceDisplayNameA(
4278 SC_RPC_HANDLE hSCManager
,
4279 LPCSTR lpServiceName
,
4280 LPSTR lpDisplayName
,
4281 LPBOUNDED_DWORD_4K lpcchBuffer
)
4283 // PMANAGER_HANDLE hManager;
4284 PSERVICE lpService
= NULL
;
4287 LPWSTR lpServiceNameW
;
4289 DPRINT("RGetServiceDisplayNameA() called\n");
4290 DPRINT("hSCManager = %p\n", hSCManager
);
4291 DPRINT("lpServiceName: %s\n", lpServiceName
);
4292 DPRINT("lpDisplayName: %p\n", lpDisplayName
);
4293 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
4295 // hManager = (PMANAGER_HANDLE)hSCManager;
4296 // if (hManager->Handle.Tag != MANAGER_TAG)
4298 // DPRINT("Invalid manager handle!\n");
4299 // return ERROR_INVALID_HANDLE;
4302 if (lpServiceName
!= NULL
)
4304 dwLength
= (DWORD
)(strlen(lpServiceName
) + 1);
4305 lpServiceNameW
= HeapAlloc(GetProcessHeap(),
4307 dwLength
* sizeof(WCHAR
));
4308 if (!lpServiceNameW
)
4309 return ERROR_NOT_ENOUGH_MEMORY
;
4311 MultiByteToWideChar(CP_ACP
,
4318 lpService
= ScmGetServiceEntryByName(lpServiceNameW
);
4320 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
4323 if (lpService
== NULL
)
4325 DPRINT("Could not find a service!\n");
4327 /* If the service could not be found and lpcchBuffer is 0, windows
4328 puts null in lpDisplayName and puts 1 in lpcchBuffer */
4329 if (*lpcchBuffer
== 0)
4332 if (lpDisplayName
!= NULL
)
4337 return ERROR_SERVICE_DOES_NOT_EXIST
;
4340 if (!lpService
->lpDisplayName
)
4342 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
4343 if (lpDisplayName
!= NULL
&&
4344 *lpcchBuffer
> dwLength
)
4346 WideCharToMultiByte(CP_ACP
,
4348 lpService
->lpServiceName
,
4349 (int)wcslen(lpService
->lpServiceName
),
4354 return ERROR_SUCCESS
;
4359 dwLength
= (DWORD
)wcslen(lpService
->lpDisplayName
);
4360 if (lpDisplayName
!= NULL
&&
4361 *lpcchBuffer
> dwLength
)
4363 WideCharToMultiByte(CP_ACP
,
4365 lpService
->lpDisplayName
,
4366 (int)wcslen(lpService
->lpDisplayName
),
4371 return ERROR_SUCCESS
;
4375 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
4377 *lpcchBuffer
= dwLength
* 2;
4384 DWORD
RGetServiceKeyNameA(
4385 SC_RPC_HANDLE hSCManager
,
4386 LPCSTR lpDisplayName
,
4387 LPSTR lpServiceName
,
4388 LPBOUNDED_DWORD_4K lpcchBuffer
)
4393 LPWSTR lpDisplayNameW
;
4395 DPRINT("RGetServiceKeyNameA() called\n");
4396 DPRINT("hSCManager = %p\n", hSCManager
);
4397 DPRINT("lpDisplayName: %s\n", lpDisplayName
);
4398 DPRINT("lpServiceName: %p\n", lpServiceName
);
4399 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
4401 dwLength
= (DWORD
)(strlen(lpDisplayName
) + 1);
4402 lpDisplayNameW
= HeapAlloc(GetProcessHeap(),
4404 dwLength
* sizeof(WCHAR
));
4405 if (!lpDisplayNameW
)
4406 return ERROR_NOT_ENOUGH_MEMORY
;
4408 MultiByteToWideChar(CP_ACP
,
4415 lpService
= ScmGetServiceEntryByDisplayName(lpDisplayNameW
);
4417 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
4419 if (lpService
== NULL
)
4421 DPRINT("Could not find the service!\n");
4423 /* If the service could not be found and lpcchBuffer is 0,
4424 put null in lpDisplayName and puts 1 in lpcchBuffer, verified WINXP. */
4425 if (*lpcchBuffer
== 0)
4428 if (lpServiceName
!= NULL
)
4434 return ERROR_SERVICE_DOES_NOT_EXIST
;
4437 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
4438 if (lpServiceName
!= NULL
&&
4439 *lpcchBuffer
> dwLength
)
4441 WideCharToMultiByte(CP_ACP
,
4443 lpService
->lpServiceName
,
4444 (int)wcslen(lpService
->lpServiceName
),
4449 return ERROR_SUCCESS
;
4452 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
4454 *lpcchBuffer
= dwLength
* 2;
4461 DWORD
RI_ScGetCurrentGroupStateW(
4462 SC_RPC_HANDLE hSCManager
,
4463 LPWSTR lpLoadOrderGroup
,
4467 return ERROR_CALL_NOT_IMPLEMENTED
;
4472 DWORD
REnumServiceGroupW(
4473 SC_RPC_HANDLE hSCManager
,
4474 DWORD dwServiceType
,
4475 DWORD dwServiceState
,
4478 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
4479 LPBOUNDED_DWORD_256K lpServicesReturned
,
4480 LPBOUNDED_DWORD_256K lpResumeIndex
,
4481 LPCWSTR pszGroupName
)
4483 PMANAGER_HANDLE hManager
;
4485 DWORD dwError
= ERROR_SUCCESS
;
4486 PLIST_ENTRY ServiceEntry
;
4487 PSERVICE CurrentService
;
4489 DWORD dwRequiredSize
;
4490 DWORD dwServiceCount
;
4492 DWORD dwLastResumeCount
= 0;
4493 LPENUM_SERVICE_STATUSW lpStatusPtr
;
4496 DPRINT("REnumServiceGroupW() called\n");
4499 return ERROR_SHUTDOWN_IN_PROGRESS
;
4501 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
4502 if (hManager
== NULL
)
4504 DPRINT1("Invalid service manager handle!\n");
4505 return ERROR_INVALID_HANDLE
;
4508 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
4510 return ERROR_INVALID_ADDRESS
;
4513 *pcbBytesNeeded
= 0;
4514 *lpServicesReturned
= 0;
4516 if ((dwServiceType
== 0) ||
4517 ((dwServiceType
& ~SERVICE_TYPE_ALL
) != 0))
4519 DPRINT("Not a valid Service Type!\n");
4520 return ERROR_INVALID_PARAMETER
;
4523 if ((dwServiceState
== 0) ||
4524 ((dwServiceState
& ~SERVICE_STATE_ALL
) != 0))
4526 DPRINT("Not a valid Service State!\n");
4527 return ERROR_INVALID_PARAMETER
;
4530 /* Check access rights */
4531 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
4532 SC_MANAGER_ENUMERATE_SERVICE
))
4534 DPRINT("Insufficient access rights! 0x%lx\n",
4535 hManager
->Handle
.DesiredAccess
);
4536 return ERROR_ACCESS_DENIED
;
4540 dwLastResumeCount
= *lpResumeIndex
;
4542 /* Lock the service database shared */
4543 ScmLockDatabaseShared();
4545 lpService
= ScmGetServiceEntryByResumeCount(dwLastResumeCount
);
4546 if (lpService
== NULL
)
4548 dwError
= ERROR_SUCCESS
;
4555 for (ServiceEntry
= &lpService
->ServiceListEntry
;
4556 ServiceEntry
!= &ServiceListHead
;
4557 ServiceEntry
= ServiceEntry
->Flink
)
4559 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
4563 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
4566 dwState
= SERVICE_ACTIVE
;
4567 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
4568 dwState
= SERVICE_INACTIVE
;
4570 if ((dwState
& dwServiceState
) == 0)
4575 if (*pszGroupName
== 0)
4577 if (CurrentService
->lpGroup
!= NULL
)
4582 if ((CurrentService
->lpGroup
== NULL
) ||
4583 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
4588 dwSize
= sizeof(ENUM_SERVICE_STATUSW
) +
4589 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
4590 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
4592 if (dwRequiredSize
+ dwSize
> cbBufSize
)
4594 DPRINT("Service name: %S no fit\n", CurrentService
->lpServiceName
);
4598 DPRINT("Service name: %S fit\n", CurrentService
->lpServiceName
);
4599 dwRequiredSize
+= dwSize
;
4601 dwLastResumeCount
= CurrentService
->dwResumeCount
;
4604 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize
);
4605 DPRINT("dwServiceCount: %lu\n", dwServiceCount
);
4608 ServiceEntry
!= &ServiceListHead
;
4609 ServiceEntry
= ServiceEntry
->Flink
)
4611 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
4615 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
4618 dwState
= SERVICE_ACTIVE
;
4619 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
4620 dwState
= SERVICE_INACTIVE
;
4622 if ((dwState
& dwServiceState
) == 0)
4627 if (*pszGroupName
== 0)
4629 if (CurrentService
->lpGroup
!= NULL
)
4634 if ((CurrentService
->lpGroup
== NULL
) ||
4635 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
4640 dwRequiredSize
+= (sizeof(ENUM_SERVICE_STATUSW
) +
4641 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
4642 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
)));
4644 dwError
= ERROR_MORE_DATA
;
4647 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize
);
4650 *lpResumeIndex
= dwLastResumeCount
;
4652 *lpServicesReturned
= dwServiceCount
;
4653 *pcbBytesNeeded
= dwRequiredSize
;
4655 lpStatusPtr
= (LPENUM_SERVICE_STATUSW
)lpBuffer
;
4656 lpStringPtr
= (LPWSTR
)((ULONG_PTR
)lpBuffer
+
4657 dwServiceCount
* sizeof(ENUM_SERVICE_STATUSW
));
4660 for (ServiceEntry
= &lpService
->ServiceListEntry
;
4661 ServiceEntry
!= &ServiceListHead
;
4662 ServiceEntry
= ServiceEntry
->Flink
)
4664 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
4668 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
4671 dwState
= SERVICE_ACTIVE
;
4672 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
4673 dwState
= SERVICE_INACTIVE
;
4675 if ((dwState
& dwServiceState
) == 0)
4680 if (*pszGroupName
== 0)
4682 if (CurrentService
->lpGroup
!= NULL
)
4687 if ((CurrentService
->lpGroup
== NULL
) ||
4688 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
4693 dwSize
= sizeof(ENUM_SERVICE_STATUSW
) +
4694 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
4695 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
4697 if (dwRequiredSize
+ dwSize
> cbBufSize
)
4700 /* Copy the service name */
4701 wcscpy(lpStringPtr
, CurrentService
->lpServiceName
);
4702 lpStatusPtr
->lpServiceName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
4703 lpStringPtr
+= (wcslen(CurrentService
->lpServiceName
) + 1);
4705 /* Copy the display name */
4706 wcscpy(lpStringPtr
, CurrentService
->lpDisplayName
);
4707 lpStatusPtr
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
4708 lpStringPtr
+= (wcslen(CurrentService
->lpDisplayName
) + 1);
4710 /* Copy the status information */
4711 memcpy(&lpStatusPtr
->ServiceStatus
,
4712 &CurrentService
->Status
,
4713 sizeof(SERVICE_STATUS
));
4716 dwRequiredSize
+= dwSize
;
4719 if (dwError
== ERROR_SUCCESS
)
4721 *pcbBytesNeeded
= 0;
4722 if (lpResumeIndex
) *lpResumeIndex
= 0;
4726 /* Unlock the service database */
4727 ScmUnlockDatabase();
4729 DPRINT("REnumServiceGroupW() done (Error %lu)\n", dwError
);
4736 DWORD
RChangeServiceConfig2A(
4737 SC_RPC_HANDLE hService
,
4738 SC_RPC_CONFIG_INFOA Info
)
4740 SC_RPC_CONFIG_INFOW InfoW
;
4741 DWORD dwRet
, dwLength
;
4744 DPRINT("RChangeServiceConfig2A() called\n");
4745 DPRINT("dwInfoLevel = %lu\n", Info
.dwInfoLevel
);
4747 InfoW
.dwInfoLevel
= Info
.dwInfoLevel
;
4749 if (InfoW
.dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
4751 LPSERVICE_DESCRIPTIONW lpServiceDescriptionW
;
4752 //LPSERVICE_DESCRIPTIONA lpServiceDescriptionA;
4754 //lpServiceDescriptionA = Info.psd;
4756 ///if (lpServiceDescriptionA &&
4757 ///lpServiceDescriptionA->lpDescription)
4759 dwLength
= (DWORD
)((strlen(Info
.lpDescription
) + 1) * sizeof(WCHAR
));
4761 lpServiceDescriptionW
= HeapAlloc(GetProcessHeap(),
4763 dwLength
+ sizeof(SERVICE_DESCRIPTIONW
));
4764 if (!lpServiceDescriptionW
)
4766 return ERROR_NOT_ENOUGH_MEMORY
;
4769 lpServiceDescriptionW
->lpDescription
= (LPWSTR
)(lpServiceDescriptionW
+ 1);
4771 MultiByteToWideChar(CP_ACP
,
4775 lpServiceDescriptionW
->lpDescription
,
4778 ptr
= lpServiceDescriptionW
;
4779 InfoW
.psd
= lpServiceDescriptionW
;
4782 else if (Info
.dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
4784 LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW
;
4785 LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA
;
4786 DWORD dwRebootLen
= 0;
4787 DWORD dwCommandLen
= 0;
4788 DWORD dwActionArrayLen
= 0;
4789 LPWSTR lpStr
= NULL
;
4791 lpServiceFailureActionsA
= Info
.psfa
;
4793 if (lpServiceFailureActionsA
)
4796 * The following code is inspired by the
4797 * SERVICE_CONFIG_FAILURE_ACTIONS case of
4798 * the RQueryServiceConfig2W function.
4801 /* Retrieve the needed length for the two data strings */
4802 if (lpServiceFailureActionsA
->lpRebootMsg
)
4804 dwRebootLen
= (DWORD
)((strlen(lpServiceFailureActionsA
->lpRebootMsg
) + 1) * sizeof(WCHAR
));
4806 if (lpServiceFailureActionsA
->lpCommand
)
4808 dwCommandLen
= (DWORD
)((strlen(lpServiceFailureActionsA
->lpCommand
) + 1) * sizeof(WCHAR
));
4812 * Retrieve the size of the lpsaActions array if needed.
4813 * We will copy the lpsaActions array only if there is at
4814 * least one action AND that the original array is valid.
4816 if (lpServiceFailureActionsA
->cActions
> 0 && lpServiceFailureActionsA
->lpsaActions
)
4818 dwActionArrayLen
= lpServiceFailureActionsA
->cActions
* sizeof(SC_ACTION
);
4821 /* Compute the total length for the UNICODE structure, including data */
4822 dwLength
= sizeof(SERVICE_FAILURE_ACTIONSW
) +
4823 dwActionArrayLen
+ dwRebootLen
+ dwCommandLen
;
4825 /* Allocate the structure */
4826 lpServiceFailureActionsW
= HeapAlloc(GetProcessHeap(),
4829 if (!lpServiceFailureActionsW
)
4831 return ERROR_NOT_ENOUGH_MEMORY
;
4834 /* Copy the members */
4835 lpServiceFailureActionsW
->dwResetPeriod
= lpServiceFailureActionsA
->dwResetPeriod
;
4836 lpServiceFailureActionsW
->cActions
= lpServiceFailureActionsA
->cActions
;
4838 /* Copy the lpsaActions array if needed */
4839 if (dwActionArrayLen
> 0)
4841 /* The storage zone is just after the end of the SERVICE_FAILURE_ACTIONSW structure */
4842 lpServiceFailureActionsW
->lpsaActions
= (LPSC_ACTION
)((ULONG_PTR
)(lpServiceFailureActionsW
+ 1));
4844 /* dwActionArrayLen == lpServiceFailureActionsW->cActions * sizeof(SC_ACTION) */
4845 RtlCopyMemory(lpServiceFailureActionsW
->lpsaActions
,
4846 lpServiceFailureActionsA
->lpsaActions
,
4851 /* No lpsaActions array */
4852 lpServiceFailureActionsW
->lpsaActions
= NULL
;
4854 /* The data strings are stored just after the lpsaActions array */
4855 lpStr
= (LPWSTR
)((ULONG_PTR
)(lpServiceFailureActionsW
+ 1) + dwActionArrayLen
);
4858 * Convert the data strings to UNICODE
4861 lpServiceFailureActionsW
->lpRebootMsg
= NULL
;
4862 lpServiceFailureActionsW
->lpCommand
= NULL
;
4866 /* lpRebootMsg points just after the lpsaActions array */
4867 lpServiceFailureActionsW
->lpRebootMsg
= lpStr
;
4869 MultiByteToWideChar(CP_ACP
,
4871 lpServiceFailureActionsA
->lpRebootMsg
,
4873 lpServiceFailureActionsW
->lpRebootMsg
,
4876 lpStr
+= dwRebootLen
/ sizeof(WCHAR
);
4881 /* lpRebootMsg points just after the lpRebootMsg data string */
4882 lpServiceFailureActionsW
->lpCommand
= lpStr
;
4884 MultiByteToWideChar(CP_ACP
,
4886 lpServiceFailureActionsA
->lpCommand
,
4888 lpServiceFailureActionsW
->lpCommand
,
4892 /* Set the pointers */
4893 ptr
= lpServiceFailureActionsW
;
4894 InfoW
.psfa
= lpServiceFailureActionsW
;
4898 dwRet
= RChangeServiceConfig2W(hService
, InfoW
);
4900 HeapFree(GetProcessHeap(), 0, ptr
);
4907 ScmSetFailureActions(PSERVICE_HANDLE hSvc
,
4910 LPSERVICE_FAILURE_ACTIONSW lpFailureActions
)
4912 LPSERVICE_FAILURE_ACTIONSW lpReadBuffer
= NULL
;
4913 LPSERVICE_FAILURE_ACTIONSW lpWriteBuffer
= NULL
;
4914 BOOL bIsActionRebootSet
= FALSE
;
4915 DWORD dwDesiredAccess
= SERVICE_CHANGE_CONFIG
;
4916 DWORD dwRequiredSize
= 0;
4921 /* There is nothing to be done if we have no failure actions */
4922 if (lpFailureActions
== NULL
)
4923 return ERROR_SUCCESS
;
4926 * 1- Check whether or not we can set
4927 * failure actions for this service.
4930 /* Failure actions can only be set for Win32 services, not for drivers */
4931 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
4932 return ERROR_CANNOT_DETECT_DRIVER_FAILURE
;
4935 * If the service controller handles the SC_ACTION_RESTART action,
4936 * hService must have the SERVICE_START access right.
4938 * If you specify SC_ACTION_REBOOT, the caller must have the
4939 * SE_SHUTDOWN_NAME privilege.
4941 if (lpFailureActions
->cActions
> 0 &&
4942 lpFailureActions
->lpsaActions
!= NULL
)
4944 for (i
= 0; i
< lpFailureActions
->cActions
; ++i
)
4946 if (lpFailureActions
->lpsaActions
[i
].Type
== SC_ACTION_RESTART
)
4947 dwDesiredAccess
|= SERVICE_START
;
4948 else if (lpFailureActions
->lpsaActions
[i
].Type
== SC_ACTION_REBOOT
)
4949 bIsActionRebootSet
= TRUE
;
4953 /* Re-check the access rights */
4954 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
4957 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
4958 return ERROR_ACCESS_DENIED
;
4961 /* FIXME: Check if the caller has the SE_SHUTDOWN_NAME privilege */
4962 if (bIsActionRebootSet
)
4967 * 2- Retrieve the original value of FailureActions.
4970 /* Query value length */
4971 dwError
= RegQueryValueExW(hServiceKey
,
4977 if (dwError
!= ERROR_SUCCESS
&&
4978 dwError
!= ERROR_MORE_DATA
&&
4979 dwError
!= ERROR_FILE_NOT_FOUND
)
4982 dwRequiredSize
= (dwType
== REG_BINARY
) ? max(sizeof(SERVICE_FAILURE_ACTIONSW
), dwRequiredSize
)
4983 : sizeof(SERVICE_FAILURE_ACTIONSW
);
4985 /* Initialize the read buffer */
4986 lpReadBuffer
= HeapAlloc(GetProcessHeap(),
4989 if (lpReadBuffer
== NULL
)
4990 return ERROR_NOT_ENOUGH_MEMORY
;
4992 /* Now we can fill the read buffer */
4993 if (dwError
!= ERROR_FILE_NOT_FOUND
&&
4994 dwType
== REG_BINARY
)
4996 dwError
= RegQueryValueExW(hServiceKey
,
5000 (LPBYTE
)lpReadBuffer
,
5002 if (dwError
!= ERROR_SUCCESS
&&
5003 dwError
!= ERROR_FILE_NOT_FOUND
)
5006 if (dwRequiredSize
< sizeof(SERVICE_FAILURE_ACTIONSW
))
5007 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSW
);
5012 * The value of the error doesn't really matter, the only
5013 * important thing is that it must be != ERROR_SUCCESS.
5015 dwError
= ERROR_INVALID_DATA
;
5018 if (dwError
== ERROR_SUCCESS
)
5020 lpReadBuffer
->cActions
= min(lpReadBuffer
->cActions
, (dwRequiredSize
- sizeof(SERVICE_FAILURE_ACTIONSW
)) / sizeof(SC_ACTION
));
5021 lpReadBuffer
->lpsaActions
= (lpReadBuffer
->cActions
> 0 ? (LPSC_ACTION
)(lpReadBuffer
+ 1) : NULL
);
5025 lpReadBuffer
->dwResetPeriod
= 0;
5026 lpReadBuffer
->cActions
= 0;
5027 lpReadBuffer
->lpsaActions
= NULL
;
5030 lpReadBuffer
->lpRebootMsg
= NULL
;
5031 lpReadBuffer
->lpCommand
= NULL
;
5034 * 3- Initialize the new value to set.
5037 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSW
);
5039 if (lpFailureActions
->lpsaActions
== NULL
)
5042 * lpFailureActions->cActions is ignored.
5043 * Therefore we use the original values
5044 * of cActions and lpsaActions.
5046 dwRequiredSize
+= lpReadBuffer
->cActions
* sizeof(SC_ACTION
);
5051 * The reset period and array of failure actions
5052 * are deleted if lpFailureActions->cActions == 0 .
5054 dwRequiredSize
+= lpFailureActions
->cActions
* sizeof(SC_ACTION
);
5057 lpWriteBuffer
= HeapAlloc(GetProcessHeap(),
5060 if (lpWriteBuffer
== NULL
)
5062 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
5066 /* Clean the pointers as they have no meaning when the structure is stored in the registry */
5067 lpWriteBuffer
->lpRebootMsg
= NULL
;
5068 lpWriteBuffer
->lpCommand
= NULL
;
5069 lpWriteBuffer
->lpsaActions
= NULL
;
5071 /* Set the members */
5072 if (lpFailureActions
->lpsaActions
== NULL
)
5075 * lpFailureActions->dwResetPeriod and lpFailureActions->cActions are ignored.
5076 * Therefore we use the original values of dwResetPeriod, cActions and lpsaActions.
5078 lpWriteBuffer
->dwResetPeriod
= lpReadBuffer
->dwResetPeriod
;
5079 lpWriteBuffer
->cActions
= lpReadBuffer
->cActions
;
5081 if (lpReadBuffer
->lpsaActions
!= NULL
)
5083 memmove(lpWriteBuffer
+ 1,
5084 lpReadBuffer
->lpsaActions
,
5085 lpReadBuffer
->cActions
* sizeof(SC_ACTION
));
5090 if (lpFailureActions
->cActions
> 0)
5092 lpWriteBuffer
->dwResetPeriod
= lpFailureActions
->dwResetPeriod
;
5093 lpWriteBuffer
->cActions
= lpFailureActions
->cActions
;
5095 memmove(lpWriteBuffer
+ 1,
5096 lpFailureActions
->lpsaActions
,
5097 lpFailureActions
->cActions
* sizeof(SC_ACTION
));
5101 /* The reset period and array of failure actions are deleted */
5102 lpWriteBuffer
->dwResetPeriod
= 0;
5103 lpWriteBuffer
->cActions
= 0;
5107 /* Save the new failure actions into the registry */
5108 dwError
= RegSetValueExW(hServiceKey
,
5112 (LPBYTE
)lpWriteBuffer
,
5115 /* We modify the strings only in case of success.*/
5116 if (dwError
== ERROR_SUCCESS
)
5118 /* Modify the Reboot Message value, if specified */
5119 if (lpFailureActions
->lpRebootMsg
!= NULL
)
5121 /* If the Reboot Message is "" then we delete it */
5122 if (*lpFailureActions
->lpRebootMsg
== 0)
5124 DPRINT("Delete Reboot Message value\n");
5125 RegDeleteValueW(hServiceKey
, L
"RebootMessage");
5129 DPRINT("Setting Reboot Message value %S\n", lpFailureActions
->lpRebootMsg
);
5130 RegSetValueExW(hServiceKey
,
5134 (LPBYTE
)lpFailureActions
->lpRebootMsg
,
5135 (DWORD
)((wcslen(lpFailureActions
->lpRebootMsg
) + 1) * sizeof(WCHAR
)));
5139 /* Modify the Failure Command value, if specified */
5140 if (lpFailureActions
->lpCommand
!= NULL
)
5142 /* If the FailureCommand string is an empty string, delete the value */
5143 if (*lpFailureActions
->lpCommand
== 0)
5145 DPRINT("Delete Failure Command value\n");
5146 RegDeleteValueW(hServiceKey
, L
"FailureCommand");
5150 DPRINT("Setting Failure Command value %S\n", lpFailureActions
->lpCommand
);
5151 RegSetValueExW(hServiceKey
,
5155 (LPBYTE
)lpFailureActions
->lpCommand
,
5156 (DWORD
)((wcslen(lpFailureActions
->lpCommand
) + 1) * sizeof(WCHAR
)));
5162 if (lpWriteBuffer
!= NULL
)
5163 HeapFree(GetProcessHeap(), 0, lpWriteBuffer
);
5165 if (lpReadBuffer
!= NULL
)
5166 HeapFree(GetProcessHeap(), 0, lpReadBuffer
);
5173 DWORD
RChangeServiceConfig2W(
5174 SC_RPC_HANDLE hService
,
5175 SC_RPC_CONFIG_INFOW Info
)
5177 DWORD dwError
= ERROR_SUCCESS
;
5178 PSERVICE_HANDLE hSvc
;
5179 PSERVICE lpService
= NULL
;
5180 HKEY hServiceKey
= NULL
;
5182 DPRINT("RChangeServiceConfig2W() called\n");
5183 DPRINT("dwInfoLevel = %lu\n", Info
.dwInfoLevel
);
5186 return ERROR_SHUTDOWN_IN_PROGRESS
;
5188 hSvc
= ScmGetServiceFromHandle(hService
);
5191 DPRINT1("Invalid service handle!\n");
5192 return ERROR_INVALID_HANDLE
;
5195 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5196 SERVICE_CHANGE_CONFIG
))
5198 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5199 return ERROR_ACCESS_DENIED
;
5202 lpService
= hSvc
->ServiceEntry
;
5203 if (lpService
== NULL
)
5205 DPRINT("lpService == NULL!\n");
5206 return ERROR_INVALID_HANDLE
;
5209 /* Lock the service database exclusively */
5210 ScmLockDatabaseExclusive();
5212 if (lpService
->bDeleted
)
5214 DPRINT("The service has already been marked for delete!\n");
5215 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
5219 /* Open the service key */
5220 dwError
= ScmOpenServiceKey(lpService
->szServiceName
,
5221 KEY_READ
| KEY_SET_VALUE
,
5223 if (dwError
!= ERROR_SUCCESS
)
5226 if (Info
.dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
5228 LPSERVICE_DESCRIPTIONW lpServiceDescription
= (LPSERVICE_DESCRIPTIONW
)Info
.psd
;
5230 /* Modify the service description, if specified */
5231 if (lpServiceDescription
!= NULL
&&
5232 lpServiceDescription
->lpDescription
!= NULL
)
5234 /* If the description is "" then we delete it */
5235 if (*lpServiceDescription
->lpDescription
== 0)
5237 DPRINT("Delete service description\n");
5238 dwError
= RegDeleteValueW(hServiceKey
, L
"Description");
5240 if (dwError
== ERROR_FILE_NOT_FOUND
)
5241 dwError
= ERROR_SUCCESS
;
5245 DPRINT("Setting service description value %S\n", lpServiceDescription
->lpDescription
);
5246 dwError
= RegSetValueExW(hServiceKey
,
5250 (LPBYTE
)lpServiceDescription
->lpDescription
,
5251 (DWORD
)((wcslen(lpServiceDescription
->lpDescription
) + 1) * sizeof(WCHAR
)));
5256 dwError
= ERROR_SUCCESS
;
5259 else if (Info
.dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5261 dwError
= ScmSetFailureActions(hSvc
,
5264 (LPSERVICE_FAILURE_ACTIONSW
)Info
.psfa
);
5268 if (hServiceKey
!= NULL
)
5269 RegCloseKey(hServiceKey
);
5271 /* Unlock the service database */
5272 ScmUnlockDatabase();
5274 DPRINT("RChangeServiceConfig2W() done (Error %lu)\n", dwError
);
5281 DWORD
RQueryServiceConfig2A(
5282 SC_RPC_HANDLE hService
,
5286 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
5288 DWORD dwError
= ERROR_SUCCESS
;
5289 PSERVICE_HANDLE hSvc
;
5290 PSERVICE lpService
= NULL
;
5291 HKEY hServiceKey
= NULL
;
5292 DWORD dwRequiredSize
= 0;
5294 LPWSTR lpDescriptionW
= NULL
;
5295 LPWSTR lpRebootMessageW
= NULL
;
5296 LPWSTR lpFailureCommandW
= NULL
;
5298 DPRINT("RQueryServiceConfig2A() called hService %p dwInfoLevel %u, lpBuffer %p cbBufSize %u pcbBytesNeeded %p\n",
5299 hService
, dwInfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
5302 return ERROR_INVALID_ADDRESS
;
5305 return ERROR_SHUTDOWN_IN_PROGRESS
;
5307 hSvc
= ScmGetServiceFromHandle(hService
);
5310 DPRINT1("Invalid service handle!\n");
5311 return ERROR_INVALID_HANDLE
;
5314 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5315 SERVICE_QUERY_CONFIG
))
5317 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5318 return ERROR_ACCESS_DENIED
;
5321 lpService
= hSvc
->ServiceEntry
;
5322 if (lpService
== NULL
)
5324 DPRINT("lpService == NULL!\n");
5325 return ERROR_INVALID_HANDLE
;
5328 /* Lock the service database shared */
5329 ScmLockDatabaseShared();
5331 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
5334 if (dwError
!= ERROR_SUCCESS
)
5337 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
5339 LPSERVICE_DESCRIPTIONA lpServiceDescription
= (LPSERVICE_DESCRIPTIONA
)lpBuffer
;
5342 dwError
= ScmReadString(hServiceKey
,
5345 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5348 *pcbBytesNeeded
= sizeof(SERVICE_DESCRIPTIONA
);
5349 if (dwError
== ERROR_SUCCESS
)
5350 *pcbBytesNeeded
+= (DWORD
)((wcslen(lpDescriptionW
) + 1) * sizeof(WCHAR
));
5352 if (cbBufSize
< *pcbBytesNeeded
)
5354 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5358 if (dwError
== ERROR_SUCCESS
)
5360 lpStr
= (LPSTR
)(lpServiceDescription
+ 1);
5362 WideCharToMultiByte(CP_ACP
,
5367 (int)wcslen(lpDescriptionW
),
5370 lpServiceDescription
->lpDescription
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceDescription
);
5374 lpServiceDescription
->lpDescription
= NULL
;
5375 dwError
= ERROR_SUCCESS
;
5378 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5380 LPSERVICE_FAILURE_ACTIONSA lpFailureActions
= (LPSERVICE_FAILURE_ACTIONSA
)lpBuffer
;
5383 /* Query value length */
5384 dwError
= RegQueryValueExW(hServiceKey
,
5390 if (dwError
!= ERROR_SUCCESS
&&
5391 dwError
!= ERROR_MORE_DATA
&&
5392 dwError
!= ERROR_FILE_NOT_FOUND
)
5395 dwRequiredSize
= (dwType
== REG_BINARY
) ? max(sizeof(SERVICE_FAILURE_ACTIONSA
), dwRequiredSize
)
5396 : sizeof(SERVICE_FAILURE_ACTIONSA
);
5398 /* Get the strings */
5399 ScmReadString(hServiceKey
,
5401 &lpFailureCommandW
);
5403 ScmReadString(hServiceKey
,
5407 if (lpRebootMessageW
)
5408 dwRequiredSize
+= (DWORD
)((wcslen(lpRebootMessageW
) + 1) * sizeof(WCHAR
));
5410 if (lpFailureCommandW
)
5411 dwRequiredSize
+= (DWORD
)((wcslen(lpFailureCommandW
) + 1) * sizeof(WCHAR
));
5413 if (cbBufSize
< dwRequiredSize
)
5415 *pcbBytesNeeded
= dwRequiredSize
;
5416 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5420 /* Now we can fill the buffer */
5421 if (dwError
!= ERROR_FILE_NOT_FOUND
&& dwType
== REG_BINARY
)
5423 dwError
= RegQueryValueExW(hServiceKey
,
5427 (LPBYTE
)lpFailureActions
,
5429 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5432 if (dwRequiredSize
< sizeof(SERVICE_FAILURE_ACTIONSA
))
5433 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSA
);
5438 * The value of the error doesn't really matter, the only
5439 * important thing is that it must be != ERROR_SUCCESS .
5441 dwError
= ERROR_INVALID_DATA
;
5444 if (dwError
== ERROR_SUCCESS
)
5446 lpFailureActions
->cActions
= min(lpFailureActions
->cActions
, (dwRequiredSize
- sizeof(SERVICE_FAILURE_ACTIONSA
)) / sizeof(SC_ACTION
));
5448 /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */
5449 lpFailureActions
->lpsaActions
= (lpFailureActions
->cActions
> 0 ? (LPSC_ACTION
)(ULONG_PTR
)sizeof(SERVICE_FAILURE_ACTIONSA
) : NULL
);
5451 lpStr
= (LPSTR
)((ULONG_PTR
)(lpFailureActions
+ 1) + lpFailureActions
->cActions
* sizeof(SC_ACTION
));
5455 lpFailureActions
->dwResetPeriod
= 0;
5456 lpFailureActions
->cActions
= 0;
5457 lpFailureActions
->lpsaActions
= NULL
;
5458 lpStr
= (LPSTR
)(lpFailureActions
+ 1);
5461 lpFailureActions
->lpRebootMsg
= NULL
;
5462 lpFailureActions
->lpCommand
= NULL
;
5464 if (lpRebootMessageW
)
5466 WideCharToMultiByte(CP_ACP
,
5471 (int)wcslen(lpRebootMessageW
),
5474 lpFailureActions
->lpRebootMsg
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5475 lpStr
+= strlen(lpStr
) + 1;
5478 if (lpFailureCommandW
)
5480 WideCharToMultiByte(CP_ACP
,
5485 (int)wcslen(lpFailureCommandW
),
5488 lpFailureActions
->lpCommand
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5489 /* lpStr += strlen(lpStr) + 1; */
5492 dwError
= ERROR_SUCCESS
;
5496 /* Unlock the service database */
5497 ScmUnlockDatabase();
5499 if (lpDescriptionW
!= NULL
)
5500 HeapFree(GetProcessHeap(), 0, lpDescriptionW
);
5502 if (lpRebootMessageW
!= NULL
)
5503 HeapFree(GetProcessHeap(), 0, lpRebootMessageW
);
5505 if (lpFailureCommandW
!= NULL
)
5506 HeapFree(GetProcessHeap(), 0, lpFailureCommandW
);
5508 if (hServiceKey
!= NULL
)
5509 RegCloseKey(hServiceKey
);
5511 DPRINT("RQueryServiceConfig2A() done (Error %lu)\n", dwError
);
5518 DWORD
RQueryServiceConfig2W(
5519 SC_RPC_HANDLE hService
,
5523 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
5525 DWORD dwError
= ERROR_SUCCESS
;
5526 PSERVICE_HANDLE hSvc
;
5527 PSERVICE lpService
= NULL
;
5528 HKEY hServiceKey
= NULL
;
5529 DWORD dwRequiredSize
= 0;
5531 LPWSTR lpDescription
= NULL
;
5532 LPWSTR lpRebootMessage
= NULL
;
5533 LPWSTR lpFailureCommand
= NULL
;
5535 DPRINT("RQueryServiceConfig2W() called\n");
5538 return ERROR_INVALID_ADDRESS
;
5541 return ERROR_SHUTDOWN_IN_PROGRESS
;
5543 hSvc
= ScmGetServiceFromHandle(hService
);
5546 DPRINT1("Invalid service handle!\n");
5547 return ERROR_INVALID_HANDLE
;
5550 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5551 SERVICE_QUERY_CONFIG
))
5553 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5554 return ERROR_ACCESS_DENIED
;
5557 lpService
= hSvc
->ServiceEntry
;
5558 if (lpService
== NULL
)
5560 DPRINT("lpService == NULL!\n");
5561 return ERROR_INVALID_HANDLE
;
5564 /* Lock the service database shared */
5565 ScmLockDatabaseShared();
5567 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
5570 if (dwError
!= ERROR_SUCCESS
)
5573 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
5575 LPSERVICE_DESCRIPTIONW lpServiceDescription
= (LPSERVICE_DESCRIPTIONW
)lpBuffer
;
5578 dwError
= ScmReadString(hServiceKey
,
5581 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5584 *pcbBytesNeeded
= sizeof(SERVICE_DESCRIPTIONW
);
5585 if (dwError
== ERROR_SUCCESS
)
5586 *pcbBytesNeeded
+= (DWORD
)((wcslen(lpDescription
) + 1) * sizeof(WCHAR
));
5588 if (cbBufSize
< *pcbBytesNeeded
)
5590 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5594 if (dwError
== ERROR_SUCCESS
)
5596 lpStr
= (LPWSTR
)(lpServiceDescription
+ 1);
5597 wcscpy(lpStr
, lpDescription
);
5598 lpServiceDescription
->lpDescription
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceDescription
);
5602 lpServiceDescription
->lpDescription
= NULL
;
5603 dwError
= ERROR_SUCCESS
;
5606 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5608 LPSERVICE_FAILURE_ACTIONSW lpFailureActions
= (LPSERVICE_FAILURE_ACTIONSW
)lpBuffer
;
5609 LPWSTR lpStr
= NULL
;
5611 /* Query value length */
5612 dwError
= RegQueryValueExW(hServiceKey
,
5618 if (dwError
!= ERROR_SUCCESS
&&
5619 dwError
!= ERROR_MORE_DATA
&&
5620 dwError
!= ERROR_FILE_NOT_FOUND
)
5623 dwRequiredSize
= (dwType
== REG_BINARY
) ? max(sizeof(SERVICE_FAILURE_ACTIONSW
), dwRequiredSize
)
5624 : sizeof(SERVICE_FAILURE_ACTIONSW
);
5626 /* Get the strings */
5627 ScmReadString(hServiceKey
,
5631 ScmReadString(hServiceKey
,
5635 if (lpRebootMessage
)
5636 dwRequiredSize
+= (DWORD
)((wcslen(lpRebootMessage
) + 1) * sizeof(WCHAR
));
5638 if (lpFailureCommand
)
5639 dwRequiredSize
+= (DWORD
)((wcslen(lpFailureCommand
) + 1) * sizeof(WCHAR
));
5641 if (cbBufSize
< dwRequiredSize
)
5643 *pcbBytesNeeded
= dwRequiredSize
;
5644 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5648 /* Now we can fill the buffer */
5649 if (dwError
!= ERROR_FILE_NOT_FOUND
&& dwType
== REG_BINARY
)
5651 dwError
= RegQueryValueExW(hServiceKey
,
5655 (LPBYTE
)lpFailureActions
,
5657 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5660 if (dwRequiredSize
< sizeof(SERVICE_FAILURE_ACTIONSW
))
5661 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSW
);
5666 * The value of the error doesn't really matter, the only
5667 * important thing is that it must be != ERROR_SUCCESS .
5669 dwError
= ERROR_INVALID_DATA
;
5672 if (dwError
== ERROR_SUCCESS
)
5674 lpFailureActions
->cActions
= min(lpFailureActions
->cActions
, (dwRequiredSize
- sizeof(SERVICE_FAILURE_ACTIONSW
)) / sizeof(SC_ACTION
));
5676 /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */
5677 lpFailureActions
->lpsaActions
= (lpFailureActions
->cActions
> 0 ? (LPSC_ACTION
)(ULONG_PTR
)sizeof(SERVICE_FAILURE_ACTIONSW
) : NULL
);
5679 lpStr
= (LPWSTR
)((ULONG_PTR
)(lpFailureActions
+ 1) + lpFailureActions
->cActions
* sizeof(SC_ACTION
));
5683 lpFailureActions
->dwResetPeriod
= 0;
5684 lpFailureActions
->cActions
= 0;
5685 lpFailureActions
->lpsaActions
= NULL
;
5686 lpStr
= (LPWSTR
)(lpFailureActions
+ 1);
5689 lpFailureActions
->lpRebootMsg
= NULL
;
5690 lpFailureActions
->lpCommand
= NULL
;
5692 if (lpRebootMessage
)
5694 wcscpy(lpStr
, lpRebootMessage
);
5695 lpFailureActions
->lpRebootMsg
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5696 lpStr
+= wcslen(lpStr
) + 1;
5699 if (lpFailureCommand
)
5701 wcscpy(lpStr
, lpFailureCommand
);
5702 lpFailureActions
->lpCommand
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5703 /* lpStr += wcslen(lpStr) + 1; */
5706 dwError
= ERROR_SUCCESS
;
5710 /* Unlock the service database */
5711 ScmUnlockDatabase();
5713 if (lpDescription
!= NULL
)
5714 HeapFree(GetProcessHeap(), 0, lpDescription
);
5716 if (lpRebootMessage
!= NULL
)
5717 HeapFree(GetProcessHeap(), 0, lpRebootMessage
);
5719 if (lpFailureCommand
!= NULL
)
5720 HeapFree(GetProcessHeap(), 0, lpFailureCommand
);
5722 if (hServiceKey
!= NULL
)
5723 RegCloseKey(hServiceKey
);
5725 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError
);
5732 DWORD
RQueryServiceStatusEx(
5733 SC_RPC_HANDLE hService
,
5734 SC_STATUS_TYPE InfoLevel
,
5737 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
5739 LPSERVICE_STATUS_PROCESS lpStatus
;
5740 PSERVICE_HANDLE hSvc
;
5743 DPRINT("RQueryServiceStatusEx() called\n");
5746 return ERROR_SHUTDOWN_IN_PROGRESS
;
5748 if (InfoLevel
!= SC_STATUS_PROCESS_INFO
)
5749 return ERROR_INVALID_LEVEL
;
5751 *pcbBytesNeeded
= sizeof(SERVICE_STATUS_PROCESS
);
5753 if (cbBufSize
< sizeof(SERVICE_STATUS_PROCESS
))
5754 return ERROR_INSUFFICIENT_BUFFER
;
5756 hSvc
= ScmGetServiceFromHandle(hService
);
5759 DPRINT1("Invalid service handle!\n");
5760 return ERROR_INVALID_HANDLE
;
5763 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5764 SERVICE_QUERY_STATUS
))
5766 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5767 return ERROR_ACCESS_DENIED
;
5770 lpService
= hSvc
->ServiceEntry
;
5771 if (lpService
== NULL
)
5773 DPRINT("lpService == NULL!\n");
5774 return ERROR_INVALID_HANDLE
;
5777 /* Lock the service database shared */
5778 ScmLockDatabaseShared();
5780 lpStatus
= (LPSERVICE_STATUS_PROCESS
)lpBuffer
;
5782 /* Return service status information */
5783 RtlCopyMemory(lpStatus
,
5785 sizeof(SERVICE_STATUS
));
5787 lpStatus
->dwProcessId
= (lpService
->lpImage
!= NULL
) ? lpService
->lpImage
->dwProcessId
: 0; /* FIXME */
5788 lpStatus
->dwServiceFlags
= 0; /* FIXME */
5790 /* Unlock the service database */
5791 ScmUnlockDatabase();
5793 return ERROR_SUCCESS
;
5798 DWORD
REnumServicesStatusExA(
5799 SC_RPC_HANDLE hSCManager
,
5800 SC_ENUM_TYPE InfoLevel
,
5801 DWORD dwServiceType
,
5802 DWORD dwServiceState
,
5805 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
5806 LPBOUNDED_DWORD_256K lpServicesReturned
,
5807 LPBOUNDED_DWORD_256K lpResumeIndex
,
5808 LPCSTR pszGroupName
)
5810 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrW
= NULL
;
5811 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrIncrW
;
5812 LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtrA
= NULL
;
5813 LPWSTR lpStringPtrW
;
5815 LPWSTR pszGroupNameW
= NULL
;
5817 DWORD dwServiceCount
;
5819 DPRINT("REnumServicesStatusExA() called\n");
5821 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
5823 return ERROR_INVALID_ADDRESS
;
5828 pszGroupNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, (strlen(pszGroupName
) + 1) * sizeof(WCHAR
));
5831 DPRINT("Failed to allocate buffer!\n");
5832 return ERROR_NOT_ENOUGH_MEMORY
;
5835 MultiByteToWideChar(CP_ACP
,
5840 (int)(strlen(pszGroupName
) + 1));
5843 if ((cbBufSize
> 0) && (lpBuffer
))
5845 lpStatusPtrW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, cbBufSize
);
5848 DPRINT("Failed to allocate buffer!\n");
5849 return ERROR_NOT_ENOUGH_MEMORY
;
5853 dwError
= REnumServicesStatusExW(hSCManager
,
5857 (LPBYTE
)lpStatusPtrW
,
5864 /* if no services were returned then we are Done */
5865 if (*lpServicesReturned
== 0)
5868 lpStatusPtrIncrW
= lpStatusPtrW
;
5869 lpStatusPtrA
= (LPENUM_SERVICE_STATUS_PROCESSA
)lpBuffer
;
5870 lpStringPtrA
= (LPSTR
)((ULONG_PTR
)lpBuffer
+
5871 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUS_PROCESSA
));
5872 lpStringPtrW
= (LPWSTR
)((ULONG_PTR
)lpStatusPtrW
+
5873 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUS_PROCESSW
));
5875 for (dwServiceCount
= 0; dwServiceCount
< *lpServicesReturned
; dwServiceCount
++)
5877 /* Copy the service name */
5878 WideCharToMultiByte(CP_ACP
,
5883 (int)wcslen(lpStringPtrW
),
5887 lpStatusPtrA
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
5888 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
5889 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
5891 /* Copy the display name */
5892 WideCharToMultiByte(CP_ACP
,
5897 (int)wcslen(lpStringPtrW
),
5901 lpStatusPtrA
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
5902 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
5903 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
5905 /* Copy the status information */
5906 memcpy(&lpStatusPtrA
->ServiceStatusProcess
,
5907 &lpStatusPtrIncrW
->ServiceStatusProcess
,
5908 sizeof(SERVICE_STATUS
));
5910 lpStatusPtrA
->ServiceStatusProcess
.dwProcessId
= lpStatusPtrIncrW
->ServiceStatusProcess
.dwProcessId
; /* FIXME */
5911 lpStatusPtrA
->ServiceStatusProcess
.dwServiceFlags
= 0; /* FIXME */
5919 HeapFree(GetProcessHeap(), 0, pszGroupNameW
);
5922 HeapFree(GetProcessHeap(), 0, lpStatusPtrW
);
5924 DPRINT("REnumServicesStatusExA() done (Error %lu)\n", dwError
);
5931 DWORD
REnumServicesStatusExW(
5932 SC_RPC_HANDLE hSCManager
,
5933 SC_ENUM_TYPE InfoLevel
,
5934 DWORD dwServiceType
,
5935 DWORD dwServiceState
,
5938 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
5939 LPBOUNDED_DWORD_256K lpServicesReturned
,
5940 LPBOUNDED_DWORD_256K lpResumeIndex
,
5941 LPCWSTR pszGroupName
)
5943 PMANAGER_HANDLE hManager
;
5945 DWORD dwError
= ERROR_SUCCESS
;
5946 PLIST_ENTRY ServiceEntry
;
5947 PSERVICE CurrentService
;
5949 DWORD dwRequiredSize
;
5950 DWORD dwServiceCount
;
5952 DWORD dwLastResumeCount
= 0;
5953 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr
;
5956 DPRINT("REnumServicesStatusExW() called\n");
5959 return ERROR_SHUTDOWN_IN_PROGRESS
;
5961 if (InfoLevel
!= SC_ENUM_PROCESS_INFO
)
5962 return ERROR_INVALID_LEVEL
;
5964 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
5965 if (hManager
== NULL
)
5967 DPRINT1("Invalid service manager handle!\n");
5968 return ERROR_INVALID_HANDLE
;
5971 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
5973 return ERROR_INVALID_ADDRESS
;
5976 *pcbBytesNeeded
= 0;
5977 *lpServicesReturned
= 0;
5979 if ((dwServiceType
== 0) ||
5980 ((dwServiceType
& ~SERVICE_TYPE_ALL
) != 0))
5982 DPRINT("Not a valid Service Type!\n");
5983 return ERROR_INVALID_PARAMETER
;
5986 if ((dwServiceState
== 0) ||
5987 ((dwServiceState
& ~SERVICE_STATE_ALL
) != 0))
5989 DPRINT("Not a valid Service State!\n");
5990 return ERROR_INVALID_PARAMETER
;
5993 /* Check access rights */
5994 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
5995 SC_MANAGER_ENUMERATE_SERVICE
))
5997 DPRINT("Insufficient access rights! 0x%lx\n",
5998 hManager
->Handle
.DesiredAccess
);
5999 return ERROR_ACCESS_DENIED
;
6003 dwLastResumeCount
= *lpResumeIndex
;
6005 /* Lock the service database shared */
6006 ScmLockDatabaseShared();
6008 lpService
= ScmGetServiceEntryByResumeCount(dwLastResumeCount
);
6009 if (lpService
== NULL
)
6011 dwError
= ERROR_SUCCESS
;
6018 for (ServiceEntry
= &lpService
->ServiceListEntry
;
6019 ServiceEntry
!= &ServiceListHead
;
6020 ServiceEntry
= ServiceEntry
->Flink
)
6022 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
6026 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
6029 dwState
= SERVICE_ACTIVE
;
6030 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
6031 dwState
= SERVICE_INACTIVE
;
6033 if ((dwState
& dwServiceState
) == 0)
6038 if (*pszGroupName
== 0)
6040 if (CurrentService
->lpGroup
!= NULL
)
6045 if ((CurrentService
->lpGroup
== NULL
) ||
6046 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
6051 dwSize
= sizeof(ENUM_SERVICE_STATUS_PROCESSW
) +
6052 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
6053 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
6055 if (dwRequiredSize
+ dwSize
<= cbBufSize
)
6057 DPRINT("Service name: %S fit\n", CurrentService
->lpServiceName
);
6058 dwRequiredSize
+= dwSize
;
6060 dwLastResumeCount
= CurrentService
->dwResumeCount
;
6064 DPRINT("Service name: %S no fit\n", CurrentService
->lpServiceName
);
6070 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize
);
6071 DPRINT("dwServiceCount: %lu\n", dwServiceCount
);
6074 ServiceEntry
!= &ServiceListHead
;
6075 ServiceEntry
= ServiceEntry
->Flink
)
6077 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
6081 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
6084 dwState
= SERVICE_ACTIVE
;
6085 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
6086 dwState
= SERVICE_INACTIVE
;
6088 if ((dwState
& dwServiceState
) == 0)
6093 if (*pszGroupName
== 0)
6095 if (CurrentService
->lpGroup
!= NULL
)
6100 if ((CurrentService
->lpGroup
== NULL
) ||
6101 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
6106 dwRequiredSize
+= (sizeof(ENUM_SERVICE_STATUS_PROCESSW
) +
6107 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
6108 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
)));
6110 dwError
= ERROR_MORE_DATA
;
6113 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize
);
6116 *lpResumeIndex
= dwLastResumeCount
;
6118 *lpServicesReturned
= dwServiceCount
;
6119 *pcbBytesNeeded
= dwRequiredSize
;
6121 /* If there was no services that matched */
6122 if ((!dwServiceCount
) && (dwError
!= ERROR_MORE_DATA
))
6124 dwError
= ERROR_SERVICE_DOES_NOT_EXIST
;
6128 lpStatusPtr
= (LPENUM_SERVICE_STATUS_PROCESSW
)lpBuffer
;
6129 lpStringPtr
= (LPWSTR
)((ULONG_PTR
)lpBuffer
+
6130 dwServiceCount
* sizeof(ENUM_SERVICE_STATUS_PROCESSW
));
6133 for (ServiceEntry
= &lpService
->ServiceListEntry
;
6134 ServiceEntry
!= &ServiceListHead
;
6135 ServiceEntry
= ServiceEntry
->Flink
)
6137 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
6141 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
6144 dwState
= SERVICE_ACTIVE
;
6145 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
6146 dwState
= SERVICE_INACTIVE
;
6148 if ((dwState
& dwServiceState
) == 0)
6153 if (*pszGroupName
== 0)
6155 if (CurrentService
->lpGroup
!= NULL
)
6160 if ((CurrentService
->lpGroup
== NULL
) ||
6161 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
6166 dwSize
= sizeof(ENUM_SERVICE_STATUS_PROCESSW
) +
6167 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
6168 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
6170 if (dwRequiredSize
+ dwSize
<= cbBufSize
)
6172 /* Copy the service name */
6174 CurrentService
->lpServiceName
);
6175 lpStatusPtr
->lpServiceName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
6176 lpStringPtr
+= (wcslen(CurrentService
->lpServiceName
) + 1);
6178 /* Copy the display name */
6180 CurrentService
->lpDisplayName
);
6181 lpStatusPtr
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
6182 lpStringPtr
+= (wcslen(CurrentService
->lpDisplayName
) + 1);
6184 /* Copy the status information */
6185 memcpy(&lpStatusPtr
->ServiceStatusProcess
,
6186 &CurrentService
->Status
,
6187 sizeof(SERVICE_STATUS
));
6188 lpStatusPtr
->ServiceStatusProcess
.dwProcessId
=
6189 (CurrentService
->lpImage
!= NULL
) ? CurrentService
->lpImage
->dwProcessId
: 0; /* FIXME */
6190 lpStatusPtr
->ServiceStatusProcess
.dwServiceFlags
= 0; /* FIXME */
6193 dwRequiredSize
+= dwSize
;
6203 *pcbBytesNeeded
= 0;
6209 /* Unlock the service database */
6210 ScmUnlockDatabase();
6212 DPRINT("REnumServicesStatusExW() done (Error %lu)\n", dwError
);
6219 DWORD
RSendTSMessage(
6220 handle_t BindingHandle
) /* FIXME */
6223 return ERROR_CALL_NOT_IMPLEMENTED
;
6228 DWORD
RCreateServiceWOW64A(
6229 handle_t BindingHandle
,
6230 LPSTR lpServiceName
,
6231 LPSTR lpDisplayName
,
6232 DWORD dwDesiredAccess
,
6233 DWORD dwServiceType
,
6235 DWORD dwErrorControl
,
6236 LPSTR lpBinaryPathName
,
6237 LPSTR lpLoadOrderGroup
,
6239 LPBYTE lpDependencies
,
6241 LPSTR lpServiceStartName
,
6244 LPSC_RPC_HANDLE lpServiceHandle
)
6247 return ERROR_CALL_NOT_IMPLEMENTED
;
6252 DWORD
RCreateServiceWOW64W(
6253 handle_t BindingHandle
,
6254 LPWSTR lpServiceName
,
6255 LPWSTR lpDisplayName
,
6256 DWORD dwDesiredAccess
,
6257 DWORD dwServiceType
,
6259 DWORD dwErrorControl
,
6260 LPWSTR lpBinaryPathName
,
6261 LPWSTR lpLoadOrderGroup
,
6263 LPBYTE lpDependencies
,
6265 LPWSTR lpServiceStartName
,
6268 LPSC_RPC_HANDLE lpServiceHandle
)
6271 return ERROR_CALL_NOT_IMPLEMENTED
;
6276 DWORD
RQueryServiceTagInfo(
6277 handle_t BindingHandle
) /* FIXME */
6280 return ERROR_CALL_NOT_IMPLEMENTED
;
6285 DWORD
RNotifyServiceStatusChange(
6286 SC_RPC_HANDLE hService
,
6287 SC_RPC_NOTIFY_PARAMS NotifyParams
,
6288 GUID
*pClientProcessGuid
,
6289 GUID
*pSCMProcessGuid
,
6290 PBOOL pfCreateRemoteQueue
,
6291 LPSC_NOTIFY_RPC_HANDLE phNotify
)
6294 return ERROR_CALL_NOT_IMPLEMENTED
;
6299 DWORD
RGetNotifyResults(
6300 SC_NOTIFY_RPC_HANDLE hNotify
,
6301 PSC_RPC_NOTIFY_PARAMS_LIST
*ppNotifyParams
)
6304 return ERROR_CALL_NOT_IMPLEMENTED
;
6309 DWORD
RCloseNotifyHandle(
6310 LPSC_NOTIFY_RPC_HANDLE phNotify
,
6314 return ERROR_CALL_NOT_IMPLEMENTED
;
6319 DWORD
RControlServiceExA(
6320 SC_RPC_HANDLE hService
,
6325 return ERROR_CALL_NOT_IMPLEMENTED
;
6330 DWORD
RControlServiceExW(
6331 SC_RPC_HANDLE hService
,
6336 return ERROR_CALL_NOT_IMPLEMENTED
;
6341 DWORD
RSendPnPMessage(
6342 handle_t BindingHandle
) /* FIXME */
6345 return ERROR_CALL_NOT_IMPLEMENTED
;
6350 DWORD
RValidatePnPService(
6351 handle_t BindingHandle
) /* FIXME */
6354 return ERROR_CALL_NOT_IMPLEMENTED
;
6359 DWORD
ROpenServiceStatusHandle(
6360 handle_t BindingHandle
) /* FIXME */
6363 return ERROR_CALL_NOT_IMPLEMENTED
;
6369 handle_t BindingHandle
) /* FIXME */
6372 return ERROR_CALL_NOT_IMPLEMENTED
;
6376 void __RPC_FAR
* __RPC_USER
midl_user_allocate(SIZE_T len
)
6378 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
);
6382 void __RPC_USER
midl_user_free(void __RPC_FAR
* ptr
)
6384 HeapFree(GetProcessHeap(), 0, ptr
);
6388 void __RPC_USER
SC_RPC_HANDLE_rundown(SC_RPC_HANDLE hSCObject
)
6390 /* Close the handle */
6391 RCloseServiceHandle(&hSCObject
);
6395 void __RPC_USER
SC_RPC_LOCK_rundown(SC_RPC_LOCK Lock
)
6397 /* Unlock the database */
6398 RUnlockServiceDatabase(&Lock
);
6402 void __RPC_USER
SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE hNotify
)