Click here to Skip to main content
Click here to Skip to main content
Alternative Article

Simple Windows Service in C++

, 24 Sep 2014 BSD
Rate this:
Please Sign up or sign in to vote.
This is an alternative for "Simple Windows Service in C++"

Introduction

Struggling to start with the basics of Windows Services? This little project will provide you with a very simple background process class in C++ that can be used right away for creating a Service.

Please note that the exact purpose of this example is to encapsulate all details for novice programmers so they just can get started with writing a service right away. This is not a walk through on lower level how to write a service. All of that has been encapsulated in the JDMBackgroundProcess class and has been described already in the article Simple Windows Service in C++[^].

This article is an alternative approach to the first article.

Background

There are not many Windows Service examples in C++. A useful one that I found is located here: http://www.codeproject.com/Articles/499465/Simple-Windows-Service-in-Cplusplus.

However I wanted a solution with an ANSI C++ interface that could be very easily integrated with existing source code. I have written a wrapper class called JDMBackgroundProcess with a very simple interface that could do this trick. It also encapsulates all Windows specific code so it can be extended to other operating systems as well (for example Linux Daemons).

Using the Code

Let's go straight to an example of how we can change a normal executable program to start acting as a service. All we have to do are a few simple steps:

  1. Add a JDMBackgroundProcess object to your main function and provide a new "Main" function.
  2. Call the StartInBackground() function of the JDMBackgroundProcess object.
  3. Report to JDMBackgroundProcess object that your "Main" function is running.
  4. Check the status of the service regularly and exit your "Main" function when the service is being stopped.

Let's clarify this with a main function below:

static int  JDM_BGP_CALL_CONV Main(int argc, char* argv[]);
static void JDM_BGP_CALL_CONV ExtraPauseFunction();
static void JDM_BGP_CALL_CONV EventNotifier(JDM_BGP_EVENTS EventCode);

JDMBackgroundProcess* pBGP;

/*---------------------------------------------------------------------------*/
/* main                                                                      */
/*---------------------------------------------------------------------------*/
/* Normal entry point of the program, which decides if and how the Main()    */
/* function is called that contains the actual implementation                */
/*---------------------------------------------------------------------------*/
int main(int argc, char* argv[])
{
  long RetVal=-1;
  JDMBackgroundProcess BGP(".ProcessName", "ProcessDescription", Main, EventNotifier);

  /* Actually the next statement looks awful, but it's not as the pointer  */
  /* pBGP is valid through execution time of the whole program and I don't */
  /* want to pass this pointer back and forth trough the several callback  */
  /* functions. I really prefer to have the BGP itself on the stack here   */
  /* as it is faster.                                                      */
  pBGP=&BGP;

  /* In case we find any of the following special parameters as the first   */
  /* parameter then we assume the console has called the background process */
  /* and we start the chosen functionality or start the process in the      */
  /* foreground.                                                            */
  if(argc>1) {
         if(!_stricmp("debug",     argv[1])) {return BGP.StartInForeground(argc, argv);}
    else if(!_stricmp("install",   argv[1])) {return BGP.Install(argc, argv);}
    else if(!_stricmp("create",    argv[1])) {return BGP.Install(argc, argv);}
    else if(!_stricmp("uninstall", argv[1])) {return BGP.Uninstall(argc, argv);}
    else if(!_stricmp("delete",    argv[1])) {return BGP.Uninstall(argc, argv);}
  }

  /* No special parameter given, we assume the operating system and not the */
  /* console has started this background process.                           */
  RetVal=BGP.StartInBackground();

  return RetVal;
} /* main */

As you can see, a BGP object with a chosen process name and process description gets created and a function pointer to a new "Main" function is provided. At the end of the main function, we will call the StartInBackground() function to let the service interact with the operating system.

The event notifier function is optional. The process name and process description will be visible in the services management console of Windows.

Now let's see the newly provided "Main" function (which can be a copy of the old main function of your program with some small additions):

/*---------------------------------------------------------------------------*/
/* Main                                                                      */
/*---------------------------------------------------------------------------*/
/* The main function that should contain the actual implementation of the    */
/* process. This is where the magic happens through a simple BGP interface.  */
/* Basically you have to report to the BGP when the service is running, by   */
/* calling the function ReportRunning(). For the rest you only need to check */
/* if the BGP is paused by calling CheckAndHandlePauseResume(), this         */
/* function sleeps and already handles the resume and stop for you. Finally  */
/* you need to check if the BGP has received a stop command and exit the     */
/* function as soon as possible. That's all ... 3 functions to run your BGP  */
/* based program.                                                            */
/*---------------------------------------------------------------------------*/
static int JDM_BGP_CALL_CONV Main(int argc, char* argv[])
{
  /* Initialise something here if needed */
  if(pBGP->IsStartedInForeground()==true) {
    cout << "Press <CTRL>+Break to PAUSE, <CTRL>+C to RESUME and close window to STOP" << endl;
  }

  /* Now report to the BGP object that we start running and we are active */
  pBGP->ReportRunning();
  while(pBGP->StopReceived()==false) { /* Always check if the BGP received a stop to end the program */

    /* Running */
    cout << "run" << endl;

    /* Check if the program needs to be paused */
    pBGP->CheckAndHandlePauseResume(1000, &ExtraPauseFunction);

    /* Do your action here, create threads etc., check for stop and pause in your threads as well! */
    Sleep(1000);

  }

  /* We have received a stop, end the program */
  cout << "stop" << endl;

  /* Deinitialise something here if needed */
  Sleep(1000);

  return 0;
} /* Main */

Basically, what should be added is a call to pBGP->ReportRunning() to report to the JDMBackgroundProcess that we have started our program.

Further on, we check by pBGP->StopReceived() if the operating system has requested for the service to be stopped, and if so we will exit our "Main" function. Also we check if the service needs to be paused by pBGP->CheckAndHandlePauseResume().

That's all there is to it, I could not think of a more simple solution than this.

The latest source code can be downloaded at https://sourceforge.net/projects/jdmbackgroundprocess/.

History

  • 2014-09-24: Removed empty "Download source (no EXE)", updated a typing mistake in the comments of the source code, updated the download file with the latest sources.
  • 2014-06-15: Added additional text to the Introduction paragraph
  • 2014-06-13: Added example source code at top of the page in addition to the SourceForge link
  • 2014-06-12: Initial version

License

This article, along with any associated source code and files, is licensed under The BSD License

Share

About the Author

Jeroen De Maeijer
Software Developer (Senior) ReBuS B.V.
Netherlands Netherlands
No Biography provided
Follow on   LinkedIn

Comments and Discussions

 
GeneralMy vote of 4 Pinmemberjrynd20-Aug-14 11:06 
GeneralRe: My vote of 4 PinprofessionalJeroen De Maeijer20-Aug-14 19:00 
GeneralMy vote of 2 PinmemberCristian Amarie15-Jun-14 3:27 
GeneralRe: My vote of 2 [modified] PinprofessionalJ.R.F. De Maeijer15-Jun-14 6:58 
SuggestionRe: My vote of 2 Pinprotectorthatraja15-Jul-14 2:54 
GeneralRe: My vote of 2 PinprofessionalJ.R.F. De Maeijer15-Jul-14 3:55 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.141015.1 | Last Updated 24 Sep 2014
Article Copyright 2014 by Jeroen De Maeijer
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid