2 * PROJECT: ReactOS Service Control Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/system/services/database.c
5 * PURPOSE: Database control interface
6 * COPYRIGHT: Copyright 2002-2006 Eric Kohl
7 * Copyright 2006 Hervé Poussineau <hpoussin@reactos.org>
8 * Copyright 2007 Ged Murphy <gedmurphy@reactos.org>
9 * Gregor Brunmar <gregor.brunmar@home.se>
13 /* INCLUDES *****************************************************************/
20 #include <reactos/undocuser.h>
26 /* GLOBALS *******************************************************************/
28 LIST_ENTRY ImageListHead
;
29 LIST_ENTRY ServiceListHead
;
31 static RTL_RESOURCE DatabaseLock
;
32 static DWORD ResumeCount
= 1;
33 static DWORD NoInteractiveServices
= 0;
34 static DWORD ServiceTag
= 0;
36 /* The critical section synchronizes service control requests */
37 static CRITICAL_SECTION ControlServiceCriticalSection
;
38 static DWORD PipeTimeout
= 30000; /* 30 Seconds */
41 /* FUNCTIONS *****************************************************************/
44 ScmCreateNewControlPipe(PSERVICE_IMAGE pServiceImage
)
46 WCHAR szControlPipeName
[MAX_PATH
+ 1];
47 SECURITY_ATTRIBUTES SecurityAttributes
;
48 HKEY hServiceCurrentKey
= INVALID_HANDLE_VALUE
;
49 DWORD ServiceCurrent
= 0;
54 /* Get the service number */
55 /* TODO: Create registry entry with correct write access */
56 dwError
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
,
57 L
"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL
,
63 if (dwError
!= ERROR_SUCCESS
)
65 DPRINT1("RegCreateKeyEx() failed with error %lu\n", dwError
);
69 if (KeyDisposition
== REG_OPENED_EXISTING_KEY
)
71 dwKeySize
= sizeof(DWORD
);
72 dwError
= RegQueryValueExW(hServiceCurrentKey
,
73 L
"", 0, NULL
, (BYTE
*)&ServiceCurrent
, &dwKeySize
);
75 if (dwError
!= ERROR_SUCCESS
)
77 RegCloseKey(hServiceCurrentKey
);
78 DPRINT1("RegQueryValueEx() failed with error %lu\n", dwError
);
85 dwError
= RegSetValueExW(hServiceCurrentKey
, L
"", 0, REG_DWORD
, (BYTE
*)&ServiceCurrent
, sizeof(ServiceCurrent
));
87 RegCloseKey(hServiceCurrentKey
);
89 if (dwError
!= ERROR_SUCCESS
)
91 DPRINT1("RegSetValueExW() failed (Error %lu)\n", dwError
);
95 /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
96 StringCchPrintfW(szControlPipeName
, ARRAYSIZE(szControlPipeName
),
97 L
"\\\\.\\pipe\\net\\NtControlPipe%lu", ServiceCurrent
);
99 DPRINT("PipeName: %S\n", szControlPipeName
);
101 SecurityAttributes
.nLength
= sizeof(SecurityAttributes
);
102 SecurityAttributes
.lpSecurityDescriptor
= pPipeSD
;
103 SecurityAttributes
.bInheritHandle
= FALSE
;
105 pServiceImage
->hControlPipe
= CreateNamedPipeW(szControlPipeName
,
106 PIPE_ACCESS_DUPLEX
| FILE_FLAG_OVERLAPPED
,
107 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
,
112 &SecurityAttributes
);
113 DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName
);
114 if (pServiceImage
->hControlPipe
== INVALID_HANDLE_VALUE
)
116 DPRINT1("Failed to create control pipe!\n");
117 return GetLastError();
120 return ERROR_SUCCESS
;
124 static PSERVICE_IMAGE
125 ScmGetServiceImageByImagePath(LPWSTR lpImagePath
)
127 PLIST_ENTRY ImageEntry
;
128 PSERVICE_IMAGE CurrentImage
;
130 DPRINT("ScmGetServiceImageByImagePath(%S) called\n", lpImagePath
);
132 ImageEntry
= ImageListHead
.Flink
;
133 while (ImageEntry
!= &ImageListHead
)
135 CurrentImage
= CONTAINING_RECORD(ImageEntry
,
138 if (_wcsicmp(CurrentImage
->pszImagePath
, lpImagePath
) == 0)
140 DPRINT("Found image: '%S'\n", CurrentImage
->pszImagePath
);
144 ImageEntry
= ImageEntry
->Flink
;
147 DPRINT("Couldn't find a matching image\n");
155 ScmGetServiceNameFromTag(IN PTAG_INFO_NAME_FROM_TAG_IN_PARAMS InParams
,
156 OUT PTAG_INFO_NAME_FROM_TAG_OUT_PARAMS
*OutParams
)
158 PLIST_ENTRY ServiceEntry
;
159 PSERVICE CurrentService
;
160 PSERVICE_IMAGE CurrentImage
;
161 PTAG_INFO_NAME_FROM_TAG_OUT_PARAMS OutBuffer
= NULL
;
164 /* Lock the database */
165 ScmLockDatabaseExclusive();
167 /* Find the matching service */
168 ServiceEntry
= ServiceListHead
.Flink
;
169 while (ServiceEntry
!= &ServiceListHead
)
171 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
175 /* We must match the tag */
176 if (CurrentService
->dwTag
== InParams
->dwTag
&&
177 CurrentService
->lpImage
!= NULL
)
179 CurrentImage
= CurrentService
->lpImage
;
180 /* And matching the PID */
181 if (CurrentImage
->dwProcessId
== InParams
->dwPid
)
187 ServiceEntry
= ServiceEntry
->Flink
;
191 if (ServiceEntry
== &ServiceListHead
)
193 dwError
= ERROR_RETRY
;
197 /* Allocate the output buffer */
198 OutBuffer
= MIDL_user_allocate(sizeof(TAG_INFO_NAME_FROM_TAG_OUT_PARAMS
));
199 if (OutBuffer
== NULL
)
201 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
205 /* And the buffer for the name */
206 OutBuffer
->pszName
= MIDL_user_allocate(wcslen(CurrentService
->lpServiceName
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
207 if (OutBuffer
->pszName
== NULL
)
209 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
213 /* Fill in output data */
214 wcscpy(OutBuffer
->pszName
, CurrentService
->lpServiceName
);
215 OutBuffer
->TagType
= TagTypeService
;
218 *OutParams
= OutBuffer
;
219 dwError
= ERROR_SUCCESS
;
223 /* Unlock database */
226 /* If failure, free allocated memory */
227 if (dwError
!= ERROR_SUCCESS
)
229 if (OutBuffer
!= NULL
)
231 MIDL_user_free(OutBuffer
);
235 /* Return error/success */
242 ScmIsSameServiceAccount(
243 _In_ PCWSTR pszAccountName1
,
244 _In_ PCWSTR pszAccountName2
)
246 if (pszAccountName1
== NULL
&&
247 pszAccountName2
== NULL
)
250 if (pszAccountName1
== NULL
&&
251 pszAccountName2
!= NULL
&&
252 _wcsicmp(pszAccountName2
, L
"LocalSystem") == 0)
255 if (pszAccountName1
!= NULL
&&
256 pszAccountName2
== NULL
&&
257 _wcsicmp(pszAccountName1
, L
"LocalSystem") == 0)
260 if (pszAccountName1
!= NULL
&&
261 pszAccountName2
!= NULL
&&
262 _wcsicmp(pszAccountName1
, pszAccountName2
) == 0)
271 ScmIsLocalSystemAccount(
272 _In_ PCWSTR pszAccountName
)
274 if (pszAccountName
== NULL
||
275 _wcsicmp(pszAccountName
, L
"LocalSystem") == 0)
284 ScmEnableBackupRestorePrivileges(
288 PTOKEN_PRIVILEGES pTokenPrivileges
= NULL
;
292 DPRINT("ScmEnableBackupRestorePrivileges(%p %d)\n", hToken
, bEnable
);
294 dwSize
= sizeof(TOKEN_PRIVILEGES
) + 2 * sizeof(LUID_AND_ATTRIBUTES
);
295 pTokenPrivileges
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwSize
);
296 if (pTokenPrivileges
== NULL
)
298 DPRINT1("Failed to allocate the privilege buffer!\n");
302 pTokenPrivileges
->PrivilegeCount
= 2;
303 pTokenPrivileges
->Privileges
[0].Luid
.LowPart
= SE_BACKUP_PRIVILEGE
;
304 pTokenPrivileges
->Privileges
[0].Luid
.HighPart
= 0;
305 pTokenPrivileges
->Privileges
[0].Attributes
= (bEnable
? SE_PRIVILEGE_ENABLED
: 0);
306 pTokenPrivileges
->Privileges
[1].Luid
.LowPart
= SE_RESTORE_PRIVILEGE
;
307 pTokenPrivileges
->Privileges
[1].Luid
.HighPart
= 0;
308 pTokenPrivileges
->Privileges
[1].Attributes
= (bEnable
? SE_PRIVILEGE_ENABLED
: 0);
310 bRet
= AdjustTokenPrivileges(hToken
, FALSE
, pTokenPrivileges
, 0, NULL
, NULL
);
313 DPRINT1("AdjustTokenPrivileges() failed with error %lu\n", GetLastError());
315 else if (GetLastError() == ERROR_NOT_ALL_ASSIGNED
)
317 DPRINT1("AdjustTokenPrivileges() succeeded, but with not all privileges assigned\n");
322 if (pTokenPrivileges
!= NULL
)
323 HeapFree(GetProcessHeap(), 0, pTokenPrivileges
);
332 IN PSERVICE pService
,
333 IN PSERVICE_IMAGE pImage
)
335 PROFILEINFOW ProfileInfo
;
336 PWSTR pszUserName
= NULL
;
337 PWSTR pszDomainName
= NULL
;
338 PWSTR pszPassword
= NULL
;
340 DWORD dwError
= ERROR_SUCCESS
;
342 DPRINT("ScmLogonService(%p %p)\n", pService
, pImage
);
343 DPRINT("Service %S\n", pService
->lpServiceName
);
345 if (ScmIsLocalSystemAccount(pImage
->pszAccountName
))
346 return ERROR_SUCCESS
;
348 /* Get the user and domain names */
349 ptr
= wcschr(pImage
->pszAccountName
, L
'\\');
353 pszUserName
= ptr
+ 1;
354 pszDomainName
= pImage
->pszAccountName
;
358 // ERROR_INVALID_SERVICE_ACCOUNT
359 pszUserName
= pImage
->pszAccountName
;
360 pszDomainName
= NULL
;
363 /* Build the service 'password' */
364 pszPassword
= HeapAlloc(GetProcessHeap(),
366 (wcslen(pService
->lpServiceName
) + 5) * sizeof(WCHAR
));
367 if (pszPassword
== NULL
)
369 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
373 wcscpy(pszPassword
, L
"_SC_");
374 wcscat(pszPassword
, pService
->lpServiceName
);
376 DPRINT("Domain: %S User: %S Password: %S\n", pszDomainName
, pszUserName
, pszPassword
);
378 /* Do the service logon */
379 if (!LogonUserW(pszUserName
,
382 LOGON32_LOGON_SERVICE
,
383 LOGON32_PROVIDER_DEFAULT
,
386 dwError
= GetLastError();
387 DPRINT1("LogonUserW() failed (Error %lu)\n", dwError
);
389 /* Normalize the returned error */
390 dwError
= ERROR_SERVICE_LOGON_FAILED
;
394 /* Load the user profile; the per-user environment variables are thus correctly initialized */
395 ZeroMemory(&ProfileInfo
, sizeof(ProfileInfo
));
396 ProfileInfo
.dwSize
= sizeof(ProfileInfo
);
397 ProfileInfo
.dwFlags
= PI_NOUI
;
398 ProfileInfo
.lpUserName
= pszUserName
;
399 // ProfileInfo.lpProfilePath = NULL;
400 // ProfileInfo.lpDefaultPath = NULL;
401 // ProfileInfo.lpServerName = NULL;
402 // ProfileInfo.lpPolicyPath = NULL;
403 // ProfileInfo.hProfile = NULL;
405 ScmEnableBackupRestorePrivileges(pImage
->hToken
, TRUE
);
406 if (!LoadUserProfileW(pImage
->hToken
, &ProfileInfo
))
407 dwError
= GetLastError();
408 ScmEnableBackupRestorePrivileges(pImage
->hToken
, FALSE
);
410 if (dwError
!= ERROR_SUCCESS
)
412 DPRINT1("LoadUserProfileW() failed (Error %lu)\n", dwError
);
416 pImage
->hProfile
= ProfileInfo
.hProfile
;
419 if (pszPassword
!= NULL
)
420 HeapFree(GetProcessHeap(), 0, pszPassword
);
430 ScmCreateOrReferenceServiceImage(PSERVICE pService
)
432 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
433 UNICODE_STRING ImagePath
;
434 UNICODE_STRING ObjectName
;
435 PSERVICE_IMAGE pServiceImage
= NULL
;
437 DWORD dwError
= ERROR_SUCCESS
;
441 DPRINT("ScmCreateOrReferenceServiceImage(%p)\n", pService
);
443 RtlInitUnicodeString(&ImagePath
, NULL
);
444 RtlInitUnicodeString(&ObjectName
, NULL
);
446 /* Get service data */
447 RtlZeroMemory(&QueryTable
,
450 QueryTable
[0].Name
= L
"ImagePath";
451 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
452 QueryTable
[0].EntryContext
= &ImagePath
;
453 QueryTable
[1].Name
= L
"ObjectName";
454 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
455 QueryTable
[1].EntryContext
= &ObjectName
;
457 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
458 pService
->lpServiceName
,
462 if (!NT_SUCCESS(Status
))
464 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
465 return RtlNtStatusToDosError(Status
);
468 DPRINT("ImagePath: '%wZ'\n", &ImagePath
);
469 DPRINT("ObjectName: '%wZ'\n", &ObjectName
);
471 pServiceImage
= ScmGetServiceImageByImagePath(ImagePath
.Buffer
);
472 if (pServiceImage
== NULL
)
474 dwRecordSize
= sizeof(SERVICE_IMAGE
) +
475 ImagePath
.Length
+ sizeof(WCHAR
) +
476 ((ObjectName
.Length
!= 0) ? (ObjectName
.Length
+ sizeof(WCHAR
)) : 0);
478 /* Create a new service image */
479 pServiceImage
= HeapAlloc(GetProcessHeap(),
482 if (pServiceImage
== NULL
)
484 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
488 pServiceImage
->dwImageRunCount
= 1;
489 pServiceImage
->hControlPipe
= INVALID_HANDLE_VALUE
;
490 pServiceImage
->hProcess
= INVALID_HANDLE_VALUE
;
492 pString
= (PWSTR
)((INT_PTR
)pServiceImage
+ sizeof(SERVICE_IMAGE
));
494 /* Set the image path */
495 pServiceImage
->pszImagePath
= pString
;
496 wcscpy(pServiceImage
->pszImagePath
,
499 /* Set the account name */
500 if (ObjectName
.Length
> 0)
502 pString
= pString
+ wcslen(pString
) + 1;
504 pServiceImage
->pszAccountName
= pString
;
505 wcscpy(pServiceImage
->pszAccountName
,
510 dwError
= ScmLogonService(pService
, pServiceImage
);
511 if (dwError
!= ERROR_SUCCESS
)
513 DPRINT1("ScmLogonService() failed (Error %lu)\n", dwError
);
515 /* Release the service image */
516 HeapFree(GetProcessHeap(), 0, pServiceImage
);
521 /* Create the control pipe */
522 dwError
= ScmCreateNewControlPipe(pServiceImage
);
523 if (dwError
!= ERROR_SUCCESS
)
525 DPRINT1("ScmCreateNewControlPipe() failed (Error %lu)\n", dwError
);
527 /* Unload the user profile */
528 if (pServiceImage
->hProfile
!= NULL
)
530 ScmEnableBackupRestorePrivileges(pServiceImage
->hToken
, TRUE
);
531 UnloadUserProfile(pServiceImage
->hToken
, pServiceImage
->hProfile
);
532 ScmEnableBackupRestorePrivileges(pServiceImage
->hToken
, FALSE
);
535 /* Close the logon token */
536 if (pServiceImage
->hToken
!= NULL
)
537 CloseHandle(pServiceImage
->hToken
);
539 /* Release the service image */
540 HeapFree(GetProcessHeap(), 0, pServiceImage
);
545 /* FIXME: Add more initialization code here */
548 /* Append service record */
549 InsertTailList(&ImageListHead
,
550 &pServiceImage
->ImageListEntry
);
554 // if ((lpService->Status.dwServiceType & SERVICE_WIN32_SHARE_PROCESS) == 0)
556 /* Fail if services in an image use different accounts */
557 if (!ScmIsSameServiceAccount(pServiceImage
->pszAccountName
, ObjectName
.Buffer
))
559 dwError
= ERROR_DIFFERENT_SERVICE_ACCOUNT
;
563 /* Increment the run counter */
564 pServiceImage
->dwImageRunCount
++;
567 DPRINT("pServiceImage->pszImagePath: %S\n", pServiceImage
->pszImagePath
);
568 DPRINT("pServiceImage->pszAccountName: %S\n", pServiceImage
->pszAccountName
);
569 DPRINT("pServiceImage->dwImageRunCount: %lu\n", pServiceImage
->dwImageRunCount
);
571 /* Link the service image to the service */
572 pService
->lpImage
= pServiceImage
;
575 RtlFreeUnicodeString(&ObjectName
);
576 RtlFreeUnicodeString(&ImagePath
);
578 DPRINT("ScmCreateOrReferenceServiceImage() done (Error: %lu)\n", dwError
);
585 ScmRemoveServiceImage(PSERVICE_IMAGE pServiceImage
)
587 DPRINT1("ScmRemoveServiceImage() called\n");
589 /* FIXME: Terminate the process */
591 /* Remove the service image from the list */
592 RemoveEntryList(&pServiceImage
->ImageListEntry
);
594 /* Close the process handle */
595 if (pServiceImage
->hProcess
!= INVALID_HANDLE_VALUE
)
596 CloseHandle(pServiceImage
->hProcess
);
598 /* Close the control pipe */
599 if (pServiceImage
->hControlPipe
!= INVALID_HANDLE_VALUE
)
600 CloseHandle(pServiceImage
->hControlPipe
);
602 /* Unload the user profile */
603 if (pServiceImage
->hProfile
!= NULL
)
605 ScmEnableBackupRestorePrivileges(pServiceImage
->hToken
, TRUE
);
606 UnloadUserProfile(pServiceImage
->hToken
, pServiceImage
->hProfile
);
607 ScmEnableBackupRestorePrivileges(pServiceImage
->hToken
, FALSE
);
610 /* Close the logon token */
611 if (pServiceImage
->hToken
!= NULL
)
612 CloseHandle(pServiceImage
->hToken
);
614 /* Release the service image */
615 HeapFree(GetProcessHeap(), 0, pServiceImage
);
620 ScmGetServiceEntryByName(LPCWSTR lpServiceName
)
622 PLIST_ENTRY ServiceEntry
;
623 PSERVICE CurrentService
;
625 DPRINT("ScmGetServiceEntryByName() called\n");
627 ServiceEntry
= ServiceListHead
.Flink
;
628 while (ServiceEntry
!= &ServiceListHead
)
630 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
633 if (_wcsicmp(CurrentService
->lpServiceName
, lpServiceName
) == 0)
635 DPRINT("Found service: '%S'\n", CurrentService
->lpServiceName
);
636 return CurrentService
;
639 ServiceEntry
= ServiceEntry
->Flink
;
642 DPRINT("Couldn't find a matching service\n");
649 ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName
)
651 PLIST_ENTRY ServiceEntry
;
652 PSERVICE CurrentService
;
654 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
656 ServiceEntry
= ServiceListHead
.Flink
;
657 while (ServiceEntry
!= &ServiceListHead
)
659 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
662 if (_wcsicmp(CurrentService
->lpDisplayName
, lpDisplayName
) == 0)
664 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
665 return CurrentService
;
668 ServiceEntry
= ServiceEntry
->Flink
;
671 DPRINT("Couldn't find a matching service\n");
678 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount
)
680 PLIST_ENTRY ServiceEntry
;
681 PSERVICE CurrentService
;
683 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
685 ServiceEntry
= ServiceListHead
.Flink
;
686 while (ServiceEntry
!= &ServiceListHead
)
688 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
691 if (CurrentService
->dwResumeCount
> dwResumeCount
)
693 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
694 return CurrentService
;
697 ServiceEntry
= ServiceEntry
->Flink
;
700 DPRINT("Couldn't find a matching service\n");
707 ScmGenerateServiceTag(PSERVICE lpServiceRecord
)
709 /* Check for an overflow */
710 if (ServiceTag
== -1)
712 return ERROR_INVALID_DATA
;
715 /* This is only valid for Win32 services */
716 if (!(lpServiceRecord
->Status
.dwServiceType
& SERVICE_WIN32
))
718 return ERROR_INVALID_PARAMETER
;
721 /* Increment the tag counter and set it */
722 ServiceTag
= ServiceTag
% 0xFFFFFFFF + 1;
723 lpServiceRecord
->dwTag
= ServiceTag
;
725 return ERROR_SUCCESS
;
730 ScmCreateNewServiceRecord(LPCWSTR lpServiceName
,
731 PSERVICE
*lpServiceRecord
,
735 PSERVICE lpService
= NULL
;
737 DPRINT("Service: '%S'\n", lpServiceName
);
739 /* Allocate service entry */
740 lpService
= HeapAlloc(GetProcessHeap(),
742 FIELD_OFFSET(SERVICE
, szServiceName
[wcslen(lpServiceName
) + 1]));
743 if (lpService
== NULL
)
744 return ERROR_NOT_ENOUGH_MEMORY
;
746 *lpServiceRecord
= lpService
;
748 /* Copy service name */
749 wcscpy(lpService
->szServiceName
, lpServiceName
);
750 lpService
->lpServiceName
= lpService
->szServiceName
;
751 lpService
->lpDisplayName
= lpService
->lpServiceName
;
753 /* Set the start type */
754 lpService
->dwStartType
= dwStartType
;
756 /* Set the resume count */
757 lpService
->dwResumeCount
= ResumeCount
++;
759 /* Append service record */
760 InsertTailList(&ServiceListHead
,
761 &lpService
->ServiceListEntry
);
763 /* Initialize the service status */
764 lpService
->Status
.dwServiceType
= dwServiceType
;
765 lpService
->Status
.dwCurrentState
= SERVICE_STOPPED
;
766 lpService
->Status
.dwControlsAccepted
= 0;
767 lpService
->Status
.dwWin32ExitCode
=
768 (dwStartType
== SERVICE_DISABLED
) ? ERROR_SERVICE_DISABLED
: ERROR_SERVICE_NEVER_STARTED
;
769 lpService
->Status
.dwServiceSpecificExitCode
= 0;
770 lpService
->Status
.dwCheckPoint
= 0;
771 lpService
->Status
.dwWaitHint
=
772 (dwServiceType
& SERVICE_DRIVER
) ? 0 : 2000; /* 2 seconds */
774 return ERROR_SUCCESS
;
779 ScmDeleteServiceRecord(PSERVICE lpService
)
781 DPRINT("Deleting Service %S\n", lpService
->lpServiceName
);
783 /* Delete the display name */
784 if (lpService
->lpDisplayName
!= NULL
&&
785 lpService
->lpDisplayName
!= lpService
->lpServiceName
)
786 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
788 /* Dereference the service image */
789 if (lpService
->lpImage
)
791 lpService
->lpImage
->dwImageRunCount
--;
793 if (lpService
->lpImage
->dwImageRunCount
== 0)
795 ScmRemoveServiceImage(lpService
->lpImage
);
796 lpService
->lpImage
= NULL
;
800 /* Decrement the group reference counter */
801 ScmSetServiceGroup(lpService
, NULL
);
803 /* Release the SecurityDescriptor */
804 if (lpService
->pSecurityDescriptor
!= NULL
)
805 HeapFree(GetProcessHeap(), 0, lpService
->pSecurityDescriptor
);
807 /* Remove the Service from the List */
808 RemoveEntryList(&lpService
->ServiceListEntry
);
810 DPRINT("Deleted Service %S\n", lpService
->lpServiceName
);
812 /* Delete the service record */
813 HeapFree(GetProcessHeap(), 0, lpService
);
820 CreateServiceListEntry(LPCWSTR lpServiceName
,
823 PSERVICE lpService
= NULL
;
824 LPWSTR lpDisplayName
= NULL
;
825 LPWSTR lpGroup
= NULL
;
830 DWORD dwErrorControl
;
833 DPRINT("Service: '%S'\n", lpServiceName
);
834 if (*lpServiceName
== L
'{')
835 return ERROR_SUCCESS
;
837 dwSize
= sizeof(DWORD
);
838 dwError
= RegQueryValueExW(hServiceKey
,
842 (LPBYTE
)&dwServiceType
,
844 if (dwError
!= ERROR_SUCCESS
)
845 return ERROR_SUCCESS
;
847 if (((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
848 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
) &&
849 (dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
850 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
851 return ERROR_SUCCESS
;
853 DPRINT("Service type: %lx\n", dwServiceType
);
855 dwSize
= sizeof(DWORD
);
856 dwError
= RegQueryValueExW(hServiceKey
,
860 (LPBYTE
)&dwStartType
,
862 if (dwError
!= ERROR_SUCCESS
)
863 return ERROR_SUCCESS
;
865 DPRINT("Start type: %lx\n", dwStartType
);
867 dwSize
= sizeof(DWORD
);
868 dwError
= RegQueryValueExW(hServiceKey
,
872 (LPBYTE
)&dwErrorControl
,
874 if (dwError
!= ERROR_SUCCESS
)
875 return ERROR_SUCCESS
;
877 DPRINT("Error control: %lx\n", dwErrorControl
);
879 dwError
= RegQueryValueExW(hServiceKey
,
885 if (dwError
!= ERROR_SUCCESS
)
888 DPRINT("Tag: %lx\n", dwTagId
);
890 dwError
= ScmReadString(hServiceKey
,
893 if (dwError
!= ERROR_SUCCESS
)
896 DPRINT("Group: %S\n", lpGroup
);
898 dwError
= ScmReadString(hServiceKey
,
901 if (dwError
!= ERROR_SUCCESS
)
902 lpDisplayName
= NULL
;
904 DPRINT("Display name: %S\n", lpDisplayName
);
906 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
910 if (dwError
!= ERROR_SUCCESS
)
913 lpService
->dwErrorControl
= dwErrorControl
;
914 lpService
->dwTag
= dwTagId
;
918 dwError
= ScmSetServiceGroup(lpService
, lpGroup
);
919 if (dwError
!= ERROR_SUCCESS
)
923 if (lpDisplayName
!= NULL
)
925 lpService
->lpDisplayName
= lpDisplayName
;
926 lpDisplayName
= NULL
;
929 DPRINT("ServiceName: '%S'\n", lpService
->lpServiceName
);
930 if (lpService
->lpGroup
!= NULL
)
932 DPRINT("Group: '%S'\n", lpService
->lpGroup
->lpGroupName
);
934 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
935 lpService
->dwStartType
,
936 lpService
->Status
.dwServiceType
,
938 lpService
->dwErrorControl
);
940 if (ScmIsDeleteFlagSet(hServiceKey
))
941 lpService
->bDeleted
= TRUE
;
943 ScmGenerateServiceTag(lpService
);
945 if (lpService
->Status
.dwServiceType
& SERVICE_WIN32
)
947 dwError
= ScmReadSecurityDescriptor(hServiceKey
,
948 &lpService
->pSecurityDescriptor
);
949 if (dwError
!= ERROR_SUCCESS
)
952 /* Assing the default security descriptor if the security descriptor cannot be read */
953 if (lpService
->pSecurityDescriptor
== NULL
)
955 DPRINT("No security descriptor found! Assign default security descriptor!\n");
956 dwError
= ScmCreateDefaultServiceSD(&lpService
->pSecurityDescriptor
);
957 if (dwError
!= ERROR_SUCCESS
)
960 dwError
= ScmWriteSecurityDescriptor(hServiceKey
,
961 lpService
->pSecurityDescriptor
);
962 if (dwError
!= ERROR_SUCCESS
)
969 HeapFree(GetProcessHeap(), 0, lpGroup
);
971 if (lpDisplayName
!= NULL
)
972 HeapFree(GetProcessHeap(), 0, lpDisplayName
);
974 if (lpService
!= NULL
)
976 ASSERT(lpService
->lpImage
== NULL
);
984 ScmDeleteMarkedServices(VOID
)
986 PLIST_ENTRY ServiceEntry
;
987 PSERVICE CurrentService
;
991 ServiceEntry
= ServiceListHead
.Flink
;
992 while (ServiceEntry
!= &ServiceListHead
)
994 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
996 ServiceEntry
= ServiceEntry
->Flink
;
998 if (CurrentService
->bDeleted
!= FALSE
)
1000 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1001 L
"System\\CurrentControlSet\\Services",
1005 if (dwError
== ERROR_SUCCESS
)
1007 dwError
= ScmDeleteRegKey(hServicesKey
, CurrentService
->lpServiceName
);
1008 RegCloseKey(hServicesKey
);
1009 if (dwError
== ERROR_SUCCESS
)
1011 RemoveEntryList(&CurrentService
->ServiceListEntry
);
1012 HeapFree(GetProcessHeap(), 0, CurrentService
);
1016 if (dwError
!= ERROR_SUCCESS
)
1017 DPRINT1("Delete service failed: %S\n", CurrentService
->lpServiceName
);
1025 ScmGetNoInteractiveServicesValue(VOID
)
1031 lError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1032 L
"SYSTEM\\CurrentControlSet\\Control\\Windows",
1036 if (lError
== ERROR_SUCCESS
)
1038 dwKeySize
= sizeof(NoInteractiveServices
);
1039 lError
= RegQueryValueExW(hKey
,
1040 L
"NoInteractiveServices",
1043 (LPBYTE
)&NoInteractiveServices
,
1051 ScmCreateServiceDatabase(VOID
)
1053 WCHAR szSubKey
[MAX_PATH
];
1057 DWORD dwSubKeyLength
;
1058 FILETIME ftLastChanged
;
1061 DPRINT("ScmCreateServiceDatabase() called\n");
1063 /* Retrieve the NoInteractiveServies value */
1064 ScmGetNoInteractiveServicesValue();
1066 /* Create the service group list */
1067 dwError
= ScmCreateGroupList();
1068 if (dwError
!= ERROR_SUCCESS
)
1071 /* Initialize image and service lists */
1072 InitializeListHead(&ImageListHead
);
1073 InitializeListHead(&ServiceListHead
);
1075 /* Initialize the database lock */
1076 RtlInitializeResource(&DatabaseLock
);
1078 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1079 L
"System\\CurrentControlSet\\Services",
1083 if (dwError
!= ERROR_SUCCESS
)
1089 dwSubKeyLength
= MAX_PATH
;
1090 dwError
= RegEnumKeyExW(hServicesKey
,
1098 if (dwError
== ERROR_SUCCESS
&&
1099 szSubKey
[0] != L
'{')
1101 DPRINT("SubKeyName: '%S'\n", szSubKey
);
1103 dwError
= RegOpenKeyExW(hServicesKey
,
1108 if (dwError
== ERROR_SUCCESS
)
1110 dwError
= CreateServiceListEntry(szSubKey
,
1113 RegCloseKey(hServiceKey
);
1117 if (dwError
!= ERROR_SUCCESS
)
1123 RegCloseKey(hServicesKey
);
1125 /* Wait for the LSA server */
1128 /* Delete services that are marked for delete */
1129 ScmDeleteMarkedServices();
1131 DPRINT("ScmCreateServiceDatabase() done\n");
1133 return ERROR_SUCCESS
;
1138 ScmShutdownServiceDatabase(VOID
)
1140 DPRINT("ScmShutdownServiceDatabase() called\n");
1142 ScmDeleteMarkedServices();
1143 RtlDeleteResource(&DatabaseLock
);
1145 DPRINT("ScmShutdownServiceDatabase() done\n");
1150 ScmCheckDriver(PSERVICE Service
)
1152 OBJECT_ATTRIBUTES ObjectAttributes
;
1153 UNICODE_STRING DirName
;
1156 POBJECT_DIRECTORY_INFORMATION DirInfo
;
1161 DPRINT("ScmCheckDriver(%S) called\n", Service
->lpServiceName
);
1163 if (Service
->Status
.dwServiceType
== SERVICE_KERNEL_DRIVER
)
1165 RtlInitUnicodeString(&DirName
, L
"\\Driver");
1167 else // if (Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER)
1169 ASSERT(Service
->Status
.dwServiceType
== SERVICE_FILE_SYSTEM_DRIVER
);
1170 RtlInitUnicodeString(&DirName
, L
"\\FileSystem");
1173 InitializeObjectAttributes(&ObjectAttributes
,
1179 Status
= NtOpenDirectoryObject(&DirHandle
,
1180 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
1182 if (!NT_SUCCESS(Status
))
1187 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
1188 2 * MAX_PATH
* sizeof(WCHAR
);
1189 DirInfo
= HeapAlloc(GetProcessHeap(),
1196 Status
= NtQueryDirectoryObject(DirHandle
,
1203 if (Status
== STATUS_NO_MORE_ENTRIES
)
1205 /* FIXME: Add current service to 'failed service' list */
1206 DPRINT("Service '%S' failed\n", Service
->lpServiceName
);
1210 if (!NT_SUCCESS(Status
))
1213 DPRINT("Comparing: '%S' '%wZ'\n", Service
->lpServiceName
, &DirInfo
->Name
);
1215 if (_wcsicmp(Service
->lpServiceName
, DirInfo
->Name
.Buffer
) == 0)
1217 DPRINT("Found: '%S' '%wZ'\n",
1218 Service
->lpServiceName
, &DirInfo
->Name
);
1220 /* Mark service as 'running' */
1221 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1222 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
1223 Service
->Status
.dwWin32ExitCode
= ERROR_SUCCESS
;
1224 Service
->Status
.dwServiceSpecificExitCode
= 0;
1225 Service
->Status
.dwCheckPoint
= 0;
1226 Service
->Status
.dwWaitHint
= 0;
1228 /* Mark the service group as 'running' */
1229 if (Service
->lpGroup
!= NULL
)
1231 Service
->lpGroup
->ServicesRunning
= TRUE
;
1238 HeapFree(GetProcessHeap(),
1243 return STATUS_SUCCESS
;
1248 ScmGetBootAndSystemDriverState(VOID
)
1250 PLIST_ENTRY ServiceEntry
;
1251 PSERVICE CurrentService
;
1253 DPRINT("ScmGetBootAndSystemDriverState() called\n");
1255 ServiceEntry
= ServiceListHead
.Flink
;
1256 while (ServiceEntry
!= &ServiceListHead
)
1258 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1260 if (CurrentService
->dwStartType
== SERVICE_BOOT_START
||
1261 CurrentService
->dwStartType
== SERVICE_SYSTEM_START
)
1264 DPRINT(" Checking service: %S\n", CurrentService
->lpServiceName
);
1266 ScmCheckDriver(CurrentService
);
1269 ServiceEntry
= ServiceEntry
->Flink
;
1272 DPRINT("ScmGetBootAndSystemDriverState() done\n");
1277 ScmControlService(HANDLE hControlPipe
,
1279 SERVICE_STATUS_HANDLE hServiceStatus
,
1282 PSCM_CONTROL_PACKET ControlPacket
;
1283 SCM_REPLY_PACKET ReplyPacket
;
1285 DWORD dwWriteCount
= 0;
1286 DWORD dwReadCount
= 0;
1289 DWORD dwError
= ERROR_SUCCESS
;
1291 OVERLAPPED Overlapped
= {0};
1293 DPRINT("ScmControlService() called\n");
1295 /* Acquire the service control critical section, to synchronize requests */
1296 EnterCriticalSection(&ControlServiceCriticalSection
);
1298 /* Calculate the total length of the start command line */
1299 PacketSize
= sizeof(SCM_CONTROL_PACKET
);
1300 PacketSize
+= (DWORD
)((wcslen(pServiceName
) + 1) * sizeof(WCHAR
));
1302 ControlPacket
= HeapAlloc(GetProcessHeap(),
1305 if (ControlPacket
== NULL
)
1307 LeaveCriticalSection(&ControlServiceCriticalSection
);
1308 return ERROR_NOT_ENOUGH_MEMORY
;
1311 ControlPacket
->dwSize
= PacketSize
;
1312 ControlPacket
->dwControl
= dwControl
;
1313 ControlPacket
->hServiceStatus
= hServiceStatus
;
1315 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
1317 Ptr
= (PWSTR
)((PBYTE
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
1318 wcscpy(Ptr
, pServiceName
);
1320 ControlPacket
->dwArgumentsCount
= 0;
1321 ControlPacket
->dwArgumentsOffset
= 0;
1323 bResult
= WriteFile(hControlPipe
,
1328 if (bResult
== FALSE
)
1330 DPRINT("WriteFile() returned FALSE\n");
1332 dwError
= GetLastError();
1333 if (dwError
== ERROR_IO_PENDING
)
1335 DPRINT("dwError: ERROR_IO_PENDING\n");
1337 dwError
= WaitForSingleObject(hControlPipe
,
1339 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1341 if (dwError
== WAIT_TIMEOUT
)
1343 bResult
= CancelIo(hControlPipe
);
1344 if (bResult
== FALSE
)
1346 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1349 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1352 else if (dwError
== WAIT_OBJECT_0
)
1354 bResult
= GetOverlappedResult(hControlPipe
,
1358 if (bResult
== FALSE
)
1360 dwError
= GetLastError();
1361 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1369 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
1374 /* Read the reply */
1375 Overlapped
.hEvent
= (HANDLE
) NULL
;
1377 bResult
= ReadFile(hControlPipe
,
1379 sizeof(SCM_REPLY_PACKET
),
1382 if (bResult
== FALSE
)
1384 DPRINT("ReadFile() returned FALSE\n");
1386 dwError
= GetLastError();
1387 if (dwError
== ERROR_IO_PENDING
)
1389 DPRINT("dwError: ERROR_IO_PENDING\n");
1391 dwError
= WaitForSingleObject(hControlPipe
,
1393 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1395 if (dwError
== WAIT_TIMEOUT
)
1397 bResult
= CancelIo(hControlPipe
);
1398 if (bResult
== FALSE
)
1400 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1403 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1406 else if (dwError
== WAIT_OBJECT_0
)
1408 bResult
= GetOverlappedResult(hControlPipe
,
1412 if (bResult
== FALSE
)
1414 dwError
= GetLastError();
1415 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1423 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1429 /* Release the control packet */
1430 HeapFree(GetProcessHeap(),
1434 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1436 dwError
= ReplyPacket
.dwError
;
1439 LeaveCriticalSection(&ControlServiceCriticalSection
);
1441 DPRINT("ScmControlService() done\n");
1448 ScmSendStartCommand(PSERVICE Service
,
1452 DWORD dwError
= ERROR_SUCCESS
;
1453 PSCM_CONTROL_PACKET ControlPacket
;
1454 SCM_REPLY_PACKET ReplyPacket
;
1461 DWORD dwWriteCount
= 0;
1462 DWORD dwReadCount
= 0;
1463 OVERLAPPED Overlapped
= {0};
1465 DPRINT("ScmSendStartCommand() called\n");
1467 /* Calculate the total length of the start command line */
1468 PacketSize
= sizeof(SCM_CONTROL_PACKET
);
1469 PacketSize
+= (DWORD
)((wcslen(Service
->lpServiceName
) + 1) * sizeof(WCHAR
));
1472 * Calculate the required packet size for the start argument vector 'argv',
1473 * composed of the list of pointer offsets, followed by UNICODE strings.
1474 * The strings are stored continuously after the vector of offsets, with
1475 * the offsets being relative to the beginning of the vector, as in the
1476 * following layout (with N == argc):
1477 * [argOff(0)]...[argOff(N-1)][str(0)]...[str(N-1)] .
1479 if (argc
> 0 && argv
!= NULL
)
1481 PacketSize
= ALIGN_UP(PacketSize
, PWSTR
);
1482 PacketSize
+= (argc
* sizeof(PWSTR
));
1484 DPRINT("Argc: %lu\n", argc
);
1485 for (i
= 0; i
< argc
; i
++)
1487 DPRINT("Argv[%lu]: %S\n", i
, argv
[i
]);
1488 PacketSize
+= (DWORD
)((wcslen(argv
[i
]) + 1) * sizeof(WCHAR
));
1492 /* Allocate a control packet */
1493 ControlPacket
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, PacketSize
);
1494 if (ControlPacket
== NULL
)
1495 return ERROR_NOT_ENOUGH_MEMORY
;
1497 ControlPacket
->dwSize
= PacketSize
;
1498 ControlPacket
->dwControl
= (Service
->Status
.dwServiceType
& SERVICE_WIN32_OWN_PROCESS
)
1499 ? SERVICE_CONTROL_START_OWN
1500 : SERVICE_CONTROL_START_SHARE
;
1501 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
1502 ControlPacket
->dwServiceTag
= Service
->dwTag
;
1504 /* Copy the start command line */
1505 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
1506 Ptr
= (PWSTR
)((ULONG_PTR
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
1507 wcscpy(Ptr
, Service
->lpServiceName
);
1509 ControlPacket
->dwArgumentsCount
= 0;
1510 ControlPacket
->dwArgumentsOffset
= 0;
1512 /* Copy the argument vector */
1513 if (argc
> 0 && argv
!= NULL
)
1515 Ptr
+= wcslen(Service
->lpServiceName
) + 1;
1516 pOffPtr
= (PWSTR
*)ALIGN_UP_POINTER(Ptr
, PWSTR
);
1517 pArgPtr
= (PWSTR
)((ULONG_PTR
)pOffPtr
+ argc
* sizeof(PWSTR
));
1519 ControlPacket
->dwArgumentsCount
= argc
;
1520 ControlPacket
->dwArgumentsOffset
= (DWORD
)((ULONG_PTR
)pOffPtr
- (ULONG_PTR
)ControlPacket
);
1522 DPRINT("dwArgumentsCount: %lu\n", ControlPacket
->dwArgumentsCount
);
1523 DPRINT("dwArgumentsOffset: %lu\n", ControlPacket
->dwArgumentsOffset
);
1525 for (i
= 0; i
< argc
; i
++)
1527 wcscpy(pArgPtr
, argv
[i
]);
1528 pOffPtr
[i
] = (PWSTR
)((ULONG_PTR
)pArgPtr
- (ULONG_PTR
)pOffPtr
);
1529 DPRINT("offset[%lu]: %p\n", i
, pOffPtr
[i
]);
1530 pArgPtr
+= wcslen(argv
[i
]) + 1;
1534 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1539 if (bResult
== FALSE
)
1541 DPRINT("WriteFile() returned FALSE\n");
1543 dwError
= GetLastError();
1544 if (dwError
== ERROR_IO_PENDING
)
1546 DPRINT("dwError: ERROR_IO_PENDING\n");
1548 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1550 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1552 if (dwError
== WAIT_TIMEOUT
)
1554 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1555 if (bResult
== FALSE
)
1557 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1560 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1563 else if (dwError
== WAIT_OBJECT_0
)
1565 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1569 if (bResult
== FALSE
)
1571 dwError
= GetLastError();
1572 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1580 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
1585 /* Read the reply */
1586 Overlapped
.hEvent
= (HANDLE
) NULL
;
1588 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1590 sizeof(SCM_REPLY_PACKET
),
1593 if (bResult
== FALSE
)
1595 DPRINT("ReadFile() returned FALSE\n");
1597 dwError
= GetLastError();
1598 if (dwError
== ERROR_IO_PENDING
)
1600 DPRINT("dwError: ERROR_IO_PENDING\n");
1602 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1604 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1606 if (dwError
== WAIT_TIMEOUT
)
1608 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1609 if (bResult
== FALSE
)
1611 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1614 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1617 else if (dwError
== WAIT_OBJECT_0
)
1619 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1623 if (bResult
== FALSE
)
1625 dwError
= GetLastError();
1626 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1634 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1640 /* Release the control packet */
1641 HeapFree(GetProcessHeap(),
1645 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1647 dwError
= ReplyPacket
.dwError
;
1650 DPRINT("ScmSendStartCommand() done\n");
1657 ScmWaitForServiceConnect(PSERVICE Service
)
1660 DWORD dwProcessId
= 0;
1661 DWORD dwError
= ERROR_SUCCESS
;
1663 OVERLAPPED Overlapped
= {0};
1665 LPCWSTR lpLogStrings
[3];
1666 WCHAR szBuffer1
[20];
1667 WCHAR szBuffer2
[20];
1670 DPRINT("ScmWaitForServiceConnect()\n");
1672 Overlapped
.hEvent
= (HANDLE
)NULL
;
1674 bResult
= ConnectNamedPipe(Service
->lpImage
->hControlPipe
,
1676 if (bResult
== FALSE
)
1678 DPRINT("ConnectNamedPipe() returned FALSE\n");
1680 dwError
= GetLastError();
1681 if (dwError
== ERROR_IO_PENDING
)
1683 DPRINT("dwError: ERROR_IO_PENDING\n");
1685 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1687 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1689 if (dwError
== WAIT_TIMEOUT
)
1691 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1693 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1694 if (bResult
== FALSE
)
1696 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1700 _ultow(PipeTimeout
, szBuffer1
, 10);
1701 lpLogStrings
[0] = Service
->lpDisplayName
;
1702 lpLogStrings
[1] = szBuffer1
;
1704 ScmLogEvent(EVENT_CONNECTION_TIMEOUT
,
1705 EVENTLOG_ERROR_TYPE
,
1709 DPRINT1("Log EVENT_CONNECTION_TIMEOUT by %S\n", Service
->lpDisplayName
);
1711 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1713 else if (dwError
== WAIT_OBJECT_0
)
1715 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1719 if (bResult
== FALSE
)
1721 dwError
= GetLastError();
1722 DPRINT1("GetOverlappedResult failed (Error %lu)\n", dwError
);
1728 else if (dwError
!= ERROR_PIPE_CONNECTED
)
1730 DPRINT1("ConnectNamedPipe failed (Error %lu)\n", dwError
);
1735 DPRINT("Control pipe connected!\n");
1737 Overlapped
.hEvent
= (HANDLE
) NULL
;
1739 /* Read the process id from pipe */
1740 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1741 (LPVOID
)&dwProcessId
,
1745 if (bResult
== FALSE
)
1747 DPRINT("ReadFile() returned FALSE\n");
1749 dwError
= GetLastError();
1750 if (dwError
== ERROR_IO_PENDING
)
1752 DPRINT("dwError: ERROR_IO_PENDING\n");
1754 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1756 if (dwError
== WAIT_TIMEOUT
)
1758 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1760 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1761 if (bResult
== FALSE
)
1763 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1767 _ultow(PipeTimeout
, szBuffer1
, 10);
1768 lpLogStrings
[0] = szBuffer1
;
1770 ScmLogEvent(EVENT_READFILE_TIMEOUT
,
1771 EVENTLOG_ERROR_TYPE
,
1775 DPRINT1("Log EVENT_READFILE_TIMEOUT by %S\n", Service
->lpDisplayName
);
1777 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1779 else if (dwError
== WAIT_OBJECT_0
)
1781 DPRINT("WaitForSingleObject() returned WAIT_OBJECT_0\n");
1783 DPRINT("Process Id: %lu\n", dwProcessId
);
1785 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1789 if (bResult
== FALSE
)
1791 dwError
= GetLastError();
1792 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1799 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
1804 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1809 if (dwProcessId
!= Service
->lpImage
->dwProcessId
)
1812 _ultow(Service
->lpImage
->dwProcessId
, szBuffer1
, 10);
1813 _ultow(dwProcessId
, szBuffer2
, 10);
1815 lpLogStrings
[0] = Service
->lpDisplayName
;
1816 lpLogStrings
[1] = szBuffer1
;
1817 lpLogStrings
[2] = szBuffer2
;
1819 ScmLogEvent(EVENT_SERVICE_DIFFERENT_PID_CONNECTED
,
1820 EVENTLOG_WARNING_TYPE
,
1825 DPRINT1("Log EVENT_SERVICE_DIFFERENT_PID_CONNECTED by %S\n", Service
->lpDisplayName
);
1828 DPRINT("ScmWaitForServiceConnect() done\n");
1830 return ERROR_SUCCESS
;
1835 ScmStartUserModeService(PSERVICE Service
,
1839 PROCESS_INFORMATION ProcessInformation
;
1840 STARTUPINFOW StartupInfo
;
1841 LPVOID lpEnvironment
;
1843 DWORD dwError
= ERROR_SUCCESS
;
1845 DPRINT("ScmStartUserModeService(%p)\n", Service
);
1847 /* If the image is already running ... */
1848 if (Service
->lpImage
->dwImageRunCount
> 1)
1850 /* ... just send a start command */
1851 return ScmSendStartCommand(Service
, argc
, argv
);
1854 /* Otherwise start its process */
1855 ZeroMemory(&StartupInfo
, sizeof(StartupInfo
));
1856 StartupInfo
.cb
= sizeof(StartupInfo
);
1857 ZeroMemory(&ProcessInformation
, sizeof(ProcessInformation
));
1859 if (Service
->lpImage
->hToken
)
1861 /* User token: Run the service under the user account */
1863 if (!CreateEnvironmentBlock(&lpEnvironment
, Service
->lpImage
->hToken
, FALSE
))
1865 /* We failed, run the service with the current environment */
1866 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n",
1867 GetLastError(), Service
->lpServiceName
);
1868 lpEnvironment
= NULL
;
1871 /* Impersonate the new user */
1872 Result
= ImpersonateLoggedOnUser(Service
->lpImage
->hToken
);
1875 /* Launch the process in the user's logon session */
1876 Result
= CreateProcessAsUserW(Service
->lpImage
->hToken
,
1878 Service
->lpImage
->pszImagePath
,
1882 CREATE_UNICODE_ENVIRONMENT
| DETACHED_PROCESS
| CREATE_SUSPENDED
,
1886 &ProcessInformation
);
1888 dwError
= GetLastError();
1890 /* Revert the impersonation */
1895 dwError
= GetLastError();
1896 DPRINT1("ImpersonateLoggedOnUser() failed with error %d\n", dwError
);
1901 /* No user token: Run the service under the LocalSystem account */
1903 if (!CreateEnvironmentBlock(&lpEnvironment
, NULL
, TRUE
))
1905 /* We failed, run the service with the current environment */
1906 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n",
1907 GetLastError(), Service
->lpServiceName
);
1908 lpEnvironment
= NULL
;
1911 /* Use the interactive desktop if the service is interactive */
1912 if ((NoInteractiveServices
== 0) &&
1913 (Service
->Status
.dwServiceType
& SERVICE_INTERACTIVE_PROCESS
))
1915 StartupInfo
.dwFlags
|= STARTF_INHERITDESKTOP
;
1916 StartupInfo
.lpDesktop
= L
"WinSta0\\Default";
1919 if (wcsstr(Service
->lpImage
->pszImagePath
, L
"\\system32\\lsass.exe") == NULL
)
1921 Result
= CreateProcessW(NULL
,
1922 Service
->lpImage
->pszImagePath
,
1926 CREATE_UNICODE_ENVIRONMENT
| DETACHED_PROCESS
| CREATE_SUSPENDED
,
1930 &ProcessInformation
);
1932 dwError
= GetLastError();
1937 dwError
= ERROR_SUCCESS
;
1942 DestroyEnvironmentBlock(lpEnvironment
);
1946 DPRINT1("Starting '%S' failed with error %d\n",
1947 Service
->lpServiceName
, dwError
);
1951 DPRINT("Process Id: %lu Handle %p\n",
1952 ProcessInformation
.dwProcessId
,
1953 ProcessInformation
.hProcess
);
1954 DPRINT("Thread Id: %lu Handle %p\n",
1955 ProcessInformation
.dwThreadId
,
1956 ProcessInformation
.hThread
);
1958 /* Get the process handle and ID */
1959 Service
->lpImage
->hProcess
= ProcessInformation
.hProcess
;
1960 Service
->lpImage
->dwProcessId
= ProcessInformation
.dwProcessId
;
1962 /* Resume the main thread and close its handle */
1963 ResumeThread(ProcessInformation
.hThread
);
1964 CloseHandle(ProcessInformation
.hThread
);
1966 /* Connect control pipe */
1967 dwError
= ScmWaitForServiceConnect(Service
);
1968 if (dwError
!= ERROR_SUCCESS
)
1970 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
1971 Service
->lpImage
->dwProcessId
= 0;
1975 /* Send the start command */
1976 return ScmSendStartCommand(Service
, argc
, argv
);
1981 ScmLoadService(PSERVICE Service
,
1985 PSERVICE_GROUP Group
= Service
->lpGroup
;
1986 DWORD dwError
= ERROR_SUCCESS
;
1987 LPCWSTR lpLogStrings
[2];
1988 WCHAR szLogBuffer
[80];
1990 DPRINT("ScmLoadService() called\n");
1991 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
1993 if (Service
->Status
.dwCurrentState
!= SERVICE_STOPPED
)
1995 DPRINT("Service %S is already running!\n", Service
->lpServiceName
);
1996 return ERROR_SERVICE_ALREADY_RUNNING
;
1999 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
2001 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
2003 /* Start the driver */
2004 dwError
= ScmStartDriver(Service
);
2006 else // if (Service->Status.dwServiceType & (SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS))
2008 /* Start user-mode service */
2009 dwError
= ScmCreateOrReferenceServiceImage(Service
);
2010 if (dwError
== ERROR_SUCCESS
)
2012 dwError
= ScmStartUserModeService(Service
, argc
, argv
);
2013 if (dwError
== ERROR_SUCCESS
)
2015 Service
->Status
.dwCurrentState
= SERVICE_START_PENDING
;
2016 Service
->Status
.dwControlsAccepted
= 0;
2020 Service
->lpImage
->dwImageRunCount
--;
2021 if (Service
->lpImage
->dwImageRunCount
== 0)
2023 ScmRemoveServiceImage(Service
->lpImage
);
2024 Service
->lpImage
= NULL
;
2030 DPRINT("ScmLoadService() done (Error %lu)\n", dwError
);
2032 if (dwError
== ERROR_SUCCESS
)
2036 Group
->ServicesRunning
= TRUE
;
2039 /* Log a successful service start */
2040 LoadStringW(GetModuleHandle(NULL
), IDS_SERVICE_START
, szLogBuffer
, 80);
2041 lpLogStrings
[0] = Service
->lpDisplayName
;
2042 lpLogStrings
[1] = szLogBuffer
;
2044 ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS
,
2045 EVENTLOG_INFORMATION_TYPE
,
2051 if (Service
->dwErrorControl
!= SERVICE_ERROR_IGNORE
)
2053 /* Log a failed service start */
2054 StringCchPrintfW(szLogBuffer
, ARRAYSIZE(szLogBuffer
),
2056 lpLogStrings
[0] = Service
->lpServiceName
;
2057 lpLogStrings
[1] = szLogBuffer
;
2058 ScmLogEvent(EVENT_SERVICE_START_FAILED
,
2059 EVENTLOG_ERROR_TYPE
,
2065 switch (Service
->dwErrorControl
)
2067 case SERVICE_ERROR_SEVERE
:
2068 if (IsLastKnownGood
== FALSE
)
2070 /* FIXME: Boot last known good configuration */
2074 case SERVICE_ERROR_CRITICAL
:
2075 if (IsLastKnownGood
== FALSE
)
2077 /* FIXME: Boot last known good configuration */
2093 ScmStartService(PSERVICE Service
,
2097 DWORD dwError
= ERROR_SUCCESS
;
2098 SC_RPC_LOCK Lock
= NULL
;
2100 DPRINT("ScmStartService() called\n");
2101 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
2103 /* Acquire the service control critical section, to synchronize starts */
2104 EnterCriticalSection(&ControlServiceCriticalSection
);
2107 * Acquire the user service start lock while the service is starting, if
2108 * needed (i.e. if we are not starting it during the initialization phase).
2109 * If we don't success, bail out.
2113 dwError
= ScmAcquireServiceStartLock(TRUE
, &Lock
);
2114 if (dwError
!= ERROR_SUCCESS
) goto done
;
2117 /* Really start the service */
2118 dwError
= ScmLoadService(Service
, argc
, argv
);
2120 /* Release the service start lock, if needed, and the critical section */
2121 if (Lock
) ScmReleaseServiceStartLock(&Lock
);
2124 LeaveCriticalSection(&ControlServiceCriticalSection
);
2126 DPRINT("ScmStartService() done (Error %lu)\n", dwError
);
2133 ScmAutoStartServices(VOID
)
2136 PLIST_ENTRY GroupEntry
;
2137 PLIST_ENTRY ServiceEntry
;
2138 PSERVICE_GROUP CurrentGroup
;
2139 PSERVICE CurrentService
;
2140 WCHAR szSafeBootServicePath
[MAX_PATH
];
2141 DWORD SafeBootEnabled
;
2147 * This function MUST be called ONLY at initialization time.
2148 * Therefore, no need to acquire the user service start lock.
2150 ASSERT(ScmInitialize
);
2152 /* Retrieve the SafeBoot parameter */
2153 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2154 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option",
2158 if (dwError
== ERROR_SUCCESS
)
2160 dwKeySize
= sizeof(SafeBootEnabled
);
2161 dwError
= RegQueryValueExW(hKey
,
2165 (LPBYTE
)&SafeBootEnabled
,
2170 /* Default to Normal boot if the value doesn't exist */
2171 if (dwError
!= ERROR_SUCCESS
)
2172 SafeBootEnabled
= 0;
2174 /* Acquire the service control critical section, to synchronize starts */
2175 EnterCriticalSection(&ControlServiceCriticalSection
);
2177 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
2178 ServiceEntry
= ServiceListHead
.Flink
;
2179 while (ServiceEntry
!= &ServiceListHead
)
2181 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2183 /* Build the safe boot path */
2184 StringCchCopyW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2185 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
2187 switch (SafeBootEnabled
)
2189 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
2192 StringCchCatW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2197 StringCchCatW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2202 if (SafeBootEnabled
!= 0)
2204 /* If key does not exist then do not assume safe mode */
2205 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2206 szSafeBootServicePath
,
2210 if (dwError
== ERROR_SUCCESS
)
2214 /* Finish Safe Boot path off */
2215 StringCchCatW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2216 CurrentService
->lpServiceName
);
2218 /* Check that the key is in the Safe Boot path */
2219 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2220 szSafeBootServicePath
,
2224 if (dwError
!= ERROR_SUCCESS
)
2226 /* Mark service as visited so it is not auto-started */
2227 CurrentService
->ServiceVisited
= TRUE
;
2231 /* Must be auto-started in safe mode - mark as unvisited */
2233 CurrentService
->ServiceVisited
= FALSE
;
2238 DPRINT1("WARNING: Could not open the associated Safe Boot key!");
2239 CurrentService
->ServiceVisited
= FALSE
;
2243 ServiceEntry
= ServiceEntry
->Flink
;
2246 /* Start all services which are members of an existing group */
2247 GroupEntry
= GroupListHead
.Flink
;
2248 while (GroupEntry
!= &GroupListHead
)
2250 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
2252 DPRINT("Group '%S'\n", CurrentGroup
->lpGroupName
);
2254 /* Start all services witch have a valid tag */
2255 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
2257 ServiceEntry
= ServiceListHead
.Flink
;
2258 while (ServiceEntry
!= &ServiceListHead
)
2260 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2262 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
2263 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2264 (CurrentService
->ServiceVisited
== FALSE
) &&
2265 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
2267 CurrentService
->ServiceVisited
= TRUE
;
2268 ScmLoadService(CurrentService
, 0, NULL
);
2271 ServiceEntry
= ServiceEntry
->Flink
;
2275 /* Start all services which have an invalid tag or which do not have a tag */
2276 ServiceEntry
= ServiceListHead
.Flink
;
2277 while (ServiceEntry
!= &ServiceListHead
)
2279 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2281 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
2282 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2283 (CurrentService
->ServiceVisited
== FALSE
))
2285 CurrentService
->ServiceVisited
= TRUE
;
2286 ScmLoadService(CurrentService
, 0, NULL
);
2289 ServiceEntry
= ServiceEntry
->Flink
;
2292 GroupEntry
= GroupEntry
->Flink
;
2295 /* Start all services which are members of any non-existing group */
2296 ServiceEntry
= ServiceListHead
.Flink
;
2297 while (ServiceEntry
!= &ServiceListHead
)
2299 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2301 if ((CurrentService
->lpGroup
!= NULL
) &&
2302 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2303 (CurrentService
->ServiceVisited
== FALSE
))
2305 CurrentService
->ServiceVisited
= TRUE
;
2306 ScmLoadService(CurrentService
, 0, NULL
);
2309 ServiceEntry
= ServiceEntry
->Flink
;
2312 /* Start all services which are not a member of any group */
2313 ServiceEntry
= ServiceListHead
.Flink
;
2314 while (ServiceEntry
!= &ServiceListHead
)
2316 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2318 if ((CurrentService
->lpGroup
== NULL
) &&
2319 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2320 (CurrentService
->ServiceVisited
== FALSE
))
2322 CurrentService
->ServiceVisited
= TRUE
;
2323 ScmLoadService(CurrentService
, 0, NULL
);
2326 ServiceEntry
= ServiceEntry
->Flink
;
2329 /* Clear 'ServiceVisited' flag again */
2330 ServiceEntry
= ServiceListHead
.Flink
;
2331 while (ServiceEntry
!= &ServiceListHead
)
2333 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2334 CurrentService
->ServiceVisited
= FALSE
;
2335 ServiceEntry
= ServiceEntry
->Flink
;
2338 /* Release the critical section */
2339 LeaveCriticalSection(&ControlServiceCriticalSection
);
2344 ScmAutoShutdownServices(VOID
)
2346 PLIST_ENTRY ServiceEntry
;
2347 PSERVICE CurrentService
;
2349 DPRINT("ScmAutoShutdownServices() called\n");
2351 /* Lock the service database exclusively */
2352 ScmLockDatabaseExclusive();
2354 ServiceEntry
= ServiceListHead
.Flink
;
2355 while (ServiceEntry
!= &ServiceListHead
)
2357 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2359 if ((CurrentService
->Status
.dwControlsAccepted
& SERVICE_ACCEPT_SHUTDOWN
) &&
2360 (CurrentService
->Status
.dwCurrentState
== SERVICE_RUNNING
||
2361 CurrentService
->Status
.dwCurrentState
== SERVICE_START_PENDING
))
2363 /* Send the shutdown notification */
2364 DPRINT("Shutdown service: %S\n", CurrentService
->lpServiceName
);
2365 ScmControlService(CurrentService
->lpImage
->hControlPipe
,
2366 CurrentService
->lpServiceName
,
2367 (SERVICE_STATUS_HANDLE
)CurrentService
,
2368 SERVICE_CONTROL_SHUTDOWN
);
2371 ServiceEntry
= ServiceEntry
->Flink
;
2374 /* Unlock the service database */
2375 ScmUnlockDatabase();
2377 DPRINT("ScmAutoShutdownServices() done\n");
2382 ScmLockDatabaseExclusive(VOID
)
2384 return RtlAcquireResourceExclusive(&DatabaseLock
, TRUE
);
2389 ScmLockDatabaseShared(VOID
)
2391 return RtlAcquireResourceShared(&DatabaseLock
, TRUE
);
2396 ScmUnlockDatabase(VOID
)
2398 RtlReleaseResource(&DatabaseLock
);
2403 ScmInitNamedPipeCriticalSection(VOID
)
2409 InitializeCriticalSection(&ControlServiceCriticalSection
);
2411 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2412 L
"SYSTEM\\CurrentControlSet\\Control",
2416 if (dwError
== ERROR_SUCCESS
)
2418 dwKeySize
= sizeof(PipeTimeout
);
2419 RegQueryValueExW(hKey
,
2420 L
"ServicesPipeTimeout",
2423 (LPBYTE
)&PipeTimeout
,
2431 ScmDeleteNamedPipeCriticalSection(VOID
)
2433 DeleteCriticalSection(&ControlServiceCriticalSection
);