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

使用 Boost.Application 库创建 Windows 服务应用程序

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.82/5 (22投票s)

2013年10月2日

CPOL

11分钟阅读

viewsIcon

52864

downloadIcon

848

本文介绍了用于构建 Windows 服务的 Boost.Application 库。

重要提示:  

本文介绍了 Boost.Application(库提案至 boost.org)的旧版本(0.3)!

新版本(0.4),具有不同的接口,已可在以下地址下载:

https://github.com/retf/Boost.Application

请注意,0.3 版本不再维护!0.4 版本现在正在维护并定期更新。 

引言

在本文中,我将介绍一个“Boost.Application”库,用于构建 Windows 服务。请注意,Boost.Application 尚未成为官方的 Boost C++ 库。

“Boost.Application”为任何想要为 Windows 或 Unix 变体(例如 Linux、MacOS)构建系统应用程序的基本基础结构的人提供了一个应用程序环境或起点。

本教程重点关注 Windows 端开发,如果您是 UNIX 用户,请参考库文档了解更多详细信息。

该库处于“beta”状态,最新版本可从以下地址下载:https://sourceforge.net/projects/boostapp/

反馈

如果您是 Boost 用户,并且使用 Boost 邮件列表,请直接在列表中提供您对该库的反馈。(请说明您是否认为该库应被接受为 boost.com 的一部分)。
https://boost.ac.cn/community/groups.html

如果您是 CodeProject 用户,请在此页面直接提供您对该库的反馈。

Bug

如果您发现任何错误,请发送至:re.tf@acm.org

库依赖项

Boost.Application 是一个纯头文件库,但它依赖于其他需要构建和可用的 Boost 库,因此您需要在您的机器上下载并构建 Boost。Boost 的构建过程并不容易,但这里提供了很好的文档:https://boost.ac.cn/doc/libs/1_54_0/more/getting_started/windows.html

或者您可以查看这篇不错的文章来帮助构建:https://codeproject.org.cn/Articles/11597/Building-Boost-libraries-for-Visual-Studio

1. Boost.Application 安装

首先要做的是下载 Boost,将其解压缩到您的驱动器,例如:“c:\”,然后进行构建。之后,您需要下载 Boost.Application 并将其复制到 Boost 文件夹。

将这两个文件夹复制到您的 Boost 安装目录

现在您的环境已准备就绪,可以使用了。

2. Boost.Application 简介

Boost.Application 库的主要目的是抽象 Windows 服务 API。Boost.Application 主要支持两种类型的应用程序:

  • 普通应用程序:这种应用程序是普通的交互式终端/控制台应用程序。
  • 服务器应用程序:这种应用程序会生成一个服务(Windows)或后台进程/守护进程(Unix)。

本文重点介绍“服务器应用程序”类型,但也会使用普通应用程序作为调用服务器的客户端。

Boost.Application 支持许多其他有用的现成功能,例如:

  1. 插件扩展系统;
  2. 环境变量访问;
  3. 参数访问;
  4. 设置(Windows 服务);
  5. 进程(可执行文件)单一实例实例化支持;
  6. 路径处理;
  7. 以及更多。

本文旨在涵盖第 1 项和第 4 项。请参阅库手册了解 Boost.Application 提供的其他功能。手册可通过以下方式访问:boost_installation\libs\application\doc\html\index.html

文档处于 alpha 状态。如果您是英语母语者,并希望为文档做出贡献,或者想为库贡献新功能(请参阅文档中的未来工作),请与我联系。

3. 示例应用程序项目

本文提供了一个操作指南教程,展示了如何使用 Boost.Application 库构建客户端-服务器应用程序;本文还将简要介绍其他 Boost 库,例如:

  • Boost.Thread;
  • Boost.Program_options;
  • Boost.UUID;
  • Boost.System;
  • Boost.Asio。

因此,将开发一个使用“TCP/IP”套接字连接到服务器(服务/服务器应用程序)的客户端(控制台/普通应用程序)。客户端的角色是将一个字符串发送到服务器,服务器的角色是根据从客户端收到的字符串返回一个“GUID/UUID”。

