2009-12-03 23 views
27

Tôi đã xem và không thể tìm thấy câu hỏi đơn giản:Dịch vụ Windows có thể xác định ServiceName của nó như thế nào?

Dịch vụ Windows xác định ServiceName được khởi động như thế nào?

Tôi biết việc cài đặt có thể hack tại sổ đăng ký và thêm đối số dòng lệnh, nhưng về mặt logic có vẻ như là nên không cần thiết, do đó, câu hỏi này.

Tôi hy vọng sẽ chạy nhiều bản sao của một nhị phân đơn sạch hơn đăng ký hack.

Sửa:

này được viết bằng C#. Ứng dụng của tôi Main() điểm vào làm những việc khác nhau, tùy thuộc vào đối số dòng lệnh :

  • Cài đặt và gỡ bỏ dịch vụ. Dòng lệnh có thể cung cấp ServiceName không mặc định và có thể thay đổi số lượng chuỗi công việc.
  • Chạy dưới dạng dòng lệnh thực thi (để gỡ lỗi),
  • Chạy dưới dạng "Dịch vụ Windows". Ở đây, nó tạo ra một thể hiện của lớp ServiceBase -derived của tôi, sau đó gọi System.ServiceProcess.ServiceBase.Run (ví dụ);

Hiện nay, các bước cài đặt gắn thêm tên dịch vụ và chủ đề đếm đến ImagePath trong registry để ứng dụng có thể xác định đó là ServiceName.

+0

Bạn không đề cập đến ngôn ngữ bạn đã viết dịch vụ. – Walter

Trả lời

24

Từ: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=387024

Đây là giải pháp WMI. Trọng các ServiceBase.ServiceMainCallback() cũng có thể làm việc, nhưng điều này dường như làm việc cho tôi ...

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"); 
    } 
+1

Đối với dịch vụ 64 bit sẽ "chọn * Từ Win32_Service" vẫn hoạt động? – shindigo

+1

Trả lời nhận xét của riêng tôi: có truy vấn này hoạt động trên WIN7 với dịch vụ 64 bit. Hãy chắc chắn rằng bạn không cố gắng này trước khi theService.Run() được gọi! Ngoài ra - thư mục làm việc là Windows \ System32 – shindigo

+0

Cảm ơn bạn đã dành thời gian để đăng bài này, bạn đã tiết kiệm cho tôi rất nhiều đau đớn. – Waltzy

1

Điểm nhập ServiceMain() mà mọi dịch vụ thực thi phải thực hiện nhận ServiceName làm đối số đầu vào đầu tiên của nó.

Nếu bạn đang viết dịch vụ của mình bằng .NET, điểm vào ServiceMain() được .NET thực hiện cho bạn. ServiceName được gán khi dịch vụ được cài đặt bằng thuộc tính ServiceProcess.ServiceBase.ServiceName. Nếu bạn đang cố gắng tùy chỉnh một dịch vụ .NET để hỗ trợ các giá trị ServiceName động, tôi không có đầu mối làm thế nào để truy cập vào ServiceName thực tế khi chạy.

+0

để xác định tại thời điểm chạy lệnh SC QUERYEX – lsalamon

+0

