Enable windows service programmatically

半腔热情 提交于 2019-11-30 09:25:03

问题


I am trying to enable a windows service programmatically by modifying the value in registry as below. The value does change. However, I am not able to start the service after that because windows still seeing it as disabled.

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);
    }
}

回答1:


There are several ways you can change the startup type of a windows service (see this question). If I remember correctly the WMI method worked when I tested it but was not totally reliable, so I used the Windows API function ChangeServiceConfig. I never tried the registry method. I would think that would be the most flaky of the three options.

Note that if you want the 'Automatic (Delayed Start)' mode then you need to call 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
}



回答2:


I don't think that editing the registry is the recommended way to do this. Unfortunately it isn't exposed in the ServiceController class. I would recommend using WMI, which has the method ChangeStartMode (You will need to add a reference to 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" });
    }
}


来源:https://stackoverflow.com/questions/24947407/enable-windows-service-programmatically

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!