4. 在 Visual Studio 中创建应用程序骨架

请注意,本文使用的 IDE 是 Visual Studio 2012,并且所有提供的示例都适用于此环境。所有代码和项目均已提供;请查看页面顶部的下载链接。

4.1 为客户端和服务器应用程序创建 Visual Studio 项目骨架。

打开 Visual Studio,并创建两个 Win32 项目,一个用于客户端,一个用于服务器。

4.2 在每个项目中,打开属性窗口,将 Boost 安装目录添加到“C/C++ -> 常规 -> 附加包含目录”

4.3 再次在每个项目中打开属性窗口,并将 Boost 库目录添加到“链接器 -> 常规 -> 附加库目录”

请注意,当您构建 Boost 时,库的常用位置是:C:\boost_1_54_0\stage\lib

5. 服务器应用程序

5.1 将 Boost.Application 接口添加到服务器实现。

#include "stdafx.h"
#include <boost\application.hpp>

int _tmain(int argc, _TCHAR* argv[])
{
    return 0;
}

5.2 创建一个类(函数对象)来保存服务器实现。

class my_server
{
public:
   int operator()(const std::vector< application_ctrl::string_type >& args, 
      application_ctrl& ctrl)
   {
      return 0;
   }
};

这里有两个重要事项。第一个是 args,函数对象总是接收一个包含传递给应用程序的参数的向量;第二个参数是 ctrl,它拥有应用程序的当前状态以及允许您控制应用程序的多个其他方法。

到目前为止,完整的代码如下:

#include "stdafx.h"

#define BOOST_ALL_DYN_LINK

#include <boost\application.hpp>

using namespace boost::application;

class my_server
{
public:
   int operator()(const std::vector< application_ctrl::string_type >& args, 
      application_ctrl& ctrl)
   {
      return 0;
   }
};

int _tmain(int argc, _TCHAR* argv[])
{
       return 0;
}

BOOST_ALL_DYN_LINK 用于启用对其他所需的 Boost 库的动态链接。

此时,您可以将以上所有代码复制到客户端应用程序中。

5.3 实例化服务器类以作为 Windows 服务。

为此,请将以下代码添加到 main 函数中:

int _tmain(int argc, _TCHAR* argv[])
{
   return application<
      application_type<server_application>, 
      my_application< my_server > >( args(argc, argv))();
}

这里还需要一个细节。服务器必须持续运行,并且仅在用户请求时停止(使用 SCM),因此我们需要在我们的运算符函数对象中添加一行代码来完成此操作。

class my_server
{
public:
   int operator()(const std::vector< application_ctrl::string_type >& args, 
      application_ctrl& ctrl)
   {
      ctrl.wait_for_termination_request(); // <--
      return 0;
   }
};

5.4 错误处理程序

Boost.Application 提供两种错误处理方式:一种会抛出 boost::system::system_error 类型的异常,另一种会接收一个 boost::system::error_code 变量 ec,该变量会被设置为操作结果,并且不会抛出异常。参考:https://boost.ac.cn/doc/libs/1_54_0/libs/system/doc/index.html 了解更多。

我们将使用异常版本,请看:

int _tmain(int argc, _TCHAR* argv[])
{
   try 
   {
      return application<
         application_type<server_application>, 
         my_application< my_server > >( args(argc, argv))();
   }
   catch(boost::system::system_error& se)
   {
      std::cerr << se.what() << std::endl;
      return 1;
   }
}

6. 为服务器应用程序添加设置处理程序

为了测试我们的 Windows 服务,我们需要安装它。安装会使 SCM 了解该服务,并导致 SCM 将其添加到控制面板服务控制台中显示的服务列表中。

Boost.Application 提供了一个设置处理程序,可以添加到“函数对象”类中,以启用应用程序的安装/卸载。

6.1 向应用程序(函数对象)类添加“设置”处理程序。

class my_server
{
public:

   int setup(application_ctrl& ctrl)
   {
      return 0;
   }

   // ...
};

设置处理程序将在 operator() 之前自动调用,因此我们可以添加代码来自动安装我们的应用程序服务;然后,当用户请求设置时,我们可以运行代码来安装或卸载服务并退出。

