Creating a Windows NT/Windows 2000 Service

Environment:

Introduction

A Windows service is an EXE specially designed to communicate with the Service Control Manager (SCM) of Windows NT/2000. The SCM maintains a database of installed services and driver services, and provides a unified and secure means of controlling them. The SCM is started at system boot and it is a remote procedure call (RPC) server. As a developer trying a simple service, you can divide the program in to four parts.

  1. Main program of Win 32/Console application.
  2. A so-called ServiceMain(), the main program of Service. It's the entry point of a service.
  3. A Service Control Handler (SCH), a function to communicate with the SCM.
  4. A Service Installer/Uninstaller, to register an EXE as a Service.

The Main Program

First, let us take a look at the main program of the Console application (it can also be a WinMain()).

#include "Winsvc.h"        //Header file for Services.

main()
{
  SERVICE_TABLE_ENTRY Table[]={{"Service1",ServiceMain},
                               {NULL,NULL}};
  StartServiceCtrlDispatcher(Table);
}

The only thing done by the main() is to fill a SERVICE_TABLE_ENTRY array. The position [0][0] contains the name of the Service (any string you like). Position [0][1] contains the name of the Service Main function; I specified it earlier in the list. It actually is a function pointer to the Service main function. The name can be anything. Now we start the first step to a service by calling StartServiceCtrlDispatcher() with the SERVICE_TABLE_ENTRY array. Note that the function signature should be that of the form. The [1][0] and [1][1] positions are NULL, just to mark the end of the array. (Not a must.) We can add more entries to the list if we have more than one service running from the same EXE.

The declaration of a typical ServiceMain() is as follows:

void WINAPI ServiceMain(DWORD argc, LPTSTR *argv)

The ServiceMain Function

Now let us analyze our ServiceMain function. The main steps of this function are to:

  1. Fill the SERVICE_STATUS structure with appropriate values to communicate with the SCM.
  2. Register the Service Control Handler function mentioned earlier.
  3. Call the actual processing functions.

To proceed, we need two global variables here:

SERVICE_STATUS m_ServiceStatus;
SERVICE_STATUS_HANDLE m_ServiceStatusHandle;

The ServiceMain() can accept command-line arguments just as any C++ main() function. The first parameter contains the number of arguments being passed to the service. There will always be at least one argument. The second parameter is a pointer to an array of string pointers. The first item in the array always points to the service name. The SERVICE_STATUS data structure is used to fill the current state of the Service and notify it to the SCM. We use the API function SetServiceStatus() for the purpose. The data members of SERVICE_STATUS to look for are:

Data Member Name Description
dwServiceType SERVICE_WIN32  
dwCurrentState SERVICE_START_PENDING Trying To Start (Initially)
dwControlsAccepted SERVICE_ACCEPT_STOP Accepts Stop/Start only in Service control program. Usually in the control Panel (NT)/Administrative tools (2000). We can also set our service to accept PAUSE and CONTINUE functionality.

In the beginning of the ServiceMain(), we should set the dwCurrentState of SERVICE_STATUS to SERVICE_START_PENDING. This signals the SCM that the service is starting. If any error occurs along the way, we should notify the SCM by passing SERVICE_STOPPED. By default, the SCM will look for an activity from the service; if it fails to show any progress within two minutes, SCM kills that service.

The API function RegisterServiceCtrlHandler() is used to set the Service Control Handler Function of the Service with the SCM. The function takes two parameters as earlier, one service name (String) and the pointer to the Service Control Handler Function. That function should align with the signature.

Once we get here, we now set dwCurrentState as SERVICE_RUNNING to notify that the service has started to function. The next step is to call the actual processing steps.

The Service Control Handler Function

The Service Control Handler function is used by the SCM to communicate with the Service program about a user action on the service, such as a start, stop, pause, or continue. It basically contains a switch statement to deal with each case. Here we will call the appropriate steps to clean up and terminate the process. This function receives an opcode which can have values like SERVICE_CONTROL_PAUSE, SERVICE_CONTROL_CONTINUE, SERVICE_CONTROL_STOP, SERVICE_CONTROL_INTERROGATE, and so forth. We have to write appropriate steps on each.

Service Installer/Uninstaller

To install a service we need to make some entries in the system Registry. Windows has some APIs to do these steps, instead of using the Registry functions. They are CreateService() and DeleteService(). For both these functions we need to open the SCM database with the appropriate rights. I prefer using SC_MANAGER_ALL_ACCESS. To install a service, first open the SCM by using OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS). Then invoke CreateService() with the appropriate binary file path of our service. Here also we have to give the name of our service. We need this name if we want to delete a particular service. In deleting a service we need to open the specific service first by its name and then invoke DeleteService() on it. That's all that we need. Take a look at the code given with it for more details.

Downloads

Download exe and cpp file - 32 Kb


