Thursday, April 14, 2011

Signalling Initialization Failure from Service.OnStart

We have a case where during Service startup (OnStart), a worker thread is started. The worker thread connects to a SQL database. If the database is unavailable, the worker thread can signal the main thread of the failure. The question is; How to signal the Service Control Manager that startup has failed.

From stackoverflow
  • This is how we handled this situation. This code was added to our main service class and then at the point where we wanted to return startup as failed, made a call to SetServiceFail(1065) followed by a return from OnStart. In this case 1065 returns a database does not exist status.

    I would also note that in SetServiceFail I hard-coded the serviceType since in our case all of our services are stand-alone so I kept it simple.

    private void SetServiceFail (int ErrorCode)
    {
         SERVICE_STATUS _ServiceStatus = new SERVICE_STATUS ();
         _ServiceStatus.currentState = (int) State.SERVICE_STOPPED;
         _ServiceStatus.serviceType = 16; //SERVICE_WIN32_OWN_PROCESS
         _ServiceStatus.waitHint = 0;
         _ServiceStatus.win32ExitCode = ErrorCode;
         _ServiceStatus.serviceSpecificExitCode = 0;
         _ServiceStatus.checkPoint = 0;
         _ServiceStatus.controlsAccepted = 0 |
               (this.CanStop ? (int) ControlsAccepted.ACCEPT_STOP : 0) |
               (this.CanShutdown ? (int) ControlsAccepted.ACCEPT_SHUTDOWN : 0) |
               (this.CanPauseAndContinue ? (int) ControlsAccepted.ACCEPT_PAUSE_CONTINUE : 0) |
               (this.CanHandleSessionChangeEvent ? (int) ControlsAccepted.ACCEPT_SESSION_CHANGE : 0) |
               (this.CanHandlePowerEvent ? (int) ControlsAccepted.ACCEPT_POWER_EVENT : 0);
         SetServiceStatus (this.ServiceHandle, ref _ServiceStatus);
    }
    
    public enum State
    {
         SERVICE_STOPPED = 1,
         SERVICE_START_PENDING = 2,
         SERVICE_STOP_PENDING = 3,
         SERVICE_RUNNING = 4,
         SERVICE_CONTINUE_PENDING = 5,
         SERVICE_PAUSE_PENDING = 6,
         SERVICE_PAUSED = 7
    }
    
    public enum ControlsAccepted
    {
         ACCEPT_STOP = 1,
         ACCEPT_PAUSE_CONTINUE = 2,
         ACCEPT_SHUTDOWN = 4,
         ACCEPT_POWER_EVENT = 64,
         ACCEPT_SESSION_CHANGE = 128
    }
    
    [StructLayout (LayoutKind.Sequential)]
    private struct SERVICE_STATUS
    {
         public int serviceType;
         public int currentState;
         public int controlsAccepted;
         public int win32ExitCode;
         public int serviceSpecificExitCode;
         public int checkPoint;
         public int waitHint;
    }
    
    [DllImport ("advapi32.dll")]
    private static extern bool SetServiceStatus (IntPtr hServiceStatus, ref SERVICE_STATUS lpServiceStatus);
    
  • One way to stop it is to use the ServiceController, but you wont get any fancy message in the service control manager about an error or a failure to start.

    
    var controller = new System.ServiceProcess.ServiceController("NameOfYourService");
    controller.Stop();
    
  • http://www.boyet.com/Articles/dotNETServicesOnStart.html

0 comments:

Post a Comment