6.2 集成 Boost.Program_options 以了解用户意图,并启用服务安装。

program_options 库允许用户通过常规方法(如命令行和配置文件)获取程序选项,即用户提供的键值对。参考:https://boost.ac.cn/doc/libs/1_54_0/doc/html/program_options.html 了解更多。

class my_server
{
public:

   int setup(application_ctrl& ctrl)
   {
      // get our executable path name
      boost::filesystem::path executable_path_name = ctrl.executable_path_name();

      // define our simple installation schema options
      po::options_description install("service options");
      install.add_options()
         ("help", "produce a help message")
         (",i", "install service")
         (",u", "unistall service")
         (",c", "check service")
         ("name", po::value<std::string>()->default_value(ctrl.executable_name().stem().string()), "service name")
         ("display", po::value<std::string>()->default_value(""), "service display name (optional, installation only)")
         ("description", po::value<std::string>()->default_value(""), "service description (optional, installation only)")
         ;

      po::variables_map vm;
      po::store(po::parse_command_line(ctrl.argc(), ctrl.argv(), install), vm);
      boost::system::error_code ec;

      if (vm.count("help")) 
      {
         std::cout << install << std::cout;
         return 1;
      }

      if (vm.count("-i")) 
      {
         install_windows_service(
            setup_arg(vm["name"].as<std::string>()), 
            setup_arg(vm["display"].as<std::string>()), 
            setup_arg(vm["description"].as<std::string>()), 
            setup_arg(executable_path_name)).install(ec);

         std::cout << ec.message() << std::endl;

         return 1;
      }

      if (vm.count("-u")) 
      {
         uninstall_windows_service(
            setup_arg(vm["name"].as<std::string>()), 
            setup_arg(executable_path_name)).uninstall(ec);
                       
         std::cout << ec.message() << std::endl;

         return 1;
      }

      if (vm.count("-c")) 
      {
         if(check_windows_service(setup_arg(vm["name"].as<std::string>())).exist(ec))
            std::cout 
               << "Windows service '" 
               << vm["name"].as<std::string>() 
               << "' is aready installed!" 
               << std::endl;
         else
            std::cout 
               << "Windows service '" 
               << vm["name"].as<std::string>() 
               << "' is not installed!" 
               << std::endl;

         std::cout << ec.message() << std::endl;
         return 1;
      }
      return 0;
   }
};

6.3 测试服务安装(设置)

现在我们拥有了一个用于安装、卸载和检查服务是否已安装的服务器命令行界面。当用户请求安装时,例如:“server.exe -i”,安装请求由 Boost.Program_options 识别,并执行“-i if”中的代码,安装服务。请注意,在这种情况下,我们从 setup 方法返回 1。这会导致执行在安装后退出,并且运算符(包含服务器逻辑)不会被执行。

命令行选项是:

// [installation]
// server.exe -i
// /or/
// server.exe -i --name "My Service"
// server.exe -i --name "My Service"
// [check]
// server.exe -c
// /or/
// server.exe -c --name "My Service" 
// [unstalation]
// server.exe -u
// /or/
// server.exe -u --name "My Service" 
// 
// Note that when arg name are not priovided, the name will be the name of
// executable, in this case, service name will be: 'server'

现在是时候构建和安装服务了。请注意,您必须以管理员身份运行安装。为此,请像这样以管理员身份打开控制台:

然后转到您的服务器应用程序目录,使用“-i”运行服务器,例如:

E:\project.boost.app.v3\libs\application\doc\codeproject_article\Debug>server.exe -i --name="My Service App"
The operation completed successfully

要卸载,您可以使用:

E:\project.boost.app.v3\libs\application\doc\codeproject_article\Debug>server.exe -u --name="My Service App"
The operation completed successfully

在 SCM 中查找“My Service App”服务。

控制面板\所有控制面板项\管理工具\服务

该服务仍然什么也不做,但您可以将其启动和停止作为测试。

7. 为服务器添加应用程序逻辑

