我希望以编程方式启用并启动C#中的Net.Tcp端口共享服务。我可以使用ServiceController类轻松启动服务。但是,如何启用默认禁用的服务?
我在网上找到了一条推荐,将以下注册表项设置为2,如下所示,可以将服务启动类型设置为自动:
string path = "SYSTEM\\CurrentControlSet\\Services\\" + serviceName;
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(path, true)) {
key.SetValue("Start", 2);
}
我试过这个,虽然它似乎确实将启动类型更改为自动,但必须有更多,因为服务现在不会启动(以编程方式或手动方式)。我不得不通过services.msc手动重置启动类型以重置事物,以便可以启用并重新启动服务。
有没有人解决过这个问题?
答案 0 :(得分:11)
根据您想要的解决方案的“纯粹”程度,有多种方法可以做到这一点。这里有一些选择。 请注意,所有这些解决方案都需要管理权限,并且必须在升级过程中运行。
这将涉及shell sc.exe
并通过命令行参数更改服务的启动类型。这与上面提到的解决方案类似,只是不需要注册表黑客攻击。
namespace Sample
{
using System;
using System.Diagnostics;
using System.Globalization;
internal class ServiceSample
{
private static bool ChangeStartupType(string serviceName, string startupType)
{
string arguments = string.Format(
CultureInfo.InvariantCulture,
"config {0} start= {1}",
serviceName,
startupType);
using (Process sc = Process.Start("sc.exe", arguments))
{
sc.WaitForExit();
return sc.ExitCode == 0;
}
}
private static void Main()
{
ServiceSample.ChangeStartupType("NetTcpPortSharing", "auto");
}
}
}
这需要System.Management.dll
的装配参考。在这里,我们将使用WMI功能ChangeStartMode
来获取服务。
namespace Sample
{
using System;
using System.Globalization;
using System.Management;
internal class ServiceSample
{
private static bool ChangeStartupType(string serviceName, string startupType)
{
const string MethodName = "ChangeStartMode";
ManagementPath path = new ManagementPath();
path.Server = ".";
path.NamespacePath = @"root\CIMV2";
path.RelativePath = string.Format(
CultureInfo.InvariantCulture,
"Win32_Service.Name='{0}'",
serviceName);
using (ManagementObject serviceObject = new ManagementObject(path))
{
ManagementBaseObject inputParameters = serviceObject.GetMethodParameters(MethodName);
inputParameters["startmode"] = startupType;
ManagementBaseObject outputParameters = serviceObject.InvokeMethod(MethodName, inputParameters, null);
return (uint)outputParameters.Properties["ReturnValue"].Value == 0;
}
}
private static void Main()
{
ServiceSample.ChangeStartupType("NetTcpPortSharing", "Automatic");
}
}
}
对于某些人来说,这是最“纯粹”的方法,尽管做出正确的做法更为棘手。基本上你会想从.NET调用ChangeServiceConfig。但是,这需要您首先为指定的服务拨打OpenService,并且 需要事先致电OpenSCManager(当您不在时,不要忘记CloseServiceHandle完成!)。
注意:此代码仅用于演示目的。它不包含任何错误处理并可能泄漏资源。正确的实现应使用SafeHandle
类型以确保正确清理,并应添加适当的错误检查。
namespace Sample
{
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
internal class ServiceSample
{
private const uint SC_MANAGER_CONNECT = 0x1;
private const uint SERVICE_CHANGE_CONFIG = 0x2;
private const uint STANDARD_RIGHTS_WRITE = 0x20000;
private const uint SERVICE_NO_CHANGE = 0xFFFFFFFF;
private const uint SERVICE_AUTO_START = 0x2;
private const uint SERVICE_DEMAND_START = 0x3;
private const uint SERVICE_DISABLED = 0x4;
[DllImport("advapi32.dll", SetLastError = true)]
private static extern IntPtr OpenSCManager(string lpMachineName, string lpDatabaseName, uint dwDesiredAccess);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool ChangeServiceConfig(IntPtr hService, uint dwServiceType, uint dwStartType, uint dwErrorControl, string lpBinaryPathName, string lpLoadOrderGroup, IntPtr lpdwTagId, string lpDependencies, string lpServiceStartName, string lpPassword, string lpDisplayName);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool CloseServiceHandle(IntPtr hSCObject);
private static bool ChangeStartupType(string serviceName, uint startType)
{
IntPtr scManager = ServiceSample.OpenSCManager(null, null, ServiceSample.SC_MANAGER_CONNECT);
IntPtr service = ServiceSample.OpenService(scManager, serviceName, ServiceSample.SERVICE_CHANGE_CONFIG | ServiceSample.STANDARD_RIGHTS_WRITE);
bool succeeded = ServiceSample.ChangeServiceConfig(service, ServiceSample.SERVICE_NO_CHANGE, startType, ServiceSample.SERVICE_NO_CHANGE, null, null, IntPtr.Zero, null, null, null, null);
ServiceSample.CloseServiceHandle(service);
ServiceSample.CloseServiceHandle(scManager);
return succeeded;
}
private static void Main()
{
ServiceSample.ChangeStartupType("NetTcpPortSharing", ServiceSample.SERVICE_AUTO_START);
}
}
}
答案 1 :(得分:0)
使用ServiceController
有一个简单的答案System.ServiceProcess.ServiceController netTcpPortSharingService = new System.ServiceProcess.ServiceController("NetTcpPortSharing");
if (netTcpPortSharingService != null)
{
if(netTcpPortSharingService.Status!=ServiceControllerStatus.Running && netTcpPortSharingService.Status!=ServiceControllerStatus.StartPending)
{
netTcpPortSharingService.Start();
}
}