@Remy - có vẻ như ServiceMain là dành cho mã C++ (http://msdn.microsoft.com/en-us/library/ms685138%28VS.85%29.aspx), tôi đang sử dụng C#. @Isalamon - Tôi tin rằng bạn đang nhầm lẫn, nhưng nếu bạn có thể hiển thị như thế nào ** SC ** có thể được sử dụng, xin vui lòng gửi một câu trả lời với các chi tiết. – NVRAM

+0

Thậm chí các dịch vụ .NET có một điểm vào ServiceMain(), chỉ là một .NET thực hiện cho bạn (phương thức ServiceBase.ServiceMainCallback()). Tôi chỉ nhận thấy rằng sự kiện ServiceBase.OnStart có tham số args. Tôi đã không viết các dịch vụ trong .NET, nhưng giả sử ServiceBase không loại bỏ tham số đầu tiên được cung cấp bởi ServiceMain() (ServiceName) khi xây dựng tham số args, thì bạn có thể rút ra ServiceName từ nó. –

5

tài sản ServiceBase.ServiceName cho tên thời gian biên dịch của dịch vụ. Nếu bạn chỉ định một tên khác khi cài đặt dịch vụ, thì thuộc tính ServiceName sẽ không cung cấp tên chính xác. Vì vậy, tôi đã phải sử dụng mã dưới đây để có được tên dịch vụ của dịch vụ của tôi.

Đó là một sự thay thế (không sử dụng LINQ) phương pháp NVRAM của:

/** 
* 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"; 
} 

Tôi đã sai cố gắng để có được tên của dịch vụ cửa sổ như dòng đầu tiên trong hàm main() mà không gọi ServiceBase.Run().Chúng ta phải đăng ký tệp thực thi của chúng tôi dưới dạng dịch vụ bằng ServiceBase.Run() trước khi lấy tên của nó.

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

+1

+1 để chỉ ra rằng tên dịch vụ không có sẵn cho đến khi ServiceBase.Run() được gọi. Nhìn lại, nó có vẻ hiển nhiên, nhưng tôi đã kiểm tra trong nhà xây dựng, và vẫn nhận được tên biên dịch. – msulis

+1

Điều gì xảy ra nếu chúng tôi đang lưu trữ nhiều dịch vụ trong cùng một exe? Chúng sẽ được thực hiện trong các quá trình khác nhau? Nếu không thì chúng ta cần phải nói tên của dịch vụ của chuỗi hiện tại thay vì quá trình hiện tại. Trong trường hợp đó chúng ta có thể làm điều đó như thế nào? – drowa

2

phiên bản ngắn với 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"]; 
0

Bằng cách tìm kiếm một giải pháp tốt hơn tôi đã cố gắng này:

string serviceName = "myDynamicServiceName"; 
string serviceBin = "path\\to\\Service.exe"; 
string configFile = "path\\to\\myConfig.xml"; 
string credentials = "obj= .\\mytestuser password= test"; 

string scCommand = string.Format("sc create {0} start= auto binPath= \"\\\"{1}\\\" -ini={2} -sn={3}\" type= own{4}", serviceName, serviceBin, configFile , serviceName ,credentials); 

tôi đã thông qua servicename và một tập tin cấu hình cho binpath. Dịch vụ này đã được cài đặt bằng cách sử dụng các Sc.exe (tôi không sử dụng các installutil!)

Trên dịch vụ mà bạn có thể nhận được các dòng lệnh-Arguments

protected override void OnStart(string[] args){ 
    string binpath = new System.IO.FileInfo(System.Reflection.Assembly.GetAssembly(this.GetType()).Location).DirectoryName + "\\"; 
    System.IO.StreamWriter sw = new System.IO.StreamWriter(binpath + "test.log"); 

    sw.WriteLine(binpath); 

    string[] cmdArgs = System.Environment.GetCommandLineArgs(); 
    foreach (string item in cmdArgs) { 
     sw.WriteLine(item); 
    } 

    sw.Flush(); 
    sw.Dispose(); 
    sw = null; 
} 
0

Có gì sai với this.ServiceName, nếu bạn đang ở trong service.cs?

ví dụ:

protected override void OnStart(string[] args) 
    { 
     Logger.Info($"{this.ServiceName} started on {Environment.MachineName}..."); 
    } 
+2

Đây không phải là tên dịch vụ tương tự xuất hiện trong danh sách Dịch vụ Windows: ( – fabriciorissetto

+0

ServiceBase.ServiceName và ServiceInstaller.ServiceName là hai thuộc tính khác nhau, nhưng chúng phải giống nhau. https://docs.microsoft.com/en-us/dotnet/api/system.serviceprocess.serviceinstaller?view=netframework-4.7.1 –

0

Tôi đã có một vấn đề con gà và quả trứng mà tôi cần phải biết vị trí dịch vụ trước khi hoàn tất Service.Run() (Dịch vụ có thể là một phần của một khách hàng hoặc máy chủ cài đặt, cài đặt đặt tên cho chúng một cách thích hợp và tôi cần phải phát hiện ra nó đang khởi động)

Tôi dựa vào sổ đăng ký để lấy cho tôi tên.

public String IdentifySelfFromRegistry() 
{ 
    String executionPath = Assembly.GetEntryAssembly().Location; 
    Microsoft.Win32.RegistryKey services = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(
      @"SYSTEM\CurrentControlSet\services"); 
    if (services != null) 
    { 
     foreach(String subkey in services.GetSubKeyNames()) 
     { 
      if (executionPath.Equals(ServicePathFromServiceKey(services.OpenSubKey(subkey)))) 
       return subkey; 
     } 
    } 
    return String.Empty; 
} 

protected static String ServicePathFromServiceKey(Microsoft.Win32.RegistryKey serviceKey) 
{ 
    if (serviceKey != null) 
    { 
     String exec = serviceKey.GetValue(ServicePathEntry) as String; 
     if (exec != null) 
      return exec.Trim('\"'); 
    } 
    return String.Empty; 
} 
Các vấn đề liên quan