现在是时候为我们的服务器添加应用程序逻辑了,我们将在此使用 Boost.Asio,我们将构建一个基本的 TCP/IP 服务器,它将在端口 9512 上监听。

7.1 创建一个工作线程

为了让事情更有条理,我们将把逻辑放在一个工作线程中。

// ...
class my_server
{
public:

   // ...

   int operator()(const std::vector< application_ctrl::string_type >& args, 
      application_ctrl& ctrl)
   {
      // launch a work thread
      boost::thread thread(boost::bind(&my_server::work_thread, this, &ctrl));

      ctrl.wait_for_termination_request(); 
      thread.join();

      return 0;
   }

protected:

   void work_thread(boost::application::application_ctrl* ctrl)
   {
      // application logic
   }

};

7.2 将 Boost.Asio 添加到服务器。

Boost.Asio 是一个跨平台的 C++ 库,用于网络和低级 I/O 编程,它使用现代 C++ 方法为开发人员提供一致的异步模型。参考:https://boost.ac.cn/doc/libs/1_54_0/doc/html/boost_asio.html 了解更多。

// ...
class my_server
{
public:
   // ...

protected:
   void work_thread(boost::application::application_ctrl* ctrl)
   {
      // application logic
      using boost::asio::ip::tcp;

      try
      {
         boost::asio::io_service io_service;

         tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 9512));

         for (;;)
         {
            if(ctrl->state() == boost::application::application_running)
            {
               boost::system::error_code error;

               tcp::socket socket(io_service);
               acceptor.accept(socket);

               // our data is limited to 1024 bytes
               char data[1024];
               
               size_t length = socket.read_some(boost::asio::buffer(data), error);

               if(error == boost::asio::error::eof)
                  break; // Connection closed cleanly by peer.
               else if (error)
                  throw boost::system::system_error(error); // Some other error.

               // response (echo)
               std::string message(data, length);

               boost::asio::write(socket, boost::asio::buffer(message), 
                  boost::asio::transfer_all(), error);
            }
            else if(ctrl->state() == boost::application::application_stoped)
            {
               return;
            }
         }
      }
      catch (std::exception& e)
      {
         std::cerr << e.what() << std::endl;
      }
   }
};

此服务器仅回显(ECHO)来自客户端的消息,并且缓冲区只有 1024 个字符,因此最大消息大小为 1024。

8. 客户端应用程序

客户端应用程序将向服务器发送一个字符串,此时服务器仅将此消息回显给客户端。

8.1 客户端“函数对象”类实现。

class my_client
{
public:

   int operator()(const std::vector< application_ctrl::string_type >& args, 
      application_ctrl& ctrl)
      {
      using boost::asio::ip::tcp;

      // define our simple installation schema options
      po::options_description cli("client options");
      cli.add_options()
         ("help", "produce a help message")
         (",s", po::value<std::string>()->default_value("test"), "string to send")
         ;

      po::variables_map vm;
      po::store(po::parse_command_line(ctrl.argc(), ctrl.argv(), cli), vm);

      if (vm.count("help")) 
      {
         std::cout << cli << std::cout;
         return 1;
      }

      std::string message_string = vm["-s"].as<std::string>();

      if(message_string.size() > 1024)
      {
         std::cerr << "Message is too long!" << std::endl; 
      }

      std::cout 
         << "We will send to server : " 
         << message_string
         << std::endl;

      boost::system::error_code error;
      boost::asio::io_service io_service;

      tcp::resolver resolver(io_service);
      tcp::resolver::query query(tcp::v4(), "localhost", "9512");
      tcp::resolver::iterator iterator = resolver.resolve(query);

      tcp::socket socket(io_service);
      boost::asio::connect(socket, iterator);

      boost::asio::write(socket, boost::asio::buffer(message_string), 
               boost::asio::transfer_all(), error);

      char reply[1024];
      size_t reply_length = socket.read_some(boost::asio::buffer(reply), error);

      std::cout << "Reply is: ";
      std::cout.write(reply, reply_length);
      std::cout << "\n";
      
      return 0;
   }

}; // my_client class

8.2 实例化一个普通应用程序

