Geoff Chappell, Software Analyst
A service DLL running in a SVCHOST process calls this function to register a callback for stopping a service.
Access to the function is indirect, through the RegisterStopCallback member of the SVCHOST_GLOBAL_DATA structure whose address was passed to the service DLL’s SvchostPushServiceGlobals function. The member has the following type definition:
typedef DWORD (WINAPI *LPREGISTER_STOP_CALLBACK) ( HANDLE *phNewWaitObject, PCWSTR pszServiceName, HANDLE hObject, WAITORTIMERCALLBACK Callback, PVOID Context, DWORD dwFlags);
The phNewWaitObject argument provides the address of a variable that is to receive a wait handle.
The pszServiceName argument is the address of a (case-insensitive) name of the service for which the stop callback is being registered.
The hObject argument is a handle to an object that the service DLL will signal when the given service is stopping.
The Callback argument is the address of a function that is to be called back in another thread after the object is signalled. The prototype is the same as for the documented RegisterWaitForSingleObject function.
The Context argument is an arbitrary value that is to be passed back to the service DLL as the lpParameter argument for the callback function.
The dwFlags argument provides bit flags to vary behaviour. These flags are the same as for the RegisterWaitForSingleObject function.
The function returns zero for success, else an error code.
This function is intended to be called from a service DLL’s ServiceMain function. Where the same service if implemented in a service program might call the RegisterWaitForSingleObject function in accordance with Microsoft’s documentation for writing a ServiceMain function, it instead calls the RegisterStopCallback function.
If any of phNewWaitObject, pszServiceName, hObject and Callback are NULL, the function fails (returning ERROR_INVALID_PARAMETER). If the given service is not configured for execution in this instance of SVCHOST, the function fails (returning ERROR_INVALID_DATA). This is also the outcome if the service already has a callback registered.
The function registers its own callback with the KERNEL32 function RegisterWaitForSingleObject. It passes the phNewWaitObject, hObject and dwFlags arguments as given, but specifies an infinite timeout and provides its own callback and context. Setting up this context may fail for lack of memory, causing the function to fail (returning ERROR_NOT_ENOUGH_MEMORY). If the registration fails, its error code is returned as the function’s error code.
When the function returns success, the variable at the address specified as phNewWaitObject contains a cookie (not formally a handle) that represents the wait condition. The wait can be cancelled by passing this cookie to UnregisterWait or UnregisterWaitEx, and must be cancelled from the callback if not before.
When the service is to stop, has set the service’s status as SERVICE_STOP_PENDING and has done as much cleaning up as it can do from its control handler, it should signal the object it specified as hObject. Some other thread will then be found for executing the callback function that SVCHOST registered. In turn, SVCHOST will call the service DLL’s callback function that was specified as the Callback argument. This callback function, with prototype
VOID CALLBACK Callback (PVOID lpParameter, BOOLEAN TimerOrWaitFired);
will receive as its lpParameter argument whatever was passed as the Context. The TimerOrWaitFired argument should always be FALSE. In addition to whatever the callback function may need to do for the service’s own purposes, it has the following responsibilities to SVCHOST and to the Service Control Manager:
The point to registering the callback with SVCHOST instead of calling RegisterWaitForSingleObject directly is that SVCHOST can know to unload the service DLL when the callback is done. Unloading occurs if the following conditions are both satisfied:
|Availability||version 5.1 from Windows XP SP2, version 5.2 from Windows Server 2003 SP1, and higher|
where service is the name of the service that has stopped.
The RegisterStopCallback function is exposed to service DLLs by SVCHOST.EXE in version 5.1 from Windows XP SP2, version 5.2 from Windows Server 2003 SP1, and higher.
Note that a service DLL has no formal means to determine if the SVCHOST_GLOBAL_DATA structure it receives from SVCHOST actually does provide for a RegisterStopCallback function.
Microsoft does not formally document either this function or the structure that it is learnt through—or, for that matter, how to write a service DLL to run under SVCHOST. That said, the function does rate a mention in Guidelines for Services (Windows) which is otherwise about the Restart Manager.