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 ****************************************************************/
18 /* GLOBALS *****************************************************************/
20 #define MANAGER_TAG 0x72674D68 /* 'hMgr' */
21 #define SERVICE_TAG 0x63765368 /* 'hSvc' */
23 typedef struct _SCMGR_HANDLE
30 typedef struct _MANAGER_HANDLE
33 WCHAR DatabaseName
[1];
34 } MANAGER_HANDLE
, *PMANAGER_HANDLE
;
37 typedef struct _SERVICE_HANDLE
40 PSERVICE ServiceEntry
;
41 } SERVICE_HANDLE
, *PSERVICE_HANDLE
;
44 #define SC_MANAGER_READ \
45 (STANDARD_RIGHTS_READ | \
46 SC_MANAGER_QUERY_LOCK_STATUS | \
47 SC_MANAGER_ENUMERATE_SERVICE)
49 #define SC_MANAGER_WRITE \
50 (STANDARD_RIGHTS_WRITE | \
51 SC_MANAGER_MODIFY_BOOT_CONFIG | \
52 SC_MANAGER_CREATE_SERVICE)
54 #define SC_MANAGER_EXECUTE \
55 (STANDARD_RIGHTS_EXECUTE | \
57 SC_MANAGER_ENUMERATE_SERVICE | \
58 SC_MANAGER_CONNECT | \
59 SC_MANAGER_CREATE_SERVICE)
62 #define SERVICE_READ \
63 (STANDARD_RIGHTS_READ | \
64 SERVICE_INTERROGATE | \
65 SERVICE_ENUMERATE_DEPENDENTS | \
66 SERVICE_QUERY_STATUS | \
69 #define SERVICE_WRITE \
70 (STANDARD_RIGHTS_WRITE | \
71 SERVICE_CHANGE_CONFIG)
73 #define SERVICE_EXECUTE \
74 (STANDARD_RIGHTS_EXECUTE | \
75 SERVICE_USER_DEFINED_CONTROL | \
76 SERVICE_PAUSE_CONTINUE | \
80 #define TAG_ARRAY_SIZE 32
82 /* VARIABLES ***************************************************************/
84 static GENERIC_MAPPING
85 ScmManagerMapping
= {SC_MANAGER_READ
,
88 SC_MANAGER_ALL_ACCESS
};
90 static GENERIC_MAPPING
91 ScmServiceMapping
= {SERVICE_READ
,
97 /* FUNCTIONS ***************************************************************/
100 ScmStartRpcServer(VOID
)
104 DPRINT("ScmStartRpcServer() called\n");
106 Status
= RpcServerUseProtseqEpW(L
"ncacn_np",
110 if (Status
!= RPC_S_OK
)
112 DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status
);
116 Status
= RpcServerRegisterIf(svcctl_v2_0_s_ifspec
,
119 if (Status
!= RPC_S_OK
)
121 DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status
);
125 Status
= RpcServerListen(1, 20, TRUE
);
126 if (Status
!= RPC_S_OK
)
128 DPRINT1("RpcServerListen() failed (Status %lx)\n", Status
);
132 DPRINT("ScmStartRpcServer() done\n");
137 ScmCreateManagerHandle(LPWSTR lpDatabaseName
,
142 if (lpDatabaseName
== NULL
)
143 lpDatabaseName
= SERVICES_ACTIVE_DATABASEW
;
145 if (_wcsicmp(lpDatabaseName
, SERVICES_FAILED_DATABASEW
) == 0)
147 DPRINT("Database %S, does not exist\n", lpDatabaseName
);
148 return ERROR_DATABASE_DOES_NOT_EXIST
;
150 else if (_wcsicmp(lpDatabaseName
, SERVICES_ACTIVE_DATABASEW
) != 0)
152 DPRINT("Invalid Database name %S.\n", lpDatabaseName
);
153 return ERROR_INVALID_NAME
;
156 Ptr
= HeapAlloc(GetProcessHeap(),
158 FIELD_OFFSET(MANAGER_HANDLE
, DatabaseName
[wcslen(lpDatabaseName
) + 1]));
160 return ERROR_NOT_ENOUGH_MEMORY
;
162 Ptr
->Handle
.Tag
= MANAGER_TAG
;
164 wcscpy(Ptr
->DatabaseName
, lpDatabaseName
);
166 *Handle
= (SC_HANDLE
)Ptr
;
168 return ERROR_SUCCESS
;
173 ScmCreateServiceHandle(PSERVICE lpServiceEntry
,
178 Ptr
= HeapAlloc(GetProcessHeap(),
180 sizeof(SERVICE_HANDLE
));
182 return ERROR_NOT_ENOUGH_MEMORY
;
184 Ptr
->Handle
.Tag
= SERVICE_TAG
;
186 Ptr
->ServiceEntry
= lpServiceEntry
;
188 *Handle
= (SC_HANDLE
)Ptr
;
190 return ERROR_SUCCESS
;
194 static PMANAGER_HANDLE
195 ScmGetServiceManagerFromHandle(SC_RPC_HANDLE Handle
)
197 PMANAGER_HANDLE pManager
= NULL
;
201 if (((PMANAGER_HANDLE
)Handle
)->Handle
.Tag
== MANAGER_TAG
)
202 pManager
= (PMANAGER_HANDLE
)Handle
;
204 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
206 DPRINT1("Exception: Invalid Service Manager handle!\n");
214 static PSERVICE_HANDLE
215 ScmGetServiceFromHandle(SC_RPC_HANDLE Handle
)
217 PSERVICE_HANDLE pService
= NULL
;
221 if (((PSERVICE_HANDLE
)Handle
)->Handle
.Tag
== SERVICE_TAG
)
222 pService
= (PSERVICE_HANDLE
)Handle
;
224 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
226 DPRINT1("Exception: Invalid Service handle!\n");
235 ScmCheckAccess(SC_HANDLE Handle
,
236 DWORD dwDesiredAccess
)
238 PMANAGER_HANDLE hMgr
;
240 hMgr
= (PMANAGER_HANDLE
)Handle
;
241 if (hMgr
->Handle
.Tag
== MANAGER_TAG
)
243 RtlMapGenericMask(&dwDesiredAccess
,
246 hMgr
->Handle
.DesiredAccess
= dwDesiredAccess
;
248 return ERROR_SUCCESS
;
250 else if (hMgr
->Handle
.Tag
== SERVICE_TAG
)
252 RtlMapGenericMask(&dwDesiredAccess
,
255 hMgr
->Handle
.DesiredAccess
= dwDesiredAccess
;
257 return ERROR_SUCCESS
;
260 return ERROR_INVALID_HANDLE
;
265 ScmAssignNewTag(PSERVICE lpService
)
269 DWORD dwGroupTagCount
= 0;
270 PDWORD pdwGroupTags
= NULL
;
272 DWORD dwTagUsedBase
= 1;
273 BOOLEAN TagUsed
[TAG_ARRAY_SIZE
];
277 PLIST_ENTRY ServiceEntry
;
278 PSERVICE CurrentService
;
280 ASSERT(lpService
!= NULL
);
281 ASSERT(lpService
->lpGroup
!= NULL
);
283 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
284 L
"System\\CurrentControlSet\\Control\\GroupOrderList",
289 if (dwError
!= ERROR_SUCCESS
)
292 /* query value length */
294 dwError
= RegQueryValueExW(hKey
,
295 lpService
->lpGroup
->szGroupName
,
301 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_MORE_DATA
)
304 pdwGroupTags
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, cbDataSize
);
307 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
311 dwError
= RegQueryValueExW(hKey
,
312 lpService
->lpGroup
->szGroupName
,
315 (LPBYTE
)pdwGroupTags
,
318 if (dwError
!= ERROR_SUCCESS
)
321 if (cbDataSize
< sizeof(pdwGroupTags
[0]))
324 dwGroupTagCount
= min(pdwGroupTags
[0], cbDataSize
/ sizeof(pdwGroupTags
[0]) - 1);
329 /* mark all tags as unused */
330 for (i
= 0; i
< TAG_ARRAY_SIZE
; i
++)
333 /* mark tags in GroupOrderList as used */
334 for (i
= 1; i
<= dwGroupTagCount
; i
++)
336 nTagOffset
= pdwGroupTags
[i
] - dwTagUsedBase
;
337 if (nTagOffset
>= 0 && nTagOffset
< TAG_ARRAY_SIZE
)
338 TagUsed
[nTagOffset
] = TRUE
;
341 /* mark tags in service list as used */
342 ServiceEntry
= lpService
->ServiceListEntry
.Flink
;
343 while (ServiceEntry
!= &lpService
->ServiceListEntry
)
345 ASSERT(ServiceEntry
!= NULL
);
346 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
347 if (CurrentService
->lpGroup
== lpService
->lpGroup
)
349 nTagOffset
= CurrentService
->dwTag
- dwTagUsedBase
;
350 if (nTagOffset
>= 0 && nTagOffset
< TAG_ARRAY_SIZE
)
351 TagUsed
[nTagOffset
] = TRUE
;
354 ServiceEntry
= ServiceEntry
->Flink
;
357 /* find unused tag, if any */
358 for (i
= 0; i
< TAG_ARRAY_SIZE
; i
++)
362 dwFreeTag
= dwTagUsedBase
+ i
;
367 dwTagUsedBase
+= TAG_ARRAY_SIZE
;
368 } while (!dwFreeTag
);
372 HeapFree(GetProcessHeap(), 0, pdwGroupTags
);
379 lpService
->dwTag
= dwFreeTag
;
380 DPRINT("Assigning new tag %lu to service %S in group %S\n",
381 lpService
->dwTag
, lpService
->lpServiceName
, lpService
->lpGroup
->szGroupName
);
382 dwError
= ERROR_SUCCESS
;
386 DPRINT1("Failed to assign new tag to service %S, error=%lu\n",
387 lpService
->lpServiceName
, dwError
);
394 /* Create a path suitable for the bootloader out of the full path */
396 ScmConvertToBootPathName(wchar_t *CanonName
, wchar_t **RelativeName
)
398 SIZE_T ServiceNameLen
, ExpandedLen
;
402 UNICODE_STRING NtPathName
, SystemRoot
, LinkTarget
;
403 OBJECT_ATTRIBUTES ObjectAttributes
;
405 HANDLE SymbolicLinkHandle
;
407 DPRINT("ScmConvertToBootPathName %S\n", CanonName
);
410 return ERROR_INVALID_PARAMETER
;
412 *RelativeName
= NULL
;
414 ServiceNameLen
= wcslen(CanonName
);
416 /* First check, if it's already good */
417 if (ServiceNameLen
> 12 &&
418 !_wcsnicmp(L
"\\SystemRoot\\", CanonName
, 12))
420 *RelativeName
= HeapAlloc(GetProcessHeap(),
422 (ServiceNameLen
+ 1) * sizeof(WCHAR
));
423 if (*RelativeName
== NULL
)
425 DPRINT("Error allocating memory for boot driver name!\n");
426 return ERROR_NOT_ENOUGH_MEMORY
;
430 wcscpy(*RelativeName
, CanonName
);
432 DPRINT("Bootdriver name %S\n", *RelativeName
);
433 return ERROR_SUCCESS
;
436 /* If it has %SystemRoot% prefix, substitute it to \System*/
437 if (ServiceNameLen
> 13 &&
438 !_wcsnicmp(L
"%SystemRoot%\\", CanonName
, 13))
440 /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */
441 *RelativeName
= HeapAlloc(GetProcessHeap(),
443 ServiceNameLen
* sizeof(WCHAR
));
445 if (*RelativeName
== NULL
)
447 DPRINT("Error allocating memory for boot driver name!\n");
448 return ERROR_NOT_ENOUGH_MEMORY
;
452 wcscpy(*RelativeName
, L
"\\SystemRoot\\");
453 wcscat(*RelativeName
, CanonName
+ 13);
455 DPRINT("Bootdriver name %S\n", *RelativeName
);
456 return ERROR_SUCCESS
;
459 /* Get buffer size needed for expanding env strings */
460 BufferSize
= ExpandEnvironmentStringsW(L
"%SystemRoot%\\", &Dest
, 1);
464 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
465 return ERROR_INVALID_ENVIRONMENT
;
468 /* Allocate memory, since the size is known now */
469 Expanded
= HeapAlloc(GetProcessHeap(),
471 (BufferSize
+ 1) * sizeof(WCHAR
));
474 DPRINT("Error allocating memory for boot driver name!\n");
475 return ERROR_NOT_ENOUGH_MEMORY
;
479 if (ExpandEnvironmentStringsW(L
"%SystemRoot%\\", Expanded
, BufferSize
) >
482 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
483 HeapFree(GetProcessHeap(), 0, Expanded
);
484 return ERROR_NOT_ENOUGH_MEMORY
;
487 /* Convert to NT-style path */
488 if (!RtlDosPathNameToNtPathName_U(Expanded
, &NtPathName
, NULL
, NULL
))
490 DPRINT("Error during a call to RtlDosPathNameToNtPathName_U()\n");
491 return ERROR_INVALID_ENVIRONMENT
;
494 DPRINT("Converted to NT-style %wZ\n", &NtPathName
);
496 /* No need to keep the dos-path anymore */
497 HeapFree(GetProcessHeap(), 0, Expanded
);
499 /* Copy it to the allocated place */
500 Expanded
= HeapAlloc(GetProcessHeap(),
502 NtPathName
.Length
+ sizeof(UNICODE_NULL
));
505 DPRINT("Error allocating memory for boot driver name!\n");
506 return ERROR_NOT_ENOUGH_MEMORY
;
509 ExpandedLen
= NtPathName
.Length
/ sizeof(WCHAR
);
510 wcsncpy(Expanded
, NtPathName
.Buffer
, ExpandedLen
);
511 Expanded
[ExpandedLen
] = UNICODE_NULL
;
513 if (ServiceNameLen
> ExpandedLen
&&
514 !_wcsnicmp(Expanded
, CanonName
, ExpandedLen
))
516 /* Only \SystemRoot\ is missing */
517 *RelativeName
= HeapAlloc(GetProcessHeap(),
519 (ServiceNameLen
- ExpandedLen
) * sizeof(WCHAR
) + 13*sizeof(WCHAR
));
520 if (*RelativeName
== NULL
)
522 DPRINT("Error allocating memory for boot driver name!\n");
523 HeapFree(GetProcessHeap(), 0, Expanded
);
524 return ERROR_NOT_ENOUGH_MEMORY
;
527 wcscpy(*RelativeName
, L
"\\SystemRoot\\");
528 wcscat(*RelativeName
, CanonName
+ ExpandedLen
);
530 RtlFreeUnicodeString(&NtPathName
);
531 return ERROR_SUCCESS
;
534 /* The most complex case starts here */
535 RtlInitUnicodeString(&SystemRoot
, L
"\\SystemRoot");
536 InitializeObjectAttributes(&ObjectAttributes
,
538 OBJ_CASE_INSENSITIVE
,
542 /* Open this symlink */
543 Status
= NtOpenSymbolicLinkObject(&SymbolicLinkHandle
, SYMBOLIC_LINK_QUERY
, &ObjectAttributes
);
545 if (NT_SUCCESS(Status
))
547 LinkTarget
.Length
= 0;
548 LinkTarget
.MaximumLength
= 0;
550 DPRINT("Opened symbolic link object\n");
552 Status
= NtQuerySymbolicLinkObject(SymbolicLinkHandle
, &LinkTarget
, &BufferSize
);
553 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_TOO_SMALL
)
555 /* Check if required buffer size is sane */
556 if (BufferSize
> 0xFFFD)
558 DPRINT("Too large buffer required\n");
560 if (SymbolicLinkHandle
) NtClose(SymbolicLinkHandle
);
561 HeapFree(GetProcessHeap(), 0, Expanded
);
562 return ERROR_NOT_ENOUGH_MEMORY
;
565 /* Alloc the string */
566 LinkTarget
.Length
= (USHORT
)BufferSize
;
567 LinkTarget
.MaximumLength
= LinkTarget
.Length
+ sizeof(UNICODE_NULL
);
568 LinkTarget
.Buffer
= HeapAlloc(GetProcessHeap(),
570 LinkTarget
.MaximumLength
);
571 if (!LinkTarget
.Buffer
)
573 DPRINT("Unable to alloc buffer\n");
574 if (SymbolicLinkHandle
) NtClose(SymbolicLinkHandle
);
575 HeapFree(GetProcessHeap(), 0, Expanded
);
576 return ERROR_NOT_ENOUGH_MEMORY
;
579 /* Do a real query now */
580 Status
= NtQuerySymbolicLinkObject(SymbolicLinkHandle
, &LinkTarget
, &BufferSize
);
581 if (NT_SUCCESS(Status
))
583 DPRINT("LinkTarget: %wZ\n", &LinkTarget
);
585 ExpandedLen
= LinkTarget
.Length
/ sizeof(WCHAR
);
586 if ((ServiceNameLen
> ExpandedLen
) &&
587 !_wcsnicmp(LinkTarget
.Buffer
, CanonName
, ExpandedLen
))
589 *RelativeName
= HeapAlloc(GetProcessHeap(),
591 (ServiceNameLen
- ExpandedLen
) * sizeof(WCHAR
) + 13*sizeof(WCHAR
));
593 if (*RelativeName
== NULL
)
595 DPRINT("Unable to alloc buffer\n");
596 if (SymbolicLinkHandle
) NtClose(SymbolicLinkHandle
);
597 HeapFree(GetProcessHeap(), 0, Expanded
);
598 RtlFreeUnicodeString(&NtPathName
);
599 return ERROR_NOT_ENOUGH_MEMORY
;
602 /* Copy it over, substituting the first part
604 wcscpy(*RelativeName
, L
"\\SystemRoot\\");
605 wcscat(*RelativeName
, CanonName
+ExpandedLen
+1);
608 if (SymbolicLinkHandle
) NtClose(SymbolicLinkHandle
);
609 HeapFree(GetProcessHeap(), 0, Expanded
);
610 RtlFreeUnicodeString(&NtPathName
);
613 return ERROR_SUCCESS
;
617 if (SymbolicLinkHandle
) NtClose(SymbolicLinkHandle
);
618 HeapFree(GetProcessHeap(), 0, Expanded
);
619 RtlFreeUnicodeString(&NtPathName
);
620 return ERROR_INVALID_PARAMETER
;
625 DPRINT("Error, Status = %08X\n", Status
);
626 if (SymbolicLinkHandle
) NtClose(SymbolicLinkHandle
);
627 HeapFree(GetProcessHeap(), 0, Expanded
);
628 RtlFreeUnicodeString(&NtPathName
);
629 return ERROR_INVALID_PARAMETER
;
634 DPRINT("Error, Status = %08X\n", Status
);
635 if (SymbolicLinkHandle
) NtClose(SymbolicLinkHandle
);
636 HeapFree(GetProcessHeap(), 0, Expanded
);
637 RtlFreeUnicodeString(&NtPathName
);
638 return ERROR_INVALID_PARAMETER
;
644 DPRINT("Error, Status = %08X\n", Status
);
645 HeapFree(GetProcessHeap(), 0, Expanded
);
646 return ERROR_INVALID_PARAMETER
;
652 ScmCanonDriverImagePath(DWORD dwStartType
,
653 const wchar_t *lpServiceName
,
654 wchar_t **lpCanonName
)
657 SIZE_T ServiceNameLen
;
658 UNICODE_STRING NtServiceName
;
660 const WCHAR
*SourceName
= lpServiceName
;
662 /* Calculate the length of the service's name */
663 ServiceNameLen
= wcslen(lpServiceName
);
665 /* 12 is wcslen(L"\\SystemRoot\\") */
666 if (ServiceNameLen
> 12 &&
667 !_wcsnicmp(L
"\\SystemRoot\\", lpServiceName
, 12))
669 /* SystemRoot prefix is already included */
670 *lpCanonName
= HeapAlloc(GetProcessHeap(),
672 (ServiceNameLen
+ 1) * sizeof(WCHAR
));
674 if (*lpCanonName
== NULL
)
676 DPRINT("Error allocating memory for canonized service name!\n");
677 return ERROR_NOT_ENOUGH_MEMORY
;
680 /* If it's a boot-time driver, it must be systemroot relative */
681 if (dwStartType
== SERVICE_BOOT_START
)
685 wcscpy(*lpCanonName
, SourceName
);
687 DPRINT("Canonicalized name %S\n", *lpCanonName
);
691 /* Check if it has %SystemRoot% (len=13) */
692 if (ServiceNameLen
> 13 &&
693 !_wcsnicmp(L
"%SystemRoot%\\", lpServiceName
, 13))
695 /* Substitute %SystemRoot% with \\SystemRoot\\ */
696 *lpCanonName
= HeapAlloc(GetProcessHeap(),
698 (ServiceNameLen
+ 1) * sizeof(WCHAR
));
700 if (*lpCanonName
== NULL
)
702 DPRINT("Error allocating memory for canonized service name!\n");
703 return ERROR_NOT_ENOUGH_MEMORY
;
706 /* If it's a boot-time driver, it must be systemroot relative */
707 if (dwStartType
== SERVICE_BOOT_START
)
708 wcscpy(*lpCanonName
, L
"\\SystemRoot\\");
710 wcscat(*lpCanonName
, lpServiceName
+ 13);
712 DPRINT("Canonicalized name %S\n", *lpCanonName
);
716 /* Check if it's a relative path name */
717 if (lpServiceName
[0] != L
'\\' && lpServiceName
[1] != L
':')
719 *lpCanonName
= HeapAlloc(GetProcessHeap(),
721 (ServiceNameLen
+ 1) * sizeof(WCHAR
));
723 if (*lpCanonName
== NULL
)
725 DPRINT("Error allocating memory for canonized service name!\n");
726 return ERROR_NOT_ENOUGH_MEMORY
;
729 /* Just copy it over without changing */
730 wcscpy(*lpCanonName
, lpServiceName
);
735 /* It seems to be a DOS path, convert it */
736 if (!RtlDosPathNameToNtPathName_U(lpServiceName
, &NtServiceName
, NULL
, NULL
))
738 DPRINT("RtlDosPathNameToNtPathName_U() failed!\n");
739 return ERROR_INVALID_PARAMETER
;
742 *lpCanonName
= HeapAlloc(GetProcessHeap(),
744 NtServiceName
.Length
+ sizeof(WCHAR
));
746 if (*lpCanonName
== NULL
)
748 DPRINT("Error allocating memory for canonized service name!\n");
749 RtlFreeUnicodeString(&NtServiceName
);
750 return ERROR_NOT_ENOUGH_MEMORY
;
753 /* Copy the string */
754 wcsncpy(*lpCanonName
, NtServiceName
.Buffer
, NtServiceName
.Length
/ sizeof(WCHAR
));
756 /* The unicode string is not needed anymore */
757 RtlFreeUnicodeString(&NtServiceName
);
759 if (dwStartType
!= SERVICE_BOOT_START
)
761 DPRINT("Canonicalized name %S\n", *lpCanonName
);
765 /* The service is boot-started, so must be relative */
766 Result
= ScmConvertToBootPathName(*lpCanonName
, &RelativeName
);
769 /* There is a problem, free name and return */
770 HeapFree(GetProcessHeap(), 0, *lpCanonName
);
771 DPRINT("Error converting named!\n");
775 ASSERT(RelativeName
);
777 /* Copy that string */
778 wcscpy(*lpCanonName
, RelativeName
+ 12);
780 /* Free the allocated buffer */
781 HeapFree(GetProcessHeap(), 0, RelativeName
);
783 DPRINT("Canonicalized name %S\n", *lpCanonName
);
790 /* Internal recursive function */
791 /* Need to search for every dependency on every service */
793 Int_EnumDependentServicesW(HKEY hServicesKey
,
795 DWORD dwServiceState
,
796 PSERVICE
*lpServices
,
797 LPDWORD pcbBytesNeeded
,
798 LPDWORD lpServicesReturned
)
800 DWORD dwError
= ERROR_SUCCESS
;
801 WCHAR szNameBuf
[MAX_PATH
];
802 WCHAR szValueBuf
[MAX_PATH
];
803 WCHAR
*lpszNameBuf
= szNameBuf
;
804 WCHAR
*lpszValueBuf
= szValueBuf
;
808 PSERVICE lpCurrentService
;
809 HKEY hServiceEnumKey
;
810 DWORD dwCurrentServiceState
= SERVICE_ACTIVE
;
811 DWORD dwDependServiceStrPtr
= 0;
812 DWORD dwRequiredSize
= 0;
814 /* Get the number of service keys */
815 dwError
= RegQueryInfoKeyW(hServicesKey
,
827 if (dwError
!= ERROR_SUCCESS
)
829 DPRINT("ERROR! Unable to get number of services keys.\n");
833 /* Iterate the service keys to see if another service depends on the this service */
834 for (dwIteration
= 0; dwIteration
< dwNumSubKeys
; dwIteration
++)
837 dwError
= RegEnumKeyExW(hServicesKey
,
845 if (dwError
!= ERROR_SUCCESS
)
848 /* Open the Service key */
849 dwError
= RegOpenKeyExW(hServicesKey
,
854 if (dwError
!= ERROR_SUCCESS
)
859 /* Check for the DependOnService Value */
860 dwError
= RegQueryValueExW(hServiceEnumKey
,
864 (LPBYTE
)lpszValueBuf
,
867 /* FIXME: Handle load order. */
869 /* If the service found has a DependOnService value */
870 if (dwError
== ERROR_SUCCESS
)
872 dwDependServiceStrPtr
= 0;
874 /* Can be more than one Dependencies in the DependOnService string */
875 while (wcslen(lpszValueBuf
+ dwDependServiceStrPtr
) > 0)
877 if (_wcsicmp(lpszValueBuf
+ dwDependServiceStrPtr
, lpService
->lpServiceName
) == 0)
879 /* Get the current enumed service pointer */
880 lpCurrentService
= ScmGetServiceEntryByName(lpszNameBuf
);
882 /* Check for valid Service */
883 if (!lpCurrentService
)
885 /* This should never happen! */
886 DPRINT("This should not happen at this point, report to Developer\n");
887 return ERROR_NOT_FOUND
;
890 /* Determine state the service is in */
891 if (lpCurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
892 dwCurrentServiceState
= SERVICE_INACTIVE
;
894 /* If the ServiceState matches that requested or searching for SERVICE_STATE_ALL */
895 if ((dwCurrentServiceState
== dwServiceState
) ||
896 (dwServiceState
== SERVICE_STATE_ALL
))
898 /* Calculate the required size */
899 dwRequiredSize
+= sizeof(SERVICE_STATUS
);
900 dwRequiredSize
+= (DWORD
)((wcslen(lpCurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
));
901 dwRequiredSize
+= (DWORD
)((wcslen(lpCurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
903 /* Add the size for service name and display name pointers */
904 dwRequiredSize
+= (2 * sizeof(PVOID
));
906 /* increase the BytesNeeded size */
907 *pcbBytesNeeded
= *pcbBytesNeeded
+ dwRequiredSize
;
909 /* Don't fill callers buffer yet, as MSDN read that the last service with dependency
912 /* Recursive call to check for its dependencies */
913 Int_EnumDependentServicesW(hServicesKey
,
920 /* If the lpServices is valid set the service pointer */
922 lpServices
[*lpServicesReturned
] = lpCurrentService
;
924 *lpServicesReturned
= *lpServicesReturned
+ 1;
928 dwDependServiceStrPtr
+= (DWORD
)(wcslen(lpszValueBuf
+ dwDependServiceStrPtr
) + 1);
931 else if (*pcbBytesNeeded
)
933 dwError
= ERROR_SUCCESS
;
936 RegCloseKey(hServiceEnumKey
);
944 DWORD
RCloseServiceHandle(
945 LPSC_RPC_HANDLE hSCObject
)
947 PMANAGER_HANDLE hManager
;
948 PSERVICE_HANDLE hService
;
952 DWORD pcbBytesNeeded
= 0;
953 DWORD dwServicesReturned
= 0;
955 DPRINT("RCloseServiceHandle() called\n");
957 DPRINT("hSCObject = %p\n", *hSCObject
);
960 return ERROR_INVALID_HANDLE
;
962 hManager
= ScmGetServiceManagerFromHandle(*hSCObject
);
963 hService
= ScmGetServiceFromHandle(*hSCObject
);
965 if (hManager
!= NULL
)
967 DPRINT("Found manager handle\n");
969 /* FIXME: add handle cleanup code */
971 HeapFree(GetProcessHeap(), 0, hManager
);
976 DPRINT("RCloseServiceHandle() done\n");
977 return ERROR_SUCCESS
;
979 else if (hService
!= NULL
)
981 DPRINT("Found service handle\n");
983 /* Lock the service database exlusively */
984 ScmLockDatabaseExclusive();
986 /* Get the pointer to the service record */
987 lpService
= hService
->ServiceEntry
;
989 /* FIXME: add handle cleanup code */
991 /* Free the handle */
992 HeapFree(GetProcessHeap(), 0, hService
);
995 ASSERT(lpService
->dwRefCount
> 0);
997 lpService
->dwRefCount
--;
998 DPRINT("CloseServiceHandle - lpService->dwRefCount %u\n",
999 lpService
->dwRefCount
);
1001 if (lpService
->dwRefCount
== 0)
1003 /* If this service has been marked for deletion */
1004 if (lpService
->bDeleted
)
1006 /* Open the Services Reg key */
1007 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1008 L
"System\\CurrentControlSet\\Services",
1010 KEY_SET_VALUE
| KEY_READ
,
1012 if (dwError
!= ERROR_SUCCESS
)
1014 DPRINT("Failed to open services key\n");
1015 ScmUnlockDatabase();
1019 /* Call the internal function with NULL, just to get bytes we need */
1020 Int_EnumDependentServicesW(hServicesKey
,
1025 &dwServicesReturned
);
1027 /* if pcbBytesNeeded returned a value then there are services running that are dependent on this service */
1030 DPRINT("Deletion failed due to running dependencies.\n");
1031 RegCloseKey(hServicesKey
);
1032 ScmUnlockDatabase();
1033 return ERROR_SUCCESS
;
1036 /* There are no references and no runnning dependencies,
1037 it is now safe to delete the service */
1039 /* Delete the Service Key */
1040 dwError
= RegDeleteKeyW(hServicesKey
,
1041 lpService
->lpServiceName
);
1043 RegCloseKey(hServicesKey
);
1045 if (dwError
!= ERROR_SUCCESS
)
1047 DPRINT("Failed to Delete the Service Registry key\n");
1048 ScmUnlockDatabase();
1052 /* Delete the Service */
1053 ScmDeleteServiceRecord(lpService
);
1057 ScmUnlockDatabase();
1061 DPRINT("RCloseServiceHandle() done\n");
1062 return ERROR_SUCCESS
;
1065 DPRINT("Invalid handle tag (Tag %lx)\n", hManager
->Handle
.Tag
);
1067 return ERROR_INVALID_HANDLE
;
1072 DWORD
RControlService(
1073 SC_RPC_HANDLE hService
,
1075 LPSERVICE_STATUS lpServiceStatus
)
1077 PSERVICE_HANDLE hSvc
;
1079 ACCESS_MASK DesiredAccess
;
1080 DWORD dwError
= ERROR_SUCCESS
;
1081 DWORD pcbBytesNeeded
= 0;
1082 DWORD dwServicesReturned
= 0;
1083 DWORD dwControlsAccepted
;
1084 DWORD dwCurrentState
;
1085 HKEY hServicesKey
= NULL
;
1087 DPRINT("RControlService() called\n");
1090 return ERROR_SHUTDOWN_IN_PROGRESS
;
1092 /* Check the service handle */
1093 hSvc
= ScmGetServiceFromHandle(hService
);
1096 DPRINT1("Invalid service handle!\n");
1097 return ERROR_INVALID_HANDLE
;
1100 /* Check the service entry point */
1101 lpService
= hSvc
->ServiceEntry
;
1102 if (lpService
== NULL
)
1104 DPRINT1("lpService == NULL!\n");
1105 return ERROR_INVALID_HANDLE
;
1108 /* Check access rights */
1111 case SERVICE_CONTROL_STOP
:
1112 DesiredAccess
= SERVICE_STOP
;
1115 case SERVICE_CONTROL_PAUSE
:
1116 case SERVICE_CONTROL_CONTINUE
:
1117 DesiredAccess
= SERVICE_PAUSE_CONTINUE
;
1120 case SERVICE_CONTROL_INTERROGATE
:
1121 DesiredAccess
= SERVICE_INTERROGATE
;
1125 if (dwControl
>= 128 && dwControl
<= 255)
1126 DesiredAccess
= SERVICE_USER_DEFINED_CONTROL
;
1128 return ERROR_INVALID_PARAMETER
;
1132 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1134 return ERROR_ACCESS_DENIED
;
1136 /* Return the current service status information */
1137 RtlCopyMemory(lpServiceStatus
,
1139 sizeof(SERVICE_STATUS
));
1141 if (dwControl
== SERVICE_CONTROL_STOP
)
1143 /* Check if the service has dependencies running as windows
1144 doesn't stop a service that does */
1146 /* Open the Services Reg key */
1147 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1148 L
"System\\CurrentControlSet\\Services",
1152 if (dwError
!= ERROR_SUCCESS
)
1154 DPRINT("Failed to open services key\n");
1158 /* Call the internal function with NULL, just to get bytes we need */
1159 Int_EnumDependentServicesW(hServicesKey
,
1164 &dwServicesReturned
);
1166 RegCloseKey(hServicesKey
);
1168 /* If pcbBytesNeeded is not zero then there are services running that
1169 are dependent on this service */
1170 if (pcbBytesNeeded
!= 0)
1172 DPRINT("Service has running dependencies. Failed to stop service.\n");
1173 return ERROR_DEPENDENT_SERVICES_RUNNING
;
1177 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
1179 /* Send control code to the driver */
1180 dwError
= ScmControlDriver(lpService
,
1186 dwControlsAccepted
= lpService
->Status
.dwControlsAccepted
;
1187 dwCurrentState
= lpService
->Status
.dwCurrentState
;
1189 /* Return ERROR_SERVICE_NOT_ACTIVE if the service has not been started */
1190 if (lpService
->lpImage
== NULL
|| dwCurrentState
== SERVICE_STOPPED
)
1191 return ERROR_SERVICE_NOT_ACTIVE
;
1193 /* Check the current state before sending a control request */
1194 switch (dwCurrentState
)
1196 case SERVICE_STOP_PENDING
:
1197 case SERVICE_STOPPED
:
1198 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL
;
1200 case SERVICE_START_PENDING
:
1203 case SERVICE_CONTROL_STOP
:
1206 case SERVICE_CONTROL_INTERROGATE
:
1207 RtlCopyMemory(lpServiceStatus
,
1209 sizeof(SERVICE_STATUS
));
1210 return ERROR_SUCCESS
;
1213 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL
;
1218 /* Check if the control code is acceptable to the service */
1221 case SERVICE_CONTROL_STOP
:
1222 if ((dwControlsAccepted
& SERVICE_ACCEPT_STOP
) == 0)
1223 return ERROR_INVALID_SERVICE_CONTROL
;
1226 case SERVICE_CONTROL_PAUSE
:
1227 case SERVICE_CONTROL_CONTINUE
:
1228 if ((dwControlsAccepted
& SERVICE_ACCEPT_PAUSE_CONTINUE
) == 0)
1229 return ERROR_INVALID_SERVICE_CONTROL
;
1233 /* Send control code to the service */
1234 dwError
= ScmControlService(lpService
,
1237 /* Return service status information */
1238 RtlCopyMemory(lpServiceStatus
,
1240 sizeof(SERVICE_STATUS
));
1248 DWORD
RDeleteService(
1249 SC_RPC_HANDLE hService
)
1251 PSERVICE_HANDLE hSvc
;
1255 DPRINT("RDeleteService() called\n");
1258 return ERROR_SHUTDOWN_IN_PROGRESS
;
1260 hSvc
= ScmGetServiceFromHandle(hService
);
1263 DPRINT1("Invalid service handle!\n");
1264 return ERROR_INVALID_HANDLE
;
1267 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1269 return ERROR_ACCESS_DENIED
;
1271 lpService
= hSvc
->ServiceEntry
;
1272 if (lpService
== NULL
)
1274 DPRINT("lpService == NULL!\n");
1275 return ERROR_INVALID_HANDLE
;
1278 /* Lock the service database exclusively */
1279 ScmLockDatabaseExclusive();
1281 if (lpService
->bDeleted
)
1283 DPRINT("The service has already been marked for delete!\n");
1284 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
1288 /* Mark service for delete */
1289 lpService
->bDeleted
= TRUE
;
1291 dwError
= ScmMarkServiceForDelete(lpService
);
1294 /* Unlock the service database */
1295 ScmUnlockDatabase();
1297 DPRINT("RDeleteService() done\n");
1304 DWORD
RLockServiceDatabase(
1305 SC_RPC_HANDLE hSCManager
,
1306 LPSC_RPC_LOCK lpLock
)
1308 PMANAGER_HANDLE hMgr
;
1310 DPRINT("RLockServiceDatabase() called\n");
1314 hMgr
= ScmGetServiceManagerFromHandle(hSCManager
);
1317 DPRINT1("Invalid service manager handle!\n");
1318 return ERROR_INVALID_HANDLE
;
1321 if (!RtlAreAllAccessesGranted(hMgr
->Handle
.DesiredAccess
,
1323 return ERROR_ACCESS_DENIED
;
1325 return ScmAcquireServiceStartLock(FALSE
, lpLock
);
1330 DWORD
RQueryServiceObjectSecurity(
1331 SC_RPC_HANDLE hService
,
1332 SECURITY_INFORMATION dwSecurityInformation
,
1333 LPBYTE lpSecurityDescriptor
,
1335 LPBOUNDED_DWORD_256K pcbBytesNeeded
)
1337 PSERVICE_HANDLE hSvc
;
1339 ULONG DesiredAccess
= 0;
1341 DWORD dwBytesNeeded
;
1345 SECURITY_DESCRIPTOR ObjectDescriptor
;
1347 DPRINT("RQueryServiceObjectSecurity() called\n");
1349 hSvc
= ScmGetServiceFromHandle(hService
);
1352 DPRINT1("Invalid service handle!\n");
1353 return ERROR_INVALID_HANDLE
;
1356 if (dwSecurityInformation
& (DACL_SECURITY_INFORMATION
|
1357 GROUP_SECURITY_INFORMATION
|
1358 OWNER_SECURITY_INFORMATION
))
1359 DesiredAccess
|= READ_CONTROL
;
1361 if (dwSecurityInformation
& SACL_SECURITY_INFORMATION
)
1362 DesiredAccess
|= ACCESS_SYSTEM_SECURITY
;
1364 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1367 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1368 return ERROR_ACCESS_DENIED
;
1371 lpService
= hSvc
->ServiceEntry
;
1372 if (lpService
== NULL
)
1374 DPRINT("lpService == NULL!\n");
1375 return ERROR_INVALID_HANDLE
;
1378 /* Lock the service database */
1379 ScmLockDatabaseShared();
1383 Status
= RtlCreateSecurityDescriptor(&ObjectDescriptor
, SECURITY_DESCRIPTOR_REVISION
);
1385 Status
= RtlQuerySecurityObject(&ObjectDescriptor
/* lpService->lpSecurityDescriptor */,
1386 dwSecurityInformation
,
1387 (PSECURITY_DESCRIPTOR
)lpSecurityDescriptor
,
1391 /* Unlock the service database */
1392 ScmUnlockDatabase();
1394 if (NT_SUCCESS(Status
))
1396 *pcbBytesNeeded
= dwBytesNeeded
;
1397 dwError
= STATUS_SUCCESS
;
1399 else if (Status
== STATUS_BUFFER_TOO_SMALL
)
1401 *pcbBytesNeeded
= dwBytesNeeded
;
1402 dwError
= ERROR_INSUFFICIENT_BUFFER
;
1404 else if (Status
== STATUS_BAD_DESCRIPTOR_FORMAT
)
1406 dwError
= ERROR_GEN_FAILURE
;
1410 dwError
= RtlNtStatusToDosError(Status
);
1418 DWORD
RSetServiceObjectSecurity(
1419 SC_RPC_HANDLE hService
,
1420 DWORD dwSecurityInformation
,
1421 LPBYTE lpSecurityDescriptor
,
1422 DWORD dwSecuityDescriptorSize
)
1424 PSERVICE_HANDLE hSvc
;
1426 ULONG DesiredAccess
= 0;
1427 /* HANDLE hToken = NULL; */
1429 /* NTSTATUS Status; */
1432 DPRINT("RSetServiceObjectSecurity() called\n");
1434 hSvc
= ScmGetServiceFromHandle(hService
);
1437 DPRINT1("Invalid service handle!\n");
1438 return ERROR_INVALID_HANDLE
;
1441 if (dwSecurityInformation
== 0 ||
1442 dwSecurityInformation
& ~(OWNER_SECURITY_INFORMATION
| GROUP_SECURITY_INFORMATION
1443 | DACL_SECURITY_INFORMATION
| SACL_SECURITY_INFORMATION
))
1444 return ERROR_INVALID_PARAMETER
;
1446 if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR
)lpSecurityDescriptor
))
1447 return ERROR_INVALID_PARAMETER
;
1449 if (dwSecurityInformation
& SACL_SECURITY_INFORMATION
)
1450 DesiredAccess
|= ACCESS_SYSTEM_SECURITY
;
1452 if (dwSecurityInformation
& DACL_SECURITY_INFORMATION
)
1453 DesiredAccess
|= WRITE_DAC
;
1455 if (dwSecurityInformation
& (OWNER_SECURITY_INFORMATION
| GROUP_SECURITY_INFORMATION
))
1456 DesiredAccess
|= WRITE_OWNER
;
1458 if ((dwSecurityInformation
& OWNER_SECURITY_INFORMATION
) &&
1459 (((PISECURITY_DESCRIPTOR
)lpSecurityDescriptor
)->Owner
== NULL
))
1460 return ERROR_INVALID_PARAMETER
;
1462 if ((dwSecurityInformation
& GROUP_SECURITY_INFORMATION
) &&
1463 (((PISECURITY_DESCRIPTOR
)lpSecurityDescriptor
)->Group
== NULL
))
1464 return ERROR_INVALID_PARAMETER
;
1466 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1469 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1470 return ERROR_ACCESS_DENIED
;
1473 lpService
= hSvc
->ServiceEntry
;
1474 if (lpService
== NULL
)
1476 DPRINT("lpService == NULL!\n");
1477 return ERROR_INVALID_HANDLE
;
1480 if (lpService
->bDeleted
)
1481 return ERROR_SERVICE_MARKED_FOR_DELETE
;
1484 RpcImpersonateClient(NULL
);
1486 Status
= NtOpenThreadToken(NtCurrentThread(),
1490 if (!NT_SUCCESS(Status
))
1491 return RtlNtStatusToDosError(Status
);
1496 /* Lock the service database exclusive */
1497 ScmLockDatabaseExclusive();
1500 Status
= RtlSetSecurityObject(dwSecurityInformation
,
1501 (PSECURITY_DESCRIPTOR
)lpSecurityDescriptor
,
1502 &lpService
->lpSecurityDescriptor
,
1505 if (!NT_SUCCESS(Status
))
1507 dwError
= RtlNtStatusToDosError(Status
);
1512 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
1513 READ_CONTROL
| KEY_CREATE_SUB_KEY
| KEY_SET_VALUE
,
1515 if (dwError
!= ERROR_SUCCESS
)
1519 dwError
= ERROR_SUCCESS
;
1520 // dwError = ScmWriteSecurityDescriptor(hServiceKey,
1521 // lpService->lpSecurityDescriptor);
1523 RegFlushKey(hServiceKey
);
1524 RegCloseKey(hServiceKey
);
1533 /* Unlock service database */
1534 ScmUnlockDatabase();
1536 DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError
);
1543 DWORD
RQueryServiceStatus(
1544 SC_RPC_HANDLE hService
,
1545 LPSERVICE_STATUS lpServiceStatus
)
1547 PSERVICE_HANDLE hSvc
;
1550 DPRINT("RQueryServiceStatus() called\n");
1553 return ERROR_SHUTDOWN_IN_PROGRESS
;
1555 hSvc
= ScmGetServiceFromHandle(hService
);
1558 DPRINT1("Invalid service handle!\n");
1559 return ERROR_INVALID_HANDLE
;
1562 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1563 SERVICE_QUERY_STATUS
))
1565 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1566 return ERROR_ACCESS_DENIED
;
1569 lpService
= hSvc
->ServiceEntry
;
1570 if (lpService
== NULL
)
1572 DPRINT("lpService == NULL!\n");
1573 return ERROR_INVALID_HANDLE
;
1576 /* Lock the service database shared */
1577 ScmLockDatabaseShared();
1579 /* Return service status information */
1580 RtlCopyMemory(lpServiceStatus
,
1582 sizeof(SERVICE_STATUS
));
1584 /* Unlock the service database */
1585 ScmUnlockDatabase();
1587 return ERROR_SUCCESS
;
1592 ScmIsValidServiceState(DWORD dwCurrentState
)
1594 switch (dwCurrentState
)
1596 case SERVICE_STOPPED
:
1597 case SERVICE_START_PENDING
:
1598 case SERVICE_STOP_PENDING
:
1599 case SERVICE_RUNNING
:
1600 case SERVICE_CONTINUE_PENDING
:
1601 case SERVICE_PAUSE_PENDING
:
1602 case SERVICE_PAUSED
:
1612 DWORD
RSetServiceStatus(
1613 RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
1614 LPSERVICE_STATUS lpServiceStatus
)
1617 DWORD dwPreviousState
;
1618 LPCWSTR lpErrorStrings
[2];
1619 WCHAR szErrorBuffer
[32];
1621 DPRINT("RSetServiceStatus() called\n");
1622 DPRINT("hServiceStatus = %lu\n", hServiceStatus
);
1623 DPRINT("dwServiceType = %lu\n", lpServiceStatus
->dwServiceType
);
1624 DPRINT("dwCurrentState = %lu\n", lpServiceStatus
->dwCurrentState
);
1625 DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus
->dwControlsAccepted
);
1626 DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus
->dwWin32ExitCode
);
1627 DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus
->dwServiceSpecificExitCode
);
1628 DPRINT("dwCheckPoint = %lu\n", lpServiceStatus
->dwCheckPoint
);
1629 DPRINT("dwWaitHint = %lu\n", lpServiceStatus
->dwWaitHint
);
1631 if (hServiceStatus
== 0)
1633 DPRINT("hServiceStatus == NULL!\n");
1634 return ERROR_INVALID_HANDLE
;
1637 lpService
= (PSERVICE
)hServiceStatus
;
1639 /* Check current state */
1640 if (!ScmIsValidServiceState(lpServiceStatus
->dwCurrentState
))
1642 DPRINT("Invalid service state!\n");
1643 return ERROR_INVALID_DATA
;
1646 /* Check service type */
1647 if (!(lpServiceStatus
->dwServiceType
& SERVICE_WIN32
) &&
1648 (lpServiceStatus
->dwServiceType
& SERVICE_DRIVER
))
1650 DPRINT("Invalid service type!\n");
1651 return ERROR_INVALID_DATA
;
1654 /* Check accepted controls */
1655 if (lpServiceStatus
->dwControlsAccepted
& ~0xFF)
1657 DPRINT("Invalid controls accepted!\n");
1658 return ERROR_INVALID_DATA
;
1661 /* Lock the service database exclusively */
1662 ScmLockDatabaseExclusive();
1664 /* Save the current service state */
1665 dwPreviousState
= lpService
->Status
.dwCurrentState
;
1667 RtlCopyMemory(&lpService
->Status
,
1669 sizeof(SERVICE_STATUS
));
1671 /* Unlock the service database */
1672 ScmUnlockDatabase();
1674 /* Log a failed service stop */
1675 if ((lpServiceStatus
->dwCurrentState
== SERVICE_STOPPED
) &&
1676 (dwPreviousState
!= SERVICE_STOPPED
))
1678 if (lpServiceStatus
->dwWin32ExitCode
!= ERROR_SUCCESS
)
1680 swprintf(szErrorBuffer
, L
"%lu", lpServiceStatus
->dwWin32ExitCode
);
1681 lpErrorStrings
[0] = lpService
->lpDisplayName
;
1682 lpErrorStrings
[1] = szErrorBuffer
;
1684 ScmLogError(EVENT_SERVICE_EXIT_FAILED
,
1690 DPRINT("Set %S to %lu\n", lpService
->lpDisplayName
, lpService
->Status
.dwCurrentState
);
1691 DPRINT("RSetServiceStatus() done\n");
1693 return ERROR_SUCCESS
;
1698 DWORD
RUnlockServiceDatabase(
1701 DPRINT("RUnlockServiceDatabase(%p)\n", Lock
);
1702 return ScmReleaseServiceStartLock(Lock
);
1707 DWORD
RNotifyBootConfigStatus(
1708 SVCCTL_HANDLEW lpMachineName
,
1709 DWORD BootAcceptable
)
1711 DPRINT1("RNotifyBootConfigStatus(%p %lu) called\n", lpMachineName
, BootAcceptable
);
1712 return ERROR_SUCCESS
;
1715 // return ERROR_CALL_NOT_IMPLEMENTED;
1720 DWORD
RI_ScSetServiceBitsW(
1721 RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
1722 DWORD dwServiceBits
,
1724 int bUpdateImmediately
,
1728 return ERROR_CALL_NOT_IMPLEMENTED
;
1733 DWORD
RChangeServiceConfigW(
1734 SC_RPC_HANDLE hService
,
1735 DWORD dwServiceType
,
1737 DWORD dwErrorControl
,
1738 LPWSTR lpBinaryPathName
,
1739 LPWSTR lpLoadOrderGroup
,
1741 LPBYTE lpDependencies
,
1743 LPWSTR lpServiceStartName
,
1746 LPWSTR lpDisplayName
)
1748 DWORD dwError
= ERROR_SUCCESS
;
1749 PSERVICE_HANDLE hSvc
;
1750 PSERVICE lpService
= NULL
;
1751 HKEY hServiceKey
= NULL
;
1752 LPWSTR lpDisplayNameW
= NULL
;
1753 LPWSTR lpImagePathW
= NULL
;
1755 DPRINT("RChangeServiceConfigW() called\n");
1756 DPRINT("dwServiceType = %lu\n", dwServiceType
);
1757 DPRINT("dwStartType = %lu\n", dwStartType
);
1758 DPRINT("dwErrorControl = %lu\n", dwErrorControl
);
1759 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName
);
1760 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup
);
1761 DPRINT("lpDisplayName = %S\n", lpDisplayName
);
1764 return ERROR_SHUTDOWN_IN_PROGRESS
;
1766 hSvc
= ScmGetServiceFromHandle(hService
);
1769 DPRINT1("Invalid service handle!\n");
1770 return ERROR_INVALID_HANDLE
;
1773 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1774 SERVICE_CHANGE_CONFIG
))
1776 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1777 return ERROR_ACCESS_DENIED
;
1780 lpService
= hSvc
->ServiceEntry
;
1781 if (lpService
== NULL
)
1783 DPRINT("lpService == NULL!\n");
1784 return ERROR_INVALID_HANDLE
;
1787 /* Lock the service database exclusively */
1788 ScmLockDatabaseExclusive();
1790 if (lpService
->bDeleted
)
1792 DPRINT("The service has already been marked for delete!\n");
1793 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
1797 /* Open the service key */
1798 dwError
= ScmOpenServiceKey(lpService
->szServiceName
,
1801 if (dwError
!= ERROR_SUCCESS
)
1804 /* Write service data to the registry */
1805 /* Set the display name */
1806 if (lpDisplayName
!= NULL
&& *lpDisplayName
!= 0)
1808 RegSetValueExW(hServiceKey
,
1812 (LPBYTE
)lpDisplayName
,
1813 (DWORD
)((wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
)));
1815 /* Update the display name */
1816 lpDisplayNameW
= HeapAlloc(GetProcessHeap(),
1818 (wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
));
1819 if (lpDisplayNameW
== NULL
)
1821 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
1825 if (lpService
->lpDisplayName
!= lpService
->lpServiceName
)
1826 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
1828 lpService
->lpDisplayName
= lpDisplayNameW
;
1831 if (dwServiceType
!= SERVICE_NO_CHANGE
)
1833 /* Set the service type */
1834 dwError
= RegSetValueExW(hServiceKey
,
1838 (LPBYTE
)&dwServiceType
,
1840 if (dwError
!= ERROR_SUCCESS
)
1843 lpService
->Status
.dwServiceType
= dwServiceType
;
1846 if (dwStartType
!= SERVICE_NO_CHANGE
)
1848 /* Set the start value */
1849 dwError
= RegSetValueExW(hServiceKey
,
1853 (LPBYTE
)&dwStartType
,
1855 if (dwError
!= ERROR_SUCCESS
)
1858 lpService
->dwStartType
= dwStartType
;
1861 if (dwErrorControl
!= SERVICE_NO_CHANGE
)
1863 /* Set the error control value */
1864 dwError
= RegSetValueExW(hServiceKey
,
1868 (LPBYTE
)&dwErrorControl
,
1870 if (dwError
!= ERROR_SUCCESS
)
1873 lpService
->dwErrorControl
= dwErrorControl
;
1876 if (lpBinaryPathName
!= NULL
&& *lpBinaryPathName
!= 0)
1878 /* Set the image path */
1879 lpImagePathW
= lpBinaryPathName
;
1881 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
1883 dwError
= ScmCanonDriverImagePath(lpService
->dwStartType
,
1887 if (dwError
!= ERROR_SUCCESS
)
1891 dwError
= RegSetValueExW(hServiceKey
,
1895 (LPBYTE
)lpImagePathW
,
1896 (DWORD
)((wcslen(lpImagePathW
) + 1) * sizeof(WCHAR
)));
1898 if (lpImagePathW
!= lpBinaryPathName
)
1899 HeapFree(GetProcessHeap(), 0, lpImagePathW
);
1901 if (dwError
!= ERROR_SUCCESS
)
1905 /* Set the group name */
1906 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
1908 dwError
= RegSetValueExW(hServiceKey
,
1912 (LPBYTE
)lpLoadOrderGroup
,
1913 (DWORD
)((wcslen(lpLoadOrderGroup
) + 1) * sizeof(WCHAR
)));
1914 if (dwError
!= ERROR_SUCCESS
)
1917 dwError
= ScmSetServiceGroup(lpService
,
1919 if (dwError
!= ERROR_SUCCESS
)
1923 if (lpdwTagId
!= NULL
)
1925 dwError
= ScmAssignNewTag(lpService
);
1926 if (dwError
!= ERROR_SUCCESS
)
1929 dwError
= RegSetValueExW(hServiceKey
,
1933 (LPBYTE
)&lpService
->dwTag
,
1935 if (dwError
!= ERROR_SUCCESS
)
1938 *lpdwTagId
= lpService
->dwTag
;
1941 /* Write dependencies */
1942 if (lpDependencies
!= NULL
&& *lpDependencies
!= 0)
1944 dwError
= ScmWriteDependencies(hServiceKey
,
1945 (LPWSTR
)lpDependencies
,
1947 if (dwError
!= ERROR_SUCCESS
)
1951 if (lpPassword
!= NULL
)
1953 /* FIXME: Decrypt and write password */
1957 if (hServiceKey
!= NULL
)
1958 RegCloseKey(hServiceKey
);
1960 /* Unlock the service database */
1961 ScmUnlockDatabase();
1963 DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError
);
1970 DWORD
RCreateServiceW(
1971 SC_RPC_HANDLE hSCManager
,
1972 LPCWSTR lpServiceName
,
1973 LPCWSTR lpDisplayName
,
1974 DWORD dwDesiredAccess
,
1975 DWORD dwServiceType
,
1977 DWORD dwErrorControl
,
1978 LPCWSTR lpBinaryPathName
,
1979 LPCWSTR lpLoadOrderGroup
,
1981 LPBYTE lpDependencies
,
1983 LPCWSTR lpServiceStartName
,
1986 LPSC_RPC_HANDLE lpServiceHandle
)
1988 PMANAGER_HANDLE hManager
;
1989 DWORD dwError
= ERROR_SUCCESS
;
1990 PSERVICE lpService
= NULL
;
1991 SC_HANDLE hServiceHandle
= NULL
;
1992 LPWSTR lpImagePath
= NULL
;
1993 HKEY hServiceKey
= NULL
;
1994 LPWSTR lpObjectName
;
1996 DPRINT("RCreateServiceW() called\n");
1997 DPRINT("lpServiceName = %S\n", lpServiceName
);
1998 DPRINT("lpDisplayName = %S\n", lpDisplayName
);
1999 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess
);
2000 DPRINT("dwServiceType = %lu\n", dwServiceType
);
2001 DPRINT("dwStartType = %lu\n", dwStartType
);
2002 DPRINT("dwErrorControl = %lu\n", dwErrorControl
);
2003 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName
);
2004 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup
);
2005 DPRINT("lpdwTagId = %p\n", lpdwTagId
);
2008 return ERROR_SHUTDOWN_IN_PROGRESS
;
2010 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
2011 if (hManager
== NULL
)
2013 DPRINT1("Invalid service manager handle!\n");
2014 return ERROR_INVALID_HANDLE
;
2017 /* Check access rights */
2018 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
2019 SC_MANAGER_CREATE_SERVICE
))
2021 DPRINT("Insufficient access rights! 0x%lx\n",
2022 hManager
->Handle
.DesiredAccess
);
2023 return ERROR_ACCESS_DENIED
;
2026 if (wcslen(lpServiceName
) == 0)
2028 return ERROR_INVALID_NAME
;
2031 if (wcslen(lpBinaryPathName
) == 0)
2033 return ERROR_INVALID_PARAMETER
;
2036 /* Check for invalid service type value */
2037 if ((dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
2038 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
) &&
2039 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
2040 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
))
2041 return ERROR_INVALID_PARAMETER
;
2043 /* Check for invalid start type value */
2044 if ((dwStartType
!= SERVICE_BOOT_START
) &&
2045 (dwStartType
!= SERVICE_SYSTEM_START
) &&
2046 (dwStartType
!= SERVICE_AUTO_START
) &&
2047 (dwStartType
!= SERVICE_DEMAND_START
) &&
2048 (dwStartType
!= SERVICE_DISABLED
))
2049 return ERROR_INVALID_PARAMETER
;
2051 /* Only drivers can be boot start or system start services */
2052 if ((dwStartType
== SERVICE_BOOT_START
) ||
2053 (dwStartType
== SERVICE_SYSTEM_START
))
2055 if ((dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
2056 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
2057 return ERROR_INVALID_PARAMETER
;
2060 /* Check for invalid error control value */
2061 if ((dwErrorControl
!= SERVICE_ERROR_IGNORE
) &&
2062 (dwErrorControl
!= SERVICE_ERROR_NORMAL
) &&
2063 (dwErrorControl
!= SERVICE_ERROR_SEVERE
) &&
2064 (dwErrorControl
!= SERVICE_ERROR_CRITICAL
))
2065 return ERROR_INVALID_PARAMETER
;
2067 if ((dwServiceType
== (SERVICE_WIN32_OWN_PROCESS
| SERVICE_INTERACTIVE_PROCESS
)) &&
2068 (lpServiceStartName
))
2070 return ERROR_INVALID_PARAMETER
;
2073 if (lpdwTagId
&& (!lpLoadOrderGroup
|| !*lpLoadOrderGroup
))
2075 return ERROR_INVALID_PARAMETER
;
2078 /* Lock the service database exclusively */
2079 ScmLockDatabaseExclusive();
2081 lpService
= ScmGetServiceEntryByName(lpServiceName
);
2084 /* Unlock the service database */
2085 ScmUnlockDatabase();
2087 /* Check if it is marked for deletion */
2088 if (lpService
->bDeleted
)
2089 return ERROR_SERVICE_MARKED_FOR_DELETE
;
2091 /* Return Error exist */
2092 return ERROR_SERVICE_EXISTS
;
2095 if (lpDisplayName
!= NULL
&&
2096 ScmGetServiceEntryByDisplayName(lpDisplayName
) != NULL
)
2098 /* Unlock the service database */
2099 ScmUnlockDatabase();
2101 return ERROR_DUPLICATE_SERVICE_NAME
;
2104 if (dwServiceType
& SERVICE_DRIVER
)
2106 dwError
= ScmCanonDriverImagePath(dwStartType
,
2109 if (dwError
!= ERROR_SUCCESS
)
2114 if (dwStartType
== SERVICE_BOOT_START
||
2115 dwStartType
== SERVICE_SYSTEM_START
)
2117 /* Unlock the service database */
2118 ScmUnlockDatabase();
2120 return ERROR_INVALID_PARAMETER
;
2124 /* Allocate a new service entry */
2125 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
2127 if (dwError
!= ERROR_SUCCESS
)
2130 /* Fill the new service entry */
2131 lpService
->Status
.dwServiceType
= dwServiceType
;
2132 lpService
->dwStartType
= dwStartType
;
2133 lpService
->dwErrorControl
= dwErrorControl
;
2135 /* Fill the display name */
2136 if (lpDisplayName
!= NULL
&&
2137 *lpDisplayName
!= 0 &&
2138 _wcsicmp(lpService
->lpDisplayName
, lpDisplayName
) != 0)
2140 lpService
->lpDisplayName
= HeapAlloc(GetProcessHeap(),
2142 (wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
));
2143 if (lpService
->lpDisplayName
== NULL
)
2145 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
2148 wcscpy(lpService
->lpDisplayName
, lpDisplayName
);
2151 /* Assign the service to a group */
2152 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
2154 dwError
= ScmSetServiceGroup(lpService
,
2156 if (dwError
!= ERROR_SUCCESS
)
2160 /* Assign a new tag */
2161 if (lpdwTagId
!= NULL
)
2163 dwError
= ScmAssignNewTag(lpService
);
2164 if (dwError
!= ERROR_SUCCESS
)
2168 /* Write service data to the registry */
2169 /* Create the service key */
2170 dwError
= ScmCreateServiceKey(lpServiceName
,
2173 if (dwError
!= ERROR_SUCCESS
)
2176 /* Set the display name */
2177 if (lpDisplayName
!= NULL
&& *lpDisplayName
!= 0)
2179 RegSetValueExW(hServiceKey
,
2183 (LPBYTE
)lpDisplayName
,
2184 (DWORD
)((wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
)));
2187 /* Set the service type */
2188 dwError
= RegSetValueExW(hServiceKey
,
2192 (LPBYTE
)&dwServiceType
,
2194 if (dwError
!= ERROR_SUCCESS
)
2197 /* Set the start value */
2198 dwError
= RegSetValueExW(hServiceKey
,
2202 (LPBYTE
)&dwStartType
,
2204 if (dwError
!= ERROR_SUCCESS
)
2207 /* Set the error control value */
2208 dwError
= RegSetValueExW(hServiceKey
,
2212 (LPBYTE
)&dwErrorControl
,
2214 if (dwError
!= ERROR_SUCCESS
)
2217 /* Set the image path */
2218 if (dwServiceType
& SERVICE_WIN32
)
2220 dwError
= RegSetValueExW(hServiceKey
,
2224 (LPBYTE
)lpBinaryPathName
,
2225 (DWORD
)((wcslen(lpBinaryPathName
) + 1) * sizeof(WCHAR
)));
2226 if (dwError
!= ERROR_SUCCESS
)
2229 else if (dwServiceType
& SERVICE_DRIVER
)
2231 dwError
= RegSetValueExW(hServiceKey
,
2235 (LPBYTE
)lpImagePath
,
2236 (DWORD
)((wcslen(lpImagePath
) + 1) * sizeof(WCHAR
)));
2237 if (dwError
!= ERROR_SUCCESS
)
2241 /* Set the group name */
2242 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
2244 dwError
= RegSetValueExW(hServiceKey
,
2248 (LPBYTE
)lpLoadOrderGroup
,
2249 (DWORD
)((wcslen(lpLoadOrderGroup
) + 1) * sizeof(WCHAR
)));
2250 if (dwError
!= ERROR_SUCCESS
)
2254 if (lpdwTagId
!= NULL
)
2256 dwError
= RegSetValueExW(hServiceKey
,
2260 (LPBYTE
)&lpService
->dwTag
,
2262 if (dwError
!= ERROR_SUCCESS
)
2266 /* Write dependencies */
2267 if (lpDependencies
!= NULL
&& *lpDependencies
!= 0)
2269 dwError
= ScmWriteDependencies(hServiceKey
,
2270 (LPCWSTR
)lpDependencies
,
2272 if (dwError
!= ERROR_SUCCESS
)
2276 /* Write service start name */
2277 if (dwServiceType
& SERVICE_WIN32
)
2279 lpObjectName
= (lpServiceStartName
!= NULL
) ? (LPWSTR
)lpServiceStartName
: L
"LocalSystem";
2280 dwError
= RegSetValueExW(hServiceKey
,
2284 (LPBYTE
)lpObjectName
,
2285 (DWORD
)((wcslen(lpObjectName
) + 1) * sizeof(WCHAR
)));
2286 if (dwError
!= ERROR_SUCCESS
)
2290 if (lpPassword
!= NULL
)
2292 /* FIXME: Decrypt and write password */
2295 dwError
= ScmCreateServiceHandle(lpService
,
2297 if (dwError
!= ERROR_SUCCESS
)
2300 dwError
= ScmCheckAccess(hServiceHandle
,
2302 if (dwError
!= ERROR_SUCCESS
)
2305 lpService
->dwRefCount
= 1;
2306 DPRINT("CreateService - lpService->dwRefCount %u\n", lpService
->dwRefCount
);
2309 /* Unlock the service database */
2310 ScmUnlockDatabase();
2312 if (hServiceKey
!= NULL
)
2313 RegCloseKey(hServiceKey
);
2315 if (dwError
== ERROR_SUCCESS
)
2317 DPRINT("hService %p\n", hServiceHandle
);
2318 *lpServiceHandle
= (SC_RPC_HANDLE
)hServiceHandle
;
2320 if (lpdwTagId
!= NULL
)
2321 *lpdwTagId
= lpService
->dwTag
;
2325 if (lpService
!= NULL
&&
2326 lpService
->lpServiceName
!= NULL
)
2328 /* Release the display name buffer */
2329 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
2334 /* Remove the service handle */
2335 HeapFree(GetProcessHeap(), 0, hServiceHandle
);
2338 if (lpService
!= NULL
)
2340 /* FIXME: remove the service entry */
2344 if (lpImagePath
!= NULL
)
2345 HeapFree(GetProcessHeap(), 0, lpImagePath
);
2347 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError
);
2354 DWORD
REnumDependentServicesW(
2355 SC_RPC_HANDLE hService
,
2356 DWORD dwServiceState
,
2359 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
2360 LPBOUNDED_DWORD_256K lpServicesReturned
)
2362 DWORD dwError
= ERROR_SUCCESS
;
2363 DWORD dwServicesReturned
= 0;
2364 DWORD dwServiceCount
;
2365 HKEY hServicesKey
= NULL
;
2366 PSERVICE_HANDLE hSvc
;
2367 PSERVICE lpService
= NULL
;
2368 PSERVICE
*lpServicesArray
= NULL
;
2369 LPENUM_SERVICE_STATUSW lpServicesPtr
= NULL
;
2372 *pcbBytesNeeded
= 0;
2373 *lpServicesReturned
= 0;
2375 DPRINT("REnumDependentServicesW() called\n");
2377 hSvc
= ScmGetServiceFromHandle(hService
);
2380 DPRINT1("Invalid service handle!\n");
2381 return ERROR_INVALID_HANDLE
;
2384 lpService
= hSvc
->ServiceEntry
;
2386 /* Check access rights */
2387 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
2388 SC_MANAGER_ENUMERATE_SERVICE
))
2390 DPRINT("Insufficient access rights! 0x%lx\n",
2391 hSvc
->Handle
.DesiredAccess
);
2392 return ERROR_ACCESS_DENIED
;
2395 /* Open the Services Reg key */
2396 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2397 L
"System\\CurrentControlSet\\Services",
2401 if (dwError
!= ERROR_SUCCESS
)
2404 /* First determine the bytes needed and get the number of dependent services */
2405 dwError
= Int_EnumDependentServicesW(hServicesKey
,
2410 &dwServicesReturned
);
2411 if (dwError
!= ERROR_SUCCESS
)
2414 /* If buffer size is less than the bytes needed or pointer is null */
2415 if ((!lpServices
) || (cbBufSize
< *pcbBytesNeeded
))
2417 dwError
= ERROR_MORE_DATA
;
2421 /* Allocate memory for array of service pointers */
2422 lpServicesArray
= HeapAlloc(GetProcessHeap(),
2424 (dwServicesReturned
+ 1) * sizeof(PSERVICE
));
2425 if (!lpServicesArray
)
2427 DPRINT1("Could not allocate a buffer!!\n");
2428 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
2432 dwServicesReturned
= 0;
2433 *pcbBytesNeeded
= 0;
2435 dwError
= Int_EnumDependentServicesW(hServicesKey
,
2440 &dwServicesReturned
);
2441 if (dwError
!= ERROR_SUCCESS
)
2446 lpServicesPtr
= (LPENUM_SERVICE_STATUSW
)lpServices
;
2447 lpStr
= (LPWSTR
)(lpServices
+ (dwServicesReturned
* sizeof(ENUM_SERVICE_STATUSW
)));
2449 /* Copy EnumDepenedentService to Buffer */
2450 for (dwServiceCount
= 0; dwServiceCount
< dwServicesReturned
; dwServiceCount
++)
2452 lpService
= lpServicesArray
[dwServiceCount
];
2454 /* Copy status info */
2455 memcpy(&lpServicesPtr
->ServiceStatus
,
2457 sizeof(SERVICE_STATUS
));
2459 /* Copy display name */
2460 wcscpy(lpStr
, lpService
->lpDisplayName
);
2461 lpServicesPtr
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
2462 lpStr
+= (wcslen(lpService
->lpDisplayName
) + 1);
2464 /* Copy service name */
2465 wcscpy(lpStr
, lpService
->lpServiceName
);
2466 lpServicesPtr
->lpServiceName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
2467 lpStr
+= (wcslen(lpService
->lpServiceName
) + 1);
2472 *lpServicesReturned
= dwServicesReturned
;
2475 if (lpServicesArray
!= NULL
)
2476 HeapFree(GetProcessHeap(), 0, lpServicesArray
);
2478 RegCloseKey(hServicesKey
);
2480 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError
);
2487 DWORD
REnumServicesStatusW(
2488 SC_RPC_HANDLE hSCManager
,
2489 DWORD dwServiceType
,
2490 DWORD dwServiceState
,
2493 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
2494 LPBOUNDED_DWORD_256K lpServicesReturned
,
2495 LPBOUNDED_DWORD_256K lpResumeHandle
)
2497 /* Enumerate all the services, not regarding of their group */
2498 return REnumServiceGroupW(hSCManager
,
2511 DWORD
ROpenSCManagerW(
2512 LPWSTR lpMachineName
,
2513 LPWSTR lpDatabaseName
,
2514 DWORD dwDesiredAccess
,
2515 LPSC_RPC_HANDLE lpScHandle
)
2520 DPRINT("ROpenSCManagerW() called\n");
2521 DPRINT("lpMachineName = %p\n", lpMachineName
);
2522 DPRINT("lpMachineName: %S\n", lpMachineName
);
2523 DPRINT("lpDataBaseName = %p\n", lpDatabaseName
);
2524 DPRINT("lpDataBaseName: %S\n", lpDatabaseName
);
2525 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess
);
2528 return ERROR_SHUTDOWN_IN_PROGRESS
;
2531 return ERROR_INVALID_PARAMETER
;
2533 dwError
= ScmCreateManagerHandle(lpDatabaseName
,
2535 if (dwError
!= ERROR_SUCCESS
)
2537 DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError
);
2541 /* Check the desired access */
2542 dwError
= ScmCheckAccess(hHandle
,
2543 dwDesiredAccess
| SC_MANAGER_CONNECT
);
2544 if (dwError
!= ERROR_SUCCESS
)
2546 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError
);
2547 HeapFree(GetProcessHeap(), 0, hHandle
);
2551 *lpScHandle
= (SC_RPC_HANDLE
)hHandle
;
2552 DPRINT("*hScm = %p\n", *lpScHandle
);
2554 DPRINT("ROpenSCManagerW() done\n");
2556 return ERROR_SUCCESS
;
2561 DWORD
ROpenServiceW(
2562 SC_RPC_HANDLE hSCManager
,
2563 LPWSTR lpServiceName
,
2564 DWORD dwDesiredAccess
,
2565 LPSC_RPC_HANDLE lpServiceHandle
)
2568 PMANAGER_HANDLE hManager
;
2570 DWORD dwError
= ERROR_SUCCESS
;
2572 DPRINT("ROpenServiceW() called\n");
2573 DPRINT("hSCManager = %p\n", hSCManager
);
2574 DPRINT("lpServiceName = %p\n", lpServiceName
);
2575 DPRINT("lpServiceName: %S\n", lpServiceName
);
2576 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess
);
2579 return ERROR_SHUTDOWN_IN_PROGRESS
;
2581 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
2582 if (hManager
== NULL
)
2584 DPRINT1("Invalid service manager handle!\n");
2585 return ERROR_INVALID_HANDLE
;
2588 if (!lpServiceHandle
)
2589 return ERROR_INVALID_PARAMETER
;
2592 return ERROR_INVALID_ADDRESS
;
2594 /* Lock the service database exclusive */
2595 ScmLockDatabaseExclusive();
2597 /* Get service database entry */
2598 lpService
= ScmGetServiceEntryByName(lpServiceName
);
2599 if (lpService
== NULL
)
2601 DPRINT("Could not find a service!\n");
2602 dwError
= ERROR_SERVICE_DOES_NOT_EXIST
;
2606 /* Create a service handle */
2607 dwError
= ScmCreateServiceHandle(lpService
,
2609 if (dwError
!= ERROR_SUCCESS
)
2611 DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError
);
2615 /* Check the desired access */
2616 dwError
= ScmCheckAccess(hHandle
,
2618 if (dwError
!= ERROR_SUCCESS
)
2620 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError
);
2621 HeapFree(GetProcessHeap(), 0, hHandle
);
2625 lpService
->dwRefCount
++;
2626 DPRINT("OpenService - lpService->dwRefCount %u\n",lpService
->dwRefCount
);
2628 *lpServiceHandle
= (SC_RPC_HANDLE
)hHandle
;
2629 DPRINT("*hService = %p\n", *lpServiceHandle
);
2632 /* Unlock the service database */
2633 ScmUnlockDatabase();
2635 DPRINT("ROpenServiceW() done\n");
2642 DWORD
RQueryServiceConfigW(
2643 SC_RPC_HANDLE hService
,
2644 LPBYTE lpBuf
, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2646 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
2648 LPQUERY_SERVICE_CONFIGW lpServiceConfig
= (LPQUERY_SERVICE_CONFIGW
)lpBuf
;
2649 DWORD dwError
= ERROR_SUCCESS
;
2650 PSERVICE_HANDLE hSvc
;
2651 PSERVICE lpService
= NULL
;
2652 HKEY hServiceKey
= NULL
;
2653 LPWSTR lpImagePath
= NULL
;
2654 LPWSTR lpServiceStartName
= NULL
;
2655 LPWSTR lpDependencies
= NULL
;
2656 DWORD dwDependenciesLength
= 0;
2657 DWORD dwRequiredSize
;
2658 WCHAR lpEmptyString
[] = {0,0};
2661 DPRINT("RQueryServiceConfigW() called\n");
2664 return ERROR_SHUTDOWN_IN_PROGRESS
;
2666 hSvc
= ScmGetServiceFromHandle(hService
);
2669 DPRINT1("Invalid service handle!\n");
2670 return ERROR_INVALID_HANDLE
;
2673 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
2674 SERVICE_QUERY_CONFIG
))
2676 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
2677 return ERROR_ACCESS_DENIED
;
2680 lpService
= hSvc
->ServiceEntry
;
2681 if (lpService
== NULL
)
2683 DPRINT("lpService == NULL!\n");
2684 return ERROR_INVALID_HANDLE
;
2687 /* Lock the service database shared */
2688 ScmLockDatabaseShared();
2690 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
2693 if (dwError
!= ERROR_SUCCESS
)
2696 /* Read the image path */
2697 dwError
= ScmReadString(hServiceKey
,
2700 if (dwError
!= ERROR_SUCCESS
)
2703 /* Read the service start name */
2704 ScmReadString(hServiceKey
,
2706 &lpServiceStartName
);
2708 /* Read the dependencies */
2709 ScmReadDependencies(hServiceKey
,
2711 &dwDependenciesLength
);
2713 dwRequiredSize
= sizeof(QUERY_SERVICE_CONFIGW
);
2715 if (lpImagePath
!= NULL
)
2716 dwRequiredSize
+= (DWORD
)((wcslen(lpImagePath
) + 1) * sizeof(WCHAR
));
2718 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2720 if ((lpService
->lpGroup
!= NULL
) && (lpService
->lpGroup
->lpGroupName
!= NULL
))
2721 dwRequiredSize
+= (DWORD
)((wcslen(lpService
->lpGroup
->lpGroupName
) + 1) * sizeof(WCHAR
));
2723 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2725 if (lpDependencies
!= NULL
)
2726 dwRequiredSize
+= dwDependenciesLength
* sizeof(WCHAR
);
2728 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2730 if (lpServiceStartName
!= NULL
)
2731 dwRequiredSize
+= (DWORD
)((wcslen(lpServiceStartName
) + 1) * sizeof(WCHAR
));
2733 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2735 if (lpService
->lpDisplayName
!= NULL
)
2736 dwRequiredSize
+= (DWORD
)((wcslen(lpService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
2738 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2740 if (lpServiceConfig
== NULL
|| cbBufSize
< dwRequiredSize
)
2742 dwError
= ERROR_INSUFFICIENT_BUFFER
;
2746 lpServiceConfig
->dwServiceType
= lpService
->Status
.dwServiceType
;
2747 lpServiceConfig
->dwStartType
= lpService
->dwStartType
;
2748 lpServiceConfig
->dwErrorControl
= lpService
->dwErrorControl
;
2749 lpServiceConfig
->dwTagId
= lpService
->dwTag
;
2751 lpStr
= (LPWSTR
)(lpServiceConfig
+ 1);
2753 /* Append the image path */
2754 if (lpImagePath
!= NULL
)
2756 wcscpy(lpStr
, lpImagePath
);
2760 wcscpy(lpStr
, lpEmptyString
);
2763 lpServiceConfig
->lpBinaryPathName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2764 lpStr
+= (wcslen(lpStr
) + 1);
2766 /* Append the group name */
2767 if ((lpService
->lpGroup
!= NULL
) && (lpService
->lpGroup
->lpGroupName
!= NULL
))
2769 wcscpy(lpStr
, lpService
->lpGroup
->lpGroupName
);
2773 wcscpy(lpStr
, lpEmptyString
);
2776 lpServiceConfig
->lpLoadOrderGroup
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2777 lpStr
+= (wcslen(lpStr
) + 1);
2779 /* Append Dependencies */
2780 if (lpDependencies
!= NULL
)
2784 dwDependenciesLength
* sizeof(WCHAR
));
2788 wcscpy(lpStr
, lpEmptyString
);
2791 lpServiceConfig
->lpDependencies
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2792 if (lpDependencies
!= NULL
)
2793 lpStr
+= dwDependenciesLength
;
2795 lpStr
+= (wcslen(lpStr
) + 1);
2797 /* Append the service start name */
2798 if (lpServiceStartName
!= NULL
)
2800 wcscpy(lpStr
, lpServiceStartName
);
2804 wcscpy(lpStr
, lpEmptyString
);
2807 lpServiceConfig
->lpServiceStartName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2808 lpStr
+= (wcslen(lpStr
) + 1);
2810 /* Append the display name */
2811 if (lpService
->lpDisplayName
!= NULL
)
2813 wcscpy(lpStr
, lpService
->lpDisplayName
);
2817 wcscpy(lpStr
, lpEmptyString
);
2820 lpServiceConfig
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
2823 if (pcbBytesNeeded
!= NULL
)
2824 *pcbBytesNeeded
= dwRequiredSize
;
2827 /* Unlock the service database */
2828 ScmUnlockDatabase();
2830 if (lpImagePath
!= NULL
)
2831 HeapFree(GetProcessHeap(), 0, lpImagePath
);
2833 if (lpServiceStartName
!= NULL
)
2834 HeapFree(GetProcessHeap(), 0, lpServiceStartName
);
2836 if (lpDependencies
!= NULL
)
2837 HeapFree(GetProcessHeap(), 0, lpDependencies
);
2839 if (hServiceKey
!= NULL
)
2840 RegCloseKey(hServiceKey
);
2842 DPRINT("RQueryServiceConfigW() done\n");
2849 DWORD
RQueryServiceLockStatusW(
2850 SC_RPC_HANDLE hSCManager
,
2851 LPBYTE lpBuf
, // LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2853 LPBOUNDED_DWORD_4K pcbBytesNeeded
)
2855 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
= (LPQUERY_SERVICE_LOCK_STATUSW
)lpBuf
;
2856 PMANAGER_HANDLE hMgr
;
2857 DWORD dwRequiredSize
;
2859 if (!lpLockStatus
|| !pcbBytesNeeded
)
2860 return ERROR_INVALID_PARAMETER
;
2862 hMgr
= ScmGetServiceManagerFromHandle(hSCManager
);
2865 DPRINT1("Invalid service manager handle!\n");
2866 return ERROR_INVALID_HANDLE
;
2869 if (!RtlAreAllAccessesGranted(hMgr
->Handle
.DesiredAccess
,
2870 SC_MANAGER_QUERY_LOCK_STATUS
))
2872 DPRINT("Insufficient access rights! 0x%lx\n", hMgr
->Handle
.DesiredAccess
);
2873 return ERROR_ACCESS_DENIED
;
2876 /* FIXME: we need to compute instead the real length of the owner name */
2877 dwRequiredSize
= sizeof(QUERY_SERVICE_LOCK_STATUSW
) + sizeof(WCHAR
);
2878 *pcbBytesNeeded
= dwRequiredSize
;
2880 if (cbBufSize
< dwRequiredSize
)
2881 return ERROR_INSUFFICIENT_BUFFER
;
2883 ScmQueryServiceLockStatusW(lpLockStatus
);
2885 return ERROR_SUCCESS
;
2890 DWORD
RStartServiceW(
2891 SC_RPC_HANDLE hService
,
2893 LPSTRING_PTRSW argv
)
2895 DWORD dwError
= ERROR_SUCCESS
;
2896 PSERVICE_HANDLE hSvc
;
2897 PSERVICE lpService
= NULL
;
2898 SC_RPC_LOCK Lock
= NULL
;
2903 DPRINT("RStartServiceW(%p %lu %p) called\n", hService
, argc
, argv
);
2904 DPRINT(" argc: %lu\n", argc
);
2907 for (i
= 0; i
< argc
; i
++)
2909 DPRINT(" argv[%lu]: %S\n", i
, argv
[i
].StringPtr
);
2915 return ERROR_SHUTDOWN_IN_PROGRESS
;
2917 hSvc
= ScmGetServiceFromHandle(hService
);
2920 DPRINT1("Invalid service handle!\n");
2921 return ERROR_INVALID_HANDLE
;
2924 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
2927 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
2928 return ERROR_ACCESS_DENIED
;
2931 lpService
= hSvc
->ServiceEntry
;
2932 if (lpService
== NULL
)
2934 DPRINT("lpService == NULL!\n");
2935 return ERROR_INVALID_HANDLE
;
2938 if (lpService
->dwStartType
== SERVICE_DISABLED
)
2939 return ERROR_SERVICE_DISABLED
;
2941 if (lpService
->bDeleted
)
2942 return ERROR_SERVICE_MARKED_FOR_DELETE
;
2944 /* Acquire the service start lock until the service has been started */
2945 dwError
= ScmAcquireServiceStartLock(TRUE
, &Lock
);
2946 if (dwError
!= ERROR_SUCCESS
)
2949 /* Start the service */
2950 dwError
= ScmStartService(lpService
, argc
, (LPWSTR
*)argv
);
2952 /* Release the service start lock */
2953 ScmReleaseServiceStartLock(&Lock
);
2960 DWORD
RGetServiceDisplayNameW(
2961 SC_RPC_HANDLE hSCManager
,
2962 LPCWSTR lpServiceName
,
2963 LPWSTR lpDisplayName
,
2966 // PMANAGER_HANDLE hManager;
2971 DPRINT("RGetServiceDisplayNameW() called\n");
2972 DPRINT("hSCManager = %p\n", hSCManager
);
2973 DPRINT("lpServiceName: %S\n", lpServiceName
);
2974 DPRINT("lpDisplayName: %p\n", lpDisplayName
);
2975 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
2977 // hManager = (PMANAGER_HANDLE)hSCManager;
2978 // if (hManager->Handle.Tag != MANAGER_TAG)
2980 // DPRINT("Invalid manager handle!\n");
2981 // return ERROR_INVALID_HANDLE;
2984 /* Get service database entry */
2985 lpService
= ScmGetServiceEntryByName(lpServiceName
);
2986 if (lpService
== NULL
)
2988 DPRINT("Could not find a service!\n");
2990 /* If the service could not be found and lpcchBuffer is less than 2, windows
2991 puts null in lpDisplayName and puts 2 in lpcchBuffer */
2992 if (*lpcchBuffer
< 2)
2995 if (lpDisplayName
!= NULL
)
3001 return ERROR_SERVICE_DOES_NOT_EXIST
;
3004 if (!lpService
->lpDisplayName
)
3006 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
3008 if (lpDisplayName
!= NULL
&&
3009 *lpcchBuffer
> dwLength
)
3011 wcscpy(lpDisplayName
, lpService
->lpServiceName
);
3016 dwLength
= (DWORD
)wcslen(lpService
->lpDisplayName
);
3018 if (lpDisplayName
!= NULL
&&
3019 *lpcchBuffer
> dwLength
)
3021 wcscpy(lpDisplayName
, lpService
->lpDisplayName
);
3025 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
3027 *lpcchBuffer
= dwLength
;
3034 DWORD
RGetServiceKeyNameW(
3035 SC_RPC_HANDLE hSCManager
,
3036 LPCWSTR lpDisplayName
,
3037 LPWSTR lpServiceName
,
3040 // PMANAGER_HANDLE hManager;
3045 DPRINT("RGetServiceKeyNameW() called\n");
3046 DPRINT("hSCManager = %p\n", hSCManager
);
3047 DPRINT("lpDisplayName: %S\n", lpDisplayName
);
3048 DPRINT("lpServiceName: %p\n", lpServiceName
);
3049 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
3051 // hManager = (PMANAGER_HANDLE)hSCManager;
3052 // if (hManager->Handle.Tag != MANAGER_TAG)
3054 // DPRINT("Invalid manager handle!\n");
3055 // return ERROR_INVALID_HANDLE;
3058 /* Get service database entry */
3059 lpService
= ScmGetServiceEntryByDisplayName(lpDisplayName
);
3060 if (lpService
== NULL
)
3062 DPRINT("Could not find a service!\n");
3064 /* If the service could not be found and lpcchBuffer is less than 2, windows
3065 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3066 if (*lpcchBuffer
< 2)
3069 if (lpServiceName
!= NULL
)
3075 return ERROR_SERVICE_DOES_NOT_EXIST
;
3078 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
3080 if (lpServiceName
!= NULL
&&
3081 *lpcchBuffer
> dwLength
)
3083 wcscpy(lpServiceName
, lpService
->lpServiceName
);
3084 *lpcchBuffer
= dwLength
;
3085 return ERROR_SUCCESS
;
3088 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
3090 *lpcchBuffer
= dwLength
;
3097 DWORD
RI_ScSetServiceBitsA(
3098 RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
3099 DWORD dwServiceBits
,
3101 int bUpdateImmediately
,
3105 return ERROR_CALL_NOT_IMPLEMENTED
;
3110 DWORD
RChangeServiceConfigA(
3111 SC_RPC_HANDLE hService
,
3112 DWORD dwServiceType
,
3114 DWORD dwErrorControl
,
3115 LPSTR lpBinaryPathName
,
3116 LPSTR lpLoadOrderGroup
,
3118 LPBYTE lpDependencies
,
3120 LPSTR lpServiceStartName
,
3123 LPSTR lpDisplayName
)
3125 DWORD dwError
= ERROR_SUCCESS
;
3126 PSERVICE_HANDLE hSvc
;
3127 PSERVICE lpService
= NULL
;
3128 HKEY hServiceKey
= NULL
;
3129 LPWSTR lpDisplayNameW
= NULL
;
3130 LPWSTR lpBinaryPathNameW
= NULL
;
3131 LPWSTR lpCanonicalImagePathW
= NULL
;
3132 LPWSTR lpLoadOrderGroupW
= NULL
;
3133 LPWSTR lpDependenciesW
= NULL
;
3135 DPRINT("RChangeServiceConfigA() called\n");
3136 DPRINT("dwServiceType = %lu\n", dwServiceType
);
3137 DPRINT("dwStartType = %lu\n", dwStartType
);
3138 DPRINT("dwErrorControl = %lu\n", dwErrorControl
);
3139 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName
);
3140 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup
);
3141 DPRINT("lpDisplayName = %s\n", lpDisplayName
);
3144 return ERROR_SHUTDOWN_IN_PROGRESS
;
3146 hSvc
= ScmGetServiceFromHandle(hService
);
3149 DPRINT1("Invalid service handle!\n");
3150 return ERROR_INVALID_HANDLE
;
3153 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3154 SERVICE_CHANGE_CONFIG
))
3156 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
3157 return ERROR_ACCESS_DENIED
;
3160 lpService
= hSvc
->ServiceEntry
;
3161 if (lpService
== NULL
)
3163 DPRINT("lpService == NULL!\n");
3164 return ERROR_INVALID_HANDLE
;
3167 /* Lock the service database exclusively */
3168 ScmLockDatabaseExclusive();
3170 if (lpService
->bDeleted
)
3172 DPRINT("The service has already been marked for delete!\n");
3173 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
3177 /* Open the service key */
3178 dwError
= ScmOpenServiceKey(lpService
->szServiceName
,
3181 if (dwError
!= ERROR_SUCCESS
)
3184 /* Write service data to the registry */
3186 if (lpDisplayName
!= NULL
&& *lpDisplayName
!= 0)
3188 /* Set the display name */
3189 lpDisplayNameW
= HeapAlloc(GetProcessHeap(),
3191 (strlen(lpDisplayName
) + 1) * sizeof(WCHAR
));
3192 if (lpDisplayNameW
== NULL
)
3194 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3198 MultiByteToWideChar(CP_ACP
,
3203 (int)(strlen(lpDisplayName
) + 1));
3205 RegSetValueExW(hServiceKey
,
3209 (LPBYTE
)lpDisplayNameW
,
3210 (DWORD
)((wcslen(lpDisplayNameW
) + 1) * sizeof(WCHAR
)));
3212 /* Update lpService->lpDisplayName */
3213 if (lpService
->lpDisplayName
)
3214 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
3216 lpService
->lpDisplayName
= lpDisplayNameW
;
3219 if (dwServiceType
!= SERVICE_NO_CHANGE
)
3221 /* Set the service type */
3222 dwError
= RegSetValueExW(hServiceKey
,
3226 (LPBYTE
)&dwServiceType
,
3228 if (dwError
!= ERROR_SUCCESS
)
3231 lpService
->Status
.dwServiceType
= dwServiceType
;
3234 if (dwStartType
!= SERVICE_NO_CHANGE
)
3236 /* Set the start value */
3237 dwError
= RegSetValueExW(hServiceKey
,
3241 (LPBYTE
)&dwStartType
,
3243 if (dwError
!= ERROR_SUCCESS
)
3246 lpService
->dwStartType
= dwStartType
;
3249 if (dwErrorControl
!= SERVICE_NO_CHANGE
)
3251 /* Set the error control value */
3252 dwError
= RegSetValueExW(hServiceKey
,
3256 (LPBYTE
)&dwErrorControl
,
3258 if (dwError
!= ERROR_SUCCESS
)
3261 lpService
->dwErrorControl
= dwErrorControl
;
3264 if (lpBinaryPathName
!= NULL
&& *lpBinaryPathName
!= 0)
3266 /* Set the image path */
3267 lpBinaryPathNameW
= HeapAlloc(GetProcessHeap(),
3269 (strlen(lpBinaryPathName
) + 1) * sizeof(WCHAR
));
3270 if (lpBinaryPathNameW
== NULL
)
3272 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3276 MultiByteToWideChar(CP_ACP
,
3281 (int)(strlen(lpBinaryPathName
) + 1));
3283 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
3285 dwError
= ScmCanonDriverImagePath(lpService
->dwStartType
,
3287 &lpCanonicalImagePathW
);
3289 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW
);
3291 if (dwError
!= ERROR_SUCCESS
)
3294 lpBinaryPathNameW
= lpCanonicalImagePathW
;
3297 dwError
= RegSetValueExW(hServiceKey
,
3301 (LPBYTE
)lpBinaryPathNameW
,
3302 (DWORD
)((wcslen(lpBinaryPathNameW
) + 1) * sizeof(WCHAR
)));
3304 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW
);
3306 if (dwError
!= ERROR_SUCCESS
)
3310 /* Set the group name */
3311 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
3313 lpLoadOrderGroupW
= HeapAlloc(GetProcessHeap(),
3315 (strlen(lpLoadOrderGroup
) + 1) * sizeof(WCHAR
));
3316 if (lpLoadOrderGroupW
== NULL
)
3318 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3322 MultiByteToWideChar(CP_ACP
,
3327 (int)(strlen(lpLoadOrderGroup
) + 1));
3329 dwError
= RegSetValueExW(hServiceKey
,
3333 (LPBYTE
)lpLoadOrderGroupW
,
3334 (DWORD
)((wcslen(lpLoadOrderGroupW
) + 1) * sizeof(WCHAR
)));
3335 if (dwError
!= ERROR_SUCCESS
)
3337 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3341 dwError
= ScmSetServiceGroup(lpService
,
3344 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3346 if (dwError
!= ERROR_SUCCESS
)
3350 if (lpdwTagId
!= NULL
)
3352 dwError
= ScmAssignNewTag(lpService
);
3353 if (dwError
!= ERROR_SUCCESS
)
3356 dwError
= RegSetValueExW(hServiceKey
,
3360 (LPBYTE
)&lpService
->dwTag
,
3362 if (dwError
!= ERROR_SUCCESS
)
3365 *lpdwTagId
= lpService
->dwTag
;
3368 /* Write dependencies */
3369 if (lpDependencies
!= NULL
&& *lpDependencies
!= 0)
3371 lpDependenciesW
= HeapAlloc(GetProcessHeap(),
3373 (strlen((LPSTR
)lpDependencies
) + 1) * sizeof(WCHAR
));
3374 if (lpDependenciesW
== NULL
)
3376 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3380 MultiByteToWideChar(CP_ACP
,
3382 (LPSTR
)lpDependencies
,
3385 (int)(strlen((LPSTR
)lpDependencies
) + 1));
3387 dwError
= ScmWriteDependencies(hServiceKey
,
3388 (LPWSTR
)lpDependenciesW
,
3391 HeapFree(GetProcessHeap(), 0, lpDependenciesW
);
3394 if (lpPassword
!= NULL
)
3396 /* FIXME: Decrypt and write password */
3400 /* Unlock the service database */
3401 ScmUnlockDatabase();
3403 if (hServiceKey
!= NULL
)
3404 RegCloseKey(hServiceKey
);
3406 DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError
);
3413 DWORD
RCreateServiceA(
3414 SC_RPC_HANDLE hSCManager
,
3415 LPSTR lpServiceName
,
3416 LPSTR lpDisplayName
,
3417 DWORD dwDesiredAccess
,
3418 DWORD dwServiceType
,
3420 DWORD dwErrorControl
,
3421 LPSTR lpBinaryPathName
,
3422 LPSTR lpLoadOrderGroup
,
3424 LPBYTE lpDependencies
,
3426 LPSTR lpServiceStartName
,
3429 LPSC_RPC_HANDLE lpServiceHandle
)
3431 DWORD dwError
= ERROR_SUCCESS
;
3432 LPWSTR lpServiceNameW
= NULL
;
3433 LPWSTR lpDisplayNameW
= NULL
;
3434 LPWSTR lpBinaryPathNameW
= NULL
;
3435 LPWSTR lpLoadOrderGroupW
= NULL
;
3436 LPWSTR lpDependenciesW
= NULL
;
3437 LPWSTR lpServiceStartNameW
= NULL
;
3438 DWORD dwDependenciesLength
= 0;
3445 len
= MultiByteToWideChar(CP_ACP
, 0, lpServiceName
, -1, NULL
, 0);
3446 lpServiceNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3447 if (!lpServiceNameW
)
3449 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3452 MultiByteToWideChar(CP_ACP
, 0, lpServiceName
, -1, lpServiceNameW
, len
);
3457 len
= MultiByteToWideChar(CP_ACP
, 0, lpDisplayName
, -1, NULL
, 0);
3458 lpDisplayNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3459 if (!lpDisplayNameW
)
3461 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3464 MultiByteToWideChar(CP_ACP
, 0, lpDisplayName
, -1, lpDisplayNameW
, len
);
3467 if (lpBinaryPathName
)
3469 len
= MultiByteToWideChar(CP_ACP
, 0, lpBinaryPathName
, -1, NULL
, 0);
3470 lpBinaryPathNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3471 if (!lpBinaryPathNameW
)
3473 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3476 MultiByteToWideChar(CP_ACP
, 0, lpBinaryPathName
, -1, lpBinaryPathNameW
, len
);
3479 if (lpLoadOrderGroup
)
3481 len
= MultiByteToWideChar(CP_ACP
, 0, lpLoadOrderGroup
, -1, NULL
, 0);
3482 lpLoadOrderGroupW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3483 if (!lpLoadOrderGroupW
)
3485 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3488 MultiByteToWideChar(CP_ACP
, 0, lpLoadOrderGroup
, -1, lpLoadOrderGroupW
, len
);
3493 lpStr
= (LPCSTR
)lpDependencies
;
3496 cchLength
= strlen(lpStr
) + 1;
3497 dwDependenciesLength
+= (DWORD
)cchLength
;
3498 lpStr
= lpStr
+ cchLength
;
3500 dwDependenciesLength
++;
3502 lpDependenciesW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwDependenciesLength
* sizeof(WCHAR
));
3503 if (!lpDependenciesW
)
3505 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3508 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)lpDependencies
, dwDependenciesLength
, lpDependenciesW
, dwDependenciesLength
);
3511 if (lpServiceStartName
)
3513 len
= MultiByteToWideChar(CP_ACP
, 0, lpServiceStartName
, -1, NULL
, 0);
3514 lpServiceStartNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3515 if (!lpServiceStartNameW
)
3517 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3520 MultiByteToWideChar(CP_ACP
, 0, lpServiceStartName
, -1, lpServiceStartNameW
, len
);
3523 dwError
= RCreateServiceW(hSCManager
,
3533 (LPBYTE
)lpDependenciesW
,
3534 dwDependenciesLength
,
3535 lpServiceStartNameW
,
3541 if (lpServiceNameW
!=NULL
)
3542 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
3544 if (lpDisplayNameW
!= NULL
)
3545 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
3547 if (lpBinaryPathNameW
!= NULL
)
3548 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW
);
3550 if (lpLoadOrderGroupW
!= NULL
)
3551 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3553 if (lpDependenciesW
!= NULL
)
3554 HeapFree(GetProcessHeap(), 0, lpDependenciesW
);
3556 if (lpServiceStartNameW
!= NULL
)
3557 HeapFree(GetProcessHeap(), 0, lpServiceStartNameW
);
3564 DWORD
REnumDependentServicesA(
3565 SC_RPC_HANDLE hService
,
3566 DWORD dwServiceState
,
3569 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
3570 LPBOUNDED_DWORD_256K lpServicesReturned
)
3572 DWORD dwError
= ERROR_SUCCESS
;
3573 DWORD dwServicesReturned
= 0;
3574 DWORD dwServiceCount
;
3575 HKEY hServicesKey
= NULL
;
3576 PSERVICE_HANDLE hSvc
;
3577 PSERVICE lpService
= NULL
;
3578 PSERVICE
*lpServicesArray
= NULL
;
3579 LPENUM_SERVICE_STATUSA lpServicesPtr
= NULL
;
3582 *pcbBytesNeeded
= 0;
3583 *lpServicesReturned
= 0;
3585 DPRINT("REnumDependentServicesA() called\n");
3587 hSvc
= ScmGetServiceFromHandle(hService
);
3590 DPRINT1("Invalid service handle!\n");
3591 return ERROR_INVALID_HANDLE
;
3594 lpService
= hSvc
->ServiceEntry
;
3596 /* Check access rights */
3597 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3598 SC_MANAGER_ENUMERATE_SERVICE
))
3600 DPRINT("Insufficient access rights! 0x%lx\n",
3601 hSvc
->Handle
.DesiredAccess
);
3602 return ERROR_ACCESS_DENIED
;
3605 /* Open the Services Reg key */
3606 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
3607 L
"System\\CurrentControlSet\\Services",
3612 if (dwError
!= ERROR_SUCCESS
)
3615 /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3616 both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3617 are the same for both. Verified in WINXP. */
3619 /* First determine the bytes needed and get the number of dependent services*/
3620 dwError
= Int_EnumDependentServicesW(hServicesKey
,
3625 &dwServicesReturned
);
3626 if (dwError
!= ERROR_SUCCESS
)
3629 /* If buffer size is less than the bytes needed or pointer is null*/
3630 if ((!lpServices
) || (cbBufSize
< *pcbBytesNeeded
))
3632 dwError
= ERROR_MORE_DATA
;
3636 /* Allocate memory for array of service pointers */
3637 lpServicesArray
= HeapAlloc(GetProcessHeap(),
3639 (dwServicesReturned
+ 1) * sizeof(PSERVICE
));
3640 if (!lpServicesArray
)
3642 DPRINT("Could not allocate a buffer!!\n");
3643 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3647 dwServicesReturned
= 0;
3648 *pcbBytesNeeded
= 0;
3650 dwError
= Int_EnumDependentServicesW(hServicesKey
,
3655 &dwServicesReturned
);
3656 if (dwError
!= ERROR_SUCCESS
)
3661 lpServicesPtr
= (LPENUM_SERVICE_STATUSA
)lpServices
;
3662 lpStr
= (LPSTR
)(lpServices
+ (dwServicesReturned
* sizeof(ENUM_SERVICE_STATUSA
)));
3664 /* Copy EnumDepenedentService to Buffer */
3665 for (dwServiceCount
= 0; dwServiceCount
< dwServicesReturned
; dwServiceCount
++)
3667 lpService
= lpServicesArray
[dwServiceCount
];
3669 /* Copy the status info */
3670 memcpy(&lpServicesPtr
->ServiceStatus
,
3672 sizeof(SERVICE_STATUS
));
3674 /* Copy display name */
3675 WideCharToMultiByte(CP_ACP
,
3677 lpService
->lpDisplayName
,
3680 (int)wcslen(lpService
->lpDisplayName
),
3683 lpServicesPtr
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
3684 lpStr
+= strlen(lpStr
) + 1;
3686 /* Copy service name */
3687 WideCharToMultiByte(CP_ACP
,
3689 lpService
->lpServiceName
,
3692 (int)wcslen(lpService
->lpServiceName
),
3695 lpServicesPtr
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
3696 lpStr
+= strlen(lpStr
) + 1;
3701 *lpServicesReturned
= dwServicesReturned
;
3704 if (lpServicesArray
)
3705 HeapFree(GetProcessHeap(), 0, lpServicesArray
);
3707 RegCloseKey(hServicesKey
);
3709 DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError
);
3716 DWORD
REnumServicesStatusA(
3717 SC_RPC_HANDLE hSCManager
,
3718 DWORD dwServiceType
,
3719 DWORD dwServiceState
,
3722 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
3723 LPBOUNDED_DWORD_256K lpServicesReturned
,
3724 LPBOUNDED_DWORD_256K lpResumeHandle
)
3726 LPENUM_SERVICE_STATUSW lpStatusPtrW
= NULL
;
3727 LPENUM_SERVICE_STATUSW lpStatusPtrIncrW
;
3728 LPENUM_SERVICE_STATUSA lpStatusPtrA
= NULL
;
3729 LPWSTR lpStringPtrW
;
3732 DWORD dwServiceCount
;
3734 DPRINT("REnumServicesStatusA() called\n");
3736 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
3738 return ERROR_INVALID_ADDRESS
;
3741 if ((dwBufSize
> 0) && (lpBuffer
))
3743 lpStatusPtrW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwBufSize
);
3746 DPRINT("Failed to allocate buffer!\n");
3747 return ERROR_NOT_ENOUGH_MEMORY
;
3751 dwError
= REnumServicesStatusW(hSCManager
,
3754 (LPBYTE
)lpStatusPtrW
,
3760 /* if no services were returned then we are Done */
3761 if (*lpServicesReturned
== 0)
3764 lpStatusPtrIncrW
= lpStatusPtrW
;
3765 lpStatusPtrA
= (LPENUM_SERVICE_STATUSA
)lpBuffer
;
3766 lpStringPtrA
= (LPSTR
)((ULONG_PTR
)lpBuffer
+
3767 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUSA
));
3768 lpStringPtrW
= (LPWSTR
)((ULONG_PTR
)lpStatusPtrW
+
3769 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUSW
));
3771 for (dwServiceCount
= 0; dwServiceCount
< *lpServicesReturned
; dwServiceCount
++)
3773 /* Copy the service name */
3774 WideCharToMultiByte(CP_ACP
,
3779 (int)wcslen(lpStringPtrW
),
3783 lpStatusPtrA
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
3784 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
3785 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
3787 /* Copy the display name */
3788 WideCharToMultiByte(CP_ACP
,
3793 (int)wcslen(lpStringPtrW
),
3797 lpStatusPtrA
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
3798 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
3799 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
3801 /* Copy the status information */
3802 memcpy(&lpStatusPtrA
->ServiceStatus
,
3803 &lpStatusPtrIncrW
->ServiceStatus
,
3804 sizeof(SERVICE_STATUS
));
3812 HeapFree(GetProcessHeap(), 0, lpStatusPtrW
);
3814 DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError
);
3821 DWORD
ROpenSCManagerA(
3822 LPSTR lpMachineName
,
3823 LPSTR lpDatabaseName
,
3824 DWORD dwDesiredAccess
,
3825 LPSC_RPC_HANDLE lpScHandle
)
3827 UNICODE_STRING MachineName
;
3828 UNICODE_STRING DatabaseName
;
3831 DPRINT("ROpenSCManagerA() called\n");
3834 RtlCreateUnicodeStringFromAsciiz(&MachineName
,
3838 RtlCreateUnicodeStringFromAsciiz(&DatabaseName
,
3841 dwError
= ROpenSCManagerW(lpMachineName
? MachineName
.Buffer
: NULL
,
3842 lpDatabaseName
? DatabaseName
.Buffer
: NULL
,
3847 RtlFreeUnicodeString(&MachineName
);
3850 RtlFreeUnicodeString(&DatabaseName
);
3857 DWORD
ROpenServiceA(
3858 SC_RPC_HANDLE hSCManager
,
3859 LPSTR lpServiceName
,
3860 DWORD dwDesiredAccess
,
3861 LPSC_RPC_HANDLE lpServiceHandle
)
3863 UNICODE_STRING ServiceName
;
3866 DPRINT("ROpenServiceA() called\n");
3869 RtlCreateUnicodeStringFromAsciiz(&ServiceName
,
3872 dwError
= ROpenServiceW(hSCManager
,
3873 lpServiceName
? ServiceName
.Buffer
: NULL
,
3878 RtlFreeUnicodeString(&ServiceName
);
3885 DWORD
RQueryServiceConfigA(
3886 SC_RPC_HANDLE hService
,
3887 LPBYTE lpBuf
, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
3889 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
3891 LPQUERY_SERVICE_CONFIGA lpServiceConfig
= (LPQUERY_SERVICE_CONFIGA
)lpBuf
;
3892 DWORD dwError
= ERROR_SUCCESS
;
3893 PSERVICE_HANDLE hSvc
;
3894 PSERVICE lpService
= NULL
;
3895 HKEY hServiceKey
= NULL
;
3896 LPWSTR lpImagePath
= NULL
;
3897 LPWSTR lpServiceStartName
= NULL
;
3898 LPWSTR lpDependencies
= NULL
;
3899 DWORD dwDependenciesLength
= 0;
3900 DWORD dwRequiredSize
;
3901 CHAR lpEmptyString
[]={0,0};
3904 DPRINT("RQueryServiceConfigA() called\n");
3907 return ERROR_SHUTDOWN_IN_PROGRESS
;
3909 hSvc
= ScmGetServiceFromHandle(hService
);
3912 DPRINT1("Invalid service handle!\n");
3913 return ERROR_INVALID_HANDLE
;
3916 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3917 SERVICE_QUERY_CONFIG
))
3919 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
3920 return ERROR_ACCESS_DENIED
;
3923 lpService
= hSvc
->ServiceEntry
;
3924 if (lpService
== NULL
)
3926 DPRINT("lpService == NULL!\n");
3927 return ERROR_INVALID_HANDLE
;
3930 /* Lock the service database shared */
3931 ScmLockDatabaseShared();
3933 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
3936 if (dwError
!= ERROR_SUCCESS
)
3939 /* Read the image path */
3940 dwError
= ScmReadString(hServiceKey
,
3943 if (dwError
!= ERROR_SUCCESS
)
3946 /* Read the service start name */
3947 ScmReadString(hServiceKey
,
3949 &lpServiceStartName
);
3951 /* Read the dependencies */
3952 ScmReadDependencies(hServiceKey
,
3954 &dwDependenciesLength
);
3956 dwRequiredSize
= sizeof(QUERY_SERVICE_CONFIGA
);
3958 if (lpImagePath
!= NULL
)
3959 dwRequiredSize
+= (DWORD
)(wcslen(lpImagePath
) + 1);
3961 dwRequiredSize
+= 2;
3963 if ((lpService
->lpGroup
!= NULL
) && (lpService
->lpGroup
->lpGroupName
!= NULL
))
3964 dwRequiredSize
+= (DWORD
)(wcslen(lpService
->lpGroup
->lpGroupName
) + 1);
3966 dwRequiredSize
+= 2;
3968 /* Add Dependencies length */
3969 if (lpDependencies
!= NULL
)
3970 dwRequiredSize
+= dwDependenciesLength
;
3972 dwRequiredSize
+= 2;
3974 if (lpServiceStartName
!= NULL
)
3975 dwRequiredSize
+= (DWORD
)(wcslen(lpServiceStartName
) + 1);
3977 dwRequiredSize
+= 2;
3979 if (lpService
->lpDisplayName
!= NULL
)
3980 dwRequiredSize
+= (DWORD
)(wcslen(lpService
->lpDisplayName
) + 1);
3982 dwRequiredSize
+= 2;
3984 if (lpServiceConfig
== NULL
|| cbBufSize
< dwRequiredSize
)
3986 dwError
= ERROR_INSUFFICIENT_BUFFER
;
3990 lpServiceConfig
->dwServiceType
= lpService
->Status
.dwServiceType
;
3991 lpServiceConfig
->dwStartType
= lpService
->dwStartType
;
3992 lpServiceConfig
->dwErrorControl
= lpService
->dwErrorControl
;
3993 lpServiceConfig
->dwTagId
= lpService
->dwTag
;
3995 lpStr
= (LPSTR
)(lpServiceConfig
+ 1);
3997 /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
3998 Verified in WINXP */
4002 WideCharToMultiByte(CP_ACP
,
4007 (int)(wcslen(lpImagePath
) + 1),
4013 strcpy(lpStr
, lpEmptyString
);
4016 lpServiceConfig
->lpBinaryPathName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4017 lpStr
+= (strlen((LPSTR
)lpStr
) + 1);
4019 if (lpService
->lpGroup
&& lpService
->lpGroup
->lpGroupName
)
4021 WideCharToMultiByte(CP_ACP
,
4023 lpService
->lpGroup
->lpGroupName
,
4026 (int)(wcslen(lpService
->lpGroup
->lpGroupName
) + 1),
4032 strcpy(lpStr
, lpEmptyString
);
4035 lpServiceConfig
->lpLoadOrderGroup
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4036 lpStr
+= (strlen(lpStr
) + 1);
4038 /* Append Dependencies */
4041 WideCharToMultiByte(CP_ACP
,
4044 dwDependenciesLength
,
4046 dwDependenciesLength
,
4052 strcpy(lpStr
, lpEmptyString
);
4055 lpServiceConfig
->lpDependencies
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4057 lpStr
+= dwDependenciesLength
;
4059 lpStr
+= (strlen(lpStr
) + 1);
4061 if (lpServiceStartName
)
4063 WideCharToMultiByte(CP_ACP
,
4068 (int)(wcslen(lpServiceStartName
) + 1),
4074 strcpy(lpStr
, lpEmptyString
);
4077 lpServiceConfig
->lpServiceStartName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4078 lpStr
+= (strlen(lpStr
) + 1);
4080 if (lpService
->lpDisplayName
)
4082 WideCharToMultiByte(CP_ACP
,
4084 lpService
->lpDisplayName
,
4087 (int)(wcslen(lpService
->lpDisplayName
) + 1),
4093 strcpy(lpStr
, lpEmptyString
);
4096 lpServiceConfig
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceConfig
);
4099 if (pcbBytesNeeded
!= NULL
)
4100 *pcbBytesNeeded
= dwRequiredSize
;
4103 /* Unlock the service database */
4104 ScmUnlockDatabase();
4106 if (lpImagePath
!= NULL
)
4107 HeapFree(GetProcessHeap(), 0, lpImagePath
);
4109 if (lpServiceStartName
!= NULL
)
4110 HeapFree(GetProcessHeap(), 0, lpServiceStartName
);
4112 if (lpDependencies
!= NULL
)
4113 HeapFree(GetProcessHeap(), 0, lpDependencies
);
4115 if (hServiceKey
!= NULL
)
4116 RegCloseKey(hServiceKey
);
4118 DPRINT("RQueryServiceConfigA() done\n");
4125 DWORD
RQueryServiceLockStatusA(
4126 SC_RPC_HANDLE hSCManager
,
4127 LPBYTE lpBuf
, // LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
4129 LPBOUNDED_DWORD_4K pcbBytesNeeded
)
4131 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
= (LPQUERY_SERVICE_LOCK_STATUSA
)lpBuf
;
4132 PMANAGER_HANDLE hMgr
;
4133 DWORD dwRequiredSize
;
4135 if (!lpLockStatus
|| !pcbBytesNeeded
)
4136 return ERROR_INVALID_PARAMETER
;
4138 hMgr
= ScmGetServiceManagerFromHandle(hSCManager
);
4141 DPRINT1("Invalid service manager handle!\n");
4142 return ERROR_INVALID_HANDLE
;
4145 if (!RtlAreAllAccessesGranted(hMgr
->Handle
.DesiredAccess
,
4146 SC_MANAGER_QUERY_LOCK_STATUS
))
4148 DPRINT("Insufficient access rights! 0x%lx\n", hMgr
->Handle
.DesiredAccess
);
4149 return ERROR_ACCESS_DENIED
;
4152 /* FIXME: we need to compute instead the real length of the owner name */
4153 dwRequiredSize
= sizeof(QUERY_SERVICE_LOCK_STATUSA
) + sizeof(CHAR
);
4154 *pcbBytesNeeded
= dwRequiredSize
;
4156 if (cbBufSize
< dwRequiredSize
)
4157 return ERROR_INSUFFICIENT_BUFFER
;
4159 ScmQueryServiceLockStatusA(lpLockStatus
);
4161 return ERROR_SUCCESS
;
4166 DWORD
RStartServiceA(
4167 SC_RPC_HANDLE hService
,
4169 LPSTRING_PTRSA argv
)
4171 DWORD dwError
= ERROR_SUCCESS
;
4172 PSERVICE_HANDLE hSvc
;
4173 PSERVICE lpService
= NULL
;
4174 SC_RPC_LOCK Lock
= NULL
;
4175 LPWSTR
*lpVector
= NULL
;
4179 DPRINT("RStartServiceA() called\n");
4182 return ERROR_SHUTDOWN_IN_PROGRESS
;
4184 hSvc
= ScmGetServiceFromHandle(hService
);
4187 DPRINT1("Invalid service handle!\n");
4188 return ERROR_INVALID_HANDLE
;
4191 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
4194 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
4195 return ERROR_ACCESS_DENIED
;
4198 lpService
= hSvc
->ServiceEntry
;
4199 if (lpService
== NULL
)
4201 DPRINT("lpService == NULL!\n");
4202 return ERROR_INVALID_HANDLE
;
4205 if (lpService
->dwStartType
== SERVICE_DISABLED
)
4206 return ERROR_SERVICE_DISABLED
;
4208 if (lpService
->bDeleted
)
4209 return ERROR_SERVICE_MARKED_FOR_DELETE
;
4211 /* Build a Unicode argument vector */
4214 lpVector
= HeapAlloc(GetProcessHeap(),
4216 argc
* sizeof(LPWSTR
));
4217 if (lpVector
== NULL
)
4218 return ERROR_NOT_ENOUGH_MEMORY
;
4220 for (i
= 0; i
< argc
; i
++)
4222 dwLength
= MultiByteToWideChar(CP_ACP
,
4229 lpVector
[i
] = HeapAlloc(GetProcessHeap(),
4231 dwLength
* sizeof(WCHAR
));
4232 if (lpVector
[i
] == NULL
)
4234 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
4238 MultiByteToWideChar(CP_ACP
,
4247 /* Acquire the service start lock until the service has been started */
4248 dwError
= ScmAcquireServiceStartLock(TRUE
, &Lock
);
4249 if (dwError
!= ERROR_SUCCESS
)
4252 /* Start the service */
4253 dwError
= ScmStartService(lpService
, argc
, lpVector
);
4255 /* Release the service start lock */
4256 ScmReleaseServiceStartLock(&Lock
);
4259 /* Free the Unicode argument vector */
4260 if (lpVector
!= NULL
)
4262 for (i
= 0; i
< argc
; i
++)
4264 if (lpVector
[i
] != NULL
)
4265 HeapFree(GetProcessHeap(), 0, lpVector
[i
]);
4267 HeapFree(GetProcessHeap(), 0, lpVector
);
4275 DWORD
RGetServiceDisplayNameA(
4276 SC_RPC_HANDLE hSCManager
,
4277 LPCSTR lpServiceName
,
4278 LPSTR lpDisplayName
,
4279 LPBOUNDED_DWORD_4K lpcchBuffer
)
4281 // PMANAGER_HANDLE hManager;
4282 PSERVICE lpService
= NULL
;
4285 LPWSTR lpServiceNameW
;
4287 DPRINT("RGetServiceDisplayNameA() called\n");
4288 DPRINT("hSCManager = %p\n", hSCManager
);
4289 DPRINT("lpServiceName: %s\n", lpServiceName
);
4290 DPRINT("lpDisplayName: %p\n", lpDisplayName
);
4291 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
4293 // hManager = (PMANAGER_HANDLE)hSCManager;
4294 // if (hManager->Handle.Tag != MANAGER_TAG)
4296 // DPRINT("Invalid manager handle!\n");
4297 // return ERROR_INVALID_HANDLE;
4300 if (lpServiceName
!= NULL
)
4302 dwLength
= (DWORD
)(strlen(lpServiceName
) + 1);
4303 lpServiceNameW
= HeapAlloc(GetProcessHeap(),
4305 dwLength
* sizeof(WCHAR
));
4306 if (!lpServiceNameW
)
4307 return ERROR_NOT_ENOUGH_MEMORY
;
4309 MultiByteToWideChar(CP_ACP
,
4316 lpService
= ScmGetServiceEntryByName(lpServiceNameW
);
4318 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
4321 if (lpService
== NULL
)
4323 DPRINT("Could not find a service!\n");
4325 /* If the service could not be found and lpcchBuffer is 0, windows
4326 puts null in lpDisplayName and puts 1 in lpcchBuffer */
4327 if (*lpcchBuffer
== 0)
4330 if (lpDisplayName
!= NULL
)
4335 return ERROR_SERVICE_DOES_NOT_EXIST
;
4338 if (!lpService
->lpDisplayName
)
4340 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
4341 if (lpDisplayName
!= NULL
&&
4342 *lpcchBuffer
> dwLength
)
4344 WideCharToMultiByte(CP_ACP
,
4346 lpService
->lpServiceName
,
4347 (int)wcslen(lpService
->lpServiceName
),
4352 return ERROR_SUCCESS
;
4357 dwLength
= (DWORD
)wcslen(lpService
->lpDisplayName
);
4358 if (lpDisplayName
!= NULL
&&
4359 *lpcchBuffer
> dwLength
)
4361 WideCharToMultiByte(CP_ACP
,
4363 lpService
->lpDisplayName
,
4364 (int)wcslen(lpService
->lpDisplayName
),
4369 return ERROR_SUCCESS
;
4373 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
4375 *lpcchBuffer
= dwLength
* 2;
4382 DWORD
RGetServiceKeyNameA(
4383 SC_RPC_HANDLE hSCManager
,
4384 LPCSTR lpDisplayName
,
4385 LPSTR lpServiceName
,
4386 LPBOUNDED_DWORD_4K lpcchBuffer
)
4391 LPWSTR lpDisplayNameW
;
4393 DPRINT("RGetServiceKeyNameA() called\n");
4394 DPRINT("hSCManager = %p\n", hSCManager
);
4395 DPRINT("lpDisplayName: %s\n", lpDisplayName
);
4396 DPRINT("lpServiceName: %p\n", lpServiceName
);
4397 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
4399 dwLength
= (DWORD
)(strlen(lpDisplayName
) + 1);
4400 lpDisplayNameW
= HeapAlloc(GetProcessHeap(),
4402 dwLength
* sizeof(WCHAR
));
4403 if (!lpDisplayNameW
)
4404 return ERROR_NOT_ENOUGH_MEMORY
;
4406 MultiByteToWideChar(CP_ACP
,
4413 lpService
= ScmGetServiceEntryByDisplayName(lpDisplayNameW
);
4415 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
4417 if (lpService
== NULL
)
4419 DPRINT("Could not find the service!\n");
4421 /* If the service could not be found and lpcchBuffer is 0,
4422 put null in lpDisplayName and puts 1 in lpcchBuffer, verified WINXP. */
4423 if (*lpcchBuffer
== 0)
4426 if (lpServiceName
!= NULL
)
4432 return ERROR_SERVICE_DOES_NOT_EXIST
;
4435 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
4436 if (lpServiceName
!= NULL
&&
4437 *lpcchBuffer
> dwLength
)
4439 WideCharToMultiByte(CP_ACP
,
4441 lpService
->lpServiceName
,
4442 (int)wcslen(lpService
->lpServiceName
),
4447 return ERROR_SUCCESS
;
4450 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
4452 *lpcchBuffer
= dwLength
* 2;
4459 DWORD
RI_ScGetCurrentGroupStateW(
4460 SC_RPC_HANDLE hSCManager
,
4461 LPWSTR lpLoadOrderGroup
,
4465 return ERROR_CALL_NOT_IMPLEMENTED
;
4470 DWORD
REnumServiceGroupW(
4471 SC_RPC_HANDLE hSCManager
,
4472 DWORD dwServiceType
,
4473 DWORD dwServiceState
,
4476 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
4477 LPBOUNDED_DWORD_256K lpServicesReturned
,
4478 LPBOUNDED_DWORD_256K lpResumeIndex
,
4479 LPCWSTR pszGroupName
)
4481 PMANAGER_HANDLE hManager
;
4483 DWORD dwError
= ERROR_SUCCESS
;
4484 PLIST_ENTRY ServiceEntry
;
4485 PSERVICE CurrentService
;
4487 DWORD dwRequiredSize
;
4488 DWORD dwServiceCount
;
4490 DWORD dwLastResumeCount
= 0;
4491 LPENUM_SERVICE_STATUSW lpStatusPtr
;
4494 DPRINT("REnumServiceGroupW() called\n");
4497 return ERROR_SHUTDOWN_IN_PROGRESS
;
4499 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
4500 if (hManager
== NULL
)
4502 DPRINT1("Invalid service manager handle!\n");
4503 return ERROR_INVALID_HANDLE
;
4506 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
4508 return ERROR_INVALID_ADDRESS
;
4511 *pcbBytesNeeded
= 0;
4512 *lpServicesReturned
= 0;
4514 if ((dwServiceType
== 0) ||
4515 ((dwServiceType
& ~SERVICE_TYPE_ALL
) != 0))
4517 DPRINT("Not a valid Service Type!\n");
4518 return ERROR_INVALID_PARAMETER
;
4521 if ((dwServiceState
== 0) ||
4522 ((dwServiceState
& ~SERVICE_STATE_ALL
) != 0))
4524 DPRINT("Not a valid Service State!\n");
4525 return ERROR_INVALID_PARAMETER
;
4528 /* Check access rights */
4529 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
4530 SC_MANAGER_ENUMERATE_SERVICE
))
4532 DPRINT("Insufficient access rights! 0x%lx\n",
4533 hManager
->Handle
.DesiredAccess
);
4534 return ERROR_ACCESS_DENIED
;
4538 dwLastResumeCount
= *lpResumeIndex
;
4540 /* Lock the service database shared */
4541 ScmLockDatabaseShared();
4543 lpService
= ScmGetServiceEntryByResumeCount(dwLastResumeCount
);
4544 if (lpService
== NULL
)
4546 dwError
= ERROR_SUCCESS
;
4553 for (ServiceEntry
= &lpService
->ServiceListEntry
;
4554 ServiceEntry
!= &ServiceListHead
;
4555 ServiceEntry
= ServiceEntry
->Flink
)
4557 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
4561 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
4564 dwState
= SERVICE_ACTIVE
;
4565 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
4566 dwState
= SERVICE_INACTIVE
;
4568 if ((dwState
& dwServiceState
) == 0)
4573 if (*pszGroupName
== 0)
4575 if (CurrentService
->lpGroup
!= NULL
)
4580 if ((CurrentService
->lpGroup
== NULL
) ||
4581 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
4586 dwSize
= sizeof(ENUM_SERVICE_STATUSW
) +
4587 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
4588 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
4590 if (dwRequiredSize
+ dwSize
> cbBufSize
)
4592 DPRINT("Service name: %S no fit\n", CurrentService
->lpServiceName
);
4596 DPRINT("Service name: %S fit\n", CurrentService
->lpServiceName
);
4597 dwRequiredSize
+= dwSize
;
4599 dwLastResumeCount
= CurrentService
->dwResumeCount
;
4602 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize
);
4603 DPRINT("dwServiceCount: %lu\n", dwServiceCount
);
4606 ServiceEntry
!= &ServiceListHead
;
4607 ServiceEntry
= ServiceEntry
->Flink
)
4609 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
4613 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
4616 dwState
= SERVICE_ACTIVE
;
4617 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
4618 dwState
= SERVICE_INACTIVE
;
4620 if ((dwState
& dwServiceState
) == 0)
4625 if (*pszGroupName
== 0)
4627 if (CurrentService
->lpGroup
!= NULL
)
4632 if ((CurrentService
->lpGroup
== NULL
) ||
4633 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
4638 dwRequiredSize
+= (sizeof(ENUM_SERVICE_STATUSW
) +
4639 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
4640 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
)));
4642 dwError
= ERROR_MORE_DATA
;
4645 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize
);
4648 *lpResumeIndex
= dwLastResumeCount
;
4650 *lpServicesReturned
= dwServiceCount
;
4651 *pcbBytesNeeded
= dwRequiredSize
;
4653 lpStatusPtr
= (LPENUM_SERVICE_STATUSW
)lpBuffer
;
4654 lpStringPtr
= (LPWSTR
)((ULONG_PTR
)lpBuffer
+
4655 dwServiceCount
* sizeof(ENUM_SERVICE_STATUSW
));
4658 for (ServiceEntry
= &lpService
->ServiceListEntry
;
4659 ServiceEntry
!= &ServiceListHead
;
4660 ServiceEntry
= ServiceEntry
->Flink
)
4662 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
4666 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
4669 dwState
= SERVICE_ACTIVE
;
4670 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
4671 dwState
= SERVICE_INACTIVE
;
4673 if ((dwState
& dwServiceState
) == 0)
4678 if (*pszGroupName
== 0)
4680 if (CurrentService
->lpGroup
!= NULL
)
4685 if ((CurrentService
->lpGroup
== NULL
) ||
4686 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
4691 dwSize
= sizeof(ENUM_SERVICE_STATUSW
) +
4692 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
4693 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
4695 if (dwRequiredSize
+ dwSize
> cbBufSize
)
4698 /* Copy the service name */
4699 wcscpy(lpStringPtr
, CurrentService
->lpServiceName
);
4700 lpStatusPtr
->lpServiceName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
4701 lpStringPtr
+= (wcslen(CurrentService
->lpServiceName
) + 1);
4703 /* Copy the display name */
4704 wcscpy(lpStringPtr
, CurrentService
->lpDisplayName
);
4705 lpStatusPtr
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
4706 lpStringPtr
+= (wcslen(CurrentService
->lpDisplayName
) + 1);
4708 /* Copy the status information */
4709 memcpy(&lpStatusPtr
->ServiceStatus
,
4710 &CurrentService
->Status
,
4711 sizeof(SERVICE_STATUS
));
4714 dwRequiredSize
+= dwSize
;
4717 if (dwError
== ERROR_SUCCESS
)
4719 *pcbBytesNeeded
= 0;
4720 if (lpResumeIndex
) *lpResumeIndex
= 0;
4724 /* Unlock the service database */
4725 ScmUnlockDatabase();
4727 DPRINT("REnumServiceGroupW() done (Error %lu)\n", dwError
);
4734 // WARNING: This function is untested
4737 DWORD
RChangeServiceConfig2A(
4738 SC_RPC_HANDLE hService
,
4739 SC_RPC_CONFIG_INFOA Info
)
4741 SC_RPC_CONFIG_INFOW InfoW
;
4742 DWORD dwRet
, dwLength
;
4745 DPRINT("RChangeServiceConfig2A() called\n");
4746 DPRINT("dwInfoLevel = %lu\n", Info
.dwInfoLevel
);
4748 InfoW
.dwInfoLevel
= Info
.dwInfoLevel
;
4750 if (InfoW
.dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
4752 LPSERVICE_DESCRIPTIONW lpServiceDescriptonW
;
4753 //LPSERVICE_DESCRIPTIONA lpServiceDescriptonA;
4755 //lpServiceDescriptonA = Info.psd;
4757 ///if (lpServiceDescriptonA &&
4758 ///lpServiceDescriptonA->lpDescription)
4760 dwLength
= (DWORD
)((strlen(Info
.lpDescription
) + 1) * sizeof(WCHAR
));
4762 lpServiceDescriptonW
= HeapAlloc(GetProcessHeap(),
4764 dwLength
+ sizeof(SERVICE_DESCRIPTIONW
));
4765 if (!lpServiceDescriptonW
)
4767 return ERROR_NOT_ENOUGH_MEMORY
;
4770 lpServiceDescriptonW
->lpDescription
= (LPWSTR
)(lpServiceDescriptonW
+ 1);
4772 MultiByteToWideChar(CP_ACP
,
4776 lpServiceDescriptonW
->lpDescription
,
4779 ptr
= lpServiceDescriptonW
;
4780 InfoW
.psd
= lpServiceDescriptonW
;
4783 else if (Info
.dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
4785 LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW
;
4786 LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA
;
4787 DWORD dwRebootLen
= 0;
4788 DWORD dwCommandLen
= 0;
4790 lpServiceFailureActionsA
= Info
.psfa
;
4792 if (lpServiceFailureActionsA
)
4794 if (lpServiceFailureActionsA
->lpRebootMsg
)
4796 dwRebootLen
= (DWORD
)((strlen(lpServiceFailureActionsA
->lpRebootMsg
) + 1) * sizeof(WCHAR
));
4798 if (lpServiceFailureActionsA
->lpCommand
)
4800 dwCommandLen
= (DWORD
)((strlen(lpServiceFailureActionsA
->lpCommand
) + 1) * sizeof(WCHAR
));
4802 dwLength
= dwRebootLen
+ dwCommandLen
+ sizeof(SERVICE_FAILURE_ACTIONSW
);
4804 lpServiceFailureActionsW
= HeapAlloc(GetProcessHeap(),
4807 if (!lpServiceFailureActionsW
)
4809 return ERROR_NOT_ENOUGH_MEMORY
;
4812 lpServiceFailureActionsW
->cActions
= lpServiceFailureActionsA
->cActions
;
4813 lpServiceFailureActionsW
->dwResetPeriod
= lpServiceFailureActionsA
->dwResetPeriod
;
4814 CopyMemory(lpServiceFailureActionsW
->lpsaActions
, lpServiceFailureActionsA
->lpsaActions
, sizeof(SC_ACTION
));
4816 if (lpServiceFailureActionsA
->lpRebootMsg
)
4818 MultiByteToWideChar(CP_ACP
,
4820 lpServiceFailureActionsA
->lpRebootMsg
,
4822 lpServiceFailureActionsW
->lpRebootMsg
,
4826 if (lpServiceFailureActionsA
->lpCommand
)
4828 MultiByteToWideChar(CP_ACP
,
4830 lpServiceFailureActionsA
->lpCommand
,
4832 lpServiceFailureActionsW
->lpCommand
,
4836 ptr
= lpServiceFailureActionsW
;
4840 dwRet
= RChangeServiceConfig2W(hService
, InfoW
);
4842 HeapFree(GetProcessHeap(), 0, ptr
);
4849 ScmSetFailureActions(PSERVICE_HANDLE hSvc
,
4852 LPSERVICE_FAILURE_ACTIONSW lpFailureActions
)
4854 LPSERVICE_FAILURE_ACTIONSW lpReadBuffer
= NULL
;
4855 LPSERVICE_FAILURE_ACTIONSW lpWriteBuffer
= NULL
;
4856 BOOL bIsActionRebootSet
= FALSE
;
4857 DWORD dwDesiredAccess
= SERVICE_CHANGE_CONFIG
;
4858 DWORD dwRequiredSize
= 0;
4863 /* There is nothing to be done if we have no failure actions */
4864 if (lpFailureActions
== NULL
)
4865 return ERROR_SUCCESS
;
4868 * 1- Check whether or not we can set
4869 * failure actions for this service.
4872 /* Failure actions can only be set for Win32 services, not for drivers */
4873 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
4874 return ERROR_CANNOT_DETECT_DRIVER_FAILURE
;
4877 * If the service controller handles the SC_ACTION_RESTART action,
4878 * hService must have the SERVICE_START access right.
4880 * If you specify SC_ACTION_REBOOT, the caller must have the
4881 * SE_SHUTDOWN_NAME privilege.
4883 if (lpFailureActions
->cActions
> 0 &&
4884 lpFailureActions
->lpsaActions
!= NULL
)
4886 for (i
= 0; i
< lpFailureActions
->cActions
; ++i
)
4888 if (lpFailureActions
->lpsaActions
[i
].Type
== SC_ACTION_RESTART
)
4889 dwDesiredAccess
|= SERVICE_START
;
4890 else if (lpFailureActions
->lpsaActions
[i
].Type
== SC_ACTION_REBOOT
)
4891 bIsActionRebootSet
= TRUE
;
4895 /* Re-check the access rights */
4896 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
4899 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
4900 return ERROR_ACCESS_DENIED
;
4903 /* FIXME: Check if the caller has the SE_SHUTDOWN_NAME privilege */
4904 if (bIsActionRebootSet
)
4909 * 2- Retrieve the original value of FailureActions.
4912 /* Query value length */
4913 dwError
= RegQueryValueExW(hServiceKey
,
4919 if (dwError
!= ERROR_SUCCESS
&&
4920 dwError
!= ERROR_MORE_DATA
&&
4921 dwError
!= ERROR_FILE_NOT_FOUND
)
4924 dwRequiredSize
= (dwType
== REG_BINARY
) ? max(sizeof(SERVICE_FAILURE_ACTIONSW
), dwRequiredSize
)
4925 : sizeof(SERVICE_FAILURE_ACTIONSW
);
4927 /* Initialize the read buffer */
4928 lpReadBuffer
= HeapAlloc(GetProcessHeap(),
4931 if (lpReadBuffer
== NULL
)
4932 return ERROR_NOT_ENOUGH_MEMORY
;
4934 /* Now we can fill the read buffer */
4935 if (dwError
!= ERROR_FILE_NOT_FOUND
&&
4936 dwType
== REG_BINARY
)
4938 dwError
= RegQueryValueExW(hServiceKey
,
4942 (LPBYTE
)lpReadBuffer
,
4944 if (dwError
!= ERROR_SUCCESS
&&
4945 dwError
!= ERROR_FILE_NOT_FOUND
)
4948 if (dwRequiredSize
< sizeof(SERVICE_FAILURE_ACTIONSW
))
4949 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSW
);
4954 * The value of the error doesn't really matter, the only
4955 * important thing is that it must be != ERROR_SUCCESS.
4957 dwError
= ERROR_INVALID_DATA
;
4960 if (dwError
== ERROR_SUCCESS
)
4962 lpReadBuffer
->cActions
= min(lpReadBuffer
->cActions
, (dwRequiredSize
- sizeof(SERVICE_FAILURE_ACTIONSW
)) / sizeof(SC_ACTION
));
4963 lpReadBuffer
->lpsaActions
= (lpReadBuffer
->cActions
> 0 ? (LPSC_ACTION
)(lpReadBuffer
+ 1) : NULL
);
4967 lpReadBuffer
->dwResetPeriod
= 0;
4968 lpReadBuffer
->cActions
= 0;
4969 lpReadBuffer
->lpsaActions
= NULL
;
4972 lpReadBuffer
->lpRebootMsg
= NULL
;
4973 lpReadBuffer
->lpCommand
= NULL
;
4976 * 3- Initialize the new value to set.
4979 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSW
);
4981 if (lpFailureActions
->lpsaActions
== NULL
)
4984 * lpFailureActions->cActions is ignored.
4985 * Therefore we use the original values
4986 * of cActions and lpsaActions.
4988 dwRequiredSize
+= lpReadBuffer
->cActions
* sizeof(SC_ACTION
);
4993 * The reset period and array of failure actions
4994 * are deleted if lpFailureActions->cActions == 0 .
4996 dwRequiredSize
+= lpFailureActions
->cActions
* sizeof(SC_ACTION
);
4999 lpWriteBuffer
= HeapAlloc(GetProcessHeap(),
5002 if (lpWriteBuffer
== NULL
)
5004 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
5008 /* Clean the pointers as they have no meaning when the structure is stored in the registry */
5009 lpWriteBuffer
->lpRebootMsg
= NULL
;
5010 lpWriteBuffer
->lpCommand
= NULL
;
5011 lpWriteBuffer
->lpsaActions
= NULL
;
5013 /* Set the members */
5014 if (lpFailureActions
->lpsaActions
== NULL
)
5017 * lpFailureActions->dwResetPeriod and lpFailureActions->cActions are ignored.
5018 * Therefore we use the original values of dwResetPeriod, cActions and lpsaActions.
5020 lpWriteBuffer
->dwResetPeriod
= lpReadBuffer
->dwResetPeriod
;
5021 lpWriteBuffer
->cActions
= lpReadBuffer
->cActions
;
5023 if (lpReadBuffer
->lpsaActions
!= NULL
)
5025 memmove(lpWriteBuffer
+ 1,
5026 lpReadBuffer
->lpsaActions
,
5027 lpReadBuffer
->cActions
* sizeof(SC_ACTION
));
5032 if (lpFailureActions
->cActions
> 0)
5034 lpWriteBuffer
->dwResetPeriod
= lpFailureActions
->dwResetPeriod
;
5035 lpWriteBuffer
->cActions
= lpFailureActions
->cActions
;
5037 memmove(lpWriteBuffer
+ 1,
5038 lpFailureActions
->lpsaActions
,
5039 lpFailureActions
->cActions
* sizeof(SC_ACTION
));
5043 /* The reset period and array of failure actions are deleted */
5044 lpWriteBuffer
->dwResetPeriod
= 0;
5045 lpWriteBuffer
->cActions
= 0;
5049 /* Save the new failure actions into the registry */
5050 dwError
= RegSetValueExW(hServiceKey
,
5054 (LPBYTE
)lpWriteBuffer
,
5057 /* We modify the strings only in case of success.*/
5058 if (dwError
== ERROR_SUCCESS
)
5060 /* Modify the Reboot Message value, if specified */
5061 if (lpFailureActions
->lpRebootMsg
!= NULL
)
5063 /* If the Reboot Message is "" then we delete it */
5064 if (*lpFailureActions
->lpRebootMsg
== 0)
5066 DPRINT("Delete Reboot Message value\n");
5067 RegDeleteValueW(hServiceKey
, L
"RebootMessage");
5071 DPRINT("Setting Reboot Message value %S\n", lpFailureActions
->lpRebootMsg
);
5072 RegSetValueExW(hServiceKey
,
5076 (LPBYTE
)lpFailureActions
->lpRebootMsg
,
5077 (DWORD
)((wcslen(lpFailureActions
->lpRebootMsg
) + 1) * sizeof(WCHAR
)));
5081 /* Modify the Failure Command value, if specified */
5082 if (lpFailureActions
->lpCommand
!= NULL
)
5084 /* If the FailureCommand string is an empty string, delete the value */
5085 if (*lpFailureActions
->lpCommand
== 0)
5087 DPRINT("Delete Failure Command value\n");
5088 RegDeleteValueW(hServiceKey
, L
"FailureCommand");
5092 DPRINT("Setting Failure Command value %S\n", lpFailureActions
->lpCommand
);
5093 RegSetValueExW(hServiceKey
,
5097 (LPBYTE
)lpFailureActions
->lpCommand
,
5098 (DWORD
)((wcslen(lpFailureActions
->lpCommand
) + 1) * sizeof(WCHAR
)));
5104 if (lpWriteBuffer
!= NULL
)
5105 HeapFree(GetProcessHeap(), 0, lpWriteBuffer
);
5107 if (lpReadBuffer
!= NULL
)
5108 HeapFree(GetProcessHeap(), 0, lpReadBuffer
);
5115 DWORD
RChangeServiceConfig2W(
5116 SC_RPC_HANDLE hService
,
5117 SC_RPC_CONFIG_INFOW Info
)
5119 DWORD dwError
= ERROR_SUCCESS
;
5120 PSERVICE_HANDLE hSvc
;
5121 PSERVICE lpService
= NULL
;
5122 HKEY hServiceKey
= NULL
;
5124 DPRINT("RChangeServiceConfig2W() called\n");
5125 DPRINT("dwInfoLevel = %lu\n", Info
.dwInfoLevel
);
5128 return ERROR_SHUTDOWN_IN_PROGRESS
;
5130 hSvc
= ScmGetServiceFromHandle(hService
);
5133 DPRINT1("Invalid service handle!\n");
5134 return ERROR_INVALID_HANDLE
;
5137 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5138 SERVICE_CHANGE_CONFIG
))
5140 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5141 return ERROR_ACCESS_DENIED
;
5144 lpService
= hSvc
->ServiceEntry
;
5145 if (lpService
== NULL
)
5147 DPRINT("lpService == NULL!\n");
5148 return ERROR_INVALID_HANDLE
;
5151 /* Lock the service database exclusively */
5152 ScmLockDatabaseExclusive();
5154 if (lpService
->bDeleted
)
5156 DPRINT("The service has already been marked for delete!\n");
5157 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
5161 /* Open the service key */
5162 dwError
= ScmOpenServiceKey(lpService
->szServiceName
,
5163 KEY_READ
| KEY_SET_VALUE
,
5165 if (dwError
!= ERROR_SUCCESS
)
5168 if (Info
.dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
5170 LPSERVICE_DESCRIPTIONW lpServiceDescription
= (LPSERVICE_DESCRIPTIONW
)Info
.psd
;
5172 /* Modify the service description, if specified */
5173 if (lpServiceDescription
!= NULL
&&
5174 lpServiceDescription
->lpDescription
!= NULL
)
5176 /* If the description is "" then we delete it */
5177 if (*lpServiceDescription
->lpDescription
== 0)
5179 DPRINT("Delete service description\n");
5180 dwError
= RegDeleteValueW(hServiceKey
, L
"Description");
5182 if (dwError
== ERROR_FILE_NOT_FOUND
)
5183 dwError
= ERROR_SUCCESS
;
5187 DPRINT("Setting service description value %S\n", lpServiceDescription
->lpDescription
);
5188 dwError
= RegSetValueExW(hServiceKey
,
5192 (LPBYTE
)lpServiceDescription
->lpDescription
,
5193 (DWORD
)((wcslen(lpServiceDescription
->lpDescription
) + 1) * sizeof(WCHAR
)));
5198 dwError
= ERROR_SUCCESS
;
5201 else if (Info
.dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5203 dwError
= ScmSetFailureActions(hSvc
,
5206 (LPSERVICE_FAILURE_ACTIONSW
)Info
.psfa
);
5210 if (hServiceKey
!= NULL
)
5211 RegCloseKey(hServiceKey
);
5213 /* Unlock the service database */
5214 ScmUnlockDatabase();
5216 DPRINT("RChangeServiceConfig2W() done (Error %lu)\n", dwError
);
5223 DWORD
RQueryServiceConfig2A(
5224 SC_RPC_HANDLE hService
,
5228 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
5230 DWORD dwError
= ERROR_SUCCESS
;
5231 PSERVICE_HANDLE hSvc
;
5232 PSERVICE lpService
= NULL
;
5233 HKEY hServiceKey
= NULL
;
5234 DWORD dwRequiredSize
= 0;
5236 LPWSTR lpDescriptionW
= NULL
;
5237 LPWSTR lpRebootMessageW
= NULL
;
5238 LPWSTR lpFailureCommandW
= NULL
;
5240 DPRINT("RQueryServiceConfig2A() called hService %p dwInfoLevel %u, lpBuffer %p cbBufSize %u pcbBytesNeeded %p\n",
5241 hService
, dwInfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
5244 return ERROR_INVALID_ADDRESS
;
5247 return ERROR_SHUTDOWN_IN_PROGRESS
;
5249 hSvc
= ScmGetServiceFromHandle(hService
);
5252 DPRINT1("Invalid service handle!\n");
5253 return ERROR_INVALID_HANDLE
;
5256 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5257 SERVICE_QUERY_CONFIG
))
5259 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5260 return ERROR_ACCESS_DENIED
;
5263 lpService
= hSvc
->ServiceEntry
;
5264 if (lpService
== NULL
)
5266 DPRINT("lpService == NULL!\n");
5267 return ERROR_INVALID_HANDLE
;
5270 /* Lock the service database shared */
5271 ScmLockDatabaseShared();
5273 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
5276 if (dwError
!= ERROR_SUCCESS
)
5279 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
5281 LPSERVICE_DESCRIPTIONA lpServiceDescription
= (LPSERVICE_DESCRIPTIONA
)lpBuffer
;
5284 dwError
= ScmReadString(hServiceKey
,
5287 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5290 *pcbBytesNeeded
= sizeof(SERVICE_DESCRIPTIONA
);
5291 if (dwError
== ERROR_SUCCESS
)
5292 *pcbBytesNeeded
+= (DWORD
)((wcslen(lpDescriptionW
) + 1) * sizeof(WCHAR
));
5294 if (cbBufSize
< *pcbBytesNeeded
)
5296 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5300 if (dwError
== ERROR_SUCCESS
)
5302 lpStr
= (LPSTR
)(lpServiceDescription
+ 1);
5304 WideCharToMultiByte(CP_ACP
,
5309 (int)wcslen(lpDescriptionW
),
5312 lpServiceDescription
->lpDescription
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceDescription
);
5316 lpServiceDescription
->lpDescription
= NULL
;
5317 dwError
= ERROR_SUCCESS
;
5320 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5322 LPSERVICE_FAILURE_ACTIONSA lpFailureActions
= (LPSERVICE_FAILURE_ACTIONSA
)lpBuffer
;
5325 /* Query value length */
5326 dwError
= RegQueryValueExW(hServiceKey
,
5332 if (dwError
!= ERROR_SUCCESS
&&
5333 dwError
!= ERROR_MORE_DATA
&&
5334 dwError
!= ERROR_FILE_NOT_FOUND
)
5337 dwRequiredSize
= (dwType
== REG_BINARY
) ? max(sizeof(SERVICE_FAILURE_ACTIONSA
), dwRequiredSize
)
5338 : sizeof(SERVICE_FAILURE_ACTIONSA
);
5340 /* Get the strings */
5341 ScmReadString(hServiceKey
,
5343 &lpFailureCommandW
);
5345 ScmReadString(hServiceKey
,
5349 if (lpRebootMessageW
)
5350 dwRequiredSize
+= (DWORD
)((wcslen(lpRebootMessageW
) + 1) * sizeof(WCHAR
));
5352 if (lpFailureCommandW
)
5353 dwRequiredSize
+= (DWORD
)((wcslen(lpFailureCommandW
) + 1) * sizeof(WCHAR
));
5355 if (cbBufSize
< dwRequiredSize
)
5357 *pcbBytesNeeded
= dwRequiredSize
;
5358 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5362 /* Now we can fill the buffer */
5363 if (dwError
!= ERROR_FILE_NOT_FOUND
&& dwType
== REG_BINARY
)
5365 dwError
= RegQueryValueExW(hServiceKey
,
5369 (LPBYTE
)lpFailureActions
,
5371 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5374 if (dwRequiredSize
< sizeof(SERVICE_FAILURE_ACTIONSA
))
5375 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSA
);
5380 * The value of the error doesn't really matter, the only
5381 * important thing is that it must be != ERROR_SUCCESS .
5383 dwError
= ERROR_INVALID_DATA
;
5386 if (dwError
== ERROR_SUCCESS
)
5388 lpFailureActions
->cActions
= min(lpFailureActions
->cActions
, (dwRequiredSize
- sizeof(SERVICE_FAILURE_ACTIONSA
)) / sizeof(SC_ACTION
));
5390 /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */
5391 lpFailureActions
->lpsaActions
= (lpFailureActions
->cActions
> 0 ? (LPSC_ACTION
)(ULONG_PTR
)sizeof(SERVICE_FAILURE_ACTIONSA
) : NULL
);
5393 lpStr
= (LPSTR
)((ULONG_PTR
)(lpFailureActions
+ 1) + lpFailureActions
->cActions
* sizeof(SC_ACTION
));
5397 lpFailureActions
->dwResetPeriod
= 0;
5398 lpFailureActions
->cActions
= 0;
5399 lpFailureActions
->lpsaActions
= NULL
;
5400 lpStr
= (LPSTR
)(lpFailureActions
+ 1);
5403 lpFailureActions
->lpRebootMsg
= NULL
;
5404 lpFailureActions
->lpCommand
= NULL
;
5406 if (lpRebootMessageW
)
5408 WideCharToMultiByte(CP_ACP
,
5413 (int)wcslen(lpRebootMessageW
),
5416 lpFailureActions
->lpRebootMsg
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5417 lpStr
+= strlen(lpStr
) + 1;
5420 if (lpFailureCommandW
)
5422 WideCharToMultiByte(CP_ACP
,
5427 (int)wcslen(lpFailureCommandW
),
5430 lpFailureActions
->lpCommand
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5431 /* lpStr += strlen(lpStr) + 1; */
5434 dwError
= ERROR_SUCCESS
;
5438 /* Unlock the service database */
5439 ScmUnlockDatabase();
5441 if (lpDescriptionW
!= NULL
)
5442 HeapFree(GetProcessHeap(), 0, lpDescriptionW
);
5444 if (lpRebootMessageW
!= NULL
)
5445 HeapFree(GetProcessHeap(), 0, lpRebootMessageW
);
5447 if (lpFailureCommandW
!= NULL
)
5448 HeapFree(GetProcessHeap(), 0, lpFailureCommandW
);
5450 if (hServiceKey
!= NULL
)
5451 RegCloseKey(hServiceKey
);
5453 DPRINT("RQueryServiceConfig2A() done (Error %lu)\n", dwError
);
5460 DWORD
RQueryServiceConfig2W(
5461 SC_RPC_HANDLE hService
,
5465 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
5467 DWORD dwError
= ERROR_SUCCESS
;
5468 PSERVICE_HANDLE hSvc
;
5469 PSERVICE lpService
= NULL
;
5470 HKEY hServiceKey
= NULL
;
5471 DWORD dwRequiredSize
= 0;
5473 LPWSTR lpDescription
= NULL
;
5474 LPWSTR lpRebootMessage
= NULL
;
5475 LPWSTR lpFailureCommand
= NULL
;
5477 DPRINT("RQueryServiceConfig2W() called\n");
5480 return ERROR_INVALID_ADDRESS
;
5483 return ERROR_SHUTDOWN_IN_PROGRESS
;
5485 hSvc
= ScmGetServiceFromHandle(hService
);
5488 DPRINT1("Invalid service handle!\n");
5489 return ERROR_INVALID_HANDLE
;
5492 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5493 SERVICE_QUERY_CONFIG
))
5495 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5496 return ERROR_ACCESS_DENIED
;
5499 lpService
= hSvc
->ServiceEntry
;
5500 if (lpService
== NULL
)
5502 DPRINT("lpService == NULL!\n");
5503 return ERROR_INVALID_HANDLE
;
5506 /* Lock the service database shared */
5507 ScmLockDatabaseShared();
5509 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
5512 if (dwError
!= ERROR_SUCCESS
)
5515 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
5517 LPSERVICE_DESCRIPTIONW lpServiceDescription
= (LPSERVICE_DESCRIPTIONW
)lpBuffer
;
5520 dwError
= ScmReadString(hServiceKey
,
5523 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5526 *pcbBytesNeeded
= sizeof(SERVICE_DESCRIPTIONW
);
5527 if (dwError
== ERROR_SUCCESS
)
5528 *pcbBytesNeeded
+= (DWORD
)((wcslen(lpDescription
) + 1) * sizeof(WCHAR
));
5530 if (cbBufSize
< *pcbBytesNeeded
)
5532 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5536 if (dwError
== ERROR_SUCCESS
)
5538 lpStr
= (LPWSTR
)(lpServiceDescription
+ 1);
5539 wcscpy(lpStr
, lpDescription
);
5540 lpServiceDescription
->lpDescription
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceDescription
);
5544 lpServiceDescription
->lpDescription
= NULL
;
5545 dwError
= ERROR_SUCCESS
;
5548 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5550 LPSERVICE_FAILURE_ACTIONSW lpFailureActions
= (LPSERVICE_FAILURE_ACTIONSW
)lpBuffer
;
5551 LPWSTR lpStr
= NULL
;
5553 /* Query value length */
5554 dwError
= RegQueryValueExW(hServiceKey
,
5560 if (dwError
!= ERROR_SUCCESS
&&
5561 dwError
!= ERROR_MORE_DATA
&&
5562 dwError
!= ERROR_FILE_NOT_FOUND
)
5565 dwRequiredSize
= (dwType
== REG_BINARY
) ? max(sizeof(SERVICE_FAILURE_ACTIONSW
), dwRequiredSize
)
5566 : sizeof(SERVICE_FAILURE_ACTIONSW
);
5568 /* Get the strings */
5569 ScmReadString(hServiceKey
,
5573 ScmReadString(hServiceKey
,
5577 if (lpRebootMessage
)
5578 dwRequiredSize
+= (DWORD
)((wcslen(lpRebootMessage
) + 1) * sizeof(WCHAR
));
5580 if (lpFailureCommand
)
5581 dwRequiredSize
+= (DWORD
)((wcslen(lpFailureCommand
) + 1) * sizeof(WCHAR
));
5583 if (cbBufSize
< dwRequiredSize
)
5585 *pcbBytesNeeded
= dwRequiredSize
;
5586 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5590 /* Now we can fill the buffer */
5591 if (dwError
!= ERROR_FILE_NOT_FOUND
&& dwType
== REG_BINARY
)
5593 dwError
= RegQueryValueExW(hServiceKey
,
5597 (LPBYTE
)lpFailureActions
,
5599 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5602 if (dwRequiredSize
< sizeof(SERVICE_FAILURE_ACTIONSW
))
5603 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSW
);
5608 * The value of the error doesn't really matter, the only
5609 * important thing is that it must be != ERROR_SUCCESS .
5611 dwError
= ERROR_INVALID_DATA
;
5614 if (dwError
== ERROR_SUCCESS
)
5616 lpFailureActions
->cActions
= min(lpFailureActions
->cActions
, (dwRequiredSize
- sizeof(SERVICE_FAILURE_ACTIONSW
)) / sizeof(SC_ACTION
));
5618 /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */
5619 lpFailureActions
->lpsaActions
= (lpFailureActions
->cActions
> 0 ? (LPSC_ACTION
)(ULONG_PTR
)sizeof(SERVICE_FAILURE_ACTIONSW
) : NULL
);
5621 lpStr
= (LPWSTR
)((ULONG_PTR
)(lpFailureActions
+ 1) + lpFailureActions
->cActions
* sizeof(SC_ACTION
));
5625 lpFailureActions
->dwResetPeriod
= 0;
5626 lpFailureActions
->cActions
= 0;
5627 lpFailureActions
->lpsaActions
= NULL
;
5628 lpStr
= (LPWSTR
)(lpFailureActions
+ 1);
5631 lpFailureActions
->lpRebootMsg
= NULL
;
5632 lpFailureActions
->lpCommand
= NULL
;
5634 if (lpRebootMessage
)
5636 wcscpy(lpStr
, lpRebootMessage
);
5637 lpFailureActions
->lpRebootMsg
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5638 lpStr
+= wcslen(lpStr
) + 1;
5641 if (lpFailureCommand
)
5643 wcscpy(lpStr
, lpFailureCommand
);
5644 lpFailureActions
->lpCommand
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5645 /* lpStr += wcslen(lpStr) + 1; */
5648 dwError
= ERROR_SUCCESS
;
5652 /* Unlock the service database */
5653 ScmUnlockDatabase();
5655 if (lpDescription
!= NULL
)
5656 HeapFree(GetProcessHeap(), 0, lpDescription
);
5658 if (lpRebootMessage
!= NULL
)
5659 HeapFree(GetProcessHeap(), 0, lpRebootMessage
);
5661 if (lpFailureCommand
!= NULL
)
5662 HeapFree(GetProcessHeap(), 0, lpFailureCommand
);
5664 if (hServiceKey
!= NULL
)
5665 RegCloseKey(hServiceKey
);
5667 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError
);
5674 DWORD
RQueryServiceStatusEx(
5675 SC_RPC_HANDLE hService
,
5676 SC_STATUS_TYPE InfoLevel
,
5679 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
5681 LPSERVICE_STATUS_PROCESS lpStatus
;
5682 PSERVICE_HANDLE hSvc
;
5685 DPRINT("RQueryServiceStatusEx() called\n");
5688 return ERROR_SHUTDOWN_IN_PROGRESS
;
5690 if (InfoLevel
!= SC_STATUS_PROCESS_INFO
)
5691 return ERROR_INVALID_LEVEL
;
5693 *pcbBytesNeeded
= sizeof(SERVICE_STATUS_PROCESS
);
5695 if (cbBufSize
< sizeof(SERVICE_STATUS_PROCESS
))
5696 return ERROR_INSUFFICIENT_BUFFER
;
5698 hSvc
= ScmGetServiceFromHandle(hService
);
5701 DPRINT1("Invalid service handle!\n");
5702 return ERROR_INVALID_HANDLE
;
5705 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5706 SERVICE_QUERY_STATUS
))
5708 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5709 return ERROR_ACCESS_DENIED
;
5712 lpService
= hSvc
->ServiceEntry
;
5713 if (lpService
== NULL
)
5715 DPRINT("lpService == NULL!\n");
5716 return ERROR_INVALID_HANDLE
;
5719 /* Lock the service database shared */
5720 ScmLockDatabaseShared();
5722 lpStatus
= (LPSERVICE_STATUS_PROCESS
)lpBuffer
;
5724 /* Return service status information */
5725 RtlCopyMemory(lpStatus
,
5727 sizeof(SERVICE_STATUS
));
5729 lpStatus
->dwProcessId
= (lpService
->lpImage
!= NULL
) ? lpService
->lpImage
->dwProcessId
: 0; /* FIXME */
5730 lpStatus
->dwServiceFlags
= 0; /* FIXME */
5732 /* Unlock the service database */
5733 ScmUnlockDatabase();
5735 return ERROR_SUCCESS
;
5740 DWORD
REnumServicesStatusExA(
5741 SC_RPC_HANDLE hSCManager
,
5742 SC_ENUM_TYPE InfoLevel
,
5743 DWORD dwServiceType
,
5744 DWORD dwServiceState
,
5747 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
5748 LPBOUNDED_DWORD_256K lpServicesReturned
,
5749 LPBOUNDED_DWORD_256K lpResumeIndex
,
5750 LPCSTR pszGroupName
)
5752 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrW
= NULL
;
5753 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrIncrW
;
5754 LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtrA
= NULL
;
5755 LPWSTR lpStringPtrW
;
5757 LPWSTR pszGroupNameW
= NULL
;
5759 DWORD dwServiceCount
;
5761 DPRINT("REnumServicesStatusExA() called\n");
5763 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
5765 return ERROR_INVALID_ADDRESS
;
5770 pszGroupNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, (strlen(pszGroupName
) + 1) * sizeof(WCHAR
));
5773 DPRINT("Failed to allocate buffer!\n");
5774 return ERROR_NOT_ENOUGH_MEMORY
;
5777 MultiByteToWideChar(CP_ACP
,
5782 (int)(strlen(pszGroupName
) + 1));
5785 if ((cbBufSize
> 0) && (lpBuffer
))
5787 lpStatusPtrW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, cbBufSize
);
5790 DPRINT("Failed to allocate buffer!\n");
5791 return ERROR_NOT_ENOUGH_MEMORY
;
5795 dwError
= REnumServicesStatusExW(hSCManager
,
5799 (LPBYTE
)lpStatusPtrW
,
5806 /* if no services were returned then we are Done */
5807 if (*lpServicesReturned
== 0)
5810 lpStatusPtrIncrW
= lpStatusPtrW
;
5811 lpStatusPtrA
= (LPENUM_SERVICE_STATUS_PROCESSA
)lpBuffer
;
5812 lpStringPtrA
= (LPSTR
)((ULONG_PTR
)lpBuffer
+
5813 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUS_PROCESSA
));
5814 lpStringPtrW
= (LPWSTR
)((ULONG_PTR
)lpStatusPtrW
+
5815 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUS_PROCESSW
));
5817 for (dwServiceCount
= 0; dwServiceCount
< *lpServicesReturned
; dwServiceCount
++)
5819 /* Copy the service name */
5820 WideCharToMultiByte(CP_ACP
,
5825 (int)wcslen(lpStringPtrW
),
5829 lpStatusPtrA
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
5830 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
5831 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
5833 /* Copy the display name */
5834 WideCharToMultiByte(CP_ACP
,
5839 (int)wcslen(lpStringPtrW
),
5843 lpStatusPtrA
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
5844 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
5845 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
5847 /* Copy the status information */
5848 memcpy(&lpStatusPtrA
->ServiceStatusProcess
,
5849 &lpStatusPtrIncrW
->ServiceStatusProcess
,
5850 sizeof(SERVICE_STATUS
));
5852 lpStatusPtrA
->ServiceStatusProcess
.dwProcessId
= lpStatusPtrIncrW
->ServiceStatusProcess
.dwProcessId
; /* FIXME */
5853 lpStatusPtrA
->ServiceStatusProcess
.dwServiceFlags
= 0; /* FIXME */
5861 HeapFree(GetProcessHeap(), 0, pszGroupNameW
);
5864 HeapFree(GetProcessHeap(), 0, lpStatusPtrW
);
5866 DPRINT("REnumServicesStatusExA() done (Error %lu)\n", dwError
);
5873 DWORD
REnumServicesStatusExW(
5874 SC_RPC_HANDLE hSCManager
,
5875 SC_ENUM_TYPE InfoLevel
,
5876 DWORD dwServiceType
,
5877 DWORD dwServiceState
,
5880 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
5881 LPBOUNDED_DWORD_256K lpServicesReturned
,
5882 LPBOUNDED_DWORD_256K lpResumeIndex
,
5883 LPCWSTR pszGroupName
)
5885 PMANAGER_HANDLE hManager
;
5887 DWORD dwError
= ERROR_SUCCESS
;
5888 PLIST_ENTRY ServiceEntry
;
5889 PSERVICE CurrentService
;
5891 DWORD dwRequiredSize
;
5892 DWORD dwServiceCount
;
5894 DWORD dwLastResumeCount
= 0;
5895 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr
;
5898 DPRINT("REnumServicesStatusExW() called\n");
5901 return ERROR_SHUTDOWN_IN_PROGRESS
;
5903 if (InfoLevel
!= SC_ENUM_PROCESS_INFO
)
5904 return ERROR_INVALID_LEVEL
;
5906 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
5907 if (hManager
== NULL
)
5909 DPRINT1("Invalid service manager handle!\n");
5910 return ERROR_INVALID_HANDLE
;
5913 if (pcbBytesNeeded
== NULL
|| lpServicesReturned
== NULL
)
5915 return ERROR_INVALID_ADDRESS
;
5918 *pcbBytesNeeded
= 0;
5919 *lpServicesReturned
= 0;
5921 if ((dwServiceType
== 0) ||
5922 ((dwServiceType
& ~SERVICE_TYPE_ALL
) != 0))
5924 DPRINT("Not a valid Service Type!\n");
5925 return ERROR_INVALID_PARAMETER
;
5928 if ((dwServiceState
== 0) ||
5929 ((dwServiceState
& ~SERVICE_STATE_ALL
) != 0))
5931 DPRINT("Not a valid Service State!\n");
5932 return ERROR_INVALID_PARAMETER
;
5935 /* Check access rights */
5936 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
5937 SC_MANAGER_ENUMERATE_SERVICE
))
5939 DPRINT("Insufficient access rights! 0x%lx\n",
5940 hManager
->Handle
.DesiredAccess
);
5941 return ERROR_ACCESS_DENIED
;
5945 dwLastResumeCount
= *lpResumeIndex
;
5947 /* Lock the service database shared */
5948 ScmLockDatabaseShared();
5950 lpService
= ScmGetServiceEntryByResumeCount(dwLastResumeCount
);
5951 if (lpService
== NULL
)
5953 dwError
= ERROR_SUCCESS
;
5960 for (ServiceEntry
= &lpService
->ServiceListEntry
;
5961 ServiceEntry
!= &ServiceListHead
;
5962 ServiceEntry
= ServiceEntry
->Flink
)
5964 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
5968 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
5971 dwState
= SERVICE_ACTIVE
;
5972 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
5973 dwState
= SERVICE_INACTIVE
;
5975 if ((dwState
& dwServiceState
) == 0)
5980 if (*pszGroupName
== 0)
5982 if (CurrentService
->lpGroup
!= NULL
)
5987 if ((CurrentService
->lpGroup
== NULL
) ||
5988 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
5993 dwSize
= sizeof(ENUM_SERVICE_STATUS_PROCESSW
) +
5994 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
5995 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
5997 if (dwRequiredSize
+ dwSize
<= cbBufSize
)
5999 DPRINT("Service name: %S fit\n", CurrentService
->lpServiceName
);
6000 dwRequiredSize
+= dwSize
;
6002 dwLastResumeCount
= CurrentService
->dwResumeCount
;
6006 DPRINT("Service name: %S no fit\n", CurrentService
->lpServiceName
);
6012 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize
);
6013 DPRINT("dwServiceCount: %lu\n", dwServiceCount
);
6016 ServiceEntry
!= &ServiceListHead
;
6017 ServiceEntry
= ServiceEntry
->Flink
)
6019 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
6023 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
6026 dwState
= SERVICE_ACTIVE
;
6027 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
6028 dwState
= SERVICE_INACTIVE
;
6030 if ((dwState
& dwServiceState
) == 0)
6035 if (*pszGroupName
== 0)
6037 if (CurrentService
->lpGroup
!= NULL
)
6042 if ((CurrentService
->lpGroup
== NULL
) ||
6043 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
6048 dwRequiredSize
+= (sizeof(ENUM_SERVICE_STATUS_PROCESSW
) +
6049 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
6050 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
)));
6052 dwError
= ERROR_MORE_DATA
;
6055 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize
);
6058 *lpResumeIndex
= dwLastResumeCount
;
6060 *lpServicesReturned
= dwServiceCount
;
6061 *pcbBytesNeeded
= dwRequiredSize
;
6063 /* If there was no services that matched */
6064 if ((!dwServiceCount
) && (dwError
!= ERROR_MORE_DATA
))
6066 dwError
= ERROR_SERVICE_DOES_NOT_EXIST
;
6070 lpStatusPtr
= (LPENUM_SERVICE_STATUS_PROCESSW
)lpBuffer
;
6071 lpStringPtr
= (LPWSTR
)((ULONG_PTR
)lpBuffer
+
6072 dwServiceCount
* sizeof(ENUM_SERVICE_STATUS_PROCESSW
));
6075 for (ServiceEntry
= &lpService
->ServiceListEntry
;
6076 ServiceEntry
!= &ServiceListHead
;
6077 ServiceEntry
= ServiceEntry
->Flink
)
6079 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
6083 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
6086 dwState
= SERVICE_ACTIVE
;
6087 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
6088 dwState
= SERVICE_INACTIVE
;
6090 if ((dwState
& dwServiceState
) == 0)
6095 if (*pszGroupName
== 0)
6097 if (CurrentService
->lpGroup
!= NULL
)
6102 if ((CurrentService
->lpGroup
== NULL
) ||
6103 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
6108 dwSize
= sizeof(ENUM_SERVICE_STATUS_PROCESSW
) +
6109 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
6110 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
6112 if (dwRequiredSize
+ dwSize
<= cbBufSize
)
6114 /* Copy the service name */
6116 CurrentService
->lpServiceName
);
6117 lpStatusPtr
->lpServiceName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
6118 lpStringPtr
+= (wcslen(CurrentService
->lpServiceName
) + 1);
6120 /* Copy the display name */
6122 CurrentService
->lpDisplayName
);
6123 lpStatusPtr
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
6124 lpStringPtr
+= (wcslen(CurrentService
->lpDisplayName
) + 1);
6126 /* Copy the status information */
6127 memcpy(&lpStatusPtr
->ServiceStatusProcess
,
6128 &CurrentService
->Status
,
6129 sizeof(SERVICE_STATUS
));
6130 lpStatusPtr
->ServiceStatusProcess
.dwProcessId
=
6131 (CurrentService
->lpImage
!= NULL
) ? CurrentService
->lpImage
->dwProcessId
: 0; /* FIXME */
6132 lpStatusPtr
->ServiceStatusProcess
.dwServiceFlags
= 0; /* FIXME */
6135 dwRequiredSize
+= dwSize
;
6145 *pcbBytesNeeded
= 0;
6151 /* Unlock the service database */
6152 ScmUnlockDatabase();
6154 DPRINT("REnumServicesStatusExW() done (Error %lu)\n", dwError
);
6161 DWORD
RSendTSMessage(
6162 handle_t BindingHandle
) /* FIXME */
6165 return ERROR_CALL_NOT_IMPLEMENTED
;
6170 DWORD
RCreateServiceWOW64A(
6171 handle_t BindingHandle
,
6172 LPSTR lpServiceName
,
6173 LPSTR lpDisplayName
,
6174 DWORD dwDesiredAccess
,
6175 DWORD dwServiceType
,
6177 DWORD dwErrorControl
,
6178 LPSTR lpBinaryPathName
,
6179 LPSTR lpLoadOrderGroup
,
6181 LPBYTE lpDependencies
,
6183 LPSTR lpServiceStartName
,
6186 LPSC_RPC_HANDLE lpServiceHandle
)
6189 return ERROR_CALL_NOT_IMPLEMENTED
;
6194 DWORD
RCreateServiceWOW64W(
6195 handle_t BindingHandle
,
6196 LPWSTR lpServiceName
,
6197 LPWSTR lpDisplayName
,
6198 DWORD dwDesiredAccess
,
6199 DWORD dwServiceType
,
6201 DWORD dwErrorControl
,
6202 LPWSTR lpBinaryPathName
,
6203 LPWSTR lpLoadOrderGroup
,
6205 LPBYTE lpDependencies
,
6207 LPWSTR lpServiceStartName
,
6210 LPSC_RPC_HANDLE lpServiceHandle
)
6213 return ERROR_CALL_NOT_IMPLEMENTED
;
6218 DWORD
RQueryServiceTagInfo(
6219 handle_t BindingHandle
) /* FIXME */
6222 return ERROR_CALL_NOT_IMPLEMENTED
;
6227 DWORD
RNotifyServiceStatusChange(
6228 SC_RPC_HANDLE hService
,
6229 SC_RPC_NOTIFY_PARAMS NotifyParams
,
6230 GUID
*pClientProcessGuid
,
6231 GUID
*pSCMProcessGuid
,
6232 PBOOL pfCreateRemoteQueue
,
6233 LPSC_NOTIFY_RPC_HANDLE phNotify
)
6236 return ERROR_CALL_NOT_IMPLEMENTED
;
6241 DWORD
RGetNotifyResults(
6242 SC_NOTIFY_RPC_HANDLE hNotify
,
6243 PSC_RPC_NOTIFY_PARAMS_LIST
*ppNotifyParams
)
6246 return ERROR_CALL_NOT_IMPLEMENTED
;
6251 DWORD
RCloseNotifyHandle(
6252 LPSC_NOTIFY_RPC_HANDLE phNotify
,
6256 return ERROR_CALL_NOT_IMPLEMENTED
;
6261 DWORD
RControlServiceExA(
6262 SC_RPC_HANDLE hService
,
6267 return ERROR_CALL_NOT_IMPLEMENTED
;
6272 DWORD
RControlServiceExW(
6273 SC_RPC_HANDLE hService
,
6278 return ERROR_CALL_NOT_IMPLEMENTED
;
6283 DWORD
RSendPnPMessage(
6284 handle_t BindingHandle
) /* FIXME */
6287 return ERROR_CALL_NOT_IMPLEMENTED
;
6292 DWORD
RValidatePnPService(
6293 handle_t BindingHandle
) /* FIXME */
6296 return ERROR_CALL_NOT_IMPLEMENTED
;
6301 DWORD
ROpenServiceStatusHandle(
6302 handle_t BindingHandle
) /* FIXME */
6305 return ERROR_CALL_NOT_IMPLEMENTED
;
6311 handle_t BindingHandle
) /* FIXME */
6314 return ERROR_CALL_NOT_IMPLEMENTED
;
6318 void __RPC_FAR
* __RPC_USER
midl_user_allocate(SIZE_T len
)
6320 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
);
6324 void __RPC_USER
midl_user_free(void __RPC_FAR
* ptr
)
6326 HeapFree(GetProcessHeap(), 0, ptr
);
6330 void __RPC_USER
SC_RPC_HANDLE_rundown(SC_RPC_HANDLE hSCObject
)
6332 /* Close the handle */
6333 RCloseServiceHandle(&hSCObject
);
6337 void __RPC_USER
SC_RPC_LOCK_rundown(SC_RPC_LOCK Lock
)
6339 /* Unlock the database */
6340 RUnlockServiceDatabase(&Lock
);
6344 void __RPC_USER
SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE hNotify
)