Comments

  • Creating a Service on Windows Mobile

    Posted by tushnim on 12/10/2008 10:02pm

    Will the steps be the same for Win Mobile as depicted here for "Windows NT/Windows 2000"? OR, is there a different step(s) for creating a service on Win Mobile 6/7.

    Reply
  • creatin simple NT service application

    Posted by p_rajendraprasad on 11/18/2004 05:39am

    If possible can you pls give the step by step procedure to develop an NT service and procedure to install...

    • 1233

      Posted by pifangsi on 03/28/2005 02:08am

      11122

      Reply
    Reply
  • ? how can i communicate with user-functions in a service ?

    Posted by gutdat on 09/10/2004 03:42am

    situation: a service (works fine, thanks to the demos here) and a Dialog-exe (MFC-Dialog with visualc++6) should communicate each-other. i do not mean service-communication via SMC to stop or start a service, i mean interconnection for dataexchange or send fast information. a kind of PostMessage(..) with lparam to access data directly (but PostMessage() does not work in my service). Is there a way?

    • I did it using shared memory

      Posted by stbi on 02/07/2009 08:04am

      I successfully used shared memory as described here to communicate between the service and an application: http://www.codeproject.com/KB/threads/Win32IPC.aspx http://www.codeproject.com/cpp/Win32MRW.asp I only removed the event stuff from the demo code as I didn't need it. (Sorry for the bad formatting, but this forum seems not to support line breaks.)

      Reply
    • The same predicament

      Posted by waxie on 09/14/2007 02:55am

      I would also really appreciate if you can provide feedbacks on the question by gutdat. I am also having the same problem. Any inputs would be great! :) Thanks.

      Reply
    Reply
  • can a service do file I/O?

    Posted by sivart1444 on 07/09/2004 11:26am

    can it. where can i find out what they can do and how to fix them?

    • to fix or debug services

      Posted by gutdat on 09/10/2004 03:30am

      i do not find a normal way with debug-tools, so i use normal ofstream-class to write status an results in a file and look them with an editor. additional i use a lot try-and-catch clauses to track down an error. it is a stupid way but works.

      Reply
    Reply
  • consise and to the point

    Posted by maekawa on 06/09/2004 03:49am

    This article is very good for beginners like me who must make Windows Service applications from now. Very consise and to the point,easy for understand. Thanks Anish.

    Reply
  • do you know how to create services that run from svchost?

    Posted by Legacy on 05/25/2003 12:00am

    Originally posted by: geecka

    hi,
    
    i want to create a service in a dll that run under svchost service but i didn't find any docs about this type of service (what function to export,how the dll service comunicate with SCManager ....);

    to create a simple service is easy...

    • Me too!

      Posted by maniaque on 04/18/2006 02:31pm

      If you find any information, please, share it with me! I'm intrested in this question too, very much!

      Reply
    Reply
  • Is there any notification when a human user logon and logoff

    Posted by Legacy on 12/10/2002 12:00am

    Originally posted by: ZHEFU ZHANG

    Hi, just as the title. My service is not interactive with desktop, but I need to know when the user logon his account. Thanks ahead for replying

    • you check it yourself

      Posted by boywen on 09/26/2004 10:22pm

      start a kernel timer and do your checking routines there every few seconds... i.e.,you can check system_user. i used to do that.

      Reply
    Reply
  • How to enter a description for a service

    Posted by Legacy on 12/04/2002 12:00am

    Originally posted by: ppychu

    I cannot find any field in the structure that takes
    in a desc. for the service. WHen looking
    at the services GUI window, it seems that all 3rd party
    services (other than Microsoft) has no description.
    Any gurus can help???

    Thanks

    Reply
  • NT Service - How to add dialog box

    Posted by Legacy on 11/15/2002 12:00am

    Originally posted by: Sudhir

    How to add dialog box to NT service?

    (Specifically in Borland C++ builder.)

    T&R,
    Sudhir

    Reply
  • How can connect to the Database through the ODBC API in service

    Posted by Legacy on 10/04/2002 12:00am

    Originally posted by: aliho

    How can connect to the Database through the ODBC API in service?

    I'am already have some code, but it does not work in service, it works in based on dialog program.
    there is a code:
    SQLHENV henv;
    SQLHDBC hdbc;
    SQLRETURN retcode;
    retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
    if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
    retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
    if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
    retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
    if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
    SQLSetConnectAttr(hdbc,SQL_LOGIN_TIMEOUT,(void*) 5, 0);
    retcode = SQLConnect(hdbc, (SQLCHAR*) "iwdsn", SQL_NTS,(SQLCHAR*) "SYSDBA", SQL_NTS, (SQLCHAR*) "masterkey", SQL_NTS);
    if (retcode != SQL_SUCCESS){
    short i = 1, MsgLen;
    SQLCHAR SqlState[300] ;
    SQLINTEGER NativeError;
    SQLCHAR Msg[300];
    while ((retcode = SQLGetDiagRec(SQL_HANDLE_DBC, hdbc, i, SqlState, &NativeError,
    Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA) {
    i++;
    }
    return -1;
    }
    }
    SQLDisconnect(hdbc);
    }else
    SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
    SQLFreeHandle(SQL_HANDLE_ENV, henv);
    }

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • 10 Rules that Make or Break Enterprise App Development Projects In today's app-driven world, application development is a top priority. Even so, 68% of enterprise application delivery projects fail. Designing and building applications that pay for themselves and adapt to future needs is incredibly difficult. Executing one successful project is lucky, but making it a repeatable process and strategic advantage? That's where the money is. With help from our most experienced project leads and software engineers, …

  • Java developers know that testing code changes can be a huge pain, and waiting for an application to redeploy after a code fix can take an eternity. Wouldn't it be great if you could see your code changes immediately, fine-tune, debug, explore and deploy code without waiting for ages? In this white paper, find out how that's possible with a Java plugin that drastically changes the way you develop, test and run Java applications. Discover the advantages of this plugin, and the changes you can expect to see …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds