Windows服务如何确定其ServiceName?

NVR*_*RAM 34 c# service windows-services

我看了,找不到一个简单的问题:

Windows服务如何确定启动它的ServiceName?

我知道安装可以破解注册表并添加一个命令行参数,但逻辑上看起来它应该是不必要的,因此这个问题.

我希望比注册表黑客更干净地运行单个二进制文件的多个副本.

编辑:

这是用C#编写的.我的应用程序Main()入口点执行不同的操作,具体取决于命令行参数:

  • 安装或卸载服务.命令行可以提供非默认的ServiceName,并且可以更改工作线程的数量.
  • 作为命令行可执行文件运行(用于调试),
  • 作为"Windows服务"运行.在这里,它创建了一个ServiceBase派生类的实例,然后调用System.ServiceProcess.ServiceBase.Run(instance);

目前,安装步骤将服务名称和线程计数附加到注册表中的ImagePath,以便应用程序可以确定它的ServiceName.

NVR*_*RAM 29

来自:https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?反馈ID = 387024

这是一个WMI解决方案.覆盖ServiceBase.ServiceMainCallback()也可能有效,但这似乎对我有用......

    protected String GetServiceName()
    {
        // Calling System.ServiceProcess.ServiceBase::ServiceNamea allways returns
        // an empty string,
        // see https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=387024

        // So we have to do some more work to find out our service name, this only works if
        // the process contains a single service, if there are more than one services hosted
        // in the process you will have to do something else

        int processId = System.Diagnostics.Process.GetCurrentProcess().Id;
        String query = "SELECT * FROM Win32_Service where ProcessId = " + processId;
        System.Management.ManagementObjectSearcher searcher =
            new System.Management.ManagementObjectSearcher(query);

        foreach (System.Management.ManagementObject queryObj in searcher.Get()) {
            return queryObj["Name"].ToString();
        }

        throw new Exception("Can not get the ServiceName");
    } 
Run Code Online (Sandbox Code Playgroud)

  • 回答我自己的评论:是的,此查询适用于具有64位服务的WIN7。确保在调用Service.Run()之前不要尝试这样做!另外-工作文件夹是Windows \ System32 (2认同)

viv*_*k.m 6

ServiceBase.ServiceName属性提供编译时的服务名称.如果在安装服务时指定其他名称,则ServiceName属性将不会提供正确的名称.所以,我必须使用下面的代码来获取我的服务的服务名称.

它是NVRAM方法的另一种选择(不使用LINQ):

/**
 * Returns the service name of currently running windows service.
 */
static String getServiceName()
{
    ServiceController[] scServices;
    scServices = ServiceController.GetServices();

    // Display the list of services currently running on this computer.
    int my_pid = System.Diagnostics.Process.GetCurrentProcess().Id;

    foreach (ServiceController scTemp in scServices)
    {
        // Write the service name and the display name
        // for each running service.

        // Query WMI for additional information about this service.
        // Display the start name (LocalSytem, etc) and the service
        // description.
        ManagementObject wmiService;
        wmiService = new ManagementObject("Win32_Service.Name='" + scTemp.ServiceName + "'");
        wmiService.Get();

        int id = Convert.ToInt32(wmiService["ProcessId"]);
        if (id == my_pid)
        {
            return scTemp.ServiceName;
#if IS_CONSOLE
            Console.WriteLine();
            Console.WriteLine("  Service :        {0}", scTemp.ServiceName);
            Console.WriteLine("    Display name:    {0}", scTemp.DisplayName);

            Console.WriteLine("    Start name:      {0}", wmiService["StartName"]);
            Console.WriteLine("    Description:     {0}", wmiService["Description"]);

            Console.WriteLine("    Found.......");
#endif
        }
    }
    return "NotFound";
}
Run Code Online (Sandbox Code Playgroud)

我没有首先调用ServiceBase.Run()而错误地尝试在main()中获取Windows服务的名称作为第一行.我们必须在获取其名称之前使用ServiceBase.Run()将可执行文件注册为服务.

参考:http://msdn.microsoft.com/en-us/library/hde9d63a.aspx#Y320

  • +1 指出在调用 ServiceBase.Run() 之前服务名称不可用。回想起来,这似乎很明显,但我正在检查构造函数,并且仍然得到编译时名称。 (2认同)

Mah*_*esh 5

带 Linq 的简短版本

  int processId = System.Diagnostics.Process.GetCurrentProcess().Id;
  ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_Service where ProcessId = " + processId);
  ManagementObjectCollection collection = searcher.Get();
  var serviceName = (string)collection.Cast<ManagementBaseObject>().First()["Name"];
Run Code Online (Sandbox Code Playgroud)