简单的 C++ Windows 服务






4.58/5 (20投票s)
这是“简单的 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程序变成一个服务。 我们只需要几个简单的步骤
- 将一个
JDMBackgroundProcess
对象添加到您的 main 函数,并提供一个新的“Main
”函数。 - 调用
JDMBackgroundProcess
对象的StartInBackground()
函数。 - 向
JDMBackgroundProcess
对象报告您的“Main
”函数正在运行。 - 定期检查服务的状态,并在服务停止时退出您的“
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:初始版本