Five Steps to Writing Windows Services in C

Five Steps to Writing Windows Services in C

hen I had to write my first NT service, I went to MSDN and looked for samples. There, I found “Creating a Simple Win32 Service in C++, an article by Nigel Thompson with an example written in C++. Though the article explained the process quite well, I still felt I was missing important information. I wanted to understand what functions are called, by what framework, and when, but C++ didn’t make this easy. The object-oriented approach was convenient, but since calls for low-level Win32 functions are encapsulated by class, it is insufficient for learning about the essence of the Services. This is why I feel C is more suitable for the first steps in writing services or for implementing services that perform simple background tasks. C++ is worth using only after you gain a more thorough understanding of the subject. When I had to leave the place I worked and I had to transfer my knowledge to another person, it was very easy to explain the essence of NT services using my examples written in C.

A service is a console application that runs in the background and performs tasks that don’t require user interaction. The Windows NT/2000/XP operating systems offer special support for service programs. The installed services can be configured through the Services applet, available from the Control Panel in Windows NT or from Control Panel | Administrative Tools in Windows 2000/XP. Services can be configured to start automatically when operating system starts, so you dont have to start each of them manually after a system reboot.

This article explains how to create a service that periodically queries the amount of available physical memory and writes the result to a text file. The next sections guide you through the process of building, installing, and implementing the service.

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 #include 

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
", 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.

