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
;
1088 LPCWSTR lpErrorStrings
[2];
1090 DPRINT("RControlService() called\n");
1093 return ERROR_SHUTDOWN_IN_PROGRESS
;
1095 /* Check the service handle */
1096 hSvc
= ScmGetServiceFromHandle(hService
);
1099 DPRINT1("Invalid service handle!\n");
1100 return ERROR_INVALID_HANDLE
;
1103 /* Check the service entry point */
1104 lpService
= hSvc
->ServiceEntry
;
1105 if (lpService
== NULL
)
1107 DPRINT1("lpService == NULL!\n");
1108 return ERROR_INVALID_HANDLE
;
1111 /* Check access rights */
1114 case SERVICE_CONTROL_STOP
:
1115 DesiredAccess
= SERVICE_STOP
;
1118 case SERVICE_CONTROL_PAUSE
:
1119 case SERVICE_CONTROL_CONTINUE
:
1120 DesiredAccess
= SERVICE_PAUSE_CONTINUE
;
1123 case SERVICE_CONTROL_INTERROGATE
:
1124 DesiredAccess
= SERVICE_INTERROGATE
;
1128 if (dwControl
>= 128 && dwControl
<= 255)
1129 DesiredAccess
= SERVICE_USER_DEFINED_CONTROL
;
1131 return ERROR_INVALID_PARAMETER
;
1135 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1137 return ERROR_ACCESS_DENIED
;
1139 /* Return the current service status information */
1140 RtlCopyMemory(lpServiceStatus
,
1142 sizeof(SERVICE_STATUS
));
1144 if (dwControl
== SERVICE_CONTROL_STOP
)
1146 /* Check if the service has dependencies running as windows
1147 doesn't stop a service that does */
1149 /* Open the Services Reg key */
1150 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1151 L
"System\\CurrentControlSet\\Services",
1155 if (dwError
!= ERROR_SUCCESS
)
1157 DPRINT("Failed to open services key\n");
1161 /* Call the internal function with NULL, just to get bytes we need */
1162 Int_EnumDependentServicesW(hServicesKey
,
1167 &dwServicesReturned
);
1169 RegCloseKey(hServicesKey
);
1171 /* If pcbBytesNeeded is not zero then there are services running that
1172 are dependent on this service */
1173 if (pcbBytesNeeded
!= 0)
1175 DPRINT("Service has running dependencies. Failed to stop service.\n");
1176 return ERROR_DEPENDENT_SERVICES_RUNNING
;
1180 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
1182 /* Send control code to the driver */
1183 dwError
= ScmControlDriver(lpService
,
1189 dwControlsAccepted
= lpService
->Status
.dwControlsAccepted
;
1190 dwCurrentState
= lpService
->Status
.dwCurrentState
;
1192 /* Return ERROR_SERVICE_NOT_ACTIVE if the service has not been started */
1193 if (lpService
->lpImage
== NULL
|| dwCurrentState
== SERVICE_STOPPED
)
1194 return ERROR_SERVICE_NOT_ACTIVE
;
1196 /* Check the current state before sending a control request */
1197 switch (dwCurrentState
)
1199 case SERVICE_STOP_PENDING
:
1200 case SERVICE_STOPPED
:
1201 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL
;
1203 case SERVICE_START_PENDING
:
1206 case SERVICE_CONTROL_STOP
:
1209 case SERVICE_CONTROL_INTERROGATE
:
1210 RtlCopyMemory(lpServiceStatus
,
1212 sizeof(SERVICE_STATUS
));
1213 return ERROR_SUCCESS
;
1216 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL
;
1221 /* Check if the control code is acceptable to the service */
1224 case SERVICE_CONTROL_STOP
:
1225 if ((dwControlsAccepted
& SERVICE_ACCEPT_STOP
) == 0)
1226 return ERROR_INVALID_SERVICE_CONTROL
;
1229 case SERVICE_CONTROL_PAUSE
:
1230 case SERVICE_CONTROL_CONTINUE
:
1231 if ((dwControlsAccepted
& SERVICE_ACCEPT_PAUSE_CONTINUE
) == 0)
1232 return ERROR_INVALID_SERVICE_CONTROL
;
1236 /* Send control code to the service */
1237 dwError
= ScmControlService(lpService
,
1240 /* Return service status information */
1241 RtlCopyMemory(lpServiceStatus
,
1243 sizeof(SERVICE_STATUS
));
1246 if (dwError
== ERROR_SUCCESS
)
1248 if (dwControl
!= SERVICE_CONTROL_INTERROGATE
)
1250 /* Log a sucessful send control */
1251 lpErrorStrings
[0] = lpService
->lpDisplayName
;
1255 case SERVICE_CONTROL_STOP
:
1256 lpErrorStrings
[1] = L
"stop";
1259 case SERVICE_CONTROL_PAUSE
:
1260 lpErrorStrings
[1] = L
"pause";
1263 case SERVICE_CONTROL_CONTINUE
:
1264 lpErrorStrings
[1] = L
"continue";
1268 lpErrorStrings
[1] = L
"other";
1272 ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS
,
1273 EVENTLOG_INFORMATION_TYPE
,
1284 DWORD
RDeleteService(
1285 SC_RPC_HANDLE hService
)
1287 PSERVICE_HANDLE hSvc
;
1291 DPRINT("RDeleteService() called\n");
1294 return ERROR_SHUTDOWN_IN_PROGRESS
;
1296 hSvc
= ScmGetServiceFromHandle(hService
);
1299 DPRINT1("Invalid service handle!\n");
1300 return ERROR_INVALID_HANDLE
;
1303 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1305 return ERROR_ACCESS_DENIED
;
1307 lpService
= hSvc
->ServiceEntry
;
1308 if (lpService
== NULL
)
1310 DPRINT("lpService == NULL!\n");
1311 return ERROR_INVALID_HANDLE
;
1314 /* Lock the service database exclusively */
1315 ScmLockDatabaseExclusive();
1317 if (lpService
->bDeleted
)
1319 DPRINT("The service has already been marked for delete!\n");
1320 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
1324 /* Mark service for delete */
1325 lpService
->bDeleted
= TRUE
;
1327 dwError
= ScmMarkServiceForDelete(lpService
);
1330 /* Unlock the service database */
1331 ScmUnlockDatabase();
1333 DPRINT("RDeleteService() done\n");
1340 DWORD
RLockServiceDatabase(
1341 SC_RPC_HANDLE hSCManager
,
1342 LPSC_RPC_LOCK lpLock
)
1344 PMANAGER_HANDLE hMgr
;
1346 DPRINT("RLockServiceDatabase() called\n");
1350 hMgr
= ScmGetServiceManagerFromHandle(hSCManager
);
1353 DPRINT1("Invalid service manager handle!\n");
1354 return ERROR_INVALID_HANDLE
;
1357 if (!RtlAreAllAccessesGranted(hMgr
->Handle
.DesiredAccess
,
1359 return ERROR_ACCESS_DENIED
;
1361 return ScmAcquireServiceStartLock(FALSE
, lpLock
);
1366 DWORD
RQueryServiceObjectSecurity(
1367 SC_RPC_HANDLE hService
,
1368 SECURITY_INFORMATION dwSecurityInformation
,
1369 LPBYTE lpSecurityDescriptor
,
1371 LPBOUNDED_DWORD_256K pcbBytesNeeded
)
1373 PSERVICE_HANDLE hSvc
;
1375 ULONG DesiredAccess
= 0;
1377 DWORD dwBytesNeeded
;
1381 SECURITY_DESCRIPTOR ObjectDescriptor
;
1383 DPRINT("RQueryServiceObjectSecurity() called\n");
1385 hSvc
= ScmGetServiceFromHandle(hService
);
1388 DPRINT1("Invalid service handle!\n");
1389 return ERROR_INVALID_HANDLE
;
1392 if (dwSecurityInformation
& (DACL_SECURITY_INFORMATION
|
1393 GROUP_SECURITY_INFORMATION
|
1394 OWNER_SECURITY_INFORMATION
))
1395 DesiredAccess
|= READ_CONTROL
;
1397 if (dwSecurityInformation
& SACL_SECURITY_INFORMATION
)
1398 DesiredAccess
|= ACCESS_SYSTEM_SECURITY
;
1400 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1403 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1404 return ERROR_ACCESS_DENIED
;
1407 lpService
= hSvc
->ServiceEntry
;
1408 if (lpService
== NULL
)
1410 DPRINT("lpService == NULL!\n");
1411 return ERROR_INVALID_HANDLE
;
1414 /* Lock the service database */
1415 ScmLockDatabaseShared();
1419 Status
= RtlCreateSecurityDescriptor(&ObjectDescriptor
, SECURITY_DESCRIPTOR_REVISION
);
1421 Status
= RtlQuerySecurityObject(&ObjectDescriptor
/* lpService->lpSecurityDescriptor */,
1422 dwSecurityInformation
,
1423 (PSECURITY_DESCRIPTOR
)lpSecurityDescriptor
,
1427 /* Unlock the service database */
1428 ScmUnlockDatabase();
1430 if (NT_SUCCESS(Status
))
1432 *pcbBytesNeeded
= dwBytesNeeded
;
1433 dwError
= STATUS_SUCCESS
;
1435 else if (Status
== STATUS_BUFFER_TOO_SMALL
)
1437 *pcbBytesNeeded
= dwBytesNeeded
;
1438 dwError
= ERROR_INSUFFICIENT_BUFFER
;
1440 else if (Status
== STATUS_BAD_DESCRIPTOR_FORMAT
)
1442 dwError
= ERROR_GEN_FAILURE
;
1446 dwError
= RtlNtStatusToDosError(Status
);
1454 DWORD
RSetServiceObjectSecurity(
1455 SC_RPC_HANDLE hService
,
1456 DWORD dwSecurityInformation
,
1457 LPBYTE lpSecurityDescriptor
,
1458 DWORD dwSecuityDescriptorSize
)
1460 PSERVICE_HANDLE hSvc
;
1462 ULONG DesiredAccess
= 0;
1463 /* HANDLE hToken = NULL; */
1465 /* NTSTATUS Status; */
1468 DPRINT("RSetServiceObjectSecurity() called\n");
1470 hSvc
= ScmGetServiceFromHandle(hService
);
1473 DPRINT1("Invalid service handle!\n");
1474 return ERROR_INVALID_HANDLE
;
1477 if (dwSecurityInformation
== 0 ||
1478 dwSecurityInformation
& ~(OWNER_SECURITY_INFORMATION
| GROUP_SECURITY_INFORMATION
1479 | DACL_SECURITY_INFORMATION
| SACL_SECURITY_INFORMATION
))
1480 return ERROR_INVALID_PARAMETER
;
1482 if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR
)lpSecurityDescriptor
))
1483 return ERROR_INVALID_PARAMETER
;
1485 if (dwSecurityInformation
& SACL_SECURITY_INFORMATION
)
1486 DesiredAccess
|= ACCESS_SYSTEM_SECURITY
;
1488 if (dwSecurityInformation
& DACL_SECURITY_INFORMATION
)
1489 DesiredAccess
|= WRITE_DAC
;
1491 if (dwSecurityInformation
& (OWNER_SECURITY_INFORMATION
| GROUP_SECURITY_INFORMATION
))
1492 DesiredAccess
|= WRITE_OWNER
;
1494 if ((dwSecurityInformation
& OWNER_SECURITY_INFORMATION
) &&
1495 (((PISECURITY_DESCRIPTOR
)lpSecurityDescriptor
)->Owner
== NULL
))
1496 return ERROR_INVALID_PARAMETER
;
1498 if ((dwSecurityInformation
& GROUP_SECURITY_INFORMATION
) &&
1499 (((PISECURITY_DESCRIPTOR
)lpSecurityDescriptor
)->Group
== NULL
))
1500 return ERROR_INVALID_PARAMETER
;
1502 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1505 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1506 return ERROR_ACCESS_DENIED
;
1509 lpService
= hSvc
->ServiceEntry
;
1510 if (lpService
== NULL
)
1512 DPRINT("lpService == NULL!\n");
1513 return ERROR_INVALID_HANDLE
;
1516 if (lpService
->bDeleted
)
1517 return ERROR_SERVICE_MARKED_FOR_DELETE
;
1520 RpcImpersonateClient(NULL
);
1522 Status
= NtOpenThreadToken(NtCurrentThread(),
1526 if (!NT_SUCCESS(Status
))
1527 return RtlNtStatusToDosError(Status
);
1532 /* Lock the service database exclusive */
1533 ScmLockDatabaseExclusive();
1536 Status
= RtlSetSecurityObject(dwSecurityInformation
,
1537 (PSECURITY_DESCRIPTOR
)lpSecurityDescriptor
,
1538 &lpService
->lpSecurityDescriptor
,
1541 if (!NT_SUCCESS(Status
))
1543 dwError
= RtlNtStatusToDosError(Status
);
1548 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
1549 READ_CONTROL
| KEY_CREATE_SUB_KEY
| KEY_SET_VALUE
,
1551 if (dwError
!= ERROR_SUCCESS
)
1555 dwError
= ERROR_SUCCESS
;
1556 // dwError = ScmWriteSecurityDescriptor(hServiceKey,
1557 // lpService->lpSecurityDescriptor);
1559 RegFlushKey(hServiceKey
);
1560 RegCloseKey(hServiceKey
);
1569 /* Unlock service database */
1570 ScmUnlockDatabase();
1572 DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError
);
1579 DWORD
RQueryServiceStatus(
1580 SC_RPC_HANDLE hService
,
1581 LPSERVICE_STATUS lpServiceStatus
)
1583 PSERVICE_HANDLE hSvc
;
1586 DPRINT("RQueryServiceStatus() called\n");
1589 return ERROR_SHUTDOWN_IN_PROGRESS
;
1591 hSvc
= ScmGetServiceFromHandle(hService
);
1594 DPRINT1("Invalid service handle!\n");
1595 return ERROR_INVALID_HANDLE
;
1598 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1599 SERVICE_QUERY_STATUS
))
1601 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1602 return ERROR_ACCESS_DENIED
;
1605 lpService
= hSvc
->ServiceEntry
;
1606 if (lpService
== NULL
)
1608 DPRINT("lpService == NULL!\n");
1609 return ERROR_INVALID_HANDLE
;
1612 /* Lock the service database shared */
1613 ScmLockDatabaseShared();
1615 /* Return service status information */
1616 RtlCopyMemory(lpServiceStatus
,
1618 sizeof(SERVICE_STATUS
));
1620 /* Unlock the service database */
1621 ScmUnlockDatabase();
1623 return ERROR_SUCCESS
;
1628 ScmIsValidServiceState(DWORD dwCurrentState
)
1630 switch (dwCurrentState
)
1632 case SERVICE_STOPPED
:
1633 case SERVICE_START_PENDING
:
1634 case SERVICE_STOP_PENDING
:
1635 case SERVICE_RUNNING
:
1636 case SERVICE_CONTINUE_PENDING
:
1637 case SERVICE_PAUSE_PENDING
:
1638 case SERVICE_PAUSED
:
1648 DWORD
RSetServiceStatus(
1649 RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
1650 LPSERVICE_STATUS lpServiceStatus
)
1653 DWORD dwPreviousState
;
1654 DWORD dwPreviousType
;
1655 LPCWSTR lpErrorStrings
[2];
1656 WCHAR szErrorBuffer
[32];
1658 DPRINT("RSetServiceStatus() called\n");
1659 DPRINT("hServiceStatus = %lu\n", hServiceStatus
);
1660 DPRINT("dwServiceType = 0x%lx\n", lpServiceStatus
->dwServiceType
);
1661 DPRINT("dwCurrentState = %lu\n", lpServiceStatus
->dwCurrentState
);
1662 DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus
->dwControlsAccepted
);
1663 DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus
->dwWin32ExitCode
);
1664 DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus
->dwServiceSpecificExitCode
);
1665 DPRINT("dwCheckPoint = %lu\n", lpServiceStatus
->dwCheckPoint
);
1666 DPRINT("dwWaitHint = %lu\n", lpServiceStatus
->dwWaitHint
);
1668 if (hServiceStatus
== 0)
1670 DPRINT("hServiceStatus == NULL!\n");
1671 return ERROR_INVALID_HANDLE
;
1674 lpService
= (PSERVICE
)hServiceStatus
;
1676 /* Check current state */
1677 if (!ScmIsValidServiceState(lpServiceStatus
->dwCurrentState
))
1679 DPRINT("Invalid service state!\n");
1680 return ERROR_INVALID_DATA
;
1683 /* Check service type */
1684 if (!(lpServiceStatus
->dwServiceType
& SERVICE_WIN32
) &&
1685 (lpServiceStatus
->dwServiceType
& SERVICE_DRIVER
))
1687 DPRINT("Invalid service type!\n");
1688 return ERROR_INVALID_DATA
;
1691 /* Check accepted controls */
1692 if (lpServiceStatus
->dwControlsAccepted
& ~0xFF)
1694 DPRINT("Invalid controls accepted!\n");
1695 return ERROR_INVALID_DATA
;
1698 /* Set the wait hint and check point only if the service is in a pending state,
1699 otherwise they should be 0 */
1700 if (lpServiceStatus
->dwCurrentState
== SERVICE_STOPPED
||
1701 lpServiceStatus
->dwCurrentState
== SERVICE_PAUSED
||
1702 lpServiceStatus
->dwCurrentState
== SERVICE_RUNNING
)
1704 lpServiceStatus
->dwWaitHint
= 0;
1705 lpServiceStatus
->dwCheckPoint
= 0;
1708 /* Lock the service database exclusively */
1709 ScmLockDatabaseExclusive();
1711 /* Save the current service state */
1712 dwPreviousState
= lpService
->Status
.dwCurrentState
;
1714 /* Save the current service type */
1715 dwPreviousType
= lpService
->Status
.dwServiceType
;
1717 /* Update the service status */
1718 RtlCopyMemory(&lpService
->Status
,
1720 sizeof(SERVICE_STATUS
));
1722 /* Restore the previous service type */
1723 lpService
->Status
.dwServiceType
= dwPreviousType
;
1725 /* Unlock the service database */
1726 ScmUnlockDatabase();
1728 if ((lpServiceStatus
->dwCurrentState
== SERVICE_STOPPED
) &&
1729 (dwPreviousState
!= SERVICE_STOPPED
) &&
1730 (lpServiceStatus
->dwWin32ExitCode
!= ERROR_SUCCESS
))
1732 /* Log a failed service stop */
1733 swprintf(szErrorBuffer
, L
"%lu", lpServiceStatus
->dwWin32ExitCode
);
1734 lpErrorStrings
[0] = lpService
->lpDisplayName
;
1735 lpErrorStrings
[1] = szErrorBuffer
;
1737 ScmLogEvent(EVENT_SERVICE_EXIT_FAILED
,
1738 EVENTLOG_ERROR_TYPE
,
1742 else if (lpServiceStatus
->dwCurrentState
!= dwPreviousState
&&
1743 (lpServiceStatus
->dwCurrentState
== SERVICE_STOPPED
||
1744 lpServiceStatus
->dwCurrentState
== SERVICE_RUNNING
||
1745 lpServiceStatus
->dwCurrentState
== SERVICE_PAUSED
))
1747 /* Log a successful service status change */
1748 lpErrorStrings
[0] = lpService
->lpDisplayName
;
1750 switch(lpServiceStatus
->dwCurrentState
)
1752 case SERVICE_STOPPED
:
1753 lpErrorStrings
[1] = L
"stopped";
1756 case SERVICE_RUNNING
:
1757 lpErrorStrings
[1] = L
"running";
1760 case SERVICE_PAUSED
:
1761 lpErrorStrings
[1] = L
"paused";
1765 ScmLogEvent(EVENT_SERVICE_STATUS_SUCCESS
,
1766 EVENTLOG_INFORMATION_TYPE
,
1771 DPRINT("Set %S to %lu\n", lpService
->lpDisplayName
, lpService
->Status
.dwCurrentState
);
1772 DPRINT("RSetServiceStatus() done\n");
1774 return ERROR_SUCCESS
;
1779 DWORD
RUnlockServiceDatabase(
1782 DPRINT("RUnlockServiceDatabase(%p)\n", Lock
);
1783 return ScmReleaseServiceStartLock(Lock
);
1788 DWORD
RNotifyBootConfigStatus(
1789 SVCCTL_HANDLEW lpMachineName
,
1790 DWORD BootAcceptable
)
1792 DPRINT1("RNotifyBootConfigStatus(%p %lu) called\n", lpMachineName
, BootAcceptable
);
1793 return ERROR_SUCCESS
;
1796 // return ERROR_CALL_NOT_IMPLEMENTED;
1801 DWORD
RI_ScSetServiceBitsW(
1802 RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
1803 DWORD dwServiceBits
,
1805 int bUpdateImmediately
,
1809 return ERROR_CALL_NOT_IMPLEMENTED
;
1814 DWORD
RChangeServiceConfigW(
1815 SC_RPC_HANDLE hService
,
1816 DWORD dwServiceType
,
1818 DWORD dwErrorControl
,
1819 LPWSTR lpBinaryPathName
,
1820 LPWSTR lpLoadOrderGroup
,
1822 LPBYTE lpDependencies
,
1824 LPWSTR lpServiceStartName
,
1827 LPWSTR lpDisplayName
)
1829 DWORD dwError
= ERROR_SUCCESS
;
1830 PSERVICE_HANDLE hSvc
;
1831 PSERVICE lpService
= NULL
;
1832 HKEY hServiceKey
= NULL
;
1833 LPWSTR lpDisplayNameW
= NULL
;
1834 LPWSTR lpImagePathW
= NULL
;
1836 DPRINT("RChangeServiceConfigW() called\n");
1837 DPRINT("dwServiceType = 0x%lx\n", dwServiceType
);
1838 DPRINT("dwStartType = %lu\n", dwStartType
);
1839 DPRINT("dwErrorControl = %lu\n", dwErrorControl
);
1840 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName
);
1841 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup
);
1842 DPRINT("lpDisplayName = %S\n", lpDisplayName
);
1845 return ERROR_SHUTDOWN_IN_PROGRESS
;
1847 hSvc
= ScmGetServiceFromHandle(hService
);
1850 DPRINT1("Invalid service handle!\n");
1851 return ERROR_INVALID_HANDLE
;
1854 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1855 SERVICE_CHANGE_CONFIG
))
1857 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1858 return ERROR_ACCESS_DENIED
;
1861 lpService
= hSvc
->ServiceEntry
;
1862 if (lpService
== NULL
)
1864 DPRINT("lpService == NULL!\n");
1865 return ERROR_INVALID_HANDLE
;
1868 /* Lock the service database exclusively */
1869 ScmLockDatabaseExclusive();
1871 if (lpService
->bDeleted
)
1873 DPRINT("The service has already been marked for delete!\n");
1874 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
1878 /* Open the service key */
1879 dwError
= ScmOpenServiceKey(lpService
->szServiceName
,
1882 if (dwError
!= ERROR_SUCCESS
)
1885 /* Write service data to the registry */
1886 /* Set the display name */
1887 if (lpDisplayName
!= NULL
&& *lpDisplayName
!= 0)
1889 RegSetValueExW(hServiceKey
,
1893 (LPBYTE
)lpDisplayName
,
1894 (DWORD
)((wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
)));
1896 /* Update the display name */
1897 lpDisplayNameW
= HeapAlloc(GetProcessHeap(),
1899 (wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
));
1900 if (lpDisplayNameW
== NULL
)
1902 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
1906 if (lpService
->lpDisplayName
!= lpService
->lpServiceName
)
1907 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
1909 lpService
->lpDisplayName
= lpDisplayNameW
;
1912 if (dwServiceType
!= SERVICE_NO_CHANGE
)
1914 /* Set the service type */
1915 dwError
= RegSetValueExW(hServiceKey
,
1919 (LPBYTE
)&dwServiceType
,
1921 if (dwError
!= ERROR_SUCCESS
)
1924 lpService
->Status
.dwServiceType
= dwServiceType
;
1927 if (dwStartType
!= SERVICE_NO_CHANGE
)
1929 /* Set the start value */
1930 dwError
= RegSetValueExW(hServiceKey
,
1934 (LPBYTE
)&dwStartType
,
1936 if (dwError
!= ERROR_SUCCESS
)
1939 lpService
->dwStartType
= dwStartType
;
1942 if (dwErrorControl
!= SERVICE_NO_CHANGE
)
1944 /* Set the error control value */
1945 dwError
= RegSetValueExW(hServiceKey
,
1949 (LPBYTE
)&dwErrorControl
,
1951 if (dwError
!= ERROR_SUCCESS
)
1954 lpService
->dwErrorControl
= dwErrorControl
;
1957 if (lpBinaryPathName
!= NULL
&& *lpBinaryPathName
!= 0)
1959 /* Set the image path */
1960 lpImagePathW
= lpBinaryPathName
;
1962 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
1964 dwError
= ScmCanonDriverImagePath(lpService
->dwStartType
,
1968 if (dwError
!= ERROR_SUCCESS
)
1972 dwError
= RegSetValueExW(hServiceKey
,
1976 (LPBYTE
)lpImagePathW
,
1977 (DWORD
)((wcslen(lpImagePathW
) + 1) * sizeof(WCHAR
)));
1979 if (lpImagePathW
!= lpBinaryPathName
)
1980 HeapFree(GetProcessHeap(), 0, lpImagePathW
);
1982 if (dwError
!= ERROR_SUCCESS
)
1986 /* Set the group name */
1987 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
1989 dwError
= RegSetValueExW(hServiceKey
,
1993 (LPBYTE
)lpLoadOrderGroup
,
1994 (DWORD
)((wcslen(lpLoadOrderGroup
) + 1) * sizeof(WCHAR
)));
1995 if (dwError
!= ERROR_SUCCESS
)
1998 dwError
= ScmSetServiceGroup(lpService
,
2000 if (dwError
!= ERROR_SUCCESS
)
2004 if (lpdwTagId
!= NULL
)
2006 dwError
= ScmAssignNewTag(lpService
);
2007 if (dwError
!= ERROR_SUCCESS
)
2010 dwError
= RegSetValueExW(hServiceKey
,
2014 (LPBYTE
)&lpService
->dwTag
,
2016 if (dwError
!= ERROR_SUCCESS
)
2019 *lpdwTagId
= lpService
->dwTag
;
2022 /* Write dependencies */
2023 if (lpDependencies
!= NULL
&& *lpDependencies
!= 0)
2025 dwError
= ScmWriteDependencies(hServiceKey
,
2026 (LPWSTR
)lpDependencies
,
2028 if (dwError
!= ERROR_SUCCESS
)
2032 if (lpPassword
!= NULL
)
2034 /* FIXME: Decrypt and write password */
2038 if (hServiceKey
!= NULL
)
2039 RegCloseKey(hServiceKey
);
2041 /* Unlock the service database */
2042 ScmUnlockDatabase();
2044 DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError
);
2051 DWORD
RCreateServiceW(
2052 SC_RPC_HANDLE hSCManager
,
2053 LPCWSTR lpServiceName
,
2054 LPCWSTR lpDisplayName
,
2055 DWORD dwDesiredAccess
,
2056 DWORD dwServiceType
,
2058 DWORD dwErrorControl
,
2059 LPCWSTR lpBinaryPathName
,
2060 LPCWSTR lpLoadOrderGroup
,
2062 LPBYTE lpDependencies
,
2064 LPCWSTR lpServiceStartName
,
2067 LPSC_RPC_HANDLE lpServiceHandle
)
2069 PMANAGER_HANDLE hManager
;
2070 DWORD dwError
= ERROR_SUCCESS
;
2071 PSERVICE lpService
= NULL
;
2072 SC_HANDLE hServiceHandle
= NULL
;
2073 LPWSTR lpImagePath
= NULL
;
2074 HKEY hServiceKey
= NULL
;
2075 LPWSTR lpObjectName
;
2077 DPRINT("RCreateServiceW() called\n");
2078 DPRINT("lpServiceName = %S\n", lpServiceName
);
2079 DPRINT("lpDisplayName = %S\n", lpDisplayName
);
2080 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess
);
2081 DPRINT("dwServiceType = 0x%lx\n", dwServiceType
);
2082 DPRINT("dwStartType = %lu\n", dwStartType
);
2083 DPRINT("dwErrorControl = %lu\n", dwErrorControl
);
2084 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName
);
2085 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup
);
2086 DPRINT("lpdwTagId = %p\n", lpdwTagId
);
2089 return ERROR_SHUTDOWN_IN_PROGRESS
;
2091 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
2092 if (hManager
== NULL
)
2094 DPRINT1("Invalid service manager handle!\n");
2095 return ERROR_INVALID_HANDLE
;
2098 /* Check access rights */
2099 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
2100 SC_MANAGER_CREATE_SERVICE
))
2102 DPRINT("Insufficient access rights! 0x%lx\n",
2103 hManager
->Handle
.DesiredAccess
);
2104 return ERROR_ACCESS_DENIED
;
2107 if (wcslen(lpServiceName
) == 0)
2109 return ERROR_INVALID_NAME
;
2112 if (wcslen(lpBinaryPathName
) == 0)
2114 return ERROR_INVALID_PARAMETER
;
2117 /* Check for invalid service type value */
2118 if ((dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
2119 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
) &&
2120 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
2121 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
))
2122 return ERROR_INVALID_PARAMETER
;
2124 /* Check for invalid start type value */
2125 if ((dwStartType
!= SERVICE_BOOT_START
) &&
2126 (dwStartType
!= SERVICE_SYSTEM_START
) &&
2127 (dwStartType
!= SERVICE_AUTO_START
) &&
2128 (dwStartType
!= SERVICE_DEMAND_START
) &&
2129 (dwStartType
!= SERVICE_DISABLED
))
2130 return ERROR_INVALID_PARAMETER
;
2132 /* Only drivers can be boot start or system start services */
2133 if ((dwStartType
== SERVICE_BOOT_START
) ||
2134 (dwStartType
== SERVICE_SYSTEM_START
))
2136 if ((dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
2137 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
2138 return ERROR_INVALID_PARAMETER
;
2141 /* Check for invalid error control value */
2142 if ((dwErrorControl
!= SERVICE_ERROR_IGNORE
) &&
2143 (dwErrorControl
!= SERVICE_ERROR_NORMAL
) &&
2144 (dwErrorControl
!= SERVICE_ERROR_SEVERE
) &&
2145 (dwErrorControl
!= SERVICE_ERROR_CRITICAL
))
2146 return ERROR_INVALID_PARAMETER
;
2148 if ((dwServiceType
== (SERVICE_WIN32_OWN_PROCESS
| SERVICE_INTERACTIVE_PROCESS
)) &&
2149 (lpServiceStartName
))
2151 return ERROR_INVALID_PARAMETER
;
2154 if (lpdwTagId
&& (!lpLoadOrderGroup
|| !*lpLoadOrderGroup
))
2156 return ERROR_INVALID_PARAMETER
;
2159 /* Lock the service database exclusively */
2160 ScmLockDatabaseExclusive();
2162 lpService
= ScmGetServiceEntryByName(lpServiceName
);
2165 /* Unlock the service database */
2166 ScmUnlockDatabase();
2168 /* Check if it is marked for deletion */
2169 if (lpService
->bDeleted
)
2170 return ERROR_SERVICE_MARKED_FOR_DELETE
;
2172 /* Return Error exist */
2173 return ERROR_SERVICE_EXISTS
;
2176 if (lpDisplayName
!= NULL
&&
2177 ScmGetServiceEntryByDisplayName(lpDisplayName
) != NULL
)
2179 /* Unlock the service database */
2180 ScmUnlockDatabase();
2182 return ERROR_DUPLICATE_SERVICE_NAME
;
2185 if (dwServiceType
& SERVICE_DRIVER
)
2187 dwError
= ScmCanonDriverImagePath(dwStartType
,
2190 if (dwError
!= ERROR_SUCCESS
)
2195 if (dwStartType
== SERVICE_BOOT_START
||
2196 dwStartType
== SERVICE_SYSTEM_START
)
2198 /* Unlock the service database */
2199 ScmUnlockDatabase();
2201 return ERROR_INVALID_PARAMETER
;
2205 /* Allocate a new service entry */
2206 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
2208 if (dwError
!= ERROR_SUCCESS
)
2211 /* Fill the new service entry */
2212 lpService
->Status
.dwServiceType
= dwServiceType
;
2213 lpService
->dwStartType
= dwStartType
;
2214 lpService
->dwErrorControl
= dwErrorControl
;
2216 /* Fill the display name */
2217 if (lpDisplayName
!= NULL
&&
2218 *lpDisplayName
!= 0 &&
2219 _wcsicmp(lpService
->lpDisplayName
, lpDisplayName
) != 0)
2221 lpService
->lpDisplayName
= HeapAlloc(GetProcessHeap(),
2223 (wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
));
2224 if (lpService
->lpDisplayName
== NULL
)
2226 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
2229 wcscpy(lpService
->lpDisplayName
, lpDisplayName
);
2232 /* Assign the service to a group */
2233 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
2235 dwError
= ScmSetServiceGroup(lpService
,
2237 if (dwError
!= ERROR_SUCCESS
)
2241 /* Assign a new tag */
2242 if (lpdwTagId
!= NULL
)
2244 dwError
= ScmAssignNewTag(lpService
);
2245 if (dwError
!= ERROR_SUCCESS
)
2249 /* Write service data to the registry */
2250 /* Create the service key */
2251 dwError
= ScmCreateServiceKey(lpServiceName
,
2254 if (dwError
!= ERROR_SUCCESS
)
2257 /* Set the display name */
2258 if (lpDisplayName
!= NULL
&& *lpDisplayName
!= 0)
2260 RegSetValueExW(hServiceKey
,
2264 (LPBYTE
)lpDisplayName
,
2265 (DWORD
)((wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
)));
2268 /* Set the service type */
2269 dwError
= RegSetValueExW(hServiceKey
,
2273 (LPBYTE
)&dwServiceType
,
2275 if (dwError
!= ERROR_SUCCESS
)
2278 /* Set the start value */
2279 dwError
= RegSetValueExW(hServiceKey
,
2283 (LPBYTE
)&dwStartType
,
2285 if (dwError
!= ERROR_SUCCESS
)
2288 /* Set the error control value */
2289 dwError
= RegSetValueExW(hServiceKey
,
2293 (LPBYTE
)&dwErrorControl
,
2295 if (dwError
!= ERROR_SUCCESS
)
2298 /* Set the image path */
2299 if (dwServiceType
& SERVICE_WIN32
)
2301 dwError
= RegSetValueExW(hServiceKey
,
2305 (LPBYTE
)lpBinaryPathName
,
2306 (DWORD
)((wcslen(lpBinaryPathName
) + 1) * sizeof(WCHAR
)));
2307 if (dwError
!= ERROR_SUCCESS
)
2310 else if (dwServiceType
& SERVICE_DRIVER
)
2312 dwError
= RegSetValueExW(hServiceKey
,
2316 (LPBYTE
)lpImagePath
,
2317 (DWORD
)((wcslen(lpImagePath
) + 1) * sizeof(WCHAR
)));
2318 if (dwError
!= ERROR_SUCCESS
)
2322 /* Set the group name */
2323 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
2325 dwError
= RegSetValueExW(hServiceKey
,
2329 (LPBYTE
)lpLoadOrderGroup
,
2330 (DWORD
)((wcslen(lpLoadOrderGroup
) + 1) * sizeof(WCHAR
)));
2331 if (dwError
!= ERROR_SUCCESS
)
2335 if (lpdwTagId
!= NULL
)
2337 dwError
= RegSetValueExW(hServiceKey
,
2341 (LPBYTE
)&lpService
->dwTag
,
2343 if (dwError
!= ERROR_SUCCESS
)
2347 /* Write dependencies */
2348 if (lpDependencies
!= NULL
&& *lpDependencies
!= 0)
2350 dwError
= ScmWriteDependencies(hServiceKey
,
2351 (LPCWSTR
)lpDependencies
,
2353 if (dwError
!= ERROR_SUCCESS
)
2357 /* Write service start name */
2358 if (dwServiceType
& SERVICE_WIN32
)
2360 lpObjectName
= (lpServiceStartName
!= NULL
) ? (LPWSTR
)lpServiceStartName
: L
"LocalSystem";
2361 dwError
= RegSetValueExW(hServiceKey
,
2365 (LPBYTE
)lpObjectName
,
2366 (DWORD
)((wcslen(lpObjectName
) + 1) * sizeof(WCHAR
)));
2367 if (dwError
!= ERROR_SUCCESS
)
2371 if (lpPassword
!= NULL
)
2373 /* FIXME: Decrypt and write password */
2376 dwError
= ScmCreateServiceHandle(lpService
,
2378 if (dwError
!= ERROR_SUCCESS
)
2381 dwError
= ScmCheckAccess(hServiceHandle
,
2383 if (dwError
!= ERROR_SUCCESS
)
2386 lpService
->dwRefCount
= 1;
2387 DPRINT("CreateService - lpService->dwRefCount %u\n", lpService
->dwRefCount
);
2390 /* Unlock the service database */
2391 ScmUnlockDatabase();
2393 if (hServiceKey
!= NULL
)
2394 RegCloseKey(hServiceKey
);
2396 if (dwError
== ERROR_SUCCESS
)
2398 DPRINT("hService %p\n", hServiceHandle
);
2399 *lpServiceHandle
= (SC_RPC_HANDLE
)hServiceHandle
;
2401 if (lpdwTagId
!= NULL
)
2402 *lpdwTagId
= lpService
->dwTag
;
2406 if (lpService
!= NULL
&&
2407 lpService
->lpServiceName
!= NULL
)
2409 /* Release the display name buffer */
2410 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
2415 /* Remove the service handle */
2416 HeapFree(GetProcessHeap(), 0, hServiceHandle
);
2419 if (lpService
!= NULL
)
2421 /* FIXME: remove the service entry */
2425 if (lpImagePath
!= NULL
)
2426 HeapFree(GetProcessHeap(), 0, lpImagePath
);
2428 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError
);
2435 DWORD
REnumDependentServicesW(
2436 SC_RPC_HANDLE hService
,
2437 DWORD dwServiceState
,
2440 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
2441 LPBOUNDED_DWORD_256K lpServicesReturned
)
2443 DWORD dwError
= ERROR_SUCCESS
;
2444 DWORD dwServicesReturned
= 0;
2445 DWORD dwServiceCount
;
2446 HKEY hServicesKey
= NULL
;
2447 PSERVICE_HANDLE hSvc
;
2448 PSERVICE lpService
= NULL
;
2449 PSERVICE
*lpServicesArray
= NULL
;
2450 LPENUM_SERVICE_STATUSW lpServicesPtr
= NULL
;
2453 *pcbBytesNeeded
= 0;
2454 *lpServicesReturned
= 0;
2456 DPRINT("REnumDependentServicesW() called\n");
2458 hSvc
= ScmGetServiceFromHandle(hService
);
2461 DPRINT1("Invalid service handle!\n");
2462 return ERROR_INVALID_HANDLE
;
2465 lpService
= hSvc
->ServiceEntry
;
2467 /* Check access rights */
2468 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
2469 SC_MANAGER_ENUMERATE_SERVICE
))
2471 DPRINT("Insufficient access rights! 0x%lx\n",
2472 hSvc
->Handle
.DesiredAccess
);
2473 return ERROR_ACCESS_DENIED
;
2476 /* Open the Services Reg key */
2477 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2478 L
"System\\CurrentControlSet\\Services",
2482 if (dwError
!= ERROR_SUCCESS
)
2485 /* First determine the bytes needed and get the number of dependent services */
2486 dwError
= Int_EnumDependentServicesW(hServicesKey
,
2491 &dwServicesReturned
);
2492 if (dwError
!= ERROR_SUCCESS
)
2495 /* If buffer size is less than the bytes needed or pointer is null */
2496 if ((!lpServices
) || (cbBufSize
< *pcbBytesNeeded
))
2498 dwError
= ERROR_MORE_DATA
;
2502 /* Allocate memory for array of service pointers */
2503 lpServicesArray
= HeapAlloc(GetProcessHeap(),
2505 (dwServicesReturned
+ 1) * sizeof(PSERVICE
));
2506 if (!lpServicesArray
)
2508 DPRINT1("Could not allocate a buffer!!\n");
2509 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
2513 dwServicesReturned
= 0;
2514 *pcbBytesNeeded
= 0;
2516 dwError
= Int_EnumDependentServicesW(hServicesKey
,
2521 &dwServicesReturned
);
2522 if (dwError
!= ERROR_SUCCESS
)
2527 lpServicesPtr
= (LPENUM_SERVICE_STATUSW
)lpServices
;
2528 lpStr
= (LPWSTR
)(lpServices
+ (dwServicesReturned
* sizeof(ENUM_SERVICE_STATUSW
)));
2530 /* Copy EnumDepenedentService to Buffer */
2531 for (dwServiceCount
= 0; dwServiceCount
< dwServicesReturned
; dwServiceCount
++)
2533 lpService
= lpServicesArray
[dwServiceCount
];
2535 /* Copy status info */
2536 memcpy(&lpServicesPtr
->ServiceStatus
,
2538 sizeof(SERVICE_STATUS
));
2540 /* Copy display name */
2541 wcscpy(lpStr
, lpService
->lpDisplayName
);
2542 lpServicesPtr
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
2543 lpStr
+= (wcslen(lpService
->lpDisplayName
) + 1);
2545 /* Copy service name */
2546 wcscpy(lpStr
, lpService
->lpServiceName
);
2547 lpServicesPtr
->lpServiceName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
2548 lpStr
+= (wcslen(lpService
->lpServiceName
) + 1);
2553 *lpServicesReturned
= dwServicesReturned
;
2556 if (lpServicesArray
!= NULL
)
2557 HeapFree(GetProcessHeap(), 0, lpServicesArray
);
2559 RegCloseKey(hServicesKey
);
2561 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError
);
2568 DWORD
REnumServicesStatusW(
2569 SC_RPC_HANDLE hSCManager
,
2570 DWORD dwServiceType
,
2571 DWORD dwServiceState
,
2574 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
2575 LPBOUNDED_DWORD_256K lpServicesReturned
,
2576 LPBOUNDED_DWORD_256K lpResumeHandle
)
2578 /* Enumerate all the services, not regarding of their group */
2579 return REnumServiceGroupW(hSCManager
,
2592 DWORD
ROpenSCManagerW(
2593 LPWSTR lpMachineName
,
2594 LPWSTR lpDatabaseName
,
2595 DWORD dwDesiredAccess
,
2596 LPSC_RPC_HANDLE lpScHandle
)
2601 DPRINT("ROpenSCManagerW() called\n");
2602 DPRINT("lpMachineName = %p\n", lpMachineName
);
2603 DPRINT("lpMachineName: %S\n", lpMachineName
);
2604 DPRINT("lpDataBaseName = %p\n", lpDatabaseName
);
2605 DPRINT("lpDataBaseName: %S\n", lpDatabaseName
);
2606 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess
);
2609 return ERROR_SHUTDOWN_IN_PROGRESS
;
2612 return ERROR_INVALID_PARAMETER
;
2614 dwError
= ScmCreateManagerHandle(lpDatabaseName
,
2616 if (dwError
!= ERROR_SUCCESS
)
2618 DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError
);
2622 /* Check the desired access */
2623 dwError
= ScmCheckAccess(hHandle
,
2624 dwDesiredAccess
| SC_MANAGER_CONNECT
);
2625 if (dwError
!= ERROR_SUCCESS
)
2627 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError
);
2628 HeapFree(GetProcessHeap(), 0, hHandle
);
2632 *lpScHandle
= (SC_RPC_HANDLE
)hHandle
;
2633 DPRINT("*hScm = %p\n", *lpScHandle
);
2635 DPRINT("ROpenSCManagerW() done\n");
2637 return ERROR_SUCCESS
;
2642 DWORD
ROpenServiceW(
2643 SC_RPC_HANDLE hSCManager
,
2644 LPWSTR lpServiceName
,
2645 DWORD dwDesiredAccess
,
2646 LPSC_RPC_HANDLE lpServiceHandle
)
2649 PMANAGER_HANDLE hManager
;
2651 DWORD dwError
= ERROR_SUCCESS
;
2653 DPRINT("ROpenServiceW() called\n");
2654 DPRINT("hSCManager = %p\n", hSCManager
);
2655 DPRINT("lpServiceName = %p\n", lpServiceName
);
2656 DPRINT("lpServiceName: %S\n", lpServiceName
);
2657 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess
);
2660 return ERROR_SHUTDOWN_IN_PROGRESS
;
2662 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
2663 if (hManager
== NULL
)
2665 DPRINT1("Invalid service manager handle!\n");
2666 return ERROR_INVALID_HANDLE
;
2669 if (!lpServiceHandle
)
2670 return ERROR_INVALID_PARAMETER
;
2673 return ERROR_INVALID_ADDRESS
;
2675 /* Lock the service database exclusive */
2676 ScmLockDatabaseExclusive();
2678 /* Get service database entry */
2679 lpService
= ScmGetServiceEntryByName(lpServiceName
);
2680 if (lpService
== NULL
)
2682 DPRINT("Could not find a service!\n");
2683 dwError
= ERROR_SERVICE_DOES_NOT_EXIST
;
2687 /* Create a service handle */
2688 dwError
= ScmCreateServiceHandle(lpService
,
2690 if (dwError
!= ERROR_SUCCESS
)
2692 DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError
);
2696 /* Check the desired access */
2697 dwError
= ScmCheckAccess(hHandle
,
2699 if (dwError
!= ERROR_SUCCESS
)
2701 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError
);
2702 HeapFree(GetProcessHeap(), 0, hHandle
);
2706 lpService
->dwRefCount
++;
2707 DPRINT("OpenService - lpService->dwRefCount %u\n",lpService
->dwRefCount
);
2709 *lpServiceHandle
= (SC_RPC_HANDLE
)hHandle
;
2710 DPRINT("*hService = %p\n", *lpServiceHandle
);
2713 /* Unlock the service database */
2714 ScmUnlockDatabase();
2716 DPRINT("ROpenServiceW() done\n");
2723 DWORD
RQueryServiceConfigW(
2724 SC_RPC_HANDLE hService
,
2725 LPBYTE lpBuf
, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2727 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
2729 LPQUERY_SERVICE_CONFIGW lpServiceConfig
= (LPQUERY_SERVICE_CONFIGW
)lpBuf
;
2730 DWORD dwError
= ERROR_SUCCESS
;
2731 PSERVICE_HANDLE hSvc
;
2732 PSERVICE lpService
= NULL
;
2733 HKEY hServiceKey
= NULL
;
2734 LPWSTR lpImagePath
= NULL
;
2735 LPWSTR lpServiceStartName
= NULL
;
2736 LPWSTR lpDependencies
= NULL
;
2737 DWORD dwDependenciesLength
= 0;
2738 DWORD dwRequiredSize
;
2739 WCHAR lpEmptyString
[] = {0,0};
2742 DPRINT("RQueryServiceConfigW() called\n");
2745 return ERROR_SHUTDOWN_IN_PROGRESS
;
2747 hSvc
= ScmGetServiceFromHandle(hService
);
2750 DPRINT1("Invalid service handle!\n");
2751 return ERROR_INVALID_HANDLE
;
2754 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
2755 SERVICE_QUERY_CONFIG
))
2757 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
2758 return ERROR_ACCESS_DENIED
;
2761 lpService
= hSvc
->ServiceEntry
;
2762 if (lpService
== NULL
)
2764 DPRINT("lpService == NULL!\n");
2765 return ERROR_INVALID_HANDLE
;
2768 /* Lock the service database shared */
2769 ScmLockDatabaseShared();
2771 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
2774 if (dwError
!= ERROR_SUCCESS
)
2777 /* Read the image path */
2778 dwError
= ScmReadString(hServiceKey
,
2781 if (dwError
!= ERROR_SUCCESS
)
2784 /* Read the service start name */
2785 ScmReadString(hServiceKey
,
2787 &lpServiceStartName
);
2789 /* Read the dependencies */
2790 ScmReadDependencies(hServiceKey
,
2792 &dwDependenciesLength
);
2794 dwRequiredSize
= sizeof(QUERY_SERVICE_CONFIGW
);
2796 if (lpImagePath
!= NULL
)
2797 dwRequiredSize
+= (DWORD
)((wcslen(lpImagePath
) + 1) * sizeof(WCHAR
));
2799 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2801 if ((lpService
->lpGroup
!= NULL
) && (lpService
->lpGroup
->lpGroupName
!= NULL
))
2802 dwRequiredSize
+= (DWORD
)((wcslen(lpService
->lpGroup
->lpGroupName
) + 1) * sizeof(WCHAR
));
2804 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2806 if (lpDependencies
!= NULL
)
2807 dwRequiredSize
+= dwDependenciesLength
* sizeof(WCHAR
);
2809 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2811 if (lpServiceStartName
!= NULL
)
2812 dwRequiredSize
+= (DWORD
)((wcslen(lpServiceStartName
) + 1) * sizeof(WCHAR
));
2814 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2816 if (lpService
->lpDisplayName
!= NULL
)
2817 dwRequiredSize
+= (DWORD
)((wcslen(lpService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
2819 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2821 if (lpServiceConfig
== NULL
|| cbBufSize
< dwRequiredSize
)
2823 dwError
= ERROR_INSUFFICIENT_BUFFER
;
2827 lpServiceConfig
->dwServiceType
= lpService
->Status
.dwServiceType
;
2828 lpServiceConfig
->dwStartType
= lpService
->dwStartType
;
2829 lpServiceConfig
->dwErrorControl
= lpService
->dwErrorControl
;
2830 lpServiceConfig
->dwTagId
= lpService
->dwTag
;
2832 lpStr
= (LPWSTR
)(lpServiceConfig
+ 1);
2834 /* Append the image path */
2835 if (lpImagePath
!= NULL
)
2837 wcscpy(lpStr
, lpImagePath
);
2841 wcscpy(lpStr
, lpEmptyString
);
2844 lpServiceConfig
->lpBinaryPathName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2845 lpStr
+= (wcslen(lpStr
) + 1);
2847 /* Append the group name */
2848 if ((lpService
->lpGroup
!= NULL
) && (lpService
->lpGroup
->lpGroupName
!= NULL
))
2850 wcscpy(lpStr
, lpService
->lpGroup
->lpGroupName
);
2854 wcscpy(lpStr
, lpEmptyString
);
2857 lpServiceConfig
->lpLoadOrderGroup
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2858 lpStr
+= (wcslen(lpStr
) + 1);
2860 /* Append Dependencies */
2861 if (lpDependencies
!= NULL
)
2865 dwDependenciesLength
* sizeof(WCHAR
));
2869 wcscpy(lpStr
, lpEmptyString
);
2872 lpServiceConfig
->lpDependencies
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2873 if (lpDependencies
!= NULL
)
2874 lpStr
+= dwDependenciesLength
;
2876 lpStr
+= (wcslen(lpStr
) + 1);
2878 /* Append the service start name */
2879 if (lpServiceStartName
!= NULL
)
2881 wcscpy(lpStr
, lpServiceStartName
);
2885 wcscpy(lpStr
, lpEmptyString
);
2888 lpServiceConfig
->lpServiceStartName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2889 lpStr
+= (wcslen(lpStr
) + 1);
2891 /* Append the display name */
2892 if (lpService
->lpDisplayName
!= NULL
)
2894 wcscpy(lpStr
, lpService
->lpDisplayName
);
2898 wcscpy(lpStr
, lpEmptyString
);
2901 lpServiceConfig
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2904 if (pcbBytesNeeded
!= NULL
)
2905 *pcbBytesNeeded
= dwRequiredSize
;
2908 /* Unlock the service database */
2909 ScmUnlockDatabase();
2911 if (lpImagePath
!= NULL
)
2912 HeapFree(GetProcessHeap(), 0, lpImagePath
);
2914 if (lpServiceStartName
!= NULL
)
2915 HeapFree(GetProcessHeap(), 0, lpServiceStartName
);
2917 if (lpDependencies
!= NULL
)
2918 HeapFree(GetProcessHeap(), 0, lpDependencies
);
2920 if (hServiceKey
!= NULL
)
2921 RegCloseKey(hServiceKey
);
2923 DPRINT("RQueryServiceConfigW() done\n");
2930 DWORD
RQueryServiceLockStatusW(
2931 SC_RPC_HANDLE hSCManager
,
2932 LPBYTE lpBuf
, // LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2934 LPBOUNDED_DWORD_4K pcbBytesNeeded
)
2936 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
= (LPQUERY_SERVICE_LOCK_STATUSW
)lpBuf
;
2937 PMANAGER_HANDLE hMgr
;
2938 DWORD dwRequiredSize
;
2940 if (!lpLockStatus
|| !pcbBytesNeeded
)
2941 return ERROR_INVALID_PARAMETER
;
2943 hMgr
= ScmGetServiceManagerFromHandle(hSCManager
);
2946 DPRINT1("Invalid service manager handle!\n");
2947 return ERROR_INVALID_HANDLE
;
2950 if (!RtlAreAllAccessesGranted(hMgr
->Handle
.DesiredAccess
,
2951 SC_MANAGER_QUERY_LOCK_STATUS
))
2953 DPRINT("Insufficient access rights! 0x%lx\n", hMgr
->Handle
.DesiredAccess
);
2954 return ERROR_ACCESS_DENIED
;
2957 /* FIXME: we need to compute instead the real length of the owner name */
2958 dwRequiredSize
= sizeof(QUERY_SERVICE_LOCK_STATUSW
) + sizeof(WCHAR
);
2959 *pcbBytesNeeded
= dwRequiredSize
;
2961 if (cbBufSize
< dwRequiredSize
)
2962 return ERROR_INSUFFICIENT_BUFFER
;
2964 ScmQueryServiceLockStatusW(lpLockStatus
);
2966 return ERROR_SUCCESS
;
2971 DWORD
RStartServiceW(
2972 SC_RPC_HANDLE hService
,
2974 LPSTRING_PTRSW argv
)
2976 DWORD dwError
= ERROR_SUCCESS
;
2977 PSERVICE_HANDLE hSvc
;
2978 PSERVICE lpService
= NULL
;
2983 DPRINT("RStartServiceW(%p %lu %p) called\n", hService
, argc
, argv
);
2984 DPRINT(" argc: %lu\n", argc
);
2987 for (i
= 0; i
< argc
; i
++)
2989 DPRINT(" argv[%lu]: %S\n", i
, argv
[i
].StringPtr
);
2995 return ERROR_SHUTDOWN_IN_PROGRESS
;
2997 hSvc
= ScmGetServiceFromHandle(hService
);
3000 DPRINT1("Invalid service handle!\n");
3001 return ERROR_INVALID_HANDLE
;
3004 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3007 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
3008 return ERROR_ACCESS_DENIED
;
3011 lpService
= hSvc
->ServiceEntry
;
3012 if (lpService
== NULL
)
3014 DPRINT("lpService == NULL!\n");
3015 return ERROR_INVALID_HANDLE
;
3018 if (lpService
->dwStartType
== SERVICE_DISABLED
)
3019 return ERROR_SERVICE_DISABLED
;
3021 if (lpService
->bDeleted
)
3022 return ERROR_SERVICE_MARKED_FOR_DELETE
;
3024 /* Start the service */
3025 dwError
= ScmStartService(lpService
, argc
, (LPWSTR
*)argv
);
3032 DWORD
RGetServiceDisplayNameW(
3033 SC_RPC_HANDLE hSCManager
,
3034 LPCWSTR lpServiceName
,
3035 LPWSTR lpDisplayName
,
3038 // PMANAGER_HANDLE hManager;
3043 DPRINT("RGetServiceDisplayNameW() called\n");
3044 DPRINT("hSCManager = %p\n", hSCManager
);
3045 DPRINT("lpServiceName: %S\n", lpServiceName
);
3046 DPRINT("lpDisplayName: %p\n", lpDisplayName
);
3047 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
3049 // hManager = (PMANAGER_HANDLE)hSCManager;
3050 // if (hManager->Handle.Tag != MANAGER_TAG)
3052 // DPRINT("Invalid manager handle!\n");
3053 // return ERROR_INVALID_HANDLE;
3056 /* Get service database entry */
3057 lpService
= ScmGetServiceEntryByName(lpServiceName
);
3058 if (lpService
== NULL
)
3060 DPRINT("Could not find a service!\n");
3062 /* If the service could not be found and lpcchBuffer is less than 2, windows
3063 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3064 if (*lpcchBuffer
< 2)
3067 if (lpDisplayName
!= NULL
)
3073 return ERROR_SERVICE_DOES_NOT_EXIST
;
3076 if (!lpService
->lpDisplayName
)
3078 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
3080 if (lpDisplayName
!= NULL
&&
3081 *lpcchBuffer
> dwLength
)
3083 wcscpy(lpDisplayName
, lpService
->lpServiceName
);
3088 dwLength
= (DWORD
)wcslen(lpService
->lpDisplayName
);
3090 if (lpDisplayName
!= NULL
&&
3091 *lpcchBuffer
> dwLength
)
3093 wcscpy(lpDisplayName
, lpService
->lpDisplayName
);
3097 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
3099 *lpcchBuffer
= dwLength
;
3106 DWORD
RGetServiceKeyNameW(
3107 SC_RPC_HANDLE hSCManager
,
3108 LPCWSTR lpDisplayName
,
3109 LPWSTR lpServiceName
,
3112 // PMANAGER_HANDLE hManager;
3117 DPRINT("RGetServiceKeyNameW() called\n");
3118 DPRINT("hSCManager = %p\n", hSCManager
);
3119 DPRINT("lpDisplayName: %S\n", lpDisplayName
);
3120 DPRINT("lpServiceName: %p\n", lpServiceName
);
3121 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
3123 // hManager = (PMANAGER_HANDLE)hSCManager;
3124 // if (hManager->Handle.Tag != MANAGER_TAG)
3126 // DPRINT("Invalid manager handle!\n");
3127 // return ERROR_INVALID_HANDLE;
3130 /* Get service database entry */
3131 lpService
= ScmGetServiceEntryByDisplayName(lpDisplayName
);
3132 if (lpService
== NULL
)
3134 DPRINT("Could not find a service!\n");
3136 /* If the service could not be found and lpcchBuffer is less than 2, windows
3137 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3138 if (*lpcchBuffer
< 2)
3141 if (lpServiceName
!= NULL
)
3147 return ERROR_SERVICE_DOES_NOT_EXIST
;
3150 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
3152 if (lpServiceName
!= NULL
&&
3153 *lpcchBuffer
> dwLength
)
3155 wcscpy(lpServiceName
, lpService
->lpServiceName
);
3156 *lpcchBuffer
= dwLength
;
3157 return ERROR_SUCCESS
;
3160 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
3162 *lpcchBuffer
= dwLength
;
3169 DWORD
RI_ScSetServiceBitsA(
3170 RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
3171 DWORD dwServiceBits
,
3173 int bUpdateImmediately
,
3177 return ERROR_CALL_NOT_IMPLEMENTED
;
3182 DWORD
RChangeServiceConfigA(
3183 SC_RPC_HANDLE hService
,
3184 DWORD dwServiceType
,
3186 DWORD dwErrorControl
,
3187 LPSTR lpBinaryPathName
,
3188 LPSTR lpLoadOrderGroup
,
3190 LPBYTE lpDependencies
,
3192 LPSTR lpServiceStartName
,
3195 LPSTR lpDisplayName
)
3197 DWORD dwError
= ERROR_SUCCESS
;
3198 PSERVICE_HANDLE hSvc
;
3199 PSERVICE lpService
= NULL
;
3200 HKEY hServiceKey
= NULL
;
3201 LPWSTR lpDisplayNameW
= NULL
;
3202 LPWSTR lpBinaryPathNameW
= NULL
;
3203 LPWSTR lpCanonicalImagePathW
= NULL
;
3204 LPWSTR lpLoadOrderGroupW
= NULL
;
3205 LPWSTR lpDependenciesW
= NULL
;
3207 DPRINT("RChangeServiceConfigA() called\n");
3208 DPRINT("dwServiceType = %lu\n", dwServiceType
);
3209 DPRINT("dwStartType = %lu\n", dwStartType
);
3210 DPRINT("dwErrorControl = %lu\n", dwErrorControl
);
3211 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName
);
3212 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup
);
3213 DPRINT("lpDisplayName = %s\n", lpDisplayName
);
3216 return ERROR_SHUTDOWN_IN_PROGRESS
;
3218 hSvc
= ScmGetServiceFromHandle(hService
);
3221 DPRINT1("Invalid service handle!\n");
3222 return ERROR_INVALID_HANDLE
;
3225 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3226 SERVICE_CHANGE_CONFIG
))
3228 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
3229 return ERROR_ACCESS_DENIED
;
3232 lpService
= hSvc
->ServiceEntry
;
3233 if (lpService
== NULL
)
3235 DPRINT("lpService == NULL!\n");
3236 return ERROR_INVALID_HANDLE
;
3239 /* Lock the service database exclusively */
3240 ScmLockDatabaseExclusive();
3242 if (lpService
->bDeleted
)
3244 DPRINT("The service has already been marked for delete!\n");
3245 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
3249 /* Open the service key */
3250 dwError
= ScmOpenServiceKey(lpService
->szServiceName
,
3253 if (dwError
!= ERROR_SUCCESS
)
3256 /* Write service data to the registry */
3258 if (lpDisplayName
!= NULL
&& *lpDisplayName
!= 0)
3260 /* Set the display name */
3261 lpDisplayNameW
= HeapAlloc(GetProcessHeap(),
3263 (strlen(lpDisplayName
) + 1) * sizeof(WCHAR
));
3264 if (lpDisplayNameW
== NULL
)
3266 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3270 MultiByteToWideChar(CP_ACP
,
3275 (int)(strlen(lpDisplayName
) + 1));
3277 RegSetValueExW(hServiceKey
,
3281 (LPBYTE
)lpDisplayNameW
,
3282 (DWORD
)((wcslen(lpDisplayNameW
) + 1) * sizeof(WCHAR
)));
3284 /* Update lpService->lpDisplayName */
3285 if (lpService
->lpDisplayName
)
3286 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
3288 lpService
->lpDisplayName
= lpDisplayNameW
;
3291 if (dwServiceType
!= SERVICE_NO_CHANGE
)
3293 /* Set the service type */
3294 dwError
= RegSetValueExW(hServiceKey
,
3298 (LPBYTE
)&dwServiceType
,
3300 if (dwError
!= ERROR_SUCCESS
)
3303 lpService
->Status
.dwServiceType
= dwServiceType
;
3306 if (dwStartType
!= SERVICE_NO_CHANGE
)
3308 /* Set the start value */
3309 dwError
= RegSetValueExW(hServiceKey
,
3313 (LPBYTE
)&dwStartType
,
3315 if (dwError
!= ERROR_SUCCESS
)
3318 lpService
->dwStartType
= dwStartType
;
3321 if (dwErrorControl
!= SERVICE_NO_CHANGE
)
3323 /* Set the error control value */
3324 dwError
= RegSetValueExW(hServiceKey
,
3328 (LPBYTE
)&dwErrorControl
,
3330 if (dwError
!= ERROR_SUCCESS
)
3333 lpService
->dwErrorControl
= dwErrorControl
;
3336 if (lpBinaryPathName
!= NULL
&& *lpBinaryPathName
!= 0)
3338 /* Set the image path */
3339 lpBinaryPathNameW
= HeapAlloc(GetProcessHeap(),
3341 (strlen(lpBinaryPathName
) + 1) * sizeof(WCHAR
));
3342 if (lpBinaryPathNameW
== NULL
)
3344 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3348 MultiByteToWideChar(CP_ACP
,
3353 (int)(strlen(lpBinaryPathName
) + 1));
3355 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
3357 dwError
= ScmCanonDriverImagePath(lpService
->dwStartType
,
3359 &lpCanonicalImagePathW
);
3361 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW
);
3363 if (dwError
!= ERROR_SUCCESS
)
3366 lpBinaryPathNameW
= lpCanonicalImagePathW
;
3369 dwError
= RegSetValueExW(hServiceKey
,
3373 (LPBYTE
)lpBinaryPathNameW
,
3374 (DWORD
)((wcslen(lpBinaryPathNameW
) + 1) * sizeof(WCHAR
)));
3376 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW
);
3378 if (dwError
!= ERROR_SUCCESS
)
3382 /* Set the group name */
3383 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
3385 lpLoadOrderGroupW
= HeapAlloc(GetProcessHeap(),
3387 (strlen(lpLoadOrderGroup
) + 1) * sizeof(WCHAR
));
3388 if (lpLoadOrderGroupW
== NULL
)
3390 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3394 MultiByteToWideChar(CP_ACP
,
3399 (int)(strlen(lpLoadOrderGroup
) + 1));
3401 dwError
= RegSetValueExW(hServiceKey
,
3405 (LPBYTE
)lpLoadOrderGroupW
,
3406 (DWORD
)((wcslen(lpLoadOrderGroupW
) + 1) * sizeof(WCHAR
)));
3407 if (dwError
!= ERROR_SUCCESS
)
3409 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3413 dwError
= ScmSetServiceGroup(lpService
,
3416 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3418 if (dwError
!= ERROR_SUCCESS
)
3422 if (lpdwTagId
!= NULL
)
3424 dwError
= ScmAssignNewTag(lpService
);
3425 if (dwError
!= ERROR_SUCCESS
)
3428 dwError
= RegSetValueExW(hServiceKey
,
3432 (LPBYTE
)&lpService
->dwTag
,
3434 if (dwError
!= ERROR_SUCCESS
)
3437 *lpdwTagId
= lpService
->dwTag
;
3440 /* Write dependencies */
3441 if (lpDependencies
!= NULL
&& *lpDependencies
!= 0)
3443 lpDependenciesW
= HeapAlloc(GetProcessHeap(),
3445 (strlen((LPSTR
)lpDependencies
) + 1) * sizeof(WCHAR
));
3446 if (lpDependenciesW
== NULL
)
3448 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3452 MultiByteToWideChar(CP_ACP
,
3454 (LPSTR
)lpDependencies
,
3457 (int)(strlen((LPSTR
)lpDependencies
) + 1));
3459 dwError
= ScmWriteDependencies(hServiceKey
,
3460 (LPWSTR
)lpDependenciesW
,
3463 HeapFree(GetProcessHeap(), 0, lpDependenciesW
);
3466 if (lpPassword
!= NULL
)
3468 /* FIXME: Decrypt and write password */
3472 /* Unlock the service database */
3473 ScmUnlockDatabase();
3475 if (hServiceKey
!= NULL
)
3476 RegCloseKey(hServiceKey
);
3478 DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError
);
3485 DWORD
RCreateServiceA(
3486 SC_RPC_HANDLE hSCManager
,
3487 LPSTR lpServiceName
,
3488 LPSTR lpDisplayName
,
3489 DWORD dwDesiredAccess
,
3490 DWORD dwServiceType
,
3492 DWORD dwErrorControl
,
3493 LPSTR lpBinaryPathName
,
3494 LPSTR lpLoadOrderGroup
,
3496 LPBYTE lpDependencies
,
3498 LPSTR lpServiceStartName
,
3501 LPSC_RPC_HANDLE lpServiceHandle
)
3503 DWORD dwError
= ERROR_SUCCESS
;
3504 LPWSTR lpServiceNameW
= NULL
;
3505 LPWSTR lpDisplayNameW
= NULL
;
3506 LPWSTR lpBinaryPathNameW
= NULL
;
3507 LPWSTR lpLoadOrderGroupW
= NULL
;
3508 LPWSTR lpDependenciesW
= NULL
;
3509 LPWSTR lpServiceStartNameW
= NULL
;
3510 DWORD dwDependenciesLength
= 0;
3517 len
= MultiByteToWideChar(CP_ACP
, 0, lpServiceName
, -1, NULL
, 0);
3518 lpServiceNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3519 if (!lpServiceNameW
)
3521 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3524 MultiByteToWideChar(CP_ACP
, 0, lpServiceName
, -1, lpServiceNameW
, len
);
3529 len
= MultiByteToWideChar(CP_ACP
, 0, lpDisplayName
, -1, NULL
, 0);
3530 lpDisplayNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3531 if (!lpDisplayNameW
)
3533 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3536 MultiByteToWideChar(CP_ACP
, 0, lpDisplayName
, -1, lpDisplayNameW
, len
);
3539 if (lpBinaryPathName
)
3541 len
= MultiByteToWideChar(CP_ACP
, 0, lpBinaryPathName
, -1, NULL
, 0);
3542 lpBinaryPathNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3543 if (!lpBinaryPathNameW
)
3545 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3548 MultiByteToWideChar(CP_ACP
, 0, lpBinaryPathName
, -1, lpBinaryPathNameW
, len
);
3551 if (lpLoadOrderGroup
)
3553 len
= MultiByteToWideChar(CP_ACP
, 0, lpLoadOrderGroup
, -1, NULL
, 0);
3554 lpLoadOrderGroupW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3555 if (!lpLoadOrderGroupW
)
3557 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3560 MultiByteToWideChar(CP_ACP
, 0, lpLoadOrderGroup
, -1, lpLoadOrderGroupW
, len
);
3565 lpStr
= (LPCSTR
)lpDependencies
;
3568 cchLength
= strlen(lpStr
) + 1;
3569 dwDependenciesLength
+= (DWORD
)cchLength
;
3570 lpStr
= lpStr
+ cchLength
;
3572 dwDependenciesLength
++;
3574 lpDependenciesW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwDependenciesLength
* sizeof(WCHAR
));
3575 if (!lpDependenciesW
)
3577 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3580 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)lpDependencies
, dwDependenciesLength
, lpDependenciesW
, dwDependenciesLength
);
3583 if (lpServiceStartName
)
3585 len
= MultiByteToWideChar(CP_ACP
, 0, lpServiceStartName
, -1, NULL
, 0);
3586 lpServiceStartNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3587 if (!lpServiceStartNameW
)
3589 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3592 MultiByteToWideChar(CP_ACP
, 0, lpServiceStartName
, -1, lpServiceStartNameW
, len
);
3595 dwError
= RCreateServiceW(hSCManager
,
3605 (LPBYTE
)lpDependenciesW
,
3606 dwDependenciesLength
,
3607 lpServiceStartNameW
,
3613 if (lpServiceNameW
!=NULL
)
3614 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
3616 if (lpDisplayNameW
!= NULL
)
3617 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
3619 if (lpBinaryPathNameW
!= NULL
)
3620 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW
);
3622 if (lpLoadOrderGroupW
!= NULL
)
3623 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3625 if (lpDependenciesW
!= NULL
)
3626 HeapFree(GetProcessHeap(), 0, lpDependenciesW
);
3628 if (lpServiceStartNameW
!= NULL
)
3629 HeapFree(GetProcessHeap(), 0, lpServiceStartNameW
);
3636 DWORD
REnumDependentServicesA(
3637 SC_RPC_HANDLE hService
,
3638 DWORD dwServiceState
,
3641 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
3642 LPBOUNDED_DWORD_256K lpServicesReturned
)
3644 DWORD dwError
= ERROR_SUCCESS
;
3645 DWORD dwServicesReturned
= 0;
3646 DWORD dwServiceCount
;
3647 HKEY hServicesKey
= NULL
;
3648 PSERVICE_HANDLE hSvc
;
3649 PSERVICE lpService
= NULL
;
3650 PSERVICE
*lpServicesArray
= NULL
;
3651 LPENUM_SERVICE_STATUSA lpServicesPtr
= NULL
;
3654 *pcbBytesNeeded
= 0;
3655 *lpServicesReturned
= 0;
3657 DPRINT("REnumDependentServicesA() called\n");
3659 hSvc
= ScmGetServiceFromHandle(hService
);
3662 DPRINT1("Invalid service handle!\n");
3663 return ERROR_INVALID_HANDLE
;
3666 lpService
= hSvc
->ServiceEntry
;
3668 /* Check access rights */
3669 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3670 SC_MANAGER_ENUMERATE_SERVICE
))
3672 DPRINT("Insufficient access rights! 0x%lx\n",
3673 hSvc
->Handle
.DesiredAccess
);
3674 return ERROR_ACCESS_DENIED
;
3677 /* Open the Services Reg key */
3678 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
3679 L
"System\\CurrentControlSet\\Services",
3684 if (dwError
!= ERROR_SUCCESS
)
3687 /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3688 both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3689 are the same for both. Verified in WINXP. */
3691 /* First determine the bytes needed and get the number of dependent services*/
3692 dwError
= Int_EnumDependentServicesW(hServicesKey
,
3697 &dwServicesReturned
);
3698 if (dwError
!= ERROR_SUCCESS
)
3701 /* If buffer size is less than the bytes needed or pointer is null*/
3702 if ((!lpServices
) || (cbBufSize
< *pcbBytesNeeded
))
3704 dwError
= ERROR_MORE_DATA
;
3708 /* Allocate memory for array of service pointers */
3709 lpServicesArray
= HeapAlloc(GetProcessHeap(),
3711 (dwServicesReturned
+ 1) * sizeof(PSERVICE
));
3712 if (!lpServicesArray
)
3714 DPRINT("Could not allocate a buffer!!\n");
3715 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3719 dwServicesReturned
= 0;
3720 *pcbBytesNeeded
= 0;
3722 dwError
= Int_EnumDependentServicesW(hServicesKey
,
3727 &dwServicesReturned
);
3728 if (dwError
!= ERROR_SUCCESS
)
3733 lpServicesPtr
= (LPENUM_SERVICE_STATUSA
)lpServices
;
3734 lpStr
= (LPSTR
)(lpServices
+ (dwServicesReturned
* sizeof(ENUM_SERVICE_STATUSA
)));
3736 /* Copy EnumDepenedentService to Buffer */
3737 for (dwServiceCount
= 0; dwServiceCount
< dwServicesReturned
; dwServiceCount
++)
3739 lpService
= lpServicesArray
[dwServiceCount
];
3741 /* Copy the status info */
3742 memcpy(&lpServicesPtr
->ServiceStatus
,
3744 sizeof(SERVICE_STATUS
));
3746 /* Copy display name */
3747 WideCharToMultiByte(CP_ACP
,
3749 lpService
->lpDisplayName
,
3752 (int)wcslen(lpService
->lpDisplayName
),
3755 lpServicesPtr
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
3756 lpStr
+= strlen(lpStr
) + 1;
3758 /* Copy service name */
3759 WideCharToMultiByte(CP_ACP
,
3761 lpService
->lpServiceName
,
3764 (int)wcslen(lpService
->lpServiceName
),
3767 lpServicesPtr
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
3768 lpStr
+= strlen(lpStr
) + 1;
3773 *lpServicesReturned
= dwServicesReturned
;
3776 if (lpServicesArray
)
3777 HeapFree(GetProcessHeap(), 0, lpServicesArray
);
3779 RegCloseKey(hServicesKey
);
3781 DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError
);
3788 DWORD
REnumServicesStatusA(
3789 SC_RPC_HANDLE hSCManager
,
3790 DWORD dwServiceType
,
3791 DWORD dwServiceState
,
3794 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
3795 LPBOUNDED_DWORD_256K lpServicesReturned
,
3796 LPBOUNDED_DWORD_256K lpResumeHandle
)
3798 LPENUM_SERVICE_STATUSW lpStatusPtrW
= NULL
;
3799 LPENUM_SERVICE_STATUSW lpStatusPtrIncrW
;
3800 LPENUM_SERVICE_STATUSA lpStatusPtrA
= NULL
;
3801 LPWSTR lpStringPtrW
;
3804 DWORD dwServiceCount
;
3806 DPRINT("REnumServicesStatusA() called\n");
3808 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
3810 return ERROR_INVALID_ADDRESS
;
3813 if ((dwBufSize
> 0) && (lpBuffer
))
3815 lpStatusPtrW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwBufSize
);
3818 DPRINT("Failed to allocate buffer!\n");
3819 return ERROR_NOT_ENOUGH_MEMORY
;
3823 dwError
= REnumServicesStatusW(hSCManager
,
3826 (LPBYTE
)lpStatusPtrW
,
3832 /* if no services were returned then we are Done */
3833 if (*lpServicesReturned
== 0)
3836 lpStatusPtrIncrW
= lpStatusPtrW
;
3837 lpStatusPtrA
= (LPENUM_SERVICE_STATUSA
)lpBuffer
;
3838 lpStringPtrA
= (LPSTR
)((ULONG_PTR
)lpBuffer
+
3839 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUSA
));
3840 lpStringPtrW
= (LPWSTR
)((ULONG_PTR
)lpStatusPtrW
+
3841 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUSW
));
3843 for (dwServiceCount
= 0; dwServiceCount
< *lpServicesReturned
; dwServiceCount
++)
3845 /* Copy the service name */
3846 WideCharToMultiByte(CP_ACP
,
3851 (int)wcslen(lpStringPtrW
),
3855 lpStatusPtrA
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
3856 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
3857 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
3859 /* Copy the display name */
3860 WideCharToMultiByte(CP_ACP
,
3865 (int)wcslen(lpStringPtrW
),
3869 lpStatusPtrA
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
3870 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
3871 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
3873 /* Copy the status information */
3874 memcpy(&lpStatusPtrA
->ServiceStatus
,
3875 &lpStatusPtrIncrW
->ServiceStatus
,
3876 sizeof(SERVICE_STATUS
));
3884 HeapFree(GetProcessHeap(), 0, lpStatusPtrW
);
3886 DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError
);
3893 DWORD
ROpenSCManagerA(
3894 LPSTR lpMachineName
,
3895 LPSTR lpDatabaseName
,
3896 DWORD dwDesiredAccess
,
3897 LPSC_RPC_HANDLE lpScHandle
)
3899 UNICODE_STRING MachineName
;
3900 UNICODE_STRING DatabaseName
;
3903 DPRINT("ROpenSCManagerA() called\n");
3906 RtlCreateUnicodeStringFromAsciiz(&MachineName
,
3910 RtlCreateUnicodeStringFromAsciiz(&DatabaseName
,
3913 dwError
= ROpenSCManagerW(lpMachineName
? MachineName
.Buffer
: NULL
,
3914 lpDatabaseName
? DatabaseName
.Buffer
: NULL
,
3919 RtlFreeUnicodeString(&MachineName
);
3922 RtlFreeUnicodeString(&DatabaseName
);
3929 DWORD
ROpenServiceA(
3930 SC_RPC_HANDLE hSCManager
,
3931 LPSTR lpServiceName
,
3932 DWORD dwDesiredAccess
,
3933 LPSC_RPC_HANDLE lpServiceHandle
)
3935 UNICODE_STRING ServiceName
;
3938 DPRINT("ROpenServiceA() called\n");
3941 RtlCreateUnicodeStringFromAsciiz(&ServiceName
,
3944 dwError
= ROpenServiceW(hSCManager
,
3945 lpServiceName
? ServiceName
.Buffer
: NULL
,
3950 RtlFreeUnicodeString(&ServiceName
);
3957 DWORD
RQueryServiceConfigA(
3958 SC_RPC_HANDLE hService
,
3959 LPBYTE lpBuf
, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
3961 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
3963 LPQUERY_SERVICE_CONFIGA lpServiceConfig
= (LPQUERY_SERVICE_CONFIGA
)lpBuf
;
3964 DWORD dwError
= ERROR_SUCCESS
;
3965 PSERVICE_HANDLE hSvc
;
3966 PSERVICE lpService
= NULL
;
3967 HKEY hServiceKey
= NULL
;
3968 LPWSTR lpImagePath
= NULL
;
3969 LPWSTR lpServiceStartName
= NULL
;
3970 LPWSTR lpDependencies
= NULL
;
3971 DWORD dwDependenciesLength
= 0;
3972 DWORD dwRequiredSize
;
3973 CHAR lpEmptyString
[]={0,0};
3976 DPRINT("RQueryServiceConfigA() called\n");
3979 return ERROR_SHUTDOWN_IN_PROGRESS
;
3981 hSvc
= ScmGetServiceFromHandle(hService
);
3984 DPRINT1("Invalid service handle!\n");
3985 return ERROR_INVALID_HANDLE
;
3988 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3989 SERVICE_QUERY_CONFIG
))
3991 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
3992 return ERROR_ACCESS_DENIED
;
3995 lpService
= hSvc
->ServiceEntry
;
3996 if (lpService
== NULL
)
3998 DPRINT("lpService == NULL!\n");
3999 return ERROR_INVALID_HANDLE
;
4002 /* Lock the service database shared */
4003 ScmLockDatabaseShared();
4005 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
4008 if (dwError
!= ERROR_SUCCESS
)
4011 /* Read the image path */
4012 dwError
= ScmReadString(hServiceKey
,
4015 if (dwError
!= ERROR_SUCCESS
)
4018 /* Read the service start name */
4019 ScmReadString(hServiceKey
,
4021 &lpServiceStartName
);
4023 /* Read the dependencies */
4024 ScmReadDependencies(hServiceKey
,
4026 &dwDependenciesLength
);
4028 dwRequiredSize
= sizeof(QUERY_SERVICE_CONFIGA
);
4030 if (lpImagePath
!= NULL
)
4031 dwRequiredSize
+= (DWORD
)(wcslen(lpImagePath
) + 1);
4033 dwRequiredSize
+= 2;
4035 if ((lpService
->lpGroup
!= NULL
) && (lpService
->lpGroup
->lpGroupName
!= NULL
))
4036 dwRequiredSize
+= (DWORD
)(wcslen(lpService
->lpGroup
->lpGroupName
) + 1);
4038 dwRequiredSize
+= 2;
4040 /* Add Dependencies length */
4041 if (lpDependencies
!= NULL
)
4042 dwRequiredSize
+= dwDependenciesLength
;
4044 dwRequiredSize
+= 2;
4046 if (lpServiceStartName
!= NULL
)
4047 dwRequiredSize
+= (DWORD
)(wcslen(lpServiceStartName
) + 1);
4049 dwRequiredSize
+= 2;
4051 if (lpService
->lpDisplayName
!= NULL
)
4052 dwRequiredSize
+= (DWORD
)(wcslen(lpService
->lpDisplayName
) + 1);
4054 dwRequiredSize
+= 2;
4056 if (lpServiceConfig
== NULL
|| cbBufSize
< dwRequiredSize
)
4058 dwError
= ERROR_INSUFFICIENT_BUFFER
;
4062 lpServiceConfig
->dwServiceType
= lpService
->Status
.dwServiceType
;
4063 lpServiceConfig
->dwStartType
= lpService
->dwStartType
;
4064 lpServiceConfig
->dwErrorControl
= lpService
->dwErrorControl
;
4065 lpServiceConfig
->dwTagId
= lpService
->dwTag
;
4067 lpStr
= (LPSTR
)(lpServiceConfig
+ 1);
4069 /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
4070 Verified in WINXP */
4074 WideCharToMultiByte(CP_ACP
,
4079 (int)(wcslen(lpImagePath
) + 1),
4085 strcpy(lpStr
, lpEmptyString
);
4088 lpServiceConfig
->lpBinaryPathName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4089 lpStr
+= (strlen((LPSTR
)lpStr
) + 1);
4091 if (lpService
->lpGroup
&& lpService
->lpGroup
->lpGroupName
)
4093 WideCharToMultiByte(CP_ACP
,
4095 lpService
->lpGroup
->lpGroupName
,
4098 (int)(wcslen(lpService
->lpGroup
->lpGroupName
) + 1),
4104 strcpy(lpStr
, lpEmptyString
);
4107 lpServiceConfig
->lpLoadOrderGroup
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4108 lpStr
+= (strlen(lpStr
) + 1);
4110 /* Append Dependencies */
4113 WideCharToMultiByte(CP_ACP
,
4116 dwDependenciesLength
,
4118 dwDependenciesLength
,
4124 strcpy(lpStr
, lpEmptyString
);
4127 lpServiceConfig
->lpDependencies
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4129 lpStr
+= dwDependenciesLength
;
4131 lpStr
+= (strlen(lpStr
) + 1);
4133 if (lpServiceStartName
)
4135 WideCharToMultiByte(CP_ACP
,
4140 (int)(wcslen(lpServiceStartName
) + 1),
4146 strcpy(lpStr
, lpEmptyString
);
4149 lpServiceConfig
->lpServiceStartName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4150 lpStr
+= (strlen(lpStr
) + 1);
4152 if (lpService
->lpDisplayName
)
4154 WideCharToMultiByte(CP_ACP
,
4156 lpService
->lpDisplayName
,
4159 (int)(wcslen(lpService
->lpDisplayName
) + 1),
4165 strcpy(lpStr
, lpEmptyString
);
4168 lpServiceConfig
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4171 if (pcbBytesNeeded
!= NULL
)
4172 *pcbBytesNeeded
= dwRequiredSize
;
4175 /* Unlock the service database */
4176 ScmUnlockDatabase();
4178 if (lpImagePath
!= NULL
)
4179 HeapFree(GetProcessHeap(), 0, lpImagePath
);
4181 if (lpServiceStartName
!= NULL
)
4182 HeapFree(GetProcessHeap(), 0, lpServiceStartName
);
4184 if (lpDependencies
!= NULL
)
4185 HeapFree(GetProcessHeap(), 0, lpDependencies
);
4187 if (hServiceKey
!= NULL
)
4188 RegCloseKey(hServiceKey
);
4190 DPRINT("RQueryServiceConfigA() done\n");
4197 DWORD
RQueryServiceLockStatusA(
4198 SC_RPC_HANDLE hSCManager
,
4199 LPBYTE lpBuf
, // LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
4201 LPBOUNDED_DWORD_4K pcbBytesNeeded
)
4203 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
= (LPQUERY_SERVICE_LOCK_STATUSA
)lpBuf
;
4204 PMANAGER_HANDLE hMgr
;
4205 DWORD dwRequiredSize
;
4207 if (!lpLockStatus
|| !pcbBytesNeeded
)
4208 return ERROR_INVALID_PARAMETER
;
4210 hMgr
= ScmGetServiceManagerFromHandle(hSCManager
);
4213 DPRINT1("Invalid service manager handle!\n");
4214 return ERROR_INVALID_HANDLE
;
4217 if (!RtlAreAllAccessesGranted(hMgr
->Handle
.DesiredAccess
,
4218 SC_MANAGER_QUERY_LOCK_STATUS
))
4220 DPRINT("Insufficient access rights! 0x%lx\n", hMgr
->Handle
.DesiredAccess
);
4221 return ERROR_ACCESS_DENIED
;
4224 /* FIXME: we need to compute instead the real length of the owner name */
4225 dwRequiredSize
= sizeof(QUERY_SERVICE_LOCK_STATUSA
) + sizeof(CHAR
);
4226 *pcbBytesNeeded
= dwRequiredSize
;
4228 if (cbBufSize
< dwRequiredSize
)
4229 return ERROR_INSUFFICIENT_BUFFER
;
4231 ScmQueryServiceLockStatusA(lpLockStatus
);
4233 return ERROR_SUCCESS
;
4238 DWORD
RStartServiceA(
4239 SC_RPC_HANDLE hService
,
4241 LPSTRING_PTRSA argv
)
4243 DWORD dwError
= ERROR_SUCCESS
;
4244 PSERVICE_HANDLE hSvc
;
4245 PSERVICE lpService
= NULL
;
4246 LPWSTR
*lpVector
= NULL
;
4250 DPRINT("RStartServiceA() called\n");
4253 return ERROR_SHUTDOWN_IN_PROGRESS
;
4255 hSvc
= ScmGetServiceFromHandle(hService
);
4258 DPRINT1("Invalid service handle!\n");
4259 return ERROR_INVALID_HANDLE
;
4262 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
4265 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
4266 return ERROR_ACCESS_DENIED
;
4269 lpService
= hSvc
->ServiceEntry
;
4270 if (lpService
== NULL
)
4272 DPRINT("lpService == NULL!\n");
4273 return ERROR_INVALID_HANDLE
;
4276 if (lpService
->dwStartType
== SERVICE_DISABLED
)
4277 return ERROR_SERVICE_DISABLED
;
4279 if (lpService
->bDeleted
)
4280 return ERROR_SERVICE_MARKED_FOR_DELETE
;
4282 /* Build a Unicode argument vector */
4285 lpVector
= HeapAlloc(GetProcessHeap(),
4287 argc
* sizeof(LPWSTR
));
4288 if (lpVector
== NULL
)
4289 return ERROR_NOT_ENOUGH_MEMORY
;
4291 for (i
= 0; i
< argc
; i
++)
4293 dwLength
= MultiByteToWideChar(CP_ACP
,
4300 lpVector
[i
] = HeapAlloc(GetProcessHeap(),
4302 dwLength
* sizeof(WCHAR
));
4303 if (lpVector
[i
] == NULL
)
4305 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
4309 MultiByteToWideChar(CP_ACP
,
4318 /* Start the service */
4319 dwError
= ScmStartService(lpService
, argc
, lpVector
);
4322 /* Free the Unicode argument vector */
4323 if (lpVector
!= NULL
)
4325 for (i
= 0; i
< argc
; i
++)
4327 if (lpVector
[i
] != NULL
)
4328 HeapFree(GetProcessHeap(), 0, lpVector
[i
]);
4330 HeapFree(GetProcessHeap(), 0, lpVector
);
4338 DWORD
RGetServiceDisplayNameA(
4339 SC_RPC_HANDLE hSCManager
,
4340 LPCSTR lpServiceName
,
4341 LPSTR lpDisplayName
,
4342 LPBOUNDED_DWORD_4K lpcchBuffer
)
4344 // PMANAGER_HANDLE hManager;
4345 PSERVICE lpService
= NULL
;
4348 LPWSTR lpServiceNameW
;
4350 DPRINT("RGetServiceDisplayNameA() called\n");
4351 DPRINT("hSCManager = %p\n", hSCManager
);
4352 DPRINT("lpServiceName: %s\n", lpServiceName
);
4353 DPRINT("lpDisplayName: %p\n", lpDisplayName
);
4354 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
4356 // hManager = (PMANAGER_HANDLE)hSCManager;
4357 // if (hManager->Handle.Tag != MANAGER_TAG)
4359 // DPRINT("Invalid manager handle!\n");
4360 // return ERROR_INVALID_HANDLE;
4363 if (lpServiceName
!= NULL
)
4365 dwLength
= (DWORD
)(strlen(lpServiceName
) + 1);
4366 lpServiceNameW
= HeapAlloc(GetProcessHeap(),
4368 dwLength
* sizeof(WCHAR
));
4369 if (!lpServiceNameW
)
4370 return ERROR_NOT_ENOUGH_MEMORY
;
4372 MultiByteToWideChar(CP_ACP
,
4379 lpService
= ScmGetServiceEntryByName(lpServiceNameW
);
4381 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
4384 if (lpService
== NULL
)
4386 DPRINT("Could not find a service!\n");
4388 /* If the service could not be found and lpcchBuffer is 0, windows
4389 puts null in lpDisplayName and puts 1 in lpcchBuffer */
4390 if (*lpcchBuffer
== 0)
4393 if (lpDisplayName
!= NULL
)
4398 return ERROR_SERVICE_DOES_NOT_EXIST
;
4401 if (!lpService
->lpDisplayName
)
4403 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
4404 if (lpDisplayName
!= NULL
&&
4405 *lpcchBuffer
> dwLength
)
4407 WideCharToMultiByte(CP_ACP
,
4409 lpService
->lpServiceName
,
4410 (int)wcslen(lpService
->lpServiceName
),
4415 return ERROR_SUCCESS
;
4420 dwLength
= (DWORD
)wcslen(lpService
->lpDisplayName
);
4421 if (lpDisplayName
!= NULL
&&
4422 *lpcchBuffer
> dwLength
)
4424 WideCharToMultiByte(CP_ACP
,
4426 lpService
->lpDisplayName
,
4427 (int)wcslen(lpService
->lpDisplayName
),
4432 return ERROR_SUCCESS
;
4436 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
4438 *lpcchBuffer
= dwLength
* 2;
4445 DWORD
RGetServiceKeyNameA(
4446 SC_RPC_HANDLE hSCManager
,
4447 LPCSTR lpDisplayName
,
4448 LPSTR lpServiceName
,
4449 LPBOUNDED_DWORD_4K lpcchBuffer
)
4454 LPWSTR lpDisplayNameW
;
4456 DPRINT("RGetServiceKeyNameA() called\n");
4457 DPRINT("hSCManager = %p\n", hSCManager
);
4458 DPRINT("lpDisplayName: %s\n", lpDisplayName
);
4459 DPRINT("lpServiceName: %p\n", lpServiceName
);
4460 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
4462 dwLength
= (DWORD
)(strlen(lpDisplayName
) + 1);
4463 lpDisplayNameW
= HeapAlloc(GetProcessHeap(),
4465 dwLength
* sizeof(WCHAR
));
4466 if (!lpDisplayNameW
)
4467 return ERROR_NOT_ENOUGH_MEMORY
;
4469 MultiByteToWideChar(CP_ACP
,
4476 lpService
= ScmGetServiceEntryByDisplayName(lpDisplayNameW
);
4478 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
4480 if (lpService
== NULL
)
4482 DPRINT("Could not find the service!\n");
4484 /* If the service could not be found and lpcchBuffer is 0,
4485 put null in lpDisplayName and puts 1 in lpcchBuffer, verified WINXP. */
4486 if (*lpcchBuffer
== 0)
4489 if (lpServiceName
!= NULL
)
4495 return ERROR_SERVICE_DOES_NOT_EXIST
;
4498 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
4499 if (lpServiceName
!= NULL
&&
4500 *lpcchBuffer
> dwLength
)
4502 WideCharToMultiByte(CP_ACP
,
4504 lpService
->lpServiceName
,
4505 (int)wcslen(lpService
->lpServiceName
),
4510 return ERROR_SUCCESS
;
4513 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
4515 *lpcchBuffer
= dwLength
* 2;
4522 DWORD
RI_ScGetCurrentGroupStateW(
4523 SC_RPC_HANDLE hSCManager
,
4524 LPWSTR lpLoadOrderGroup
,
4528 return ERROR_CALL_NOT_IMPLEMENTED
;
4533 DWORD
REnumServiceGroupW(
4534 SC_RPC_HANDLE hSCManager
,
4535 DWORD dwServiceType
,
4536 DWORD dwServiceState
,
4539 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
4540 LPBOUNDED_DWORD_256K lpServicesReturned
,
4541 LPBOUNDED_DWORD_256K lpResumeIndex
,
4542 LPCWSTR pszGroupName
)
4544 PMANAGER_HANDLE hManager
;
4546 DWORD dwError
= ERROR_SUCCESS
;
4547 PLIST_ENTRY ServiceEntry
;
4548 PSERVICE CurrentService
;
4550 DWORD dwRequiredSize
;
4551 DWORD dwServiceCount
;
4553 DWORD dwLastResumeCount
= 0;
4554 LPENUM_SERVICE_STATUSW lpStatusPtr
;
4557 DPRINT("REnumServiceGroupW() called\n");
4560 return ERROR_SHUTDOWN_IN_PROGRESS
;
4562 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
4563 if (hManager
== NULL
)
4565 DPRINT1("Invalid service manager handle!\n");
4566 return ERROR_INVALID_HANDLE
;
4569 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
4571 return ERROR_INVALID_ADDRESS
;
4574 *pcbBytesNeeded
= 0;
4575 *lpServicesReturned
= 0;
4577 if ((dwServiceType
== 0) ||
4578 ((dwServiceType
& ~SERVICE_TYPE_ALL
) != 0))
4580 DPRINT("Not a valid Service Type!\n");
4581 return ERROR_INVALID_PARAMETER
;
4584 if ((dwServiceState
== 0) ||
4585 ((dwServiceState
& ~SERVICE_STATE_ALL
) != 0))
4587 DPRINT("Not a valid Service State!\n");
4588 return ERROR_INVALID_PARAMETER
;
4591 /* Check access rights */
4592 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
4593 SC_MANAGER_ENUMERATE_SERVICE
))
4595 DPRINT("Insufficient access rights! 0x%lx\n",
4596 hManager
->Handle
.DesiredAccess
);
4597 return ERROR_ACCESS_DENIED
;
4601 dwLastResumeCount
= *lpResumeIndex
;
4603 /* Lock the service database shared */
4604 ScmLockDatabaseShared();
4606 lpService
= ScmGetServiceEntryByResumeCount(dwLastResumeCount
);
4607 if (lpService
== NULL
)
4609 dwError
= ERROR_SUCCESS
;
4616 for (ServiceEntry
= &lpService
->ServiceListEntry
;
4617 ServiceEntry
!= &ServiceListHead
;
4618 ServiceEntry
= ServiceEntry
->Flink
)
4620 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
4624 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
4627 dwState
= SERVICE_ACTIVE
;
4628 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
4629 dwState
= SERVICE_INACTIVE
;
4631 if ((dwState
& dwServiceState
) == 0)
4636 if (*pszGroupName
== 0)
4638 if (CurrentService
->lpGroup
!= NULL
)
4643 if ((CurrentService
->lpGroup
== NULL
) ||
4644 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
4649 dwSize
= sizeof(ENUM_SERVICE_STATUSW
) +
4650 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
4651 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
4653 if (dwRequiredSize
+ dwSize
> cbBufSize
)
4655 DPRINT("Service name: %S no fit\n", CurrentService
->lpServiceName
);
4659 DPRINT("Service name: %S fit\n", CurrentService
->lpServiceName
);
4660 dwRequiredSize
+= dwSize
;
4662 dwLastResumeCount
= CurrentService
->dwResumeCount
;
4665 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize
);
4666 DPRINT("dwServiceCount: %lu\n", dwServiceCount
);
4669 ServiceEntry
!= &ServiceListHead
;
4670 ServiceEntry
= ServiceEntry
->Flink
)
4672 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
4676 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
4679 dwState
= SERVICE_ACTIVE
;
4680 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
4681 dwState
= SERVICE_INACTIVE
;
4683 if ((dwState
& dwServiceState
) == 0)
4688 if (*pszGroupName
== 0)
4690 if (CurrentService
->lpGroup
!= NULL
)
4695 if ((CurrentService
->lpGroup
== NULL
) ||
4696 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
4701 dwRequiredSize
+= (sizeof(ENUM_SERVICE_STATUSW
) +
4702 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
4703 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
)));
4705 dwError
= ERROR_MORE_DATA
;
4708 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize
);
4711 *lpResumeIndex
= dwLastResumeCount
;
4713 *lpServicesReturned
= dwServiceCount
;
4714 *pcbBytesNeeded
= dwRequiredSize
;
4716 lpStatusPtr
= (LPENUM_SERVICE_STATUSW
)lpBuffer
;
4717 lpStringPtr
= (LPWSTR
)((ULONG_PTR
)lpBuffer
+
4718 dwServiceCount
* sizeof(ENUM_SERVICE_STATUSW
));
4721 for (ServiceEntry
= &lpService
->ServiceListEntry
;
4722 ServiceEntry
!= &ServiceListHead
;
4723 ServiceEntry
= ServiceEntry
->Flink
)
4725 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
4729 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
4732 dwState
= SERVICE_ACTIVE
;
4733 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
4734 dwState
= SERVICE_INACTIVE
;
4736 if ((dwState
& dwServiceState
) == 0)
4741 if (*pszGroupName
== 0)
4743 if (CurrentService
->lpGroup
!= NULL
)
4748 if ((CurrentService
->lpGroup
== NULL
) ||
4749 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
4754 dwSize
= sizeof(ENUM_SERVICE_STATUSW
) +
4755 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
4756 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
4758 if (dwRequiredSize
+ dwSize
> cbBufSize
)
4761 /* Copy the service name */
4762 wcscpy(lpStringPtr
, CurrentService
->lpServiceName
);
4763 lpStatusPtr
->lpServiceName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
4764 lpStringPtr
+= (wcslen(CurrentService
->lpServiceName
) + 1);
4766 /* Copy the display name */
4767 wcscpy(lpStringPtr
, CurrentService
->lpDisplayName
);
4768 lpStatusPtr
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
4769 lpStringPtr
+= (wcslen(CurrentService
->lpDisplayName
) + 1);
4771 /* Copy the status information */
4772 memcpy(&lpStatusPtr
->ServiceStatus
,
4773 &CurrentService
->Status
,
4774 sizeof(SERVICE_STATUS
));
4777 dwRequiredSize
+= dwSize
;
4780 if (dwError
== ERROR_SUCCESS
)
4782 *pcbBytesNeeded
= 0;
4783 if (lpResumeIndex
) *lpResumeIndex
= 0;
4787 /* Unlock the service database */
4788 ScmUnlockDatabase();
4790 DPRINT("REnumServiceGroupW() done (Error %lu)\n", dwError
);
4797 DWORD
RChangeServiceConfig2A(
4798 SC_RPC_HANDLE hService
,
4799 SC_RPC_CONFIG_INFOA Info
)
4801 SC_RPC_CONFIG_INFOW InfoW
;
4802 DWORD dwRet
, dwLength
;
4805 DPRINT("RChangeServiceConfig2A() called\n");
4806 DPRINT("dwInfoLevel = %lu\n", Info
.dwInfoLevel
);
4808 InfoW
.dwInfoLevel
= Info
.dwInfoLevel
;
4810 if (InfoW
.dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
4812 LPSERVICE_DESCRIPTIONW lpServiceDescriptionW
;
4813 //LPSERVICE_DESCRIPTIONA lpServiceDescriptionA;
4815 //lpServiceDescriptionA = Info.psd;
4817 ///if (lpServiceDescriptionA &&
4818 ///lpServiceDescriptionA->lpDescription)
4820 dwLength
= (DWORD
)((strlen(Info
.lpDescription
) + 1) * sizeof(WCHAR
));
4822 lpServiceDescriptionW
= HeapAlloc(GetProcessHeap(),
4824 dwLength
+ sizeof(SERVICE_DESCRIPTIONW
));
4825 if (!lpServiceDescriptionW
)
4827 return ERROR_NOT_ENOUGH_MEMORY
;
4830 lpServiceDescriptionW
->lpDescription
= (LPWSTR
)(lpServiceDescriptionW
+ 1);
4832 MultiByteToWideChar(CP_ACP
,
4836 lpServiceDescriptionW
->lpDescription
,
4839 ptr
= lpServiceDescriptionW
;
4840 InfoW
.psd
= lpServiceDescriptionW
;
4843 else if (Info
.dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
4845 LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW
;
4846 LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA
;
4847 DWORD dwRebootLen
= 0;
4848 DWORD dwCommandLen
= 0;
4849 DWORD dwActionArrayLen
= 0;
4850 LPWSTR lpStr
= NULL
;
4852 lpServiceFailureActionsA
= Info
.psfa
;
4854 if (lpServiceFailureActionsA
)
4857 * The following code is inspired by the
4858 * SERVICE_CONFIG_FAILURE_ACTIONS case of
4859 * the RQueryServiceConfig2W function.
4862 /* Retrieve the needed length for the two data strings */
4863 if (lpServiceFailureActionsA
->lpRebootMsg
)
4865 dwRebootLen
= (DWORD
)((strlen(lpServiceFailureActionsA
->lpRebootMsg
) + 1) * sizeof(WCHAR
));
4867 if (lpServiceFailureActionsA
->lpCommand
)
4869 dwCommandLen
= (DWORD
)((strlen(lpServiceFailureActionsA
->lpCommand
) + 1) * sizeof(WCHAR
));
4873 * Retrieve the size of the lpsaActions array if needed.
4874 * We will copy the lpsaActions array only if there is at
4875 * least one action AND that the original array is valid.
4877 if (lpServiceFailureActionsA
->cActions
> 0 && lpServiceFailureActionsA
->lpsaActions
)
4879 dwActionArrayLen
= lpServiceFailureActionsA
->cActions
* sizeof(SC_ACTION
);
4882 /* Compute the total length for the UNICODE structure, including data */
4883 dwLength
= sizeof(SERVICE_FAILURE_ACTIONSW
) +
4884 dwActionArrayLen
+ dwRebootLen
+ dwCommandLen
;
4886 /* Allocate the structure */
4887 lpServiceFailureActionsW
= HeapAlloc(GetProcessHeap(),
4890 if (!lpServiceFailureActionsW
)
4892 return ERROR_NOT_ENOUGH_MEMORY
;
4895 /* Copy the members */
4896 lpServiceFailureActionsW
->dwResetPeriod
= lpServiceFailureActionsA
->dwResetPeriod
;
4897 lpServiceFailureActionsW
->cActions
= lpServiceFailureActionsA
->cActions
;
4899 /* Copy the lpsaActions array if needed */
4900 if (dwActionArrayLen
> 0)
4902 /* The storage zone is just after the end of the SERVICE_FAILURE_ACTIONSW structure */
4903 lpServiceFailureActionsW
->lpsaActions
= (LPSC_ACTION
)((ULONG_PTR
)(lpServiceFailureActionsW
+ 1));
4905 /* dwActionArrayLen == lpServiceFailureActionsW->cActions * sizeof(SC_ACTION) */
4906 RtlCopyMemory(lpServiceFailureActionsW
->lpsaActions
,
4907 lpServiceFailureActionsA
->lpsaActions
,
4912 /* No lpsaActions array */
4913 lpServiceFailureActionsW
->lpsaActions
= NULL
;
4915 /* The data strings are stored just after the lpsaActions array */
4916 lpStr
= (LPWSTR
)((ULONG_PTR
)(lpServiceFailureActionsW
+ 1) + dwActionArrayLen
);
4919 * Convert the data strings to UNICODE
4922 lpServiceFailureActionsW
->lpRebootMsg
= NULL
;
4923 lpServiceFailureActionsW
->lpCommand
= NULL
;
4927 /* lpRebootMsg points just after the lpsaActions array */
4928 lpServiceFailureActionsW
->lpRebootMsg
= lpStr
;
4930 MultiByteToWideChar(CP_ACP
,
4932 lpServiceFailureActionsA
->lpRebootMsg
,
4934 lpServiceFailureActionsW
->lpRebootMsg
,
4937 lpStr
+= dwRebootLen
/ sizeof(WCHAR
);
4942 /* lpRebootMsg points just after the lpRebootMsg data string */
4943 lpServiceFailureActionsW
->lpCommand
= lpStr
;
4945 MultiByteToWideChar(CP_ACP
,
4947 lpServiceFailureActionsA
->lpCommand
,
4949 lpServiceFailureActionsW
->lpCommand
,
4953 /* Set the pointers */
4954 ptr
= lpServiceFailureActionsW
;
4955 InfoW
.psfa
= lpServiceFailureActionsW
;
4959 dwRet
= RChangeServiceConfig2W(hService
, InfoW
);
4961 HeapFree(GetProcessHeap(), 0, ptr
);
4968 ScmSetFailureActions(PSERVICE_HANDLE hSvc
,
4971 LPSERVICE_FAILURE_ACTIONSW lpFailureActions
)
4973 LPSERVICE_FAILURE_ACTIONSW lpReadBuffer
= NULL
;
4974 LPSERVICE_FAILURE_ACTIONSW lpWriteBuffer
= NULL
;
4975 BOOL bIsActionRebootSet
= FALSE
;
4976 DWORD dwDesiredAccess
= SERVICE_CHANGE_CONFIG
;
4977 DWORD dwRequiredSize
= 0;
4982 /* There is nothing to be done if we have no failure actions */
4983 if (lpFailureActions
== NULL
)
4984 return ERROR_SUCCESS
;
4987 * 1- Check whether or not we can set
4988 * failure actions for this service.
4991 /* Failure actions can only be set for Win32 services, not for drivers */
4992 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
4993 return ERROR_CANNOT_DETECT_DRIVER_FAILURE
;
4996 * If the service controller handles the SC_ACTION_RESTART action,
4997 * hService must have the SERVICE_START access right.
4999 * If you specify SC_ACTION_REBOOT, the caller must have the
5000 * SE_SHUTDOWN_NAME privilege.
5002 if (lpFailureActions
->cActions
> 0 &&
5003 lpFailureActions
->lpsaActions
!= NULL
)
5005 for (i
= 0; i
< lpFailureActions
->cActions
; ++i
)
5007 if (lpFailureActions
->lpsaActions
[i
].Type
== SC_ACTION_RESTART
)
5008 dwDesiredAccess
|= SERVICE_START
;
5009 else if (lpFailureActions
->lpsaActions
[i
].Type
== SC_ACTION_REBOOT
)
5010 bIsActionRebootSet
= TRUE
;
5014 /* Re-check the access rights */
5015 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5018 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5019 return ERROR_ACCESS_DENIED
;
5022 /* FIXME: Check if the caller has the SE_SHUTDOWN_NAME privilege */
5023 if (bIsActionRebootSet
)
5028 * 2- Retrieve the original value of FailureActions.
5031 /* Query value length */
5032 dwError
= RegQueryValueExW(hServiceKey
,
5038 if (dwError
!= ERROR_SUCCESS
&&
5039 dwError
!= ERROR_MORE_DATA
&&
5040 dwError
!= ERROR_FILE_NOT_FOUND
)
5043 dwRequiredSize
= (dwType
== REG_BINARY
) ? max(sizeof(SERVICE_FAILURE_ACTIONSW
), dwRequiredSize
)
5044 : sizeof(SERVICE_FAILURE_ACTIONSW
);
5046 /* Initialize the read buffer */
5047 lpReadBuffer
= HeapAlloc(GetProcessHeap(),
5050 if (lpReadBuffer
== NULL
)
5051 return ERROR_NOT_ENOUGH_MEMORY
;
5053 /* Now we can fill the read buffer */
5054 if (dwError
!= ERROR_FILE_NOT_FOUND
&&
5055 dwType
== REG_BINARY
)
5057 dwError
= RegQueryValueExW(hServiceKey
,
5061 (LPBYTE
)lpReadBuffer
,
5063 if (dwError
!= ERROR_SUCCESS
&&
5064 dwError
!= ERROR_FILE_NOT_FOUND
)
5067 if (dwRequiredSize
< sizeof(SERVICE_FAILURE_ACTIONSW
))
5068 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSW
);
5073 * The value of the error doesn't really matter, the only
5074 * important thing is that it must be != ERROR_SUCCESS.
5076 dwError
= ERROR_INVALID_DATA
;
5079 if (dwError
== ERROR_SUCCESS
)
5081 lpReadBuffer
->cActions
= min(lpReadBuffer
->cActions
, (dwRequiredSize
- sizeof(SERVICE_FAILURE_ACTIONSW
)) / sizeof(SC_ACTION
));
5082 lpReadBuffer
->lpsaActions
= (lpReadBuffer
->cActions
> 0 ? (LPSC_ACTION
)(lpReadBuffer
+ 1) : NULL
);
5086 lpReadBuffer
->dwResetPeriod
= 0;
5087 lpReadBuffer
->cActions
= 0;
5088 lpReadBuffer
->lpsaActions
= NULL
;
5091 lpReadBuffer
->lpRebootMsg
= NULL
;
5092 lpReadBuffer
->lpCommand
= NULL
;
5095 * 3- Initialize the new value to set.
5098 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSW
);
5100 if (lpFailureActions
->lpsaActions
== NULL
)
5103 * lpFailureActions->cActions is ignored.
5104 * Therefore we use the original values
5105 * of cActions and lpsaActions.
5107 dwRequiredSize
+= lpReadBuffer
->cActions
* sizeof(SC_ACTION
);
5112 * The reset period and array of failure actions
5113 * are deleted if lpFailureActions->cActions == 0 .
5115 dwRequiredSize
+= lpFailureActions
->cActions
* sizeof(SC_ACTION
);
5118 lpWriteBuffer
= HeapAlloc(GetProcessHeap(),
5121 if (lpWriteBuffer
== NULL
)
5123 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
5127 /* Clean the pointers as they have no meaning when the structure is stored in the registry */
5128 lpWriteBuffer
->lpRebootMsg
= NULL
;
5129 lpWriteBuffer
->lpCommand
= NULL
;
5130 lpWriteBuffer
->lpsaActions
= NULL
;
5132 /* Set the members */
5133 if (lpFailureActions
->lpsaActions
== NULL
)
5136 * lpFailureActions->dwResetPeriod and lpFailureActions->cActions are ignored.
5137 * Therefore we use the original values of dwResetPeriod, cActions and lpsaActions.
5139 lpWriteBuffer
->dwResetPeriod
= lpReadBuffer
->dwResetPeriod
;
5140 lpWriteBuffer
->cActions
= lpReadBuffer
->cActions
;
5142 if (lpReadBuffer
->lpsaActions
!= NULL
)
5144 memmove(lpWriteBuffer
+ 1,
5145 lpReadBuffer
->lpsaActions
,
5146 lpReadBuffer
->cActions
* sizeof(SC_ACTION
));
5151 if (lpFailureActions
->cActions
> 0)
5153 lpWriteBuffer
->dwResetPeriod
= lpFailureActions
->dwResetPeriod
;
5154 lpWriteBuffer
->cActions
= lpFailureActions
->cActions
;
5156 memmove(lpWriteBuffer
+ 1,
5157 lpFailureActions
->lpsaActions
,
5158 lpFailureActions
->cActions
* sizeof(SC_ACTION
));
5162 /* The reset period and array of failure actions are deleted */
5163 lpWriteBuffer
->dwResetPeriod
= 0;
5164 lpWriteBuffer
->cActions
= 0;
5168 /* Save the new failure actions into the registry */
5169 dwError
= RegSetValueExW(hServiceKey
,
5173 (LPBYTE
)lpWriteBuffer
,
5176 /* We modify the strings only in case of success.*/
5177 if (dwError
== ERROR_SUCCESS
)
5179 /* Modify the Reboot Message value, if specified */
5180 if (lpFailureActions
->lpRebootMsg
!= NULL
)
5182 /* If the Reboot Message is "" then we delete it */
5183 if (*lpFailureActions
->lpRebootMsg
== 0)
5185 DPRINT("Delete Reboot Message value\n");
5186 RegDeleteValueW(hServiceKey
, L
"RebootMessage");
5190 DPRINT("Setting Reboot Message value %S\n", lpFailureActions
->lpRebootMsg
);
5191 RegSetValueExW(hServiceKey
,
5195 (LPBYTE
)lpFailureActions
->lpRebootMsg
,
5196 (DWORD
)((wcslen(lpFailureActions
->lpRebootMsg
) + 1) * sizeof(WCHAR
)));
5200 /* Modify the Failure Command value, if specified */
5201 if (lpFailureActions
->lpCommand
!= NULL
)
5203 /* If the FailureCommand string is an empty string, delete the value */
5204 if (*lpFailureActions
->lpCommand
== 0)
5206 DPRINT("Delete Failure Command value\n");
5207 RegDeleteValueW(hServiceKey
, L
"FailureCommand");
5211 DPRINT("Setting Failure Command value %S\n", lpFailureActions
->lpCommand
);
5212 RegSetValueExW(hServiceKey
,
5216 (LPBYTE
)lpFailureActions
->lpCommand
,
5217 (DWORD
)((wcslen(lpFailureActions
->lpCommand
) + 1) * sizeof(WCHAR
)));
5223 if (lpWriteBuffer
!= NULL
)
5224 HeapFree(GetProcessHeap(), 0, lpWriteBuffer
);
5226 if (lpReadBuffer
!= NULL
)
5227 HeapFree(GetProcessHeap(), 0, lpReadBuffer
);
5234 DWORD
RChangeServiceConfig2W(
5235 SC_RPC_HANDLE hService
,
5236 SC_RPC_CONFIG_INFOW Info
)
5238 DWORD dwError
= ERROR_SUCCESS
;
5239 PSERVICE_HANDLE hSvc
;
5240 PSERVICE lpService
= NULL
;
5241 HKEY hServiceKey
= NULL
;
5243 DPRINT("RChangeServiceConfig2W() called\n");
5244 DPRINT("dwInfoLevel = %lu\n", Info
.dwInfoLevel
);
5247 return ERROR_SHUTDOWN_IN_PROGRESS
;
5249 hSvc
= ScmGetServiceFromHandle(hService
);
5252 DPRINT1("Invalid service handle!\n");
5253 return ERROR_INVALID_HANDLE
;
5256 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5257 SERVICE_CHANGE_CONFIG
))
5259 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5260 return ERROR_ACCESS_DENIED
;
5263 lpService
= hSvc
->ServiceEntry
;
5264 if (lpService
== NULL
)
5266 DPRINT("lpService == NULL!\n");
5267 return ERROR_INVALID_HANDLE
;
5270 /* Lock the service database exclusively */
5271 ScmLockDatabaseExclusive();
5273 if (lpService
->bDeleted
)
5275 DPRINT("The service has already been marked for delete!\n");
5276 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
5280 /* Open the service key */
5281 dwError
= ScmOpenServiceKey(lpService
->szServiceName
,
5282 KEY_READ
| KEY_SET_VALUE
,
5284 if (dwError
!= ERROR_SUCCESS
)
5287 if (Info
.dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
5289 LPSERVICE_DESCRIPTIONW lpServiceDescription
= (LPSERVICE_DESCRIPTIONW
)Info
.psd
;
5291 /* Modify the service description, if specified */
5292 if (lpServiceDescription
!= NULL
&&
5293 lpServiceDescription
->lpDescription
!= NULL
)
5295 /* If the description is "" then we delete it */
5296 if (*lpServiceDescription
->lpDescription
== 0)
5298 DPRINT("Delete service description\n");
5299 dwError
= RegDeleteValueW(hServiceKey
, L
"Description");
5301 if (dwError
== ERROR_FILE_NOT_FOUND
)
5302 dwError
= ERROR_SUCCESS
;
5306 DPRINT("Setting service description value %S\n", lpServiceDescription
->lpDescription
);
5307 dwError
= RegSetValueExW(hServiceKey
,
5311 (LPBYTE
)lpServiceDescription
->lpDescription
,
5312 (DWORD
)((wcslen(lpServiceDescription
->lpDescription
) + 1) * sizeof(WCHAR
)));
5317 dwError
= ERROR_SUCCESS
;
5320 else if (Info
.dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5322 dwError
= ScmSetFailureActions(hSvc
,
5325 (LPSERVICE_FAILURE_ACTIONSW
)Info
.psfa
);
5329 if (hServiceKey
!= NULL
)
5330 RegCloseKey(hServiceKey
);
5332 /* Unlock the service database */
5333 ScmUnlockDatabase();
5335 DPRINT("RChangeServiceConfig2W() done (Error %lu)\n", dwError
);
5342 DWORD
RQueryServiceConfig2A(
5343 SC_RPC_HANDLE hService
,
5347 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
5349 DWORD dwError
= ERROR_SUCCESS
;
5350 PSERVICE_HANDLE hSvc
;
5351 PSERVICE lpService
= NULL
;
5352 HKEY hServiceKey
= NULL
;
5353 DWORD dwRequiredSize
= 0;
5355 LPWSTR lpDescriptionW
= NULL
;
5356 LPWSTR lpRebootMessageW
= NULL
;
5357 LPWSTR lpFailureCommandW
= NULL
;
5359 DPRINT("RQueryServiceConfig2A() called hService %p dwInfoLevel %u, lpBuffer %p cbBufSize %u pcbBytesNeeded %p\n",
5360 hService
, dwInfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
5363 return ERROR_INVALID_ADDRESS
;
5366 return ERROR_SHUTDOWN_IN_PROGRESS
;
5368 hSvc
= ScmGetServiceFromHandle(hService
);
5371 DPRINT1("Invalid service handle!\n");
5372 return ERROR_INVALID_HANDLE
;
5375 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5376 SERVICE_QUERY_CONFIG
))
5378 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5379 return ERROR_ACCESS_DENIED
;
5382 lpService
= hSvc
->ServiceEntry
;
5383 if (lpService
== NULL
)
5385 DPRINT("lpService == NULL!\n");
5386 return ERROR_INVALID_HANDLE
;
5389 /* Lock the service database shared */
5390 ScmLockDatabaseShared();
5392 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
5395 if (dwError
!= ERROR_SUCCESS
)
5398 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
5400 LPSERVICE_DESCRIPTIONA lpServiceDescription
= (LPSERVICE_DESCRIPTIONA
)lpBuffer
;
5403 dwError
= ScmReadString(hServiceKey
,
5406 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5409 *pcbBytesNeeded
= sizeof(SERVICE_DESCRIPTIONA
);
5410 if (dwError
== ERROR_SUCCESS
)
5411 *pcbBytesNeeded
+= (DWORD
)((wcslen(lpDescriptionW
) + 1) * sizeof(WCHAR
));
5413 if (cbBufSize
< *pcbBytesNeeded
)
5415 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5419 if (dwError
== ERROR_SUCCESS
)
5421 lpStr
= (LPSTR
)(lpServiceDescription
+ 1);
5423 WideCharToMultiByte(CP_ACP
,
5428 (int)wcslen(lpDescriptionW
),
5431 lpServiceDescription
->lpDescription
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceDescription
);
5435 lpServiceDescription
->lpDescription
= NULL
;
5436 dwError
= ERROR_SUCCESS
;
5439 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5441 LPSERVICE_FAILURE_ACTIONSA lpFailureActions
= (LPSERVICE_FAILURE_ACTIONSA
)lpBuffer
;
5444 /* Query value length */
5445 dwError
= RegQueryValueExW(hServiceKey
,
5451 if (dwError
!= ERROR_SUCCESS
&&
5452 dwError
!= ERROR_MORE_DATA
&&
5453 dwError
!= ERROR_FILE_NOT_FOUND
)
5456 dwRequiredSize
= (dwType
== REG_BINARY
) ? max(sizeof(SERVICE_FAILURE_ACTIONSA
), dwRequiredSize
)
5457 : sizeof(SERVICE_FAILURE_ACTIONSA
);
5459 /* Get the strings */
5460 ScmReadString(hServiceKey
,
5462 &lpFailureCommandW
);
5464 ScmReadString(hServiceKey
,
5468 if (lpRebootMessageW
)
5469 dwRequiredSize
+= (DWORD
)((wcslen(lpRebootMessageW
) + 1) * sizeof(WCHAR
));
5471 if (lpFailureCommandW
)
5472 dwRequiredSize
+= (DWORD
)((wcslen(lpFailureCommandW
) + 1) * sizeof(WCHAR
));
5474 if (cbBufSize
< dwRequiredSize
)
5476 *pcbBytesNeeded
= dwRequiredSize
;
5477 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5481 /* Now we can fill the buffer */
5482 if (dwError
!= ERROR_FILE_NOT_FOUND
&& dwType
== REG_BINARY
)
5484 dwError
= RegQueryValueExW(hServiceKey
,
5488 (LPBYTE
)lpFailureActions
,
5490 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5493 if (dwRequiredSize
< sizeof(SERVICE_FAILURE_ACTIONSA
))
5494 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSA
);
5499 * The value of the error doesn't really matter, the only
5500 * important thing is that it must be != ERROR_SUCCESS .
5502 dwError
= ERROR_INVALID_DATA
;
5505 if (dwError
== ERROR_SUCCESS
)
5507 lpFailureActions
->cActions
= min(lpFailureActions
->cActions
, (dwRequiredSize
- sizeof(SERVICE_FAILURE_ACTIONSA
)) / sizeof(SC_ACTION
));
5509 /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */
5510 lpFailureActions
->lpsaActions
= (lpFailureActions
->cActions
> 0 ? (LPSC_ACTION
)(ULONG_PTR
)sizeof(SERVICE_FAILURE_ACTIONSA
) : NULL
);
5512 lpStr
= (LPSTR
)((ULONG_PTR
)(lpFailureActions
+ 1) + lpFailureActions
->cActions
* sizeof(SC_ACTION
));
5516 lpFailureActions
->dwResetPeriod
= 0;
5517 lpFailureActions
->cActions
= 0;
5518 lpFailureActions
->lpsaActions
= NULL
;
5519 lpStr
= (LPSTR
)(lpFailureActions
+ 1);
5522 lpFailureActions
->lpRebootMsg
= NULL
;
5523 lpFailureActions
->lpCommand
= NULL
;
5525 if (lpRebootMessageW
)
5527 WideCharToMultiByte(CP_ACP
,
5532 (int)wcslen(lpRebootMessageW
),
5535 lpFailureActions
->lpRebootMsg
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5536 lpStr
+= strlen(lpStr
) + 1;
5539 if (lpFailureCommandW
)
5541 WideCharToMultiByte(CP_ACP
,
5546 (int)wcslen(lpFailureCommandW
),
5549 lpFailureActions
->lpCommand
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5550 /* lpStr += strlen(lpStr) + 1; */
5553 dwError
= ERROR_SUCCESS
;
5557 /* Unlock the service database */
5558 ScmUnlockDatabase();
5560 if (lpDescriptionW
!= NULL
)
5561 HeapFree(GetProcessHeap(), 0, lpDescriptionW
);
5563 if (lpRebootMessageW
!= NULL
)
5564 HeapFree(GetProcessHeap(), 0, lpRebootMessageW
);
5566 if (lpFailureCommandW
!= NULL
)
5567 HeapFree(GetProcessHeap(), 0, lpFailureCommandW
);
5569 if (hServiceKey
!= NULL
)
5570 RegCloseKey(hServiceKey
);
5572 DPRINT("RQueryServiceConfig2A() done (Error %lu)\n", dwError
);
5579 DWORD
RQueryServiceConfig2W(
5580 SC_RPC_HANDLE hService
,
5584 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
5586 DWORD dwError
= ERROR_SUCCESS
;
5587 PSERVICE_HANDLE hSvc
;
5588 PSERVICE lpService
= NULL
;
5589 HKEY hServiceKey
= NULL
;
5590 DWORD dwRequiredSize
= 0;
5592 LPWSTR lpDescription
= NULL
;
5593 LPWSTR lpRebootMessage
= NULL
;
5594 LPWSTR lpFailureCommand
= NULL
;
5596 DPRINT("RQueryServiceConfig2W() called\n");
5599 return ERROR_INVALID_ADDRESS
;
5602 return ERROR_SHUTDOWN_IN_PROGRESS
;
5604 hSvc
= ScmGetServiceFromHandle(hService
);
5607 DPRINT1("Invalid service handle!\n");
5608 return ERROR_INVALID_HANDLE
;
5611 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5612 SERVICE_QUERY_CONFIG
))
5614 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5615 return ERROR_ACCESS_DENIED
;
5618 lpService
= hSvc
->ServiceEntry
;
5619 if (lpService
== NULL
)
5621 DPRINT("lpService == NULL!\n");
5622 return ERROR_INVALID_HANDLE
;
5625 /* Lock the service database shared */
5626 ScmLockDatabaseShared();
5628 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
5631 if (dwError
!= ERROR_SUCCESS
)
5634 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
5636 LPSERVICE_DESCRIPTIONW lpServiceDescription
= (LPSERVICE_DESCRIPTIONW
)lpBuffer
;
5639 dwError
= ScmReadString(hServiceKey
,
5642 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5645 *pcbBytesNeeded
= sizeof(SERVICE_DESCRIPTIONW
);
5646 if (dwError
== ERROR_SUCCESS
)
5647 *pcbBytesNeeded
+= (DWORD
)((wcslen(lpDescription
) + 1) * sizeof(WCHAR
));
5649 if (cbBufSize
< *pcbBytesNeeded
)
5651 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5655 if (dwError
== ERROR_SUCCESS
)
5657 lpStr
= (LPWSTR
)(lpServiceDescription
+ 1);
5658 wcscpy(lpStr
, lpDescription
);
5659 lpServiceDescription
->lpDescription
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceDescription
);
5663 lpServiceDescription
->lpDescription
= NULL
;
5664 dwError
= ERROR_SUCCESS
;
5667 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5669 LPSERVICE_FAILURE_ACTIONSW lpFailureActions
= (LPSERVICE_FAILURE_ACTIONSW
)lpBuffer
;
5670 LPWSTR lpStr
= NULL
;
5672 /* Query value length */
5673 dwError
= RegQueryValueExW(hServiceKey
,
5679 if (dwError
!= ERROR_SUCCESS
&&
5680 dwError
!= ERROR_MORE_DATA
&&
5681 dwError
!= ERROR_FILE_NOT_FOUND
)
5684 dwRequiredSize
= (dwType
== REG_BINARY
) ? max(sizeof(SERVICE_FAILURE_ACTIONSW
), dwRequiredSize
)
5685 : sizeof(SERVICE_FAILURE_ACTIONSW
);
5687 /* Get the strings */
5688 ScmReadString(hServiceKey
,
5692 ScmReadString(hServiceKey
,
5696 if (lpRebootMessage
)
5697 dwRequiredSize
+= (DWORD
)((wcslen(lpRebootMessage
) + 1) * sizeof(WCHAR
));
5699 if (lpFailureCommand
)
5700 dwRequiredSize
+= (DWORD
)((wcslen(lpFailureCommand
) + 1) * sizeof(WCHAR
));
5702 if (cbBufSize
< dwRequiredSize
)
5704 *pcbBytesNeeded
= dwRequiredSize
;
5705 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5709 /* Now we can fill the buffer */
5710 if (dwError
!= ERROR_FILE_NOT_FOUND
&& dwType
== REG_BINARY
)
5712 dwError
= RegQueryValueExW(hServiceKey
,
5716 (LPBYTE
)lpFailureActions
,
5718 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5721 if (dwRequiredSize
< sizeof(SERVICE_FAILURE_ACTIONSW
))
5722 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSW
);
5727 * The value of the error doesn't really matter, the only
5728 * important thing is that it must be != ERROR_SUCCESS .
5730 dwError
= ERROR_INVALID_DATA
;
5733 if (dwError
== ERROR_SUCCESS
)
5735 lpFailureActions
->cActions
= min(lpFailureActions
->cActions
, (dwRequiredSize
- sizeof(SERVICE_FAILURE_ACTIONSW
)) / sizeof(SC_ACTION
));
5737 /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */
5738 lpFailureActions
->lpsaActions
= (lpFailureActions
->cActions
> 0 ? (LPSC_ACTION
)(ULONG_PTR
)sizeof(SERVICE_FAILURE_ACTIONSW
) : NULL
);
5740 lpStr
= (LPWSTR
)((ULONG_PTR
)(lpFailureActions
+ 1) + lpFailureActions
->cActions
* sizeof(SC_ACTION
));
5744 lpFailureActions
->dwResetPeriod
= 0;
5745 lpFailureActions
->cActions
= 0;
5746 lpFailureActions
->lpsaActions
= NULL
;
5747 lpStr
= (LPWSTR
)(lpFailureActions
+ 1);
5750 lpFailureActions
->lpRebootMsg
= NULL
;
5751 lpFailureActions
->lpCommand
= NULL
;
5753 if (lpRebootMessage
)
5755 wcscpy(lpStr
, lpRebootMessage
);
5756 lpFailureActions
->lpRebootMsg
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5757 lpStr
+= wcslen(lpStr
) + 1;
5760 if (lpFailureCommand
)
5762 wcscpy(lpStr
, lpFailureCommand
);
5763 lpFailureActions
->lpCommand
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5764 /* lpStr += wcslen(lpStr) + 1; */
5767 dwError
= ERROR_SUCCESS
;
5771 /* Unlock the service database */
5772 ScmUnlockDatabase();
5774 if (lpDescription
!= NULL
)
5775 HeapFree(GetProcessHeap(), 0, lpDescription
);
5777 if (lpRebootMessage
!= NULL
)
5778 HeapFree(GetProcessHeap(), 0, lpRebootMessage
);
5780 if (lpFailureCommand
!= NULL
)
5781 HeapFree(GetProcessHeap(), 0, lpFailureCommand
);
5783 if (hServiceKey
!= NULL
)
5784 RegCloseKey(hServiceKey
);
5786 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError
);
5793 DWORD
RQueryServiceStatusEx(
5794 SC_RPC_HANDLE hService
,
5795 SC_STATUS_TYPE InfoLevel
,
5798 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
5800 LPSERVICE_STATUS_PROCESS lpStatus
;
5801 PSERVICE_HANDLE hSvc
;
5804 DPRINT("RQueryServiceStatusEx() called\n");
5807 return ERROR_SHUTDOWN_IN_PROGRESS
;
5809 if (InfoLevel
!= SC_STATUS_PROCESS_INFO
)
5810 return ERROR_INVALID_LEVEL
;
5812 *pcbBytesNeeded
= sizeof(SERVICE_STATUS_PROCESS
);
5814 if (cbBufSize
< sizeof(SERVICE_STATUS_PROCESS
))
5815 return ERROR_INSUFFICIENT_BUFFER
;
5817 hSvc
= ScmGetServiceFromHandle(hService
);
5820 DPRINT1("Invalid service handle!\n");
5821 return ERROR_INVALID_HANDLE
;
5824 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5825 SERVICE_QUERY_STATUS
))
5827 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5828 return ERROR_ACCESS_DENIED
;
5831 lpService
= hSvc
->ServiceEntry
;
5832 if (lpService
== NULL
)
5834 DPRINT("lpService == NULL!\n");
5835 return ERROR_INVALID_HANDLE
;
5838 /* Lock the service database shared */
5839 ScmLockDatabaseShared();
5841 lpStatus
= (LPSERVICE_STATUS_PROCESS
)lpBuffer
;
5843 /* Return service status information */
5844 RtlCopyMemory(lpStatus
,
5846 sizeof(SERVICE_STATUS
));
5848 lpStatus
->dwProcessId
= (lpService
->lpImage
!= NULL
) ? lpService
->lpImage
->dwProcessId
: 0; /* FIXME */
5849 lpStatus
->dwServiceFlags
= 0; /* FIXME */
5851 /* Unlock the service database */
5852 ScmUnlockDatabase();
5854 return ERROR_SUCCESS
;
5859 DWORD
REnumServicesStatusExA(
5860 SC_RPC_HANDLE hSCManager
,
5861 SC_ENUM_TYPE InfoLevel
,
5862 DWORD dwServiceType
,
5863 DWORD dwServiceState
,
5866 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
5867 LPBOUNDED_DWORD_256K lpServicesReturned
,
5868 LPBOUNDED_DWORD_256K lpResumeIndex
,
5869 LPCSTR pszGroupName
)
5871 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrW
= NULL
;
5872 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrIncrW
;
5873 LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtrA
= NULL
;
5874 LPWSTR lpStringPtrW
;
5876 LPWSTR pszGroupNameW
= NULL
;
5878 DWORD dwServiceCount
;
5880 DPRINT("REnumServicesStatusExA() called\n");
5882 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
5884 return ERROR_INVALID_ADDRESS
;
5889 pszGroupNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, (strlen(pszGroupName
) + 1) * sizeof(WCHAR
));
5892 DPRINT("Failed to allocate buffer!\n");
5893 return ERROR_NOT_ENOUGH_MEMORY
;
5896 MultiByteToWideChar(CP_ACP
,
5901 (int)(strlen(pszGroupName
) + 1));
5904 if ((cbBufSize
> 0) && (lpBuffer
))
5906 lpStatusPtrW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, cbBufSize
);
5909 DPRINT("Failed to allocate buffer!\n");
5910 return ERROR_NOT_ENOUGH_MEMORY
;
5914 dwError
= REnumServicesStatusExW(hSCManager
,
5918 (LPBYTE
)lpStatusPtrW
,
5925 /* if no services were returned then we are Done */
5926 if (*lpServicesReturned
== 0)
5929 lpStatusPtrIncrW
= lpStatusPtrW
;
5930 lpStatusPtrA
= (LPENUM_SERVICE_STATUS_PROCESSA
)lpBuffer
;
5931 lpStringPtrA
= (LPSTR
)((ULONG_PTR
)lpBuffer
+
5932 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUS_PROCESSA
));
5933 lpStringPtrW
= (LPWSTR
)((ULONG_PTR
)lpStatusPtrW
+
5934 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUS_PROCESSW
));
5936 for (dwServiceCount
= 0; dwServiceCount
< *lpServicesReturned
; dwServiceCount
++)
5938 /* Copy the service name */
5939 WideCharToMultiByte(CP_ACP
,
5944 (int)wcslen(lpStringPtrW
),
5948 lpStatusPtrA
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
5949 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
5950 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
5952 /* Copy the display name */
5953 WideCharToMultiByte(CP_ACP
,
5958 (int)wcslen(lpStringPtrW
),
5962 lpStatusPtrA
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
5963 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
5964 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
5966 /* Copy the status information */
5967 memcpy(&lpStatusPtrA
->ServiceStatusProcess
,
5968 &lpStatusPtrIncrW
->ServiceStatusProcess
,
5969 sizeof(SERVICE_STATUS
));
5971 lpStatusPtrA
->ServiceStatusProcess
.dwProcessId
= lpStatusPtrIncrW
->ServiceStatusProcess
.dwProcessId
; /* FIXME */
5972 lpStatusPtrA
->ServiceStatusProcess
.dwServiceFlags
= 0; /* FIXME */
5980 HeapFree(GetProcessHeap(), 0, pszGroupNameW
);
5983 HeapFree(GetProcessHeap(), 0, lpStatusPtrW
);
5985 DPRINT("REnumServicesStatusExA() done (Error %lu)\n", dwError
);
5992 DWORD
REnumServicesStatusExW(
5993 SC_RPC_HANDLE hSCManager
,
5994 SC_ENUM_TYPE InfoLevel
,
5995 DWORD dwServiceType
,
5996 DWORD dwServiceState
,
5999 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
6000 LPBOUNDED_DWORD_256K lpServicesReturned
,
6001 LPBOUNDED_DWORD_256K lpResumeIndex
,
6002 LPCWSTR pszGroupName
)
6004 PMANAGER_HANDLE hManager
;
6006 DWORD dwError
= ERROR_SUCCESS
;
6007 PLIST_ENTRY ServiceEntry
;
6008 PSERVICE CurrentService
;
6010 DWORD dwRequiredSize
;
6011 DWORD dwServiceCount
;
6013 DWORD dwLastResumeCount
= 0;
6014 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr
;
6017 DPRINT("REnumServicesStatusExW() called\n");
6020 return ERROR_SHUTDOWN_IN_PROGRESS
;
6022 if (InfoLevel
!= SC_ENUM_PROCESS_INFO
)
6023 return ERROR_INVALID_LEVEL
;
6025 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
6026 if (hManager
== NULL
)
6028 DPRINT1("Invalid service manager handle!\n");
6029 return ERROR_INVALID_HANDLE
;
6032 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
6034 return ERROR_INVALID_ADDRESS
;
6037 *pcbBytesNeeded
= 0;
6038 *lpServicesReturned
= 0;
6040 if ((dwServiceType
== 0) ||
6041 ((dwServiceType
& ~SERVICE_TYPE_ALL
) != 0))
6043 DPRINT("Not a valid Service Type!\n");
6044 return ERROR_INVALID_PARAMETER
;
6047 if ((dwServiceState
== 0) ||
6048 ((dwServiceState
& ~SERVICE_STATE_ALL
) != 0))
6050 DPRINT("Not a valid Service State!\n");
6051 return ERROR_INVALID_PARAMETER
;
6054 /* Check access rights */
6055 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
6056 SC_MANAGER_ENUMERATE_SERVICE
))
6058 DPRINT("Insufficient access rights! 0x%lx\n",
6059 hManager
->Handle
.DesiredAccess
);
6060 return ERROR_ACCESS_DENIED
;
6064 dwLastResumeCount
= *lpResumeIndex
;
6066 /* Lock the service database shared */
6067 ScmLockDatabaseShared();
6069 lpService
= ScmGetServiceEntryByResumeCount(dwLastResumeCount
);
6070 if (lpService
== NULL
)
6072 dwError
= ERROR_SUCCESS
;
6079 for (ServiceEntry
= &lpService
->ServiceListEntry
;
6080 ServiceEntry
!= &ServiceListHead
;
6081 ServiceEntry
= ServiceEntry
->Flink
)
6083 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
6087 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
6090 dwState
= SERVICE_ACTIVE
;
6091 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
6092 dwState
= SERVICE_INACTIVE
;
6094 if ((dwState
& dwServiceState
) == 0)
6099 if (*pszGroupName
== 0)
6101 if (CurrentService
->lpGroup
!= NULL
)
6106 if ((CurrentService
->lpGroup
== NULL
) ||
6107 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
6112 dwSize
= sizeof(ENUM_SERVICE_STATUS_PROCESSW
) +
6113 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
6114 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
6116 if (dwRequiredSize
+ dwSize
<= cbBufSize
)
6118 DPRINT("Service name: %S fit\n", CurrentService
->lpServiceName
);
6119 dwRequiredSize
+= dwSize
;
6121 dwLastResumeCount
= CurrentService
->dwResumeCount
;
6125 DPRINT("Service name: %S no fit\n", CurrentService
->lpServiceName
);
6131 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize
);
6132 DPRINT("dwServiceCount: %lu\n", dwServiceCount
);
6135 ServiceEntry
!= &ServiceListHead
;
6136 ServiceEntry
= ServiceEntry
->Flink
)
6138 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
6142 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
6145 dwState
= SERVICE_ACTIVE
;
6146 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
6147 dwState
= SERVICE_INACTIVE
;
6149 if ((dwState
& dwServiceState
) == 0)
6154 if (*pszGroupName
== 0)
6156 if (CurrentService
->lpGroup
!= NULL
)
6161 if ((CurrentService
->lpGroup
== NULL
) ||
6162 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
6167 dwRequiredSize
+= (sizeof(ENUM_SERVICE_STATUS_PROCESSW
) +
6168 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
6169 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
)));
6171 dwError
= ERROR_MORE_DATA
;
6174 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize
);
6177 *lpResumeIndex
= dwLastResumeCount
;
6179 *lpServicesReturned
= dwServiceCount
;
6180 *pcbBytesNeeded
= dwRequiredSize
;
6182 /* If there was no services that matched */
6183 if ((!dwServiceCount
) && (dwError
!= ERROR_MORE_DATA
))
6185 dwError
= ERROR_SERVICE_DOES_NOT_EXIST
;
6189 lpStatusPtr
= (LPENUM_SERVICE_STATUS_PROCESSW
)lpBuffer
;
6190 lpStringPtr
= (LPWSTR
)((ULONG_PTR
)lpBuffer
+
6191 dwServiceCount
* sizeof(ENUM_SERVICE_STATUS_PROCESSW
));
6194 for (ServiceEntry
= &lpService
->ServiceListEntry
;
6195 ServiceEntry
!= &ServiceListHead
;
6196 ServiceEntry
= ServiceEntry
->Flink
)
6198 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
6202 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
6205 dwState
= SERVICE_ACTIVE
;
6206 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
6207 dwState
= SERVICE_INACTIVE
;
6209 if ((dwState
& dwServiceState
) == 0)
6214 if (*pszGroupName
== 0)
6216 if (CurrentService
->lpGroup
!= NULL
)
6221 if ((CurrentService
->lpGroup
== NULL
) ||
6222 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
6227 dwSize
= sizeof(ENUM_SERVICE_STATUS_PROCESSW
) +
6228 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
6229 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
6231 if (dwRequiredSize
+ dwSize
<= cbBufSize
)
6233 /* Copy the service name */
6235 CurrentService
->lpServiceName
);
6236 lpStatusPtr
->lpServiceName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
6237 lpStringPtr
+= (wcslen(CurrentService
->lpServiceName
) + 1);
6239 /* Copy the display name */
6241 CurrentService
->lpDisplayName
);
6242 lpStatusPtr
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
6243 lpStringPtr
+= (wcslen(CurrentService
->lpDisplayName
) + 1);
6245 /* Copy the status information */
6246 memcpy(&lpStatusPtr
->ServiceStatusProcess
,
6247 &CurrentService
->Status
,
6248 sizeof(SERVICE_STATUS
));
6249 lpStatusPtr
->ServiceStatusProcess
.dwProcessId
=
6250 (CurrentService
->lpImage
!= NULL
) ? CurrentService
->lpImage
->dwProcessId
: 0; /* FIXME */
6251 lpStatusPtr
->ServiceStatusProcess
.dwServiceFlags
= 0; /* FIXME */
6254 dwRequiredSize
+= dwSize
;
6264 *pcbBytesNeeded
= 0;
6270 /* Unlock the service database */
6271 ScmUnlockDatabase();
6273 DPRINT("REnumServicesStatusExW() done (Error %lu)\n", dwError
);
6280 DWORD
RSendTSMessage(
6281 handle_t BindingHandle
) /* FIXME */
6284 return ERROR_CALL_NOT_IMPLEMENTED
;
6289 DWORD
RCreateServiceWOW64A(
6290 handle_t BindingHandle
,
6291 LPSTR lpServiceName
,
6292 LPSTR lpDisplayName
,
6293 DWORD dwDesiredAccess
,
6294 DWORD dwServiceType
,
6296 DWORD dwErrorControl
,
6297 LPSTR lpBinaryPathName
,
6298 LPSTR lpLoadOrderGroup
,
6300 LPBYTE lpDependencies
,
6302 LPSTR lpServiceStartName
,
6305 LPSC_RPC_HANDLE lpServiceHandle
)
6308 return ERROR_CALL_NOT_IMPLEMENTED
;
6313 DWORD
RCreateServiceWOW64W(
6314 handle_t BindingHandle
,
6315 LPWSTR lpServiceName
,
6316 LPWSTR lpDisplayName
,
6317 DWORD dwDesiredAccess
,
6318 DWORD dwServiceType
,
6320 DWORD dwErrorControl
,
6321 LPWSTR lpBinaryPathName
,
6322 LPWSTR lpLoadOrderGroup
,
6324 LPBYTE lpDependencies
,
6326 LPWSTR lpServiceStartName
,
6329 LPSC_RPC_HANDLE lpServiceHandle
)
6332 return ERROR_CALL_NOT_IMPLEMENTED
;
6337 DWORD
RQueryServiceTagInfo(
6338 handle_t BindingHandle
) /* FIXME */
6341 return ERROR_CALL_NOT_IMPLEMENTED
;
6346 DWORD
RNotifyServiceStatusChange(
6347 SC_RPC_HANDLE hService
,
6348 SC_RPC_NOTIFY_PARAMS NotifyParams
,
6349 GUID
*pClientProcessGuid
,
6350 GUID
*pSCMProcessGuid
,
6351 PBOOL pfCreateRemoteQueue
,
6352 LPSC_NOTIFY_RPC_HANDLE phNotify
)
6355 return ERROR_CALL_NOT_IMPLEMENTED
;
6360 DWORD
RGetNotifyResults(
6361 SC_NOTIFY_RPC_HANDLE hNotify
,
6362 PSC_RPC_NOTIFY_PARAMS_LIST
*ppNotifyParams
)
6365 return ERROR_CALL_NOT_IMPLEMENTED
;
6370 DWORD
RCloseNotifyHandle(
6371 LPSC_NOTIFY_RPC_HANDLE phNotify
,
6375 return ERROR_CALL_NOT_IMPLEMENTED
;
6380 DWORD
RControlServiceExA(
6381 SC_RPC_HANDLE hService
,
6386 return ERROR_CALL_NOT_IMPLEMENTED
;
6391 DWORD
RControlServiceExW(
6392 SC_RPC_HANDLE hService
,
6397 return ERROR_CALL_NOT_IMPLEMENTED
;
6402 DWORD
RSendPnPMessage(
6403 handle_t BindingHandle
) /* FIXME */
6406 return ERROR_CALL_NOT_IMPLEMENTED
;
6411 DWORD
RValidatePnPService(
6412 handle_t BindingHandle
) /* FIXME */
6415 return ERROR_CALL_NOT_IMPLEMENTED
;
6420 DWORD
ROpenServiceStatusHandle(
6421 handle_t BindingHandle
) /* FIXME */
6424 return ERROR_CALL_NOT_IMPLEMENTED
;
6430 handle_t BindingHandle
) /* FIXME */
6433 return ERROR_CALL_NOT_IMPLEMENTED
;
6437 void __RPC_FAR
* __RPC_USER
midl_user_allocate(SIZE_T len
)
6439 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
);
6443 void __RPC_USER
midl_user_free(void __RPC_FAR
* ptr
)
6445 HeapFree(GetProcessHeap(), 0, ptr
);
6449 void __RPC_USER
SC_RPC_HANDLE_rundown(SC_RPC_HANDLE hSCObject
)
6451 /* Close the handle */
6452 RCloseServiceHandle(&hSCObject
);
6456 void __RPC_USER
SC_RPC_LOCK_rundown(SC_RPC_LOCK Lock
)
6458 /* Unlock the database */
6459 RUnlockServiceDatabase(&Lock
);
6463 void __RPC_USER
SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE hNotify
)