获取已安装服务的版本信息?

7
我想通过程序检查我的Windows服务的最新版本是否已安装。我有以下代码:
var ctl = ServiceController.GetServices().Where(s => s.ServiceName == "MyService").FirstOrDefault();
if (ctl != null) {
  // now what?
}

我在ServiceController接口中没有看到任何可以告诉我版本号的内容。我该怎么做?


你有看过这个吗... https://dev59.com/LHM_5IYBdhLWcg3wfTO7 - Aaron McIver
@Aaron - 谢谢,那是一个很好的起点! :) - Shaul Behr
3个回答

12

恐怕没有其他办法可以获取可执行文件路径,因为ServiceController不提供该信息。

以下是我以前创建的示例:

private static string GetExecutablePathForService(string serviceName, RegistryView registryView, bool throwErrorIfNonExisting)
    {
        string registryPath = @"SYSTEM\CurrentControlSet\Services\" + serviceName;
        RegistryKey key = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, registryView).OpenSubKey(registryPath);
        if(key==null)
        {
            if (throwErrorIfNonExisting)
                throw new ArgumentException("Non-existent service: " + serviceName, "serviceName");
            else
                return null;
        }
        string value = key.GetValue("ImagePath").ToString();
        key.Close();
        if(value.StartsWith("\""))
        {
            value = Regex.Match(value, "\"([^\"]+)\"").Groups[1].Value;
        }

        return Environment.ExpandEnvironmentVariables(value);
    }
在获取exe路径后,只需使用FileVersionInfo.GetVersionInfo(exePath)类获取版本信息。

+1 谢谢!如何将 FileVersionInfo 与从 Assembly.GetAssembly(...).GetName().Version 返回的 Version 对象进行比较? - Shaul Behr
2
这应该会给你文件版本号,而你提到的那个是程序集版本号。如果你需要程序集版本号,那么你必须将其作为一个程序集加载(正如你所提到的)。但是请注意,一旦你加载了它,即使你以 ReflectionOnly 的方式加载,直到你的进程终止之前,你都已经锁定了该文件。 - Aliostad
我很好奇这个正则表达式在这里做了什么? 我明白“如果值以引号开头,那么...”它似乎是在去掉前导和尾随引号 - 和 value = value.Trim(new[] { '"' }); 做的一样..但它还在做些其他的事情吗? - ckittel
1
@ckittel 它修剪它。但是由于该值末尾有一些内容,因此普通的修剪无法正常工作:"c:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\Binn\sqlservr.exe" -sMSSQLSERVER - Aliostad
这很有道理,谢谢。我没有考虑命令行参数。 - ckittel

2
如果您拥有该服务,您可以将版本信息放入DisplayName中,例如DisplayName="MyService 2017.06.28.1517"。这样就可以找到现有安装的服务并解析版本信息。
var ctl = ServiceController
    .GetServices()
    .FirstOrDefault(s => s.ServiceName == "MyService");
if (ctl != null) {
    // get version substring, you might have your own style.
    string substr = s.DisplayName.SubString("MyService".Length);
    Version installedVersion = new Version(substr);
    // do stuff, e.g. check if installed version is newer than current assembly.
}

如果您想避免使用注册表,这可能很有用。问题在于,服务条目可能会根据安装例程而放置在注册表的不同部分。


0

如果你想要从程序集属性中自动获取服务的当前版本,可以在ServiceBase类中设置以下属性。

public static string ServiceVersion { get; private set; }

然后在你的OnStart方法中添加以下内容...

ServiceVersion = typeof(Program).Assembly.GetName().Version.ToString();

完整示例

using System.Diagnostics;
using System.ServiceProcess;

public partial class VaultServerUtilities : ServiceBase
{

    public static string ServiceVersion { get; private set; }

    public VaultServerUtilities()
    {
        InitializeComponent();

        VSUEventLog = new EventLog();
        if (!EventLog.SourceExists("Vault Server Utilities"))
        {
            EventLog.CreateEventSource("Vault Server Utilities", "Service Log");
        }

        VSUEventLog.Source = "Vault Server Utilities";
        VSUEventLog.Log = "Service Log";

    }


    protected override void OnStart(string[] args)
    {

        ServiceVersion = typeof(Program).Assembly.GetName().Version.ToString();
        VSUEventLog.WriteEntry(string.Format("Vault Server Utilities v{0} has started successfully.", ServiceVersion));

    }

    protected override void OnStop()
    {
        VSUEventLog.WriteEntry(string.Format("Vault Server Utilities v{0} has be shutdown.", ServiceVersion));
    }
}

在上面的示例中,我的事件日志显示了我的服务的当前版本... 输入图像描述

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接