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 LPCWSTR lpErrorStrings
[2];
1621 WCHAR szErrorBuffer
[32];
1623 DPRINT("RSetServiceStatus() called\n");
1624 DPRINT("hServiceStatus = %lu\n", hServiceStatus
);
1625 DPRINT("dwServiceType = %lu\n", lpServiceStatus
->dwServiceType
);
1626 DPRINT("dwCurrentState = %lu\n", lpServiceStatus
->dwCurrentState
);
1627 DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus
->dwControlsAccepted
);
1628 DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus
->dwWin32ExitCode
);
1629 DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus
->dwServiceSpecificExitCode
);
1630 DPRINT("dwCheckPoint = %lu\n", lpServiceStatus
->dwCheckPoint
);
1631 DPRINT("dwWaitHint = %lu\n", lpServiceStatus
->dwWaitHint
);
1633 if (hServiceStatus
== 0)
1635 DPRINT("hServiceStatus == NULL!\n");
1636 return ERROR_INVALID_HANDLE
;
1639 lpService
= (PSERVICE
)hServiceStatus
;
1641 /* Check current state */
1642 if (!ScmIsValidServiceState(lpServiceStatus
->dwCurrentState
))
1644 DPRINT("Invalid service state!\n");
1645 return ERROR_INVALID_DATA
;
1648 /* Check service type */
1649 if (!(lpServiceStatus
->dwServiceType
& SERVICE_WIN32
) &&
1650 (lpServiceStatus
->dwServiceType
& SERVICE_DRIVER
))
1652 DPRINT("Invalid service type!\n");
1653 return ERROR_INVALID_DATA
;
1656 /* Check accepted controls */
1657 if (lpServiceStatus
->dwControlsAccepted
& ~0xFF)
1659 DPRINT("Invalid controls accepted!\n");
1660 return ERROR_INVALID_DATA
;
1663 /* Lock the service database exclusively */
1664 ScmLockDatabaseExclusive();
1666 /* Save the current service state */
1667 dwPreviousState
= lpService
->Status
.dwCurrentState
;
1669 RtlCopyMemory(&lpService
->Status
,
1671 sizeof(SERVICE_STATUS
));
1673 /* Unlock the service database */
1674 ScmUnlockDatabase();
1676 /* Log a failed service stop */
1677 if ((lpServiceStatus
->dwCurrentState
== SERVICE_STOPPED
) &&
1678 (dwPreviousState
!= SERVICE_STOPPED
))
1680 if (lpServiceStatus
->dwWin32ExitCode
!= ERROR_SUCCESS
)
1682 swprintf(szErrorBuffer
, L
"%lu", lpServiceStatus
->dwWin32ExitCode
);
1683 lpErrorStrings
[0] = lpService
->lpDisplayName
;
1684 lpErrorStrings
[1] = szErrorBuffer
;
1686 ScmLogError(EVENT_SERVICE_EXIT_FAILED
,
1692 DPRINT("Set %S to %lu\n", lpService
->lpDisplayName
, lpService
->Status
.dwCurrentState
);
1693 DPRINT("RSetServiceStatus() done\n");
1695 return ERROR_SUCCESS
;
1700 DWORD
RUnlockServiceDatabase(
1703 DPRINT("RUnlockServiceDatabase(%p)\n", Lock
);
1704 return ScmReleaseServiceStartLock(Lock
);
1709 DWORD
RNotifyBootConfigStatus(
1710 SVCCTL_HANDLEW lpMachineName
,
1711 DWORD BootAcceptable
)
1713 DPRINT1("RNotifyBootConfigStatus(%p %lu) called\n", lpMachineName
, BootAcceptable
);
1714 return ERROR_SUCCESS
;
1717 // return ERROR_CALL_NOT_IMPLEMENTED;
1722 DWORD
RI_ScSetServiceBitsW(
1723 RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
1724 DWORD dwServiceBits
,
1726 int bUpdateImmediately
,
1730 return ERROR_CALL_NOT_IMPLEMENTED
;
1735 DWORD
RChangeServiceConfigW(
1736 SC_RPC_HANDLE hService
,
1737 DWORD dwServiceType
,
1739 DWORD dwErrorControl
,
1740 LPWSTR lpBinaryPathName
,
1741 LPWSTR lpLoadOrderGroup
,
1743 LPBYTE lpDependencies
,
1745 LPWSTR lpServiceStartName
,
1748 LPWSTR lpDisplayName
)
1750 DWORD dwError
= ERROR_SUCCESS
;
1751 PSERVICE_HANDLE hSvc
;
1752 PSERVICE lpService
= NULL
;
1753 HKEY hServiceKey
= NULL
;
1754 LPWSTR lpDisplayNameW
= NULL
;
1755 LPWSTR lpImagePathW
= NULL
;
1757 DPRINT("RChangeServiceConfigW() called\n");
1758 DPRINT("dwServiceType = %lu\n", dwServiceType
);
1759 DPRINT("dwStartType = %lu\n", dwStartType
);
1760 DPRINT("dwErrorControl = %lu\n", dwErrorControl
);
1761 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName
);
1762 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup
);
1763 DPRINT("lpDisplayName = %S\n", lpDisplayName
);
1766 return ERROR_SHUTDOWN_IN_PROGRESS
;
1768 hSvc
= ScmGetServiceFromHandle(hService
);
1771 DPRINT1("Invalid service handle!\n");
1772 return ERROR_INVALID_HANDLE
;
1775 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1776 SERVICE_CHANGE_CONFIG
))
1778 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1779 return ERROR_ACCESS_DENIED
;
1782 lpService
= hSvc
->ServiceEntry
;
1783 if (lpService
== NULL
)
1785 DPRINT("lpService == NULL!\n");
1786 return ERROR_INVALID_HANDLE
;
1789 /* Lock the service database exclusively */
1790 ScmLockDatabaseExclusive();
1792 if (lpService
->bDeleted
)
1794 DPRINT("The service has already been marked for delete!\n");
1795 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
1799 /* Open the service key */
1800 dwError
= ScmOpenServiceKey(lpService
->szServiceName
,
1803 if (dwError
!= ERROR_SUCCESS
)
1806 /* Write service data to the registry */
1807 /* Set the display name */
1808 if (lpDisplayName
!= NULL
&& *lpDisplayName
!= 0)
1810 RegSetValueExW(hServiceKey
,
1814 (LPBYTE
)lpDisplayName
,
1815 (DWORD
)((wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
)));
1817 /* Update the display name */
1818 lpDisplayNameW
= HeapAlloc(GetProcessHeap(),
1820 (wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
));
1821 if (lpDisplayNameW
== NULL
)
1823 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
1827 if (lpService
->lpDisplayName
!= lpService
->lpServiceName
)
1828 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
1830 lpService
->lpDisplayName
= lpDisplayNameW
;
1833 if (dwServiceType
!= SERVICE_NO_CHANGE
)
1835 /* Set the service type */
1836 dwError
= RegSetValueExW(hServiceKey
,
1840 (LPBYTE
)&dwServiceType
,
1842 if (dwError
!= ERROR_SUCCESS
)
1845 lpService
->Status
.dwServiceType
= dwServiceType
;
1848 if (dwStartType
!= SERVICE_NO_CHANGE
)
1850 /* Set the start value */
1851 dwError
= RegSetValueExW(hServiceKey
,
1855 (LPBYTE
)&dwStartType
,
1857 if (dwError
!= ERROR_SUCCESS
)
1860 lpService
->dwStartType
= dwStartType
;
1863 if (dwErrorControl
!= SERVICE_NO_CHANGE
)
1865 /* Set the error control value */
1866 dwError
= RegSetValueExW(hServiceKey
,
1870 (LPBYTE
)&dwErrorControl
,
1872 if (dwError
!= ERROR_SUCCESS
)
1875 lpService
->dwErrorControl
= dwErrorControl
;
1878 if (lpBinaryPathName
!= NULL
&& *lpBinaryPathName
!= 0)
1880 /* Set the image path */
1881 lpImagePathW
= lpBinaryPathName
;
1883 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
1885 dwError
= ScmCanonDriverImagePath(lpService
->dwStartType
,
1889 if (dwError
!= ERROR_SUCCESS
)
1893 dwError
= RegSetValueExW(hServiceKey
,
1897 (LPBYTE
)lpImagePathW
,
1898 (DWORD
)((wcslen(lpImagePathW
) + 1) * sizeof(WCHAR
)));
1900 if (lpImagePathW
!= lpBinaryPathName
)
1901 HeapFree(GetProcessHeap(), 0, lpImagePathW
);
1903 if (dwError
!= ERROR_SUCCESS
)
1907 /* Set the group name */
1908 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
1910 dwError
= RegSetValueExW(hServiceKey
,
1914 (LPBYTE
)lpLoadOrderGroup
,
1915 (DWORD
)((wcslen(lpLoadOrderGroup
) + 1) * sizeof(WCHAR
)));
1916 if (dwError
!= ERROR_SUCCESS
)
1919 dwError
= ScmSetServiceGroup(lpService
,
1921 if (dwError
!= ERROR_SUCCESS
)
1925 if (lpdwTagId
!= NULL
)
1927 dwError
= ScmAssignNewTag(lpService
);
1928 if (dwError
!= ERROR_SUCCESS
)
1931 dwError
= RegSetValueExW(hServiceKey
,
1935 (LPBYTE
)&lpService
->dwTag
,
1937 if (dwError
!= ERROR_SUCCESS
)
1940 *lpdwTagId
= lpService
->dwTag
;
1943 /* Write dependencies */
1944 if (lpDependencies
!= NULL
&& *lpDependencies
!= 0)
1946 dwError
= ScmWriteDependencies(hServiceKey
,
1947 (LPWSTR
)lpDependencies
,
1949 if (dwError
!= ERROR_SUCCESS
)
1953 if (lpPassword
!= NULL
)
1955 /* FIXME: Decrypt and write password */
1959 if (hServiceKey
!= NULL
)
1960 RegCloseKey(hServiceKey
);
1962 /* Unlock the service database */
1963 ScmUnlockDatabase();
1965 DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError
);
1972 DWORD
RCreateServiceW(
1973 SC_RPC_HANDLE hSCManager
,
1974 LPCWSTR lpServiceName
,
1975 LPCWSTR lpDisplayName
,
1976 DWORD dwDesiredAccess
,
1977 DWORD dwServiceType
,
1979 DWORD dwErrorControl
,
1980 LPCWSTR lpBinaryPathName
,
1981 LPCWSTR lpLoadOrderGroup
,
1983 LPBYTE lpDependencies
,
1985 LPCWSTR lpServiceStartName
,
1988 LPSC_RPC_HANDLE lpServiceHandle
)
1990 PMANAGER_HANDLE hManager
;
1991 DWORD dwError
= ERROR_SUCCESS
;
1992 PSERVICE lpService
= NULL
;
1993 SC_HANDLE hServiceHandle
= NULL
;
1994 LPWSTR lpImagePath
= NULL
;
1995 HKEY hServiceKey
= NULL
;
1996 LPWSTR lpObjectName
;
1998 DPRINT("RCreateServiceW() called\n");
1999 DPRINT("lpServiceName = %S\n", lpServiceName
);
2000 DPRINT("lpDisplayName = %S\n", lpDisplayName
);
2001 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess
);
2002 DPRINT("dwServiceType = %lu\n", dwServiceType
);
2003 DPRINT("dwStartType = %lu\n", dwStartType
);
2004 DPRINT("dwErrorControl = %lu\n", dwErrorControl
);
2005 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName
);
2006 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup
);
2007 DPRINT("lpdwTagId = %p\n", lpdwTagId
);
2010 return ERROR_SHUTDOWN_IN_PROGRESS
;
2012 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
2013 if (hManager
== NULL
)
2015 DPRINT1("Invalid service manager handle!\n");
2016 return ERROR_INVALID_HANDLE
;
2019 /* Check access rights */
2020 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
2021 SC_MANAGER_CREATE_SERVICE
))
2023 DPRINT("Insufficient access rights! 0x%lx\n",
2024 hManager
->Handle
.DesiredAccess
);
2025 return ERROR_ACCESS_DENIED
;
2028 if (wcslen(lpServiceName
) == 0)
2030 return ERROR_INVALID_NAME
;
2033 if (wcslen(lpBinaryPathName
) == 0)
2035 return ERROR_INVALID_PARAMETER
;
2038 /* Check for invalid service type value */
2039 if ((dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
2040 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
) &&
2041 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
2042 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
))
2043 return ERROR_INVALID_PARAMETER
;
2045 /* Check for invalid start type value */
2046 if ((dwStartType
!= SERVICE_BOOT_START
) &&
2047 (dwStartType
!= SERVICE_SYSTEM_START
) &&
2048 (dwStartType
!= SERVICE_AUTO_START
) &&
2049 (dwStartType
!= SERVICE_DEMAND_START
) &&
2050 (dwStartType
!= SERVICE_DISABLED
))
2051 return ERROR_INVALID_PARAMETER
;
2053 /* Only drivers can be boot start or system start services */
2054 if ((dwStartType
== SERVICE_BOOT_START
) ||
2055 (dwStartType
== SERVICE_SYSTEM_START
))
2057 if ((dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
2058 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
2059 return ERROR_INVALID_PARAMETER
;
2062 /* Check for invalid error control value */
2063 if ((dwErrorControl
!= SERVICE_ERROR_IGNORE
) &&
2064 (dwErrorControl
!= SERVICE_ERROR_NORMAL
) &&
2065 (dwErrorControl
!= SERVICE_ERROR_SEVERE
) &&
2066 (dwErrorControl
!= SERVICE_ERROR_CRITICAL
))
2067 return ERROR_INVALID_PARAMETER
;
2069 if ((dwServiceType
== (SERVICE_WIN32_OWN_PROCESS
| SERVICE_INTERACTIVE_PROCESS
)) &&
2070 (lpServiceStartName
))
2072 return ERROR_INVALID_PARAMETER
;
2075 if (lpdwTagId
&& (!lpLoadOrderGroup
|| !*lpLoadOrderGroup
))
2077 return ERROR_INVALID_PARAMETER
;
2080 /* Lock the service database exclusively */
2081 ScmLockDatabaseExclusive();
2083 lpService
= ScmGetServiceEntryByName(lpServiceName
);
2086 /* Unlock the service database */
2087 ScmUnlockDatabase();
2089 /* Check if it is marked for deletion */
2090 if (lpService
->bDeleted
)
2091 return ERROR_SERVICE_MARKED_FOR_DELETE
;
2093 /* Return Error exist */
2094 return ERROR_SERVICE_EXISTS
;
2097 if (lpDisplayName
!= NULL
&&
2098 ScmGetServiceEntryByDisplayName(lpDisplayName
) != NULL
)
2100 /* Unlock the service database */
2101 ScmUnlockDatabase();
2103 return ERROR_DUPLICATE_SERVICE_NAME
;
2106 if (dwServiceType
& SERVICE_DRIVER
)
2108 dwError
= ScmCanonDriverImagePath(dwStartType
,
2111 if (dwError
!= ERROR_SUCCESS
)
2116 if (dwStartType
== SERVICE_BOOT_START
||
2117 dwStartType
== SERVICE_SYSTEM_START
)
2119 /* Unlock the service database */
2120 ScmUnlockDatabase();
2122 return ERROR_INVALID_PARAMETER
;
2126 /* Allocate a new service entry */
2127 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
2129 if (dwError
!= ERROR_SUCCESS
)
2132 /* Fill the new service entry */
2133 lpService
->Status
.dwServiceType
= dwServiceType
;
2134 lpService
->dwStartType
= dwStartType
;
2135 lpService
->dwErrorControl
= dwErrorControl
;
2137 /* Fill the display name */
2138 if (lpDisplayName
!= NULL
&&
2139 *lpDisplayName
!= 0 &&
2140 _wcsicmp(lpService
->lpDisplayName
, lpDisplayName
) != 0)
2142 lpService
->lpDisplayName
= HeapAlloc(GetProcessHeap(),
2144 (wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
));
2145 if (lpService
->lpDisplayName
== NULL
)
2147 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
2150 wcscpy(lpService
->lpDisplayName
, lpDisplayName
);
2153 /* Assign the service to a group */
2154 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
2156 dwError
= ScmSetServiceGroup(lpService
,
2158 if (dwError
!= ERROR_SUCCESS
)
2162 /* Assign a new tag */
2163 if (lpdwTagId
!= NULL
)
2165 dwError
= ScmAssignNewTag(lpService
);
2166 if (dwError
!= ERROR_SUCCESS
)
2170 /* Write service data to the registry */
2171 /* Create the service key */
2172 dwError
= ScmCreateServiceKey(lpServiceName
,
2175 if (dwError
!= ERROR_SUCCESS
)
2178 /* Set the display name */
2179 if (lpDisplayName
!= NULL
&& *lpDisplayName
!= 0)
2181 RegSetValueExW(hServiceKey
,
2185 (LPBYTE
)lpDisplayName
,
2186 (DWORD
)((wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
)));
2189 /* Set the service type */
2190 dwError
= RegSetValueExW(hServiceKey
,
2194 (LPBYTE
)&dwServiceType
,
2196 if (dwError
!= ERROR_SUCCESS
)
2199 /* Set the start value */
2200 dwError
= RegSetValueExW(hServiceKey
,
2204 (LPBYTE
)&dwStartType
,
2206 if (dwError
!= ERROR_SUCCESS
)
2209 /* Set the error control value */
2210 dwError
= RegSetValueExW(hServiceKey
,
2214 (LPBYTE
)&dwErrorControl
,
2216 if (dwError
!= ERROR_SUCCESS
)
2219 /* Set the image path */
2220 if (dwServiceType
& SERVICE_WIN32
)
2222 dwError
= RegSetValueExW(hServiceKey
,
2226 (LPBYTE
)lpBinaryPathName
,
2227 (DWORD
)((wcslen(lpBinaryPathName
) + 1) * sizeof(WCHAR
)));
2228 if (dwError
!= ERROR_SUCCESS
)
2231 else if (dwServiceType
& SERVICE_DRIVER
)
2233 dwError
= RegSetValueExW(hServiceKey
,
2237 (LPBYTE
)lpImagePath
,
2238 (DWORD
)((wcslen(lpImagePath
) + 1) * sizeof(WCHAR
)));
2239 if (dwError
!= ERROR_SUCCESS
)
2243 /* Set the group name */
2244 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
2246 dwError
= RegSetValueExW(hServiceKey
,
2250 (LPBYTE
)lpLoadOrderGroup
,
2251 (DWORD
)((wcslen(lpLoadOrderGroup
) + 1) * sizeof(WCHAR
)));
2252 if (dwError
!= ERROR_SUCCESS
)
2256 if (lpdwTagId
!= NULL
)
2258 dwError
= RegSetValueExW(hServiceKey
,
2262 (LPBYTE
)&lpService
->dwTag
,
2264 if (dwError
!= ERROR_SUCCESS
)
2268 /* Write dependencies */
2269 if (lpDependencies
!= NULL
&& *lpDependencies
!= 0)
2271 dwError
= ScmWriteDependencies(hServiceKey
,
2272 (LPCWSTR
)lpDependencies
,
2274 if (dwError
!= ERROR_SUCCESS
)
2278 /* Write service start name */
2279 if (dwServiceType
& SERVICE_WIN32
)
2281 lpObjectName
= (lpServiceStartName
!= NULL
) ? (LPWSTR
)lpServiceStartName
: L
"LocalSystem";
2282 dwError
= RegSetValueExW(hServiceKey
,
2286 (LPBYTE
)lpObjectName
,
2287 (DWORD
)((wcslen(lpObjectName
) + 1) * sizeof(WCHAR
)));
2288 if (dwError
!= ERROR_SUCCESS
)
2292 if (lpPassword
!= NULL
)
2294 /* FIXME: Decrypt and write password */
2297 dwError
= ScmCreateServiceHandle(lpService
,
2299 if (dwError
!= ERROR_SUCCESS
)
2302 dwError
= ScmCheckAccess(hServiceHandle
,
2304 if (dwError
!= ERROR_SUCCESS
)
2307 lpService
->dwRefCount
= 1;
2308 DPRINT("CreateService - lpService->dwRefCount %u\n", lpService
->dwRefCount
);
2311 /* Unlock the service database */
2312 ScmUnlockDatabase();
2314 if (hServiceKey
!= NULL
)
2315 RegCloseKey(hServiceKey
);
2317 if (dwError
== ERROR_SUCCESS
)
2319 DPRINT("hService %p\n", hServiceHandle
);
2320 *lpServiceHandle
= (SC_RPC_HANDLE
)hServiceHandle
;
2322 if (lpdwTagId
!= NULL
)
2323 *lpdwTagId
= lpService
->dwTag
;
2327 if (lpService
!= NULL
&&
2328 lpService
->lpServiceName
!= NULL
)
2330 /* Release the display name buffer */
2331 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
2336 /* Remove the service handle */
2337 HeapFree(GetProcessHeap(), 0, hServiceHandle
);
2340 if (lpService
!= NULL
)
2342 /* FIXME: remove the service entry */
2346 if (lpImagePath
!= NULL
)
2347 HeapFree(GetProcessHeap(), 0, lpImagePath
);
2349 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError
);
2356 DWORD
REnumDependentServicesW(
2357 SC_RPC_HANDLE hService
,
2358 DWORD dwServiceState
,
2361 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
2362 LPBOUNDED_DWORD_256K lpServicesReturned
)
2364 DWORD dwError
= ERROR_SUCCESS
;
2365 DWORD dwServicesReturned
= 0;
2366 DWORD dwServiceCount
;
2367 HKEY hServicesKey
= NULL
;
2368 PSERVICE_HANDLE hSvc
;
2369 PSERVICE lpService
= NULL
;
2370 PSERVICE
*lpServicesArray
= NULL
;
2371 LPENUM_SERVICE_STATUSW lpServicesPtr
= NULL
;
2374 *pcbBytesNeeded
= 0;
2375 *lpServicesReturned
= 0;
2377 DPRINT("REnumDependentServicesW() called\n");
2379 hSvc
= ScmGetServiceFromHandle(hService
);
2382 DPRINT1("Invalid service handle!\n");
2383 return ERROR_INVALID_HANDLE
;
2386 lpService
= hSvc
->ServiceEntry
;
2388 /* Check access rights */
2389 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
2390 SC_MANAGER_ENUMERATE_SERVICE
))
2392 DPRINT("Insufficient access rights! 0x%lx\n",
2393 hSvc
->Handle
.DesiredAccess
);
2394 return ERROR_ACCESS_DENIED
;
2397 /* Open the Services Reg key */
2398 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2399 L
"System\\CurrentControlSet\\Services",
2403 if (dwError
!= ERROR_SUCCESS
)
2406 /* First determine the bytes needed and get the number of dependent services */
2407 dwError
= Int_EnumDependentServicesW(hServicesKey
,
2412 &dwServicesReturned
);
2413 if (dwError
!= ERROR_SUCCESS
)
2416 /* If buffer size is less than the bytes needed or pointer is null */
2417 if ((!lpServices
) || (cbBufSize
< *pcbBytesNeeded
))
2419 dwError
= ERROR_MORE_DATA
;
2423 /* Allocate memory for array of service pointers */
2424 lpServicesArray
= HeapAlloc(GetProcessHeap(),
2426 (dwServicesReturned
+ 1) * sizeof(PSERVICE
));
2427 if (!lpServicesArray
)
2429 DPRINT1("Could not allocate a buffer!!\n");
2430 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
2434 dwServicesReturned
= 0;
2435 *pcbBytesNeeded
= 0;
2437 dwError
= Int_EnumDependentServicesW(hServicesKey
,
2442 &dwServicesReturned
);
2443 if (dwError
!= ERROR_SUCCESS
)
2448 lpServicesPtr
= (LPENUM_SERVICE_STATUSW
)lpServices
;
2449 lpStr
= (LPWSTR
)(lpServices
+ (dwServicesReturned
* sizeof(ENUM_SERVICE_STATUSW
)));
2451 /* Copy EnumDepenedentService to Buffer */
2452 for (dwServiceCount
= 0; dwServiceCount
< dwServicesReturned
; dwServiceCount
++)
2454 lpService
= lpServicesArray
[dwServiceCount
];
2456 /* Copy status info */
2457 memcpy(&lpServicesPtr
->ServiceStatus
,
2459 sizeof(SERVICE_STATUS
));
2461 /* Copy display name */
2462 wcscpy(lpStr
, lpService
->lpDisplayName
);
2463 lpServicesPtr
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
2464 lpStr
+= (wcslen(lpService
->lpDisplayName
) + 1);
2466 /* Copy service name */
2467 wcscpy(lpStr
, lpService
->lpServiceName
);
2468 lpServicesPtr
->lpServiceName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
2469 lpStr
+= (wcslen(lpService
->lpServiceName
) + 1);
2474 *lpServicesReturned
= dwServicesReturned
;
2477 if (lpServicesArray
!= NULL
)
2478 HeapFree(GetProcessHeap(), 0, lpServicesArray
);
2480 RegCloseKey(hServicesKey
);
2482 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError
);
2489 DWORD
REnumServicesStatusW(
2490 SC_RPC_HANDLE hSCManager
,
2491 DWORD dwServiceType
,
2492 DWORD dwServiceState
,
2495 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
2496 LPBOUNDED_DWORD_256K lpServicesReturned
,
2497 LPBOUNDED_DWORD_256K lpResumeHandle
)
2499 /* Enumerate all the services, not regarding of their group */
2500 return REnumServiceGroupW(hSCManager
,
2513 DWORD
ROpenSCManagerW(
2514 LPWSTR lpMachineName
,
2515 LPWSTR lpDatabaseName
,
2516 DWORD dwDesiredAccess
,
2517 LPSC_RPC_HANDLE lpScHandle
)
2522 DPRINT("ROpenSCManagerW() called\n");
2523 DPRINT("lpMachineName = %p\n", lpMachineName
);
2524 DPRINT("lpMachineName: %S\n", lpMachineName
);
2525 DPRINT("lpDataBaseName = %p\n", lpDatabaseName
);
2526 DPRINT("lpDataBaseName: %S\n", lpDatabaseName
);
2527 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess
);
2530 return ERROR_SHUTDOWN_IN_PROGRESS
;
2533 return ERROR_INVALID_PARAMETER
;
2535 dwError
= ScmCreateManagerHandle(lpDatabaseName
,
2537 if (dwError
!= ERROR_SUCCESS
)
2539 DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError
);
2543 /* Check the desired access */
2544 dwError
= ScmCheckAccess(hHandle
,
2545 dwDesiredAccess
| SC_MANAGER_CONNECT
);
2546 if (dwError
!= ERROR_SUCCESS
)
2548 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError
);
2549 HeapFree(GetProcessHeap(), 0, hHandle
);
2553 *lpScHandle
= (SC_RPC_HANDLE
)hHandle
;
2554 DPRINT("*hScm = %p\n", *lpScHandle
);
2556 DPRINT("ROpenSCManagerW() done\n");
2558 return ERROR_SUCCESS
;
2563 DWORD
ROpenServiceW(
2564 SC_RPC_HANDLE hSCManager
,
2565 LPWSTR lpServiceName
,
2566 DWORD dwDesiredAccess
,
2567 LPSC_RPC_HANDLE lpServiceHandle
)
2570 PMANAGER_HANDLE hManager
;
2572 DWORD dwError
= ERROR_SUCCESS
;
2574 DPRINT("ROpenServiceW() called\n");
2575 DPRINT("hSCManager = %p\n", hSCManager
);
2576 DPRINT("lpServiceName = %p\n", lpServiceName
);
2577 DPRINT("lpServiceName: %S\n", lpServiceName
);
2578 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess
);
2581 return ERROR_SHUTDOWN_IN_PROGRESS
;
2583 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
2584 if (hManager
== NULL
)
2586 DPRINT1("Invalid service manager handle!\n");
2587 return ERROR_INVALID_HANDLE
;
2590 if (!lpServiceHandle
)
2591 return ERROR_INVALID_PARAMETER
;
2594 return ERROR_INVALID_ADDRESS
;
2596 /* Lock the service database exclusive */
2597 ScmLockDatabaseExclusive();
2599 /* Get service database entry */
2600 lpService
= ScmGetServiceEntryByName(lpServiceName
);
2601 if (lpService
== NULL
)
2603 DPRINT("Could not find a service!\n");
2604 dwError
= ERROR_SERVICE_DOES_NOT_EXIST
;
2608 /* Create a service handle */
2609 dwError
= ScmCreateServiceHandle(lpService
,
2611 if (dwError
!= ERROR_SUCCESS
)
2613 DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError
);
2617 /* Check the desired access */
2618 dwError
= ScmCheckAccess(hHandle
,
2620 if (dwError
!= ERROR_SUCCESS
)
2622 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError
);
2623 HeapFree(GetProcessHeap(), 0, hHandle
);
2627 lpService
->dwRefCount
++;
2628 DPRINT("OpenService - lpService->dwRefCount %u\n",lpService
->dwRefCount
);
2630 *lpServiceHandle
= (SC_RPC_HANDLE
)hHandle
;
2631 DPRINT("*hService = %p\n", *lpServiceHandle
);
2634 /* Unlock the service database */
2635 ScmUnlockDatabase();
2637 DPRINT("ROpenServiceW() done\n");
2644 DWORD
RQueryServiceConfigW(
2645 SC_RPC_HANDLE hService
,
2646 LPBYTE lpBuf
, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2648 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
2650 LPQUERY_SERVICE_CONFIGW lpServiceConfig
= (LPQUERY_SERVICE_CONFIGW
)lpBuf
;
2651 DWORD dwError
= ERROR_SUCCESS
;
2652 PSERVICE_HANDLE hSvc
;
2653 PSERVICE lpService
= NULL
;
2654 HKEY hServiceKey
= NULL
;
2655 LPWSTR lpImagePath
= NULL
;
2656 LPWSTR lpServiceStartName
= NULL
;
2657 LPWSTR lpDependencies
= NULL
;
2658 DWORD dwDependenciesLength
= 0;
2659 DWORD dwRequiredSize
;
2660 WCHAR lpEmptyString
[] = {0,0};
2663 DPRINT("RQueryServiceConfigW() called\n");
2666 return ERROR_SHUTDOWN_IN_PROGRESS
;
2668 hSvc
= ScmGetServiceFromHandle(hService
);
2671 DPRINT1("Invalid service handle!\n");
2672 return ERROR_INVALID_HANDLE
;
2675 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
2676 SERVICE_QUERY_CONFIG
))
2678 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
2679 return ERROR_ACCESS_DENIED
;
2682 lpService
= hSvc
->ServiceEntry
;
2683 if (lpService
== NULL
)
2685 DPRINT("lpService == NULL!\n");
2686 return ERROR_INVALID_HANDLE
;
2689 /* Lock the service database shared */
2690 ScmLockDatabaseShared();
2692 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
2695 if (dwError
!= ERROR_SUCCESS
)
2698 /* Read the image path */
2699 dwError
= ScmReadString(hServiceKey
,
2702 if (dwError
!= ERROR_SUCCESS
)
2705 /* Read the service start name */
2706 ScmReadString(hServiceKey
,
2708 &lpServiceStartName
);
2710 /* Read the dependencies */
2711 ScmReadDependencies(hServiceKey
,
2713 &dwDependenciesLength
);
2715 dwRequiredSize
= sizeof(QUERY_SERVICE_CONFIGW
);
2717 if (lpImagePath
!= NULL
)
2718 dwRequiredSize
+= (DWORD
)((wcslen(lpImagePath
) + 1) * sizeof(WCHAR
));
2720 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2722 if ((lpService
->lpGroup
!= NULL
) && (lpService
->lpGroup
->lpGroupName
!= NULL
))
2723 dwRequiredSize
+= (DWORD
)((wcslen(lpService
->lpGroup
->lpGroupName
) + 1) * sizeof(WCHAR
));
2725 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2727 if (lpDependencies
!= NULL
)
2728 dwRequiredSize
+= dwDependenciesLength
* sizeof(WCHAR
);
2730 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2732 if (lpServiceStartName
!= NULL
)
2733 dwRequiredSize
+= (DWORD
)((wcslen(lpServiceStartName
) + 1) * sizeof(WCHAR
));
2735 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2737 if (lpService
->lpDisplayName
!= NULL
)
2738 dwRequiredSize
+= (DWORD
)((wcslen(lpService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
2740 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2742 if (lpServiceConfig
== NULL
|| cbBufSize
< dwRequiredSize
)
2744 dwError
= ERROR_INSUFFICIENT_BUFFER
;
2748 lpServiceConfig
->dwServiceType
= lpService
->Status
.dwServiceType
;
2749 lpServiceConfig
->dwStartType
= lpService
->dwStartType
;
2750 lpServiceConfig
->dwErrorControl
= lpService
->dwErrorControl
;
2751 lpServiceConfig
->dwTagId
= lpService
->dwTag
;
2753 lpStr
= (LPWSTR
)(lpServiceConfig
+ 1);
2755 /* Append the image path */
2756 if (lpImagePath
!= NULL
)
2758 wcscpy(lpStr
, lpImagePath
);
2762 wcscpy(lpStr
, lpEmptyString
);
2765 lpServiceConfig
->lpBinaryPathName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2766 lpStr
+= (wcslen(lpStr
) + 1);
2768 /* Append the group name */
2769 if ((lpService
->lpGroup
!= NULL
) && (lpService
->lpGroup
->lpGroupName
!= NULL
))
2771 wcscpy(lpStr
, lpService
->lpGroup
->lpGroupName
);
2775 wcscpy(lpStr
, lpEmptyString
);
2778 lpServiceConfig
->lpLoadOrderGroup
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2779 lpStr
+= (wcslen(lpStr
) + 1);
2781 /* Append Dependencies */
2782 if (lpDependencies
!= NULL
)
2786 dwDependenciesLength
* sizeof(WCHAR
));
2790 wcscpy(lpStr
, lpEmptyString
);
2793 lpServiceConfig
->lpDependencies
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2794 if (lpDependencies
!= NULL
)
2795 lpStr
+= dwDependenciesLength
;
2797 lpStr
+= (wcslen(lpStr
) + 1);
2799 /* Append the service start name */
2800 if (lpServiceStartName
!= NULL
)
2802 wcscpy(lpStr
, lpServiceStartName
);
2806 wcscpy(lpStr
, lpEmptyString
);
2809 lpServiceConfig
->lpServiceStartName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2810 lpStr
+= (wcslen(lpStr
) + 1);
2812 /* Append the display name */
2813 if (lpService
->lpDisplayName
!= NULL
)
2815 wcscpy(lpStr
, lpService
->lpDisplayName
);
2819 wcscpy(lpStr
, lpEmptyString
);
2822 lpServiceConfig
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2825 if (pcbBytesNeeded
!= NULL
)
2826 *pcbBytesNeeded
= dwRequiredSize
;
2829 /* Unlock the service database */
2830 ScmUnlockDatabase();
2832 if (lpImagePath
!= NULL
)
2833 HeapFree(GetProcessHeap(), 0, lpImagePath
);
2835 if (lpServiceStartName
!= NULL
)
2836 HeapFree(GetProcessHeap(), 0, lpServiceStartName
);
2838 if (lpDependencies
!= NULL
)
2839 HeapFree(GetProcessHeap(), 0, lpDependencies
);
2841 if (hServiceKey
!= NULL
)
2842 RegCloseKey(hServiceKey
);
2844 DPRINT("RQueryServiceConfigW() done\n");
2851 DWORD
RQueryServiceLockStatusW(
2852 SC_RPC_HANDLE hSCManager
,
2853 LPBYTE lpBuf
, // LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2855 LPBOUNDED_DWORD_4K pcbBytesNeeded
)
2857 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
= (LPQUERY_SERVICE_LOCK_STATUSW
)lpBuf
;
2858 PMANAGER_HANDLE hMgr
;
2859 DWORD dwRequiredSize
;
2861 if (!lpLockStatus
|| !pcbBytesNeeded
)
2862 return ERROR_INVALID_PARAMETER
;
2864 hMgr
= ScmGetServiceManagerFromHandle(hSCManager
);
2867 DPRINT1("Invalid service manager handle!\n");
2868 return ERROR_INVALID_HANDLE
;
2871 if (!RtlAreAllAccessesGranted(hMgr
->Handle
.DesiredAccess
,
2872 SC_MANAGER_QUERY_LOCK_STATUS
))
2874 DPRINT("Insufficient access rights! 0x%lx\n", hMgr
->Handle
.DesiredAccess
);
2875 return ERROR_ACCESS_DENIED
;
2878 /* FIXME: we need to compute instead the real length of the owner name */
2879 dwRequiredSize
= sizeof(QUERY_SERVICE_LOCK_STATUSW
) + sizeof(WCHAR
);
2880 *pcbBytesNeeded
= dwRequiredSize
;
2882 if (cbBufSize
< dwRequiredSize
)
2883 return ERROR_INSUFFICIENT_BUFFER
;
2885 ScmQueryServiceLockStatusW(lpLockStatus
);
2887 return ERROR_SUCCESS
;
2892 DWORD
RStartServiceW(
2893 SC_RPC_HANDLE hService
,
2895 LPSTRING_PTRSW argv
)
2897 DWORD dwError
= ERROR_SUCCESS
;
2898 PSERVICE_HANDLE hSvc
;
2899 PSERVICE lpService
= NULL
;
2904 DPRINT("RStartServiceW(%p %lu %p) called\n", hService
, argc
, argv
);
2905 DPRINT(" argc: %lu\n", argc
);
2908 for (i
= 0; i
< argc
; i
++)
2910 DPRINT(" argv[%lu]: %S\n", i
, argv
[i
].StringPtr
);
2916 return ERROR_SHUTDOWN_IN_PROGRESS
;
2918 hSvc
= ScmGetServiceFromHandle(hService
);
2921 DPRINT1("Invalid service handle!\n");
2922 return ERROR_INVALID_HANDLE
;
2925 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
2928 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
2929 return ERROR_ACCESS_DENIED
;
2932 lpService
= hSvc
->ServiceEntry
;
2933 if (lpService
== NULL
)
2935 DPRINT("lpService == NULL!\n");
2936 return ERROR_INVALID_HANDLE
;
2939 if (lpService
->dwStartType
== SERVICE_DISABLED
)
2940 return ERROR_SERVICE_DISABLED
;
2942 if (lpService
->bDeleted
)
2943 return ERROR_SERVICE_MARKED_FOR_DELETE
;
2945 /* Start the service */
2946 dwError
= ScmStartService(lpService
, argc
, (LPWSTR
*)argv
);
2953 DWORD
RGetServiceDisplayNameW(
2954 SC_RPC_HANDLE hSCManager
,
2955 LPCWSTR lpServiceName
,
2956 LPWSTR lpDisplayName
,
2959 // PMANAGER_HANDLE hManager;
2964 DPRINT("RGetServiceDisplayNameW() called\n");
2965 DPRINT("hSCManager = %p\n", hSCManager
);
2966 DPRINT("lpServiceName: %S\n", lpServiceName
);
2967 DPRINT("lpDisplayName: %p\n", lpDisplayName
);
2968 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
2970 // hManager = (PMANAGER_HANDLE)hSCManager;
2971 // if (hManager->Handle.Tag != MANAGER_TAG)
2973 // DPRINT("Invalid manager handle!\n");
2974 // return ERROR_INVALID_HANDLE;
2977 /* Get service database entry */
2978 lpService
= ScmGetServiceEntryByName(lpServiceName
);
2979 if (lpService
== NULL
)
2981 DPRINT("Could not find a service!\n");
2983 /* If the service could not be found and lpcchBuffer is less than 2, windows
2984 puts null in lpDisplayName and puts 2 in lpcchBuffer */
2985 if (*lpcchBuffer
< 2)
2988 if (lpDisplayName
!= NULL
)
2994 return ERROR_SERVICE_DOES_NOT_EXIST
;
2997 if (!lpService
->lpDisplayName
)
2999 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
3001 if (lpDisplayName
!= NULL
&&
3002 *lpcchBuffer
> dwLength
)
3004 wcscpy(lpDisplayName
, lpService
->lpServiceName
);
3009 dwLength
= (DWORD
)wcslen(lpService
->lpDisplayName
);
3011 if (lpDisplayName
!= NULL
&&
3012 *lpcchBuffer
> dwLength
)
3014 wcscpy(lpDisplayName
, lpService
->lpDisplayName
);
3018 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
3020 *lpcchBuffer
= dwLength
;
3027 DWORD
RGetServiceKeyNameW(
3028 SC_RPC_HANDLE hSCManager
,
3029 LPCWSTR lpDisplayName
,
3030 LPWSTR lpServiceName
,
3033 // PMANAGER_HANDLE hManager;
3038 DPRINT("RGetServiceKeyNameW() called\n");
3039 DPRINT("hSCManager = %p\n", hSCManager
);
3040 DPRINT("lpDisplayName: %S\n", lpDisplayName
);
3041 DPRINT("lpServiceName: %p\n", lpServiceName
);
3042 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
3044 // hManager = (PMANAGER_HANDLE)hSCManager;
3045 // if (hManager->Handle.Tag != MANAGER_TAG)
3047 // DPRINT("Invalid manager handle!\n");
3048 // return ERROR_INVALID_HANDLE;
3051 /* Get service database entry */
3052 lpService
= ScmGetServiceEntryByDisplayName(lpDisplayName
);
3053 if (lpService
== NULL
)
3055 DPRINT("Could not find a service!\n");
3057 /* If the service could not be found and lpcchBuffer is less than 2, windows
3058 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3059 if (*lpcchBuffer
< 2)
3062 if (lpServiceName
!= NULL
)
3068 return ERROR_SERVICE_DOES_NOT_EXIST
;
3071 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
3073 if (lpServiceName
!= NULL
&&
3074 *lpcchBuffer
> dwLength
)
3076 wcscpy(lpServiceName
, lpService
->lpServiceName
);
3077 *lpcchBuffer
= dwLength
;
3078 return ERROR_SUCCESS
;
3081 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
3083 *lpcchBuffer
= dwLength
;
3090 DWORD
RI_ScSetServiceBitsA(
3091 RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
3092 DWORD dwServiceBits
,
3094 int bUpdateImmediately
,
3098 return ERROR_CALL_NOT_IMPLEMENTED
;
3103 DWORD
RChangeServiceConfigA(
3104 SC_RPC_HANDLE hService
,
3105 DWORD dwServiceType
,
3107 DWORD dwErrorControl
,
3108 LPSTR lpBinaryPathName
,
3109 LPSTR lpLoadOrderGroup
,
3111 LPBYTE lpDependencies
,
3113 LPSTR lpServiceStartName
,
3116 LPSTR lpDisplayName
)
3118 DWORD dwError
= ERROR_SUCCESS
;
3119 PSERVICE_HANDLE hSvc
;
3120 PSERVICE lpService
= NULL
;
3121 HKEY hServiceKey
= NULL
;
3122 LPWSTR lpDisplayNameW
= NULL
;
3123 LPWSTR lpBinaryPathNameW
= NULL
;
3124 LPWSTR lpCanonicalImagePathW
= NULL
;
3125 LPWSTR lpLoadOrderGroupW
= NULL
;
3126 LPWSTR lpDependenciesW
= NULL
;
3128 DPRINT("RChangeServiceConfigA() called\n");
3129 DPRINT("dwServiceType = %lu\n", dwServiceType
);
3130 DPRINT("dwStartType = %lu\n", dwStartType
);
3131 DPRINT("dwErrorControl = %lu\n", dwErrorControl
);
3132 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName
);
3133 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup
);
3134 DPRINT("lpDisplayName = %s\n", lpDisplayName
);
3137 return ERROR_SHUTDOWN_IN_PROGRESS
;
3139 hSvc
= ScmGetServiceFromHandle(hService
);
3142 DPRINT1("Invalid service handle!\n");
3143 return ERROR_INVALID_HANDLE
;
3146 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3147 SERVICE_CHANGE_CONFIG
))
3149 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
3150 return ERROR_ACCESS_DENIED
;
3153 lpService
= hSvc
->ServiceEntry
;
3154 if (lpService
== NULL
)
3156 DPRINT("lpService == NULL!\n");
3157 return ERROR_INVALID_HANDLE
;
3160 /* Lock the service database exclusively */
3161 ScmLockDatabaseExclusive();
3163 if (lpService
->bDeleted
)
3165 DPRINT("The service has already been marked for delete!\n");
3166 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
3170 /* Open the service key */
3171 dwError
= ScmOpenServiceKey(lpService
->szServiceName
,
3174 if (dwError
!= ERROR_SUCCESS
)
3177 /* Write service data to the registry */
3179 if (lpDisplayName
!= NULL
&& *lpDisplayName
!= 0)
3181 /* Set the display name */
3182 lpDisplayNameW
= HeapAlloc(GetProcessHeap(),
3184 (strlen(lpDisplayName
) + 1) * sizeof(WCHAR
));
3185 if (lpDisplayNameW
== NULL
)
3187 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3191 MultiByteToWideChar(CP_ACP
,
3196 (int)(strlen(lpDisplayName
) + 1));
3198 RegSetValueExW(hServiceKey
,
3202 (LPBYTE
)lpDisplayNameW
,
3203 (DWORD
)((wcslen(lpDisplayNameW
) + 1) * sizeof(WCHAR
)));
3205 /* Update lpService->lpDisplayName */
3206 if (lpService
->lpDisplayName
)
3207 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
3209 lpService
->lpDisplayName
= lpDisplayNameW
;
3212 if (dwServiceType
!= SERVICE_NO_CHANGE
)
3214 /* Set the service type */
3215 dwError
= RegSetValueExW(hServiceKey
,
3219 (LPBYTE
)&dwServiceType
,
3221 if (dwError
!= ERROR_SUCCESS
)
3224 lpService
->Status
.dwServiceType
= dwServiceType
;
3227 if (dwStartType
!= SERVICE_NO_CHANGE
)
3229 /* Set the start value */
3230 dwError
= RegSetValueExW(hServiceKey
,
3234 (LPBYTE
)&dwStartType
,
3236 if (dwError
!= ERROR_SUCCESS
)
3239 lpService
->dwStartType
= dwStartType
;
3242 if (dwErrorControl
!= SERVICE_NO_CHANGE
)
3244 /* Set the error control value */
3245 dwError
= RegSetValueExW(hServiceKey
,
3249 (LPBYTE
)&dwErrorControl
,
3251 if (dwError
!= ERROR_SUCCESS
)
3254 lpService
->dwErrorControl
= dwErrorControl
;
3257 if (lpBinaryPathName
!= NULL
&& *lpBinaryPathName
!= 0)
3259 /* Set the image path */
3260 lpBinaryPathNameW
= HeapAlloc(GetProcessHeap(),
3262 (strlen(lpBinaryPathName
) + 1) * sizeof(WCHAR
));
3263 if (lpBinaryPathNameW
== NULL
)
3265 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3269 MultiByteToWideChar(CP_ACP
,
3274 (int)(strlen(lpBinaryPathName
) + 1));
3276 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
3278 dwError
= ScmCanonDriverImagePath(lpService
->dwStartType
,
3280 &lpCanonicalImagePathW
);
3282 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW
);
3284 if (dwError
!= ERROR_SUCCESS
)
3287 lpBinaryPathNameW
= lpCanonicalImagePathW
;
3290 dwError
= RegSetValueExW(hServiceKey
,
3294 (LPBYTE
)lpBinaryPathNameW
,
3295 (DWORD
)((wcslen(lpBinaryPathNameW
) + 1) * sizeof(WCHAR
)));
3297 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW
);
3299 if (dwError
!= ERROR_SUCCESS
)
3303 /* Set the group name */
3304 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
3306 lpLoadOrderGroupW
= HeapAlloc(GetProcessHeap(),
3308 (strlen(lpLoadOrderGroup
) + 1) * sizeof(WCHAR
));
3309 if (lpLoadOrderGroupW
== NULL
)
3311 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3315 MultiByteToWideChar(CP_ACP
,
3320 (int)(strlen(lpLoadOrderGroup
) + 1));
3322 dwError
= RegSetValueExW(hServiceKey
,
3326 (LPBYTE
)lpLoadOrderGroupW
,
3327 (DWORD
)((wcslen(lpLoadOrderGroupW
) + 1) * sizeof(WCHAR
)));
3328 if (dwError
!= ERROR_SUCCESS
)
3330 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3334 dwError
= ScmSetServiceGroup(lpService
,
3337 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3339 if (dwError
!= ERROR_SUCCESS
)
3343 if (lpdwTagId
!= NULL
)
3345 dwError
= ScmAssignNewTag(lpService
);
3346 if (dwError
!= ERROR_SUCCESS
)
3349 dwError
= RegSetValueExW(hServiceKey
,
3353 (LPBYTE
)&lpService
->dwTag
,
3355 if (dwError
!= ERROR_SUCCESS
)
3358 *lpdwTagId
= lpService
->dwTag
;
3361 /* Write dependencies */
3362 if (lpDependencies
!= NULL
&& *lpDependencies
!= 0)
3364 lpDependenciesW
= HeapAlloc(GetProcessHeap(),
3366 (strlen((LPSTR
)lpDependencies
) + 1) * sizeof(WCHAR
));
3367 if (lpDependenciesW
== NULL
)
3369 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3373 MultiByteToWideChar(CP_ACP
,
3375 (LPSTR
)lpDependencies
,
3378 (int)(strlen((LPSTR
)lpDependencies
) + 1));
3380 dwError
= ScmWriteDependencies(hServiceKey
,
3381 (LPWSTR
)lpDependenciesW
,
3384 HeapFree(GetProcessHeap(), 0, lpDependenciesW
);
3387 if (lpPassword
!= NULL
)
3389 /* FIXME: Decrypt and write password */
3393 /* Unlock the service database */
3394 ScmUnlockDatabase();
3396 if (hServiceKey
!= NULL
)
3397 RegCloseKey(hServiceKey
);
3399 DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError
);
3406 DWORD
RCreateServiceA(
3407 SC_RPC_HANDLE hSCManager
,
3408 LPSTR lpServiceName
,
3409 LPSTR lpDisplayName
,
3410 DWORD dwDesiredAccess
,
3411 DWORD dwServiceType
,
3413 DWORD dwErrorControl
,
3414 LPSTR lpBinaryPathName
,
3415 LPSTR lpLoadOrderGroup
,
3417 LPBYTE lpDependencies
,
3419 LPSTR lpServiceStartName
,
3422 LPSC_RPC_HANDLE lpServiceHandle
)
3424 DWORD dwError
= ERROR_SUCCESS
;
3425 LPWSTR lpServiceNameW
= NULL
;
3426 LPWSTR lpDisplayNameW
= NULL
;
3427 LPWSTR lpBinaryPathNameW
= NULL
;
3428 LPWSTR lpLoadOrderGroupW
= NULL
;
3429 LPWSTR lpDependenciesW
= NULL
;
3430 LPWSTR lpServiceStartNameW
= NULL
;
3431 DWORD dwDependenciesLength
= 0;
3438 len
= MultiByteToWideChar(CP_ACP
, 0, lpServiceName
, -1, NULL
, 0);
3439 lpServiceNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3440 if (!lpServiceNameW
)
3442 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3445 MultiByteToWideChar(CP_ACP
, 0, lpServiceName
, -1, lpServiceNameW
, len
);
3450 len
= MultiByteToWideChar(CP_ACP
, 0, lpDisplayName
, -1, NULL
, 0);
3451 lpDisplayNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3452 if (!lpDisplayNameW
)
3454 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3457 MultiByteToWideChar(CP_ACP
, 0, lpDisplayName
, -1, lpDisplayNameW
, len
);
3460 if (lpBinaryPathName
)
3462 len
= MultiByteToWideChar(CP_ACP
, 0, lpBinaryPathName
, -1, NULL
, 0);
3463 lpBinaryPathNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3464 if (!lpBinaryPathNameW
)
3466 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3469 MultiByteToWideChar(CP_ACP
, 0, lpBinaryPathName
, -1, lpBinaryPathNameW
, len
);
3472 if (lpLoadOrderGroup
)
3474 len
= MultiByteToWideChar(CP_ACP
, 0, lpLoadOrderGroup
, -1, NULL
, 0);
3475 lpLoadOrderGroupW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3476 if (!lpLoadOrderGroupW
)
3478 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3481 MultiByteToWideChar(CP_ACP
, 0, lpLoadOrderGroup
, -1, lpLoadOrderGroupW
, len
);
3486 lpStr
= (LPCSTR
)lpDependencies
;
3489 cchLength
= strlen(lpStr
) + 1;
3490 dwDependenciesLength
+= (DWORD
)cchLength
;
3491 lpStr
= lpStr
+ cchLength
;
3493 dwDependenciesLength
++;
3495 lpDependenciesW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwDependenciesLength
* sizeof(WCHAR
));
3496 if (!lpDependenciesW
)
3498 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3501 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)lpDependencies
, dwDependenciesLength
, lpDependenciesW
, dwDependenciesLength
);
3504 if (lpServiceStartName
)
3506 len
= MultiByteToWideChar(CP_ACP
, 0, lpServiceStartName
, -1, NULL
, 0);
3507 lpServiceStartNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3508 if (!lpServiceStartNameW
)
3510 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3513 MultiByteToWideChar(CP_ACP
, 0, lpServiceStartName
, -1, lpServiceStartNameW
, len
);
3516 dwError
= RCreateServiceW(hSCManager
,
3526 (LPBYTE
)lpDependenciesW
,
3527 dwDependenciesLength
,
3528 lpServiceStartNameW
,
3534 if (lpServiceNameW
!=NULL
)
3535 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
3537 if (lpDisplayNameW
!= NULL
)
3538 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
3540 if (lpBinaryPathNameW
!= NULL
)
3541 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW
);
3543 if (lpLoadOrderGroupW
!= NULL
)
3544 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3546 if (lpDependenciesW
!= NULL
)
3547 HeapFree(GetProcessHeap(), 0, lpDependenciesW
);
3549 if (lpServiceStartNameW
!= NULL
)
3550 HeapFree(GetProcessHeap(), 0, lpServiceStartNameW
);
3557 DWORD
REnumDependentServicesA(
3558 SC_RPC_HANDLE hService
,
3559 DWORD dwServiceState
,
3562 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
3563 LPBOUNDED_DWORD_256K lpServicesReturned
)
3565 DWORD dwError
= ERROR_SUCCESS
;
3566 DWORD dwServicesReturned
= 0;
3567 DWORD dwServiceCount
;
3568 HKEY hServicesKey
= NULL
;
3569 PSERVICE_HANDLE hSvc
;
3570 PSERVICE lpService
= NULL
;
3571 PSERVICE
*lpServicesArray
= NULL
;
3572 LPENUM_SERVICE_STATUSA lpServicesPtr
= NULL
;
3575 *pcbBytesNeeded
= 0;
3576 *lpServicesReturned
= 0;
3578 DPRINT("REnumDependentServicesA() called\n");
3580 hSvc
= ScmGetServiceFromHandle(hService
);
3583 DPRINT1("Invalid service handle!\n");
3584 return ERROR_INVALID_HANDLE
;
3587 lpService
= hSvc
->ServiceEntry
;
3589 /* Check access rights */
3590 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3591 SC_MANAGER_ENUMERATE_SERVICE
))
3593 DPRINT("Insufficient access rights! 0x%lx\n",
3594 hSvc
->Handle
.DesiredAccess
);
3595 return ERROR_ACCESS_DENIED
;
3598 /* Open the Services Reg key */
3599 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
3600 L
"System\\CurrentControlSet\\Services",
3605 if (dwError
!= ERROR_SUCCESS
)
3608 /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3609 both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3610 are the same for both. Verified in WINXP. */
3612 /* First determine the bytes needed and get the number of dependent services*/
3613 dwError
= Int_EnumDependentServicesW(hServicesKey
,
3618 &dwServicesReturned
);
3619 if (dwError
!= ERROR_SUCCESS
)
3622 /* If buffer size is less than the bytes needed or pointer is null*/
3623 if ((!lpServices
) || (cbBufSize
< *pcbBytesNeeded
))
3625 dwError
= ERROR_MORE_DATA
;
3629 /* Allocate memory for array of service pointers */
3630 lpServicesArray
= HeapAlloc(GetProcessHeap(),
3632 (dwServicesReturned
+ 1) * sizeof(PSERVICE
));
3633 if (!lpServicesArray
)
3635 DPRINT("Could not allocate a buffer!!\n");
3636 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3640 dwServicesReturned
= 0;
3641 *pcbBytesNeeded
= 0;
3643 dwError
= Int_EnumDependentServicesW(hServicesKey
,
3648 &dwServicesReturned
);
3649 if (dwError
!= ERROR_SUCCESS
)
3654 lpServicesPtr
= (LPENUM_SERVICE_STATUSA
)lpServices
;
3655 lpStr
= (LPSTR
)(lpServices
+ (dwServicesReturned
* sizeof(ENUM_SERVICE_STATUSA
)));
3657 /* Copy EnumDepenedentService to Buffer */
3658 for (dwServiceCount
= 0; dwServiceCount
< dwServicesReturned
; dwServiceCount
++)
3660 lpService
= lpServicesArray
[dwServiceCount
];
3662 /* Copy the status info */
3663 memcpy(&lpServicesPtr
->ServiceStatus
,
3665 sizeof(SERVICE_STATUS
));
3667 /* Copy display name */
3668 WideCharToMultiByte(CP_ACP
,
3670 lpService
->lpDisplayName
,
3673 (int)wcslen(lpService
->lpDisplayName
),
3676 lpServicesPtr
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
3677 lpStr
+= strlen(lpStr
) + 1;
3679 /* Copy service name */
3680 WideCharToMultiByte(CP_ACP
,
3682 lpService
->lpServiceName
,
3685 (int)wcslen(lpService
->lpServiceName
),
3688 lpServicesPtr
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
3689 lpStr
+= strlen(lpStr
) + 1;
3694 *lpServicesReturned
= dwServicesReturned
;
3697 if (lpServicesArray
)
3698 HeapFree(GetProcessHeap(), 0, lpServicesArray
);
3700 RegCloseKey(hServicesKey
);
3702 DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError
);
3709 DWORD
REnumServicesStatusA(
3710 SC_RPC_HANDLE hSCManager
,
3711 DWORD dwServiceType
,
3712 DWORD dwServiceState
,
3715 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
3716 LPBOUNDED_DWORD_256K lpServicesReturned
,
3717 LPBOUNDED_DWORD_256K lpResumeHandle
)
3719 LPENUM_SERVICE_STATUSW lpStatusPtrW
= NULL
;
3720 LPENUM_SERVICE_STATUSW lpStatusPtrIncrW
;
3721 LPENUM_SERVICE_STATUSA lpStatusPtrA
= NULL
;
3722 LPWSTR lpStringPtrW
;
3725 DWORD dwServiceCount
;
3727 DPRINT("REnumServicesStatusA() called\n");
3729 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
3731 return ERROR_INVALID_ADDRESS
;
3734 if ((dwBufSize
> 0) && (lpBuffer
))
3736 lpStatusPtrW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwBufSize
);
3739 DPRINT("Failed to allocate buffer!\n");
3740 return ERROR_NOT_ENOUGH_MEMORY
;
3744 dwError
= REnumServicesStatusW(hSCManager
,
3747 (LPBYTE
)lpStatusPtrW
,
3753 /* if no services were returned then we are Done */
3754 if (*lpServicesReturned
== 0)
3757 lpStatusPtrIncrW
= lpStatusPtrW
;
3758 lpStatusPtrA
= (LPENUM_SERVICE_STATUSA
)lpBuffer
;
3759 lpStringPtrA
= (LPSTR
)((ULONG_PTR
)lpBuffer
+
3760 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUSA
));
3761 lpStringPtrW
= (LPWSTR
)((ULONG_PTR
)lpStatusPtrW
+
3762 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUSW
));
3764 for (dwServiceCount
= 0; dwServiceCount
< *lpServicesReturned
; dwServiceCount
++)
3766 /* Copy the service name */
3767 WideCharToMultiByte(CP_ACP
,
3772 (int)wcslen(lpStringPtrW
),
3776 lpStatusPtrA
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
3777 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
3778 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
3780 /* Copy the display name */
3781 WideCharToMultiByte(CP_ACP
,
3786 (int)wcslen(lpStringPtrW
),
3790 lpStatusPtrA
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
3791 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
3792 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
3794 /* Copy the status information */
3795 memcpy(&lpStatusPtrA
->ServiceStatus
,
3796 &lpStatusPtrIncrW
->ServiceStatus
,
3797 sizeof(SERVICE_STATUS
));
3805 HeapFree(GetProcessHeap(), 0, lpStatusPtrW
);
3807 DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError
);
3814 DWORD
ROpenSCManagerA(
3815 LPSTR lpMachineName
,
3816 LPSTR lpDatabaseName
,
3817 DWORD dwDesiredAccess
,
3818 LPSC_RPC_HANDLE lpScHandle
)
3820 UNICODE_STRING MachineName
;
3821 UNICODE_STRING DatabaseName
;
3824 DPRINT("ROpenSCManagerA() called\n");
3827 RtlCreateUnicodeStringFromAsciiz(&MachineName
,
3831 RtlCreateUnicodeStringFromAsciiz(&DatabaseName
,
3834 dwError
= ROpenSCManagerW(lpMachineName
? MachineName
.Buffer
: NULL
,
3835 lpDatabaseName
? DatabaseName
.Buffer
: NULL
,
3840 RtlFreeUnicodeString(&MachineName
);
3843 RtlFreeUnicodeString(&DatabaseName
);
3850 DWORD
ROpenServiceA(
3851 SC_RPC_HANDLE hSCManager
,
3852 LPSTR lpServiceName
,
3853 DWORD dwDesiredAccess
,
3854 LPSC_RPC_HANDLE lpServiceHandle
)
3856 UNICODE_STRING ServiceName
;
3859 DPRINT("ROpenServiceA() called\n");
3862 RtlCreateUnicodeStringFromAsciiz(&ServiceName
,
3865 dwError
= ROpenServiceW(hSCManager
,
3866 lpServiceName
? ServiceName
.Buffer
: NULL
,
3871 RtlFreeUnicodeString(&ServiceName
);
3878 DWORD
RQueryServiceConfigA(
3879 SC_RPC_HANDLE hService
,
3880 LPBYTE lpBuf
, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
3882 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
3884 LPQUERY_SERVICE_CONFIGA lpServiceConfig
= (LPQUERY_SERVICE_CONFIGA
)lpBuf
;
3885 DWORD dwError
= ERROR_SUCCESS
;
3886 PSERVICE_HANDLE hSvc
;
3887 PSERVICE lpService
= NULL
;
3888 HKEY hServiceKey
= NULL
;
3889 LPWSTR lpImagePath
= NULL
;
3890 LPWSTR lpServiceStartName
= NULL
;
3891 LPWSTR lpDependencies
= NULL
;
3892 DWORD dwDependenciesLength
= 0;
3893 DWORD dwRequiredSize
;
3894 CHAR lpEmptyString
[]={0,0};
3897 DPRINT("RQueryServiceConfigA() called\n");
3900 return ERROR_SHUTDOWN_IN_PROGRESS
;
3902 hSvc
= ScmGetServiceFromHandle(hService
);
3905 DPRINT1("Invalid service handle!\n");
3906 return ERROR_INVALID_HANDLE
;
3909 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3910 SERVICE_QUERY_CONFIG
))
3912 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
3913 return ERROR_ACCESS_DENIED
;
3916 lpService
= hSvc
->ServiceEntry
;
3917 if (lpService
== NULL
)
3919 DPRINT("lpService == NULL!\n");
3920 return ERROR_INVALID_HANDLE
;
3923 /* Lock the service database shared */
3924 ScmLockDatabaseShared();
3926 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
3929 if (dwError
!= ERROR_SUCCESS
)
3932 /* Read the image path */
3933 dwError
= ScmReadString(hServiceKey
,
3936 if (dwError
!= ERROR_SUCCESS
)
3939 /* Read the service start name */
3940 ScmReadString(hServiceKey
,
3942 &lpServiceStartName
);
3944 /* Read the dependencies */
3945 ScmReadDependencies(hServiceKey
,
3947 &dwDependenciesLength
);
3949 dwRequiredSize
= sizeof(QUERY_SERVICE_CONFIGA
);
3951 if (lpImagePath
!= NULL
)
3952 dwRequiredSize
+= (DWORD
)(wcslen(lpImagePath
) + 1);
3954 dwRequiredSize
+= 2;
3956 if ((lpService
->lpGroup
!= NULL
) && (lpService
->lpGroup
->lpGroupName
!= NULL
))
3957 dwRequiredSize
+= (DWORD
)(wcslen(lpService
->lpGroup
->lpGroupName
) + 1);
3959 dwRequiredSize
+= 2;
3961 /* Add Dependencies length */
3962 if (lpDependencies
!= NULL
)
3963 dwRequiredSize
+= dwDependenciesLength
;
3965 dwRequiredSize
+= 2;
3967 if (lpServiceStartName
!= NULL
)
3968 dwRequiredSize
+= (DWORD
)(wcslen(lpServiceStartName
) + 1);
3970 dwRequiredSize
+= 2;
3972 if (lpService
->lpDisplayName
!= NULL
)
3973 dwRequiredSize
+= (DWORD
)(wcslen(lpService
->lpDisplayName
) + 1);
3975 dwRequiredSize
+= 2;
3977 if (lpServiceConfig
== NULL
|| cbBufSize
< dwRequiredSize
)
3979 dwError
= ERROR_INSUFFICIENT_BUFFER
;
3983 lpServiceConfig
->dwServiceType
= lpService
->Status
.dwServiceType
;
3984 lpServiceConfig
->dwStartType
= lpService
->dwStartType
;
3985 lpServiceConfig
->dwErrorControl
= lpService
->dwErrorControl
;
3986 lpServiceConfig
->dwTagId
= lpService
->dwTag
;
3988 lpStr
= (LPSTR
)(lpServiceConfig
+ 1);
3990 /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
3991 Verified in WINXP */
3995 WideCharToMultiByte(CP_ACP
,
4000 (int)(wcslen(lpImagePath
) + 1),
4006 strcpy(lpStr
, lpEmptyString
);
4009 lpServiceConfig
->lpBinaryPathName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4010 lpStr
+= (strlen((LPSTR
)lpStr
) + 1);
4012 if (lpService
->lpGroup
&& lpService
->lpGroup
->lpGroupName
)
4014 WideCharToMultiByte(CP_ACP
,
4016 lpService
->lpGroup
->lpGroupName
,
4019 (int)(wcslen(lpService
->lpGroup
->lpGroupName
) + 1),
4025 strcpy(lpStr
, lpEmptyString
);
4028 lpServiceConfig
->lpLoadOrderGroup
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4029 lpStr
+= (strlen(lpStr
) + 1);
4031 /* Append Dependencies */
4034 WideCharToMultiByte(CP_ACP
,
4037 dwDependenciesLength
,
4039 dwDependenciesLength
,
4045 strcpy(lpStr
, lpEmptyString
);
4048 lpServiceConfig
->lpDependencies
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4050 lpStr
+= dwDependenciesLength
;
4052 lpStr
+= (strlen(lpStr
) + 1);
4054 if (lpServiceStartName
)
4056 WideCharToMultiByte(CP_ACP
,
4061 (int)(wcslen(lpServiceStartName
) + 1),
4067 strcpy(lpStr
, lpEmptyString
);
4070 lpServiceConfig
->lpServiceStartName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4071 lpStr
+= (strlen(lpStr
) + 1);
4073 if (lpService
->lpDisplayName
)
4075 WideCharToMultiByte(CP_ACP
,
4077 lpService
->lpDisplayName
,
4080 (int)(wcslen(lpService
->lpDisplayName
) + 1),
4086 strcpy(lpStr
, lpEmptyString
);
4089 lpServiceConfig
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4092 if (pcbBytesNeeded
!= NULL
)
4093 *pcbBytesNeeded
= dwRequiredSize
;
4096 /* Unlock the service database */
4097 ScmUnlockDatabase();
4099 if (lpImagePath
!= NULL
)
4100 HeapFree(GetProcessHeap(), 0, lpImagePath
);
4102 if (lpServiceStartName
!= NULL
)
4103 HeapFree(GetProcessHeap(), 0, lpServiceStartName
);
4105 if (lpDependencies
!= NULL
)
4106 HeapFree(GetProcessHeap(), 0, lpDependencies
);
4108 if (hServiceKey
!= NULL
)
4109 RegCloseKey(hServiceKey
);
4111 DPRINT("RQueryServiceConfigA() done\n");
4118 DWORD
RQueryServiceLockStatusA(
4119 SC_RPC_HANDLE hSCManager
,
4120 LPBYTE lpBuf
, // LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
4122 LPBOUNDED_DWORD_4K pcbBytesNeeded
)
4124 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
= (LPQUERY_SERVICE_LOCK_STATUSA
)lpBuf
;
4125 PMANAGER_HANDLE hMgr
;
4126 DWORD dwRequiredSize
;
4128 if (!lpLockStatus
|| !pcbBytesNeeded
)
4129 return ERROR_INVALID_PARAMETER
;
4131 hMgr
= ScmGetServiceManagerFromHandle(hSCManager
);
4134 DPRINT1("Invalid service manager handle!\n");
4135 return ERROR_INVALID_HANDLE
;
4138 if (!RtlAreAllAccessesGranted(hMgr
->Handle
.DesiredAccess
,
4139 SC_MANAGER_QUERY_LOCK_STATUS
))
4141 DPRINT("Insufficient access rights! 0x%lx\n", hMgr
->Handle
.DesiredAccess
);
4142 return ERROR_ACCESS_DENIED
;
4145 /* FIXME: we need to compute instead the real length of the owner name */
4146 dwRequiredSize
= sizeof(QUERY_SERVICE_LOCK_STATUSA
) + sizeof(CHAR
);
4147 *pcbBytesNeeded
= dwRequiredSize
;
4149 if (cbBufSize
< dwRequiredSize
)
4150 return ERROR_INSUFFICIENT_BUFFER
;
4152 ScmQueryServiceLockStatusA(lpLockStatus
);
4154 return ERROR_SUCCESS
;
4159 DWORD
RStartServiceA(
4160 SC_RPC_HANDLE hService
,
4162 LPSTRING_PTRSA argv
)
4164 DWORD dwError
= ERROR_SUCCESS
;
4165 PSERVICE_HANDLE hSvc
;
4166 PSERVICE lpService
= NULL
;
4167 LPWSTR
*lpVector
= NULL
;
4171 DPRINT("RStartServiceA() called\n");
4174 return ERROR_SHUTDOWN_IN_PROGRESS
;
4176 hSvc
= ScmGetServiceFromHandle(hService
);
4179 DPRINT1("Invalid service handle!\n");
4180 return ERROR_INVALID_HANDLE
;
4183 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
4186 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
4187 return ERROR_ACCESS_DENIED
;
4190 lpService
= hSvc
->ServiceEntry
;
4191 if (lpService
== NULL
)
4193 DPRINT("lpService == NULL!\n");
4194 return ERROR_INVALID_HANDLE
;
4197 if (lpService
->dwStartType
== SERVICE_DISABLED
)
4198 return ERROR_SERVICE_DISABLED
;
4200 if (lpService
->bDeleted
)
4201 return ERROR_SERVICE_MARKED_FOR_DELETE
;
4203 /* Build a Unicode argument vector */
4206 lpVector
= HeapAlloc(GetProcessHeap(),
4208 argc
* sizeof(LPWSTR
));
4209 if (lpVector
== NULL
)
4210 return ERROR_NOT_ENOUGH_MEMORY
;
4212 for (i
= 0; i
< argc
; i
++)
4214 dwLength
= MultiByteToWideChar(CP_ACP
,
4221 lpVector
[i
] = HeapAlloc(GetProcessHeap(),
4223 dwLength
* sizeof(WCHAR
));
4224 if (lpVector
[i
] == NULL
)
4226 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
4230 MultiByteToWideChar(CP_ACP
,
4239 /* Start the service */
4240 dwError
= ScmStartService(lpService
, argc
, lpVector
);
4243 /* Free the Unicode argument vector */
4244 if (lpVector
!= NULL
)
4246 for (i
= 0; i
< argc
; i
++)
4248 if (lpVector
[i
] != NULL
)
4249 HeapFree(GetProcessHeap(), 0, lpVector
[i
]);
4251 HeapFree(GetProcessHeap(), 0, lpVector
);
4259 DWORD
RGetServiceDisplayNameA(
4260 SC_RPC_HANDLE hSCManager
,
4261 LPCSTR lpServiceName
,
4262 LPSTR lpDisplayName
,
4263 LPBOUNDED_DWORD_4K lpcchBuffer
)
4265 // PMANAGER_HANDLE hManager;
4266 PSERVICE lpService
= NULL
;
4269 LPWSTR lpServiceNameW
;
4271 DPRINT("RGetServiceDisplayNameA() called\n");
4272 DPRINT("hSCManager = %p\n", hSCManager
);
4273 DPRINT("lpServiceName: %s\n", lpServiceName
);
4274 DPRINT("lpDisplayName: %p\n", lpDisplayName
);
4275 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
4277 // hManager = (PMANAGER_HANDLE)hSCManager;
4278 // if (hManager->Handle.Tag != MANAGER_TAG)
4280 // DPRINT("Invalid manager handle!\n");
4281 // return ERROR_INVALID_HANDLE;
4284 if (lpServiceName
!= NULL
)
4286 dwLength
= (DWORD
)(strlen(lpServiceName
) + 1);
4287 lpServiceNameW
= HeapAlloc(GetProcessHeap(),
4289 dwLength
* sizeof(WCHAR
));
4290 if (!lpServiceNameW
)
4291 return ERROR_NOT_ENOUGH_MEMORY
;
4293 MultiByteToWideChar(CP_ACP
,
4300 lpService
= ScmGetServiceEntryByName(lpServiceNameW
);
4302 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
4305 if (lpService
== NULL
)
4307 DPRINT("Could not find a service!\n");
4309 /* If the service could not be found and lpcchBuffer is 0, windows
4310 puts null in lpDisplayName and puts 1 in lpcchBuffer */
4311 if (*lpcchBuffer
== 0)
4314 if (lpDisplayName
!= NULL
)
4319 return ERROR_SERVICE_DOES_NOT_EXIST
;
4322 if (!lpService
->lpDisplayName
)
4324 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
4325 if (lpDisplayName
!= NULL
&&
4326 *lpcchBuffer
> dwLength
)
4328 WideCharToMultiByte(CP_ACP
,
4330 lpService
->lpServiceName
,
4331 (int)wcslen(lpService
->lpServiceName
),
4336 return ERROR_SUCCESS
;
4341 dwLength
= (DWORD
)wcslen(lpService
->lpDisplayName
);
4342 if (lpDisplayName
!= NULL
&&
4343 *lpcchBuffer
> dwLength
)
4345 WideCharToMultiByte(CP_ACP
,
4347 lpService
->lpDisplayName
,
4348 (int)wcslen(lpService
->lpDisplayName
),
4353 return ERROR_SUCCESS
;
4357 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
4359 *lpcchBuffer
= dwLength
* 2;
4366 DWORD
RGetServiceKeyNameA(
4367 SC_RPC_HANDLE hSCManager
,
4368 LPCSTR lpDisplayName
,
4369 LPSTR lpServiceName
,
4370 LPBOUNDED_DWORD_4K lpcchBuffer
)
4375 LPWSTR lpDisplayNameW
;
4377 DPRINT("RGetServiceKeyNameA() called\n");
4378 DPRINT("hSCManager = %p\n", hSCManager
);
4379 DPRINT("lpDisplayName: %s\n", lpDisplayName
);
4380 DPRINT("lpServiceName: %p\n", lpServiceName
);
4381 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
4383 dwLength
= (DWORD
)(strlen(lpDisplayName
) + 1);
4384 lpDisplayNameW
= HeapAlloc(GetProcessHeap(),
4386 dwLength
* sizeof(WCHAR
));
4387 if (!lpDisplayNameW
)
4388 return ERROR_NOT_ENOUGH_MEMORY
;
4390 MultiByteToWideChar(CP_ACP
,
4397 lpService
= ScmGetServiceEntryByDisplayName(lpDisplayNameW
);
4399 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
4401 if (lpService
== NULL
)
4403 DPRINT("Could not find the service!\n");
4405 /* If the service could not be found and lpcchBuffer is 0,
4406 put null in lpDisplayName and puts 1 in lpcchBuffer, verified WINXP. */
4407 if (*lpcchBuffer
== 0)
4410 if (lpServiceName
!= NULL
)
4416 return ERROR_SERVICE_DOES_NOT_EXIST
;
4419 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
4420 if (lpServiceName
!= NULL
&&
4421 *lpcchBuffer
> dwLength
)
4423 WideCharToMultiByte(CP_ACP
,
4425 lpService
->lpServiceName
,
4426 (int)wcslen(lpService
->lpServiceName
),
4431 return ERROR_SUCCESS
;
4434 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
4436 *lpcchBuffer
= dwLength
* 2;
4443 DWORD
RI_ScGetCurrentGroupStateW(
4444 SC_RPC_HANDLE hSCManager
,
4445 LPWSTR lpLoadOrderGroup
,
4449 return ERROR_CALL_NOT_IMPLEMENTED
;
4454 DWORD
REnumServiceGroupW(
4455 SC_RPC_HANDLE hSCManager
,
4456 DWORD dwServiceType
,
4457 DWORD dwServiceState
,
4460 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
4461 LPBOUNDED_DWORD_256K lpServicesReturned
,
4462 LPBOUNDED_DWORD_256K lpResumeIndex
,
4463 LPCWSTR pszGroupName
)
4465 PMANAGER_HANDLE hManager
;
4467 DWORD dwError
= ERROR_SUCCESS
;
4468 PLIST_ENTRY ServiceEntry
;
4469 PSERVICE CurrentService
;
4471 DWORD dwRequiredSize
;
4472 DWORD dwServiceCount
;
4474 DWORD dwLastResumeCount
= 0;
4475 LPENUM_SERVICE_STATUSW lpStatusPtr
;
4478 DPRINT("REnumServiceGroupW() called\n");
4481 return ERROR_SHUTDOWN_IN_PROGRESS
;
4483 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
4484 if (hManager
== NULL
)
4486 DPRINT1("Invalid service manager handle!\n");
4487 return ERROR_INVALID_HANDLE
;
4490 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
4492 return ERROR_INVALID_ADDRESS
;
4495 *pcbBytesNeeded
= 0;
4496 *lpServicesReturned
= 0;
4498 if ((dwServiceType
== 0) ||
4499 ((dwServiceType
& ~SERVICE_TYPE_ALL
) != 0))
4501 DPRINT("Not a valid Service Type!\n");
4502 return ERROR_INVALID_PARAMETER
;
4505 if ((dwServiceState
== 0) ||
4506 ((dwServiceState
& ~SERVICE_STATE_ALL
) != 0))
4508 DPRINT("Not a valid Service State!\n");
4509 return ERROR_INVALID_PARAMETER
;
4512 /* Check access rights */
4513 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
4514 SC_MANAGER_ENUMERATE_SERVICE
))
4516 DPRINT("Insufficient access rights! 0x%lx\n",
4517 hManager
->Handle
.DesiredAccess
);
4518 return ERROR_ACCESS_DENIED
;
4522 dwLastResumeCount
= *lpResumeIndex
;
4524 /* Lock the service database shared */
4525 ScmLockDatabaseShared();
4527 lpService
= ScmGetServiceEntryByResumeCount(dwLastResumeCount
);
4528 if (lpService
== NULL
)
4530 dwError
= ERROR_SUCCESS
;
4537 for (ServiceEntry
= &lpService
->ServiceListEntry
;
4538 ServiceEntry
!= &ServiceListHead
;
4539 ServiceEntry
= ServiceEntry
->Flink
)
4541 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
4545 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
4548 dwState
= SERVICE_ACTIVE
;
4549 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
4550 dwState
= SERVICE_INACTIVE
;
4552 if ((dwState
& dwServiceState
) == 0)
4557 if (*pszGroupName
== 0)
4559 if (CurrentService
->lpGroup
!= NULL
)
4564 if ((CurrentService
->lpGroup
== NULL
) ||
4565 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
4570 dwSize
= sizeof(ENUM_SERVICE_STATUSW
) +
4571 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
4572 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
4574 if (dwRequiredSize
+ dwSize
> cbBufSize
)
4576 DPRINT("Service name: %S no fit\n", CurrentService
->lpServiceName
);
4580 DPRINT("Service name: %S fit\n", CurrentService
->lpServiceName
);
4581 dwRequiredSize
+= dwSize
;
4583 dwLastResumeCount
= CurrentService
->dwResumeCount
;
4586 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize
);
4587 DPRINT("dwServiceCount: %lu\n", dwServiceCount
);
4590 ServiceEntry
!= &ServiceListHead
;
4591 ServiceEntry
= ServiceEntry
->Flink
)
4593 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
4597 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
4600 dwState
= SERVICE_ACTIVE
;
4601 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
4602 dwState
= SERVICE_INACTIVE
;
4604 if ((dwState
& dwServiceState
) == 0)
4609 if (*pszGroupName
== 0)
4611 if (CurrentService
->lpGroup
!= NULL
)
4616 if ((CurrentService
->lpGroup
== NULL
) ||
4617 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
4622 dwRequiredSize
+= (sizeof(ENUM_SERVICE_STATUSW
) +
4623 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
4624 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
)));
4626 dwError
= ERROR_MORE_DATA
;
4629 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize
);
4632 *lpResumeIndex
= dwLastResumeCount
;
4634 *lpServicesReturned
= dwServiceCount
;
4635 *pcbBytesNeeded
= dwRequiredSize
;
4637 lpStatusPtr
= (LPENUM_SERVICE_STATUSW
)lpBuffer
;
4638 lpStringPtr
= (LPWSTR
)((ULONG_PTR
)lpBuffer
+
4639 dwServiceCount
* sizeof(ENUM_SERVICE_STATUSW
));
4642 for (ServiceEntry
= &lpService
->ServiceListEntry
;
4643 ServiceEntry
!= &ServiceListHead
;
4644 ServiceEntry
= ServiceEntry
->Flink
)
4646 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
4650 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
4653 dwState
= SERVICE_ACTIVE
;
4654 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
4655 dwState
= SERVICE_INACTIVE
;
4657 if ((dwState
& dwServiceState
) == 0)
4662 if (*pszGroupName
== 0)
4664 if (CurrentService
->lpGroup
!= NULL
)
4669 if ((CurrentService
->lpGroup
== NULL
) ||
4670 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
4675 dwSize
= sizeof(ENUM_SERVICE_STATUSW
) +
4676 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
4677 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
4679 if (dwRequiredSize
+ dwSize
> cbBufSize
)
4682 /* Copy the service name */
4683 wcscpy(lpStringPtr
, CurrentService
->lpServiceName
);
4684 lpStatusPtr
->lpServiceName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
4685 lpStringPtr
+= (wcslen(CurrentService
->lpServiceName
) + 1);
4687 /* Copy the display name */
4688 wcscpy(lpStringPtr
, CurrentService
->lpDisplayName
);
4689 lpStatusPtr
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
4690 lpStringPtr
+= (wcslen(CurrentService
->lpDisplayName
) + 1);
4692 /* Copy the status information */
4693 memcpy(&lpStatusPtr
->ServiceStatus
,
4694 &CurrentService
->Status
,
4695 sizeof(SERVICE_STATUS
));
4698 dwRequiredSize
+= dwSize
;
4701 if (dwError
== ERROR_SUCCESS
)
4703 *pcbBytesNeeded
= 0;
4704 if (lpResumeIndex
) *lpResumeIndex
= 0;
4708 /* Unlock the service database */
4709 ScmUnlockDatabase();
4711 DPRINT("REnumServiceGroupW() done (Error %lu)\n", dwError
);
4718 DWORD
RChangeServiceConfig2A(
4719 SC_RPC_HANDLE hService
,
4720 SC_RPC_CONFIG_INFOA Info
)
4722 SC_RPC_CONFIG_INFOW InfoW
;
4723 DWORD dwRet
, dwLength
;
4726 DPRINT("RChangeServiceConfig2A() called\n");
4727 DPRINT("dwInfoLevel = %lu\n", Info
.dwInfoLevel
);
4729 InfoW
.dwInfoLevel
= Info
.dwInfoLevel
;
4731 if (InfoW
.dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
4733 LPSERVICE_DESCRIPTIONW lpServiceDescriptionW
;
4734 //LPSERVICE_DESCRIPTIONA lpServiceDescriptionA;
4736 //lpServiceDescriptionA = Info.psd;
4738 ///if (lpServiceDescriptionA &&
4739 ///lpServiceDescriptionA->lpDescription)
4741 dwLength
= (DWORD
)((strlen(Info
.lpDescription
) + 1) * sizeof(WCHAR
));
4743 lpServiceDescriptionW
= HeapAlloc(GetProcessHeap(),
4745 dwLength
+ sizeof(SERVICE_DESCRIPTIONW
));
4746 if (!lpServiceDescriptionW
)
4748 return ERROR_NOT_ENOUGH_MEMORY
;
4751 lpServiceDescriptionW
->lpDescription
= (LPWSTR
)(lpServiceDescriptionW
+ 1);
4753 MultiByteToWideChar(CP_ACP
,
4757 lpServiceDescriptionW
->lpDescription
,
4760 ptr
= lpServiceDescriptionW
;
4761 InfoW
.psd
= lpServiceDescriptionW
;
4764 else if (Info
.dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
4766 LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW
;
4767 LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA
;
4768 DWORD dwRebootLen
= 0;
4769 DWORD dwCommandLen
= 0;
4770 DWORD dwActionArrayLen
= 0;
4771 LPWSTR lpStr
= NULL
;
4773 lpServiceFailureActionsA
= Info
.psfa
;
4775 if (lpServiceFailureActionsA
)
4778 * The following code is inspired by the
4779 * SERVICE_CONFIG_FAILURE_ACTIONS case of
4780 * the RQueryServiceConfig2W function.
4783 /* Retrieve the needed length for the two data strings */
4784 if (lpServiceFailureActionsA
->lpRebootMsg
)
4786 dwRebootLen
= (DWORD
)((strlen(lpServiceFailureActionsA
->lpRebootMsg
) + 1) * sizeof(WCHAR
));
4788 if (lpServiceFailureActionsA
->lpCommand
)
4790 dwCommandLen
= (DWORD
)((strlen(lpServiceFailureActionsA
->lpCommand
) + 1) * sizeof(WCHAR
));
4794 * Retrieve the size of the lpsaActions array if needed.
4795 * We will copy the lpsaActions array only if there is at
4796 * least one action AND that the original array is valid.
4798 if (lpServiceFailureActionsA
->cActions
> 0 && lpServiceFailureActionsA
->lpsaActions
)
4800 dwActionArrayLen
= lpServiceFailureActionsA
->cActions
* sizeof(SC_ACTION
);
4803 /* Compute the total length for the UNICODE structure, including data */
4804 dwLength
= sizeof(SERVICE_FAILURE_ACTIONSW
) +
4805 dwActionArrayLen
+ dwRebootLen
+ dwCommandLen
;
4807 /* Allocate the structure */
4808 lpServiceFailureActionsW
= HeapAlloc(GetProcessHeap(),
4811 if (!lpServiceFailureActionsW
)
4813 return ERROR_NOT_ENOUGH_MEMORY
;
4816 /* Copy the members */
4817 lpServiceFailureActionsW
->dwResetPeriod
= lpServiceFailureActionsA
->dwResetPeriod
;
4818 lpServiceFailureActionsW
->cActions
= lpServiceFailureActionsA
->cActions
;
4820 /* Copy the lpsaActions array if needed */
4821 if (dwActionArrayLen
> 0)
4823 /* The storage zone is just after the end of the SERVICE_FAILURE_ACTIONSW structure */
4824 lpServiceFailureActionsW
->lpsaActions
= (LPSC_ACTION
)((ULONG_PTR
)(lpServiceFailureActionsW
+ 1));
4826 /* dwActionArrayLen == lpServiceFailureActionsW->cActions * sizeof(SC_ACTION) */
4827 RtlCopyMemory(lpServiceFailureActionsW
->lpsaActions
,
4828 lpServiceFailureActionsA
->lpsaActions
,
4833 /* No lpsaActions array */
4834 lpServiceFailureActionsW
->lpsaActions
= NULL
;
4836 /* The data strings are stored just after the lpsaActions array */
4837 lpStr
= (LPWSTR
)((ULONG_PTR
)(lpServiceFailureActionsW
+ 1) + dwActionArrayLen
);
4840 * Convert the data strings to UNICODE
4843 lpServiceFailureActionsW
->lpRebootMsg
= NULL
;
4844 lpServiceFailureActionsW
->lpCommand
= NULL
;
4848 /* lpRebootMsg points just after the lpsaActions array */
4849 lpServiceFailureActionsW
->lpRebootMsg
= lpStr
;
4851 MultiByteToWideChar(CP_ACP
,
4853 lpServiceFailureActionsA
->lpRebootMsg
,
4855 lpServiceFailureActionsW
->lpRebootMsg
,
4858 lpStr
+= dwRebootLen
/ sizeof(WCHAR
);
4863 /* lpRebootMsg points just after the lpRebootMsg data string */
4864 lpServiceFailureActionsW
->lpCommand
= lpStr
;
4866 MultiByteToWideChar(CP_ACP
,
4868 lpServiceFailureActionsA
->lpCommand
,
4870 lpServiceFailureActionsW
->lpCommand
,
4874 /* Set the pointers */
4875 ptr
= lpServiceFailureActionsW
;
4876 InfoW
.psfa
= lpServiceFailureActionsW
;
4880 dwRet
= RChangeServiceConfig2W(hService
, InfoW
);
4882 HeapFree(GetProcessHeap(), 0, ptr
);
4889 ScmSetFailureActions(PSERVICE_HANDLE hSvc
,
4892 LPSERVICE_FAILURE_ACTIONSW lpFailureActions
)
4894 LPSERVICE_FAILURE_ACTIONSW lpReadBuffer
= NULL
;
4895 LPSERVICE_FAILURE_ACTIONSW lpWriteBuffer
= NULL
;
4896 BOOL bIsActionRebootSet
= FALSE
;
4897 DWORD dwDesiredAccess
= SERVICE_CHANGE_CONFIG
;
4898 DWORD dwRequiredSize
= 0;
4903 /* There is nothing to be done if we have no failure actions */
4904 if (lpFailureActions
== NULL
)
4905 return ERROR_SUCCESS
;
4908 * 1- Check whether or not we can set
4909 * failure actions for this service.
4912 /* Failure actions can only be set for Win32 services, not for drivers */
4913 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
4914 return ERROR_CANNOT_DETECT_DRIVER_FAILURE
;
4917 * If the service controller handles the SC_ACTION_RESTART action,
4918 * hService must have the SERVICE_START access right.
4920 * If you specify SC_ACTION_REBOOT, the caller must have the
4921 * SE_SHUTDOWN_NAME privilege.
4923 if (lpFailureActions
->cActions
> 0 &&
4924 lpFailureActions
->lpsaActions
!= NULL
)
4926 for (i
= 0; i
< lpFailureActions
->cActions
; ++i
)
4928 if (lpFailureActions
->lpsaActions
[i
].Type
== SC_ACTION_RESTART
)
4929 dwDesiredAccess
|= SERVICE_START
;
4930 else if (lpFailureActions
->lpsaActions
[i
].Type
== SC_ACTION_REBOOT
)
4931 bIsActionRebootSet
= TRUE
;
4935 /* Re-check the access rights */
4936 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
4939 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
4940 return ERROR_ACCESS_DENIED
;
4943 /* FIXME: Check if the caller has the SE_SHUTDOWN_NAME privilege */
4944 if (bIsActionRebootSet
)
4949 * 2- Retrieve the original value of FailureActions.
4952 /* Query value length */
4953 dwError
= RegQueryValueExW(hServiceKey
,
4959 if (dwError
!= ERROR_SUCCESS
&&
4960 dwError
!= ERROR_MORE_DATA
&&
4961 dwError
!= ERROR_FILE_NOT_FOUND
)
4964 dwRequiredSize
= (dwType
== REG_BINARY
) ? max(sizeof(SERVICE_FAILURE_ACTIONSW
), dwRequiredSize
)
4965 : sizeof(SERVICE_FAILURE_ACTIONSW
);
4967 /* Initialize the read buffer */
4968 lpReadBuffer
= HeapAlloc(GetProcessHeap(),
4971 if (lpReadBuffer
== NULL
)
4972 return ERROR_NOT_ENOUGH_MEMORY
;
4974 /* Now we can fill the read buffer */
4975 if (dwError
!= ERROR_FILE_NOT_FOUND
&&
4976 dwType
== REG_BINARY
)
4978 dwError
= RegQueryValueExW(hServiceKey
,
4982 (LPBYTE
)lpReadBuffer
,
4984 if (dwError
!= ERROR_SUCCESS
&&
4985 dwError
!= ERROR_FILE_NOT_FOUND
)
4988 if (dwRequiredSize
< sizeof(SERVICE_FAILURE_ACTIONSW
))
4989 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSW
);
4994 * The value of the error doesn't really matter, the only
4995 * important thing is that it must be != ERROR_SUCCESS.
4997 dwError
= ERROR_INVALID_DATA
;
5000 if (dwError
== ERROR_SUCCESS
)
5002 lpReadBuffer
->cActions
= min(lpReadBuffer
->cActions
, (dwRequiredSize
- sizeof(SERVICE_FAILURE_ACTIONSW
)) / sizeof(SC_ACTION
));
5003 lpReadBuffer
->lpsaActions
= (lpReadBuffer
->cActions
> 0 ? (LPSC_ACTION
)(lpReadBuffer
+ 1) : NULL
);
5007 lpReadBuffer
->dwResetPeriod
= 0;
5008 lpReadBuffer
->cActions
= 0;
5009 lpReadBuffer
->lpsaActions
= NULL
;
5012 lpReadBuffer
->lpRebootMsg
= NULL
;
5013 lpReadBuffer
->lpCommand
= NULL
;
5016 * 3- Initialize the new value to set.
5019 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSW
);
5021 if (lpFailureActions
->lpsaActions
== NULL
)
5024 * lpFailureActions->cActions is ignored.
5025 * Therefore we use the original values
5026 * of cActions and lpsaActions.
5028 dwRequiredSize
+= lpReadBuffer
->cActions
* sizeof(SC_ACTION
);
5033 * The reset period and array of failure actions
5034 * are deleted if lpFailureActions->cActions == 0 .
5036 dwRequiredSize
+= lpFailureActions
->cActions
* sizeof(SC_ACTION
);
5039 lpWriteBuffer
= HeapAlloc(GetProcessHeap(),
5042 if (lpWriteBuffer
== NULL
)
5044 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
5048 /* Clean the pointers as they have no meaning when the structure is stored in the registry */
5049 lpWriteBuffer
->lpRebootMsg
= NULL
;
5050 lpWriteBuffer
->lpCommand
= NULL
;
5051 lpWriteBuffer
->lpsaActions
= NULL
;
5053 /* Set the members */
5054 if (lpFailureActions
->lpsaActions
== NULL
)
5057 * lpFailureActions->dwResetPeriod and lpFailureActions->cActions are ignored.
5058 * Therefore we use the original values of dwResetPeriod, cActions and lpsaActions.
5060 lpWriteBuffer
->dwResetPeriod
= lpReadBuffer
->dwResetPeriod
;
5061 lpWriteBuffer
->cActions
= lpReadBuffer
->cActions
;
5063 if (lpReadBuffer
->lpsaActions
!= NULL
)
5065 memmove(lpWriteBuffer
+ 1,
5066 lpReadBuffer
->lpsaActions
,
5067 lpReadBuffer
->cActions
* sizeof(SC_ACTION
));
5072 if (lpFailureActions
->cActions
> 0)
5074 lpWriteBuffer
->dwResetPeriod
= lpFailureActions
->dwResetPeriod
;
5075 lpWriteBuffer
->cActions
= lpFailureActions
->cActions
;
5077 memmove(lpWriteBuffer
+ 1,
5078 lpFailureActions
->lpsaActions
,
5079 lpFailureActions
->cActions
* sizeof(SC_ACTION
));
5083 /* The reset period and array of failure actions are deleted */
5084 lpWriteBuffer
->dwResetPeriod
= 0;
5085 lpWriteBuffer
->cActions
= 0;
5089 /* Save the new failure actions into the registry */
5090 dwError
= RegSetValueExW(hServiceKey
,
5094 (LPBYTE
)lpWriteBuffer
,
5097 /* We modify the strings only in case of success.*/
5098 if (dwError
== ERROR_SUCCESS
)
5100 /* Modify the Reboot Message value, if specified */
5101 if (lpFailureActions
->lpRebootMsg
!= NULL
)
5103 /* If the Reboot Message is "" then we delete it */
5104 if (*lpFailureActions
->lpRebootMsg
== 0)
5106 DPRINT("Delete Reboot Message value\n");
5107 RegDeleteValueW(hServiceKey
, L
"RebootMessage");
5111 DPRINT("Setting Reboot Message value %S\n", lpFailureActions
->lpRebootMsg
);
5112 RegSetValueExW(hServiceKey
,
5116 (LPBYTE
)lpFailureActions
->lpRebootMsg
,
5117 (DWORD
)((wcslen(lpFailureActions
->lpRebootMsg
) + 1) * sizeof(WCHAR
)));
5121 /* Modify the Failure Command value, if specified */
5122 if (lpFailureActions
->lpCommand
!= NULL
)
5124 /* If the FailureCommand string is an empty string, delete the value */
5125 if (*lpFailureActions
->lpCommand
== 0)
5127 DPRINT("Delete Failure Command value\n");
5128 RegDeleteValueW(hServiceKey
, L
"FailureCommand");
5132 DPRINT("Setting Failure Command value %S\n", lpFailureActions
->lpCommand
);
5133 RegSetValueExW(hServiceKey
,
5137 (LPBYTE
)lpFailureActions
->lpCommand
,
5138 (DWORD
)((wcslen(lpFailureActions
->lpCommand
) + 1) * sizeof(WCHAR
)));
5144 if (lpWriteBuffer
!= NULL
)
5145 HeapFree(GetProcessHeap(), 0, lpWriteBuffer
);
5147 if (lpReadBuffer
!= NULL
)
5148 HeapFree(GetProcessHeap(), 0, lpReadBuffer
);
5155 DWORD
RChangeServiceConfig2W(
5156 SC_RPC_HANDLE hService
,
5157 SC_RPC_CONFIG_INFOW Info
)
5159 DWORD dwError
= ERROR_SUCCESS
;
5160 PSERVICE_HANDLE hSvc
;
5161 PSERVICE lpService
= NULL
;
5162 HKEY hServiceKey
= NULL
;
5164 DPRINT("RChangeServiceConfig2W() called\n");
5165 DPRINT("dwInfoLevel = %lu\n", Info
.dwInfoLevel
);
5168 return ERROR_SHUTDOWN_IN_PROGRESS
;
5170 hSvc
= ScmGetServiceFromHandle(hService
);
5173 DPRINT1("Invalid service handle!\n");
5174 return ERROR_INVALID_HANDLE
;
5177 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5178 SERVICE_CHANGE_CONFIG
))
5180 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5181 return ERROR_ACCESS_DENIED
;
5184 lpService
= hSvc
->ServiceEntry
;
5185 if (lpService
== NULL
)
5187 DPRINT("lpService == NULL!\n");
5188 return ERROR_INVALID_HANDLE
;
5191 /* Lock the service database exclusively */
5192 ScmLockDatabaseExclusive();
5194 if (lpService
->bDeleted
)
5196 DPRINT("The service has already been marked for delete!\n");
5197 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
5201 /* Open the service key */
5202 dwError
= ScmOpenServiceKey(lpService
->szServiceName
,
5203 KEY_READ
| KEY_SET_VALUE
,
5205 if (dwError
!= ERROR_SUCCESS
)
5208 if (Info
.dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
5210 LPSERVICE_DESCRIPTIONW lpServiceDescription
= (LPSERVICE_DESCRIPTIONW
)Info
.psd
;
5212 /* Modify the service description, if specified */
5213 if (lpServiceDescription
!= NULL
&&
5214 lpServiceDescription
->lpDescription
!= NULL
)
5216 /* If the description is "" then we delete it */
5217 if (*lpServiceDescription
->lpDescription
== 0)
5219 DPRINT("Delete service description\n");
5220 dwError
= RegDeleteValueW(hServiceKey
, L
"Description");
5222 if (dwError
== ERROR_FILE_NOT_FOUND
)
5223 dwError
= ERROR_SUCCESS
;
5227 DPRINT("Setting service description value %S\n", lpServiceDescription
->lpDescription
);
5228 dwError
= RegSetValueExW(hServiceKey
,
5232 (LPBYTE
)lpServiceDescription
->lpDescription
,
5233 (DWORD
)((wcslen(lpServiceDescription
->lpDescription
) + 1) * sizeof(WCHAR
)));
5238 dwError
= ERROR_SUCCESS
;
5241 else if (Info
.dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5243 dwError
= ScmSetFailureActions(hSvc
,
5246 (LPSERVICE_FAILURE_ACTIONSW
)Info
.psfa
);
5250 if (hServiceKey
!= NULL
)
5251 RegCloseKey(hServiceKey
);
5253 /* Unlock the service database */
5254 ScmUnlockDatabase();
5256 DPRINT("RChangeServiceConfig2W() done (Error %lu)\n", dwError
);
5263 DWORD
RQueryServiceConfig2A(
5264 SC_RPC_HANDLE hService
,
5268 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
5270 DWORD dwError
= ERROR_SUCCESS
;
5271 PSERVICE_HANDLE hSvc
;
5272 PSERVICE lpService
= NULL
;
5273 HKEY hServiceKey
= NULL
;
5274 DWORD dwRequiredSize
= 0;
5276 LPWSTR lpDescriptionW
= NULL
;
5277 LPWSTR lpRebootMessageW
= NULL
;
5278 LPWSTR lpFailureCommandW
= NULL
;
5280 DPRINT("RQueryServiceConfig2A() called hService %p dwInfoLevel %u, lpBuffer %p cbBufSize %u pcbBytesNeeded %p\n",
5281 hService
, dwInfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
5284 return ERROR_INVALID_ADDRESS
;
5287 return ERROR_SHUTDOWN_IN_PROGRESS
;
5289 hSvc
= ScmGetServiceFromHandle(hService
);
5292 DPRINT1("Invalid service handle!\n");
5293 return ERROR_INVALID_HANDLE
;
5296 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5297 SERVICE_QUERY_CONFIG
))
5299 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5300 return ERROR_ACCESS_DENIED
;
5303 lpService
= hSvc
->ServiceEntry
;
5304 if (lpService
== NULL
)
5306 DPRINT("lpService == NULL!\n");
5307 return ERROR_INVALID_HANDLE
;
5310 /* Lock the service database shared */
5311 ScmLockDatabaseShared();
5313 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
5316 if (dwError
!= ERROR_SUCCESS
)
5319 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
5321 LPSERVICE_DESCRIPTIONA lpServiceDescription
= (LPSERVICE_DESCRIPTIONA
)lpBuffer
;
5324 dwError
= ScmReadString(hServiceKey
,
5327 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5330 *pcbBytesNeeded
= sizeof(SERVICE_DESCRIPTIONA
);
5331 if (dwError
== ERROR_SUCCESS
)
5332 *pcbBytesNeeded
+= (DWORD
)((wcslen(lpDescriptionW
) + 1) * sizeof(WCHAR
));
5334 if (cbBufSize
< *pcbBytesNeeded
)
5336 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5340 if (dwError
== ERROR_SUCCESS
)
5342 lpStr
= (LPSTR
)(lpServiceDescription
+ 1);
5344 WideCharToMultiByte(CP_ACP
,
5349 (int)wcslen(lpDescriptionW
),
5352 lpServiceDescription
->lpDescription
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceDescription
);
5356 lpServiceDescription
->lpDescription
= NULL
;
5357 dwError
= ERROR_SUCCESS
;
5360 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5362 LPSERVICE_FAILURE_ACTIONSA lpFailureActions
= (LPSERVICE_FAILURE_ACTIONSA
)lpBuffer
;
5365 /* Query value length */
5366 dwError
= RegQueryValueExW(hServiceKey
,
5372 if (dwError
!= ERROR_SUCCESS
&&
5373 dwError
!= ERROR_MORE_DATA
&&
5374 dwError
!= ERROR_FILE_NOT_FOUND
)
5377 dwRequiredSize
= (dwType
== REG_BINARY
) ? max(sizeof(SERVICE_FAILURE_ACTIONSA
), dwRequiredSize
)
5378 : sizeof(SERVICE_FAILURE_ACTIONSA
);
5380 /* Get the strings */
5381 ScmReadString(hServiceKey
,
5383 &lpFailureCommandW
);
5385 ScmReadString(hServiceKey
,
5389 if (lpRebootMessageW
)
5390 dwRequiredSize
+= (DWORD
)((wcslen(lpRebootMessageW
) + 1) * sizeof(WCHAR
));
5392 if (lpFailureCommandW
)
5393 dwRequiredSize
+= (DWORD
)((wcslen(lpFailureCommandW
) + 1) * sizeof(WCHAR
));
5395 if (cbBufSize
< dwRequiredSize
)
5397 *pcbBytesNeeded
= dwRequiredSize
;
5398 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5402 /* Now we can fill the buffer */
5403 if (dwError
!= ERROR_FILE_NOT_FOUND
&& dwType
== REG_BINARY
)
5405 dwError
= RegQueryValueExW(hServiceKey
,
5409 (LPBYTE
)lpFailureActions
,
5411 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5414 if (dwRequiredSize
< sizeof(SERVICE_FAILURE_ACTIONSA
))
5415 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSA
);
5420 * The value of the error doesn't really matter, the only
5421 * important thing is that it must be != ERROR_SUCCESS .
5423 dwError
= ERROR_INVALID_DATA
;
5426 if (dwError
== ERROR_SUCCESS
)
5428 lpFailureActions
->cActions
= min(lpFailureActions
->cActions
, (dwRequiredSize
- sizeof(SERVICE_FAILURE_ACTIONSA
)) / sizeof(SC_ACTION
));
5430 /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */
5431 lpFailureActions
->lpsaActions
= (lpFailureActions
->cActions
> 0 ? (LPSC_ACTION
)(ULONG_PTR
)sizeof(SERVICE_FAILURE_ACTIONSA
) : NULL
);
5433 lpStr
= (LPSTR
)((ULONG_PTR
)(lpFailureActions
+ 1) + lpFailureActions
->cActions
* sizeof(SC_ACTION
));
5437 lpFailureActions
->dwResetPeriod
= 0;
5438 lpFailureActions
->cActions
= 0;
5439 lpFailureActions
->lpsaActions
= NULL
;
5440 lpStr
= (LPSTR
)(lpFailureActions
+ 1);
5443 lpFailureActions
->lpRebootMsg
= NULL
;
5444 lpFailureActions
->lpCommand
= NULL
;
5446 if (lpRebootMessageW
)
5448 WideCharToMultiByte(CP_ACP
,
5453 (int)wcslen(lpRebootMessageW
),
5456 lpFailureActions
->lpRebootMsg
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5457 lpStr
+= strlen(lpStr
) + 1;
5460 if (lpFailureCommandW
)
5462 WideCharToMultiByte(CP_ACP
,
5467 (int)wcslen(lpFailureCommandW
),
5470 lpFailureActions
->lpCommand
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5471 /* lpStr += strlen(lpStr) + 1; */
5474 dwError
= ERROR_SUCCESS
;
5478 /* Unlock the service database */
5479 ScmUnlockDatabase();
5481 if (lpDescriptionW
!= NULL
)
5482 HeapFree(GetProcessHeap(), 0, lpDescriptionW
);
5484 if (lpRebootMessageW
!= NULL
)
5485 HeapFree(GetProcessHeap(), 0, lpRebootMessageW
);
5487 if (lpFailureCommandW
!= NULL
)
5488 HeapFree(GetProcessHeap(), 0, lpFailureCommandW
);
5490 if (hServiceKey
!= NULL
)
5491 RegCloseKey(hServiceKey
);
5493 DPRINT("RQueryServiceConfig2A() done (Error %lu)\n", dwError
);
5500 DWORD
RQueryServiceConfig2W(
5501 SC_RPC_HANDLE hService
,
5505 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
5507 DWORD dwError
= ERROR_SUCCESS
;
5508 PSERVICE_HANDLE hSvc
;
5509 PSERVICE lpService
= NULL
;
5510 HKEY hServiceKey
= NULL
;
5511 DWORD dwRequiredSize
= 0;
5513 LPWSTR lpDescription
= NULL
;
5514 LPWSTR lpRebootMessage
= NULL
;
5515 LPWSTR lpFailureCommand
= NULL
;
5517 DPRINT("RQueryServiceConfig2W() called\n");
5520 return ERROR_INVALID_ADDRESS
;
5523 return ERROR_SHUTDOWN_IN_PROGRESS
;
5525 hSvc
= ScmGetServiceFromHandle(hService
);
5528 DPRINT1("Invalid service handle!\n");
5529 return ERROR_INVALID_HANDLE
;
5532 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5533 SERVICE_QUERY_CONFIG
))
5535 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5536 return ERROR_ACCESS_DENIED
;
5539 lpService
= hSvc
->ServiceEntry
;
5540 if (lpService
== NULL
)
5542 DPRINT("lpService == NULL!\n");
5543 return ERROR_INVALID_HANDLE
;
5546 /* Lock the service database shared */
5547 ScmLockDatabaseShared();
5549 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
5552 if (dwError
!= ERROR_SUCCESS
)
5555 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
5557 LPSERVICE_DESCRIPTIONW lpServiceDescription
= (LPSERVICE_DESCRIPTIONW
)lpBuffer
;
5560 dwError
= ScmReadString(hServiceKey
,
5563 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5566 *pcbBytesNeeded
= sizeof(SERVICE_DESCRIPTIONW
);
5567 if (dwError
== ERROR_SUCCESS
)
5568 *pcbBytesNeeded
+= (DWORD
)((wcslen(lpDescription
) + 1) * sizeof(WCHAR
));
5570 if (cbBufSize
< *pcbBytesNeeded
)
5572 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5576 if (dwError
== ERROR_SUCCESS
)
5578 lpStr
= (LPWSTR
)(lpServiceDescription
+ 1);
5579 wcscpy(lpStr
, lpDescription
);
5580 lpServiceDescription
->lpDescription
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceDescription
);
5584 lpServiceDescription
->lpDescription
= NULL
;
5585 dwError
= ERROR_SUCCESS
;
5588 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5590 LPSERVICE_FAILURE_ACTIONSW lpFailureActions
= (LPSERVICE_FAILURE_ACTIONSW
)lpBuffer
;
5591 LPWSTR lpStr
= NULL
;
5593 /* Query value length */
5594 dwError
= RegQueryValueExW(hServiceKey
,
5600 if (dwError
!= ERROR_SUCCESS
&&
5601 dwError
!= ERROR_MORE_DATA
&&
5602 dwError
!= ERROR_FILE_NOT_FOUND
)
5605 dwRequiredSize
= (dwType
== REG_BINARY
) ? max(sizeof(SERVICE_FAILURE_ACTIONSW
), dwRequiredSize
)
5606 : sizeof(SERVICE_FAILURE_ACTIONSW
);
5608 /* Get the strings */
5609 ScmReadString(hServiceKey
,
5613 ScmReadString(hServiceKey
,
5617 if (lpRebootMessage
)
5618 dwRequiredSize
+= (DWORD
)((wcslen(lpRebootMessage
) + 1) * sizeof(WCHAR
));
5620 if (lpFailureCommand
)
5621 dwRequiredSize
+= (DWORD
)((wcslen(lpFailureCommand
) + 1) * sizeof(WCHAR
));
5623 if (cbBufSize
< dwRequiredSize
)
5625 *pcbBytesNeeded
= dwRequiredSize
;
5626 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5630 /* Now we can fill the buffer */
5631 if (dwError
!= ERROR_FILE_NOT_FOUND
&& dwType
== REG_BINARY
)
5633 dwError
= RegQueryValueExW(hServiceKey
,
5637 (LPBYTE
)lpFailureActions
,
5639 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5642 if (dwRequiredSize
< sizeof(SERVICE_FAILURE_ACTIONSW
))
5643 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSW
);
5648 * The value of the error doesn't really matter, the only
5649 * important thing is that it must be != ERROR_SUCCESS .
5651 dwError
= ERROR_INVALID_DATA
;
5654 if (dwError
== ERROR_SUCCESS
)
5656 lpFailureActions
->cActions
= min(lpFailureActions
->cActions
, (dwRequiredSize
- sizeof(SERVICE_FAILURE_ACTIONSW
)) / sizeof(SC_ACTION
));
5658 /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */
5659 lpFailureActions
->lpsaActions
= (lpFailureActions
->cActions
> 0 ? (LPSC_ACTION
)(ULONG_PTR
)sizeof(SERVICE_FAILURE_ACTIONSW
) : NULL
);
5661 lpStr
= (LPWSTR
)((ULONG_PTR
)(lpFailureActions
+ 1) + lpFailureActions
->cActions
* sizeof(SC_ACTION
));
5665 lpFailureActions
->dwResetPeriod
= 0;
5666 lpFailureActions
->cActions
= 0;
5667 lpFailureActions
->lpsaActions
= NULL
;
5668 lpStr
= (LPWSTR
)(lpFailureActions
+ 1);
5671 lpFailureActions
->lpRebootMsg
= NULL
;
5672 lpFailureActions
->lpCommand
= NULL
;
5674 if (lpRebootMessage
)
5676 wcscpy(lpStr
, lpRebootMessage
);
5677 lpFailureActions
->lpRebootMsg
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5678 lpStr
+= wcslen(lpStr
) + 1;
5681 if (lpFailureCommand
)
5683 wcscpy(lpStr
, lpFailureCommand
);
5684 lpFailureActions
->lpCommand
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5685 /* lpStr += wcslen(lpStr) + 1; */
5688 dwError
= ERROR_SUCCESS
;
5692 /* Unlock the service database */
5693 ScmUnlockDatabase();
5695 if (lpDescription
!= NULL
)
5696 HeapFree(GetProcessHeap(), 0, lpDescription
);
5698 if (lpRebootMessage
!= NULL
)
5699 HeapFree(GetProcessHeap(), 0, lpRebootMessage
);
5701 if (lpFailureCommand
!= NULL
)
5702 HeapFree(GetProcessHeap(), 0, lpFailureCommand
);
5704 if (hServiceKey
!= NULL
)
5705 RegCloseKey(hServiceKey
);
5707 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError
);
5714 DWORD
RQueryServiceStatusEx(
5715 SC_RPC_HANDLE hService
,
5716 SC_STATUS_TYPE InfoLevel
,
5719 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
5721 LPSERVICE_STATUS_PROCESS lpStatus
;
5722 PSERVICE_HANDLE hSvc
;
5725 DPRINT("RQueryServiceStatusEx() called\n");
5728 return ERROR_SHUTDOWN_IN_PROGRESS
;
5730 if (InfoLevel
!= SC_STATUS_PROCESS_INFO
)
5731 return ERROR_INVALID_LEVEL
;
5733 *pcbBytesNeeded
= sizeof(SERVICE_STATUS_PROCESS
);
5735 if (cbBufSize
< sizeof(SERVICE_STATUS_PROCESS
))
5736 return ERROR_INSUFFICIENT_BUFFER
;
5738 hSvc
= ScmGetServiceFromHandle(hService
);
5741 DPRINT1("Invalid service handle!\n");
5742 return ERROR_INVALID_HANDLE
;
5745 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5746 SERVICE_QUERY_STATUS
))
5748 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5749 return ERROR_ACCESS_DENIED
;
5752 lpService
= hSvc
->ServiceEntry
;
5753 if (lpService
== NULL
)
5755 DPRINT("lpService == NULL!\n");
5756 return ERROR_INVALID_HANDLE
;
5759 /* Lock the service database shared */
5760 ScmLockDatabaseShared();
5762 lpStatus
= (LPSERVICE_STATUS_PROCESS
)lpBuffer
;
5764 /* Return service status information */
5765 RtlCopyMemory(lpStatus
,
5767 sizeof(SERVICE_STATUS
));
5769 lpStatus
->dwProcessId
= (lpService
->lpImage
!= NULL
) ? lpService
->lpImage
->dwProcessId
: 0; /* FIXME */
5770 lpStatus
->dwServiceFlags
= 0; /* FIXME */
5772 /* Unlock the service database */
5773 ScmUnlockDatabase();
5775 return ERROR_SUCCESS
;
5780 DWORD
REnumServicesStatusExA(
5781 SC_RPC_HANDLE hSCManager
,
5782 SC_ENUM_TYPE InfoLevel
,
5783 DWORD dwServiceType
,
5784 DWORD dwServiceState
,
5787 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
5788 LPBOUNDED_DWORD_256K lpServicesReturned
,
5789 LPBOUNDED_DWORD_256K lpResumeIndex
,
5790 LPCSTR pszGroupName
)
5792 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrW
= NULL
;
5793 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrIncrW
;
5794 LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtrA
= NULL
;
5795 LPWSTR lpStringPtrW
;
5797 LPWSTR pszGroupNameW
= NULL
;
5799 DWORD dwServiceCount
;
5801 DPRINT("REnumServicesStatusExA() called\n");
5803 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
5805 return ERROR_INVALID_ADDRESS
;
5810 pszGroupNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, (strlen(pszGroupName
) + 1) * sizeof(WCHAR
));
5813 DPRINT("Failed to allocate buffer!\n");
5814 return ERROR_NOT_ENOUGH_MEMORY
;
5817 MultiByteToWideChar(CP_ACP
,
5822 (int)(strlen(pszGroupName
) + 1));
5825 if ((cbBufSize
> 0) && (lpBuffer
))
5827 lpStatusPtrW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, cbBufSize
);
5830 DPRINT("Failed to allocate buffer!\n");
5831 return ERROR_NOT_ENOUGH_MEMORY
;
5835 dwError
= REnumServicesStatusExW(hSCManager
,
5839 (LPBYTE
)lpStatusPtrW
,
5846 /* if no services were returned then we are Done */
5847 if (*lpServicesReturned
== 0)
5850 lpStatusPtrIncrW
= lpStatusPtrW
;
5851 lpStatusPtrA
= (LPENUM_SERVICE_STATUS_PROCESSA
)lpBuffer
;
5852 lpStringPtrA
= (LPSTR
)((ULONG_PTR
)lpBuffer
+
5853 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUS_PROCESSA
));
5854 lpStringPtrW
= (LPWSTR
)((ULONG_PTR
)lpStatusPtrW
+
5855 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUS_PROCESSW
));
5857 for (dwServiceCount
= 0; dwServiceCount
< *lpServicesReturned
; dwServiceCount
++)
5859 /* Copy the service name */
5860 WideCharToMultiByte(CP_ACP
,
5865 (int)wcslen(lpStringPtrW
),
5869 lpStatusPtrA
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
5870 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
5871 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
5873 /* Copy the display name */
5874 WideCharToMultiByte(CP_ACP
,
5879 (int)wcslen(lpStringPtrW
),
5883 lpStatusPtrA
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
5884 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
5885 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
5887 /* Copy the status information */
5888 memcpy(&lpStatusPtrA
->ServiceStatusProcess
,
5889 &lpStatusPtrIncrW
->ServiceStatusProcess
,
5890 sizeof(SERVICE_STATUS
));
5892 lpStatusPtrA
->ServiceStatusProcess
.dwProcessId
= lpStatusPtrIncrW
->ServiceStatusProcess
.dwProcessId
; /* FIXME */
5893 lpStatusPtrA
->ServiceStatusProcess
.dwServiceFlags
= 0; /* FIXME */
5901 HeapFree(GetProcessHeap(), 0, pszGroupNameW
);
5904 HeapFree(GetProcessHeap(), 0, lpStatusPtrW
);
5906 DPRINT("REnumServicesStatusExA() done (Error %lu)\n", dwError
);
5913 DWORD
REnumServicesStatusExW(
5914 SC_RPC_HANDLE hSCManager
,
5915 SC_ENUM_TYPE InfoLevel
,
5916 DWORD dwServiceType
,
5917 DWORD dwServiceState
,
5920 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
5921 LPBOUNDED_DWORD_256K lpServicesReturned
,
5922 LPBOUNDED_DWORD_256K lpResumeIndex
,
5923 LPCWSTR pszGroupName
)
5925 PMANAGER_HANDLE hManager
;
5927 DWORD dwError
= ERROR_SUCCESS
;
5928 PLIST_ENTRY ServiceEntry
;
5929 PSERVICE CurrentService
;
5931 DWORD dwRequiredSize
;
5932 DWORD dwServiceCount
;
5934 DWORD dwLastResumeCount
= 0;
5935 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr
;
5938 DPRINT("REnumServicesStatusExW() called\n");
5941 return ERROR_SHUTDOWN_IN_PROGRESS
;
5943 if (InfoLevel
!= SC_ENUM_PROCESS_INFO
)
5944 return ERROR_INVALID_LEVEL
;
5946 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
5947 if (hManager
== NULL
)
5949 DPRINT1("Invalid service manager handle!\n");
5950 return ERROR_INVALID_HANDLE
;
5953 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
5955 return ERROR_INVALID_ADDRESS
;
5958 *pcbBytesNeeded
= 0;
5959 *lpServicesReturned
= 0;
5961 if ((dwServiceType
== 0) ||
5962 ((dwServiceType
& ~SERVICE_TYPE_ALL
) != 0))
5964 DPRINT("Not a valid Service Type!\n");
5965 return ERROR_INVALID_PARAMETER
;
5968 if ((dwServiceState
== 0) ||
5969 ((dwServiceState
& ~SERVICE_STATE_ALL
) != 0))
5971 DPRINT("Not a valid Service State!\n");
5972 return ERROR_INVALID_PARAMETER
;
5975 /* Check access rights */
5976 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
5977 SC_MANAGER_ENUMERATE_SERVICE
))
5979 DPRINT("Insufficient access rights! 0x%lx\n",
5980 hManager
->Handle
.DesiredAccess
);
5981 return ERROR_ACCESS_DENIED
;
5985 dwLastResumeCount
= *lpResumeIndex
;
5987 /* Lock the service database shared */
5988 ScmLockDatabaseShared();
5990 lpService
= ScmGetServiceEntryByResumeCount(dwLastResumeCount
);
5991 if (lpService
== NULL
)
5993 dwError
= ERROR_SUCCESS
;
6000 for (ServiceEntry
= &lpService
->ServiceListEntry
;
6001 ServiceEntry
!= &ServiceListHead
;
6002 ServiceEntry
= ServiceEntry
->Flink
)
6004 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
6008 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
6011 dwState
= SERVICE_ACTIVE
;
6012 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
6013 dwState
= SERVICE_INACTIVE
;
6015 if ((dwState
& dwServiceState
) == 0)
6020 if (*pszGroupName
== 0)
6022 if (CurrentService
->lpGroup
!= NULL
)
6027 if ((CurrentService
->lpGroup
== NULL
) ||
6028 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
6033 dwSize
= sizeof(ENUM_SERVICE_STATUS_PROCESSW
) +
6034 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
6035 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
6037 if (dwRequiredSize
+ dwSize
<= cbBufSize
)
6039 DPRINT("Service name: %S fit\n", CurrentService
->lpServiceName
);
6040 dwRequiredSize
+= dwSize
;
6042 dwLastResumeCount
= CurrentService
->dwResumeCount
;
6046 DPRINT("Service name: %S no fit\n", CurrentService
->lpServiceName
);
6052 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize
);
6053 DPRINT("dwServiceCount: %lu\n", dwServiceCount
);
6056 ServiceEntry
!= &ServiceListHead
;
6057 ServiceEntry
= ServiceEntry
->Flink
)
6059 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
6063 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
6066 dwState
= SERVICE_ACTIVE
;
6067 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
6068 dwState
= SERVICE_INACTIVE
;
6070 if ((dwState
& dwServiceState
) == 0)
6075 if (*pszGroupName
== 0)
6077 if (CurrentService
->lpGroup
!= NULL
)
6082 if ((CurrentService
->lpGroup
== NULL
) ||
6083 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
6088 dwRequiredSize
+= (sizeof(ENUM_SERVICE_STATUS_PROCESSW
) +
6089 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
6090 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
)));
6092 dwError
= ERROR_MORE_DATA
;
6095 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize
);
6098 *lpResumeIndex
= dwLastResumeCount
;
6100 *lpServicesReturned
= dwServiceCount
;
6101 *pcbBytesNeeded
= dwRequiredSize
;
6103 /* If there was no services that matched */
6104 if ((!dwServiceCount
) && (dwError
!= ERROR_MORE_DATA
))
6106 dwError
= ERROR_SERVICE_DOES_NOT_EXIST
;
6110 lpStatusPtr
= (LPENUM_SERVICE_STATUS_PROCESSW
)lpBuffer
;
6111 lpStringPtr
= (LPWSTR
)((ULONG_PTR
)lpBuffer
+
6112 dwServiceCount
* sizeof(ENUM_SERVICE_STATUS_PROCESSW
));
6115 for (ServiceEntry
= &lpService
->ServiceListEntry
;
6116 ServiceEntry
!= &ServiceListHead
;
6117 ServiceEntry
= ServiceEntry
->Flink
)
6119 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
6123 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
6126 dwState
= SERVICE_ACTIVE
;
6127 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
6128 dwState
= SERVICE_INACTIVE
;
6130 if ((dwState
& dwServiceState
) == 0)
6135 if (*pszGroupName
== 0)
6137 if (CurrentService
->lpGroup
!= NULL
)
6142 if ((CurrentService
->lpGroup
== NULL
) ||
6143 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
6148 dwSize
= sizeof(ENUM_SERVICE_STATUS_PROCESSW
) +
6149 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
6150 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
6152 if (dwRequiredSize
+ dwSize
<= cbBufSize
)
6154 /* Copy the service name */
6156 CurrentService
->lpServiceName
);
6157 lpStatusPtr
->lpServiceName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
6158 lpStringPtr
+= (wcslen(CurrentService
->lpServiceName
) + 1);
6160 /* Copy the display name */
6162 CurrentService
->lpDisplayName
);
6163 lpStatusPtr
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
6164 lpStringPtr
+= (wcslen(CurrentService
->lpDisplayName
) + 1);
6166 /* Copy the status information */
6167 memcpy(&lpStatusPtr
->ServiceStatusProcess
,
6168 &CurrentService
->Status
,
6169 sizeof(SERVICE_STATUS
));
6170 lpStatusPtr
->ServiceStatusProcess
.dwProcessId
=
6171 (CurrentService
->lpImage
!= NULL
) ? CurrentService
->lpImage
->dwProcessId
: 0; /* FIXME */
6172 lpStatusPtr
->ServiceStatusProcess
.dwServiceFlags
= 0; /* FIXME */
6175 dwRequiredSize
+= dwSize
;
6185 *pcbBytesNeeded
= 0;
6191 /* Unlock the service database */
6192 ScmUnlockDatabase();
6194 DPRINT("REnumServicesStatusExW() done (Error %lu)\n", dwError
);
6201 DWORD
RSendTSMessage(
6202 handle_t BindingHandle
) /* FIXME */
6205 return ERROR_CALL_NOT_IMPLEMENTED
;
6210 DWORD
RCreateServiceWOW64A(
6211 handle_t BindingHandle
,
6212 LPSTR lpServiceName
,
6213 LPSTR lpDisplayName
,
6214 DWORD dwDesiredAccess
,
6215 DWORD dwServiceType
,
6217 DWORD dwErrorControl
,
6218 LPSTR lpBinaryPathName
,
6219 LPSTR lpLoadOrderGroup
,
6221 LPBYTE lpDependencies
,
6223 LPSTR lpServiceStartName
,
6226 LPSC_RPC_HANDLE lpServiceHandle
)
6229 return ERROR_CALL_NOT_IMPLEMENTED
;
6234 DWORD
RCreateServiceWOW64W(
6235 handle_t BindingHandle
,
6236 LPWSTR lpServiceName
,
6237 LPWSTR lpDisplayName
,
6238 DWORD dwDesiredAccess
,
6239 DWORD dwServiceType
,
6241 DWORD dwErrorControl
,
6242 LPWSTR lpBinaryPathName
,
6243 LPWSTR lpLoadOrderGroup
,
6245 LPBYTE lpDependencies
,
6247 LPWSTR lpServiceStartName
,
6250 LPSC_RPC_HANDLE lpServiceHandle
)
6253 return ERROR_CALL_NOT_IMPLEMENTED
;
6258 DWORD
RQueryServiceTagInfo(
6259 handle_t BindingHandle
) /* FIXME */
6262 return ERROR_CALL_NOT_IMPLEMENTED
;
6267 DWORD
RNotifyServiceStatusChange(
6268 SC_RPC_HANDLE hService
,
6269 SC_RPC_NOTIFY_PARAMS NotifyParams
,
6270 GUID
*pClientProcessGuid
,
6271 GUID
*pSCMProcessGuid
,
6272 PBOOL pfCreateRemoteQueue
,
6273 LPSC_NOTIFY_RPC_HANDLE phNotify
)
6276 return ERROR_CALL_NOT_IMPLEMENTED
;
6281 DWORD
RGetNotifyResults(
6282 SC_NOTIFY_RPC_HANDLE hNotify
,
6283 PSC_RPC_NOTIFY_PARAMS_LIST
*ppNotifyParams
)
6286 return ERROR_CALL_NOT_IMPLEMENTED
;
6291 DWORD
RCloseNotifyHandle(
6292 LPSC_NOTIFY_RPC_HANDLE phNotify
,
6296 return ERROR_CALL_NOT_IMPLEMENTED
;
6301 DWORD
RControlServiceExA(
6302 SC_RPC_HANDLE hService
,
6307 return ERROR_CALL_NOT_IMPLEMENTED
;
6312 DWORD
RControlServiceExW(
6313 SC_RPC_HANDLE hService
,
6318 return ERROR_CALL_NOT_IMPLEMENTED
;
6323 DWORD
RSendPnPMessage(
6324 handle_t BindingHandle
) /* FIXME */
6327 return ERROR_CALL_NOT_IMPLEMENTED
;
6332 DWORD
RValidatePnPService(
6333 handle_t BindingHandle
) /* FIXME */
6336 return ERROR_CALL_NOT_IMPLEMENTED
;
6341 DWORD
ROpenServiceStatusHandle(
6342 handle_t BindingHandle
) /* FIXME */
6345 return ERROR_CALL_NOT_IMPLEMENTED
;
6351 handle_t BindingHandle
) /* FIXME */
6354 return ERROR_CALL_NOT_IMPLEMENTED
;
6358 void __RPC_FAR
* __RPC_USER
midl_user_allocate(SIZE_T len
)
6360 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
);
6364 void __RPC_USER
midl_user_free(void __RPC_FAR
* ptr
)
6366 HeapFree(GetProcessHeap(), 0, ptr
);
6370 void __RPC_USER
SC_RPC_HANDLE_rundown(SC_RPC_HANDLE hSCObject
)
6372 /* Close the handle */
6373 RCloseServiceHandle(&hSCObject
);
6377 void __RPC_USER
SC_RPC_LOCK_rundown(SC_RPC_LOCK Lock
)
6379 /* Unlock the database */
6380 RUnlockServiceDatabase(&Lock
);
6384 void __RPC_USER
SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE hNotify
)