Step 2: The ServiceMain Function
Listing 1 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 initializationint InitService() {    int result;   result = WriteToLog("Monitoring started.");   return(result); }

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(); if (error) {   // Initialization failed; we stop the service   ServiceStatus.dwCurrentState = SERVICE_STOPPED;    ServiceStatus.dwWin32ExitCode = -1;    SetServiceStatus(hStatus, &ServiceStatus);    // exit ServiceMain   return; }

If initialization was successful, report the running status to the SCM:

   // We report the running status to SCM.    ServiceStatus.dwCurrentState =       SERVICE_RUNNING;    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.

Step 3: Handling Control Requests
In Step 2, you used the ServiceMain function to register the control handler function. The control handler is very similar to the window callback function that processes various Windows messages. It checks what request was sent by the SCM and acts accordingly.

Each time you call the SetServiceStatus function, you must specify that the service accepts the STOP and SHUTDOWN requests. Listing 2 shows how to handle them in the ControlHandler function.

The STOP request is sent when the SCM stops the service. For example, if the user manually stops the service from the Services applet, the SHUTDOWN request is issued to all running services by the SCM, when the machine shuts down. Both cases are handled identically:

  • Writing to the log file Monitoring is stopped.
  • The SERVICE_STOPPED state is reported to the SCM.

Since the ServiceStatus structure is global to the whole program, the worker loop in ServiceMain stops after the current state changes and the service thread terminates. There are other control requests, such as PAUSE and CONTINUE, that are not handled in this example.

The control handler function must report the service status, even if that status remains the same, every time the SCM sends a control request. Hence, SetServiceStatus is called in response to all requests.

?
Figure 1: The Services applet displaying the MemoryStatus service.

Step 4: Installing and Configuring a Service
The program is ready and may be compiled into an exe file. I created MemoryStatus.exe and copied it into C:MyServices folder on my computer. To install this service on your operating system, you’ll need to use the SC.EXE executable, which comes with the Win32 Platform SDK tools. You will use this utility to install and remove the service. The other control operations will be done through the Services applet.

Here is the command-line to install your MemoryStatus service:

sc create MemoryStatus binpath= c:MyServicesMemoryStatus.exe

Issue the create command. This specifies the service name and path to the binary file (notice the space between binpath= and the path). You can now use the Services applet to control the service (see Figure 1).

Start and stop the service using the toolbar of the applet.

?
Figure 2: The Properties window for the MemoryStatus service

The startup type of MemoryStatus is manual, which means that it will start only on-demand. Right-click on the service and choose Properties from the context menu, to get the properties window for the service (Figure 2). This is where you can alter the startup type along with other settings. You can also start/stop the service from the General tab.

To remove the service from the system, execute the following command:

sc delete MemoryStatus

Specify the delete option and the service name. The service will be marked for deletion and will be completely removed after the next restart.

Step 5: Testing Your Service
Start the MemoryStatus service from the Services applet. If there are no initialization errors, the execution should start successfully. Wait for a while, then stop the service. Examine the service’s output in the memstatus.txt file under the C:MyServices folder. On my computer, I obtained the following:

Monitoring started.273469440273379328273133568273084416Monitoring stopped.

To test the behavior of the MemoryStatus service in case of errors, you can make the memstatus.txt file read-only. In this setting, the service will not start.

Remove the read-only attribute, start the service, and reapply read-only. The service should stop its execution because writing to the log fails. If you refresh the contents of the Services applet, you will see that service status is stopped.

On to Bigger and Better Servcies
Understanding the basic concepts of Win32 services, allows you to better use C++ for designing a wrapper class. A wrapper class hides the calls to the low-level Win32 functions and provides a comfortable generic interface. Alter the MemoryStatus program code to create your own services that fit your needs! To perform more complicated tasks than one demonstrated in this article, you can create multithreaded services to divide the job between several worker threads and monitor their execution from the ServiceMain function.

devx-admin

devx-admin

Share the Post:
Software Development

Top Software Development Companies

Looking for the best in software development? Our list of Top Software Development Companies is your gateway to finding the right tech partner. Dive in

India Web Development

Top Web Development Companies in India

In the digital race, the right web development partner is your winning edge. Dive into our curated list of top web development companies in India,

USA Web Development

Top Web Development Companies in USA

Looking for the best web development companies in the USA? We’ve got you covered! Check out our top 10 picks to find the right partner

Clean Energy Adoption

Inside Michigan’s Clean Energy Revolution

Democratic state legislators in Michigan continue to discuss and debate clean energy legislation in the hopes of establishing a comprehensive clean energy strategy for the

Chips Act Revolution

European Chips Act: What is it?

In response to the intensifying worldwide technology competition, Europe has unveiled the long-awaited European Chips Act. This daring legislative proposal aims to fortify Europe’s semiconductor

Revolutionized Low-Code

You Should Use Low-Code Platforms for Apps

As the demand for rapid software development increases, low-code platforms have emerged as a popular choice among developers for their ability to build applications with

Software Development

Top Software Development Companies

Looking for the best in software development? Our list of Top Software Development Companies is your gateway to finding the right tech partner. Dive in and explore the leaders in

India Web Development

Top Web Development Companies in India

In the digital race, the right web development partner is your winning edge. Dive into our curated list of top web development companies in India, and kickstart your journey to

USA Web Development

Top Web Development Companies in USA

Looking for the best web development companies in the USA? We’ve got you covered! Check out our top 10 picks to find the right partner for your online project. Your

Clean Energy Adoption

Inside Michigan’s Clean Energy Revolution

Democratic state legislators in Michigan continue to discuss and debate clean energy legislation in the hopes of establishing a comprehensive clean energy strategy for the state. A Senate committee meeting

Chips Act Revolution

European Chips Act: What is it?

In response to the intensifying worldwide technology competition, Europe has unveiled the long-awaited European Chips Act. This daring legislative proposal aims to fortify Europe’s semiconductor supply chain and enhance its

Revolutionized Low-Code

You Should Use Low-Code Platforms for Apps

As the demand for rapid software development increases, low-code platforms have emerged as a popular choice among developers for their ability to build applications with minimal coding. These platforms not

Cybersecurity Strategy

Five Powerful Strategies to Bolster Your Cybersecurity

In today’s increasingly digital landscape, businesses of all sizes must prioritize cyber security measures to defend against potential dangers. Cyber security professionals suggest five simple technological strategies to help companies

Global Layoffs

Tech Layoffs Are Getting Worse Globally

Since the start of 2023, the global technology sector has experienced a significant rise in layoffs, with over 236,000 workers being let go by 1,019 tech firms, as per data

Huawei Electric Dazzle

Huawei Dazzles with Electric Vehicles and Wireless Earbuds

During a prominent unveiling event, Huawei, the Chinese telecommunications powerhouse, kept quiet about its enigmatic new 5G phone and alleged cutting-edge chip development. Instead, Huawei astounded the audience by presenting

Cybersecurity Banking Revolution

Digital Banking Needs Cybersecurity

The banking, financial, and insurance (BFSI) sectors are pioneers in digital transformation, using web applications and application programming interfaces (APIs) to provide seamless services to customers around the world. Rising

FinTech Leadership

Terry Clune’s Fintech Empire

Over the past 30 years, Terry Clune has built a remarkable business empire, with CluneTech at the helm. The CEO and Founder has successfully created eight fintech firms, attracting renowned

The Role Of AI Within A Web Design Agency?

In the digital age, the role of Artificial Intelligence (AI) in web design is rapidly evolving, transitioning from a futuristic concept to practical tools used in design, coding, content writing

Generative AI Revolution

Is Generative AI the Next Internet?

The increasing demand for Generative AI models has led to a surge in its adoption across diverse sectors, with healthcare, automotive, and financial services being among the top beneficiaries. These

Microsoft Laptop

The New Surface Laptop Studio 2 Is Nuts

The Surface Laptop Studio 2 is a dynamic and robust all-in-one laptop designed for creators and professionals alike. It features a 14.4″ touchscreen and a cutting-edge design that is over

5G Innovations

GPU-Accelerated 5G in Japan

NTT DOCOMO, a global telecommunications giant, is set to break new ground in the industry as it prepares to launch a GPU-accelerated 5G network in Japan. This innovative approach will

AI Ethics

AI Journalism: Balancing Integrity and Innovation

An op-ed, produced using Microsoft’s Bing Chat AI software, recently appeared in the St. Louis Post-Dispatch, discussing the potential concerns surrounding the employment of artificial intelligence (AI) in journalism. These

Savings Extravaganza

Big Deal Days Extravaganza

The highly awaited Big Deal Days event for October 2023 is nearly here, scheduled for the 10th and 11th. Similar to the previous year, this autumn sale has already created

Cisco Splunk Deal

Cisco Splunk Deal Sparks Tech Acquisition Frenzy

Cisco’s recent massive purchase of Splunk, an AI-powered cybersecurity firm, for $28 billion signals a potential boost in tech deals after a year of subdued mergers and acquisitions in the

Iran Drone Expansion

Iran’s Jet-Propelled Drone Reshapes Power Balance

Iran has recently unveiled a jet-propelled variant of its Shahed series drone, marking a significant advancement in the nation’s drone technology. The new drone is poised to reshape the regional

Solar Geoengineering

Did the Overshoot Commission Shoot Down Geoengineering?

The Overshoot Commission has recently released a comprehensive report that discusses the controversial topic of Solar Geoengineering, also known as Solar Radiation Modification (SRM). The Commission’s primary objective is to

Remote Learning

Revolutionizing Remote Learning for Success

School districts are preparing to reveal a substantial technological upgrade designed to significantly improve remote learning experiences for both educators and students amid the ongoing pandemic. This major investment, which

Revolutionary SABERS Transforming

SABERS Batteries Transforming Industries

Scientists John Connell and Yi Lin from NASA’s Solid-state Architecture Batteries for Enhanced Rechargeability and Safety (SABERS) project are working on experimental solid-state battery packs that could dramatically change the

Build a Website

How Much Does It Cost to Build a Website?

Are you wondering how much it costs to build a website? The approximated cost is based on several factors, including which add-ons and platforms you choose. For example, a self-hosted

Battery Investments

Battery Startups Attract Billion-Dollar Investments

In recent times, battery startups have experienced a significant boost in investments, with three businesses obtaining over $1 billion in funding within the last month. French company Verkor amassed $2.1