Step 2: The ServiceMain Function
shows the code for ServiceMain. This function is the entry point of a service. It runs in a separate thread, which is created by the control dispatcher. ServiceMain should register the control handler for a service as soon as possible. Do this by calling the RegisterServiceCtrlHadler function. You will pass two arguments to this function: the service name and the pointer to the ControlHandlerfunction.
This instructs the control dispatcher to invoke the ControlHandler function to handle SCM control requests. After registering the control handler, obtain the status handle (hStatus). Use hStatus to report the service's status to the SCM by calling the SetServiceStatus function.
In Listing 1 shows how to initialize the ServiceStatus structure specifying the service characteristics and its current state. Each ServiceStatus structure fields has a purpose:
- dwServiceType: indicates the type of service. Author Win32 service; assign the SERVICE_WIN32 value.
- dwCurrentState: specifies the current state of the service. Since initialization of a service has not been finished at this point, set the SERVICE_START_PENDING status.
- dwControlsAccepted: this field will inform the SCM which fields the service accepts. In this case, allow STOP and SHUTDOWN requests. Handling control requests is discussed in Step 3.
- dwWin32ExitCode and dwServiceSpecificExitCode: these fields are useful when you are terminating the service and want to report the detailed exit code. Since, you will initialize the service and will not exit, assign 0 values.
- dwCheckPoint and dwWaitHint: these fields indicate the progress of a service when it performs an initialization longer than 30 seconds . This service has a very short initialization procedure, so assign 0 values to both fields.
Report the service's status to the SCM by calling the SetServiceStatus function. This supplies the hStatus handle and the ServiceStatus structure. Notice that ServiceStatus is global, so you can use it across multiple functions. In the ServiceMain function, you assign values to several structure fields that will remain unchanged during the whole run of service, such as dwServiceType.
After reporting the status of the service, you can proceed to the initialization. Do this by calling the InitService function. This function simply adds the Monitoring started. string to the log file. Here is the code:
// Service initialization
result = WriteToLog("Monitoring started.");
In ServiceMain, test the return value of the InitService function. If there was an initialization error (in this case, it may happen if writing to the log failed), set the service status to stopped and exit the ServiceMain:
error = InitService();
// Initialization failed; we stop the service
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = -1;
// exit ServiceMain
If initialization was successful, report the running status to the SCM:
// We report the running status to SCM.
SetServiceStatus (hStatus, &ServiceStatus);
Next, start the worker loop. Every five seconds, query the available physical memory and write the result to the log file.
As seen in Listing 1, the loop continues until the current state of the service is SERVICE_RUNNING or until an error writing to the log file occurs. The state may be altered by the ControlHandler function in response to a SCM control request.