复制服务器中的代码,然后删除告诉它成为服务的行。默认情况下,应用程序是普通应用程序类型。

int _tmain(int argc, _TCHAR* argv[])
{
   return application<
   // application_type<server_application>, ß remove this line,
   // tells to your application to be a common application
   my_application< my_server > >( args(argc, argv))();
}

9. 测试服务器和客户端应用程序

为了测试,我们需要启动服务,然后打开控制台运行客户端。

9.1 使用 SCM 启动您的服务器应用程序。

9.2 启动您的客户端,例如:client.exe -s "Hello Boost Application"

您应该会收到回复:Reply is: Hello Boost Application。

10. 处理暂停事件

现在我们将为服务器添加暂停功能。

10.1 告知类需要处理暂停。

int _tmain(int argc, _TCHAR* argv[])
{
   try 
   {
      return application<
         application_type<server_application>, 
         accept_pause_and_resume<yes>, // ß       
         my_application< my_server > >( args(argc, argv))();
   }
   catch(boost::system::system_error& se)
   {
      std::cerr << se.what() << std::endl;
      return 1;
   }
}

10.2 再次启动服务以在 SCM 中看到“暂停”链接。

10.2 在应用程序中识别暂停状态

为此,请使用 ctrl->state() == boost::application::application_paused,它会告知应用程序的状态。

// ...
class my_server
{
public:
// ...


protected:

   void work_thread(boost::application::application_ctrl* ctrl)
   {
      // application logic
      using boost::asio::ip::tcp;

      try
      {
         boost::asio::io_service io_service;

         tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 9512));

         for (;;)
         {
            if(ctrl->state() == boost::application::application_stoped)
            {
               return;
            }

            boost::system::error_code error;

            tcp::socket socket(io_service);
            acceptor.accept(socket);

            // our data is limited to 1024 bytes
            char data[1024];
               
            size_t length = socket.read_some(boost::asio::buffer(data), error);

            if(error == boost::asio::error::eof)
               break; // Connection closed cleanly by peer.
            else if (error)
               throw boost::system::system_error(error); // Some other error.

            // response (echo)
            std::string message(data, length);

            // detect pause state
            if(ctrl->state() == boost::application::application_paused)
            {
               // if app is on pause state we will aswer a pause message.
               message = "application uuid engine is paused, try again later!";
            }

            boost::asio::write(socket, boost::asio::buffer(message), 
               boost::asio::transfer_all(), error);
         }
      }
      catch (std::exception& e)
      {
         std::cerr << e.what() << std::endl;
      }
   }

}; // my_server class

当服务暂停时,客户端应用程序将收到消息“application UUID engine is paused, try again later!”而不是回显。

要再次将应用程序的状态更改为“application_running”,用户需要单击“恢复”,服务将像以前一样以回显消息进行响应。

11. 在插件中添加 UUID 引擎

Boost.Application 的一个重要补充是“共享库类”,它允许用户使用在运行时加载的动态库模块(DLL、SO/DSO)来扩展应用程序。使用此功能,客户端可以为应用程序提供插件系统。

11.1. 创建一个插件项目,添加新项目:“Win32 控制台应用程序”

11.2. 选择“DLL”,然后选择“空项目”

请注意,您需要将 Boost 目录添加到项目中,请参阅第 4.2 和 4.3 项,其中说明了如何执行此操作。

11.3. 添加新的 .cpp 文件,名为“plugin.cpp”

11.3. 创建插件 API 接口

创建一个名为plugin_api.hpp的文件,它代表一个插件 API 接口。在这种情况下,我们将构建一个插件,它将使用此接口将字符串“转换”为 UUID,但也可以执行其他类型,例如,使用某个接口将字符串“转换”为 MD5 哈希。

class my_plugin_api
{
public:
   virtual ~my_plugin_api(){};
   virtual float version() = 0;
   virtual std::string transform_string(const std::string& source) = 0;
};

11.4. 在“plugin.cpp”中实现插件行为

#define BOOST_ALL_DYN_LINK
#define BOOST_LIB_DIAGNOSTIC

#include <boost/uuid/string_generator.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/uuid/name_generator.hpp>
#include <boost/lexical_cast.hpp>

