将现有服务设置为“自动(延迟启动)”

我正在尝试将已安装的 Windows服务设置为C#中的自动延迟启动。 如何设置Windows服务

Automatic (Delayed Start) 

无法在ServiceStartMode枚举中找到该值。

编辑:1

 public class ServiceAutoStartInfo { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] private struct SERVICE_DELAYED_AUTO_START_INFO { public bool fDelayedAutostart; } [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool ChangeServiceConfig2(IntPtr hService, int dwInfoLevel, IntPtr lpInfo); // Service configuration parameter const int SERVICE_CONFIG_DELAYED_AUTO_START_INFO = 3; public bool ChangeDelayedAutoStart(IntPtr hService, bool delayed) { // Validate service handle if (hService != IntPtr.Zero) { // Create SERVICE_DELAYED_AUTO_START_INFO info = new SERVICE_DELAYED_AUTO_START_INFO(); // Set the DelayedAutostart property info.fDelayedAutostart = delayed; // Allocate necessary memory IntPtr hInfo = Marshal.AllocHGlobal(Marshal.SizeOf( typeof(SERVICE_DELAYED_AUTO_START_INFO))); // Convert structure to pointer Marshal.StructureToPtr(info, hInfo, true); // Change the configuration bool result = ChangeServiceConfig2(hService, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, hInfo); // Release memory Marshal.FreeHGlobal(hInfo); return result; } return false; } } 

这就是我所说的:

 var controller = new ServiceController(s.ServiceName); var autoDelay = new ServiceAutoStartInfo(); autoDelay.ChangeDelayedAutoStart(controller.ServiceHandle.DangerousGetHandle(), true); 

但没有结果。

查看调用Windows ChangeServiceConfig2函数,其中dwInfoLevelSERVICE_CONFIG_DELAYED_AUTO_START_INFOSERVICE_DELAYED_AUTO_START_INFO结构, fDelayedAutostart设置为TRUE

或者,您可以使用命令行执行此操作:

 sc.exe config  start= delayed-auto 

我正在使用以下版本,它适用于Windows 7(以管理员身份运行时):

 using System; using System.ComponentModel; using System.Runtime.InteropServices; using System.ServiceProcess; namespace ServiceManager { ///  /// Extensions to the ServiceController class. ///  public static class ServiceControlerExtensions { ///  /// Set the start mode for the service. ///  /// The service controller. /// The desired start mode. public static void SetStartMode(this ServiceController serviceController, ServiceStartModeEx mode) { IntPtr serviceManagerHandle = OpenServiceManagerHandle(); IntPtr serviceHandle = OpenServiceHandle(serviceController, serviceManagerHandle); try { if (mode == ServiceStartModeEx.DelayedAutomatic) { ChangeServiceStartType(serviceHandle, ServiceStartModeEx.Automatic); ChangeDelayedAutoStart(serviceHandle, true); } else { // Delayed auto-start overrides other settings, so it must be set first. ChangeDelayedAutoStart(serviceHandle, false); ChangeServiceStartType(serviceHandle, mode); } } finally { if (serviceHandle != IntPtr.Zero) { CloseServiceHandle(serviceHandle); } if (serviceHandle != IntPtr.Zero) { CloseServiceHandle(serviceManagerHandle); } } } private static IntPtr OpenServiceHandle(ServiceController serviceController, IntPtr serviceManagerHandle) { var serviceHandle = OpenService( serviceManagerHandle, serviceController.ServiceName, SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG); if (serviceHandle == IntPtr.Zero) { throw new ExternalException("Open Service Error"); } return serviceHandle; } private static IntPtr OpenServiceManagerHandle() { IntPtr serviceManagerHandle = OpenSCManager(null, null, SC_MANAGER_ALL_ACCESS); if (serviceManagerHandle == IntPtr.Zero) { throw new ExternalException("Open Service Manager Error"); } return serviceManagerHandle; } private static void ChangeServiceStartType(IntPtr serviceHandle, ServiceStartModeEx mode) { bool result = ChangeServiceConfig( serviceHandle, SERVICE_NO_CHANGE, (uint)mode, SERVICE_NO_CHANGE, null, null, IntPtr.Zero, null, null, null, null); if (result == false) { ThrowLastWin32Error("Could not change service start type"); } } private static void ChangeDelayedAutoStart(IntPtr hService, bool delayed) { // Create structure that contains DelayedAutoStart property. SERVICE_DELAYED_AUTO_START_INFO info = new SERVICE_DELAYED_AUTO_START_INFO(); // Set the DelayedAutostart property in that structure. info.fDelayedAutostart = delayed; // Allocate necessary memory. IntPtr hInfo = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SERVICE_DELAYED_AUTO_START_INFO))); // Convert structure to pointer. Marshal.StructureToPtr(info, hInfo, true); // Change the configuration. bool result = ChangeServiceConfig2(hService, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, hInfo); // Release memory. Marshal.FreeHGlobal(hInfo); if (result == false) { ThrowLastWin32Error("Could not set service to delayed automatic"); } } private static void ThrowLastWin32Error(string messagePrefix) { int nError = Marshal.GetLastWin32Error(); var win32Exception = new Win32Exception(nError); string message = string.Format("{0}: {1}", messagePrefix, win32Exception.Message); throw new ExternalException(message); } [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] private static extern IntPtr OpenService( IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess); [DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] private static extern IntPtr OpenSCManager( string machineName, string databaseName, uint dwAccess); [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern Boolean ChangeServiceConfig( IntPtr hService, UInt32 nServiceType, UInt32 nStartType, UInt32 nErrorControl, String lpBinaryPathName, String lpLoadOrderGroup, IntPtr lpdwTagId, [In] char[] lpDependencies, String lpServiceStartName, String lpPassword, String lpDisplayName); [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool ChangeServiceConfig2( IntPtr hService, int dwInfoLevel, IntPtr lpInfo); [DllImport("advapi32.dll", EntryPoint = "CloseServiceHandle")] private static extern int CloseServiceHandle(IntPtr hSCObject); private const uint SERVICE_NO_CHANGE = 0xFFFFFFFF; private const uint SERVICE_QUERY_CONFIG = 0x00000001; private const uint SERVICE_CHANGE_CONFIG = 0x00000002; private const uint SC_MANAGER_ALL_ACCESS = 0x000F003F; private const int SERVICE_CONFIG_DELAYED_AUTO_START_INFO = 3; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] private struct SERVICE_DELAYED_AUTO_START_INFO { public bool fDelayedAutostart; } } } namespace ServiceManager { public enum ServiceStartModeEx { Automatic = 2, Manual = 3, Disabled = 4, DelayedAutomatic = 99 } } 

你这样称呼它:

 var serviceController = new ServiceController("Windows Update"); try { serviceController.SetStartMode(ServiceStartModeEx.DelayedAutomatic); } finally { serviceController.Close(); } 

更新:这仅适用于设置新服务,而不是OP要求的内容:

您可以使用ServiceInstallerDelayedAutoStart属性。

 installer.DelayedAutoStart = true; 

我相信你需要结合使用ChangeServiceConfig和ChangeServiceConfig2两种方法。

伪代码如下:

 public static void ChangeServiceStartupType(ServiceStartupType type, ...) { if (type == AutomaticDelayed) { if (ChangeServiceConfig2(.., DelayedAutoStart, ..)) { ChangeServiceConfig(.., Automatic, ..); } } else { ChangeServiceConfig2(.., !DelayedAutoStart, ..) ChangeServiceConfig(.., type, ..) } } 

编辑:您还需要在请求非延迟启动类型时删除“延迟自动”。 否则将无法设置“自动”类型。 (“自动延迟”覆盖“自动”)