Writing a Control Handler Function
The MyServiceCtrlHandler function in the following example is the Handler function. When this function is called by the dispatcher thread, it handles the control code passed in the Opcode parameter and then calls the SetServiceStatus function to update the service's status. Every time a Handler function receives a control code, it is appropriate to return status with a call to SetServiceStatus regardless of whether the service acts on the control.
When the pause control is received, MyServiceCtrlHandler simply sets the dwCurrentState field in the SERVICE_STATUS structure to SERVICE_PAUSED. Likewise, when the continue control is received, the state is set to SERVICE_RUNNING. Therefore, MyServiceCtrlHandler is not a good example of how to handle the pause and continue controls. Because MyServiceCtrlHandler is a template for a Handler function, code for the pause and continue controls is included for completeness. A service that supports either the pause or continue control should handle these controls in a way that makes sense. Many services support neither the pause or continue control. If the service indicates that it does not support pause or continue with the dwControlsAccepted parameter, then the SCM will not send pause or continue controls to the service's Handler function.
To output debugging information, MyServiceCtrlHandler calls SvcDebugOut. The source code SvcDebugOut is listed in Writing a Service Program's main Function.
VOID MyServiceCtrlHandler (DWORD Opcode)
{
DWORD status;
switch(Opcode)
{
case SERVICE_CONTROL_PAUSE:
// Do whatever it takes to pause here.
MyServiceStatus.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
// Do whatever it takes to continue here.
MyServiceStatus.dwCurrentState = SERVICE_RUNNING;
break;
case SERVICE_CONTROL_STOP:
// Do whatever it takes to stop here.
MyServiceStatus.dwWin32ExitCode = 0;
MyServiceStatus.dwCurrentState = SERVICE_STOPPED_PENDING;
MyServiceStatus.dwCheckPoint = 0;
MyServiceStatus.dwWaitHint = 0;
if (!SetServiceStatus (MyServiceStatusHandle,
&MyServiceStatus))
{
status = GetLastError();
SvcDebugOut(" [MY_SERVICE] SetServiceStatus error
%ld\n",status);
}
SvcDebugOut(" [MY_SERVICE] Leaving MyService \n",0);
return;
case SERVICE_CONTROL_INTERROGATE:
// Fall through to send current status.
break;
default:
SvcDebugOut(" [MY_SERVICE] Unrecognized opcode %ld\n",
Opcode);
}
// Send current status.
if (!SetServiceStatus (MyServiceStatusHandle, &MyServiceStatus))
{
status = GetLastError();
SvcDebugOut(" [MY_SERVICE] SetServiceStatus error
%ld\n",status);
}
return;
}