In this post I am going to explain how pre-shutdown notification can be enabled and handled in C# Windows service.
The need for pre-shutdown notification
Starting from Windows Vista on wards Windows provides an mechanism to notify applications/services about the system shutdown/reboot. Though shutdown notification was already supported through ServiceBase
class’s CanShutdown
property and OnShutdown
method their functionality is very limited.
The limitation of OnShutdown
method is, limited time given for the cleanup work and there is no guarantee that other essential services(e.g. DB, EventLog) are running. The last point is the fundamental reason why Microsoft brought this pre-shutdown notification.
Enabling pre-shutdown notification
If we are developing a Win32 application it is really easy to enable pre-shutdown notification. All we need to do is include SERVICE_ACCEPT_PRESHUTDOWN
flag in dwControlsAccepted
field of service’s SERVICE_STATUS
structure.
But in .NET’s ServiceBase class there is no direct way to enable pre-shutdown notification. We can achieve the goal by accessing the ServiceBase class’s internals through .NET reflection.
const int SERVICE_ACCEPT_PRESHUTDOWN = 0x100;
const int SERVICE_CONTROL_PRESHUTDOWN = 0xf;
MyService
{
...
FieldInfo acceptedCommandsFieldInfo =
typeof(ServiceBase).GetField("acceptedCommands", BindingFlags.Instance | BindingFlags.NonPublic);
if (acceptedCommandsFieldInfo == null)
throw ApplicationException("acceptedCommands field not found");
int value = (int)acceptedCommandsFieldInfo.GetValue(this);
acceptedCommandsFieldInfo.SetValue(this, value | SERVICE_ACCEPT_PRESHUTDOWN);
}
In the constructor of the service MyService
we add the SERVICE_ACCEPT_PRESHUTDOWN
flag to acceptedCommands
private field of ServiceBase using reflection. This enables the pre-shutdown notification.
Handling pre-shutdown notification
The pre-shutdown notification is delivered through the ServiceBase class’s OnCustomCommand
method. This method is called whenever a command is sent to the service which is not supported by ServiceBase. The method provides a parameter command
which holds the command code. So to handle the pre-shutdown notification we need to check whether the command
matches with pre-shutdown notification code.
protected override void OnCustomCommand(int command)
{
if (command == SERVICE_CONTROL_PRESHUTDOWN)
{
// do the clean-up here
}
else
base.OnCustomCommand(command);
}
So that is all we need to enable and handle pre-shutdown notification.