Geoff Chappell, Software Analyst
A service DLL in a SVCHOST process exports this function as its entry point for starting services.
VOID WINAPI ServiceMain (DWORD dwArgc, LPWSTR *lpszArgv);
The dwArgc argument is the number of null-terminated Unicode strings described by the lpszArgv argument. The first such string is the (case-insensitive) name of the service that is being started.
The ServiceMain function for a service that is implemented in a service DLL running in a SVCHOST instance is essentially the same as if the service were implemented in a service program. The essential differences are that:
Key | HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\service\Parameters
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\service |
Value | ServiceMain |
Type | REG_SZ |
Default | ServiceMain |
where service is the name of the service that is being started. Until SVCHOST version 6.0, the value can be in the Parameters subkey only. Version 6.00 accepts a value in the parent key if the Parameters subkey is not present.
Although a service DLL is unlikely in practice to implement more than one service, it is not restricted to just the one, and it can export as many ServiceMain functions as it cares to. It can have one ServiceMain to handle the start of any service, relying on the first string described by lpszArgv to indicate which service is being started. At the other extreme, it can have one ServiceMain for each service, all named differently, all (or all but one) configured in the registry.
A ServiceMain function in a service DLL can be coded as for one in a service program. Refer to Microsoft’s documentation. However, some work that might be done in a service program can be avoided in a service DLL because it is already done by SVCHOST. First, there is per-process initialisation which is not only convenient to be done by SVCHOST but is perhaps better attempted only once per process (as with initialising COM security). Second, though only since version 5.1, SVCHOST provides service DLLs with access to shared code and data. To learn the addresses, a service DLL should export a function named SvchostPushServiceGlobals, which SVCHOST calls before each call to any ServiceMain function in the DLL.
An important, though recent, feature of the shared code is to provide service DLLs with a very slight change of coding that allows SVCHOST to unload a service DLL that is no longer in use. To obtain this benefit, where a service program would call the KERNEL32 function RegisterWaitForSingleObject to arrange a callback for stopping a service, a service DLL instead calls the SVCHOST function RegisterStopCallback.
In version 6.0, SVCHOST logs each call to ServiceMain as an event, such that it may be retrieved through the Event Viewer in the Diagnostic channel under the heading Microsoft Windows Services Svchost Performance Diagnostic Provider. Each call is preceded by event 101 and each return is marked as event 102. For both, the event data is the service’s name. This event log provides ready confirmation that many services implemented in service DLLs do not return from ServiceMain until stopped.
The ServiceMain function in service DLLs is supported by SVCHOST.EXE in all known versions (5.0 and higher).