#include "plugin_api.hpp"

#include <iostream>

#if defined(_WIN32)
#   define LIBRARY_API __declspec(dllexport)
#else
#   define LIBRARY_API
#endif
   
extern "C" LIBRARY_API my_plugin_api* create_my_plugin(void);
extern "C" LIBRARY_API void delete_my_plugin(my_plugin_api* myplugin);

class my_plugin_sum : public my_plugin_api
{
public:

   float version() 
   { 
      return 1.0;  
   };

   std::string transform_string(const std::string& source)
   { 
      boost::uuids::uuid dns_namespace_uuid;

      boost::uuids::name_generator gen(dns_namespace_uuid);
      boost::uuids::uuid u = gen(source);

      return boost::lexical_cast<std::string>(u);
   };
   
   ~my_plugin_sum()
   {
      std::cout << ";o)" << std::endl;
   }
};

my_plugin_api* create_my_plugin(void)
{
   my_plugin_api *myplugin = new my_plugin_sum();
   return myplugin;
}

void delete_my_plugin(my_plugin_api* myplugin)
{
   delete myplugin;
}

11.5. 在服务器中使用插件

// ...
// Plugin API
#include "..\uuid_plugin\plugin_api.hpp"
// ...
class my_server
{
   // plugin entry point
   typedef my_plugin_api* (*pluginapi_create) (void);
   typedef void (*pluginapi_delete) (my_plugin_api* myplugin);

// ...

protected:

   void work_thread(boost::application::application_ctrl* ctrl)
   {
      // application logic
      using boost::asio::ip::tcp;

      try
      {
         boost::asio::io_service io_service;

         tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 9512));

         for (;;)
         {
            if(ctrl->state() == boost::application::application_stoped)
            {
               return;
            }

            boost::system::error_code error;

            tcp::socket socket(io_service);
            acceptor.accept(socket);

            // our data is limited to 1024 bytes
            char data[1024];
               
            size_t length = socket.read_some(boost::asio::buffer(data), error);

            if(error == boost::asio::error::eof)
               break; // Connection closed cleanly by peer.
            else if (error)
               throw boost::system::system_error(error); // Some other error.
         
            // response (echo)
            std::string message(data, length);
       
            // detect pause state
            if(ctrl->state() == boost::application::application_paused)
            {
               // if app is on pause state we will aswer a pause message.
               message = "application uuid engine is paused, try again later!";
            }
            else
            {
               if(plugin_.is_loaded())
               {
                  my_plugin_api* plugin = NULL;

                  if(plugin_.search_symbol(symbol(L"create_my_plugin")))
                  {
                     plugin = ((pluginapi_create)plugin_(symbol(L"create_my_plugin")))();
                  }

                  if(plugin != NULL)
                  {
                     message = plugin->transform_string(message);

                     ((pluginapi_delete)plugin_(symbol(L"delete_my_plugin")))(plugin);
                  }
               }
               else
               {
                  message = "some problem with plugin load, try again later!";
               }
            }
               
            boost::asio::write(socket, boost::asio::buffer(message), 
                  boost::asio::transfer_all(), error);
         }
      }
      catch (std::exception& e)
      {
         std::cerr << e.what() << std::endl;
      }
   }

private:

   shared_library plugin_;

}; // my_server class

当调用客户端时,结果是一个字符串的 UUID,例如:

E:\project.boost.app.v3\libs\application\doc\codeproject_article\Debug>client.exe -s "dokfile.com"

12. 应用程序处理程序

使用 Boost.Application 可让您响应用户发起的某些处理程序,因此处理程序可以直接添加到函数对象类中。

12.1 在服务器运行时更改插件

在一种假设的情况下,您希望更改服务器(插件)的行为。因此,您希望在用户连接时暂停服务器,并告知他们稍后重试;然后您更改插件的行为并恢复服务。

如果您尝试在服务器处于暂停状态时删除插件,您将收到以下消息:

12.2 为卸载插件并重新加载添加“暂停”和“恢复”处理程序。

class my_server
{
   // ...

