2015-05-18 77 views
6

我寫了一個小服務,它充當本地網絡服務器。要編寫服務,我遵循tutorial on MSDN,如何使用ServiceBase類編寫服務。服務導致SCM錯誤「報告無效當前狀態0」

但是當我註冊並啓動服務時,我收到如下所示的錯誤消息。在開始和停止服務時,我收到了兩條錯誤消息。 (示例=服務的名稱)。

示例服務報告了一個無效的當前狀態0

這裏我服務的最少的樣品與所有相關零件。代碼開頭這是在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; 
}; 

在此之後,該服務代碼我寫的,減少到相關部分:

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); 
    } 
} 

的主入口點很簡單,因爲這:

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

正如你所看到的,錯誤信息的數量相匹配的SetServiceState呼叫的數量。如果我添加其他此類調用,錯誤消息的數量會相應增加。

因此,我認爲,整個問題在我調用SetServiceStatus API的方式中,但我目前看不到問題。

你能發現問題嗎?

無論如何,這是使用C#和.NET構建服務的正確方法嗎?

回答

14

第一:

這通常不需要調用SetServiceState方法。如果你的服務真的需要很長時間才能初始化(你可以告訴SCM你還活着SERVICE_START_PENDING並且需要幾秒鐘),這可能是需要的。通常情況下,你在OnStart開始一個線程,並儘快返回。

我在C#寫了很多服務在過去的幾年,從不需要這個。

但是 - 我發現了一個MSDN示例代碼中的錯誤(我自己測試了您的代碼)。

ServiceStatus結構中用int或(更好的單位)替換long。如果使用uint,則還必須在SetServiceState方法中更改此項。請參閱Should DWORD map to int or uint?

如果你有興趣在一個小的介紹瞭如何在C#中的Windows服務與額外的設置啓動,你可以檢查我的博客文章:

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

[更新2018年1月20日]

我創造了約一個新的文章,它使用其優點(至少對我來說)自安裝方法,它不需要Visual Studio的

01的安裝項目延期

+0

太好了,謝謝,這解決了這個問題。我通常意識到MSDN文檔有多糟糕,但在這裏我只是假設這個例子中的結構定義是正確的。你也是對的,手動狀態更新並不是必須的。我的代碼的啓動在第一個版本中花了很長時間,但是我將所有內容都移到了一個線程中,因爲這些長進程的結果與啓動無關。偉大的博客條目,只是逐步列表的格式讓我幾乎感到頭痛;-)。 – Flovdis

+0

太棒了,它爲我工作。這是不可能的計算MSDN有多少錯誤....這是無限數量之一... – Fabiano

+0

非常感謝,Rainer - 我使用微軟的示例代碼來創建一個服務,並直接打這個問題。我還在此處爲他們的頁面添加了一條評論(https://technet.microsoft.com/en-us/library/cc756305(v=ws.10).aspx),指向您的解決方案。 – Rich