2015-05-18 17 views
6

Tôi đã viết một dịch vụ nhỏ, hoạt động như một máy chủ mạng cục bộ. Để viết dịch vụ, tôi đã theo dõi tutorial on MSDN, cách viết dịch vụ bằng cách sử dụng lớp ServiceBase.Dịch vụ gây ra lỗi SCM "báo cáo trạng thái hiện tại không hợp lệ 0"

Nhưng khi tôi đăng ký và bắt đầu dịch vụ, tôi nhận được thông báo lỗi như được hiển thị bên dưới. Tôi nhận được chính xác hai thông báo lỗi này lúc bắt đầu và tại điểm dừng dịch vụ. (Ví dụ = tên dịch vụ).

Các dịch vụ Ví dụ đã thông báo tình trạng hiện thời không hợp lệ 0.

Dưới đây là một mẫu tối thiểu của các dịch vụ của tôi với tất cả các bộ phận liên quan. Mã này bắt đầu với một định nghĩa enum và struct được cung cấp trong hướng dẫn MSDN:

public enum ServiceState 
{ 
    SERVICE_STOPPED = 0x00000001, 
    SERVICE_START_PENDING = 0x00000002, 
    SERVICE_STOP_PENDING = 0x00000003, 
    SERVICE_RUNNING = 0x00000004, 
    SERVICE_CONTINUE_PENDING = 0x00000005, 
    SERVICE_PAUSE_PENDING = 0x00000006, 
    SERVICE_PAUSED = 0x00000007, 
} 

[StructLayout(LayoutKind.Sequential)] 
public struct ServiceStatus 
{ 
    public long dwServiceType; 
    public ServiceState dwCurrentState; 
    public long dwControlsAccepted; 
    public long dwWin32ExitCode; 
    public long dwServiceSpecificExitCode; 
    public long dwCheckPoint; 
    public long dwWaitHint; 
}; 

Sau đó, các mã dịch vụ tôi đã viết, giảm đến các bộ phận có liên quan:

namespace example 
{ 
    public partial class Service : ServiceBase 
    { 
     public Service() 
      : base() 
     { 
      this.ServiceName = "ExampleService"; 
      this.AutoLog = false; 
      this.CanStop = true; 
      this.CanShutdown = false; 
      this.CanPauseAndContinue = false; 
      this.CanHandlePowerEvent = false; 
      this.CanHandleSessionChangeEvent = false; 
     } 

     protected override void OnStart(string[] args) 
     { 
      try { 
       SetServiceState(ServiceState.SERVICE_START_PENDING, 100000); 
       // ... initialise and start... 
       SetServiceState(ServiceState.SERVICE_RUNNING); 
      } catch (System.Exception ex) { 
       SetServiceState(ServiceState.SERVICE_STOPPED); 
      } 
     } 

     protected override void OnStop() 
     { 
      SetServiceState(ServiceState.SERVICE_STOP_PENDING, 100000); 
      // ... stop service ... 
      SetServiceState(ServiceState.SERVICE_STOPPED); 
     } 

     private void SetServiceState(ServiceState state, int waitHint = 0) 
     { 
      ServiceStatus serviceStatus = new ServiceStatus(); 
      serviceStatus.dwCurrentState = state; 
      serviceStatus.dwWaitHint = waitHint; 
      SetServiceStatus(this.ServiceHandle, ref serviceStatus); 
     } 

     [DllImport("advapi32.dll", SetLastError=true)] 
     private static extern bool SetServiceStatus(IntPtr handle, ref ServiceStatus serviceStatus); 
    } 
} 

các điểm nhập cảnh chính là đơn giản như thế này:

static void Main(string[] args) 
{ 
    ServiceBase.Run(new Service()); 
} 

như bạn có thể thấy, số lượng các thông báo lỗi phù hợp với số SetServiceState cuộc gọi. Nếu tôi thêm các cuộc gọi như vậy, số lượng thông báo lỗi sẽ tăng lên tương ứng.

Vì vậy, tôi giả sử, toàn bộ vấn đề là một nơi nào đó theo cách tôi gọi API SetServiceStatus, nhưng hiện tại tôi không thể thấy sự cố.

Bạn có thể phát hiện sự cố không?

Dù sao đây có phải là cách chính xác để xây dựng Dịch vụ bằng C# và .NET không?

Trả lời

14

Đầu tiên:

Nó là bình thường không cần thiết phải gọi phương thức SetServiceState. Nó có thể là cần thiết nếu dịch vụ của bạn thực sự mất một thời gian dài để khởi tạo (nơi bạn có thể nói với SCM bạn vẫn còn sống với SERVICE_START_PENDING và cần thêm vài giây nữa). Thông thường, bạn bắt đầu một sợi trong OnStart và trả lại càng sớm càng tốt.

Tôi đã viết nhiều dịch vụ trong C# những năm qua và không bao giờ cần đến điều này.

Nhưng - tôi đã tìm thấy lỗi trong mã mẫu MSDN (tôi đã tự kiểm tra mã của bạn).

Trong cấu trúc ServiceStatus thay thế dài bằng int hoặc (đơn vị tốt hơn). Nếu bạn sử dụng uint, bạn cũng phải thay đổi phương thức này theo phương thức SetServiceState.

Đồng thời xem Should DWORD map to int or uint?.

Nếu bạn quan tâm đến một giới thiệu nhỏ làm thế nào bạn có thể bắt đầu với một dịch vụ Windows trong C# với một thiết lập bổ sung, bạn có thể kiểm tra blog entry của tôi:

http://www.rsprog.de/samplewindowsservice/

[Cập nhật 2018/01/20 ]

tôi tạo ra một bài viết mới về điều đó, trong đó sử dụng các phương pháp tự cài đặt mà có lợi thế (ít nhất là đối với tôi), mà nó không cần phần mở rộng dự án thiết lập của Visual Studio

http://www.rsprog.de/windowsserviceselfinstall/

+0

Tuyệt vời, cảm ơn bạn, điều này đã giải quyết được vấn đề. Tôi thường biết làm thế nào xấu tài liệu MSDN là, nhưng ở đây tôi chỉ giả định định nghĩa cấu trúc này từ ví dụ là chính xác. Bạn cũng đúng, các cập nhật trạng thái thủ công không thực sự cần thiết. Việc khởi động mã của tôi mất một thời gian dài trong phiên bản đầu tiên, nhưng tôi đã chuyển mọi thứ trong một luồng, bởi vì kết quả của một số quy trình dài này không liên quan đến việc khởi động. Great blog entry, chỉ cần định dạng của danh sách từng bước đã cho tôi gần như nhức đầu ;-). – Flovdis

+0

Tuyệt vời, nó làm việc cho tôi. Không thể đếm được bao nhiêu lỗi MSDN có .... đây là một trong số vô hạn ... – Fabiano

+0

Cảm ơn rất nhiều, Rainer - Tôi đã sử dụng mã mẫu của Microsoft để tạo một dịch vụ và nhấn chính xác vấn đề này ngay lập tức. Tôi cũng đã thêm một bình luận vào trang của họ ở đây (https://technet.microsoft.com/en-us/library/cc756305(v=ws.10).aspx) trỏ đến giải pháp của bạn ở đây. – Rich

Các vấn đề liên quan