   int operator()(const std::vector< application_ctrl::string_type >& args, 
      application_ctrl& ctrl)
   {

      // ...

      plugin_path_ = ctrl.executable_path().wstring() + L"\\uuid_plugin" + shared_library::suffix();
      plugin_.load(library(plugin_path_));

      // ...
   }

   int pause()
   {
      plugin_.unload();
      return 1;
   }
   
   int resume()
   {
      plugin_.load(library(plugin_path_));
      return 1;
   }

private:

   shared_library plugin_;
   boost::filesystem::path plugin_path_;

}; // my_server class

现在您可以暂停服务,替换插件,然后恢复。所有连接都将得到处理。

12.3 支持的应用程序处理程序

下表显示了用户可用的处理程序。

Handler

可用于。

调用?

备注。

 

setup

向应用程序添加设置逻辑,例如添加 Windows 服务安装功能。

在 Main(函数对象)之前

如果用户从此处理程序返回 0,则执行继续;否则程序终止。

stop

执行一些清理或其他完成任务。

在 Main(函数对象)之后

如果用户从此处理程序返回 0,则执行继续;否则程序终止。

pause

执行一些特定于应用程序的逻辑。

当用户在 SCM 上单击暂停链接时。

将应用程序的内部状态更改为 application_paused!使用 ctrl.status() 检查当前状态。

resume

执行一些特定于应用程序的逻辑。

当用户在 SCM 上单击恢复链接时。

将应用程序的内部状态更改为 application_running!使用 ctrl.status() 检查当前状态。

limit_single_instance

使用 UUID 唯一标识应用程序。

在 Main(函数对象)之前

调用以检查系统上是否已运行应用程序实例。

single_instance

如果应用程序实例已在运行,则执行一些特定于应用程序的逻辑。

在 Main(函数对象)之前,如果应用程序实例已在运行。

如果用户从此处理程序返回 0,则执行继续;否则程序终止。

以下图表显示了每个可用处理程序的调用顺序。

13. 向服务器添加一个普通应用程序

在本最终会话中,将向我们的服务添加一个普通应用程序,这将使调试应用程序的某些部分变得容易。

int _tmain(int argc, _TCHAR* argv[])
{
   try 
   {
      bool as_serice = true;

      {
         po::variables_map vm;
         po::options_description desc;

         desc.add_options()
            (",h", "Shows help.")
            (",f", "Run as common applicatio")
            ("help", "produce a help message")
            (",i", "install service")
            (",u", "unistall service")
            (",c", "check service")
            ("name", po::value<std::string>()->default_value(""), "service name")
            ("display", po::value<std::string>()->default_value(""), 
              "service display name (optional, installation only)")
            ("description", po::value<std::string>()->default_value(""), 
              "service description (optional, installation only)")
            ;

         po::store(po::parse_command_line(argc, argv, desc), vm);

         if (vm.count("-h")) 
         {
            // show help
            std::cout << desc << std::endl;
            return 0;
         }

         if (vm.count("-f")) 
            as_serice = false;
      }

      if (!as_serice)
      {
         // instantiate server application as common_app
         return common_app<my_server>( args(argc, argv) )();
      }
      else
      {
         return application<
            application_type<server_application>, 
            accept_pause_and_resume<yes>,       
            my_application< my_server > >( args(argc, argv))();
      }
   }
   catch(boost::system::system_error& se)
   {
      std::cerr << se.what() << std::endl;
      return 1;
   }
   catch(std::exception &e)
   {
      std::cerr << e.what() << std::endl;
      return 1;
   }
   catch(...)
   {
      std::cerr << "Unknown error." << std::endl;
      return 1;
   }

   return 0;
}

现在您可以实例化一个控制台应用程序,例如:

E:\project.boost.app.v3\libs\application\doc\codeproject_article\Debug>server.exe -f

14. 结论

当任务是为 Windows 构建服务时,Boost.Application 可以节省时间,否则开发人员必须直接处理它提供的复杂 API。此外,Boost.Application 还提供了一个简单高效的应用程序扩展机制(基于插件),以及许多其他现成的功能。

© . All rights reserved.