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 = %p\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 LPQUERY_SERVICE_CONFIGW lpConfig
= NULL
;
2659 WCHAR lpEmptyString
[] = {0,0};
2662 DPRINT("RQueryServiceConfigW() called\n");
2665 return ERROR_SHUTDOWN_IN_PROGRESS
;
2667 hSvc
= ScmGetServiceFromHandle(hService
);
2670 DPRINT1("Invalid service handle!\n");
2671 return ERROR_INVALID_HANDLE
;
2674 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
2675 SERVICE_QUERY_CONFIG
))
2677 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
2678 return ERROR_ACCESS_DENIED
;
2681 lpService
= hSvc
->ServiceEntry
;
2682 if (lpService
== NULL
)
2684 DPRINT("lpService == NULL!\n");
2685 return ERROR_INVALID_HANDLE
;
2688 /* Lock the service database shared */
2689 ScmLockDatabaseShared();
2691 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
2694 if (dwError
!= ERROR_SUCCESS
)
2697 /* Read the image path */
2698 dwError
= ScmReadString(hServiceKey
,
2701 if (dwError
!= ERROR_SUCCESS
)
2704 /* Read the service start name */
2705 ScmReadString(hServiceKey
,
2707 &lpServiceStartName
);
2709 /* Read the dependencies */
2710 ScmReadDependencies(hServiceKey
,
2712 &dwDependenciesLength
);
2714 dwRequiredSize
= sizeof(QUERY_SERVICE_CONFIGW
);
2716 if (lpImagePath
!= NULL
)
2717 dwRequiredSize
+= (DWORD
)((wcslen(lpImagePath
) + 1) * sizeof(WCHAR
));
2719 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2721 if (lpService
->lpGroup
!= NULL
)
2722 dwRequiredSize
+= (DWORD
)((wcslen(lpService
->lpGroup
->lpGroupName
) + 1) * sizeof(WCHAR
));
2724 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2726 if (lpDependencies
!= NULL
)
2727 dwRequiredSize
+= dwDependenciesLength
* sizeof(WCHAR
);
2729 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2731 if (lpServiceStartName
!= NULL
)
2732 dwRequiredSize
+= (DWORD
)((wcslen(lpServiceStartName
) + 1) * sizeof(WCHAR
));
2734 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2736 if (lpService
->lpDisplayName
!= NULL
)
2737 dwRequiredSize
+= (DWORD
)((wcslen(lpService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
2739 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2741 if (lpServiceConfig
== NULL
|| cbBufSize
< dwRequiredSize
)
2743 dwError
= ERROR_INSUFFICIENT_BUFFER
;
2747 lpConfig
= (LPQUERY_SERVICE_CONFIGW
)lpServiceConfig
;
2748 lpConfig
->dwServiceType
= lpService
->Status
.dwServiceType
;
2749 lpConfig
->dwStartType
= lpService
->dwStartType
;
2750 lpConfig
->dwErrorControl
= lpService
->dwErrorControl
;
2751 lpConfig
->dwTagId
= lpService
->dwTag
;
2753 lpStr
= (LPWSTR
)(lpConfig
+ 1);
2755 /* Append the image path */
2756 if (lpImagePath
!= NULL
)
2758 wcscpy(lpStr
, lpImagePath
);
2762 wcscpy(lpStr
, lpEmptyString
);
2765 lpConfig
->lpBinaryPathName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpConfig
);
2766 lpStr
+= (wcslen(lpStr
) + 1);
2768 /* Append the group name */
2769 if (lpService
->lpGroup
!= NULL
)
2771 wcscpy(lpStr
, lpService
->lpGroup
->lpGroupName
);
2775 wcscpy(lpStr
, lpEmptyString
);
2778 lpConfig
->lpLoadOrderGroup
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpConfig
);
2779 lpStr
+= (wcslen(lpStr
) + 1);
2781 /* Append Dependencies */
2782 if (lpDependencies
!= NULL
)
2786 dwDependenciesLength
* sizeof(WCHAR
));
2790 wcscpy(lpStr
, lpEmptyString
);
2793 lpConfig
->lpDependencies
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpConfig
);
2794 if (lpDependencies
!= NULL
)
2795 lpStr
+= dwDependenciesLength
;
2797 lpStr
+= (wcslen(lpStr
) + 1);
2799 /* Append the service start name */
2800 if (lpServiceStartName
!= NULL
)
2802 wcscpy(lpStr
, lpServiceStartName
);
2806 wcscpy(lpStr
, lpEmptyString
);
2809 lpConfig
->lpServiceStartName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpConfig
);
2810 lpStr
+= (wcslen(lpStr
) + 1);
2812 /* Append the display name */
2813 if (lpService
->lpDisplayName
!= NULL
)
2815 wcscpy(lpStr
, lpService
->lpDisplayName
);
2819 wcscpy(lpStr
, lpEmptyString
);
2822 lpConfig
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpConfig
);
2825 if (pcbBytesNeeded
!= NULL
)
2826 *pcbBytesNeeded
= dwRequiredSize
;
2829 /* Unlock the service database */
2830 ScmUnlockDatabase();
2832 if (lpImagePath
!= NULL
)
2833 HeapFree(GetProcessHeap(), 0, lpImagePath
);
2835 if (lpServiceStartName
!= NULL
)
2836 HeapFree(GetProcessHeap(), 0, lpServiceStartName
);
2838 if (lpDependencies
!= NULL
)
2839 HeapFree(GetProcessHeap(), 0, lpDependencies
);
2841 if (hServiceKey
!= NULL
)
2842 RegCloseKey(hServiceKey
);
2844 DPRINT("RQueryServiceConfigW() done\n");
2851 DWORD
RQueryServiceLockStatusW(
2852 SC_RPC_HANDLE hSCManager
,
2853 LPBYTE lpBuf
, // LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2855 LPBOUNDED_DWORD_4K pcbBytesNeeded
)
2857 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
= (LPQUERY_SERVICE_LOCK_STATUSW
)lpBuf
;
2858 PMANAGER_HANDLE hMgr
;
2859 DWORD dwRequiredSize
;
2861 if (!lpLockStatus
|| !pcbBytesNeeded
)
2862 return ERROR_INVALID_PARAMETER
;
2864 hMgr
= ScmGetServiceManagerFromHandle(hSCManager
);
2867 DPRINT1("Invalid service manager handle!\n");
2868 return ERROR_INVALID_HANDLE
;
2871 if (!RtlAreAllAccessesGranted(hMgr
->Handle
.DesiredAccess
,
2872 SC_MANAGER_QUERY_LOCK_STATUS
))
2874 DPRINT("Insufficient access rights! 0x%lx\n", hMgr
->Handle
.DesiredAccess
);
2875 return ERROR_ACCESS_DENIED
;
2878 /* FIXME: we need to compute instead the real length of the owner name */
2879 dwRequiredSize
= sizeof(QUERY_SERVICE_LOCK_STATUSW
) + sizeof(WCHAR
);
2880 *pcbBytesNeeded
= dwRequiredSize
;
2882 if (cbBufSize
< dwRequiredSize
)
2883 return ERROR_INSUFFICIENT_BUFFER
;
2885 ScmQueryServiceLockStatusW(lpLockStatus
);
2887 return ERROR_SUCCESS
;
2892 DWORD
RStartServiceW(
2893 SC_RPC_HANDLE hService
,
2895 LPSTRING_PTRSW argv
)
2897 DWORD dwError
= ERROR_SUCCESS
;
2898 PSERVICE_HANDLE hSvc
;
2899 PSERVICE lpService
= NULL
;
2900 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
]);
2914 return ERROR_SHUTDOWN_IN_PROGRESS
;
2916 hSvc
= ScmGetServiceFromHandle(hService
);
2919 DPRINT1("Invalid service handle!\n");
2920 return ERROR_INVALID_HANDLE
;
2923 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
2926 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
2927 return ERROR_ACCESS_DENIED
;
2930 lpService
= hSvc
->ServiceEntry
;
2931 if (lpService
== NULL
)
2933 DPRINT("lpService == NULL!\n");
2934 return ERROR_INVALID_HANDLE
;
2937 if (lpService
->dwStartType
== SERVICE_DISABLED
)
2938 return ERROR_SERVICE_DISABLED
;
2940 if (lpService
->bDeleted
)
2941 return ERROR_SERVICE_MARKED_FOR_DELETE
;
2943 /* Acquire the service start lock until the service has been started */
2944 dwError
= ScmAcquireServiceStartLock(TRUE
, &Lock
);
2945 if (dwError
!= ERROR_SUCCESS
)
2948 /* Start the service */
2949 dwError
= ScmStartService(lpService
, argc
, (LPWSTR
*)argv
);
2951 /* Release the service start lock */
2952 ScmReleaseServiceStartLock(&Lock
);
2959 DWORD
RGetServiceDisplayNameW(
2960 SC_RPC_HANDLE hSCManager
,
2961 LPCWSTR lpServiceName
,
2962 LPWSTR lpDisplayName
,
2965 // PMANAGER_HANDLE hManager;
2970 DPRINT("RGetServiceDisplayNameW() called\n");
2971 DPRINT("hSCManager = %p\n", hSCManager
);
2972 DPRINT("lpServiceName: %S\n", lpServiceName
);
2973 DPRINT("lpDisplayName: %p\n", lpDisplayName
);
2974 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
2976 // hManager = (PMANAGER_HANDLE)hSCManager;
2977 // if (hManager->Handle.Tag != MANAGER_TAG)
2979 // DPRINT("Invalid manager handle!\n");
2980 // return ERROR_INVALID_HANDLE;
2983 /* Get service database entry */
2984 lpService
= ScmGetServiceEntryByName(lpServiceName
);
2985 if (lpService
== NULL
)
2987 DPRINT("Could not find a service!\n");
2989 /* If the service could not be found and lpcchBuffer is less than 2, windows
2990 puts null in lpDisplayName and puts 2 in lpcchBuffer */
2991 if (*lpcchBuffer
< 2)
2994 if (lpDisplayName
!= NULL
)
3000 return ERROR_SERVICE_DOES_NOT_EXIST
;
3003 if (!lpService
->lpDisplayName
)
3005 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
3007 if (lpDisplayName
!= NULL
&&
3008 *lpcchBuffer
> dwLength
)
3010 wcscpy(lpDisplayName
, lpService
->lpServiceName
);
3015 dwLength
= (DWORD
)wcslen(lpService
->lpDisplayName
);
3017 if (lpDisplayName
!= NULL
&&
3018 *lpcchBuffer
> dwLength
)
3020 wcscpy(lpDisplayName
, lpService
->lpDisplayName
);
3024 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
3026 *lpcchBuffer
= dwLength
;
3033 DWORD
RGetServiceKeyNameW(
3034 SC_RPC_HANDLE hSCManager
,
3035 LPCWSTR lpDisplayName
,
3036 LPWSTR lpServiceName
,
3039 // PMANAGER_HANDLE hManager;
3044 DPRINT("RGetServiceKeyNameW() called\n");
3045 DPRINT("hSCManager = %p\n", hSCManager
);
3046 DPRINT("lpDisplayName: %S\n", lpDisplayName
);
3047 DPRINT("lpServiceName: %p\n", lpServiceName
);
3048 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
3050 // hManager = (PMANAGER_HANDLE)hSCManager;
3051 // if (hManager->Handle.Tag != MANAGER_TAG)
3053 // DPRINT("Invalid manager handle!\n");
3054 // return ERROR_INVALID_HANDLE;
3057 /* Get service database entry */
3058 lpService
= ScmGetServiceEntryByDisplayName(lpDisplayName
);
3059 if (lpService
== NULL
)
3061 DPRINT("Could not find a service!\n");
3063 /* If the service could not be found and lpcchBuffer is less than 2, windows
3064 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3065 if (*lpcchBuffer
< 2)
3068 if (lpServiceName
!= NULL
)
3074 return ERROR_SERVICE_DOES_NOT_EXIST
;
3077 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
3079 if (lpServiceName
!= NULL
&&
3080 *lpcchBuffer
> dwLength
)
3082 wcscpy(lpServiceName
, lpService
->lpServiceName
);
3083 *lpcchBuffer
= dwLength
;
3084 return ERROR_SUCCESS
;
3087 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
3089 *lpcchBuffer
= dwLength
;
3096 DWORD
RI_ScSetServiceBitsA(
3097 RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
3098 DWORD dwServiceBits
,
3100 int bUpdateImmediately
,
3104 return ERROR_CALL_NOT_IMPLEMENTED
;
3109 DWORD
RChangeServiceConfigA(
3110 SC_RPC_HANDLE hService
,
3111 DWORD dwServiceType
,
3113 DWORD dwErrorControl
,
3114 LPSTR lpBinaryPathName
,
3115 LPSTR lpLoadOrderGroup
,
3117 LPBYTE lpDependencies
,
3119 LPSTR lpServiceStartName
,
3122 LPSTR lpDisplayName
)
3124 DWORD dwError
= ERROR_SUCCESS
;
3125 PSERVICE_HANDLE hSvc
;
3126 PSERVICE lpService
= NULL
;
3127 HKEY hServiceKey
= NULL
;
3128 LPWSTR lpDisplayNameW
= NULL
;
3129 LPWSTR lpBinaryPathNameW
= NULL
;
3130 LPWSTR lpCanonicalImagePathW
= NULL
;
3131 LPWSTR lpLoadOrderGroupW
= NULL
;
3132 LPWSTR lpDependenciesW
= NULL
;
3134 DPRINT("RChangeServiceConfigA() called\n");
3135 DPRINT("dwServiceType = %lu\n", dwServiceType
);
3136 DPRINT("dwStartType = %lu\n", dwStartType
);
3137 DPRINT("dwErrorControl = %lu\n", dwErrorControl
);
3138 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName
);
3139 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup
);
3140 DPRINT("lpDisplayName = %s\n", lpDisplayName
);
3143 return ERROR_SHUTDOWN_IN_PROGRESS
;
3145 hSvc
= ScmGetServiceFromHandle(hService
);
3148 DPRINT1("Invalid service handle!\n");
3149 return ERROR_INVALID_HANDLE
;
3152 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3153 SERVICE_CHANGE_CONFIG
))
3155 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
3156 return ERROR_ACCESS_DENIED
;
3159 lpService
= hSvc
->ServiceEntry
;
3160 if (lpService
== NULL
)
3162 DPRINT("lpService == NULL!\n");
3163 return ERROR_INVALID_HANDLE
;
3166 /* Lock the service database exclusively */
3167 ScmLockDatabaseExclusive();
3169 if (lpService
->bDeleted
)
3171 DPRINT("The service has already been marked for delete!\n");
3172 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
3176 /* Open the service key */
3177 dwError
= ScmOpenServiceKey(lpService
->szServiceName
,
3180 if (dwError
!= ERROR_SUCCESS
)
3183 /* Write service data to the registry */
3185 if (lpDisplayName
!= NULL
&& *lpDisplayName
!= 0)
3187 /* Set the display name */
3188 lpDisplayNameW
= HeapAlloc(GetProcessHeap(),
3190 (strlen(lpDisplayName
) + 1) * sizeof(WCHAR
));
3191 if (lpDisplayNameW
== NULL
)
3193 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3197 MultiByteToWideChar(CP_ACP
,
3202 (int)(strlen(lpDisplayName
) + 1));
3204 RegSetValueExW(hServiceKey
,
3208 (LPBYTE
)lpDisplayNameW
,
3209 (DWORD
)((wcslen(lpDisplayNameW
) + 1) * sizeof(WCHAR
)));
3211 /* Update lpService->lpDisplayName */
3212 if (lpService
->lpDisplayName
)
3213 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
3215 lpService
->lpDisplayName
= lpDisplayNameW
;
3218 if (dwServiceType
!= SERVICE_NO_CHANGE
)
3220 /* Set the service type */
3221 dwError
= RegSetValueExW(hServiceKey
,
3225 (LPBYTE
)&dwServiceType
,
3227 if (dwError
!= ERROR_SUCCESS
)
3230 lpService
->Status
.dwServiceType
= dwServiceType
;
3233 if (dwStartType
!= SERVICE_NO_CHANGE
)
3235 /* Set the start value */
3236 dwError
= RegSetValueExW(hServiceKey
,
3240 (LPBYTE
)&dwStartType
,
3242 if (dwError
!= ERROR_SUCCESS
)
3245 lpService
->dwStartType
= dwStartType
;
3248 if (dwErrorControl
!= SERVICE_NO_CHANGE
)
3250 /* Set the error control value */
3251 dwError
= RegSetValueExW(hServiceKey
,
3255 (LPBYTE
)&dwErrorControl
,
3257 if (dwError
!= ERROR_SUCCESS
)
3260 lpService
->dwErrorControl
= dwErrorControl
;
3263 if (lpBinaryPathName
!= NULL
&& *lpBinaryPathName
!= 0)
3265 /* Set the image path */
3266 lpBinaryPathNameW
= HeapAlloc(GetProcessHeap(),
3268 (strlen(lpBinaryPathName
) + 1) * sizeof(WCHAR
));
3269 if (lpBinaryPathNameW
== NULL
)
3271 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3275 MultiByteToWideChar(CP_ACP
,
3280 (int)(strlen(lpBinaryPathName
) + 1));
3282 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
3284 dwError
= ScmCanonDriverImagePath(lpService
->dwStartType
,
3286 &lpCanonicalImagePathW
);
3288 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW
);
3290 if (dwError
!= ERROR_SUCCESS
)
3293 lpBinaryPathNameW
= lpCanonicalImagePathW
;
3296 dwError
= RegSetValueExW(hServiceKey
,
3300 (LPBYTE
)lpBinaryPathNameW
,
3301 (DWORD
)((wcslen(lpBinaryPathNameW
) + 1) * sizeof(WCHAR
)));
3303 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW
);
3305 if (dwError
!= ERROR_SUCCESS
)
3309 /* Set the group name */
3310 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
3312 lpLoadOrderGroupW
= HeapAlloc(GetProcessHeap(),
3314 (strlen(lpLoadOrderGroup
) + 1) * sizeof(WCHAR
));
3315 if (lpLoadOrderGroupW
== NULL
)
3317 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3321 MultiByteToWideChar(CP_ACP
,
3326 (int)(strlen(lpLoadOrderGroup
) + 1));
3328 dwError
= RegSetValueExW(hServiceKey
,
3332 (LPBYTE
)lpLoadOrderGroupW
,
3333 (DWORD
)((wcslen(lpLoadOrderGroupW
) + 1) * sizeof(WCHAR
)));
3334 if (dwError
!= ERROR_SUCCESS
)
3336 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3340 dwError
= ScmSetServiceGroup(lpService
,
3343 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3345 if (dwError
!= ERROR_SUCCESS
)
3349 if (lpdwTagId
!= NULL
)
3351 dwError
= ScmAssignNewTag(lpService
);
3352 if (dwError
!= ERROR_SUCCESS
)
3355 dwError
= RegSetValueExW(hServiceKey
,
3359 (LPBYTE
)&lpService
->dwTag
,
3361 if (dwError
!= ERROR_SUCCESS
)
3364 *lpdwTagId
= lpService
->dwTag
;
3367 /* Write dependencies */
3368 if (lpDependencies
!= NULL
&& *lpDependencies
!= 0)
3370 lpDependenciesW
= HeapAlloc(GetProcessHeap(),
3372 (strlen((LPSTR
)lpDependencies
) + 1) * sizeof(WCHAR
));
3373 if (lpDependenciesW
== NULL
)
3375 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3379 MultiByteToWideChar(CP_ACP
,
3381 (LPSTR
)lpDependencies
,
3384 (int)(strlen((LPSTR
)lpDependencies
) + 1));
3386 dwError
= ScmWriteDependencies(hServiceKey
,
3387 (LPWSTR
)lpDependenciesW
,
3390 HeapFree(GetProcessHeap(), 0, lpDependenciesW
);
3393 if (lpPassword
!= NULL
)
3395 /* FIXME: Decrypt and write password */
3399 /* Unlock the service database */
3400 ScmUnlockDatabase();
3402 if (hServiceKey
!= NULL
)
3403 RegCloseKey(hServiceKey
);
3405 DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError
);
3412 DWORD
RCreateServiceA(
3413 SC_RPC_HANDLE hSCManager
,
3414 LPSTR lpServiceName
,
3415 LPSTR lpDisplayName
,
3416 DWORD dwDesiredAccess
,
3417 DWORD dwServiceType
,
3419 DWORD dwErrorControl
,
3420 LPSTR lpBinaryPathName
,
3421 LPSTR lpLoadOrderGroup
,
3423 LPBYTE lpDependencies
,
3425 LPSTR lpServiceStartName
,
3428 LPSC_RPC_HANDLE lpServiceHandle
)
3430 DWORD dwError
= ERROR_SUCCESS
;
3431 LPWSTR lpServiceNameW
= NULL
;
3432 LPWSTR lpDisplayNameW
= NULL
;
3433 LPWSTR lpBinaryPathNameW
= NULL
;
3434 LPWSTR lpLoadOrderGroupW
= NULL
;
3435 LPWSTR lpDependenciesW
= NULL
;
3436 LPWSTR lpServiceStartNameW
= NULL
;
3437 DWORD dwDependenciesLength
= 0;
3444 len
= MultiByteToWideChar(CP_ACP
, 0, lpServiceName
, -1, NULL
, 0);
3445 lpServiceNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3446 if (!lpServiceNameW
)
3448 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3451 MultiByteToWideChar(CP_ACP
, 0, lpServiceName
, -1, lpServiceNameW
, len
);
3456 len
= MultiByteToWideChar(CP_ACP
, 0, lpDisplayName
, -1, NULL
, 0);
3457 lpDisplayNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3458 if (!lpDisplayNameW
)
3460 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3463 MultiByteToWideChar(CP_ACP
, 0, lpDisplayName
, -1, lpDisplayNameW
, len
);
3466 if (lpBinaryPathName
)
3468 len
= MultiByteToWideChar(CP_ACP
, 0, lpBinaryPathName
, -1, NULL
, 0);
3469 lpBinaryPathNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3470 if (!lpBinaryPathNameW
)
3472 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3475 MultiByteToWideChar(CP_ACP
, 0, lpBinaryPathName
, -1, lpBinaryPathNameW
, len
);
3478 if (lpLoadOrderGroup
)
3480 len
= MultiByteToWideChar(CP_ACP
, 0, lpLoadOrderGroup
, -1, NULL
, 0);
3481 lpLoadOrderGroupW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3482 if (!lpLoadOrderGroupW
)
3484 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3487 MultiByteToWideChar(CP_ACP
, 0, lpLoadOrderGroup
, -1, lpLoadOrderGroupW
, len
);
3492 lpStr
= (LPCSTR
)lpDependencies
;
3495 cchLength
= strlen(lpStr
) + 1;
3496 dwDependenciesLength
+= (DWORD
)cchLength
;
3497 lpStr
= lpStr
+ cchLength
;
3499 dwDependenciesLength
++;
3501 lpDependenciesW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwDependenciesLength
* sizeof(WCHAR
));
3502 if (!lpDependenciesW
)
3504 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3507 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)lpDependencies
, dwDependenciesLength
, lpDependenciesW
, dwDependenciesLength
);
3510 if (lpServiceStartName
)
3512 len
= MultiByteToWideChar(CP_ACP
, 0, lpServiceStartName
, -1, NULL
, 0);
3513 lpServiceStartNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
));
3514 if (!lpServiceStartNameW
)
3516 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3519 MultiByteToWideChar(CP_ACP
, 0, lpServiceStartName
, -1, lpServiceStartNameW
, len
);
3522 dwError
= RCreateServiceW(hSCManager
,
3532 (LPBYTE
)lpDependenciesW
,
3533 dwDependenciesLength
,
3534 lpServiceStartNameW
,
3540 if (lpServiceNameW
!=NULL
)
3541 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
3543 if (lpDisplayNameW
!= NULL
)
3544 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
3546 if (lpBinaryPathNameW
!= NULL
)
3547 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW
);
3549 if (lpLoadOrderGroupW
!= NULL
)
3550 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3552 if (lpDependenciesW
!= NULL
)
3553 HeapFree(GetProcessHeap(), 0, lpDependenciesW
);
3555 if (lpServiceStartNameW
!= NULL
)
3556 HeapFree(GetProcessHeap(), 0, lpServiceStartNameW
);
3563 DWORD
REnumDependentServicesA(
3564 SC_RPC_HANDLE hService
,
3565 DWORD dwServiceState
,
3568 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
3569 LPBOUNDED_DWORD_256K lpServicesReturned
)
3571 DWORD dwError
= ERROR_SUCCESS
;
3572 DWORD dwServicesReturned
= 0;
3573 DWORD dwServiceCount
;
3574 HKEY hServicesKey
= NULL
;
3575 PSERVICE_HANDLE hSvc
;
3576 PSERVICE lpService
= NULL
;
3577 PSERVICE
*lpServicesArray
= NULL
;
3578 LPENUM_SERVICE_STATUSA lpServicesPtr
= NULL
;
3581 *pcbBytesNeeded
= 0;
3582 *lpServicesReturned
= 0;
3584 DPRINT("REnumDependentServicesA() called\n");
3586 hSvc
= ScmGetServiceFromHandle(hService
);
3589 DPRINT1("Invalid service handle!\n");
3590 return ERROR_INVALID_HANDLE
;
3593 lpService
= hSvc
->ServiceEntry
;
3595 /* Check access rights */
3596 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3597 SC_MANAGER_ENUMERATE_SERVICE
))
3599 DPRINT("Insufficient access rights! 0x%lx\n",
3600 hSvc
->Handle
.DesiredAccess
);
3601 return ERROR_ACCESS_DENIED
;
3604 /* Open the Services Reg key */
3605 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
3606 L
"System\\CurrentControlSet\\Services",
3611 if (dwError
!= ERROR_SUCCESS
)
3614 /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3615 both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3616 are the same for both. Verified in WINXP. */
3618 /* First determine the bytes needed and get the number of dependent services*/
3619 dwError
= Int_EnumDependentServicesW(hServicesKey
,
3624 &dwServicesReturned
);
3625 if (dwError
!= ERROR_SUCCESS
)
3628 /* If buffer size is less than the bytes needed or pointer is null*/
3629 if ((!lpServices
) || (cbBufSize
< *pcbBytesNeeded
))
3631 dwError
= ERROR_MORE_DATA
;
3635 /* Allocate memory for array of service pointers */
3636 lpServicesArray
= HeapAlloc(GetProcessHeap(),
3638 (dwServicesReturned
+ 1) * sizeof(PSERVICE
));
3639 if (!lpServicesArray
)
3641 DPRINT("Could not allocate a buffer!!\n");
3642 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3646 dwServicesReturned
= 0;
3647 *pcbBytesNeeded
= 0;
3649 dwError
= Int_EnumDependentServicesW(hServicesKey
,
3654 &dwServicesReturned
);
3655 if (dwError
!= ERROR_SUCCESS
)
3660 lpServicesPtr
= (LPENUM_SERVICE_STATUSA
)lpServices
;
3661 lpStr
= (LPSTR
)(lpServices
+ (dwServicesReturned
* sizeof(ENUM_SERVICE_STATUSA
)));
3663 /* Copy EnumDepenedentService to Buffer */
3664 for (dwServiceCount
= 0; dwServiceCount
< dwServicesReturned
; dwServiceCount
++)
3666 lpService
= lpServicesArray
[dwServiceCount
];
3668 /* Copy the status info */
3669 memcpy(&lpServicesPtr
->ServiceStatus
,
3671 sizeof(SERVICE_STATUS
));
3673 /* Copy display name */
3674 WideCharToMultiByte(CP_ACP
,
3676 lpService
->lpDisplayName
,
3679 (int)wcslen(lpService
->lpDisplayName
),
3682 lpServicesPtr
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
3683 lpStr
+= strlen(lpStr
) + 1;
3685 /* Copy service name */
3686 WideCharToMultiByte(CP_ACP
,
3688 lpService
->lpServiceName
,
3691 (int)wcslen(lpService
->lpServiceName
),
3694 lpServicesPtr
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
3695 lpStr
+= strlen(lpStr
) + 1;
3700 *lpServicesReturned
= dwServicesReturned
;
3703 if (lpServicesArray
)
3704 HeapFree(GetProcessHeap(), 0, lpServicesArray
);
3706 RegCloseKey(hServicesKey
);
3708 DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError
);
3715 DWORD
REnumServicesStatusA(
3716 SC_RPC_HANDLE hSCManager
,
3717 DWORD dwServiceType
,
3718 DWORD dwServiceState
,
3721 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
3722 LPBOUNDED_DWORD_256K lpServicesReturned
,
3723 LPBOUNDED_DWORD_256K lpResumeHandle
)
3725 LPENUM_SERVICE_STATUSW lpStatusPtrW
= NULL
;
3726 LPENUM_SERVICE_STATUSW lpStatusPtrIncrW
;
3727 LPENUM_SERVICE_STATUSA lpStatusPtrA
= NULL
;
3728 LPWSTR lpStringPtrW
;
3731 DWORD dwServiceCount
;
3733 DPRINT("REnumServicesStatusA() called\n");
3735 if ((dwBufSize
> 0) && (lpBuffer
))
3737 lpStatusPtrW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwBufSize
);
3740 DPRINT("Failed to allocate buffer!\n");
3741 return ERROR_NOT_ENOUGH_MEMORY
;
3745 dwError
= REnumServicesStatusW(hSCManager
,
3748 (LPBYTE
)lpStatusPtrW
,
3754 /* if no services were returned then we are Done */
3755 if (*lpServicesReturned
== 0)
3758 lpStatusPtrIncrW
= lpStatusPtrW
;
3759 lpStatusPtrA
= (LPENUM_SERVICE_STATUSA
)lpBuffer
;
3760 lpStringPtrA
= (LPSTR
)((ULONG_PTR
)lpBuffer
+
3761 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUSA
));
3762 lpStringPtrW
= (LPWSTR
)((ULONG_PTR
)lpStatusPtrW
+
3763 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUSW
));
3765 for (dwServiceCount
= 0; dwServiceCount
< *lpServicesReturned
; dwServiceCount
++)
3767 /* Copy the service name */
3768 WideCharToMultiByte(CP_ACP
,
3773 (int)wcslen(lpStringPtrW
),
3777 lpStatusPtrA
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
3778 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
3779 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
3781 /* Copy the display name */
3782 WideCharToMultiByte(CP_ACP
,
3787 (int)wcslen(lpStringPtrW
),
3791 lpStatusPtrA
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
3792 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
3793 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
3795 /* Copy the status information */
3796 memcpy(&lpStatusPtrA
->ServiceStatus
,
3797 &lpStatusPtrIncrW
->ServiceStatus
,
3798 sizeof(SERVICE_STATUS
));
3806 HeapFree(GetProcessHeap(), 0, lpStatusPtrW
);
3808 DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError
);
3815 DWORD
ROpenSCManagerA(
3816 LPSTR lpMachineName
,
3817 LPSTR lpDatabaseName
,
3818 DWORD dwDesiredAccess
,
3819 LPSC_RPC_HANDLE lpScHandle
)
3821 UNICODE_STRING MachineName
;
3822 UNICODE_STRING DatabaseName
;
3825 DPRINT("ROpenSCManagerA() called\n");
3828 RtlCreateUnicodeStringFromAsciiz(&MachineName
,
3832 RtlCreateUnicodeStringFromAsciiz(&DatabaseName
,
3835 dwError
= ROpenSCManagerW(lpMachineName
? MachineName
.Buffer
: NULL
,
3836 lpDatabaseName
? DatabaseName
.Buffer
: NULL
,
3841 RtlFreeUnicodeString(&MachineName
);
3844 RtlFreeUnicodeString(&DatabaseName
);
3851 DWORD
ROpenServiceA(
3852 SC_RPC_HANDLE hSCManager
,
3853 LPSTR lpServiceName
,
3854 DWORD dwDesiredAccess
,
3855 LPSC_RPC_HANDLE lpServiceHandle
)
3857 UNICODE_STRING ServiceName
;
3860 DPRINT("ROpenServiceA() called\n");
3863 RtlCreateUnicodeStringFromAsciiz(&ServiceName
,
3866 dwError
= ROpenServiceW(hSCManager
,
3867 lpServiceName
? ServiceName
.Buffer
: NULL
,
3872 RtlFreeUnicodeString(&ServiceName
);
3879 DWORD
RQueryServiceConfigA(
3880 SC_RPC_HANDLE hService
,
3881 LPBYTE lpBuf
, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
3883 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
3885 LPQUERY_SERVICE_CONFIGA lpServiceConfig
= (LPQUERY_SERVICE_CONFIGA
)lpBuf
;
3886 DWORD dwError
= ERROR_SUCCESS
;
3887 PSERVICE_HANDLE hSvc
;
3888 PSERVICE lpService
= NULL
;
3889 HKEY hServiceKey
= NULL
;
3890 LPWSTR lpImagePath
= NULL
;
3891 LPWSTR lpServiceStartName
= NULL
;
3892 LPWSTR lpDependencies
= NULL
;
3893 DWORD dwDependenciesLength
= 0;
3894 DWORD dwRequiredSize
;
3895 LPQUERY_SERVICE_CONFIGA lpConfig
= NULL
;
3896 CHAR lpEmptyString
[]={0,0};
3899 DPRINT("RQueryServiceConfigA() called\n");
3902 return ERROR_SHUTDOWN_IN_PROGRESS
;
3904 hSvc
= ScmGetServiceFromHandle(hService
);
3907 DPRINT1("Invalid service handle!\n");
3908 return ERROR_INVALID_HANDLE
;
3911 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3912 SERVICE_QUERY_CONFIG
))
3914 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
3915 return ERROR_ACCESS_DENIED
;
3918 lpService
= hSvc
->ServiceEntry
;
3919 if (lpService
== NULL
)
3921 DPRINT("lpService == NULL!\n");
3922 return ERROR_INVALID_HANDLE
;
3925 /* Lock the service database shared */
3926 ScmLockDatabaseShared();
3928 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
3931 if (dwError
!= ERROR_SUCCESS
)
3934 /* Read the image path */
3935 dwError
= ScmReadString(hServiceKey
,
3938 if (dwError
!= ERROR_SUCCESS
)
3941 /* Read the service start name */
3942 ScmReadString(hServiceKey
,
3944 &lpServiceStartName
);
3946 /* Read the dependencies */
3947 ScmReadDependencies(hServiceKey
,
3949 &dwDependenciesLength
);
3951 dwRequiredSize
= sizeof(QUERY_SERVICE_CONFIGA
);
3953 if (lpImagePath
!= NULL
)
3954 dwRequiredSize
+= (DWORD
)(wcslen(lpImagePath
) + 1);
3956 dwRequiredSize
+= 2;
3958 if ((lpService
->lpGroup
!= NULL
) && (lpService
->lpGroup
->lpGroupName
!= NULL
))
3959 dwRequiredSize
+= (DWORD
)(wcslen(lpService
->lpGroup
->lpGroupName
) + 1);
3961 dwRequiredSize
+= 2;
3963 /* Add Dependencies length */
3964 if (lpDependencies
!= NULL
)
3965 dwRequiredSize
+= dwDependenciesLength
;
3967 dwRequiredSize
+= 2;
3969 if (lpServiceStartName
!= NULL
)
3970 dwRequiredSize
+= (DWORD
)(wcslen(lpServiceStartName
) + 1);
3972 dwRequiredSize
+= 2;
3974 if (lpService
->lpDisplayName
!= NULL
)
3975 dwRequiredSize
+= (DWORD
)(wcslen(lpService
->lpDisplayName
) + 1);
3977 dwRequiredSize
+= 2;
3979 if (lpServiceConfig
== NULL
|| cbBufSize
< dwRequiredSize
)
3981 dwError
= ERROR_INSUFFICIENT_BUFFER
;
3985 lpConfig
= (LPQUERY_SERVICE_CONFIGA
)lpServiceConfig
;
3986 lpConfig
->dwServiceType
= lpService
->Status
.dwServiceType
;
3987 lpConfig
->dwStartType
= lpService
->dwStartType
;
3988 lpConfig
->dwErrorControl
= lpService
->dwErrorControl
;
3989 lpConfig
->dwTagId
= lpService
->dwTag
;
3991 lpStr
= (LPSTR
)(lpServiceConfig
+ 1);
3993 /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
3994 Verified in WINXP */
3998 WideCharToMultiByte(CP_ACP
,
4003 (int)(wcslen(lpImagePath
) + 1),
4009 strcpy(lpStr
, lpEmptyString
);
4012 lpConfig
->lpBinaryPathName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpConfig
);
4013 lpStr
+= (strlen((LPSTR
)lpStr
) + 1);
4015 if (lpService
->lpGroup
&& lpService
->lpGroup
->lpGroupName
)
4017 WideCharToMultiByte(CP_ACP
,
4019 lpService
->lpGroup
->lpGroupName
,
4022 (int)(wcslen(lpService
->lpGroup
->lpGroupName
) + 1),
4028 strcpy(lpStr
, lpEmptyString
);
4031 lpConfig
->lpLoadOrderGroup
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpConfig
);
4032 lpStr
+= (strlen(lpStr
) + 1);
4034 /* Append Dependencies */
4037 WideCharToMultiByte(CP_ACP
,
4040 dwDependenciesLength
,
4042 dwDependenciesLength
,
4048 strcpy(lpStr
, lpEmptyString
);
4051 lpConfig
->lpDependencies
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpConfig
);
4053 lpStr
+= dwDependenciesLength
;
4055 lpStr
+= (strlen(lpStr
) + 1);
4057 if (lpServiceStartName
)
4059 WideCharToMultiByte(CP_ACP
,
4064 (int)(wcslen(lpServiceStartName
) + 1),
4070 strcpy(lpStr
, lpEmptyString
);
4073 lpConfig
->lpServiceStartName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpConfig
);
4074 lpStr
+= (strlen(lpStr
) + 1);
4076 if (lpService
->lpDisplayName
)
4078 WideCharToMultiByte(CP_ACP
,
4080 lpService
->lpDisplayName
,
4083 (int)(wcslen(lpService
->lpDisplayName
) + 1),
4089 strcpy(lpStr
, lpEmptyString
);
4092 lpConfig
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpConfig
);
4095 if (pcbBytesNeeded
!= NULL
)
4096 *pcbBytesNeeded
= dwRequiredSize
;
4099 /* Unlock the service database */
4100 ScmUnlockDatabase();
4102 if (lpImagePath
!= NULL
)
4103 HeapFree(GetProcessHeap(), 0, lpImagePath
);
4105 if (lpServiceStartName
!= NULL
)
4106 HeapFree(GetProcessHeap(), 0, lpServiceStartName
);
4108 if (lpDependencies
!= NULL
)
4109 HeapFree(GetProcessHeap(), 0, lpDependencies
);
4111 if (hServiceKey
!= NULL
)
4112 RegCloseKey(hServiceKey
);
4114 DPRINT("RQueryServiceConfigA() done\n");
4121 DWORD
RQueryServiceLockStatusA(
4122 SC_RPC_HANDLE hSCManager
,
4123 LPBYTE lpBuf
, // LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
4125 LPBOUNDED_DWORD_4K pcbBytesNeeded
)
4127 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
= (LPQUERY_SERVICE_LOCK_STATUSA
)lpBuf
;
4128 PMANAGER_HANDLE hMgr
;
4129 DWORD dwRequiredSize
;
4131 if (!lpLockStatus
|| !pcbBytesNeeded
)
4132 return ERROR_INVALID_PARAMETER
;
4134 hMgr
= ScmGetServiceManagerFromHandle(hSCManager
);
4137 DPRINT1("Invalid service manager handle!\n");
4138 return ERROR_INVALID_HANDLE
;
4141 if (!RtlAreAllAccessesGranted(hMgr
->Handle
.DesiredAccess
,
4142 SC_MANAGER_QUERY_LOCK_STATUS
))
4144 DPRINT("Insufficient access rights! 0x%lx\n", hMgr
->Handle
.DesiredAccess
);
4145 return ERROR_ACCESS_DENIED
;
4148 /* FIXME: we need to compute instead the real length of the owner name */
4149 dwRequiredSize
= sizeof(QUERY_SERVICE_LOCK_STATUSA
) + sizeof(CHAR
);
4150 *pcbBytesNeeded
= dwRequiredSize
;
4152 if (cbBufSize
< dwRequiredSize
)
4153 return ERROR_INSUFFICIENT_BUFFER
;
4155 ScmQueryServiceLockStatusA(lpLockStatus
);
4157 return ERROR_SUCCESS
;
4162 DWORD
RStartServiceA(
4163 SC_RPC_HANDLE hService
,
4165 LPSTRING_PTRSA argv
)
4167 DWORD dwError
= ERROR_SUCCESS
;
4168 PSERVICE_HANDLE hSvc
;
4169 PSERVICE lpService
= NULL
;
4170 SC_RPC_LOCK Lock
= NULL
;
4171 LPWSTR
*lpVector
= NULL
;
4175 DPRINT("RStartServiceA() called\n");
4178 return ERROR_SHUTDOWN_IN_PROGRESS
;
4180 hSvc
= ScmGetServiceFromHandle(hService
);
4183 DPRINT1("Invalid service handle!\n");
4184 return ERROR_INVALID_HANDLE
;
4187 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
4190 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
4191 return ERROR_ACCESS_DENIED
;
4194 lpService
= hSvc
->ServiceEntry
;
4195 if (lpService
== NULL
)
4197 DPRINT("lpService == NULL!\n");
4198 return ERROR_INVALID_HANDLE
;
4201 if (lpService
->dwStartType
== SERVICE_DISABLED
)
4202 return ERROR_SERVICE_DISABLED
;
4204 if (lpService
->bDeleted
)
4205 return ERROR_SERVICE_MARKED_FOR_DELETE
;
4207 /* Build a Unicode argument vector */
4210 lpVector
= HeapAlloc(GetProcessHeap(),
4212 argc
* sizeof(LPWSTR
));
4213 if (lpVector
== NULL
)
4214 return ERROR_NOT_ENOUGH_MEMORY
;
4216 for (i
= 0; i
< argc
; i
++)
4218 dwLength
= MultiByteToWideChar(CP_ACP
,
4225 lpVector
[i
] = HeapAlloc(GetProcessHeap(),
4227 dwLength
* sizeof(WCHAR
));
4228 if (lpVector
[i
] == NULL
)
4230 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
4234 MultiByteToWideChar(CP_ACP
,
4243 /* Acquire the service start lock until the service has been started */
4244 dwError
= ScmAcquireServiceStartLock(TRUE
, &Lock
);
4245 if (dwError
!= ERROR_SUCCESS
)
4248 /* Start the service */
4249 dwError
= ScmStartService(lpService
, argc
, lpVector
);
4251 /* Release the service start lock */
4252 ScmReleaseServiceStartLock(&Lock
);
4255 /* Free the Unicode argument vector */
4256 if (lpVector
!= NULL
)
4258 for (i
= 0; i
< argc
; i
++)
4260 if (lpVector
[i
] != NULL
)
4261 HeapFree(GetProcessHeap(), 0, lpVector
[i
]);
4263 HeapFree(GetProcessHeap(), 0, lpVector
);
4271 DWORD
RGetServiceDisplayNameA(
4272 SC_RPC_HANDLE hSCManager
,
4273 LPCSTR lpServiceName
,
4274 LPSTR lpDisplayName
,
4275 LPBOUNDED_DWORD_4K lpcchBuffer
)
4277 // PMANAGER_HANDLE hManager;
4278 PSERVICE lpService
= NULL
;
4281 LPWSTR lpServiceNameW
;
4283 DPRINT("RGetServiceDisplayNameA() called\n");
4284 DPRINT("hSCManager = %p\n", hSCManager
);
4285 DPRINT("lpServiceName: %s\n", lpServiceName
);
4286 DPRINT("lpDisplayName: %p\n", lpDisplayName
);
4287 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
4289 // hManager = (PMANAGER_HANDLE)hSCManager;
4290 // if (hManager->Handle.Tag != MANAGER_TAG)
4292 // DPRINT("Invalid manager handle!\n");
4293 // return ERROR_INVALID_HANDLE;
4296 if (lpServiceName
!= NULL
)
4298 dwLength
= (DWORD
)(strlen(lpServiceName
) + 1);
4299 lpServiceNameW
= HeapAlloc(GetProcessHeap(),
4301 dwLength
* sizeof(WCHAR
));
4302 if (!lpServiceNameW
)
4303 return ERROR_NOT_ENOUGH_MEMORY
;
4305 MultiByteToWideChar(CP_ACP
,
4312 lpService
= ScmGetServiceEntryByName(lpServiceNameW
);
4314 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
4317 if (lpService
== NULL
)
4319 DPRINT("Could not find a service!\n");
4321 /* If the service could not be found and lpcchBuffer is 0, windows
4322 puts null in lpDisplayName and puts 1 in lpcchBuffer */
4323 if (*lpcchBuffer
== 0)
4326 if (lpDisplayName
!= NULL
)
4331 return ERROR_SERVICE_DOES_NOT_EXIST
;
4334 if (!lpService
->lpDisplayName
)
4336 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
4337 if (lpDisplayName
!= NULL
&&
4338 *lpcchBuffer
> dwLength
)
4340 WideCharToMultiByte(CP_ACP
,
4342 lpService
->lpServiceName
,
4343 (int)wcslen(lpService
->lpServiceName
),
4348 return ERROR_SUCCESS
;
4353 dwLength
= (DWORD
)wcslen(lpService
->lpDisplayName
);
4354 if (lpDisplayName
!= NULL
&&
4355 *lpcchBuffer
> dwLength
)
4357 WideCharToMultiByte(CP_ACP
,
4359 lpService
->lpDisplayName
,
4360 (int)wcslen(lpService
->lpDisplayName
),
4365 return ERROR_SUCCESS
;
4369 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
4371 *lpcchBuffer
= dwLength
* 2;
4378 DWORD
RGetServiceKeyNameA(
4379 SC_RPC_HANDLE hSCManager
,
4380 LPCSTR lpDisplayName
,
4381 LPSTR lpServiceName
,
4382 LPBOUNDED_DWORD_4K lpcchBuffer
)
4387 LPWSTR lpDisplayNameW
;
4389 DPRINT("RGetServiceKeyNameA() called\n");
4390 DPRINT("hSCManager = %p\n", hSCManager
);
4391 DPRINT("lpDisplayName: %s\n", lpDisplayName
);
4392 DPRINT("lpServiceName: %p\n", lpServiceName
);
4393 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
4395 dwLength
= (DWORD
)(strlen(lpDisplayName
) + 1);
4396 lpDisplayNameW
= HeapAlloc(GetProcessHeap(),
4398 dwLength
* sizeof(WCHAR
));
4399 if (!lpDisplayNameW
)
4400 return ERROR_NOT_ENOUGH_MEMORY
;
4402 MultiByteToWideChar(CP_ACP
,
4409 lpService
= ScmGetServiceEntryByDisplayName(lpDisplayNameW
);
4411 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
4413 if (lpService
== NULL
)
4415 DPRINT("Could not find the service!\n");
4417 /* If the service could not be found and lpcchBuffer is 0,
4418 put null in lpDisplayName and puts 1 in lpcchBuffer, verified WINXP. */
4419 if (*lpcchBuffer
== 0)
4422 if (lpServiceName
!= NULL
)
4428 return ERROR_SERVICE_DOES_NOT_EXIST
;
4431 dwLength
= (DWORD
)wcslen(lpService
->lpServiceName
);
4432 if (lpServiceName
!= NULL
&&
4433 *lpcchBuffer
> dwLength
)
4435 WideCharToMultiByte(CP_ACP
,
4437 lpService
->lpServiceName
,
4438 (int)wcslen(lpService
->lpServiceName
),
4443 return ERROR_SUCCESS
;
4446 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
4448 *lpcchBuffer
= dwLength
* 2;
4455 DWORD
RI_ScGetCurrentGroupStateW(
4456 SC_RPC_HANDLE hSCManager
,
4457 LPWSTR lpLoadOrderGroup
,
4461 return ERROR_CALL_NOT_IMPLEMENTED
;
4466 DWORD
REnumServiceGroupW(
4467 SC_RPC_HANDLE hSCManager
,
4468 DWORD dwServiceType
,
4469 DWORD dwServiceState
,
4472 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
4473 LPBOUNDED_DWORD_256K lpServicesReturned
,
4474 LPBOUNDED_DWORD_256K lpResumeIndex
,
4475 LPCWSTR pszGroupName
)
4477 PMANAGER_HANDLE hManager
;
4479 DWORD dwError
= ERROR_SUCCESS
;
4480 PLIST_ENTRY ServiceEntry
;
4481 PSERVICE CurrentService
;
4483 DWORD dwRequiredSize
;
4484 DWORD dwServiceCount
;
4486 DWORD dwLastResumeCount
= 0;
4487 LPENUM_SERVICE_STATUSW lpStatusPtr
;
4490 DPRINT("REnumServiceGroupW() called\n");
4493 return ERROR_SHUTDOWN_IN_PROGRESS
;
4495 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
4496 if (hManager
== NULL
)
4498 DPRINT1("Invalid service manager handle!\n");
4499 return ERROR_INVALID_HANDLE
;
4502 *pcbBytesNeeded
= 0;
4503 *lpServicesReturned
= 0;
4505 if ((dwServiceType
== 0) ||
4506 ((dwServiceType
& ~SERVICE_TYPE_ALL
) != 0))
4508 DPRINT("Not a valid Service Type!\n");
4509 return ERROR_INVALID_PARAMETER
;
4512 if ((dwServiceState
== 0) ||
4513 ((dwServiceState
& ~SERVICE_STATE_ALL
) != 0))
4515 DPRINT("Not a valid Service State!\n");
4516 return ERROR_INVALID_PARAMETER
;
4519 /* Check access rights */
4520 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
4521 SC_MANAGER_ENUMERATE_SERVICE
))
4523 DPRINT("Insufficient access rights! 0x%lx\n",
4524 hManager
->Handle
.DesiredAccess
);
4525 return ERROR_ACCESS_DENIED
;
4529 dwLastResumeCount
= *lpResumeIndex
;
4531 /* Lock the service database shared */
4532 ScmLockDatabaseShared();
4534 lpService
= ScmGetServiceEntryByResumeCount(dwLastResumeCount
);
4535 if (lpService
== NULL
)
4537 dwError
= ERROR_SUCCESS
;
4544 for (ServiceEntry
= &lpService
->ServiceListEntry
;
4545 ServiceEntry
!= &ServiceListHead
;
4546 ServiceEntry
= ServiceEntry
->Flink
)
4548 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
4552 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
4555 dwState
= SERVICE_ACTIVE
;
4556 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
4557 dwState
= SERVICE_INACTIVE
;
4559 if ((dwState
& dwServiceState
) == 0)
4564 if (*pszGroupName
== 0)
4566 if (CurrentService
->lpGroup
!= NULL
)
4571 if ((CurrentService
->lpGroup
== NULL
) ||
4572 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
4577 dwSize
= sizeof(ENUM_SERVICE_STATUSW
) +
4578 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
4579 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
4581 if (dwRequiredSize
+ dwSize
> cbBufSize
)
4583 DPRINT("Service name: %S no fit\n", CurrentService
->lpServiceName
);
4587 DPRINT("Service name: %S fit\n", CurrentService
->lpServiceName
);
4588 dwRequiredSize
+= dwSize
;
4590 dwLastResumeCount
= CurrentService
->dwResumeCount
;
4593 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize
);
4594 DPRINT("dwServiceCount: %lu\n", dwServiceCount
);
4597 ServiceEntry
!= &ServiceListHead
;
4598 ServiceEntry
= ServiceEntry
->Flink
)
4600 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
4604 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
4607 dwState
= SERVICE_ACTIVE
;
4608 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
4609 dwState
= SERVICE_INACTIVE
;
4611 if ((dwState
& dwServiceState
) == 0)
4616 if (*pszGroupName
== 0)
4618 if (CurrentService
->lpGroup
!= NULL
)
4623 if ((CurrentService
->lpGroup
== NULL
) ||
4624 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
4629 dwRequiredSize
+= (sizeof(ENUM_SERVICE_STATUSW
) +
4630 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
4631 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
)));
4633 dwError
= ERROR_MORE_DATA
;
4636 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize
);
4639 *lpResumeIndex
= dwLastResumeCount
;
4641 *lpServicesReturned
= dwServiceCount
;
4642 *pcbBytesNeeded
= dwRequiredSize
;
4644 lpStatusPtr
= (LPENUM_SERVICE_STATUSW
)lpBuffer
;
4645 lpStringPtr
= (LPWSTR
)((ULONG_PTR
)lpBuffer
+
4646 dwServiceCount
* sizeof(ENUM_SERVICE_STATUSW
));
4649 for (ServiceEntry
= &lpService
->ServiceListEntry
;
4650 ServiceEntry
!= &ServiceListHead
;
4651 ServiceEntry
= ServiceEntry
->Flink
)
4653 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
4657 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
4660 dwState
= SERVICE_ACTIVE
;
4661 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
4662 dwState
= SERVICE_INACTIVE
;
4664 if ((dwState
& dwServiceState
) == 0)
4669 if (*pszGroupName
== 0)
4671 if (CurrentService
->lpGroup
!= NULL
)
4676 if ((CurrentService
->lpGroup
== NULL
) ||
4677 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
4682 dwSize
= sizeof(ENUM_SERVICE_STATUSW
) +
4683 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
4684 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
4686 if (dwRequiredSize
+ dwSize
> cbBufSize
)
4689 /* Copy the service name */
4690 wcscpy(lpStringPtr
, CurrentService
->lpServiceName
);
4691 lpStatusPtr
->lpServiceName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
4692 lpStringPtr
+= (wcslen(CurrentService
->lpServiceName
) + 1);
4694 /* Copy the display name */
4695 wcscpy(lpStringPtr
, CurrentService
->lpDisplayName
);
4696 lpStatusPtr
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
4697 lpStringPtr
+= (wcslen(CurrentService
->lpDisplayName
) + 1);
4699 /* Copy the status information */
4700 memcpy(&lpStatusPtr
->ServiceStatus
,
4701 &CurrentService
->Status
,
4702 sizeof(SERVICE_STATUS
));
4705 dwRequiredSize
+= dwSize
;
4708 if (dwError
== ERROR_SUCCESS
)
4710 *pcbBytesNeeded
= 0;
4711 if (lpResumeIndex
) *lpResumeIndex
= 0;
4715 /* Unlock the service database */
4716 ScmUnlockDatabase();
4718 DPRINT("REnumServiceGroupW() done (Error %lu)\n", dwError
);
4725 // WARNING: This function is untested
4728 DWORD
RChangeServiceConfig2A(
4729 SC_RPC_HANDLE hService
,
4730 SC_RPC_CONFIG_INFOA Info
)
4732 SC_RPC_CONFIG_INFOW InfoW
;
4733 DWORD dwRet
, dwLength
;
4736 DPRINT("RChangeServiceConfig2A() called\n");
4737 DPRINT("dwInfoLevel = %lu\n", Info
.dwInfoLevel
);
4739 InfoW
.dwInfoLevel
= Info
.dwInfoLevel
;
4741 if (InfoW
.dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
4743 LPSERVICE_DESCRIPTIONW lpServiceDescriptonW
;
4744 //LPSERVICE_DESCRIPTIONA lpServiceDescriptonA;
4746 //lpServiceDescriptonA = Info.psd;
4748 ///if (lpServiceDescriptonA &&
4749 ///lpServiceDescriptonA->lpDescription)
4751 dwLength
= (DWORD
)((strlen(Info
.lpDescription
) + 1) * sizeof(WCHAR
));
4753 lpServiceDescriptonW
= HeapAlloc(GetProcessHeap(),
4755 dwLength
+ sizeof(SERVICE_DESCRIPTIONW
));
4756 if (!lpServiceDescriptonW
)
4758 return ERROR_NOT_ENOUGH_MEMORY
;
4761 lpServiceDescriptonW
->lpDescription
= (LPWSTR
)(lpServiceDescriptonW
+ 1);
4763 MultiByteToWideChar(CP_ACP
,
4767 lpServiceDescriptonW
->lpDescription
,
4770 ptr
= lpServiceDescriptonW
;
4771 InfoW
.psd
= lpServiceDescriptonW
;
4774 else if (Info
.dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
4776 LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW
;
4777 LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA
;
4778 DWORD dwRebootLen
= 0;
4779 DWORD dwCommandLen
= 0;
4781 lpServiceFailureActionsA
= Info
.psfa
;
4783 if (lpServiceFailureActionsA
)
4785 if (lpServiceFailureActionsA
->lpRebootMsg
)
4787 dwRebootLen
= (DWORD
)((strlen(lpServiceFailureActionsA
->lpRebootMsg
) + 1) * sizeof(WCHAR
));
4789 if (lpServiceFailureActionsA
->lpCommand
)
4791 dwCommandLen
= (DWORD
)((strlen(lpServiceFailureActionsA
->lpCommand
) + 1) * sizeof(WCHAR
));
4793 dwLength
= dwRebootLen
+ dwCommandLen
+ sizeof(SERVICE_FAILURE_ACTIONSW
);
4795 lpServiceFailureActionsW
= HeapAlloc(GetProcessHeap(),
4798 if (!lpServiceFailureActionsW
)
4800 return ERROR_NOT_ENOUGH_MEMORY
;
4803 lpServiceFailureActionsW
->cActions
= lpServiceFailureActionsA
->cActions
;
4804 lpServiceFailureActionsW
->dwResetPeriod
= lpServiceFailureActionsA
->dwResetPeriod
;
4805 CopyMemory(lpServiceFailureActionsW
->lpsaActions
, lpServiceFailureActionsA
->lpsaActions
, sizeof(SC_ACTION
));
4807 if (lpServiceFailureActionsA
->lpRebootMsg
)
4809 MultiByteToWideChar(CP_ACP
,
4811 lpServiceFailureActionsA
->lpRebootMsg
,
4813 lpServiceFailureActionsW
->lpRebootMsg
,
4817 if (lpServiceFailureActionsA
->lpCommand
)
4819 MultiByteToWideChar(CP_ACP
,
4821 lpServiceFailureActionsA
->lpCommand
,
4823 lpServiceFailureActionsW
->lpCommand
,
4827 ptr
= lpServiceFailureActionsW
;
4831 dwRet
= RChangeServiceConfig2W(hService
, InfoW
);
4833 HeapFree(GetProcessHeap(), 0, ptr
);
4840 ScmSetFailureActions(PSERVICE_HANDLE hSvc
,
4843 LPSERVICE_FAILURE_ACTIONSW lpFailureActions
)
4845 LPSERVICE_FAILURE_ACTIONSW lpReadBuffer
= NULL
;
4846 LPSERVICE_FAILURE_ACTIONSW lpWriteBuffer
= NULL
;
4847 BOOL bIsActionRebootSet
= FALSE
;
4848 DWORD dwDesiredAccess
= SERVICE_CHANGE_CONFIG
;
4849 DWORD dwRequiredSize
= 0;
4854 /* There is nothing to be done if we have no failure actions */
4855 if (lpFailureActions
== NULL
)
4856 return ERROR_SUCCESS
;
4859 * 1- Check whether or not we can set
4860 * failure actions for this service.
4863 /* Failure actions can only be set for Win32 services, not for drivers */
4864 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
4865 return ERROR_CANNOT_DETECT_DRIVER_FAILURE
;
4868 * If the service controller handles the SC_ACTION_RESTART action,
4869 * hService must have the SERVICE_START access right.
4871 * If you specify SC_ACTION_REBOOT, the caller must have the
4872 * SE_SHUTDOWN_NAME privilege.
4874 if (lpFailureActions
->cActions
> 0 &&
4875 lpFailureActions
->lpsaActions
!= NULL
)
4877 for (i
= 0; i
< lpFailureActions
->cActions
; ++i
)
4879 if (lpFailureActions
->lpsaActions
[i
].Type
== SC_ACTION_RESTART
)
4880 dwDesiredAccess
|= SERVICE_START
;
4881 else if (lpFailureActions
->lpsaActions
[i
].Type
== SC_ACTION_REBOOT
)
4882 bIsActionRebootSet
= TRUE
;
4886 /* Re-check the access rights */
4887 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
4890 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
4891 return ERROR_ACCESS_DENIED
;
4894 /* FIXME: Check if the caller has the SE_SHUTDOWN_NAME privilege */
4895 if (bIsActionRebootSet
)
4900 * 2- Retrieve the original value of FailureActions.
4903 /* Query value length */
4904 dwError
= RegQueryValueExW(hServiceKey
,
4910 if (dwError
!= ERROR_SUCCESS
&&
4911 dwError
!= ERROR_MORE_DATA
&&
4912 dwError
!= ERROR_FILE_NOT_FOUND
)
4915 dwRequiredSize
= (dwType
== REG_BINARY
) ? max(sizeof(SERVICE_FAILURE_ACTIONSW
), dwRequiredSize
)
4916 : sizeof(SERVICE_FAILURE_ACTIONSW
);
4918 /* Initialize the read buffer */
4919 lpReadBuffer
= HeapAlloc(GetProcessHeap(),
4922 if (lpReadBuffer
== NULL
)
4923 return ERROR_NOT_ENOUGH_MEMORY
;
4925 /* Now we can fill the read buffer */
4926 if (dwError
!= ERROR_FILE_NOT_FOUND
&&
4927 dwType
== REG_BINARY
)
4929 dwError
= RegQueryValueExW(hServiceKey
,
4933 (LPBYTE
)lpReadBuffer
,
4935 if (dwError
!= ERROR_SUCCESS
&&
4936 dwError
!= ERROR_FILE_NOT_FOUND
)
4939 if (dwRequiredSize
< sizeof(SERVICE_FAILURE_ACTIONSW
))
4940 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSW
);
4945 * The value of the error doesn't really matter, the only
4946 * important thing is that it must be != ERROR_SUCCESS.
4948 dwError
= ERROR_INVALID_DATA
;
4951 if (dwError
== ERROR_SUCCESS
)
4953 lpReadBuffer
->cActions
= min(lpReadBuffer
->cActions
, (dwRequiredSize
- sizeof(SERVICE_FAILURE_ACTIONSW
)) / sizeof(SC_ACTION
));
4954 lpReadBuffer
->lpsaActions
= (lpReadBuffer
->cActions
> 0 ? (LPSC_ACTION
)(lpReadBuffer
+ 1) : NULL
);
4958 lpReadBuffer
->dwResetPeriod
= 0;
4959 lpReadBuffer
->cActions
= 0;
4960 lpReadBuffer
->lpsaActions
= NULL
;
4963 lpReadBuffer
->lpRebootMsg
= NULL
;
4964 lpReadBuffer
->lpCommand
= NULL
;
4967 * 3- Initialize the new value to set.
4970 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSW
);
4972 if (lpFailureActions
->lpsaActions
== NULL
)
4975 * lpFailureActions->cActions is ignored.
4976 * Therefore we use the original values
4977 * of cActions and lpsaActions.
4979 dwRequiredSize
+= lpReadBuffer
->cActions
* sizeof(SC_ACTION
);
4984 * The reset period and array of failure actions
4985 * are deleted if lpFailureActions->cActions == 0 .
4987 dwRequiredSize
+= lpFailureActions
->cActions
* sizeof(SC_ACTION
);
4990 lpWriteBuffer
= HeapAlloc(GetProcessHeap(),
4993 if (lpWriteBuffer
== NULL
)
4995 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
4999 /* Clean the pointers as they have no meaning when the structure is stored in the registry */
5000 lpWriteBuffer
->lpRebootMsg
= NULL
;
5001 lpWriteBuffer
->lpCommand
= NULL
;
5002 lpWriteBuffer
->lpsaActions
= NULL
;
5004 /* Set the members */
5005 if (lpFailureActions
->lpsaActions
== NULL
)
5008 * lpFailureActions->dwResetPeriod and lpFailureActions->cActions are ignored.
5009 * Therefore we use the original values of dwResetPeriod, cActions and lpsaActions.
5011 lpWriteBuffer
->dwResetPeriod
= lpReadBuffer
->dwResetPeriod
;
5012 lpWriteBuffer
->cActions
= lpReadBuffer
->cActions
;
5014 if (lpReadBuffer
->lpsaActions
!= NULL
)
5016 memmove(lpWriteBuffer
+ 1,
5017 lpReadBuffer
->lpsaActions
,
5018 lpReadBuffer
->cActions
* sizeof(SC_ACTION
));
5023 if (lpFailureActions
->cActions
> 0)
5025 lpWriteBuffer
->dwResetPeriod
= lpFailureActions
->dwResetPeriod
;
5026 lpWriteBuffer
->cActions
= lpFailureActions
->cActions
;
5028 memmove(lpWriteBuffer
+ 1,
5029 lpFailureActions
->lpsaActions
,
5030 lpFailureActions
->cActions
* sizeof(SC_ACTION
));
5034 /* The reset period and array of failure actions are deleted */
5035 lpWriteBuffer
->dwResetPeriod
= 0;
5036 lpWriteBuffer
->cActions
= 0;
5040 /* Save the new failure actions into the registry */
5041 dwError
= RegSetValueExW(hServiceKey
,
5045 (LPBYTE
)lpWriteBuffer
,
5048 /* We modify the strings only in case of success.*/
5049 if (dwError
== ERROR_SUCCESS
)
5051 /* Modify the Reboot Message value, if specified */
5052 if (lpFailureActions
->lpRebootMsg
!= NULL
)
5054 /* If the Reboot Message is "" then we delete it */
5055 if (*lpFailureActions
->lpRebootMsg
== 0)
5057 DPRINT("Delete Reboot Message value\n");
5058 RegDeleteValueW(hServiceKey
, L
"RebootMessage");
5062 DPRINT("Setting Reboot Message value %S\n", lpFailureActions
->lpRebootMsg
);
5063 RegSetValueExW(hServiceKey
,
5067 (LPBYTE
)lpFailureActions
->lpRebootMsg
,
5068 (DWORD
)((wcslen(lpFailureActions
->lpRebootMsg
) + 1) * sizeof(WCHAR
)));
5072 /* Modify the Failure Command value, if specified */
5073 if (lpFailureActions
->lpCommand
!= NULL
)
5075 /* If the FailureCommand string is an empty string, delete the value */
5076 if (*lpFailureActions
->lpCommand
== 0)
5078 DPRINT("Delete Failure Command value\n");
5079 RegDeleteValueW(hServiceKey
, L
"FailureCommand");
5083 DPRINT("Setting Failure Command value %S\n", lpFailureActions
->lpCommand
);
5084 RegSetValueExW(hServiceKey
,
5088 (LPBYTE
)lpFailureActions
->lpCommand
,
5089 (DWORD
)((wcslen(lpFailureActions
->lpCommand
) + 1) * sizeof(WCHAR
)));
5095 if (lpWriteBuffer
!= NULL
)
5096 HeapFree(GetProcessHeap(), 0, lpWriteBuffer
);
5098 if (lpReadBuffer
!= NULL
)
5099 HeapFree(GetProcessHeap(), 0, lpReadBuffer
);
5106 DWORD
RChangeServiceConfig2W(
5107 SC_RPC_HANDLE hService
,
5108 SC_RPC_CONFIG_INFOW Info
)
5110 DWORD dwError
= ERROR_SUCCESS
;
5111 PSERVICE_HANDLE hSvc
;
5112 PSERVICE lpService
= NULL
;
5113 HKEY hServiceKey
= NULL
;
5115 DPRINT("RChangeServiceConfig2W() called\n");
5116 DPRINT("dwInfoLevel = %lu\n", Info
.dwInfoLevel
);
5119 return ERROR_SHUTDOWN_IN_PROGRESS
;
5121 hSvc
= ScmGetServiceFromHandle(hService
);
5124 DPRINT1("Invalid service handle!\n");
5125 return ERROR_INVALID_HANDLE
;
5128 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5129 SERVICE_CHANGE_CONFIG
))
5131 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5132 return ERROR_ACCESS_DENIED
;
5135 lpService
= hSvc
->ServiceEntry
;
5136 if (lpService
== NULL
)
5138 DPRINT("lpService == NULL!\n");
5139 return ERROR_INVALID_HANDLE
;
5142 /* Lock the service database exclusively */
5143 ScmLockDatabaseExclusive();
5145 if (lpService
->bDeleted
)
5147 DPRINT("The service has already been marked for delete!\n");
5148 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
5152 /* Open the service key */
5153 dwError
= ScmOpenServiceKey(lpService
->szServiceName
,
5154 KEY_READ
| KEY_SET_VALUE
,
5156 if (dwError
!= ERROR_SUCCESS
)
5159 if (Info
.dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
5161 LPSERVICE_DESCRIPTIONW lpServiceDescription
= (LPSERVICE_DESCRIPTIONW
)Info
.psd
;
5163 /* Modify the service description, if specified */
5164 if (lpServiceDescription
!= NULL
&&
5165 lpServiceDescription
->lpDescription
!= NULL
)
5167 /* If the description is "" then we delete it */
5168 if (*lpServiceDescription
->lpDescription
== 0)
5170 DPRINT("Delete service description\n");
5171 dwError
= RegDeleteValueW(hServiceKey
, L
"Description");
5173 if (dwError
== ERROR_FILE_NOT_FOUND
)
5174 dwError
= ERROR_SUCCESS
;
5178 DPRINT("Setting service description value %S\n", lpServiceDescription
->lpDescription
);
5179 dwError
= RegSetValueExW(hServiceKey
,
5183 (LPBYTE
)lpServiceDescription
->lpDescription
,
5184 (DWORD
)((wcslen(lpServiceDescription
->lpDescription
) + 1) * sizeof(WCHAR
)));
5189 dwError
= ERROR_SUCCESS
;
5192 else if (Info
.dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5194 dwError
= ScmSetFailureActions(hSvc
,
5197 (LPSERVICE_FAILURE_ACTIONSW
)Info
.psfa
);
5201 if (hServiceKey
!= NULL
)
5202 RegCloseKey(hServiceKey
);
5204 /* Unlock the service database */
5205 ScmUnlockDatabase();
5207 DPRINT("RChangeServiceConfig2W() done (Error %lu)\n", dwError
);
5214 DWORD
RQueryServiceConfig2A(
5215 SC_RPC_HANDLE hService
,
5219 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
5221 DWORD dwError
= ERROR_SUCCESS
;
5222 PSERVICE_HANDLE hSvc
;
5223 PSERVICE lpService
= NULL
;
5224 HKEY hServiceKey
= NULL
;
5225 DWORD dwRequiredSize
= 0;
5227 LPWSTR lpDescriptionW
= NULL
;
5228 LPWSTR lpRebootMessageW
= NULL
;
5229 LPWSTR lpFailureCommandW
= NULL
;
5231 DPRINT("RQueryServiceConfig2A() called hService %p dwInfoLevel %u, lpBuffer %p cbBufSize %u pcbBytesNeeded %p\n",
5232 hService
, dwInfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
5235 return ERROR_INVALID_ADDRESS
;
5238 return ERROR_SHUTDOWN_IN_PROGRESS
;
5240 hSvc
= ScmGetServiceFromHandle(hService
);
5243 DPRINT1("Invalid service handle!\n");
5244 return ERROR_INVALID_HANDLE
;
5247 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5248 SERVICE_QUERY_CONFIG
))
5250 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5251 return ERROR_ACCESS_DENIED
;
5254 lpService
= hSvc
->ServiceEntry
;
5255 if (lpService
== NULL
)
5257 DPRINT("lpService == NULL!\n");
5258 return ERROR_INVALID_HANDLE
;
5261 /* Lock the service database shared */
5262 ScmLockDatabaseShared();
5264 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
5267 if (dwError
!= ERROR_SUCCESS
)
5270 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
5272 LPSERVICE_DESCRIPTIONA lpServiceDescription
= (LPSERVICE_DESCRIPTIONA
)lpBuffer
;
5275 dwError
= ScmReadString(hServiceKey
,
5278 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5281 *pcbBytesNeeded
= sizeof(SERVICE_DESCRIPTIONA
);
5282 if (dwError
== ERROR_SUCCESS
)
5283 *pcbBytesNeeded
+= (DWORD
)((wcslen(lpDescriptionW
) + 1) * sizeof(WCHAR
));
5285 if (cbBufSize
< *pcbBytesNeeded
)
5287 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5291 if (dwError
== ERROR_SUCCESS
)
5293 lpStr
= (LPSTR
)(lpServiceDescription
+ 1);
5295 WideCharToMultiByte(CP_ACP
,
5300 (int)wcslen(lpDescriptionW
),
5303 lpServiceDescription
->lpDescription
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceDescription
);
5307 lpServiceDescription
->lpDescription
= NULL
;
5308 dwError
= ERROR_SUCCESS
;
5311 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5313 LPSERVICE_FAILURE_ACTIONSA lpFailureActions
= (LPSERVICE_FAILURE_ACTIONSA
)lpBuffer
;
5316 /* Query value length */
5317 dwError
= RegQueryValueExW(hServiceKey
,
5323 if (dwError
!= ERROR_SUCCESS
&&
5324 dwError
!= ERROR_MORE_DATA
&&
5325 dwError
!= ERROR_FILE_NOT_FOUND
)
5328 dwRequiredSize
= (dwType
== REG_BINARY
) ? max(sizeof(SERVICE_FAILURE_ACTIONSA
), dwRequiredSize
)
5329 : sizeof(SERVICE_FAILURE_ACTIONSA
);
5331 /* Get the strings */
5332 ScmReadString(hServiceKey
,
5334 &lpFailureCommandW
);
5336 ScmReadString(hServiceKey
,
5340 if (lpRebootMessageW
)
5341 dwRequiredSize
+= (DWORD
)((wcslen(lpRebootMessageW
) + 1) * sizeof(WCHAR
));
5343 if (lpFailureCommandW
)
5344 dwRequiredSize
+= (DWORD
)((wcslen(lpFailureCommandW
) + 1) * sizeof(WCHAR
));
5346 if (cbBufSize
< dwRequiredSize
)
5348 *pcbBytesNeeded
= dwRequiredSize
;
5349 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5353 /* Now we can fill the buffer */
5354 if (dwError
!= ERROR_FILE_NOT_FOUND
&& dwType
== REG_BINARY
)
5356 dwError
= RegQueryValueExW(hServiceKey
,
5360 (LPBYTE
)lpFailureActions
,
5362 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5365 if (dwRequiredSize
< sizeof(SERVICE_FAILURE_ACTIONSA
))
5366 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSA
);
5371 * The value of the error doesn't really matter, the only
5372 * important thing is that it must be != ERROR_SUCCESS .
5374 dwError
= ERROR_INVALID_DATA
;
5377 if (dwError
== ERROR_SUCCESS
)
5379 lpFailureActions
->cActions
= min(lpFailureActions
->cActions
, (dwRequiredSize
- sizeof(SERVICE_FAILURE_ACTIONSA
)) / sizeof(SC_ACTION
));
5381 /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */
5382 lpFailureActions
->lpsaActions
= (lpFailureActions
->cActions
> 0 ? (LPSC_ACTION
)(ULONG_PTR
)sizeof(SERVICE_FAILURE_ACTIONSA
) : NULL
);
5384 lpStr
= (LPSTR
)((ULONG_PTR
)(lpFailureActions
+ 1) + lpFailureActions
->cActions
* sizeof(SC_ACTION
));
5388 lpFailureActions
->dwResetPeriod
= 0;
5389 lpFailureActions
->cActions
= 0;
5390 lpFailureActions
->lpsaActions
= NULL
;
5391 lpStr
= (LPSTR
)(lpFailureActions
+ 1);
5394 lpFailureActions
->lpRebootMsg
= NULL
;
5395 lpFailureActions
->lpCommand
= NULL
;
5397 if (lpRebootMessageW
)
5399 WideCharToMultiByte(CP_ACP
,
5404 (int)wcslen(lpRebootMessageW
),
5407 lpFailureActions
->lpRebootMsg
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5408 lpStr
+= strlen(lpStr
) + 1;
5411 if (lpFailureCommandW
)
5413 WideCharToMultiByte(CP_ACP
,
5418 (int)wcslen(lpFailureCommandW
),
5421 lpFailureActions
->lpCommand
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5422 /* lpStr += strlen(lpStr) + 1; */
5425 dwError
= ERROR_SUCCESS
;
5429 /* Unlock the service database */
5430 ScmUnlockDatabase();
5432 if (lpDescriptionW
!= NULL
)
5433 HeapFree(GetProcessHeap(), 0, lpDescriptionW
);
5435 if (lpRebootMessageW
!= NULL
)
5436 HeapFree(GetProcessHeap(), 0, lpRebootMessageW
);
5438 if (lpFailureCommandW
!= NULL
)
5439 HeapFree(GetProcessHeap(), 0, lpFailureCommandW
);
5441 if (hServiceKey
!= NULL
)
5442 RegCloseKey(hServiceKey
);
5444 DPRINT("RQueryServiceConfig2A() done (Error %lu)\n", dwError
);
5451 DWORD
RQueryServiceConfig2W(
5452 SC_RPC_HANDLE hService
,
5456 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
5458 DWORD dwError
= ERROR_SUCCESS
;
5459 PSERVICE_HANDLE hSvc
;
5460 PSERVICE lpService
= NULL
;
5461 HKEY hServiceKey
= NULL
;
5462 DWORD dwRequiredSize
= 0;
5464 LPWSTR lpDescription
= NULL
;
5465 LPWSTR lpRebootMessage
= NULL
;
5466 LPWSTR lpFailureCommand
= NULL
;
5468 DPRINT("RQueryServiceConfig2W() called\n");
5471 return ERROR_INVALID_ADDRESS
;
5474 return ERROR_SHUTDOWN_IN_PROGRESS
;
5476 hSvc
= ScmGetServiceFromHandle(hService
);
5479 DPRINT1("Invalid service handle!\n");
5480 return ERROR_INVALID_HANDLE
;
5483 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5484 SERVICE_QUERY_CONFIG
))
5486 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5487 return ERROR_ACCESS_DENIED
;
5490 lpService
= hSvc
->ServiceEntry
;
5491 if (lpService
== NULL
)
5493 DPRINT("lpService == NULL!\n");
5494 return ERROR_INVALID_HANDLE
;
5497 /* Lock the service database shared */
5498 ScmLockDatabaseShared();
5500 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
5503 if (dwError
!= ERROR_SUCCESS
)
5506 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
5508 LPSERVICE_DESCRIPTIONW lpServiceDescription
= (LPSERVICE_DESCRIPTIONW
)lpBuffer
;
5511 dwError
= ScmReadString(hServiceKey
,
5514 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5517 *pcbBytesNeeded
= sizeof(SERVICE_DESCRIPTIONW
);
5518 if (dwError
== ERROR_SUCCESS
)
5519 *pcbBytesNeeded
+= (DWORD
)((wcslen(lpDescription
) + 1) * sizeof(WCHAR
));
5521 if (cbBufSize
< *pcbBytesNeeded
)
5523 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5527 if (dwError
== ERROR_SUCCESS
)
5529 lpStr
= (LPWSTR
)(lpServiceDescription
+ 1);
5530 wcscpy(lpStr
, lpDescription
);
5531 lpServiceDescription
->lpDescription
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServiceDescription
);
5535 lpServiceDescription
->lpDescription
= NULL
;
5536 dwError
= ERROR_SUCCESS
;
5539 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
5541 LPSERVICE_FAILURE_ACTIONSW lpFailureActions
= (LPSERVICE_FAILURE_ACTIONSW
)lpBuffer
;
5542 LPWSTR lpStr
= NULL
;
5544 /* Query value length */
5545 dwError
= RegQueryValueExW(hServiceKey
,
5551 if (dwError
!= ERROR_SUCCESS
&&
5552 dwError
!= ERROR_MORE_DATA
&&
5553 dwError
!= ERROR_FILE_NOT_FOUND
)
5556 dwRequiredSize
= (dwType
== REG_BINARY
) ? max(sizeof(SERVICE_FAILURE_ACTIONSW
), dwRequiredSize
)
5557 : sizeof(SERVICE_FAILURE_ACTIONSW
);
5559 /* Get the strings */
5560 ScmReadString(hServiceKey
,
5564 ScmReadString(hServiceKey
,
5568 if (lpRebootMessage
)
5569 dwRequiredSize
+= (DWORD
)((wcslen(lpRebootMessage
) + 1) * sizeof(WCHAR
));
5571 if (lpFailureCommand
)
5572 dwRequiredSize
+= (DWORD
)((wcslen(lpFailureCommand
) + 1) * sizeof(WCHAR
));
5574 if (cbBufSize
< dwRequiredSize
)
5576 *pcbBytesNeeded
= dwRequiredSize
;
5577 dwError
= ERROR_INSUFFICIENT_BUFFER
;
5581 /* Now we can fill the buffer */
5582 if (dwError
!= ERROR_FILE_NOT_FOUND
&& dwType
== REG_BINARY
)
5584 dwError
= RegQueryValueExW(hServiceKey
,
5588 (LPBYTE
)lpFailureActions
,
5590 if (dwError
!= ERROR_SUCCESS
&& dwError
!= ERROR_FILE_NOT_FOUND
)
5593 if (dwRequiredSize
< sizeof(SERVICE_FAILURE_ACTIONSW
))
5594 dwRequiredSize
= sizeof(SERVICE_FAILURE_ACTIONSW
);
5599 * The value of the error doesn't really matter, the only
5600 * important thing is that it must be != ERROR_SUCCESS .
5602 dwError
= ERROR_INVALID_DATA
;
5605 if (dwError
== ERROR_SUCCESS
)
5607 lpFailureActions
->cActions
= min(lpFailureActions
->cActions
, (dwRequiredSize
- sizeof(SERVICE_FAILURE_ACTIONSW
)) / sizeof(SC_ACTION
));
5609 /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */
5610 lpFailureActions
->lpsaActions
= (lpFailureActions
->cActions
> 0 ? (LPSC_ACTION
)(ULONG_PTR
)sizeof(SERVICE_FAILURE_ACTIONSW
) : NULL
);
5612 lpStr
= (LPWSTR
)((ULONG_PTR
)(lpFailureActions
+ 1) + lpFailureActions
->cActions
* sizeof(SC_ACTION
));
5616 lpFailureActions
->dwResetPeriod
= 0;
5617 lpFailureActions
->cActions
= 0;
5618 lpFailureActions
->lpsaActions
= NULL
;
5619 lpStr
= (LPWSTR
)(lpFailureActions
+ 1);
5622 lpFailureActions
->lpRebootMsg
= NULL
;
5623 lpFailureActions
->lpCommand
= NULL
;
5625 if (lpRebootMessage
)
5627 wcscpy(lpStr
, lpRebootMessage
);
5628 lpFailureActions
->lpRebootMsg
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5629 lpStr
+= wcslen(lpStr
) + 1;
5632 if (lpFailureCommand
)
5634 wcscpy(lpStr
, lpFailureCommand
);
5635 lpFailureActions
->lpCommand
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpFailureActions
);
5636 /* lpStr += wcslen(lpStr) + 1; */
5639 dwError
= ERROR_SUCCESS
;
5643 /* Unlock the service database */
5644 ScmUnlockDatabase();
5646 if (lpDescription
!= NULL
)
5647 HeapFree(GetProcessHeap(), 0, lpDescription
);
5649 if (lpRebootMessage
!= NULL
)
5650 HeapFree(GetProcessHeap(), 0, lpRebootMessage
);
5652 if (lpFailureCommand
!= NULL
)
5653 HeapFree(GetProcessHeap(), 0, lpFailureCommand
);
5655 if (hServiceKey
!= NULL
)
5656 RegCloseKey(hServiceKey
);
5658 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError
);
5665 DWORD
RQueryServiceStatusEx(
5666 SC_RPC_HANDLE hService
,
5667 SC_STATUS_TYPE InfoLevel
,
5670 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
5672 LPSERVICE_STATUS_PROCESS lpStatus
;
5673 PSERVICE_HANDLE hSvc
;
5676 DPRINT("RQueryServiceStatusEx() called\n");
5679 return ERROR_SHUTDOWN_IN_PROGRESS
;
5681 if (InfoLevel
!= SC_STATUS_PROCESS_INFO
)
5682 return ERROR_INVALID_LEVEL
;
5684 *pcbBytesNeeded
= sizeof(SERVICE_STATUS_PROCESS
);
5686 if (cbBufSize
< sizeof(SERVICE_STATUS_PROCESS
))
5687 return ERROR_INSUFFICIENT_BUFFER
;
5689 hSvc
= ScmGetServiceFromHandle(hService
);
5692 DPRINT1("Invalid service handle!\n");
5693 return ERROR_INVALID_HANDLE
;
5696 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
5697 SERVICE_QUERY_STATUS
))
5699 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
5700 return ERROR_ACCESS_DENIED
;
5703 lpService
= hSvc
->ServiceEntry
;
5704 if (lpService
== NULL
)
5706 DPRINT("lpService == NULL!\n");
5707 return ERROR_INVALID_HANDLE
;
5710 /* Lock the service database shared */
5711 ScmLockDatabaseShared();
5713 lpStatus
= (LPSERVICE_STATUS_PROCESS
)lpBuffer
;
5715 /* Return service status information */
5716 RtlCopyMemory(lpStatus
,
5718 sizeof(SERVICE_STATUS
));
5720 lpStatus
->dwProcessId
= (lpService
->lpImage
!= NULL
) ? lpService
->lpImage
->dwProcessId
: 0; /* FIXME */
5721 lpStatus
->dwServiceFlags
= 0; /* FIXME */
5723 /* Unlock the service database */
5724 ScmUnlockDatabase();
5726 return ERROR_SUCCESS
;
5731 DWORD
REnumServicesStatusExA(
5732 SC_RPC_HANDLE hSCManager
,
5733 SC_ENUM_TYPE InfoLevel
,
5734 DWORD dwServiceType
,
5735 DWORD dwServiceState
,
5738 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
5739 LPBOUNDED_DWORD_256K lpServicesReturned
,
5740 LPBOUNDED_DWORD_256K lpResumeIndex
,
5741 LPCSTR pszGroupName
)
5743 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrW
= NULL
;
5744 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrIncrW
;
5745 LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtrA
= NULL
;
5746 LPWSTR lpStringPtrW
;
5748 LPWSTR pszGroupNameW
= NULL
;
5750 DWORD dwServiceCount
;
5752 DPRINT("REnumServicesStatusExA() called\n");
5756 pszGroupNameW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, (strlen(pszGroupName
) + 1) * sizeof(WCHAR
));
5759 DPRINT("Failed to allocate buffer!\n");
5760 return ERROR_NOT_ENOUGH_MEMORY
;
5763 MultiByteToWideChar(CP_ACP
,
5768 (int)(strlen(pszGroupName
) + 1));
5771 if ((cbBufSize
> 0) && (lpBuffer
))
5773 lpStatusPtrW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, cbBufSize
);
5776 DPRINT("Failed to allocate buffer!\n");
5777 return ERROR_NOT_ENOUGH_MEMORY
;
5781 dwError
= REnumServicesStatusExW(hSCManager
,
5785 (LPBYTE
)lpStatusPtrW
,
5792 /* if no services were returned then we are Done */
5793 if (*lpServicesReturned
== 0)
5796 lpStatusPtrIncrW
= lpStatusPtrW
;
5797 lpStatusPtrA
= (LPENUM_SERVICE_STATUS_PROCESSA
)lpBuffer
;
5798 lpStringPtrA
= (LPSTR
)((ULONG_PTR
)lpBuffer
+
5799 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUS_PROCESSA
));
5800 lpStringPtrW
= (LPWSTR
)((ULONG_PTR
)lpStatusPtrW
+
5801 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUS_PROCESSW
));
5803 for (dwServiceCount
= 0; dwServiceCount
< *lpServicesReturned
; dwServiceCount
++)
5805 /* Copy the service name */
5806 WideCharToMultiByte(CP_ACP
,
5811 (int)wcslen(lpStringPtrW
),
5815 lpStatusPtrA
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
5816 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
5817 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
5819 /* Copy the display name */
5820 WideCharToMultiByte(CP_ACP
,
5825 (int)wcslen(lpStringPtrW
),
5829 lpStatusPtrA
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
5830 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
5831 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
5833 /* Copy the status information */
5834 memcpy(&lpStatusPtrA
->ServiceStatusProcess
,
5835 &lpStatusPtrIncrW
->ServiceStatusProcess
,
5836 sizeof(SERVICE_STATUS
));
5838 lpStatusPtrA
->ServiceStatusProcess
.dwProcessId
= lpStatusPtrIncrW
->ServiceStatusProcess
.dwProcessId
; /* FIXME */
5839 lpStatusPtrA
->ServiceStatusProcess
.dwServiceFlags
= 0; /* FIXME */
5847 HeapFree(GetProcessHeap(), 0, pszGroupNameW
);
5850 HeapFree(GetProcessHeap(), 0, lpStatusPtrW
);
5852 DPRINT("REnumServicesStatusExA() done (Error %lu)\n", dwError
);
5859 DWORD
REnumServicesStatusExW(
5860 SC_RPC_HANDLE hSCManager
,
5861 SC_ENUM_TYPE InfoLevel
,
5862 DWORD dwServiceType
,
5863 DWORD dwServiceState
,
5866 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
5867 LPBOUNDED_DWORD_256K lpServicesReturned
,
5868 LPBOUNDED_DWORD_256K lpResumeIndex
,
5869 LPCWSTR pszGroupName
)
5871 PMANAGER_HANDLE hManager
;
5873 DWORD dwError
= ERROR_SUCCESS
;
5874 PLIST_ENTRY ServiceEntry
;
5875 PSERVICE CurrentService
;
5877 DWORD dwRequiredSize
;
5878 DWORD dwServiceCount
;
5880 DWORD dwLastResumeCount
= 0;
5881 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr
;
5884 DPRINT("REnumServicesStatusExW() called\n");
5887 return ERROR_SHUTDOWN_IN_PROGRESS
;
5889 if (InfoLevel
!= SC_ENUM_PROCESS_INFO
)
5890 return ERROR_INVALID_LEVEL
;
5892 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
5893 if (hManager
== NULL
)
5895 DPRINT1("Invalid service manager handle!\n");
5896 return ERROR_INVALID_HANDLE
;
5899 *pcbBytesNeeded
= 0;
5900 *lpServicesReturned
= 0;
5902 if ((dwServiceType
== 0) ||
5903 ((dwServiceType
& ~SERVICE_TYPE_ALL
) != 0))
5905 DPRINT("Not a valid Service Type!\n");
5906 return ERROR_INVALID_PARAMETER
;
5909 if ((dwServiceState
== 0) ||
5910 ((dwServiceState
& ~SERVICE_STATE_ALL
) != 0))
5912 DPRINT("Not a valid Service State!\n");
5913 return ERROR_INVALID_PARAMETER
;
5916 /* Check access rights */
5917 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
5918 SC_MANAGER_ENUMERATE_SERVICE
))
5920 DPRINT("Insufficient access rights! 0x%lx\n",
5921 hManager
->Handle
.DesiredAccess
);
5922 return ERROR_ACCESS_DENIED
;
5926 dwLastResumeCount
= *lpResumeIndex
;
5928 /* Lock the service database shared */
5929 ScmLockDatabaseShared();
5931 lpService
= ScmGetServiceEntryByResumeCount(dwLastResumeCount
);
5932 if (lpService
== NULL
)
5934 dwError
= ERROR_SUCCESS
;
5941 for (ServiceEntry
= &lpService
->ServiceListEntry
;
5942 ServiceEntry
!= &ServiceListHead
;
5943 ServiceEntry
= ServiceEntry
->Flink
)
5945 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
5949 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
5952 dwState
= SERVICE_ACTIVE
;
5953 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
5954 dwState
= SERVICE_INACTIVE
;
5956 if ((dwState
& dwServiceState
) == 0)
5961 if (*pszGroupName
== 0)
5963 if (CurrentService
->lpGroup
!= NULL
)
5968 if ((CurrentService
->lpGroup
== NULL
) ||
5969 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
5974 dwSize
= sizeof(ENUM_SERVICE_STATUS_PROCESSW
) +
5975 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
5976 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
5978 if (dwRequiredSize
+ dwSize
<= cbBufSize
)
5980 DPRINT("Service name: %S fit\n", CurrentService
->lpServiceName
);
5981 dwRequiredSize
+= dwSize
;
5983 dwLastResumeCount
= CurrentService
->dwResumeCount
;
5987 DPRINT("Service name: %S no fit\n", CurrentService
->lpServiceName
);
5993 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize
);
5994 DPRINT("dwServiceCount: %lu\n", dwServiceCount
);
5997 ServiceEntry
!= &ServiceListHead
;
5998 ServiceEntry
= ServiceEntry
->Flink
)
6000 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
6004 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
6007 dwState
= SERVICE_ACTIVE
;
6008 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
6009 dwState
= SERVICE_INACTIVE
;
6011 if ((dwState
& dwServiceState
) == 0)
6016 if (*pszGroupName
== 0)
6018 if (CurrentService
->lpGroup
!= NULL
)
6023 if ((CurrentService
->lpGroup
== NULL
) ||
6024 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
6029 dwRequiredSize
+= (sizeof(ENUM_SERVICE_STATUS_PROCESSW
) +
6030 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
6031 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
)));
6033 dwError
= ERROR_MORE_DATA
;
6036 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize
);
6039 *lpResumeIndex
= dwLastResumeCount
;
6041 *lpServicesReturned
= dwServiceCount
;
6042 *pcbBytesNeeded
= dwRequiredSize
;
6044 /* If there was no services that matched */
6045 if ((!dwServiceCount
) && (dwError
!= ERROR_MORE_DATA
))
6047 dwError
= ERROR_SERVICE_DOES_NOT_EXIST
;
6051 lpStatusPtr
= (LPENUM_SERVICE_STATUS_PROCESSW
)lpBuffer
;
6052 lpStringPtr
= (LPWSTR
)((ULONG_PTR
)lpBuffer
+
6053 dwServiceCount
* sizeof(ENUM_SERVICE_STATUS_PROCESSW
));
6056 for (ServiceEntry
= &lpService
->ServiceListEntry
;
6057 ServiceEntry
!= &ServiceListHead
;
6058 ServiceEntry
= ServiceEntry
->Flink
)
6060 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
6064 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
6067 dwState
= SERVICE_ACTIVE
;
6068 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
6069 dwState
= SERVICE_INACTIVE
;
6071 if ((dwState
& dwServiceState
) == 0)
6076 if (*pszGroupName
== 0)
6078 if (CurrentService
->lpGroup
!= NULL
)
6083 if ((CurrentService
->lpGroup
== NULL
) ||
6084 _wcsicmp(pszGroupName
, CurrentService
->lpGroup
->lpGroupName
) != 0)
6089 dwSize
= sizeof(ENUM_SERVICE_STATUS_PROCESSW
) +
6090 (DWORD
)((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
6091 (DWORD
)((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
6093 if (dwRequiredSize
+ dwSize
<= cbBufSize
)
6095 /* Copy the service name */
6097 CurrentService
->lpServiceName
);
6098 lpStatusPtr
->lpServiceName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
6099 lpStringPtr
+= (wcslen(CurrentService
->lpServiceName
) + 1);
6101 /* Copy the display name */
6103 CurrentService
->lpDisplayName
);
6104 lpStatusPtr
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
6105 lpStringPtr
+= (wcslen(CurrentService
->lpDisplayName
) + 1);
6107 /* Copy the status information */
6108 memcpy(&lpStatusPtr
->ServiceStatusProcess
,
6109 &CurrentService
->Status
,
6110 sizeof(SERVICE_STATUS
));
6111 lpStatusPtr
->ServiceStatusProcess
.dwProcessId
=
6112 (CurrentService
->lpImage
!= NULL
) ? CurrentService
->lpImage
->dwProcessId
: 0; /* FIXME */
6113 lpStatusPtr
->ServiceStatusProcess
.dwServiceFlags
= 0; /* FIXME */
6116 dwRequiredSize
+= dwSize
;
6126 *pcbBytesNeeded
= 0;
6132 /* Unlock the service database */
6133 ScmUnlockDatabase();
6135 DPRINT("REnumServicesStatusExW() done (Error %lu)\n", dwError
);
6142 DWORD
RSendTSMessage(
6143 handle_t BindingHandle
) /* FIXME */
6146 return ERROR_CALL_NOT_IMPLEMENTED
;
6151 DWORD
RCreateServiceWOW64A(
6152 handle_t BindingHandle
,
6153 LPSTR lpServiceName
,
6154 LPSTR lpDisplayName
,
6155 DWORD dwDesiredAccess
,
6156 DWORD dwServiceType
,
6158 DWORD dwErrorControl
,
6159 LPSTR lpBinaryPathName
,
6160 LPSTR lpLoadOrderGroup
,
6162 LPBYTE lpDependencies
,
6164 LPSTR lpServiceStartName
,
6167 LPSC_RPC_HANDLE lpServiceHandle
)
6170 return ERROR_CALL_NOT_IMPLEMENTED
;
6175 DWORD
RCreateServiceWOW64W(
6176 handle_t BindingHandle
,
6177 LPWSTR lpServiceName
,
6178 LPWSTR lpDisplayName
,
6179 DWORD dwDesiredAccess
,
6180 DWORD dwServiceType
,
6182 DWORD dwErrorControl
,
6183 LPWSTR lpBinaryPathName
,
6184 LPWSTR lpLoadOrderGroup
,
6186 LPBYTE lpDependencies
,
6188 LPWSTR lpServiceStartName
,
6191 LPSC_RPC_HANDLE lpServiceHandle
)
6194 return ERROR_CALL_NOT_IMPLEMENTED
;
6199 DWORD
RQueryServiceTagInfo(
6200 handle_t BindingHandle
) /* FIXME */
6203 return ERROR_CALL_NOT_IMPLEMENTED
;
6208 DWORD
RNotifyServiceStatusChange(
6209 SC_RPC_HANDLE hService
,
6210 SC_RPC_NOTIFY_PARAMS NotifyParams
,
6211 GUID
*pClientProcessGuid
,
6212 GUID
*pSCMProcessGuid
,
6213 PBOOL pfCreateRemoteQueue
,
6214 LPSC_NOTIFY_RPC_HANDLE phNotify
)
6217 return ERROR_CALL_NOT_IMPLEMENTED
;
6222 DWORD
RGetNotifyResults(
6223 SC_NOTIFY_RPC_HANDLE hNotify
,
6224 PSC_RPC_NOTIFY_PARAMS_LIST
*ppNotifyParams
)
6227 return ERROR_CALL_NOT_IMPLEMENTED
;
6232 DWORD
RCloseNotifyHandle(
6233 LPSC_NOTIFY_RPC_HANDLE phNotify
,
6237 return ERROR_CALL_NOT_IMPLEMENTED
;
6242 DWORD
RControlServiceExA(
6243 SC_RPC_HANDLE hService
,
6248 return ERROR_CALL_NOT_IMPLEMENTED
;
6253 DWORD
RControlServiceExW(
6254 SC_RPC_HANDLE hService
,
6259 return ERROR_CALL_NOT_IMPLEMENTED
;
6264 DWORD
RSendPnPMessage(
6265 handle_t BindingHandle
) /* FIXME */
6268 return ERROR_CALL_NOT_IMPLEMENTED
;
6273 DWORD
RValidatePnPService(
6274 handle_t BindingHandle
) /* FIXME */
6277 return ERROR_CALL_NOT_IMPLEMENTED
;
6282 DWORD
ROpenServiceStatusHandle(
6283 handle_t BindingHandle
) /* FIXME */
6286 return ERROR_CALL_NOT_IMPLEMENTED
;
6292 handle_t BindingHandle
) /* FIXME */
6295 return ERROR_CALL_NOT_IMPLEMENTED
;
6299 void __RPC_FAR
* __RPC_USER
midl_user_allocate(SIZE_T len
)
6301 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
);
6305 void __RPC_USER
midl_user_free(void __RPC_FAR
* ptr
)
6307 HeapFree(GetProcessHeap(), 0, ptr
);
6311 void __RPC_USER
SC_RPC_HANDLE_rundown(SC_RPC_HANDLE hSCObject
)
6313 /* Close the handle */
6314 RCloseServiceHandle(&hSCObject
);
6318 void __RPC_USER
SC_RPC_LOCK_rundown(SC_RPC_LOCK Lock
)
6320 /* Unlock the database */
6321 RUnlockServiceDatabase(&Lock
);
6325 void __RPC_USER
SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE hNotify
)