A Class For Building An NT Service


Desktop-as-a-Service Designed for Any Cloud ? Nutanix Frame

Building a Service
Changes to revision 2
NT Service Using MFC

Ever tried to write an NT service ? :->
One of my very latest projects was to develop a CORBA server running as an NT service. Since one of my next projects will be an NT service too, I let my brain work a little harder to get it ready for as many programs as needed. The result of this was the CNTService class, that I want to share with the codegurus :-)
With this class it is very simple to create an NT service. Just derive your own class and override the "Run()" and "Stop()" pure virtual members. All of the hard bits are done by the class.

There are several virtuals to overload (multi-threading, pausable services and more).

The class accepts a set of command-line parameters. For instance you can pass the -d switch to let it run as a console process. This makes debugging much easier.
Furthermore the class has abilities to (de)install the service. This is usually a command-line switch too (but one can customize this :-).

CNTService compiles with and without UNICODE settings.

Building a Service

Now lets have a closer look at how you can build your own service.
Follow these steps (assuming you're using VC++ 5.0):
  1. create a new project workspace of type "console application"
  2. copy the files of the NTService package into the directory of your new project
  3. insert "NTService.cpp" and "NTServiceEventLogMsg.mc" into your project
  4. open the Project->Settings ... dialog and fill it out. See the image below. It says more than I could write :-)
  5. compile the file "NTServiceEventLogMsg.mc". This will produce the files "NTServiceEventLogMsg.h" and "NTServiceEventLogMsg.rc".
  6. insert the generated RC file into your project.
  7. derive your own class from CNTService and override at least the two methods "Run()" and "Stop()"
  8. write a simple "main()" to start up your program's functionality :) (You can use the sample project for a good starting point)
  9. Once your project compiles without errors, you can immediately start it. To do so, you should open the Project->Settings ... dialog once again. Select All Configurations and than check the line with the name of your project. Activate the tab Debug and insert the -d switch in the field Program arguments:

  10. Now you should be able to run and debug your service as a console program. You can use either Ctrl-C or Ctrl-Break to stop the service (that would simulate a Stop request from the service control manager)

How to fill out the settings of the file NTServiceEventLogMsg.mc

Now lets try to start the service as a real NT service (assuming you use the sample project):

  1. Log on as an administrator, if your account isn't in the administrators group (this will make life somewhat easier)
  2. Start the program with the switch -i. This will install your service.
  3. If the last step completes successfully, you can open the control panel and start the Services applet. Search for the display name of your service and select it (Very Simple Service if you try the sample).
  4. Press the Startup ... button. Have a look at the Log On As: box. For now you can let the check at System Account. If you try the sample, make sure you check the Interact With The Desktop box. This is necessary, since the sample uses the MessageBox() function (which interacts with the desktop). If you don't check this box, the sample will not run properly and will hang up itself; thus you're unable to stop the service again ! With a little bit of experience one can enhance the sample, so that it will install the service with this box already checked, but I wanted to keep the sample as simple as possible, so I leave it to you to implement that. :-)
The sample project implements a very simple service. The derived class (declaration and implementation) and the main() function are all in the same file (main.cpp). This file is less than 100 lines long (strip off all the comments and it will fit on one page of printing !)
The service only pops up a message-box every 10 seconds.

For more information have a look at CNTService.h and - of course - the sample. I think it is well commented (let me know, if you don't think so)

Changes to revision 2

  • Added two more switches to handle command line arguments: -e will force a running service to stop (corresponding method in this class: virtual BOOL EndService();) and -s will force the service to start, if it is not already running (method: virtual BOOL StartupService())
  • Todd C. Wilson added support for Win95. This enables you to create a service like application for Windows 95 (a socalled "Faceless Application"). Like a service, such an application will be started automatically by the system and will survive a user's logoff. My own experience with this kind of applications are not very great: Yes I could logoff, but the system hung when I tried to logon again. Furthermore BoundsChecker 5 (yes - I always test my software with this great tool :-) said, that the following sentence returns an invalid pointer (exactly "returned pointer is not a pointer to a function"):

  •  typedef DWORD (WINAPI *fp_RegServProc)(DWORD dwProcessId,DWORD dwType);
     fp_RegServProc fncptr=NULL;
    // ...
    HMODULE hModule = ::GetModuleHandle(TEXT("kernel32.dll"));
    fncptr=(fp_RegServProc)::GetProcAddress(hModule, "RegisterServiceProcess");
    if (fncptr!=NULL)
        (*fncptr)(0, RSP_SIMPLE_SERVICE);
    If the last line is reached, BoundsChecker warns, that fncptr does not point to a function. However, the sample program continues execution without an (serious) error.
    You should keep this problem in mind, if you plan to develop a faceless application for windows 95.
    The sample project offers a configuration "Win32 Win95 Debug", that you can use to try this new feature.

NTService Using MFC

Microsoft recommends to write an NT service as a console application . However, it is possible to write such a service using MFC, too. To do so, it isn't necessary to create an  MFC Wizard Application (although it is possible of course, but you have to
remove a lot of code, because normally you don't need the doc/view concept), but a simple Win32 application is just enough. Make sure you select Using MFC in a shared DLL from the General tab of the Settings dialog of your project. Furthermore, you have to select Multithreaded DLL / Debug Multithreaded DLL in the C/C++ tab, section Code Generation field Use run-time Library.
If you're using a precompiled header, make sure you don't  #define VC_EXTRALEAN, because the MFC based service needs parts of the "rarely used stuff", that this macro would exclude from the windows headers!
I've added a new project MFCService as part of the workspace of the sample service to demonstrate this. Just try it out and/or use it as a starting point for a more complex service. The service (installation/removal etc). works exactly as described in the sections above.

CNTService consists of three files:
Download Source 14KB
Download Sample Project 23KB

Note that the file NTServiceEventLogMsg.mc  is copyrighted by Telic Software International B.V. Many thanks to Telic for providing it in the public domain!

Date Last Updated: February 5, 1999

This article was originally published on February 3rd, 1999

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date