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.
-
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();
0 comments:
Post a Comment