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 lpLogStrings
[2];
1089 WCHAR szLogBuffer
[80];
1092 DPRINT("RControlService() called\n");
1095 return ERROR_SHUTDOWN_IN_PROGRESS
;
1097 /* Check the service handle */
1098 hSvc
= ScmGetServiceFromHandle(hService
);
1101 DPRINT1("Invalid service handle!\n");
1102 return ERROR_INVALID_HANDLE
;
1105 /* Check the service entry point */
1106 lpService
= hSvc
->ServiceEntry
;
1107 if (lpService
== NULL
)
1109 DPRINT1("lpService == NULL!\n");
1110 return ERROR_INVALID_HANDLE
;
1113 /* Check access rights */
1116 case SERVICE_CONTROL_STOP
:
1117 DesiredAccess
= SERVICE_STOP
;
1120 case SERVICE_CONTROL_PAUSE
:
1121 case SERVICE_CONTROL_CONTINUE
:
1122 DesiredAccess
= SERVICE_PAUSE_CONTINUE
;
1125 case SERVICE_CONTROL_INTERROGATE
:
1126 DesiredAccess
= SERVICE_INTERROGATE
;
1130 if (dwControl
>= 128 && dwControl
<= 255)
1131 DesiredAccess
= SERVICE_USER_DEFINED_CONTROL
;
1133 return ERROR_INVALID_PARAMETER
;
1137 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1139 return ERROR_ACCESS_DENIED
;
1141 /* Return the current service status information */
1142 RtlCopyMemory(lpServiceStatus
,
1144 sizeof(SERVICE_STATUS
));
1146 if (dwControl
== SERVICE_CONTROL_STOP
)
1148 /* Check if the service has dependencies running as windows
1149 doesn't stop a service that does */
1151 /* Open the Services Reg key */
1152 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1153 L
"System\\CurrentControlSet\\Services",
1157 if (dwError
!= ERROR_SUCCESS
)
1159 DPRINT("Failed to open services key\n");
1163 /* Call the internal function with NULL, just to get bytes we need */
1164 Int_EnumDependentServicesW(hServicesKey
,
1169 &dwServicesReturned
);
1171 RegCloseKey(hServicesKey
);
1173 /* If pcbBytesNeeded is not zero then there are services running that
1174 are dependent on this service */
1175 if (pcbBytesNeeded
!= 0)
1177 DPRINT("Service has running dependencies. Failed to stop service.\n");
1178 return ERROR_DEPENDENT_SERVICES_RUNNING
;
1182 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
1184 /* Send control code to the driver */
1185 dwError
= ScmControlDriver(lpService
,
1191 dwControlsAccepted
= lpService
->Status
.dwControlsAccepted
;
1192 dwCurrentState
= lpService
->Status
.dwCurrentState
;
1194 /* Return ERROR_SERVICE_NOT_ACTIVE if the service has not been started */
1195 if (lpService
->lpImage
== NULL
|| dwCurrentState
== SERVICE_STOPPED
)
1196 return ERROR_SERVICE_NOT_ACTIVE
;
1198 /* Check the current state before sending a control request */
1199 switch (dwCurrentState
)
1201 case SERVICE_STOP_PENDING
:
1202 case SERVICE_STOPPED
:
1203 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL
;
1205 case SERVICE_START_PENDING
:
1208 case SERVICE_CONTROL_STOP
:
1211 case SERVICE_CONTROL_INTERROGATE
:
1212 RtlCopyMemory(lpServiceStatus
,
1214 sizeof(SERVICE_STATUS
));
1215 return ERROR_SUCCESS
;
1218 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL
;
1223 /* Check if the control code is acceptable to the service */
1226 case SERVICE_CONTROL_STOP
:
1227 if ((dwControlsAccepted
& SERVICE_ACCEPT_STOP
) == 0)
1228 return ERROR_INVALID_SERVICE_CONTROL
;
1231 case SERVICE_CONTROL_PAUSE
:
1232 case SERVICE_CONTROL_CONTINUE
:
1233 if ((dwControlsAccepted
& SERVICE_ACCEPT_PAUSE_CONTINUE
) == 0)
1234 return ERROR_INVALID_SERVICE_CONTROL
;
1238 /* Send control code to the service */
1239 dwError
= ScmControlService(lpService
,
1242 /* Return service status information */
1243 RtlCopyMemory(lpServiceStatus
,
1245 sizeof(SERVICE_STATUS
));
1248 if (dwError
== ERROR_SUCCESS
)
1250 if (dwControl
== SERVICE_CONTROL_STOP
||
1251 dwControl
== SERVICE_CONTROL_PAUSE
||
1252 dwControl
== SERVICE_CONTROL_CONTINUE
)
1254 /* Log a sucessful send control */
1258 case SERVICE_CONTROL_STOP
:
1259 uID
= IDS_SERVICE_STOP
;
1262 case SERVICE_CONTROL_PAUSE
:
1263 uID
= IDS_SERVICE_PAUSE
;
1266 case SERVICE_CONTROL_CONTINUE
:
1267 uID
= IDS_SERVICE_RESUME
;
1270 LoadStringW(GetModuleHandle(NULL
), uID
, szLogBuffer
, 80);
1272 lpLogStrings
[0] = lpService
->lpDisplayName
;
1273 lpLogStrings
[1] = szLogBuffer
;
1275 ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS
,
1276 EVENTLOG_INFORMATION_TYPE
,
1287 DWORD
RDeleteService(
1288 SC_RPC_HANDLE hService
)
1290 PSERVICE_HANDLE hSvc
;
1294 DPRINT("RDeleteService() called\n");
1297 return ERROR_SHUTDOWN_IN_PROGRESS
;
1299 hSvc
= ScmGetServiceFromHandle(hService
);
1302 DPRINT1("Invalid service handle!\n");
1303 return ERROR_INVALID_HANDLE
;
1306 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1308 return ERROR_ACCESS_DENIED
;
1310 lpService
= hSvc
->ServiceEntry
;
1311 if (lpService
== NULL
)
1313 DPRINT("lpService == NULL!\n");
1314 return ERROR_INVALID_HANDLE
;
1317 /* Lock the service database exclusively */
1318 ScmLockDatabaseExclusive();
1320 if (lpService
->bDeleted
)
1322 DPRINT("The service has already been marked for delete!\n");
1323 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
1327 /* Mark service for delete */
1328 lpService
->bDeleted
= TRUE
;
1330 dwError
= ScmMarkServiceForDelete(lpService
);
1333 /* Unlock the service database */
1334 ScmUnlockDatabase();
1336 DPRINT("RDeleteService() done\n");
1343 DWORD
RLockServiceDatabase(
1344 SC_RPC_HANDLE hSCManager
,
1345 LPSC_RPC_LOCK lpLock
)
1347 PMANAGER_HANDLE hMgr
;
1349 DPRINT("RLockServiceDatabase() called\n");
1353 hMgr
= ScmGetServiceManagerFromHandle(hSCManager
);
1356 DPRINT1("Invalid service manager handle!\n");
1357 return ERROR_INVALID_HANDLE
;
1360 if (!RtlAreAllAccessesGranted(hMgr
->Handle
.DesiredAccess
,
1362 return ERROR_ACCESS_DENIED
;
1364 return ScmAcquireServiceStartLock(FALSE
, lpLock
);
1369 DWORD
RQueryServiceObjectSecurity(
1370 SC_RPC_HANDLE hService
,
1371 SECURITY_INFORMATION dwSecurityInformation
,
1372 LPBYTE lpSecurityDescriptor
,
1374 LPBOUNDED_DWORD_256K pcbBytesNeeded
)
1376 PSERVICE_HANDLE hSvc
;
1378 ULONG DesiredAccess
= 0;
1380 DWORD dwBytesNeeded
;
1384 SECURITY_DESCRIPTOR ObjectDescriptor
;
1386 DPRINT("RQueryServiceObjectSecurity() called\n");
1388 hSvc
= ScmGetServiceFromHandle(hService
);
1391 DPRINT1("Invalid service handle!\n");
1392 return ERROR_INVALID_HANDLE
;
1395 if (dwSecurityInformation
& (DACL_SECURITY_INFORMATION
|
1396 GROUP_SECURITY_INFORMATION
|
1397 OWNER_SECURITY_INFORMATION
))
1398 DesiredAccess
|= READ_CONTROL
;
1400 if (dwSecurityInformation
& SACL_SECURITY_INFORMATION
)
1401 DesiredAccess
|= ACCESS_SYSTEM_SECURITY
;
1403 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1406 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1407 return ERROR_ACCESS_DENIED
;
1410 lpService
= hSvc
->ServiceEntry
;
1411 if (lpService
== NULL
)
1413 DPRINT("lpService == NULL!\n");
1414 return ERROR_INVALID_HANDLE
;
1417 /* Lock the service database */
1418 ScmLockDatabaseShared();
1422 Status
= RtlCreateSecurityDescriptor(&ObjectDescriptor
, SECURITY_DESCRIPTOR_REVISION
);
1424 Status
= RtlQuerySecurityObject(&ObjectDescriptor
/* lpService->lpSecurityDescriptor */,
1425 dwSecurityInformation
,
1426 (PSECURITY_DESCRIPTOR
)lpSecurityDescriptor
,
1430 /* Unlock the service database */
1431 ScmUnlockDatabase();
1433 if (NT_SUCCESS(Status
))
1435 *pcbBytesNeeded
= dwBytesNeeded
;
1436 dwError
= STATUS_SUCCESS
;
1438 else if (Status
== STATUS_BUFFER_TOO_SMALL
)
1440 *pcbBytesNeeded
= dwBytesNeeded
;
1441 dwError
= ERROR_INSUFFICIENT_BUFFER
;
1443 else if (Status
== STATUS_BAD_DESCRIPTOR_FORMAT
)
1445 dwError
= ERROR_GEN_FAILURE
;
1449 dwError
= RtlNtStatusToDosError(Status
);
1457 DWORD
RSetServiceObjectSecurity(
1458 SC_RPC_HANDLE hService
,
1459 DWORD dwSecurityInformation
,
1460 LPBYTE lpSecurityDescriptor
,
1461 DWORD dwSecuityDescriptorSize
)
1463 PSERVICE_HANDLE hSvc
;
1465 ULONG DesiredAccess
= 0;
1466 /* HANDLE hToken = NULL; */
1468 /* NTSTATUS Status; */
1471 DPRINT("RSetServiceObjectSecurity() called\n");
1473 hSvc
= ScmGetServiceFromHandle(hService
);
1476 DPRINT1("Invalid service handle!\n");
1477 return ERROR_INVALID_HANDLE
;
1480 if (dwSecurityInformation
== 0 ||
1481 dwSecurityInformation
& ~(OWNER_SECURITY_INFORMATION
| GROUP_SECURITY_INFORMATION
1482 | DACL_SECURITY_INFORMATION
| SACL_SECURITY_INFORMATION
))
1483 return ERROR_INVALID_PARAMETER
;
1485 if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR
)lpSecurityDescriptor
))
1486 return ERROR_INVALID_PARAMETER
;
1488 if (dwSecurityInformation
& SACL_SECURITY_INFORMATION
)
1489 DesiredAccess
|= ACCESS_SYSTEM_SECURITY
;
1491 if (dwSecurityInformation
& DACL_SECURITY_INFORMATION
)
1492 DesiredAccess
|= WRITE_DAC
;
1494 if (dwSecurityInformation
& (OWNER_SECURITY_INFORMATION
| GROUP_SECURITY_INFORMATION
))
1495 DesiredAccess
|= WRITE_OWNER
;
1497 if ((dwSecurityInformation
& OWNER_SECURITY_INFORMATION
) &&
1498 (((PISECURITY_DESCRIPTOR
)lpSecurityDescriptor
)->Owner
== NULL
))
1499 return ERROR_INVALID_PARAMETER
;
1501 if ((dwSecurityInformation
& GROUP_SECURITY_INFORMATION
) &&
1502 (((PISECURITY_DESCRIPTOR
)lpSecurityDescriptor
)->Group
== NULL
))
1503 return ERROR_INVALID_PARAMETER
;
1505 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1508 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1509 return ERROR_ACCESS_DENIED
;
1512 lpService
= hSvc
->ServiceEntry
;
1513 if (lpService
== NULL
)
1515 DPRINT("lpService == NULL!\n");
1516 return ERROR_INVALID_HANDLE
;
1519 if (lpService
->bDeleted
)
1520 return ERROR_SERVICE_MARKED_FOR_DELETE
;
1523 RpcImpersonateClient(NULL
);
1525 Status
= NtOpenThreadToken(NtCurrentThread(),
1529 if (!NT_SUCCESS(Status
))
1530 return RtlNtStatusToDosError(Status
);
1535 /* Lock the service database exclusive */
1536 ScmLockDatabaseExclusive();
1539 Status
= RtlSetSecurityObject(dwSecurityInformation
,
1540 (PSECURITY_DESCRIPTOR
)lpSecurityDescriptor
,
1541 &lpService
->lpSecurityDescriptor
,
1544 if (!NT_SUCCESS(Status
))
1546 dwError
= RtlNtStatusToDosError(Status
);
1551 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
1552 READ_CONTROL
| KEY_CREATE_SUB_KEY
| KEY_SET_VALUE
,
1554 if (dwError
!= ERROR_SUCCESS
)
1558 dwError
= ERROR_SUCCESS
;
1559 // dwError = ScmWriteSecurityDescriptor(hServiceKey,
1560 // lpService->lpSecurityDescriptor);
1562 RegFlushKey(hServiceKey
);
1563 RegCloseKey(hServiceKey
);
1572 /* Unlock service database */
1573 ScmUnlockDatabase();
1575 DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError
);
1582 DWORD
RQueryServiceStatus(
1583 SC_RPC_HANDLE hService
,
1584 LPSERVICE_STATUS lpServiceStatus
)
1586 PSERVICE_HANDLE hSvc
;
1589 DPRINT("RQueryServiceStatus() called\n");
1592 return ERROR_SHUTDOWN_IN_PROGRESS
;
1594 hSvc
= ScmGetServiceFromHandle(hService
);
1597 DPRINT1("Invalid service handle!\n");
1598 return ERROR_INVALID_HANDLE
;
1601 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1602 SERVICE_QUERY_STATUS
))
1604 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1605 return ERROR_ACCESS_DENIED
;
1608 lpService
= hSvc
->ServiceEntry
;
1609 if (lpService
== NULL
)
1611 DPRINT("lpService == NULL!\n");
1612 return ERROR_INVALID_HANDLE
;
1615 /* Lock the service database shared */
1616 ScmLockDatabaseShared();
1618 /* Return service status information */
1619 RtlCopyMemory(lpServiceStatus
,
1621 sizeof(SERVICE_STATUS
));
1623 /* Unlock the service database */
1624 ScmUnlockDatabase();
1626 return ERROR_SUCCESS
;
1631 ScmIsValidServiceState(DWORD dwCurrentState
)
1633 switch (dwCurrentState
)
1635 case SERVICE_STOPPED
:
1636 case SERVICE_START_PENDING
:
1637 case SERVICE_STOP_PENDING
:
1638 case SERVICE_RUNNING
:
1639 case SERVICE_CONTINUE_PENDING
:
1640 case SERVICE_PAUSE_PENDING
:
1641 case SERVICE_PAUSED
:
1651 DWORD
RSetServiceStatus(
1652 RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
1653 LPSERVICE_STATUS lpServiceStatus
)
1656 DWORD dwPreviousState
;
1657 DWORD dwPreviousType
;
1658 LPCWSTR lpLogStrings
[2];
1659 WCHAR szLogBuffer
[80];
1662 DPRINT("RSetServiceStatus() called\n");
1663 DPRINT("hServiceStatus = %lu\n", hServiceStatus
);
1664 DPRINT("dwServiceType = 0x%lx\n", lpServiceStatus
->dwServiceType
);
1665 DPRINT("dwCurrentState = %lu\n", lpServiceStatus
->dwCurrentState
);
1666 DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus
->dwControlsAccepted
);
1667 DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus
->dwWin32ExitCode
);
1668 DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus
->dwServiceSpecificExitCode
);
1669 DPRINT("dwCheckPoint = %lu\n", lpServiceStatus
->dwCheckPoint
);
1670 DPRINT("dwWaitHint = %lu\n", lpServiceStatus
->dwWaitHint
);
1672 if (hServiceStatus
== 0)
1674 DPRINT("hServiceStatus == NULL!\n");
1675 return ERROR_INVALID_HANDLE
;
1678 lpService
= (PSERVICE
)hServiceStatus
;
1680 /* Check current state */
1681 if (!ScmIsValidServiceState(lpServiceStatus
->dwCurrentState
))
1683 DPRINT("Invalid service state!\n");
1684 return ERROR_INVALID_DATA
;
1687 /* Check service type */
1688 if (!(lpServiceStatus
->dwServiceType
& SERVICE_WIN32
) &&
1689 (lpServiceStatus
->dwServiceType
& SERVICE_DRIVER
))
1691 DPRINT("Invalid service type!\n");
1692 return ERROR_INVALID_DATA
;
1695 /* Check accepted controls */
1696 if (lpServiceStatus
->dwControlsAccepted
& ~0xFF)
1698 DPRINT("Invalid controls accepted!\n");
1699 return ERROR_INVALID_DATA
;
1702 /* Set the wait hint and check point only if the service is in a pending state,
1703 otherwise they should be 0 */
1704 if (lpServiceStatus
->dwCurrentState
== SERVICE_STOPPED
||
1705 lpServiceStatus
->dwCurrentState
== SERVICE_PAUSED
||
1706 lpServiceStatus
->dwCurrentState
== SERVICE_RUNNING
)
1708 lpServiceStatus
->dwWaitHint
= 0;
1709 lpServiceStatus
->dwCheckPoint
= 0;
1712 /* Lock the service database exclusively */
1713 ScmLockDatabaseExclusive();
1715 /* Save the current service state */
1716 dwPreviousState
= lpService
->Status
.dwCurrentState
;
1718 /* Save the current service type */
1719 dwPreviousType
= lpService
->Status
.dwServiceType
;
1721 /* Update the service status */
1722 RtlCopyMemory(&lpService
->Status
,
1724 sizeof(SERVICE_STATUS
));
1726 /* Restore the previous service type */
1727 lpService
->Status
.dwServiceType
= dwPreviousType
;
1729 /* Unlock the service database */
1730 ScmUnlockDatabase();
1732 if ((lpServiceStatus
->dwCurrentState
== SERVICE_STOPPED
) &&
1733 (dwPreviousState
!= SERVICE_STOPPED
) &&
1734 (lpServiceStatus
->dwWin32ExitCode
!= ERROR_SUCCESS
))
1736 /* Log a failed service stop */
1737 swprintf(szLogBuffer
, L
"%lu", lpServiceStatus
->dwWin32ExitCode
);
1738 lpLogStrings
[0] = lpService
->lpDisplayName
;
1739 lpLogStrings
[1] = szLogBuffer
;
1741 ScmLogEvent(EVENT_SERVICE_EXIT_FAILED
,
1742 EVENTLOG_ERROR_TYPE
,
1746 else if (lpServiceStatus
->dwCurrentState
!= dwPreviousState
&&
1747 (lpServiceStatus
->dwCurrentState
== SERVICE_STOPPED
||
1748 lpServiceStatus
->dwCurrentState
== SERVICE_RUNNING
||
1749 lpServiceStatus
->dwCurrentState
== SERVICE_PAUSED
))
1751 /* Log a successful service status change */
1752 switch(lpServiceStatus
->dwCurrentState
)
1754 case SERVICE_STOPPED
:
1755 uID
= IDS_SERVICE_STOPPED
;
1758 case SERVICE_RUNNING
:
1759 uID
= IDS_SERVICE_RUNNING
;
1762 case SERVICE_PAUSED
:
1763 uID
= IDS_SERVICE_PAUSED
;
1767 LoadStringW(GetModuleHandle(NULL
), uID
, szLogBuffer
, 80);
1768 lpLogStrings
[0] = lpService
->lpDisplayName
;
1769 lpLogStrings
[1] = szLogBuffer
;
1771 ScmLogEvent(EVENT_SERVICE_STATUS_SUCCESS
,
1772 EVENTLOG_INFORMATION_TYPE
,
1777 DPRINT("Set %S to %lu\n", lpService
->lpDisplayName
, lpService
->Status
.dwCurrentState
);
1778 DPRINT("RSetServiceStatus() done\n");
1780 return ERROR_SUCCESS
;
1785 DWORD
RUnlockServiceDatabase(
1788 DPRINT("RUnlockServiceDatabase(%p)\n", Lock
);
1789 return ScmReleaseServiceStartLock(Lock
);
1794 DWORD
RNotifyBootConfigStatus(
1795 SVCCTL_HANDLEW lpMachineName
,
1796 DWORD BootAcceptable
)
1798 DPRINT1("RNotifyBootConfigStatus(%p %lu) called\n", lpMachineName
, BootAcceptable
);
1799 return ERROR_SUCCESS
;
1802 // return ERROR_CALL_NOT_IMPLEMENTED;
1807 DWORD
RI_ScSetServiceBitsW(
1808 RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
1809 DWORD dwServiceBits
,
1811 int bUpdateImmediately
,
1815 return ERROR_CALL_NOT_IMPLEMENTED
;
1820 DWORD
RChangeServiceConfigW(
1821 SC_RPC_HANDLE hService
,
1822 DWORD dwServiceType
,
1824 DWORD dwErrorControl
,
1825 LPWSTR lpBinaryPathName
,
1826 LPWSTR lpLoadOrderGroup
,
1828 LPBYTE lpDependencies
,
1830 LPWSTR lpServiceStartName
,
1833 LPWSTR lpDisplayName
)
1835 DWORD dwError
= ERROR_SUCCESS
;
1836 PSERVICE_HANDLE hSvc
;
1837 PSERVICE lpService
= NULL
;
1838 HKEY hServiceKey
= NULL
;
1839 LPWSTR lpDisplayNameW
= NULL
;
1840 LPWSTR lpImagePathW
= NULL
;
1842 DPRINT("RChangeServiceConfigW() called\n");
1843 DPRINT("dwServiceType = 0x%lx\n", dwServiceType
);
1844 DPRINT("dwStartType = %lu\n", dwStartType
);
1845 DPRINT("dwErrorControl = %lu\n", dwErrorControl
);
1846 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName
);
1847 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup
);
1848 DPRINT("lpDisplayName = %S\n", lpDisplayName
);
1851 return ERROR_SHUTDOWN_IN_PROGRESS
;
1853 hSvc
= ScmGetServiceFromHandle(hService
);
1856 DPRINT1("Invalid service handle!\n");
1857 return ERROR_INVALID_HANDLE
;
1860 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1861 SERVICE_CHANGE_CONFIG
))
1863 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1864 return ERROR_ACCESS_DENIED
;
1867 lpService
= hSvc
->ServiceEntry
;
1868 if (lpService
== NULL
)
1870 DPRINT("lpService == NULL!\n");
1871 return ERROR_INVALID_HANDLE
;
1874 /* Lock the service database exclusively */
1875 ScmLockDatabaseExclusive();
1877 if (lpService
->bDeleted
)
1879 DPRINT("The service has already been marked for delete!\n");
1880 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
1884 /* Open the service key */
1885 dwError
= ScmOpenServiceKey(lpService
->szServiceName
,
1888 if (dwError
!= ERROR_SUCCESS
)
1891 /* Write service data to the registry */
1892 /* Set the display name */
1893 if (lpDisplayName
!= NULL
&& *lpDisplayName
!= 0)
1895 RegSetValueExW(hServiceKey
,
1899 (LPBYTE
)lpDisplayName
,
1900 (DWORD
)((wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
)));
1902 /* Update the display name */
1903 lpDisplayNameW
= HeapAlloc(GetProcessHeap(),
1905 (wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
));
1906 if (lpDisplayNameW
== NULL
)
1908 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
1912 if (lpService
->lpDisplayName
!= lpService
->lpServiceName
)
1913 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
1915 lpService
->lpDisplayName
= lpDisplayNameW
;
1918 if (dwServiceType
!= SERVICE_NO_CHANGE
)
1920 /* Set the service type */
1921 dwError
= RegSetValueExW(hServiceKey
,
1925 (LPBYTE
)&dwServiceType
,
1927 if (dwError
!= ERROR_SUCCESS
)
1930 lpService
->Status
.dwServiceType
= dwServiceType
;
1933 if (dwStartType
!= SERVICE_NO_CHANGE
)
1935 /* Set the start value */
1936 dwError
= RegSetValueExW(hServiceKey
,
1940 (LPBYTE
)&dwStartType
,
1942 if (dwError
!= ERROR_SUCCESS
)
1945 lpService
->dwStartType
= dwStartType
;
1948 if (dwErrorControl
!= SERVICE_NO_CHANGE
)
1950 /* Set the error control value */
1951 dwError
= RegSetValueExW(hServiceKey
,
1955 (LPBYTE
)&dwErrorControl
,
1957 if (dwError
!= ERROR_SUCCESS
)
1960 lpService
->dwErrorControl
= dwErrorControl
;
1963 if (lpBinaryPathName
!= NULL
&& *lpBinaryPathName
!= 0)
1965 /* Set the image path */
1966 lpImagePathW
= lpBinaryPathName
;
1968 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
1970 dwError
= ScmCanonDriverImagePath(lpService
->dwStartType
,
1974 if (dwError
!= ERROR_SUCCESS
)
1978 dwError
= RegSetValueExW(hServiceKey
,
1982 (LPBYTE
)lpImagePathW
,
1983 (DWORD
)((wcslen(lpImagePathW
) + 1) * sizeof(WCHAR
)));
1985 if (lpImagePathW
!= lpBinaryPathName
)
1986 HeapFree(GetProcessHeap(), 0, lpImagePathW
);
1988 if (dwError
!= ERROR_SUCCESS
)
1992 /* Set the group name */
1993 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
1995 dwError
= RegSetValueExW(hServiceKey
,
1999 (LPBYTE
)lpLoadOrderGroup
,
2000 (DWORD
)((wcslen(lpLoadOrderGroup
) + 1) * sizeof(WCHAR
)));
2001 if (dwError
!= ERROR_SUCCESS
)
2004 dwError
= ScmSetServiceGroup(lpService
,
2006 if (dwError
!= ERROR_SUCCESS
)
2010 if (lpdwTagId
!= NULL
)
2012 dwError
= ScmAssignNewTag(lpService
);
2013 if (dwError
!= ERROR_SUCCESS
)
2016 dwError
= RegSetValueExW(hServiceKey
,
2020 (LPBYTE
)&lpService
->dwTag
,
2022 if (dwError
!= ERROR_SUCCESS
)
2025 *lpdwTagId
= lpService
->dwTag
;
2028 /* Write dependencies */
2029 if (lpDependencies
!= NULL
&& *lpDependencies
!= 0)
2031 dwError
= ScmWriteDependencies(hServiceKey
,
2032 (LPWSTR
)lpDependencies
,
2034 if (dwError
!= ERROR_SUCCESS
)
2038 if (lpPassword
!= NULL
)
2040 /* FIXME: Decrypt and write password */
2044 if (hServiceKey
!= NULL
)
2045 RegCloseKey(hServiceKey
);
2047 /* Unlock the service database */
2048 ScmUnlockDatabase();
2050 DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError
);
2057 DWORD
RCreateServiceW(
2058 SC_RPC_HANDLE hSCManager
,
2059 LPCWSTR lpServiceName
,
2060 LPCWSTR lpDisplayName
,
2061 DWORD dwDesiredAccess
,
2062 DWORD dwServiceType
,
2064 DWORD dwErrorControl
,
2065 LPCWSTR lpBinaryPathName
,
2066 LPCWSTR lpLoadOrderGroup
,
2068 LPBYTE lpDependencies
,
2070 LPCWSTR lpServiceStartName
,
2073 LPSC_RPC_HANDLE lpServiceHandle
)
2075 PMANAGER_HANDLE hManager
;
2076 DWORD dwError
= ERROR_SUCCESS
;
2077 PSERVICE lpService
= NULL
;
2078 SC_HANDLE hServiceHandle
= NULL
;
2079 LPWSTR lpImagePath
= NULL
;
2080 HKEY hServiceKey
= NULL
;
2081 LPWSTR lpObjectName
;
2083 DPRINT("RCreateServiceW() called\n");
2084 DPRINT("lpServiceName = %S\n", lpServiceName
);
2085 DPRINT("lpDisplayName = %S\n", lpDisplayName
);
2086 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess
);
2087 DPRINT("dwServiceType = 0x%lx\n", dwServiceType
);
2088 DPRINT("dwStartType = %lu\n", dwStartType
);
2089 DPRINT("dwErrorControl = %lu\n", dwErrorControl
);
2090 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName
);
2091 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup
);
2092 DPRINT("lpdwTagId = %p\n", lpdwTagId
);
2095 return ERROR_SHUTDOWN_IN_PROGRESS
;
2097 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
2098 if (hManager
== NULL
)
2100 DPRINT1("Invalid service manager handle!\n");
2101 return ERROR_INVALID_HANDLE
;
2104 /* Check access rights */
2105 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
2106 SC_MANAGER_CREATE_SERVICE
))
2108 DPRINT("Insufficient access rights! 0x%lx\n",
2109 hManager
->Handle
.DesiredAccess
);
2110 return ERROR_ACCESS_DENIED
;
2113 if (wcslen(lpServiceName
) == 0)
2115 return ERROR_INVALID_NAME
;
2118 if (wcslen(lpBinaryPathName
) == 0)
2120 return ERROR_INVALID_PARAMETER
;
2123 /* Check for invalid service type value */
2124 if ((dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
2125 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
) &&
2126 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
2127 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
))
2128 return ERROR_INVALID_PARAMETER
;
2130 /* Check for invalid start type value */
2131 if ((dwStartType
!= SERVICE_BOOT_START
) &&
2132 (dwStartType
!= SERVICE_SYSTEM_START
) &&
2133 (dwStartType
!= SERVICE_AUTO_START
) &&
2134 (dwStartType
!= SERVICE_DEMAND_START
) &&
2135 (dwStartType
!= SERVICE_DISABLED
))
2136 return ERROR_INVALID_PARAMETER
;
2138 /* Only drivers can be boot start or system start services */
2139 if ((dwStartType
== SERVICE_BOOT_START
) ||
2140 (dwStartType
== SERVICE_SYSTEM_START
))
2142 if ((dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
2143 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
2144 return ERROR_INVALID_PARAMETER
;
2147 /* Check for invalid error control value */
2148 if ((dwErrorControl
!= SERVICE_ERROR_IGNORE
) &&
2149 (dwErrorControl
!= SERVICE_ERROR_NORMAL
) &&
2150 (dwErrorControl
!= SERVICE_ERROR_SEVERE
) &&
2151 (dwErrorControl
!= SERVICE_ERROR_CRITICAL
))
2152 return ERROR_INVALID_PARAMETER
;
2154 if ((dwServiceType
== (SERVICE_WIN32_OWN_PROCESS
| SERVICE_INTERACTIVE_PROCESS
)) &&
2155 (lpServiceStartName
))
2157 return ERROR_INVALID_PARAMETER
;
2160 if (lpdwTagId
&& (!lpLoadOrderGroup
|| !*lpLoadOrderGroup
))
2162 return ERROR_INVALID_PARAMETER
;
2165 /* Lock the service database exclusively */
2166 ScmLockDatabaseExclusive();
2168 lpService
= ScmGetServiceEntryByName(lpServiceName
);
2171 /* Unlock the service database */
2172 ScmUnlockDatabase();
2174 /* Check if it is marked for deletion */
2175 if (lpService
->bDeleted
)
2176 return ERROR_SERVICE_MARKED_FOR_DELETE
;
2178 /* Return Error exist */
2179 return ERROR_SERVICE_EXISTS
;
2182 if (lpDisplayName
!= NULL
&&
2183 ScmGetServiceEntryByDisplayName(lpDisplayName
) != NULL
)
2185 /* Unlock the service database */
2186 ScmUnlockDatabase();
2188 return ERROR_DUPLICATE_SERVICE_NAME
;
2191 if (dwServiceType
& SERVICE_DRIVER
)
2193 dwError
= ScmCanonDriverImagePath(dwStartType
,
2196 if (dwError
!= ERROR_SUCCESS
)
2201 if (dwStartType
== SERVICE_BOOT_START
||
2202 dwStartType
== SERVICE_SYSTEM_START
)
2204 /* Unlock the service database */
2205 ScmUnlockDatabase();
2207 return ERROR_INVALID_PARAMETER
;
2211 /* Allocate a new service entry */
2212 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
2214 if (dwError
!= ERROR_SUCCESS
)
2217 /* Fill the new service entry */
2218 lpService
->Status
.dwServiceType
= dwServiceType
;
2219 lpService
->dwStartType
= dwStartType
;
2220 lpService
->dwErrorControl
= dwErrorControl
;
2222 /* Fill the display name */
2223 if (lpDisplayName
!= NULL
&&
2224 *lpDisplayName
!= 0 &&
2225 _wcsicmp(lpService
->lpDisplayName
, lpDisplayName
) != 0)
2227 lpService
->lpDisplayName
= HeapAlloc(GetProcessHeap(),
2229 (wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
));
2230 if (lpService
->lpDisplayName
== NULL
)
2232 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
2235 wcscpy(lpService
->lpDisplayName
, lpDisplayName
);
2238 /* Assign the service to a group */
2239 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
2241 dwError
= ScmSetServiceGroup(lpService
,
2243 if (dwError
!= ERROR_SUCCESS
)
2247 /* Assign a new tag */
2248 if (lpdwTagId
!= NULL
)
2250 dwError
= ScmAssignNewTag(lpService
);
2251 if (dwError
!= ERROR_SUCCESS
)
2255 /* Write service data to the registry */
2256 /* Create the service key */
2257 dwError
= ScmCreateServiceKey(lpServiceName
,
2260 if (dwError
!= ERROR_SUCCESS
)
2263 /* Set the display name */
2264 if (lpDisplayName
!= NULL
&& *lpDisplayName
!= 0)
2266 RegSetValueExW(hServiceKey
,
2270 (LPBYTE
)lpDisplayName
,
2271 (DWORD
)((wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
)));
2274 /* Set the service type */
2275 dwError
= RegSetValueExW(hServiceKey
,
2279 (LPBYTE
)&dwServiceType
,
2281 if (dwError
!= ERROR_SUCCESS
)
2284 /* Set the start value */
2285 dwError
= RegSetValueExW(hServiceKey
,
2289 (LPBYTE
)&dwStartType
,
2291 if (dwError
!= ERROR_SUCCESS
)
2294 /* Set the error control value */
2295 dwError
= RegSetValueExW(hServiceKey
,
2299 (LPBYTE
)&dwErrorControl
,
2301 if (dwError
!= ERROR_SUCCESS
)
2304 /* Set the image path */
2305 if (dwServiceType
& SERVICE_WIN32
)
2307 dwError
= RegSetValueExW(hServiceKey
,
2311 (LPBYTE
)lpBinaryPathName
,
2312 (DWORD
)((wcslen(lpBinaryPathName
) + 1) * sizeof(WCHAR
)));
2313 if (dwError
!= ERROR_SUCCESS
)
2316 else if (dwServiceType
& SERVICE_DRIVER
)
2318 dwError
= RegSetValueExW(hServiceKey
,
2322 (LPBYTE
)lpImagePath
,
2323 (DWORD
)((wcslen(lpImagePath
) + 1) * sizeof(WCHAR
)));
2324 if (dwError
!= ERROR_SUCCESS
)
2328 /* Set the group name */
2329 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
2331 dwError
= RegSetValueExW(hServiceKey
,
2335 (LPBYTE
)lpLoadOrderGroup
,
2336 (DWORD
)((wcslen(lpLoadOrderGroup
) + 1) * sizeof(WCHAR
)));
2337 if (dwError
!= ERROR_SUCCESS
)
2341 if (lpdwTagId
!= NULL
)
2343 dwError
= RegSetValueExW(hServiceKey
,
2347 (LPBYTE
)&lpService
->dwTag
,
2349 if (dwError
!= ERROR_SUCCESS
)
2353 /* Write dependencies */
2354 if (lpDependencies
!= NULL
&& *lpDependencies
!= 0)
2356 dwError
= ScmWriteDependencies(hServiceKey
,
2357 (LPCWSTR
)lpDependencies
,
2359 if (dwError
!= ERROR_SUCCESS
)
2363 /* Write service start name */
2364 if (dwServiceType
& SERVICE_WIN32
)
2366 lpObjectName
= (lpServiceStartName
!= NULL
) ? (LPWSTR
)lpServiceStartName
: L
"LocalSystem";
2367 dwError
= RegSetValueExW(hServiceKey
,
2371 (LPBYTE
)lpObjectName
,
2372 (DWORD
)((wcslen(lpObjectName
) + 1) * sizeof(WCHAR
)));
2373 if (dwError
!= ERROR_SUCCESS
)
2377 if (lpPassword
!= NULL
)
2379 /* FIXME: Decrypt and write password */
2382 dwError
= ScmCreateServiceHandle(lpService
,
2384 if (dwError
!= ERROR_SUCCESS
)
2387 dwError
= ScmCheckAccess(hServiceHandle
,
2389 if (dwError
!= ERROR_SUCCESS
)
2392 lpService
->dwRefCount
= 1;
2393 DPRINT("CreateService - lpService->dwRefCount %u\n", lpService
->dwRefCount
);
2396 /* Unlock the service database */
2397 ScmUnlockDatabase();
2399 if (hServiceKey
!= NULL
)
2400 RegCloseKey(hServiceKey
);
2402 if (dwError
== ERROR_SUCCESS
)
2404 DPRINT("hService %p\n", hServiceHandle
);
2405 *lpServiceHandle
= (SC_RPC_HANDLE
)hServiceHandle
;
2407 if (lpdwTagId
!= NULL
)
2408 *lpdwTagId
= lpService
->dwTag
;
2412 if (lpService
!= NULL
&&
2413 lpService
->lpServiceName
!= NULL
)
2415 /* Release the display name buffer */
2416 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
2421 /* Remove the service handle */
2422 HeapFree(GetProcessHeap(), 0, hServiceHandle
);
2425 if (lpService
!= NULL
)
2427 /* FIXME: remove the service entry */
2431 if (lpImagePath
!= NULL
)
2432 HeapFree(GetProcessHeap(), 0, lpImagePath
);
2434 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError
);
2441 DWORD
REnumDependentServicesW(
2442 SC_RPC_HANDLE hService
,
2443 DWORD dwServiceState
,
2446 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
2447 LPBOUNDED_DWORD_256K lpServicesReturned
)
2449 DWORD dwError
= ERROR_SUCCESS
;
2450 DWORD dwServicesReturned
= 0;
2451 DWORD dwServiceCount
;
2452 HKEY hServicesKey
= NULL
;
2453 PSERVICE_HANDLE hSvc
;
2454 PSERVICE lpService
= NULL
;
2455 PSERVICE
*lpServicesArray
= NULL
;
2456 LPENUM_SERVICE_STATUSW lpServicesPtr
= NULL
;
2459 *pcbBytesNeeded
= 0;
2460 *lpServicesReturned
= 0;
2462 DPRINT("REnumDependentServicesW() called\n");
2464 hSvc
= ScmGetServiceFromHandle(hService
);
2467 DPRINT1("Invalid service handle!\n");
2468 return ERROR_INVALID_HANDLE
;
2471 lpService
= hSvc
->ServiceEntry
;
2473 /* Check access rights */
2474 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
2475 SC_MANAGER_ENUMERATE_SERVICE
))
2477 DPRINT("Insufficient access rights! 0x%lx\n",
2478 hSvc
->Handle
.DesiredAccess
);
2479 return ERROR_ACCESS_DENIED
;
2482 /* Open the Services Reg key */
2483 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2484 L
"System\\CurrentControlSet\\Services",
2488 if (dwError
!= ERROR_SUCCESS
)
2491 /* First determine the bytes needed and get the number of dependent services */
2492 dwError
= Int_EnumDependentServicesW(hServicesKey
,
2497 &dwServicesReturned
);
2498 if (dwError
!= ERROR_SUCCESS
)
2501 /* If buffer size is less than the bytes needed or pointer is null */
2502 if ((!lpServices
) || (cbBufSize
< *pcbBytesNeeded
))
2504 dwError
= ERROR_MORE_DATA
;
2508 /* Allocate memory for array of service pointers */
2509 lpServicesArray
= HeapAlloc(GetProcessHeap(),
2511 (dwServicesReturned
+ 1) * sizeof(PSERVICE
));
2512 if (!lpServicesArray
)
2514 DPRINT1("Could not allocate a buffer!!\n");
2515 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
2519 dwServicesReturned
= 0;
2520 *pcbBytesNeeded
= 0;
2522 dwError
= Int_EnumDependentServicesW(hServicesKey
,
2527 &dwServicesReturned
);
2528 if (dwError
!= ERROR_SUCCESS
)
2533 lpServicesPtr
= (LPENUM_SERVICE_STATUSW
)lpServices
;
2534 lpStr
= (LPWSTR
)(lpServices
+ (dwServicesReturned
* sizeof(ENUM_SERVICE_STATUSW
)));
2536 /* Copy EnumDepenedentService to Buffer */
2537 for (dwServiceCount
= 0; dwServiceCount
< dwServicesReturned
; dwServiceCount
++)
2539 lpService
= lpServicesArray
[dwServiceCount
];
2541 /* Copy status info */
2542 memcpy(&lpServicesPtr
->ServiceStatus
,
2544 sizeof(SERVICE_STATUS
));
2546 /* Copy display name */
2547 wcscpy(lpStr
, lpService
->lpDisplayName
);
2548 lpServicesPtr
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
2549 lpStr
+= (wcslen(lpService
->lpDisplayName
) + 1);
2551 /* Copy service name */
2552 wcscpy(lpStr
, lpService
->lpServiceName
);
2553 lpServicesPtr
->lpServiceName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
2554 lpStr
+= (wcslen(lpService
->lpServiceName
) + 1);
2559 *lpServicesReturned
= dwServicesReturned
;
2562 if (lpServicesArray
!= NULL
)
2563 HeapFree(GetProcessHeap(), 0, lpServicesArray
);
2565 RegCloseKey(hServicesKey
);
2567 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError
);
2574 DWORD
REnumServicesStatusW(
2575 SC_RPC_HANDLE hSCManager
,
2576 DWORD dwServiceType
,
2577 DWORD dwServiceState
,
2580 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
2581 LPBOUNDED_DWORD_256K lpServicesReturned
,
2582 LPBOUNDED_DWORD_256K lpResumeHandle
)
2584 /* Enumerate all the services, not regarding of their group */
2585 return REnumServiceGroupW(hSCManager
,
2598 DWORD
ROpenSCManagerW(
2599 LPWSTR lpMachineName
,
2600 LPWSTR lpDatabaseName
,
2601 DWORD dwDesiredAccess
,
2602 LPSC_RPC_HANDLE lpScHandle
)
2607 DPRINT("ROpenSCManagerW() called\n");
2608 DPRINT("lpMachineName = %p\n", lpMachineName
);
2609 DPRINT("lpMachineName: %S\n", lpMachineName
);
2610 DPRINT("lpDataBaseName = %p\n", lpDatabaseName
);
2611 DPRINT("lpDataBaseName: %S\n", lpDatabaseName
);
2612 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess
);
2615 return ERROR_SHUTDOWN_IN_PROGRESS
;
2618 return ERROR_INVALID_PARAMETER
;
2620 dwError
= ScmCreateManagerHandle(lpDatabaseName
,
2622 if (dwError
!= ERROR_SUCCESS
)
2624 DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError
);
2628 /* Check the desired access */
2629 dwError
= ScmCheckAccess(hHandle
,
2630 dwDesiredAccess
| SC_MANAGER_CONNECT
);
2631 if (dwError
!= ERROR_SUCCESS
)
2633 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError
);
2634 HeapFree(GetProcessHeap(), 0, hHandle
);
2638 *lpScHandle
= (SC_RPC_HANDLE
)hHandle
;
2639 DPRINT("*hScm = %p\n", *lpScHandle
);
2641 DPRINT("ROpenSCManagerW() done\n");
2643 return ERROR_SUCCESS
;
2648 DWORD
ROpenServiceW(
2649 SC_RPC_HANDLE hSCManager
,
2650 LPWSTR lpServiceName
,
2651 DWORD dwDesiredAccess
,
2652 LPSC_RPC_HANDLE lpServiceHandle
)
2655 PMANAGER_HANDLE hManager
;
2657 DWORD dwError
= ERROR_SUCCESS
;
2659 DPRINT("ROpenServiceW() called\n");
2660 DPRINT("hSCManager = %p\n", hSCManager
);
2661 DPRINT("lpServiceName = %p\n", lpServiceName
);
2662 DPRINT("lpServiceName: %S\n", lpServiceName
);
2663 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess
);
2666 return ERROR_SHUTDOWN_IN_PROGRESS
;
2668 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
2669 if (hManager
== NULL
)
2671 DPRINT1("Invalid service manager handle!\n");
2672 return ERROR_INVALID_HANDLE
;
2675 if (!lpServiceHandle
)
2676 return ERROR_INVALID_PARAMETER
;
2679 return ERROR_INVALID_ADDRESS
;
2681 /* Lock the service database exclusive */
2682 ScmLockDatabaseExclusive();
2684 /* Get service database entry */
2685 lpService
= ScmGetServiceEntryByName(lpServiceName
);
2686 if (lpService
== NULL
)
2688 DPRINT("Could not find a service!\n");
2689 dwError
= ERROR_SERVICE_DOES_NOT_EXIST
;
2693 /* Create a service handle */
2694 dwError
= ScmCreateServiceHandle(lpService
,
2696 if (dwError
!= ERROR_SUCCESS
)
2698 DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError
);
2702 /* Check the desired access */
2703 dwError
= ScmCheckAccess(hHandle
,
2705 if (dwError
!= ERROR_SUCCESS
)
2707 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError
);
2708 HeapFree(GetProcessHeap(), 0, hHandle
);
2712 lpService
->dwRefCount
++;
2713 DPRINT("OpenService - lpService->dwRefCount %u\n",lpService
->dwRefCount
);
2715 *lpServiceHandle
= (SC_RPC_HANDLE
)hHandle
;
2716 DPRINT("*hService = %p\n", *lpServiceHandle
);
2719 /* Unlock the service database */
2720 ScmUnlockDatabase();
2722 DPRINT("ROpenServiceW() done\n");
2729 DWORD
RQueryServiceConfigW(
2730 SC_RPC_HANDLE hService
,
2731 LPBYTE lpBuf
, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2733 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
2735 LPQUERY_SERVICE_CONFIGW lpServiceConfig
= (LPQUERY_SERVICE_CONFIGW
)lpBuf
;
2736 DWORD dwError
= ERROR_SUCCESS
;
2737 PSERVICE_HANDLE hSvc
;
2738 PSERVICE lpService
= NULL
;
2739 HKEY hServiceKey
= NULL
;
2740 LPWSTR lpImagePath
= NULL
;
2741 LPWSTR lpServiceStartName
= NULL
;
2742 LPWSTR lpDependencies
= NULL
;
2743 DWORD dwDependenciesLength
= 0;
2744 DWORD dwRequiredSize
;
2745 WCHAR lpEmptyString
[] = {0,0};
2748 DPRINT("RQueryServiceConfigW() called\n");
2751 return ERROR_SHUTDOWN_IN_PROGRESS
;
2753 hSvc
= ScmGetServiceFromHandle(hService
);
2756 DPRINT1("Invalid service handle!\n");
2757 return ERROR_INVALID_HANDLE
;
2760 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
2761 SERVICE_QUERY_CONFIG
))
2763 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
2764 return ERROR_ACCESS_DENIED
;
2767 lpService
= hSvc
->ServiceEntry
;
2768 if (lpService
== NULL
)
2770 DPRINT("lpService == NULL!\n");
2771 return ERROR_INVALID_HANDLE
;
2774 /* Lock the service database shared */
2775 ScmLockDatabaseShared();
2777 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
2780 if (dwError
!= ERROR_SUCCESS
)
2783 /* Read the image path */
2784 dwError
= ScmReadString(hServiceKey
,
2787 if (dwError
!= ERROR_SUCCESS
)
2790 /* Read the service start name */
2791 ScmReadString(hServiceKey
,
2793 &lpServiceStartName
);
2795 /* Read the dependencies */
2796 ScmReadDependencies(hServiceKey
,
2798 &dwDependenciesLength
);
2800 dwRequiredSize
= sizeof(QUERY_SERVICE_CONFIGW
);
2802 if (lpImagePath
!= NULL
)
2803 dwRequiredSize
+= (DWORD
)((wcslen(lpImagePath
) + 1) * sizeof(WCHAR
));
2805 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2807 if ((lpService
->lpGroup
!= NULL
) && (lpService
->lpGroup
->lpGroupName
!= NULL
))
2808 dwRequiredSize
+= (DWORD
)((wcslen(lpService
->lpGroup
->lpGroupName
) + 1) * sizeof(WCHAR
));
2810 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2812 if (lpDependencies
!= NULL
)
2813 dwRequiredSize
+= dwDependenciesLength
* sizeof(WCHAR
);
2815 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2817 if (lpServiceStartName
!= NULL
)
2818 dwRequiredSize
+= (DWORD
)((wcslen(lpServiceStartName
) + 1) * sizeof(WCHAR
));
2820 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2822 if (lpService
->lpDisplayName
!= NULL
)
2823 dwRequiredSize
+= (DWORD
)((wcslen(lpService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
2825 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2827 if (lpServiceConfig
== NULL
|| cbBufSize
< dwRequiredSize
)
2829 dwError
= ERROR_INSUFFICIENT_BUFFER
;
2833 lpServiceConfig
->dwServiceType
= lpService
->Status
.dwServiceType
;
2834 lpServiceConfig
->dwStartType
= lpService
->dwStartType
;
2835 lpServiceConfig
->dwErrorControl
= lpService
->dwErrorControl
;
2836 lpServiceConfig
->dwTagId
= lpService
->dwTag
;
2838 lpStr
= (LPWSTR
)(lpServiceConfig
+ 1);
2840 /* Append the image path */
2841 if (lpImagePath
!= NULL
)
2843 wcscpy(lpStr
, lpImagePath
);
2847 wcscpy(lpStr
, lpEmptyString
);
2850 lpServiceConfig
->lpBinaryPathName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2851 lpStr
+= (wcslen(lpStr
) + 1);
2853 /* Append the group name */
2854 if ((lpService
->lpGroup
!= NULL
) && (lpService
->lpGroup
->lpGroupName
!= NULL
))
2856 wcscpy(lpStr
, lpService
->lpGroup
->lpGroupName
);
2860 wcscpy(lpStr
, lpEmptyString
);
2863 lpServiceConfig
->lpLoadOrderGroup
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2864 lpStr
+= (wcslen(lpStr
) + 1);
2866 /* Append Dependencies */
2867 if (lpDependencies
!= NULL
)
2871 dwDependenciesLength
* sizeof(WCHAR
));
2875 wcscpy(lpStr
, lpEmptyString
);
2878 lpServiceConfig
->lpDependencies
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2879 if (lpDependencies
!= NULL
)
2880 lpStr
+= dwDependenciesLength
;
2882 lpStr
+= (wcslen(lpStr
) + 1);
2884 /* Append the service start name */
2885 if (lpServiceStartName
!= NULL
)
2887 wcscpy(lpStr
, lpServiceStartName
);
2891 wcscpy(lpStr
, lpEmptyString
);
2894 lpServiceConfig
->lpServiceStartName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2895 lpStr
+= (wcslen(lpStr
) + 1);
2897 /* Append the display name */
2898 if (lpService
->lpDisplayName
!= NULL
)
2900 wcscpy(lpStr
, lpService
->lpDisplayName
);
2904 wcscpy(lpStr
, lpEmptyString
);
2907 lpServiceConfig
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2910 if (pcbBytesNeeded
!= NULL
)
2911 *pcbBytesNeeded
= dwRequiredSize
;
2914 /* Unlock the service database */
2915 ScmUnlockDatabase();
2917 if (lpImagePath
!= NULL
)
2918 HeapFree(GetProcessHeap(), 0, lpImagePath
);
2920 if (lpServiceStartName
!= NULL
)
2921 HeapFree(GetProcessHeap(), 0, lpServiceStartName
);
2923 if (lpDependencies
!= NULL
)
2924 HeapFree(GetProcessHeap(), 0, lpDependencies
);
2926 if (hServiceKey
!= NULL
)
2927 RegCloseKey(hServiceKey
);
2929 DPRINT("RQueryServiceConfigW() done\n");
2936 DWORD
RQueryServiceLockStatusW(
2937 SC_RPC_HANDLE hSCManager
,
2938 LPBYTE lpBuf
, // LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2940 LPBOUNDED_DWORD_4K pcbBytesNeeded
)
2942 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
= (LPQUERY_SERVICE_LOCK_STATUSW
)lpBuf
;
2943 PMANAGER_HANDLE hMgr
;
2944 DWORD dwRequiredSize
;
2946 if (!lpLockStatus
|| !pcbBytesNeeded
)
2947 return ERROR_INVALID_PARAMETER
;
2949 hMgr
= ScmGetServiceManagerFromHandle(hSCManager
);
2952 DPRINT1("Invalid service manager handle!\n");
2953 return ERROR_INVALID_HANDLE
;
2956 if (!RtlAreAllAccessesGranted(hMgr
->Handle
.DesiredAccess
,
2957 SC_MANAGER_QUERY_LOCK_STATUS
))
2959 DPRINT("Insufficient access rights! 0x%lx\n", hMgr
->Handle
.DesiredAccess
);
2960 return ERROR_ACCESS_DENIED
;
2963 /* FIXME: we need to compute instead the real length of the owner name */
2964 dwRequiredSize
= sizeof(QUERY_SERVICE_LOCK_STATUSW
) + sizeof(WCHAR
);
2965 *pcbBytesNeeded
= dwRequiredSize
;
2967 if (cbBufSize
< dwRequiredSize
)
2968 return ERROR_INSUFFICIENT_BUFFER
;
2970 ScmQueryServiceLockStatusW(lpLockStatus
);
2972 return ERROR_SUCCESS
;
2977 DWORD
RStartServiceW(
2978 SC_RPC_HANDLE hService
,
2980 LPSTRING_PTRSW argv
)
2982 DWORD dwError
= ERROR_SUCCESS
;
2983 PSERVICE_HANDLE hSvc
;
2984 PSERVICE lpService
= NULL
;
2989 DPRINT("RStartServiceW(%p %lu %p) called\n", hService
, argc
, argv
);
2990 DPRINT(" argc: %lu\n", argc
);
2993 for (i
= 0; i
< argc
; i
++)
2995 DPRINT(" argv[%lu]: %S\n", i
, argv
[i
].StringPtr
);
3001 return ERROR_SHUTDOWN_IN_PROGRESS
;
3003 hSvc
= ScmGetServiceFromHandle(hService
);
3006 DPRINT1("Invalid service handle!\n");
3007 return ERROR_INVALID_HANDLE
;
3010 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3013 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
3014 return ERROR_ACCESS_DENIED
;
3017 lpService
= hSvc
->ServiceEntry
;
3018 if (lpService
== NULL
)
3020 DPRINT("lpService == NULL!\n");
3021 return ERROR_INVALID_HANDLE
;
3024 if (lpService
->dwStartType
== SERVICE_DISABLED
)
3025 return ERROR_SERVICE_DISABLED
;
3027 if (lpService
->bDeleted
)
3028 return ERROR_SERVICE_MARKED_FOR_DELETE
;
3030 /* Start the service */
3031 dwError
= ScmStartService(lpService
, argc
, (LPWSTR
*)argv
);
3038 DWORD
RGetServiceDisplayNameW(
3039 SC_RPC_HANDLE hSCManager
,
3040 LPCWSTR lpServiceName
,
3041 LPWSTR lpDisplayName
,
3044 // PMANAGER_HANDLE hManager;
3049 DPRINT("RGetServiceDisplayNameW() called\n");
3050 DPRINT("hSCManager = %p\n", hSCManager
);
3051 DPRINT("lpServiceName: %S\n", lpServiceName
);
3052 DPRINT("lpDisplayName: %p\n", lpDisplayName
);
3053 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
3055 // hManager = (PMANAGER_HANDLE)hSCManager;
3056 // if (hManager->Handle.Tag != MANAGER_TAG)
3058 // DPRINT("Invalid manager handle!\n");
3059 // return ERROR_INVALID_HANDLE;
3062 /* Get service database entry */
3063 lpService
= ScmGetServiceEntryByName(lpServiceName
);
3064 if (lpService
== NULL
)
3066 DPRINT("Could not find a service!\n");
3068 /* If the service could not be found and lpcchBuffer is less than 2, windows
3069 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3070 if (*lpcchBuffer
< 2)
3073 if (lpDisplayName
!= NULL
)
3079 return ERROR_SERVICE_DOES_NOT_EXIST
;
3082 if (!lpService
->lpDisplayName
)
3084 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
3086 if (lpDisplayName
!= NULL
&&
3087 *lpcchBuffer
> dwLength
)
3089 wcscpy(lpDisplayName
, lpService
->lpServiceName
);
3094 dwLength
= (DWORD
)wcslen(lpService
->lpDisplayName
);
3096 if (lpDisplayName
!= NULL
&&
3097 *lpcchBuffer
> dwLength
)
3099 wcscpy(lpDisplayName
, lpService
->lpDisplayName
);
3103 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
3105 *lpcchBuffer
= dwLength
;
3112 DWORD
RGetServiceKeyNameW(
3113 SC_RPC_HANDLE hSCManager
,
3114 LPCWSTR lpDisplayName
,
3115 LPWSTR lpServiceName
,
3118 // PMANAGER_HANDLE hManager;
3123 DPRINT("RGetServiceKeyNameW() called\n");
3124 DPRINT("hSCManager = %p\n", hSCManager
);
3125 DPRINT("lpDisplayName: %S\n", lpDisplayName
);
3126 DPRINT("lpServiceName: %p\n", lpServiceName
);
3127 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
3129 // hManager = (PMANAGER_HANDLE)hSCManager;
3130 // if (hManager->Handle.Tag != MANAGER_TAG)
3132 // DPRINT("Invalid manager handle!\n");
3133 // return ERROR_INVALID_HANDLE;
3136 /* Get service database entry */
3137 lpService
= ScmGetServiceEntryByDisplayName(lpDisplayName
);
3138 if (lpService
== NULL
)
3140 DPRINT("Could not find a service!\n");
3142 /* If the service could not be found and lpcchBuffer is less than 2, windows
3143 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3144 if (*lpcchBuffer
< 2)
3147 if (lpServiceName
!= NULL
)
3153 return ERROR_SERVICE_DOES_NOT_EXIST
;
3156 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
3158 if (lpServiceName
!= NULL
&&
3159 *lpcchBuffer
> dwLength
)
3161 wcscpy(lpServiceName
, lpService
->lpServiceName
);
3162 *lpcchBuffer
= dwLength
;
3163 return ERROR_SUCCESS
;
3166 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
3168 *lpcchBuffer
= dwLength
;
3175 DWORD
RI_ScSetServiceBitsA(
3176 RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
3177 DWORD dwServiceBits
,
3179 int bUpdateImmediately
,
3183 return ERROR_CALL_NOT_IMPLEMENTED
;
3188 DWORD
RChangeServiceConfigA(
3189 SC_RPC_HANDLE hService
,
3190 DWORD dwServiceType
,
3192 DWORD dwErrorControl
,
3193 LPSTR lpBinaryPathName
,
3194 LPSTR lpLoadOrderGroup
,
3196 LPBYTE lpDependencies
,
3198 LPSTR lpServiceStartName
,
3201 LPSTR lpDisplayName
)
3203 DWORD dwError
= ERROR_SUCCESS
;
3204 PSERVICE_HANDLE hSvc
;
3205 PSERVICE lpService
= NULL
;
3206 HKEY hServiceKey
= NULL
;
3207 LPWSTR lpDisplayNameW
= NULL
;
3208 LPWSTR lpBinaryPathNameW
= NULL
;
3209 LPWSTR lpCanonicalImagePathW
= NULL
;
3210 LPWSTR lpLoadOrderGroupW
= NULL
;
3211 LPWSTR lpDependenciesW
= NULL
;
3213 DPRINT("RChangeServiceConfigA() called\n");
3214 DPRINT("dwServiceType = %lu\n", dwServiceType
);
3215 DPRINT("dwStartType = %lu\n", dwStartType
);
3216 DPRINT("dwErrorControl = %lu\n", dwErrorControl
);
3217 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName
);
3218 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup
);
3219 DPRINT("lpDisplayName = %s\n", lpDisplayName
);
3222 return ERROR_SHUTDOWN_IN_PROGRESS
;
3224 hSvc
= ScmGetServiceFromHandle(hService
);
3227 DPRINT1("Invalid service handle!\n");
3228 return ERROR_INVALID_HANDLE
;
3231 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3232 SERVICE_CHANGE_CONFIG
))
3234 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
3235 return ERROR_ACCESS_DENIED
;
3238 lpService
= hSvc
->ServiceEntry
;
3239 if (lpService
== NULL
)
3241 DPRINT("lpService == NULL!\n");
3242 return ERROR_INVALID_HANDLE
;
3245 /* Lock the service database exclusively */
3246 ScmLockDatabaseExclusive();
3248 if (lpService
->bDeleted
)
3250 DPRINT("The service has already been marked for delete!\n");
3251 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
3255 /* Open the service key */
3256 dwError
= ScmOpenServiceKey(lpService
->szServiceName
,
3259 if (dwError
!= ERROR_SUCCESS
)
3262 /* Write service data to the registry */
3264 if (lpDisplayName
!= NULL
&& *lpDisplayName
!= 0)
3266 /* Set the display name */
3267 lpDisplayNameW
= HeapAlloc(GetProcessHeap(),
3269 (strlen(lpDisplayName
) + 1) * sizeof(WCHAR
));
3270 if (lpDisplayNameW
== NULL
)
3272 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3276 MultiByteToWideChar(CP_ACP
,
3281 (int)(strlen(lpDisplayName
) + 1));
3283 RegSetValueExW(hServiceKey
,
3287 (LPBYTE
)lpDisplayNameW
,
3288 (DWORD
)((wcslen(lpDisplayNameW
) + 1) * sizeof(WCHAR
)));
3290 /* Update lpService->lpDisplayName */
3291 if (lpService
->lpDisplayName
)
3292 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
3294 lpService
->lpDisplayName
= lpDisplayNameW
;
3297 if (dwServiceType
!= SERVICE_NO_CHANGE
)
3299 /* Set the service type */
3300 dwError
= RegSetValueExW(hServiceKey
,
3304 (LPBYTE
)&dwServiceType
,
3306 if (dwError
!= ERROR_SUCCESS
)
3309 lpService
->Status
.dwServiceType
= dwServiceType
;
3312 if (dwStartType
!= SERVICE_NO_CHANGE
)
3314 /* Set the start value */
3315 dwError
= RegSetValueExW(hServiceKey
,
3319 (LPBYTE
)&dwStartType
,
3321 if (dwError
!= ERROR_SUCCESS
)
3324 lpService
->dwStartType
= dwStartType
;
3327 if (dwErrorControl
!= SERVICE_NO_CHANGE
)
3329 /* Set the error control value */
3330 dwError
= RegSetValueExW(hServiceKey
,
3334 (LPBYTE
)&dwErrorControl
,
3336 if (dwError
!= ERROR_SUCCESS
)
3339 lpService
->dwErrorControl
= dwErrorControl
;
3342 if (lpBinaryPathName
!= NULL
&& *lpBinaryPathName
!= 0)
3344 /* Set the image path */
3345 lpBinaryPathNameW
= HeapAlloc(GetProcessHeap(),
3347 (strlen(lpBinaryPathName
) + 1) * sizeof(WCHAR
));
3348 if (lpBinaryPathNameW
== NULL
)
3350 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3354 MultiByteToWideChar(CP_ACP
,
3359 (int)(strlen(lpBinaryPathName
) + 1));
3361 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
3363 dwError
= ScmCanonDriverImagePath(lpService
->dwStartType
,
3365 &lpCanonicalImagePathW
);
3367 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW
);
3369 if (dwError
!= ERROR_SUCCESS
)
3372 lpBinaryPathNameW
= lpCanonicalImagePathW
;
3375 dwError
= RegSetValueExW(hServiceKey
,
3379 (LPBYTE
)lpBinaryPathNameW
,
3380 (DWORD
)((wcslen(lpBinaryPathNameW
) + 1) * sizeof(WCHAR
)));
3382 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW
);
3384 if (dwError
!= ERROR_SUCCESS
)
3388 /* Set the group name */
3389 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
3391 lpLoadOrderGroupW
= HeapAlloc(GetProcessHeap(),
3393 (strlen(lpLoadOrderGroup
) + 1) * sizeof(WCHAR
));
3394 if (lpLoadOrderGroupW
== NULL
)
3396 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3400 MultiByteToWideChar(CP_ACP
,
3405 (int)(strlen(lpLoadOrderGroup
) + 1));
3407 dwError
= RegSetValueExW(hServiceKey
,
3411 (LPBYTE
)lpLoadOrderGroupW
,
3412 (DWORD
)((wcslen(lpLoadOrderGroupW
) + 1) * sizeof(WCHAR
)));
3413 if (dwError
!= ERROR_SUCCESS
)
3415 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3419 dwError
= ScmSetServiceGroup(lpService
,
3422 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3424 if (dwError
!= ERROR_SUCCESS
)
3428 if (lpdwTagId
!= NULL
)
3430 dwError
= ScmAssignNewTag(lpService
);
3431 if (dwError
!= ERROR_SUCCESS
)
3434 dwError
= RegSetValueExW(hServiceKey
,
3438 (LPBYTE
)&lpService
->dwTag
,
3440 if (dwError
!= ERROR_SUCCESS
)
3443 *lpdwTagId
= lpService
->dwTag
;
3446 /* Write dependencies */
3447 if (lpDependencies
!= NULL
&& *lpDependencies
!= 0)
3449 lpDependenciesW
= HeapAlloc(GetProcessHeap(),
3451 (strlen((LPSTR
)lpDependencies
) + 1) * sizeof(WCHAR
));
3452 if (lpDependenciesW
== NULL
)
3454 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3458 MultiByteToWideChar(CP_ACP
,
3460 (LPSTR
)lpDependencies
,
3463 (int)(strlen((LPSTR
)lpDependencies
) + 1));
3465 dwError
= ScmWriteDependencies(hServiceKey
,
3466 (LPWSTR
)lpDependenciesW
,
3469 HeapFree(GetProcessHeap(), 0, lpDependenciesW
);
3472 if (lpPassword
!= NULL
)
3474 /* FIXME: Decrypt and write password */
3478 /* Unlock the service database */
3479 ScmUnlockDatabase();
3481 if (hServiceKey
!= NULL
)
3482 RegCloseKey(hServiceKey
);
3484 DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError
);
3491 DWORD
RCreateServiceA(
3492 SC_RPC_HANDLE hSCManager
,
3493 LPSTR lpServiceName
,
3494 LPSTR lpDisplayName
,
3495 DWORD dwDesiredAccess
,
3496 DWORD dwServiceType
,
3498 DWORD dwErrorControl
,
3499 LPSTR lpBinaryPathName
,
3500 LPSTR lpLoadOrderGroup
,
3502 LPBYTE lpDependencies
,
3504 LPSTR lpServiceStartName
,
3507 LPSC_RPC_HANDLE lpServiceHandle
)
3509 DWORD dwError
= ERROR_SUCCESS
;
3510 LPWSTR lpServiceNameW
= NULL
;
3511 LPWSTR lpDisplayNameW
= NULL
;
3512 LPWSTR lpBinaryPathNameW
= NULL
;
3513 LPWSTR lpLoadOrderGroupW
= NULL
;
3514 LPWSTR lpDependenciesW
= NULL
;
3515 LPWSTR lpServiceStartNameW
= NULL
;
3516 DWORD dwDependenciesLength
= 0;
3523 len
= MultiByteToWideChar(CP_ACP
, 0, lpServiceName
, -1, NULL
, 0);
3524 lpServiceNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3525 if (!lpServiceNameW
)
3527 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3530 MultiByteToWideChar(CP_ACP
, 0, lpServiceName
, -1, lpServiceNameW
, len
);
3535 len
= MultiByteToWideChar(CP_ACP
, 0, lpDisplayName
, -1, NULL
, 0);
3536 lpDisplayNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3537 if (!lpDisplayNameW
)
3539 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3542 MultiByteToWideChar(CP_ACP
, 0, lpDisplayName
, -1, lpDisplayNameW
, len
);
3545 if (lpBinaryPathName
)
3547 len
= MultiByteToWideChar(CP_ACP
, 0, lpBinaryPathName
, -1, NULL
, 0);
3548 lpBinaryPathNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3549 if (!lpBinaryPathNameW
)
3551 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3554 MultiByteToWideChar(CP_ACP
, 0, lpBinaryPathName
, -1, lpBinaryPathNameW
, len
);
3557 if (lpLoadOrderGroup
)
3559 len
= MultiByteToWideChar(CP_ACP
, 0, lpLoadOrderGroup
, -1, NULL
, 0);
3560 lpLoadOrderGroupW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3561 if (!lpLoadOrderGroupW
)
3563 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3566 MultiByteToWideChar(CP_ACP
, 0, lpLoadOrderGroup
, -1, lpLoadOrderGroupW
, len
);
3571 lpStr
= (LPCSTR
)lpDependencies
;
3574 cchLength
= strlen(lpStr
) + 1;
3575 dwDependenciesLength
+= (DWORD
)cchLength
;
3576 lpStr
= lpStr
+ cchLength
;
3578 dwDependenciesLength
++;
3580 lpDependenciesW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwDependenciesLength
* sizeof(WCHAR
));
3581 if (!lpDependenciesW
)
3583 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3586 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)lpDependencies
, dwDependenciesLength
, lpDependenciesW
, dwDependenciesLength
);
3589 if (lpServiceStartName
)
3591 len
= MultiByteToWideChar(CP_ACP
, 0, lpServiceStartName
, -1, NULL
, 0);
3592 lpServiceStartNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3593 if (!lpServiceStartNameW
)
3595 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3598 MultiByteToWideChar(CP_ACP
, 0, lpServiceStartName
, -1, lpServiceStartNameW
, len
);
3601 dwError
= RCreateServiceW(hSCManager
,
3611 (LPBYTE
)lpDependenciesW
,
3612 dwDependenciesLength
,
3613 lpServiceStartNameW
,
3619 if (lpServiceNameW
!=NULL
)
3620 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
3622 if (lpDisplayNameW
!= NULL
)
3623 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
3625 if (lpBinaryPathNameW
!= NULL
)
3626 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW
);
3628 if (lpLoadOrderGroupW
!= NULL
)
3629 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3631 if (lpDependenciesW
!= NULL
)
3632 HeapFree(GetProcessHeap(), 0, lpDependenciesW
);
3634 if (lpServiceStartNameW
!= NULL
)
3635 HeapFree(GetProcessHeap(), 0, lpServiceStartNameW
);
3642 DWORD
REnumDependentServicesA(
3643 SC_RPC_HANDLE hService
,
3644 DWORD dwServiceState
,
3647 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
3648 LPBOUNDED_DWORD_256K lpServicesReturned
)
3650 DWORD dwError
= ERROR_SUCCESS
;
3651 DWORD dwServicesReturned
= 0;
3652 DWORD dwServiceCount
;
3653 HKEY hServicesKey
= NULL
;
3654 PSERVICE_HANDLE hSvc
;
3655 PSERVICE lpService
= NULL
;
3656 PSERVICE
*lpServicesArray
= NULL
;
3657 LPENUM_SERVICE_STATUSA lpServicesPtr
= NULL
;
3660 *pcbBytesNeeded
= 0;
3661 *lpServicesReturned
= 0;
3663 DPRINT("REnumDependentServicesA() called\n");
3665 hSvc
= ScmGetServiceFromHandle(hService
);
3668 DPRINT1("Invalid service handle!\n");
3669 return ERROR_INVALID_HANDLE
;
3672 lpService
= hSvc
->ServiceEntry
;
3674 /* Check access rights */
3675 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3676 SC_MANAGER_ENUMERATE_SERVICE
))
3678 DPRINT("Insufficient access rights! 0x%lx\n",
3679 hSvc
->Handle
.DesiredAccess
);
3680 return ERROR_ACCESS_DENIED
;
3683 /* Open the Services Reg key */
3684 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
3685 L
"System\\CurrentControlSet\\Services",
3690 if (dwError
!= ERROR_SUCCESS
)
3693 /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3694 both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3695 are the same for both. Verified in WINXP. */
3697 /* First determine the bytes needed and get the number of dependent services*/
3698 dwError
= Int_EnumDependentServicesW(hServicesKey
,
3703 &dwServicesReturned
);
3704 if (dwError
!= ERROR_SUCCESS
)
3707 /* If buffer size is less than the bytes needed or pointer is null*/
3708 if ((!lpServices
) || (cbBufSize
< *pcbBytesNeeded
))
3710 dwError
= ERROR_MORE_DATA
;
3714 /* Allocate memory for array of service pointers */
3715 lpServicesArray
= HeapAlloc(GetProcessHeap(),
3717 (dwServicesReturned
+ 1) * sizeof(PSERVICE
));
3718 if (!lpServicesArray
)
3720 DPRINT("Could not allocate a buffer!!\n");
3721 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3725 dwServicesReturned
= 0;
3726 *pcbBytesNeeded
= 0;
3728 dwError
= Int_EnumDependentServicesW(hServicesKey
,
3733 &dwServicesReturned
);
3734 if (dwError
!= ERROR_SUCCESS
)
3739 lpServicesPtr
= (LPENUM_SERVICE_STATUSA
)lpServices
;
3740 lpStr
= (LPSTR
)(lpServices
+ (dwServicesReturned
* sizeof(ENUM_SERVICE_STATUSA
)));
3742 /* Copy EnumDepenedentService to Buffer */
3743 for (dwServiceCount
= 0; dwServiceCount
< dwServicesReturned
; dwServiceCount
++)
3745 lpService
= lpServicesArray
[dwServiceCount
];
3747 /* Copy the status info */
3748 memcpy(&lpServicesPtr
->ServiceStatus
,
3750 sizeof(SERVICE_STATUS
));
3752 /* Copy display name */
3753 WideCharToMultiByte(CP_ACP
,
3755 lpService
->lpDisplayName
,
3758 (int)wcslen(lpService
->lpDisplayName
),
3761 lpServicesPtr
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
3762 lpStr
+= strlen(lpStr
) + 1;
3764 /* Copy service name */
3765 WideCharToMultiByte(CP_ACP
,
3767 lpService
->lpServiceName
,
3770 (int)wcslen(lpService
->lpServiceName
),
3773 lpServicesPtr
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
3774 lpStr
+= strlen(lpStr
) + 1;
3779 *lpServicesReturned
= dwServicesReturned
;
3782 if (lpServicesArray
)
3783 HeapFree(GetProcessHeap(), 0, lpServicesArray
);
3785 RegCloseKey(hServicesKey
);
3787 DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError
);
3794 DWORD
REnumServicesStatusA(
3795 SC_RPC_HANDLE hSCManager
,
3796 DWORD dwServiceType
,
3797 DWORD dwServiceState
,
3800 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
3801 LPBOUNDED_DWORD_256K lpServicesReturned
,
3802 LPBOUNDED_DWORD_256K lpResumeHandle
)
3804 LPENUM_SERVICE_STATUSW lpStatusPtrW
= NULL
;
3805 LPENUM_SERVICE_STATUSW lpStatusPtrIncrW
;
3806 LPENUM_SERVICE_STATUSA lpStatusPtrA
= NULL
;
3807 LPWSTR lpStringPtrW
;
3810 DWORD dwServiceCount
;
3812 DPRINT("REnumServicesStatusA() called\n");
3814 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
3816 return ERROR_INVALID_ADDRESS
;
3819 if ((dwBufSize
> 0) && (lpBuffer
))
3821 lpStatusPtrW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwBufSize
);
3824 DPRINT("Failed to allocate buffer!\n");
3825 return ERROR_NOT_ENOUGH_MEMORY
;
3829 dwError
= REnumServicesStatusW(hSCManager
,
3832 (LPBYTE
)lpStatusPtrW
,
3838 /* if no services were returned then we are Done */
3839 if (*lpServicesReturned
== 0)
3842 lpStatusPtrIncrW
= lpStatusPtrW
;
3843 lpStatusPtrA
= (LPENUM_SERVICE_STATUSA
)lpBuffer
;
3844 lpStringPtrA
= (LPSTR
)((ULONG_PTR
)lpBuffer
+
3845 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUSA
));
3846 lpStringPtrW
= (LPWSTR
)((ULONG_PTR
)lpStatusPtrW
+
3847 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUSW
));
3849 for (dwServiceCount
= 0; dwServiceCount
< *lpServicesReturned
; dwServiceCount
++)
3851 /* Copy the service name */
3852 WideCharToMultiByte(CP_ACP
,
3857 (int)wcslen(lpStringPtrW
),
3861 lpStatusPtrA
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
3862 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
3863 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
3865 /* Copy the display name */
3866 WideCharToMultiByte(CP_ACP
,
3871 (int)wcslen(lpStringPtrW
),
3875 lpStatusPtrA
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
3876 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
3877 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
3879 /* Copy the status information */
3880 memcpy(&lpStatusPtrA
->ServiceStatus
,
3881 &lpStatusPtrIncrW
->ServiceStatus
,
3882 sizeof(SERVICE_STATUS
));
3890 HeapFree(GetProcessHeap(), 0, lpStatusPtrW
);
3892 DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError
);
3899 DWORD
ROpenSCManagerA(
3900 LPSTR lpMachineName
,
3901 LPSTR lpDatabaseName
,
3902 DWORD dwDesiredAccess
,
3903 LPSC_RPC_HANDLE lpScHandle
)
3905 UNICODE_STRING MachineName
;
3906 UNICODE_STRING DatabaseName
;
3909 DPRINT("ROpenSCManagerA() called\n");
3912 RtlCreateUnicodeStringFromAsciiz(&MachineName
,
3916 RtlCreateUnicodeStringFromAsciiz(&DatabaseName
,
3919 dwError
= ROpenSCManagerW(lpMachineName
? MachineName
.Buffer
: NULL
,
3920 lpDatabaseName
? DatabaseName
.Buffer
: NULL
,
3925 RtlFreeUnicodeString(&MachineName
);
3928 RtlFreeUnicodeString(&DatabaseName
);
3935 DWORD
ROpenServiceA(
3936 SC_RPC_HANDLE hSCManager
,
3937 LPSTR lpServiceName
,
3938 DWORD dwDesiredAccess
,
3939 LPSC_RPC_HANDLE lpServiceHandle
)
3941 UNICODE_STRING ServiceName
;
3944 DPRINT("ROpenServiceA() called\n");
3947 RtlCreateUnicodeStringFromAsciiz(&ServiceName
,
3950 dwError
= ROpenServiceW(hSCManager
,
3951 lpServiceName
? ServiceName
.Buffer
: NULL
,
3956 RtlFreeUnicodeString(&ServiceName
);
3963 DWORD
RQueryServiceConfigA(
3964 SC_RPC_HANDLE hService
,
3965 LPBYTE lpBuf
, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
3967 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
3969 LPQUERY_SERVICE_CONFIGA lpServiceConfig
= (LPQUERY_SERVICE_CONFIGA
)lpBuf
;
3970 DWORD dwError
= ERROR_SUCCESS
;
3971 PSERVICE_HANDLE hSvc
;
3972 PSERVICE lpService
= NULL
;
3973 HKEY hServiceKey
= NULL
;
3974 LPWSTR lpImagePath
= NULL
;
3975 LPWSTR lpServiceStartName
= NULL
;
3976 LPWSTR lpDependencies
= NULL
;
3977 DWORD dwDependenciesLength
= 0;
3978 DWORD dwRequiredSize
;
3979 CHAR lpEmptyString
[]={0,0};
3982 DPRINT("RQueryServiceConfigA() called\n");
3985 return ERROR_SHUTDOWN_IN_PROGRESS
;
3987 hSvc
= ScmGetServiceFromHandle(hService
);
3990 DPRINT1("Invalid service handle!\n");
3991 return ERROR_INVALID_HANDLE
;
3994 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3995 SERVICE_QUERY_CONFIG
))
3997 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
3998 return ERROR_ACCESS_DENIED
;
4001 lpService
= hSvc
->ServiceEntry
;
4002 if (lpService
== NULL
)
4004 DPRINT("lpService == NULL!\n");
4005 return ERROR_INVALID_HANDLE
;
4008 /* Lock the service database shared */
4009 ScmLockDatabaseShared();
4011 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
4014 if (dwError
!= ERROR_SUCCESS
)
4017 /* Read the image path */
4018 dwError
= ScmReadString(hServiceKey
,
4021 if (dwError
!= ERROR_SUCCESS
)
4024 /* Read the service start name */
4025 ScmReadString(hServiceKey
,
4027 &lpServiceStartName
);
4029 /* Read the dependencies */
4030 ScmReadDependencies(hServiceKey
,
4032 &dwDependenciesLength
);
4034 dwRequiredSize
= sizeof(QUERY_SERVICE_CONFIGA
);
4036 if (lpImagePath
!= NULL
)
4037 dwRequiredSize
+= (DWORD
)(wcslen(lpImagePath
) + 1);
4039 dwRequiredSize
+= 2;
4041 if ((lpService
->lpGroup
!= NULL
) && (lpService
->lpGroup
->lpGroupName
!= NULL
))
4042 dwRequiredSize
+= (DWORD
)(wcslen(lpService
->lpGroup
->lpGroupName
) + 1);
4044 dwRequiredSize
+= 2;
4046 /* Add Dependencies length */
4047 if (lpDependencies
!= NULL
)
4048 dwRequiredSize
+= dwDependenciesLength
;
4050 dwRequiredSize
+= 2;
4052 if (lpServiceStartName
!= NULL
)
4053 dwRequiredSize
+= (DWORD
)(wcslen(lpServiceStartName
) + 1);
4055 dwRequiredSize
+= 2;
4057 if (lpService
->lpDisplayName
!= NULL
)
4058 dwRequiredSize
+= (DWORD
)(wcslen(lpService
->lpDisplayName
) + 1);
4060 dwRequiredSize
+= 2;
4062 if (lpServiceConfig
== NULL
|| cbBufSize
< dwRequiredSize
)
4064 dwError
= ERROR_INSUFFICIENT_BUFFER
;
4068 lpServiceConfig
->dwServiceType
= lpService
->Status
.dwServiceType
;
4069 lpServiceConfig
->dwStartType
= lpService
->dwStartType
;
4070 lpServiceConfig
->dwErrorControl
= lpService
->dwErrorControl
;
4071 lpServiceConfig
->dwTagId
= lpService
->dwTag
;
4073 lpStr
= (LPSTR
)(lpServiceConfig
+ 1);
4075 /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
4076 Verified in WINXP */
4080 WideCharToMultiByte(CP_ACP
,
4085 (int)(wcslen(lpImagePath
) + 1),
4091 strcpy(lpStr
, lpEmptyString
);
4094 lpServiceConfig
->lpBinaryPathName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4095 lpStr
+= (strlen((LPSTR
)lpStr
) + 1);
4097 if (lpService
->lpGroup
&& lpService
->lpGroup
->lpGroupName
)
4099 WideCharToMultiByte(CP_ACP
,
4101 lpService
->lpGroup
->lpGroupName
,
4104 (int)(wcslen(lpService
->lpGroup
->lpGroupName
) + 1),
4110 strcpy(lpStr
, lpEmptyString
);
4113 lpServiceConfig
->lpLoadOrderGroup
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4114 lpStr
+= (strlen(lpStr
) + 1);
4116 /* Append Dependencies */
4119 WideCharToMultiByte(CP_ACP
,
4122 dwDependenciesLength
,
4124 dwDependenciesLength
,
4130 strcpy(lpStr
, lpEmptyString
);
4133 lpServiceConfig
->lpDependencies
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4135 lpStr
+= dwDependenciesLength
;
4137 lpStr
+= (strlen(lpStr
) + 1);
4139 if (lpServiceStartName
)
4141 WideCharToMultiByte(CP_ACP
,
4146 (int)(wcslen(lpServiceStartName
) + 1),
4152 strcpy(lpStr
, lpEmptyString
);
4155 lpServiceConfig
->lpServiceStartName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4156 lpStr
+= (strlen(lpStr
) + 1);
4158 if (lpService
->lpDisplayName
)
4160 WideCharToMultiByte(CP_ACP
,
4162 lpService
->lpDisplayName
,
4165 (int)(wcslen(lpService
->lpDisplayName
) + 1),
4171 strcpy(lpStr
, lpEmptyString
);
4174 lpServiceConfig
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4177 if (pcbBytesNeeded
!= NULL
)
4178 *pcbBytesNeeded
= dwRequiredSize
;
4181 /* Unlock the service database */
4182 ScmUnlockDatabase();
4184 if (lpImagePath
!= NULL
)
4185 HeapFree(GetProcessHeap(), 0, lpImagePath
);
4187 if (lpServiceStartName
!= NULL
)
4188 HeapFree(GetProcessHeap(), 0, lpServiceStartName
);
4190 if (lpDependencies
!= NULL
)
4191 HeapFree(GetProcessHeap(), 0, lpDependencies
);
4193 if (hServiceKey
!= NULL
)
4194 RegCloseKey(hServiceKey
);
4196 DPRINT("RQueryServiceConfigA() done\n");
4203 DWORD
RQueryServiceLockStatusA(
4204 SC_RPC_HANDLE hSCManager
,
4205 LPBYTE lpBuf
, // LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
4207 LPBOUNDED_DWORD_4K pcbBytesNeeded
)
4209 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
= (LPQUERY_SERVICE_LOCK_STATUSA
)lpBuf
;
4210 PMANAGER_HANDLE hMgr
;
4211 DWORD dwRequiredSize
;
4213 if (!lpLockStatus
|| !pcbBytesNeeded
)
4214 return ERROR_INVALID_PARAMETER
;
4216 hMgr
= ScmGetServiceManagerFromHandle(hSCManager
);
4219 DPRINT1("Invalid service manager handle!\n");
4220 return ERROR_INVALID_HANDLE
;
4223 if (!RtlAreAllAccessesGranted(hMgr
->Handle
.DesiredAccess
,
4224 SC_MANAGER_QUERY_LOCK_STATUS
))
4226 DPRINT("Insufficient access rights! 0x%lx\n", hMgr
->Handle
.DesiredAccess
);
4227 return ERROR_ACCESS_DENIED
;
4230 /* FIXME: we need to compute instead the real length of the owner name */
4231 dwRequiredSize
= sizeof(QUERY_SERVICE_LOCK_STATUSA
) + sizeof(CHAR
);
4232 *pcbBytesNeeded
= dwRequiredSize
;
4234 if (cbBufSize
< dwRequiredSize
)
4235 return ERROR_INSUFFICIENT_BUFFER
;
4237 ScmQueryServiceLockStatusA(lpLockStatus
);
4239 return ERROR_SUCCESS
;
4244 DWORD
RStartServiceA(
4245 SC_RPC_HANDLE hService
,
4247 LPSTRING_PTRSA argv
)
4249 DWORD dwError
= ERROR_SUCCESS
;
4250 PSERVICE_HANDLE hSvc
;
4251 PSERVICE lpService
= NULL
;
4252 LPWSTR
*lpVector
= NULL
;
4256 DPRINT("RStartServiceA() called\n");
4259 return ERROR_SHUTDOWN_IN_PROGRESS
;
4261 hSvc
= ScmGetServiceFromHandle(hService
);
4264 DPRINT1("Invalid service handle!\n");
4265 return ERROR_INVALID_HANDLE
;
4268 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
4271 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
4272 return ERROR_ACCESS_DENIED
;
4275 lpService
= hSvc
->ServiceEntry
;
4276 if (lpService
== NULL
)
4278 DPRINT("lpService == NULL!\n");
4279 return ERROR_INVALID_HANDLE
;
4282 if (lpService
->dwStartType
== SERVICE_DISABLED
)
4283 return ERROR_SERVICE_DISABLED
;
4285 if (lpService
->bDeleted
)
4286 return ERROR_SERVICE_MARKED_FOR_DELETE
;
4288 /* Build a Unicode argument vector */
4291 lpVector
= HeapAlloc(GetProcessHeap(),
4293 argc
* sizeof(LPWSTR
));
4294 if (lpVector
== NULL
)
4295 return ERROR_NOT_ENOUGH_MEMORY
;
4297 for (i
= 0; i
< argc
; i
++)
4299 dwLength
= MultiByteToWideChar(CP_ACP
,
4306 lpVector
[i
] = HeapAlloc(GetProcessHeap(),
4308 dwLength
* sizeof(WCHAR
));
4309 if (lpVector
[i
] == NULL
)
4311 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
4315 MultiByteToWideChar(CP_ACP
,
4324 /* Start the service */
4325 dwError
= ScmStartService(lpService
, argc
, lpVector
);
4328 /* Free the Unicode argument vector */
4329 if (lpVector
!= NULL
)
4331 for (i
= 0; i
< argc
; i
++)
4333 if (lpVector
[i
] != NULL
)
4334 HeapFree(GetProcessHeap(), 0, lpVector
[i
]);
4336 HeapFree(GetProcessHeap(), 0, lpVector
);
4344 DWORD
RGetServiceDisplayNameA(
4345 SC_RPC_HANDLE hSCManager
,
4346 LPCSTR lpServiceName
,
4347 LPSTR lpDisplayName
,
4348 LPBOUNDED_DWORD_4K lpcchBuffer
)
4350 // PMANAGER_HANDLE hManager;
4351 PSERVICE lpService
= NULL
;
4354 LPWSTR lpServiceNameW
;
4356 DPRINT("RGetServiceDisplayNameA() called\n");
4357 DPRINT("hSCManager = %p\n", hSCManager
);
4358 DPRINT("lpServiceName: %s\n", lpServiceName
);
4359 DPRINT("lpDisplayName: %p\n", lpDisplayName
);
4360 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
4362 // hManager = (PMANAGER_HANDLE)hSCManager;
4363 // if (hManager->Handle.Tag != MANAGER_TAG)
4365 // DPRINT("Invalid manager handle!\n");
4366 // return ERROR_INVALID_HANDLE;
4369 if (lpServiceName
!= NULL
)
4371 dwLength
= (DWORD
)(strlen(lpServiceName
) + 1);
4372 lpServiceNameW
= HeapAlloc(GetProcessHeap(),
4374 dwLength
* sizeof(WCHAR
));
4375 if (!lpServiceNameW
)
4376 return ERROR_NOT_ENOUGH_MEMORY
;
4378 MultiByteToWideChar(CP_ACP
,
4385 lpService
= ScmGetServiceEntryByName(lpServiceNameW
);
4387 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
4390 if (lpService
== NULL
)
4392 DPRINT("Could not find a service!\n");
4394 /* If the service could not be found and lpcchBuffer is 0, windows
4395 puts null in lpDisplayName and puts 1 in lpcchBuffer */
4396 if (*lpcchBuffer
== 0)
4399 if (lpDisplayName
!= NULL
)
4404 return ERROR_SERVICE_DOES_NOT_EXIST
;
4407 if (!lpService
->lpDisplayName
)
4409 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
4410 if (lpDisplayName
!= NULL
&&
4411 *lpcchBuffer
> dwLength
)
4413 WideCharToMultiByte(CP_ACP
,
4415 lpService
->lpServiceName
,
4416 (int)wcslen(lpService
->lpServiceName
),
4421 return ERROR_SUCCESS
;
4426 dwLength
= (DWORD
)wcslen(lpService
->lpDisplayName
);
4427 if (lpDisplayName
!= NULL
&&
4428 *lpcchBuffer
> dwLength
)
4430 WideCharToMultiByte(CP_ACP
,
4432 lpService
->lpDisplayName
,
4433 (int)wcslen(lpService
->lpDisplayName
),
4438 return ERROR_SUCCESS
;
4442 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
4444 *lpcchBuffer
= dwLength
* 2;
4451 DWORD
RGetServiceKeyNameA(
4452 SC_RPC_HANDLE hSCManager
,
4453 LPCSTR lpDisplayName
,
4454 LPSTR lpServiceName
,
4455 LPBOUNDED_DWORD_4K lpcchBuffer
)
4460 LPWSTR lpDisplayNameW
;
4462 DPRINT("RGetServiceKeyNameA() called\n");
4463 DPRINT("hSCManager = %p\n", hSCManager
);
4464 DPRINT("lpDisplayName: %s\n", lpDisplayName
);
4465 DPRINT("lpServiceName: %p\n", lpServiceName
);
4466 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
4468 dwLength
= (DWORD
)(strlen(lpDisplayName
) + 1);
4469 lpDisplayNameW
= HeapAlloc(GetProcessHeap(),
4471 dwLength
* sizeof(WCHAR
));
4472 if (!lpDisplayNameW
)
4473 return ERROR_NOT_ENOUGH_MEMORY
;
4475 MultiByteToWideChar(CP_ACP
,
4482 lpService
= ScmGetServiceEntryByDisplayName(lpDisplayNameW
);
4484 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
4486 if (lpService
== NULL
)
4488 DPRINT("Could not find the service!\n");
4490 /* If the service could not be found and lpcchBuffer is 0,
4491 put null in lpDisplayName and puts 1 in lpcchBuffer, verified WINXP. */
4492 if (*lpcchBuffer
== 0)
4495 if (lpServiceName
!= NULL
)
4501 return ERROR_SERVICE_DOES_NOT_EXIST
;
4504 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
4505 if (lpServiceName
!= NULL
&&
4506 *lpcchBuffer
> dwLength
)
4508 WideCharToMultiByte(CP_ACP
,
4510 lpService
->lpServiceName
,
4511 (int)wcslen(lpService
->lpServiceName
),
4516 return ERROR_SUCCESS
;
4519 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
4521 *lpcchBuffer
= dwLength
* 2;
4528 DWORD
RI_ScGetCurrentGroupStateW(
4529 SC_RPC_HANDLE hSCManager
,
4530 LPWSTR lpLoadOrderGroup
,
4534 return ERROR_CALL_NOT_IMPLEMENTED
;
4539 DWORD
REnumServiceGroupW(
4540 SC_RPC_HANDLE hSCManager
,
4541 DWORD dwServiceType
,
4542 DWORD dwServiceState
,
4545 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
4546 LPBOUNDED_DWORD_256K lpServicesReturned
,
4547 LPBOUNDED_DWORD_256K lpResumeIndex
,
4548 LPCWSTR pszGroupName
)
4550 PMANAGER_HANDLE hManager
;
4552 DWORD dwError
= ERROR_SUCCESS
;
4553 PLIST_ENTRY ServiceEntry
;
4554 PSERVICE CurrentService
;
4556 DWORD dwRequiredSize
;
4557 DWORD dwServiceCount
;
4559 DWORD dwLastResumeCount
= 0;
4560 LPENUM_SERVICE_STATUSW lpStatusPtr
;
4563 DPRINT("REnumServiceGroupW() called\n");
4566 return ERROR_SHUTDOWN_IN_PROGRESS
;
4568 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
4569 if (hManager
== NULL
)
4571 DPRINT1("Invalid service manager handle!\n");
4572 return ERROR_INVALID_HANDLE
;
4575 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
4577 return ERROR_INVALID_ADDRESS
;
4580 *pcbBytesNeeded
= 0;
4581 *lpServicesReturned
= 0;
4583 if ((dwServiceType
== 0) ||
4584 ((dwServiceType
& ~SERVICE_TYPE_ALL
) != 0))
4586 DPRINT("Not a valid Service Type!\n");
4587 return ERROR_INVALID_PARAMETER
;
4590 if ((dwServiceState
== 0) ||
4591 ((dwServiceState
& ~SERVICE_STATE_ALL
) != 0))
4593 DPRINT("Not a valid Service State!\n");
4594 return ERROR_INVALID_PARAMETER
;
4597 /* Check access rights */
4598 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
4599 SC_MANAGER_ENUMERATE_SERVICE
))
4601 DPRINT("Insufficient access rights! 0x%lx\n",
4602 hManager
->Handle
.DesiredAccess
);
4603 return ERROR_ACCESS_DENIED
;
4607 dwLastResumeCount
= *lpResumeIndex
;
4609 /* Lock the service database shared */
4610 ScmLockDatabaseShared();
4612 lpService
= ScmGetServiceEntryByResumeCount(dwLastResumeCount
);
4613 if (lpService
== NULL
)
4615 dwError
= ERROR_SUCCESS
;
4622 for (ServiceEntry
= &lpService
->ServiceListEntry
;
4623 ServiceEntry
!= &ServiceListHead
;
4624 ServiceEntry
= ServiceEntry
->Flink
)
4626 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
4630 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
4633 dwState
= SERVICE_ACTIVE
;
4634 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
4635 dwState
= SERVICE_INACTIVE
;
4637 if ((dwState
& dwServiceState
) == 0)
4642 if (*pszGroupName
== 0)
4644 if (CurrentService
->lpGroup
!= NULL
)
4649 if ((CurrentService
->lpGroup
== NULL
) ||
4650 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
4655 dwSize
= sizeof(ENUM_SERVICE_STATUSW
) +
4656 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
4657 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
4659 if (dwRequiredSize
+ dwSize
> cbBufSize
)
4661 DPRINT("Service name: %S no fit\n", CurrentService
->lpServiceName
);
4665 DPRINT("Service name: %S fit\n", CurrentService
->lpServiceName
);
4666 dwRequiredSize
+= dwSize
;
4668 dwLastResumeCount
= CurrentService
->dwResumeCount
;
4671 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize
);
4672 DPRINT("dwServiceCount: %lu\n", dwServiceCount
);
4675 ServiceEntry
!= &ServiceListHead
;
4676 ServiceEntry
= ServiceEntry
->Flink
)
4678 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
4682 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
4685 dwState
= SERVICE_ACTIVE
;
4686 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
4687 dwState
= SERVICE_INACTIVE
;
4689 if ((dwState
& dwServiceState
) == 0)
4694 if (*pszGroupName
== 0)
4696 if (CurrentService
->lpGroup
!= NULL
)
4701 if ((CurrentService
->lpGroup
== NULL
) ||
4702 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
4707 dwRequiredSize
+= (sizeof(ENUM_SERVICE_STATUSW
) +
4708 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
4709 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
)));
4711 dwError
= ERROR_MORE_DATA
;
4714 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize
);
4717 *lpResumeIndex
= dwLastResumeCount
;
4719 *lpServicesReturned
= dwServiceCount
;
4720 *pcbBytesNeeded
= dwRequiredSize
;
4722 lpStatusPtr
= (LPENUM_SERVICE_STATUSW
)lpBuffer
;
4723 lpStringPtr
= (LPWSTR
)((ULONG_PTR
)lpBuffer
+
4724 dwServiceCount
* sizeof(ENUM_SERVICE_STATUSW
));
4727 for (ServiceEntry
= &lpService
->ServiceListEntry
;
4728 ServiceEntry
!= &ServiceListHead
;
4729 ServiceEntry
= ServiceEntry
->Flink
)
4731 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
4735 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
4738 dwState
= SERVICE_ACTIVE
;
4739 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
4740 dwState
= SERVICE_INACTIVE
;
4742 if ((dwState
& dwServiceState
) == 0)
4747 if (*pszGroupName
== 0)
4749 if (CurrentService
->lpGroup
!= NULL
)
4754 if ((CurrentService
->lpGroup
== NULL
) ||
4755 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
4760 dwSize
= sizeof(ENUM_SERVICE_STATUSW
) +
4761 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
4762 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
4764 if (dwRequiredSize
+ dwSize
> cbBufSize
)
4767 /* Copy the service name */
4768 wcscpy(lpStringPtr
, CurrentService
->lpServiceName
);
4769 lpStatusPtr
->lpServiceName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
4770 lpStringPtr
+= (wcslen(CurrentService
->lpServiceName
) + 1);
4772 /* Copy the display name */
4773 wcscpy(lpStringPtr
, CurrentService
->lpDisplayName
);
4774 lpStatusPtr
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
4775 lpStringPtr
+= (wcslen(CurrentService
->lpDisplayName
) + 1);
4777 /* Copy the status information */
4778 memcpy(&lpStatusPtr
->ServiceStatus
,
4779 &CurrentService
->Status
,
4780 sizeof(SERVICE_STATUS
));
4783 dwRequiredSize
+= dwSize
;
4786 if (dwError
== ERROR_SUCCESS
)
4788 *pcbBytesNeeded
= 0;
4789 if (lpResumeIndex
) *lpResumeIndex
= 0;
4793 /* Unlock the service database */
4794 ScmUnlockDatabase();
4796 DPRINT("REnumServiceGroupW() done (Error %lu)\n", dwError
);
4803 DWORD
RChangeServiceConfig2A(
4804 SC_RPC_HANDLE hService
,
4805 SC_RPC_CONFIG_INFOA Info
)
4807 SC_RPC_CONFIG_INFOW InfoW
;
4808 DWORD dwRet
, dwLength
;
4811 DPRINT("RChangeServiceConfig2A() called\n");
4812 DPRINT("dwInfoLevel = %lu\n", Info
.dwInfoLevel
);
4814 InfoW
.dwInfoLevel
= Info
.dwInfoLevel
;
4816 if (InfoW
.dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
4818 LPSERVICE_DESCRIPTIONW lpServiceDescriptionW
;
4819 //LPSERVICE_DESCRIPTIONA lpServiceDescriptionA;
4821 //lpServiceDescriptionA = Info.psd;
4823 ///if (lpServiceDescriptionA &&
4824 ///lpServiceDescriptionA->lpDescription)
4826 dwLength
= (DWORD
)((strlen(Info
.lpDescription
) + 1) * sizeof(WCHAR
));
4828 lpServiceDescriptionW
= HeapAlloc(GetProcessHeap(),
4830 dwLength
+ sizeof(SERVICE_DESCRIPTIONW
));
4831 if (!lpServiceDescriptionW
)
4833 return ERROR_NOT_ENOUGH_MEMORY
;
4836 lpServiceDescriptionW
->lpDescription
= (LPWSTR
)(lpServiceDescriptionW
+ 1);
4838 MultiByteToWideChar(CP_ACP
,
4842 lpServiceDescriptionW
->lpDescription
,
4845 ptr
= lpServiceDescriptionW
;
4846 InfoW
.psd
= lpServiceDescriptionW
;
4849 else if (Info
.dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
4851 LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW
;
4852 LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA
;
4853 DWORD dwRebootLen
= 0;
4854 DWORD dwCommandLen
= 0;
4855 DWORD dwActionArrayLen
= 0;
4856 LPWSTR lpStr
= NULL
;
4858 lpServiceFailureActionsA
= Info
.psfa
;
4860 if (lpServiceFailureActionsA
)
4863 * The following code is inspired by the
4864 * SERVICE_CONFIG_FAILURE_ACTIONS case of
4865 * the RQueryServiceConfig2W function.
4868 /* Retrieve the needed length for the two data strings */
4869 if (lpServiceFailureActionsA
->lpRebootMsg
)
4871 dwRebootLen
= (DWORD
)((strlen(lpServiceFailureActionsA
->lpRebootMsg
) + 1) * sizeof(WCHAR
));
4873 if (lpServiceFailureActionsA
->lpCommand
)
4875 dwCommandLen
= (DWORD
)((strlen(lpServiceFailureActionsA
->lpCommand
) + 1) * sizeof(WCHAR
));
4879 * Retrieve the size of the lpsaActions array if needed.
4880 * We will copy the lpsaActions array only if there is at
4881 * least one action AND that the original array is valid.
4883 if (lpServiceFailureActionsA
->cActions
> 0 && lpServiceFailureActionsA
->lpsaActions
)
4885 dwActionArrayLen
= lpServiceFailureActionsA
->cActions
* sizeof(SC_ACTION
);
4888 /* Compute the total length for the UNICODE structure, including data */
4889 dwLength
= sizeof(SERVICE_FAILURE_ACTIONSW
) +
4890 dwActionArrayLen
+ dwRebootLen
+ dwCommandLen
;
4892 /* Allocate the structure */
4893 lpServiceFailureActionsW
= HeapAlloc(GetProcessHeap(),
4896 if (!lpServiceFailureActionsW
)
4898 return ERROR_NOT_ENOUGH_MEMORY
;
4901 /* Copy the members */
4902 lpServiceFailureActionsW
->dwResetPeriod
= lpServiceFailureActionsA
->dwResetPeriod
;
4903 lpServiceFailureActionsW
->cActions
= lpServiceFailureActionsA
->cActions
;
4905 /* Copy the lpsaActions array if needed */
4906 if (dwActionArrayLen
> 0)
4908 /* The storage zone is just after the end of the SERVICE_FAILURE_ACTIONSW structure */
4909 lpServiceFailureActionsW
->lpsaActions
= (LPSC_ACTION
)((ULONG_PTR
)(lpServiceFailureActionsW
+ 1));
4911 /* dwActionArrayLen == lpServiceFailureActionsW->cActions * sizeof(SC_ACTION) */
4912 RtlCopyMemory(lpServiceFailureActionsW
->lpsaActions
,
4913 lpServiceFailureActionsA
->lpsaActions
,
4918 /* No lpsaActions array */
4919 lpServiceFailureActionsW
->lpsaActions
= NULL
;
4921 /* The data strings are stored just after the lpsaActions array */
4922 lpStr
= (LPWSTR
)((ULONG_PTR
)(lpServiceFailureActionsW
+ 1) + dwActionArrayLen
);
4925 * Convert the data strings to UNICODE
4928 lpServiceFailureActionsW
->lpRebootMsg
= NULL
;
4929 lpServiceFailureActionsW
->lpCommand
= NULL
;
4933 /* lpRebootMsg points just after the lpsaActions array */
4934 lpServiceFailureActionsW
->lpRebootMsg
= lpStr
;
4936 MultiByteToWideChar(CP_ACP
,
4938 lpServiceFailureActionsA
->lpRebootMsg
,
4940 lpServiceFailureActionsW
->lpRebootMsg
,
4943 lpStr
+= dwRebootLen
/ sizeof(WCHAR
);
4948 /* lpRebootMsg points just after the lpRebootMsg data string */
4949 lpServiceFailureActionsW
->lpCommand
= lpStr
;
4951 MultiByteToWideChar(CP_ACP
,
4953 lpServiceFailureActionsA
->lpCommand
,
4955 lpServiceFailureActionsW
->lpCommand
,
4959 /* Set the pointers */
4960 ptr
= lpServiceFailureActionsW
;
4961 InfoW
.psfa
= lpServiceFailureActionsW
;
4965 dwRet
= RChangeServiceConfig2W(hService
, InfoW
);
4967 HeapFree(GetProcessHeap(), 0, ptr
);
4974 ScmSetFailureActions(PSERVICE_HANDLE hSvc
,
4977 LPSERVICE_FAILURE_ACTIONSW lpFailureActions
)
4979 LPSERVICE_FAILURE_ACTIONSW lpReadBuffer
= NULL
;
4980 LPSERVICE_FAILURE_ACTIONSW lpWriteBuffer
= NULL
;
4981 BOOL bIsActionRebootSet
= FALSE
;
4982 DWORD dwDesiredAccess
= SERVICE_CHANGE_CONFIG
;
4983 DWORD dwRequiredSize
= 0;
4988 /* There is nothing to be done if we have no failure actions */
4989 if (lpFailureActions
== NULL
)
4990 return ERROR_SUCCESS
;
4993 * 1- Check whether or not we can set
4994 * failure actions for this service.
4997 /* Failure actions can only be set for Win32 services, not for drivers */
4998 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
4999 return ERROR_CANNOT_DETECT_DRIVER_FAILURE
;
5002 * If the service controller handles the SC_ACTION_RESTART action,
5003 * hService must have the SERVICE_START access right.
5005 * If you specify SC_ACTION_REBOOT, the caller must have the
5006 * SE_SHUTDOWN_NAME privilege.
5008 if (lpFailureActions
->cActions
> 0 &&
5009 lpFailureActions
->lpsaActions
!= NULL
)
5011 for (i
= 0; i
< lpFailureActions
->cActions
; ++i
)
5013 if (lpFailureActions
->lpsaActions
[i
].Type
== SC_ACTION_RESTART
)
5014 dwDesiredAccess
|= SERVICE_START
;
5015 else if (lpFailureActions
->lpsaActions
[i
].Type
== SC_ACTION_REBOOT
)
5016 bIsActionRebootSet
= TRUE
;
5020 /* Re-check the access rights */
5021 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5024 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5025 return ERROR_ACCESS_DENIED
;
5028 /* FIXME: Check if the caller has the SE_SHUTDOWN_NAME privilege */
5029 if (bIsActionRebootSet
)
5034 * 2- Retrieve the original value of FailureActions.
5037 /* Query value length */
5038 dwError
= RegQueryValueExW(hServiceKey
,
5044 if (dwError
!= ERROR_SUCCESS
&&
5045 dwError
!= ERROR_MORE_DATA
&&
5046 dwError
!= ERROR_FILE_NOT_FOUND
)
5049 dwRequiredSize
= (dwType
== REG_BINARY
) ? max(sizeof(SERVICE_FAILURE_ACTIONSW
), dwRequiredSize
)
5050 : sizeof(SERVICE_FAILURE_ACTIONSW
);
5052 /* Initialize the read buffer */
5053 lpReadBuffer
= HeapAlloc(GetProcessHeap(),
5056 if (lpReadBuffer
== NULL
)
5057 return ERROR_NOT_ENOUGH_MEMORY
;
5059 /* Now we can fill the read buffer */
5060 if (dwError
!= ERROR_FILE_NOT_FOUND
&&
5061 dwType
== REG_BINARY
)
5063 dwError
= RegQueryValueExW(hServiceKey
,
5067 (LPBYTE
)lpReadBuffer
,
5069 if (dwError
!= ERROR_SUCCESS
&&
5070 dwError
!= ERROR_FILE_NOT_FOUND
)
5073 if (dwRequiredSize
< sizeof(SERVICE_FAILURE_ACTIONSW
))
5074 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSW
);
5079 * The value of the error doesn't really matter, the only
5080 * important thing is that it must be != ERROR_SUCCESS.
5082 dwError
= ERROR_INVALID_DATA
;
5085 if (dwError
== ERROR_SUCCESS
)
5087 lpReadBuffer
->cActions
= min(lpReadBuffer
->cActions
, (dwRequiredSize
- sizeof(SERVICE_FAILURE_ACTIONSW
)) / sizeof(SC_ACTION
));
5088 lpReadBuffer
->lpsaActions
= (lpReadBuffer
->cActions
> 0 ? (LPSC_ACTION
)(lpReadBuffer
+ 1) : NULL
);
5092 lpReadBuffer
->dwResetPeriod
= 0;
5093 lpReadBuffer
->cActions
= 0;
5094 lpReadBuffer
->lpsaActions
= NULL
;
5097 lpReadBuffer
->lpRebootMsg
= NULL
;
5098 lpReadBuffer
->lpCommand
= NULL
;
5101 * 3- Initialize the new value to set.
5104 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSW
);
5106 if (lpFailureActions
->lpsaActions
== NULL
)
5109 * lpFailureActions->cActions is ignored.
5110 * Therefore we use the original values
5111 * of cActions and lpsaActions.
5113 dwRequiredSize
+= lpReadBuffer
->cActions
* sizeof(SC_ACTION
);
5118 * The reset period and array of failure actions
5119 * are deleted if lpFailureActions->cActions == 0 .
5121 dwRequiredSize
+= lpFailureActions
->cActions
* sizeof(SC_ACTION
);
5124 lpWriteBuffer
= HeapAlloc(GetProcessHeap(),
5127 if (lpWriteBuffer
== NULL
)
5129 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
5133 /* Clean the pointers as they have no meaning when the structure is stored in the registry */
5134 lpWriteBuffer
->lpRebootMsg
= NULL
;
5135 lpWriteBuffer
->lpCommand
= NULL
;
5136 lpWriteBuffer
->lpsaActions
= NULL
;
5138 /* Set the members */
5139 if (lpFailureActions
->lpsaActions
== NULL
)
5142 * lpFailureActions->dwResetPeriod and lpFailureActions->cActions are ignored.
5143 * Therefore we use the original values of dwResetPeriod, cActions and lpsaActions.
5145 lpWriteBuffer
->dwResetPeriod
= lpReadBuffer
->dwResetPeriod
;
5146 lpWriteBuffer
->cActions
= lpReadBuffer
->cActions
;
5148 if (lpReadBuffer
->lpsaActions
!= NULL
)
5150 memmove(lpWriteBuffer
+ 1,
5151 lpReadBuffer
->lpsaActions
,
5152 lpReadBuffer
->cActions
* sizeof(SC_ACTION
));
5157 if (lpFailureActions
->cActions
> 0)
5159 lpWriteBuffer
->dwResetPeriod
= lpFailureActions
->dwResetPeriod
;
5160 lpWriteBuffer
->cActions
= lpFailureActions
->cActions
;
5162 memmove(lpWriteBuffer
+ 1,
5163 lpFailureActions
->lpsaActions
,
5164 lpFailureActions
->cActions
* sizeof(SC_ACTION
));
5168 /* The reset period and array of failure actions are deleted */
5169 lpWriteBuffer
->dwResetPeriod
= 0;
5170 lpWriteBuffer
->cActions
= 0;
5174 /* Save the new failure actions into the registry */
5175 dwError
= RegSetValueExW(hServiceKey
,
5179 (LPBYTE
)lpWriteBuffer
,
5182 /* We modify the strings only in case of success.*/
5183 if (dwError
== ERROR_SUCCESS
)
5185 /* Modify the Reboot Message value, if specified */
5186 if (lpFailureActions
->lpRebootMsg
!= NULL
)
5188 /* If the Reboot Message is "" then we delete it */
5189 if (*lpFailureActions
->lpRebootMsg
== 0)
5191 DPRINT("Delete Reboot Message value\n");
5192 RegDeleteValueW(hServiceKey
, L
"RebootMessage");
5196 DPRINT("Setting Reboot Message value %S\n", lpFailureActions
->lpRebootMsg
);
5197 RegSetValueExW(hServiceKey
,
5201 (LPBYTE
)lpFailureActions
->lpRebootMsg
,
5202 (DWORD
)((wcslen(lpFailureActions
->lpRebootMsg
) + 1) * sizeof(WCHAR
)));
5206 /* Modify the Failure Command value, if specified */
5207 if (lpFailureActions
->lpCommand
!= NULL
)
5209 /* If the FailureCommand string is an empty string, delete the value */
5210 if (*lpFailureActions
->lpCommand
== 0)
5212 DPRINT("Delete Failure Command value\n");
5213 RegDeleteValueW(hServiceKey
, L
"FailureCommand");
5217 DPRINT("Setting Failure Command value %S\n", lpFailureActions
->lpCommand
);
5218 RegSetValueExW(hServiceKey
,
5222 (LPBYTE
)lpFailureActions
->lpCommand
,
5223 (DWORD
)((wcslen(lpFailureActions
->lpCommand
) + 1) * sizeof(WCHAR
)));
5229 if (lpWriteBuffer
!= NULL
)
5230 HeapFree(GetProcessHeap(), 0, lpWriteBuffer
);
5232 if (lpReadBuffer
!= NULL
)
5233 HeapFree(GetProcessHeap(), 0, lpReadBuffer
);
5240 DWORD
RChangeServiceConfig2W(
5241 SC_RPC_HANDLE hService
,
5242 SC_RPC_CONFIG_INFOW Info
)
5244 DWORD dwError
= ERROR_SUCCESS
;
5245 PSERVICE_HANDLE hSvc
;
5246 PSERVICE lpService
= NULL
;
5247 HKEY hServiceKey
= NULL
;
5249 DPRINT("RChangeServiceConfig2W() called\n");
5250 DPRINT("dwInfoLevel = %lu\n", Info
.dwInfoLevel
);
5253 return ERROR_SHUTDOWN_IN_PROGRESS
;
5255 hSvc
= ScmGetServiceFromHandle(hService
);
5258 DPRINT1("Invalid service handle!\n");
5259 return ERROR_INVALID_HANDLE
;
5262 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5263 SERVICE_CHANGE_CONFIG
))
5265 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5266 return ERROR_ACCESS_DENIED
;
5269 lpService
= hSvc
->ServiceEntry
;
5270 if (lpService
== NULL
)
5272 DPRINT("lpService == NULL!\n");
5273 return ERROR_INVALID_HANDLE
;
5276 /* Lock the service database exclusively */
5277 ScmLockDatabaseExclusive();
5279 if (lpService
->bDeleted
)
5281 DPRINT("The service has already been marked for delete!\n");
5282 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
5286 /* Open the service key */
5287 dwError
= ScmOpenServiceKey(lpService
->szServiceName
,
5288 KEY_READ
| KEY_SET_VALUE
,
5290 if (dwError
!= ERROR_SUCCESS
)
5293 if (Info
.dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
5295 LPSERVICE_DESCRIPTIONW lpServiceDescription
= (LPSERVICE_DESCRIPTIONW
)Info
.psd
;
5297 /* Modify the service description, if specified */
5298 if (lpServiceDescription
!= NULL
&&
5299 lpServiceDescription
->lpDescription
!= NULL
)
5301 /* If the description is "" then we delete it */
5302 if (*lpServiceDescription
->lpDescription
== 0)
5304 DPRINT("Delete service description\n");
5305 dwError
= RegDeleteValueW(hServiceKey
, L
"Description");
5307 if (dwError
== ERROR_FILE_NOT_FOUND
)
5308 dwError
= ERROR_SUCCESS
;
5312 DPRINT("Setting service description value %S\n", lpServiceDescription
->lpDescription
);
5313 dwError
= RegSetValueExW(hServiceKey
,
5317 (LPBYTE
)lpServiceDescription
->lpDescription
,
5318 (DWORD
)((wcslen(lpServiceDescription
->lpDescription
) + 1) * sizeof(WCHAR
)));
5323 dwError
= ERROR_SUCCESS
;
5326 else if (Info
.dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5328 dwError
= ScmSetFailureActions(hSvc
,
5331 (LPSERVICE_FAILURE_ACTIONSW
)Info
.psfa
);
5335 if (hServiceKey
!= NULL
)
5336 RegCloseKey(hServiceKey
);
5338 /* Unlock the service database */
5339 ScmUnlockDatabase();
5341 DPRINT("RChangeServiceConfig2W() done (Error %lu)\n", dwError
);
5348 DWORD
RQueryServiceConfig2A(
5349 SC_RPC_HANDLE hService
,
5353 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
5355 DWORD dwError
= ERROR_SUCCESS
;
5356 PSERVICE_HANDLE hSvc
;
5357 PSERVICE lpService
= NULL
;
5358 HKEY hServiceKey
= NULL
;
5359 DWORD dwRequiredSize
= 0;
5361 LPWSTR lpDescriptionW
= NULL
;
5362 LPWSTR lpRebootMessageW
= NULL
;
5363 LPWSTR lpFailureCommandW
= NULL
;
5365 DPRINT("RQueryServiceConfig2A() called hService %p dwInfoLevel %u, lpBuffer %p cbBufSize %u pcbBytesNeeded %p\n",
5366 hService
, dwInfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
5369 return ERROR_INVALID_ADDRESS
;
5372 return ERROR_SHUTDOWN_IN_PROGRESS
;
5374 hSvc
= ScmGetServiceFromHandle(hService
);
5377 DPRINT1("Invalid service handle!\n");
5378 return ERROR_INVALID_HANDLE
;
5381 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5382 SERVICE_QUERY_CONFIG
))
5384 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5385 return ERROR_ACCESS_DENIED
;
5388 lpService
= hSvc
->ServiceEntry
;
5389 if (lpService
== NULL
)
5391 DPRINT("lpService == NULL!\n");
5392 return ERROR_INVALID_HANDLE
;
5395 /* Lock the service database shared */
5396 ScmLockDatabaseShared();
5398 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
5401 if (dwError
!= ERROR_SUCCESS
)
5404 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
5406 LPSERVICE_DESCRIPTIONA lpServiceDescription
= (LPSERVICE_DESCRIPTIONA
)lpBuffer
;
5409 dwError
= ScmReadString(hServiceKey
,
5412 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5415 *pcbBytesNeeded
= sizeof(SERVICE_DESCRIPTIONA
);
5416 if (dwError
== ERROR_SUCCESS
)
5417 *pcbBytesNeeded
+= (DWORD
)((wcslen(lpDescriptionW
) + 1) * sizeof(WCHAR
));
5419 if (cbBufSize
< *pcbBytesNeeded
)
5421 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5425 if (dwError
== ERROR_SUCCESS
)
5427 lpStr
= (LPSTR
)(lpServiceDescription
+ 1);
5429 WideCharToMultiByte(CP_ACP
,
5434 (int)wcslen(lpDescriptionW
),
5437 lpServiceDescription
->lpDescription
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceDescription
);
5441 lpServiceDescription
->lpDescription
= NULL
;
5442 dwError
= ERROR_SUCCESS
;
5445 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5447 LPSERVICE_FAILURE_ACTIONSA lpFailureActions
= (LPSERVICE_FAILURE_ACTIONSA
)lpBuffer
;
5450 /* Query value length */
5451 dwError
= RegQueryValueExW(hServiceKey
,
5457 if (dwError
!= ERROR_SUCCESS
&&
5458 dwError
!= ERROR_MORE_DATA
&&
5459 dwError
!= ERROR_FILE_NOT_FOUND
)
5462 dwRequiredSize
= (dwType
== REG_BINARY
) ? max(sizeof(SERVICE_FAILURE_ACTIONSA
), dwRequiredSize
)
5463 : sizeof(SERVICE_FAILURE_ACTIONSA
);
5465 /* Get the strings */
5466 ScmReadString(hServiceKey
,
5468 &lpFailureCommandW
);
5470 ScmReadString(hServiceKey
,
5474 if (lpRebootMessageW
)
5475 dwRequiredSize
+= (DWORD
)((wcslen(lpRebootMessageW
) + 1) * sizeof(WCHAR
));
5477 if (lpFailureCommandW
)
5478 dwRequiredSize
+= (DWORD
)((wcslen(lpFailureCommandW
) + 1) * sizeof(WCHAR
));
5480 if (cbBufSize
< dwRequiredSize
)
5482 *pcbBytesNeeded
= dwRequiredSize
;
5483 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5487 /* Now we can fill the buffer */
5488 if (dwError
!= ERROR_FILE_NOT_FOUND
&& dwType
== REG_BINARY
)
5490 dwError
= RegQueryValueExW(hServiceKey
,
5494 (LPBYTE
)lpFailureActions
,
5496 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5499 if (dwRequiredSize
< sizeof(SERVICE_FAILURE_ACTIONSA
))
5500 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSA
);
5505 * The value of the error doesn't really matter, the only
5506 * important thing is that it must be != ERROR_SUCCESS .
5508 dwError
= ERROR_INVALID_DATA
;
5511 if (dwError
== ERROR_SUCCESS
)
5513 lpFailureActions
->cActions
= min(lpFailureActions
->cActions
, (dwRequiredSize
- sizeof(SERVICE_FAILURE_ACTIONSA
)) / sizeof(SC_ACTION
));
5515 /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */
5516 lpFailureActions
->lpsaActions
= (lpFailureActions
->cActions
> 0 ? (LPSC_ACTION
)(ULONG_PTR
)sizeof(SERVICE_FAILURE_ACTIONSA
) : NULL
);
5518 lpStr
= (LPSTR
)((ULONG_PTR
)(lpFailureActions
+ 1) + lpFailureActions
->cActions
* sizeof(SC_ACTION
));
5522 lpFailureActions
->dwResetPeriod
= 0;
5523 lpFailureActions
->cActions
= 0;
5524 lpFailureActions
->lpsaActions
= NULL
;
5525 lpStr
= (LPSTR
)(lpFailureActions
+ 1);
5528 lpFailureActions
->lpRebootMsg
= NULL
;
5529 lpFailureActions
->lpCommand
= NULL
;
5531 if (lpRebootMessageW
)
5533 WideCharToMultiByte(CP_ACP
,
5538 (int)wcslen(lpRebootMessageW
),
5541 lpFailureActions
->lpRebootMsg
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5542 lpStr
+= strlen(lpStr
) + 1;
5545 if (lpFailureCommandW
)
5547 WideCharToMultiByte(CP_ACP
,
5552 (int)wcslen(lpFailureCommandW
),
5555 lpFailureActions
->lpCommand
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5556 /* lpStr += strlen(lpStr) + 1; */
5559 dwError
= ERROR_SUCCESS
;
5563 /* Unlock the service database */
5564 ScmUnlockDatabase();
5566 if (lpDescriptionW
!= NULL
)
5567 HeapFree(GetProcessHeap(), 0, lpDescriptionW
);
5569 if (lpRebootMessageW
!= NULL
)
5570 HeapFree(GetProcessHeap(), 0, lpRebootMessageW
);
5572 if (lpFailureCommandW
!= NULL
)
5573 HeapFree(GetProcessHeap(), 0, lpFailureCommandW
);
5575 if (hServiceKey
!= NULL
)
5576 RegCloseKey(hServiceKey
);
5578 DPRINT("RQueryServiceConfig2A() done (Error %lu)\n", dwError
);
5585 DWORD
RQueryServiceConfig2W(
5586 SC_RPC_HANDLE hService
,
5590 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
5592 DWORD dwError
= ERROR_SUCCESS
;
5593 PSERVICE_HANDLE hSvc
;
5594 PSERVICE lpService
= NULL
;
5595 HKEY hServiceKey
= NULL
;
5596 DWORD dwRequiredSize
= 0;
5598 LPWSTR lpDescription
= NULL
;
5599 LPWSTR lpRebootMessage
= NULL
;
5600 LPWSTR lpFailureCommand
= NULL
;
5602 DPRINT("RQueryServiceConfig2W() called\n");
5605 return ERROR_INVALID_ADDRESS
;
5608 return ERROR_SHUTDOWN_IN_PROGRESS
;
5610 hSvc
= ScmGetServiceFromHandle(hService
);
5613 DPRINT1("Invalid service handle!\n");
5614 return ERROR_INVALID_HANDLE
;
5617 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5618 SERVICE_QUERY_CONFIG
))
5620 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5621 return ERROR_ACCESS_DENIED
;
5624 lpService
= hSvc
->ServiceEntry
;
5625 if (lpService
== NULL
)
5627 DPRINT("lpService == NULL!\n");
5628 return ERROR_INVALID_HANDLE
;
5631 /* Lock the service database shared */
5632 ScmLockDatabaseShared();
5634 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
5637 if (dwError
!= ERROR_SUCCESS
)
5640 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
5642 LPSERVICE_DESCRIPTIONW lpServiceDescription
= (LPSERVICE_DESCRIPTIONW
)lpBuffer
;
5645 dwError
= ScmReadString(hServiceKey
,
5648 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5651 *pcbBytesNeeded
= sizeof(SERVICE_DESCRIPTIONW
);
5652 if (dwError
== ERROR_SUCCESS
)
5653 *pcbBytesNeeded
+= (DWORD
)((wcslen(lpDescription
) + 1) * sizeof(WCHAR
));
5655 if (cbBufSize
< *pcbBytesNeeded
)
5657 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5661 if (dwError
== ERROR_SUCCESS
)
5663 lpStr
= (LPWSTR
)(lpServiceDescription
+ 1);
5664 wcscpy(lpStr
, lpDescription
);
5665 lpServiceDescription
->lpDescription
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceDescription
);
5669 lpServiceDescription
->lpDescription
= NULL
;
5670 dwError
= ERROR_SUCCESS
;
5673 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5675 LPSERVICE_FAILURE_ACTIONSW lpFailureActions
= (LPSERVICE_FAILURE_ACTIONSW
)lpBuffer
;
5676 LPWSTR lpStr
= NULL
;
5678 /* Query value length */
5679 dwError
= RegQueryValueExW(hServiceKey
,
5685 if (dwError
!= ERROR_SUCCESS
&&
5686 dwError
!= ERROR_MORE_DATA
&&
5687 dwError
!= ERROR_FILE_NOT_FOUND
)
5690 dwRequiredSize
= (dwType
== REG_BINARY
) ? max(sizeof(SERVICE_FAILURE_ACTIONSW
), dwRequiredSize
)
5691 : sizeof(SERVICE_FAILURE_ACTIONSW
);
5693 /* Get the strings */
5694 ScmReadString(hServiceKey
,
5698 ScmReadString(hServiceKey
,
5702 if (lpRebootMessage
)
5703 dwRequiredSize
+= (DWORD
)((wcslen(lpRebootMessage
) + 1) * sizeof(WCHAR
));
5705 if (lpFailureCommand
)
5706 dwRequiredSize
+= (DWORD
)((wcslen(lpFailureCommand
) + 1) * sizeof(WCHAR
));
5708 if (cbBufSize
< dwRequiredSize
)
5710 *pcbBytesNeeded
= dwRequiredSize
;
5711 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5715 /* Now we can fill the buffer */
5716 if (dwError
!= ERROR_FILE_NOT_FOUND
&& dwType
== REG_BINARY
)
5718 dwError
= RegQueryValueExW(hServiceKey
,
5722 (LPBYTE
)lpFailureActions
,
5724 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5727 if (dwRequiredSize
< sizeof(SERVICE_FAILURE_ACTIONSW
))
5728 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSW
);
5733 * The value of the error doesn't really matter, the only
5734 * important thing is that it must be != ERROR_SUCCESS .
5736 dwError
= ERROR_INVALID_DATA
;
5739 if (dwError
== ERROR_SUCCESS
)
5741 lpFailureActions
->cActions
= min(lpFailureActions
->cActions
, (dwRequiredSize
- sizeof(SERVICE_FAILURE_ACTIONSW
)) / sizeof(SC_ACTION
));
5743 /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */
5744 lpFailureActions
->lpsaActions
= (lpFailureActions
->cActions
> 0 ? (LPSC_ACTION
)(ULONG_PTR
)sizeof(SERVICE_FAILURE_ACTIONSW
) : NULL
);
5746 lpStr
= (LPWSTR
)((ULONG_PTR
)(lpFailureActions
+ 1) + lpFailureActions
->cActions
* sizeof(SC_ACTION
));
5750 lpFailureActions
->dwResetPeriod
= 0;
5751 lpFailureActions
->cActions
= 0;
5752 lpFailureActions
->lpsaActions
= NULL
;
5753 lpStr
= (LPWSTR
)(lpFailureActions
+ 1);
5756 lpFailureActions
->lpRebootMsg
= NULL
;
5757 lpFailureActions
->lpCommand
= NULL
;
5759 if (lpRebootMessage
)
5761 wcscpy(lpStr
, lpRebootMessage
);
5762 lpFailureActions
->lpRebootMsg
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5763 lpStr
+= wcslen(lpStr
) + 1;
5766 if (lpFailureCommand
)
5768 wcscpy(lpStr
, lpFailureCommand
);
5769 lpFailureActions
->lpCommand
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5770 /* lpStr += wcslen(lpStr) + 1; */
5773 dwError
= ERROR_SUCCESS
;
5777 /* Unlock the service database */
5778 ScmUnlockDatabase();
5780 if (lpDescription
!= NULL
)
5781 HeapFree(GetProcessHeap(), 0, lpDescription
);
5783 if (lpRebootMessage
!= NULL
)
5784 HeapFree(GetProcessHeap(), 0, lpRebootMessage
);
5786 if (lpFailureCommand
!= NULL
)
5787 HeapFree(GetProcessHeap(), 0, lpFailureCommand
);
5789 if (hServiceKey
!= NULL
)
5790 RegCloseKey(hServiceKey
);
5792 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError
);
5799 DWORD
RQueryServiceStatusEx(
5800 SC_RPC_HANDLE hService
,
5801 SC_STATUS_TYPE InfoLevel
,
5804 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
5806 LPSERVICE_STATUS_PROCESS lpStatus
;
5807 PSERVICE_HANDLE hSvc
;
5810 DPRINT("RQueryServiceStatusEx() called\n");
5813 return ERROR_SHUTDOWN_IN_PROGRESS
;
5815 if (InfoLevel
!= SC_STATUS_PROCESS_INFO
)
5816 return ERROR_INVALID_LEVEL
;
5818 *pcbBytesNeeded
= sizeof(SERVICE_STATUS_PROCESS
);
5820 if (cbBufSize
< sizeof(SERVICE_STATUS_PROCESS
))
5821 return ERROR_INSUFFICIENT_BUFFER
;
5823 hSvc
= ScmGetServiceFromHandle(hService
);
5826 DPRINT1("Invalid service handle!\n");
5827 return ERROR_INVALID_HANDLE
;
5830 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5831 SERVICE_QUERY_STATUS
))
5833 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5834 return ERROR_ACCESS_DENIED
;
5837 lpService
= hSvc
->ServiceEntry
;
5838 if (lpService
== NULL
)
5840 DPRINT("lpService == NULL!\n");
5841 return ERROR_INVALID_HANDLE
;
5844 /* Lock the service database shared */
5845 ScmLockDatabaseShared();
5847 lpStatus
= (LPSERVICE_STATUS_PROCESS
)lpBuffer
;
5849 /* Return service status information */
5850 RtlCopyMemory(lpStatus
,
5852 sizeof(SERVICE_STATUS
));
5854 lpStatus
->dwProcessId
= (lpService
->lpImage
!= NULL
) ? lpService
->lpImage
->dwProcessId
: 0; /* FIXME */
5855 lpStatus
->dwServiceFlags
= 0; /* FIXME */
5857 /* Unlock the service database */
5858 ScmUnlockDatabase();
5860 return ERROR_SUCCESS
;
5865 DWORD
REnumServicesStatusExA(
5866 SC_RPC_HANDLE hSCManager
,
5867 SC_ENUM_TYPE InfoLevel
,
5868 DWORD dwServiceType
,
5869 DWORD dwServiceState
,
5872 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
5873 LPBOUNDED_DWORD_256K lpServicesReturned
,
5874 LPBOUNDED_DWORD_256K lpResumeIndex
,
5875 LPCSTR pszGroupName
)
5877 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrW
= NULL
;
5878 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrIncrW
;
5879 LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtrA
= NULL
;
5880 LPWSTR lpStringPtrW
;
5882 LPWSTR pszGroupNameW
= NULL
;
5884 DWORD dwServiceCount
;
5886 DPRINT("REnumServicesStatusExA() called\n");
5888 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
5890 return ERROR_INVALID_ADDRESS
;
5895 pszGroupNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, (strlen(pszGroupName
) + 1) * sizeof(WCHAR
));
5898 DPRINT("Failed to allocate buffer!\n");
5899 return ERROR_NOT_ENOUGH_MEMORY
;
5902 MultiByteToWideChar(CP_ACP
,
5907 (int)(strlen(pszGroupName
) + 1));
5910 if ((cbBufSize
> 0) && (lpBuffer
))
5912 lpStatusPtrW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, cbBufSize
);
5915 DPRINT("Failed to allocate buffer!\n");
5916 return ERROR_NOT_ENOUGH_MEMORY
;
5920 dwError
= REnumServicesStatusExW(hSCManager
,
5924 (LPBYTE
)lpStatusPtrW
,
5931 /* if no services were returned then we are Done */
5932 if (*lpServicesReturned
== 0)
5935 lpStatusPtrIncrW
= lpStatusPtrW
;
5936 lpStatusPtrA
= (LPENUM_SERVICE_STATUS_PROCESSA
)lpBuffer
;
5937 lpStringPtrA
= (LPSTR
)((ULONG_PTR
)lpBuffer
+
5938 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUS_PROCESSA
));
5939 lpStringPtrW
= (LPWSTR
)((ULONG_PTR
)lpStatusPtrW
+
5940 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUS_PROCESSW
));
5942 for (dwServiceCount
= 0; dwServiceCount
< *lpServicesReturned
; dwServiceCount
++)
5944 /* Copy the service name */
5945 WideCharToMultiByte(CP_ACP
,
5950 (int)wcslen(lpStringPtrW
),
5954 lpStatusPtrA
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
5955 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
5956 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
5958 /* Copy the display name */
5959 WideCharToMultiByte(CP_ACP
,
5964 (int)wcslen(lpStringPtrW
),
5968 lpStatusPtrA
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
5969 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
5970 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
5972 /* Copy the status information */
5973 memcpy(&lpStatusPtrA
->ServiceStatusProcess
,
5974 &lpStatusPtrIncrW
->ServiceStatusProcess
,
5975 sizeof(SERVICE_STATUS
));
5977 lpStatusPtrA
->ServiceStatusProcess
.dwProcessId
= lpStatusPtrIncrW
->ServiceStatusProcess
.dwProcessId
; /* FIXME */
5978 lpStatusPtrA
->ServiceStatusProcess
.dwServiceFlags
= 0; /* FIXME */
5986 HeapFree(GetProcessHeap(), 0, pszGroupNameW
);
5989 HeapFree(GetProcessHeap(), 0, lpStatusPtrW
);
5991 DPRINT("REnumServicesStatusExA() done (Error %lu)\n", dwError
);
5998 DWORD
REnumServicesStatusExW(
5999 SC_RPC_HANDLE hSCManager
,
6000 SC_ENUM_TYPE InfoLevel
,
6001 DWORD dwServiceType
,
6002 DWORD dwServiceState
,
6005 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
6006 LPBOUNDED_DWORD_256K lpServicesReturned
,
6007 LPBOUNDED_DWORD_256K lpResumeIndex
,
6008 LPCWSTR pszGroupName
)
6010 PMANAGER_HANDLE hManager
;
6012 DWORD dwError
= ERROR_SUCCESS
;
6013 PLIST_ENTRY ServiceEntry
;
6014 PSERVICE CurrentService
;
6016 DWORD dwRequiredSize
;
6017 DWORD dwServiceCount
;
6019 DWORD dwLastResumeCount
= 0;
6020 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr
;
6023 DPRINT("REnumServicesStatusExW() called\n");
6026 return ERROR_SHUTDOWN_IN_PROGRESS
;
6028 if (InfoLevel
!= SC_ENUM_PROCESS_INFO
)
6029 return ERROR_INVALID_LEVEL
;
6031 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
6032 if (hManager
== NULL
)
6034 DPRINT1("Invalid service manager handle!\n");
6035 return ERROR_INVALID_HANDLE
;
6038 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
6040 return ERROR_INVALID_ADDRESS
;
6043 *pcbBytesNeeded
= 0;
6044 *lpServicesReturned
= 0;
6046 if ((dwServiceType
== 0) ||
6047 ((dwServiceType
& ~SERVICE_TYPE_ALL
) != 0))
6049 DPRINT("Not a valid Service Type!\n");
6050 return ERROR_INVALID_PARAMETER
;
6053 if ((dwServiceState
== 0) ||
6054 ((dwServiceState
& ~SERVICE_STATE_ALL
) != 0))
6056 DPRINT("Not a valid Service State!\n");
6057 return ERROR_INVALID_PARAMETER
;
6060 /* Check access rights */
6061 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
6062 SC_MANAGER_ENUMERATE_SERVICE
))
6064 DPRINT("Insufficient access rights! 0x%lx\n",
6065 hManager
->Handle
.DesiredAccess
);
6066 return ERROR_ACCESS_DENIED
;
6070 dwLastResumeCount
= *lpResumeIndex
;
6072 /* Lock the service database shared */
6073 ScmLockDatabaseShared();
6075 lpService
= ScmGetServiceEntryByResumeCount(dwLastResumeCount
);
6076 if (lpService
== NULL
)
6078 dwError
= ERROR_SUCCESS
;
6085 for (ServiceEntry
= &lpService
->ServiceListEntry
;
6086 ServiceEntry
!= &ServiceListHead
;
6087 ServiceEntry
= ServiceEntry
->Flink
)
6089 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
6093 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
6096 dwState
= SERVICE_ACTIVE
;
6097 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
6098 dwState
= SERVICE_INACTIVE
;
6100 if ((dwState
& dwServiceState
) == 0)
6105 if (*pszGroupName
== 0)
6107 if (CurrentService
->lpGroup
!= NULL
)
6112 if ((CurrentService
->lpGroup
== NULL
) ||
6113 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
6118 dwSize
= sizeof(ENUM_SERVICE_STATUS_PROCESSW
) +
6119 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
6120 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
6122 if (dwRequiredSize
+ dwSize
<= cbBufSize
)
6124 DPRINT("Service name: %S fit\n", CurrentService
->lpServiceName
);
6125 dwRequiredSize
+= dwSize
;
6127 dwLastResumeCount
= CurrentService
->dwResumeCount
;
6131 DPRINT("Service name: %S no fit\n", CurrentService
->lpServiceName
);
6137 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize
);
6138 DPRINT("dwServiceCount: %lu\n", dwServiceCount
);
6141 ServiceEntry
!= &ServiceListHead
;
6142 ServiceEntry
= ServiceEntry
->Flink
)
6144 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
6148 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
6151 dwState
= SERVICE_ACTIVE
;
6152 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
6153 dwState
= SERVICE_INACTIVE
;
6155 if ((dwState
& dwServiceState
) == 0)
6160 if (*pszGroupName
== 0)
6162 if (CurrentService
->lpGroup
!= NULL
)
6167 if ((CurrentService
->lpGroup
== NULL
) ||
6168 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
6173 dwRequiredSize
+= (sizeof(ENUM_SERVICE_STATUS_PROCESSW
) +
6174 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
6175 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
)));
6177 dwError
= ERROR_MORE_DATA
;
6180 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize
);
6183 *lpResumeIndex
= dwLastResumeCount
;
6185 *lpServicesReturned
= dwServiceCount
;
6186 *pcbBytesNeeded
= dwRequiredSize
;
6188 /* If there was no services that matched */
6189 if ((!dwServiceCount
) && (dwError
!= ERROR_MORE_DATA
))
6191 dwError
= ERROR_SERVICE_DOES_NOT_EXIST
;
6195 lpStatusPtr
= (LPENUM_SERVICE_STATUS_PROCESSW
)lpBuffer
;
6196 lpStringPtr
= (LPWSTR
)((ULONG_PTR
)lpBuffer
+
6197 dwServiceCount
* sizeof(ENUM_SERVICE_STATUS_PROCESSW
));
6200 for (ServiceEntry
= &lpService
->ServiceListEntry
;
6201 ServiceEntry
!= &ServiceListHead
;
6202 ServiceEntry
= ServiceEntry
->Flink
)
6204 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
6208 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
6211 dwState
= SERVICE_ACTIVE
;
6212 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
6213 dwState
= SERVICE_INACTIVE
;
6215 if ((dwState
& dwServiceState
) == 0)
6220 if (*pszGroupName
== 0)
6222 if (CurrentService
->lpGroup
!= NULL
)
6227 if ((CurrentService
->lpGroup
== NULL
) ||
6228 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
6233 dwSize
= sizeof(ENUM_SERVICE_STATUS_PROCESSW
) +
6234 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
6235 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
6237 if (dwRequiredSize
+ dwSize
<= cbBufSize
)
6239 /* Copy the service name */
6241 CurrentService
->lpServiceName
);
6242 lpStatusPtr
->lpServiceName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
6243 lpStringPtr
+= (wcslen(CurrentService
->lpServiceName
) + 1);
6245 /* Copy the display name */
6247 CurrentService
->lpDisplayName
);
6248 lpStatusPtr
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
6249 lpStringPtr
+= (wcslen(CurrentService
->lpDisplayName
) + 1);
6251 /* Copy the status information */
6252 memcpy(&lpStatusPtr
->ServiceStatusProcess
,
6253 &CurrentService
->Status
,
6254 sizeof(SERVICE_STATUS
));
6255 lpStatusPtr
->ServiceStatusProcess
.dwProcessId
=
6256 (CurrentService
->lpImage
!= NULL
) ? CurrentService
->lpImage
->dwProcessId
: 0; /* FIXME */
6257 lpStatusPtr
->ServiceStatusProcess
.dwServiceFlags
= 0; /* FIXME */
6260 dwRequiredSize
+= dwSize
;
6270 *pcbBytesNeeded
= 0;
6276 /* Unlock the service database */
6277 ScmUnlockDatabase();
6279 DPRINT("REnumServicesStatusExW() done (Error %lu)\n", dwError
);
6286 DWORD
RSendTSMessage(
6287 handle_t BindingHandle
) /* FIXME */
6290 return ERROR_CALL_NOT_IMPLEMENTED
;
6295 DWORD
RCreateServiceWOW64A(
6296 handle_t BindingHandle
,
6297 LPSTR lpServiceName
,
6298 LPSTR lpDisplayName
,
6299 DWORD dwDesiredAccess
,
6300 DWORD dwServiceType
,
6302 DWORD dwErrorControl
,
6303 LPSTR lpBinaryPathName
,
6304 LPSTR lpLoadOrderGroup
,
6306 LPBYTE lpDependencies
,
6308 LPSTR lpServiceStartName
,
6311 LPSC_RPC_HANDLE lpServiceHandle
)
6314 return ERROR_CALL_NOT_IMPLEMENTED
;
6319 DWORD
RCreateServiceWOW64W(
6320 handle_t BindingHandle
,
6321 LPWSTR lpServiceName
,
6322 LPWSTR lpDisplayName
,
6323 DWORD dwDesiredAccess
,
6324 DWORD dwServiceType
,
6326 DWORD dwErrorControl
,
6327 LPWSTR lpBinaryPathName
,
6328 LPWSTR lpLoadOrderGroup
,
6330 LPBYTE lpDependencies
,
6332 LPWSTR lpServiceStartName
,
6335 LPSC_RPC_HANDLE lpServiceHandle
)
6338 return ERROR_CALL_NOT_IMPLEMENTED
;
6343 DWORD
RQueryServiceTagInfo(
6344 handle_t BindingHandle
) /* FIXME */
6347 return ERROR_CALL_NOT_IMPLEMENTED
;
6352 DWORD
RNotifyServiceStatusChange(
6353 SC_RPC_HANDLE hService
,
6354 SC_RPC_NOTIFY_PARAMS NotifyParams
,
6355 GUID
*pClientProcessGuid
,
6356 GUID
*pSCMProcessGuid
,
6357 PBOOL pfCreateRemoteQueue
,
6358 LPSC_NOTIFY_RPC_HANDLE phNotify
)
6361 return ERROR_CALL_NOT_IMPLEMENTED
;
6366 DWORD
RGetNotifyResults(
6367 SC_NOTIFY_RPC_HANDLE hNotify
,
6368 PSC_RPC_NOTIFY_PARAMS_LIST
*ppNotifyParams
)
6371 return ERROR_CALL_NOT_IMPLEMENTED
;
6376 DWORD
RCloseNotifyHandle(
6377 LPSC_NOTIFY_RPC_HANDLE phNotify
,
6381 return ERROR_CALL_NOT_IMPLEMENTED
;
6386 DWORD
RControlServiceExA(
6387 SC_RPC_HANDLE hService
,
6392 return ERROR_CALL_NOT_IMPLEMENTED
;
6397 DWORD
RControlServiceExW(
6398 SC_RPC_HANDLE hService
,
6403 return ERROR_CALL_NOT_IMPLEMENTED
;
6408 DWORD
RSendPnPMessage(
6409 handle_t BindingHandle
) /* FIXME */
6412 return ERROR_CALL_NOT_IMPLEMENTED
;
6417 DWORD
RValidatePnPService(
6418 handle_t BindingHandle
) /* FIXME */
6421 return ERROR_CALL_NOT_IMPLEMENTED
;
6426 DWORD
ROpenServiceStatusHandle(
6427 handle_t BindingHandle
) /* FIXME */
6430 return ERROR_CALL_NOT_IMPLEMENTED
;
6436 handle_t BindingHandle
) /* FIXME */
6439 return ERROR_CALL_NOT_IMPLEMENTED
;
6443 void __RPC_FAR
* __RPC_USER
midl_user_allocate(SIZE_T len
)
6445 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
);
6449 void __RPC_USER
midl_user_free(void __RPC_FAR
* ptr
)
6451 HeapFree(GetProcessHeap(), 0, ptr
);
6455 void __RPC_USER
SC_RPC_HANDLE_rundown(SC_RPC_HANDLE hSCObject
)
6457 /* Close the handle */
6458 RCloseServiceHandle(&hSCObject
);
6462 void __RPC_USER
SC_RPC_LOCK_rundown(SC_RPC_LOCK Lock
)
6464 /* Unlock the database */
6465 RUnlockServiceDatabase(&Lock
);
6469 void __RPC_USER
SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE hNotify
)