我想通过注册表以编程方式禁用服务。为此,我修改了以下注册表项:
Computer\HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\SensorDataService\Start
,其中我将其值设置为 0x4,该值对应于禁用状态。现在,当我在 Windows 服务管理器中检查服务时,它被报告为已禁用,我无法启动它。
但是,如果我尝试像这样以编程方式启动它:
var serviceController = new ServiceController("SensorDataService");
try
{
serviceController.Start();
} catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
当我通过 Windows 服务 UI 或 SC 命令行禁用服务时,出现异常,指出无法启动禁用的服务,这正是我所期望的。
有谁知道在注册表中设置上述值是否不足以禁用该服务?
我能够重现这一点,并使其与名称为“SensorDataService”的服务的普通注册表更改一起使用,如您所愿
Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SensorDataService\Start
,然后将值更改为0x4
,这确实意味着禁用,然后您必须重新启动您的计算机,然后当您从代码启动服务时会抛出您想要的异常。
我使用 CurrentControlSet 只是为了确保更改了正确的控件,但这对结果没有任何影响
我使用 net6.0 和 net7.0
对此进行了测试当人们在服务 GUI 中手动更改它时,我假设他们调用服务控制管理器,它会更改注册表项以及内存缓存中的内部内容或在某处创建一些文件,如果您能够重新加载它,则可能无法重新启动必要的。
我还尝试通过“RegistryChangesView”工具检查它是否没有更改任何其他注册表项,但我没有看到任何我怀疑的内容
因此,我强烈建议您通过使用服务控制管理器来实现您想要实现的目标,这里有一些方法:
使用cmd或从c#代码调用cmd:
手动使用WMI,这已经在评论中提到了这里
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.ServiceProcess;
namespace ServiceTest
{
public class Program
{
public static class ServiceHelper
{
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public 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", SetLastError = true, CharSet = CharSet.Auto)]
static extern IntPtr OpenService(
IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess);
[DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr OpenSCManager(
string machineName, string databaseName, uint dwAccess);
[DllImport("advapi32.dll", EntryPoint = "CloseServiceHandle")]
public 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;
public static void ChangeStartMode(ServiceController svc, ServiceStartMode mode)
{
var scManagerHandle = OpenSCManager(null, null, SC_MANAGER_ALL_ACCESS);
if (scManagerHandle == IntPtr.Zero)
{
throw new ExternalException("Open Service Manager Error");
}
var serviceHandle = OpenService(
scManagerHandle,
svc.ServiceName,
SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG);
if (serviceHandle == IntPtr.Zero)
{
throw new ExternalException("Open Service Error");
}
var result = ChangeServiceConfig(
serviceHandle,
SERVICE_NO_CHANGE,
(uint)mode,
SERVICE_NO_CHANGE,
null,
null,
IntPtr.Zero,
null,
null,
null,
null);
if (result == false)
{
int nError = Marshal.GetLastWin32Error();
var win32Exception = new Win32Exception(nError);
throw new ExternalException("Could not change service start type: "
+ win32Exception.Message);
}
CloseServiceHandle(serviceHandle);
CloseServiceHandle(scManagerHandle);
}
}
public static void Main(string[] args)
{
var serviceController = new ServiceController("SensorDataService");
ServiceHelper.ChangeStartMode(serviceController, ServiceStartMode.Disabled);
Console.WriteLine("Service disabled");
serviceController.Start();
Console.WriteLine("Service started");
}
}
}