Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Five Steps to Writing Windows Services in C : Page 2

Windows services are convenient for running background apps and for performing tasks that don't require user interaction. And C (not C++) is the best choice for learning the basics of these console applications. Build and implement a simple service to query the amount of available physical memory and write the result to a text file. Then use what you've learned to write your own Windows services.


advertisement
Step 1: The main Function and Global Definitions
First, include the required header files. The program invokes Win32 functions (windows.h) and writes to file on disk (stdio.h):

#include <windows.h> #include <stdio.h>

Next, define two constants:

#define SLEEP_TIME 5000 #define LOGFILE "C:\\MyServices\\memstatus.txt"

SLEEP_TIME specifies the time period in milliseconds between two consecutive queries for available memory. Use this constant in Step 2, when writing the worker loop of your service. LOGFILE defines the path to the log file for the memory queries results that you output using the WriteToLog function:


int WriteToLog(char* str) { FILE* log; log = fopen(LOGFILE, "a+"); if (log == NULL) return -1; fprintf(log, "%s\n", str); fclose(log); return 0; }

Declare several global variables to share their values across multiple functions of your program. Also, make the forward definitions of functions prototypes:

SERVICE_STATUS ServiceStatus; SERVICE_STATUS_HANDLE hStatus; void ServiceMain(int argc, char** argv); void ControlHandler(DWORD request); int InitService();

Now, that the preparation work is done, you can start coding. Service programs are a subset of console applications. Therefore, you begin by defining the main function, which is the entry point to the program. In case of services, the code for main will be surprisingly short, since it just creates the dispatch table and starts the control dispatcher:

void main() { SERVICE_TABLE_ENTRY ServiceTable[2]; ServiceTable[0].lpServiceName = "MemoryStatus"; ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain; ServiceTable[1].lpServiceName = NULL; ServiceTable[1].lpServiceProc = NULL; // Start the control dispatcher thread for our service StartServiceCtrlDispatcher(ServiceTable); }

A program may contain several services. Each of them must be listed in the special dispatch table (this program defines ServiceTable array for this purpose). Each entry in this table is in the SERVICE_TABLE_ENTRY structure, which has two fields:
  • lpServiceName: a pointer to a string with a service name; must be specified when multiple services are defined.
  • lpServiceProc: a pointer to a service main function (entry point of a service).
The last entry of the dispatch table must have NULL pointers for the service name and service main function fields. In this case, the program only hosts a single service, so defining the service name is optional.

The Services Control Manager (SCM) is the process that manages all the services in the system. When the SCM starts a service, it waits for the main thread of a process to call the StartServiceCtrlDispatcher function. Pass the dispatch table to StartServiceCtrlDispatcher. This transforms the main thread of the calling process into the control dispatcher. The dispatcher starts a new thread that runs the ServiceMain function of each service in the dispatch table (in this case, only one service). The dispatcher also monitors the execution of all the services in the program. The dispatcher then passes the control requests from the SCM to the service.

NOTE: If the StartServiceCtrlDispatcher function is not called for 30 seconds, an error is reported. To avoid this, initialize a service inside the ServiceMain function (as in the example) or in a separate thread rather than in the main function. The service described in this article does not require such precautions.

The StartServiceCtrlDispatcher call returns after all of the services in the dispatch table have finished executing (for example, after a user stops them from using the Service applet), or when an error occurs. The main process then terminates.



Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap