【问题标题】:Enable windows service programmatically以编程方式启用 Windows 服务
【发布时间】:2018-12-30 01:47:04
【问题描述】:

我正在尝试通过修改注册表中的值以编程方式启用 Windows 服务,如下所示。值确实发生了变化。但是,在那之后我无法启动该服务,因为 Windows 仍将其视为已禁用。

public void EnabledTheService(string serviceName)
{
    try
    {
        RegistryKey key = Registry.LocalMachine
                                   .OpenSubKey(@"SYSTEM\CurrentControlSet\Services\"
                                                       + serviceName, true);
        key.SetValue("Start", 2);                
    }
    catch (Exception ex)
    {
         Console.Write(ex.Message);
    }
}

public void StartService(string serviceName)
{
    ServiceController service = new ServiceController(serviceName);
    try
    {
        service.Start();
        service.WaitForStatus(ServiceControllerStatus.Running, 
                                            new TimeSpan(0, 0, 0, 20));
    }
    catch (Exception ex)
    {
        Console.Write(ex.Message);
    }
}

【问题讨论】:

  • Windows 不知道您更改了注册表项。我怀疑您必须重新启动服务小程序。在 superuser.com 上询问
  • 重启服务无济于事,确实,这是纯粹的 SC 功能,注册表只是反映了它...更改使用 ChangeServiceConfig(见下文)或者您可以通过 Process.Start 运行 cmd cs 命令。 . [sc.exe 路径] config [srvName] [sc Option]= \"[sc Value]\" 并捕获进程输出

标签: c# windows-services


【解决方案1】:

我不认为编辑注册表是推荐的方法。不幸的是,它没有在ServiceController 类中公开。我建议使用 WMI,它具有 ChangeStartMode 方法(您需要添加对 System.Management.dll 的引用):

using System.Management;

public static void EnableTheService(string serviceName)
{
    using (var mo = new ManagementObject(string.Format("Win32_Service.Name=\"{0}\"", serviceName)))
    {
        mo.InvokeMethod("ChangeStartMode", new object[] { "Automatic" });
    }
}

【讨论】:

    【解决方案2】:

    您可以通过多种方式更改 Windows 服务的启动类型(请参阅this question)。如果我没记错的话,WMI 方法在我测试时有效,但并不完全可靠,所以我使用了 Windows API 函数ChangeServiceConfig。我从未尝试过注册表方法。我认为这将是三个选项中最不稳定的。

    请注意,如果您想要“自动(延迟启动)”模式,则需要致电 ChangeServiceConfig2

    public void ChangeServiceStartType(string serviceName, ServiceStartupType startType)
    {
        //Obtain a handle to the service control manager database
        IntPtr scmHandle = OpenSCManager(null, null, SC_MANAGER_CONNECT);
        if (scmHandle == IntPtr.Zero)
        {
            throw new Exception("Failed to obtain a handle to the service control manager database.");
        }
    
        //Obtain a handle to the specified windows service
        IntPtr serviceHandle = OpenService(scmHandle, serviceName, SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG);
        if (serviceHandle == IntPtr.Zero)
        {
            throw new Exception($"Failed to obtain a handle to service '{serviceName}'.");
        }
    
        //Change the start mode
        bool changeServiceSuccess = ChangeServiceConfig(serviceHandle, SERVICE_NO_CHANGE, (uint)startType, SERVICE_NO_CHANGE, null, null, IntPtr.Zero, null, null, null, null);
        if (!changeServiceSuccess)
        {
            string msg = $"Failed to update service configuration for service '{serviceName}'. ChangeServiceConfig returned error {Marshal.GetLastWin32Error()}.";
            throw new Exception(msg);
        }
    
        //Clean up
        if (scmHandle != IntPtr.Zero)
            CloseServiceHandle(scmHandle);
        if (serviceHandle != IntPtr.Zero)
            CloseServiceHandle(serviceHandle);
    }
    
    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr OpenSCManager(string machineName, string databaseName, uint dwAccess);
    
    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess);
    
    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool ChangeServiceConfig(
        IntPtr hService,
        uint nServiceType,
        uint nStartType,
        uint nErrorControl,
        string lpBinaryPathName,
        string lpLoadOrderGroup,
        IntPtr lpdwTagId,
        [In] char[] lpDependencies,
        string lpServiceStartName,
        string lpPassword,
        string lpDisplayName);
    
    [DllImport("advapi32.dll", EntryPoint = "CloseServiceHandle")]
    private static extern int CloseServiceHandle(IntPtr hSCObject);
    
    private const uint SC_MANAGER_CONNECT = 0x0001;
    private const uint SERVICE_QUERY_CONFIG = 0x00000001;
    private const uint SERVICE_CHANGE_CONFIG = 0x00000002;
    private const uint SERVICE_NO_CHANGE = 0xFFFFFFFF;
    
    public enum ServiceStartupType : uint
    {
        /// <summary>
        /// A device driver started by the system loader. This value is valid only for driver services.
        /// </summary>
        BootStart = 0,
    
        /// <summary>
        /// A device driver started by the IoInitSystem function. This value is valid only for driver services.
        /// </summary>
        SystemStart = 1,
    
        /// <summary>
        /// A service started automatically by the service control manager during system startup.
        /// </summary>
        Automatic = 2,
    
        /// <summary>
        /// A service started by the service control manager when a process calls the StartService function.
        /// </summary>
        Manual = 3,
    
        /// <summary>
        /// A service that cannot be started. Attempts to start the service result in the error code ERROR_SERVICE_DISABLED.
        /// </summary>
        Disabled = 4
    }
    

    【讨论】:

    • 顺便说一句,您可以使用来自System.ServiceProcessServiceStartMode 用作枚举
    猜你喜欢
    • 2011-10-03
    • 1970-01-01
    • 2011-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多