在.NET框架中,ServiceController类提供了管理和操作Windows服务的功能。然而,它并不提供获取服务可执行文件路径的功能。为了实现这一功能,需要对ServiceController类进行扩展。本文将介绍如何通过继承的方式实现这一功能,并讨论相关的安全处理。
扩展ServiceController类的主要目的是添加获取服务可执行文件路径的功能。可以通过继承ServiceController类并添加新的属性和方法来实现这一目标。
首先,添加一个新的属性ImagePath,用于获取服务的可执行文件路径。这个属性的值在第一次调用时获取,而不是在实例化时获取。这样可以提高效率,但也意味着如果在从远程机器获取数据时连接被断开,可能会得到不可预测的结果。
public class ServiceController : System.ServiceProcess.ServiceController
{
private string m_ImagePath;
public string ImagePath
{
get
{
if (m_ImagePath == null)
{
m_ImagePath = GetImagePath();
}
return m_ImagePath;
}
}
// 其他代码...
}
接下来,重写DependentServices和ServicesDependedOn属性,使它们返回ServiceController类型的数组,而不是System.ServiceProcess.ServiceController类型的数组。
public new ServiceController[] DependentServices
{
get
{
if (m_DependentServices == null)
{
m_DependentServices = ServiceController.GetServices(base.DependentServices);
}
return m_DependentServices;
}
}
public new ServiceController[] ServicesDependedOn
{
get
{
if (m_ServicesDependedOn == null)
{
m_ServicesDependedOn = ServiceController.GetServices(base.ServicesDependedOn);
}
return m_ServicesDependedOn;
}
}
最后,重写GetServices静态方法,使其返回ServiceController类型的数组。
public static new ServiceController[] GetServices()
{
return GetServices(".");
}
public static new ServiceController[] GetServices(string machineName)
{
return GetServices(System.ServiceProcess.ServiceController.GetServices(machineName));
}
private static ServiceController[] GetServices(System.ServiceProcess.ServiceController[] systemServices)
{
List services = new List(systemServices.Length);
foreach (System.ServiceProcess.ServiceController service in systemServices)
{
services.Add(new ServiceController(service.ServiceName, service.MachineName));
}
return services.ToArray();
}
使用扩展后的ServiceController类非常简单。只需要调用GetServices方法获取服务列表,然后遍历这个列表,就可以获取每个服务的名称、显示名称和可执行文件路径。
static void Main(string[] args)
{
ServiceController[] services = ServiceController.GetServices("bwdemo");
foreach (ServiceController service in services)
{
Console.WriteLine("ServiceName: {0}; DisplayName: {1}", service.ServiceName, service.DisplayName);
Console.WriteLine("Image Path: {0}\n", service.ImagePath);
}
Console.ReadLine();
}
在处理远程服务时,安全是一个重要的考虑因素。ServiceController类本身并不处理安全模拟,因此需要在调用代码中处理。虽然作者没有亲自测试,但如果aleksisa的代码可以工作,那么这部分代码也应该可以工作。
此外,如果只需要获取服务列表,那么在远程计算机上设置相同的用户名和密码就足够了。