65.9K
CodeProject 正在变化。 阅读更多。
Home

简单的 C++ Windows 服务

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.58/5 (20投票s)

2014年6月12日

BSD

3分钟阅读

viewsIcon

37029

downloadIcon

1394

这是“简单的 C++ Windows 服务”的替代方案

引言

还在为 Windows 服务的基础知识而苦苦挣扎吗?这个小项目将为您提供一个非常简单的 C++ 后台进程类,可直接用于创建服务。

请注意,此示例的确切目的是封装所有细节,以便新手程序员可以立即开始编写服务。 这不是关于如何在较低级别编写服务的演练。 所有这些都已封装在 JDMBackgroundProcess 类中,并且已在文章 C++ 中的简单 Windows 服务[^] 中进行了描述。

本文是第一篇文章的另一种方法。

背景

C++ 中没有太多 Windows 服务示例。 我发现一个有用的示例位于此处:https://codeproject.org.cn/Articles/499465/Simple-Windows-Service-in-Cplusplus

但是,我想要一个具有 ANSI C++ 接口的解决方案,该解决方案可以非常容易地与现有源代码集成。 我编写了一个名为 JDMBackgroundProcess 的包装类,它具有非常简单的接口,可以做到这一点。 它还封装了所有 Windows 特定的代码,因此也可以将其扩展到其他操作系统(例如 Linux 守护进程)。

Using the Code

让我们直接看一个例子,了解如何将一个普通的exe程序变成一个服务。 我们只需要几个简单的步骤

  1. 将一个 JDMBackgroundProcess 对象添加到您的 main 函数,并提供一个新的“Main”函数。
  2. 调用 JDMBackgroundProcess 对象的 StartInBackground() 函数。
  3. JDMBackgroundProcess 对象报告您的“Main”函数正在运行。
  4. 定期检查服务的状态,并在服务停止时退出您的“Main”函数。

让我们用下面的 main 函数来澄清这一点

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 */

正如您所看到的,创建了一个具有所选进程名称和进程描述的 BGP 对象,并提供了一个指向新的“Main”函数的函数指针。 在 main 函数的末尾,我们将调用 StartInBackground() 函数,让服务与操作系统交互。

事件通知器函数是可选的。 进程名称和进程描述将在 Windows 的服务管理控制台中可见。

现在让我们看看新提供的“Main”函数(它可以是您的程序的旧 main 函数的副本,并进行了一些小的添加)

/*---------------------------------------------------------------------------*/
/* 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 */

基本上,应该添加的是调用 pBGP->ReportRunning() 以向 JDMBackgroundProcess 报告我们已经启动了我们的程序。

此外,我们通过 pBGP->StopReceived() 检查操作系统是否已请求停止服务,如果是,我们将退出我们的“Main”函数。 我们还通过 pBGP->CheckAndHandlePauseResume() 检查是否需要暂停服务。

这就是全部,我想不出比这更简单的解决方案了。

最新的源代码可以在 https://sourceforge.net/projects/jdmbackgroundprocess/ 下载。

历史

  • 2014-09-24:删除了空的“下载源代码(无 EXE)”,更新了源代码注释中的一个打字错误,用最新的源代码更新了下载文件。
  • 2014-06-15:向“简介”段落添加了更多文本
  • 2014-06-13:除了 SourceForge 链接之外,还在页面顶部添加了示例源代码
  • 2014-06-12:初始版本
© . All rights reserved.