Click here to Skip to main content
15,881,882 members
Articles / Programming Languages / C++

Create a Windows Service Application Using the Boost.Application Library

Rate me:
Please Sign up or sign in to vote.
4.82/5 (22 votes)
23 Nov 2013CPOL11 min read 51.1K   828   51   6
This article presents the Boost.Application library used to build a Windows Service.

Image 1

Important Note:<o:p>  

This article presents the old (0.3) version of Boost.Application (Library Proposal to boost.org)!<o:p>

A new version (0.4) with other interface is aready  available to download on: <o:p>

https://github.com/retf/Boost.Application<o:p>

Note that version 0.3 is no longer maintained! Version 0.4, is now maintained and receives regular updates. 

Introduction

In this article I will present a “Boost.Application” library to build a windows service. Note that Boost.Application is not yet an official Boost C++ library.

A “Boost.Application” provides an application environment, or start point to any people that want a basic infrastructure to build a system application on Windows or Unix Variants (e.g., Linux, MacOS).

In this tutorial concentrate on Windows Side development, if you are a UNIX user, refer to library documentation to more detail.

The library is in “beta” status, and the last version can be downloaded on: https://sourceforge.net/projects/boostapp/

Feedback

If you are boost user, and use Boost Mailing Lists, please provide your feedback about the library directly on the list. (Specify if you think if the library should be accepted as part of boost.com).
http://www.boost.org/community/groups.html

If you are a CodeProject user, please provide your feedback about the library directly in this page.

Bugs

If you find any bugs, please send them to me at: re.tf@acm.org

Library dependences

Boost.Application is a header only library, but have some dependences on other boost libraries that need to be built and be available, thus you need to download and build boost on your machine. The build process of boost is not very easy, but a good documentation is provided here: http://www.boost.org/doc/libs/1_54_0/more/getting_started/windows.html.

Or you can check this good article to help with the build: http://www.codeproject.com/Articles/11597/Building-Boost-libraries-for-Visual-Studio.

1. Boost.Application Installation

The first thing to do is download boost, unzip on your drive, e.g.: “c:\”, and build it. After that you need to download Boost.Application and copy it to the boost folder.

Image 2

Copy both folders to your boost installation directory:

Image 3

Now you have your environment ready to use.

2. Boost.Application Introduction

The main propose of the Boost.Application library is to abstract the Windows Service API of the user. Boost.Application supports basically two flavors of applications that can be:

  • Common Application: This kind of application is a usual Interactive Terminal/Console Application.
  • Server Application: This kind of application generates a Service (Windows), or a background process/Daemon (Unix).

This article is focused on “Server Application” flavor, but it will use Common Application too as a client that will call a server.

Boost.Application supports many others useful ready-to-use features, e.g.:

  1. Plugin extension system;
  2. Environment variables access;
  3. Args access;
  4. Setup (windows service);
  5. Process (executable) Single instance Instantiation support;
  6. Path handle;
  7. And many others.

This article intends to cover items 1 and 4. Check library manual to know more about other features provided in Boost.Application, the manual can be accessed here: boost_installation\libs\application\doc\html\index.html.

The documentation is in alpha status. If you are a native English speaker and would like to contribute to the documentation, or want to contribute with some new functionality for the libraries (see future work on documentation), please contact me.

3. Sample Application Project

This article provides a how-to tutorial that shows how to use the Boost.Application library to build a client-server application; this article covers in less detail level other boost libraries like:

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

Thus a client (console/common application) that connects to the server (service/server application) using a “TCP/IP” socket will be developed. The client role is to send a string to the server, and the server role is to return a “GUID/UUID” based on the received string from the client.

Image 4

4. Create Application Skeleton on Visual Studio

Note that the IDE used in this article is Visual Studio 2012, and all samples provided are to this environment. All code and projects are provided; check the download link on the top of the page.

4.1 Create Visual Studio Project skeletons to Client and Server applications.

Open Visual Studio, and create two Win32 projects, one for the client and another for the server.

Image 5

Image 6

4.2 On each project, open properties window and add boost installation directories to “C/C++ -> General -> Additional Include Directories”

Image 7

4.3 On each project, open properties window again, and add boost libs directories to “Linker -> General -> Additional Library Directories”

Note that when you build boost, the common place for libs is: C:\boost_1_54_0\stage\lib.

Image 8

5. Server Application

5.1 Add a Boost.Application interface to the server implementation.

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

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

5.2 Create a class (functor) that will hold the server implementation.

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

Here are two important things. The first is args, the functor will always receive a vector with the argument passed to the application; the second parameter is ctrl, which owns the current state of the application and several other methods that allow you to control the application.

The complete code, up to this point, looks like:

C++
#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 is used to enable a dynamic link to other boost needed libraries.

At this point you can copy all of the above code to the client application too.

5.3 Instantiate server class to be a Windows Service.

To do that, add the below code to the main function:

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

One more detail is needed here. The server must be running continuous, and only stop when the user requests (using SCM), so we need to add a line of code in our operator functor that will do this.

C++
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 Error Handler

Boost.Application provides two ways to handle errors: one throws an exception of type boost::system::system_error and another receives a boost::system::error_code variable ec that would be set to the result of the operation, and does not throw an exception. Refer to: http://www.boost.org/doc/libs/1_54_0/libs/system/doc/index.html to know more.

We will use the exception version, see:

C++
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. Add setup handler to server application

In order to test our Windows service, we need to install it. Installation makes the SCM aware of the service and causes the SCM to add it to the list of services that appear in the Services Console of the Control Panel.

Boost.Application provides a setup handler that can be added to the “functor” class to enable installation/un-installation of the application.

6.1 Add a “setup” handler to the application (functor) class.

C++
class my_server
{
public:

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

   // ...
};

The setup handler will be called automatically, before operator(), then we can add code that automated installation of our application service; then when the user requests setup, we can run code to install or uninstall the service and exit.

6.2 Integrate Boost.Program_options to know what user want, and enable service installation.

The program_options library allows the user to obtain program options, that is pairs from the user, via conventional methods such as command line and config file. Refer to: http://www.boost.org/doc/libs/1_54_0/doc/html/program_options.html to know more.

C++
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 Test Service Installation (setup)

Now we have a command line interface on our server to install, uninstall, and check if the service is installed. When the user requests installation, e.g.: ‘server.exe -i', the installation requisition is identified by Boost.Program_options and the code on ‘-i if' is executed, installing the service. Note that in this case we return 1, from the setup method. This causes a execution to exit after installation, and the operator (that holds server logic) is not executed.

The command line options are:

// [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'

Now it is time to build and install the service. Note that you must run the installation as Admin. To do that, open a console as Admin like:

Image 9

Then go to your server application directory and run the server using “-i", like:

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

To uninstall, you can use:

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

On SCM look for the “My Service App” service.

Control Panel\All Control Panel Items\Administrative Tools\Services:

Image 10

The service still does nothing, but you can start and stop it as a test.

7. Add Application Logic to Server

Now it is time to add the application logic to our server, we will use Boost.Asio here, we will construct a basic TCP/IP server that will listen on port 9512.

7.1 Create a work thread

To make things more organized, we will put our logic on a work thread.

C++
// ...
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 Add Boost.Asio to server.

Boost.Asio is a cross-platform C++ library for network and low-level I/O programming that provides developers with a consistent asynchronous model using a modern C++ approach. Refer to: http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio.html to know more.

C++
// ...
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;
      }
   }
};

This server just echoes (ECHO) the message from the client, and has a buffer of only 1024 characters, so the maximum message size is 1024.

8. Client Application

The client application will send a string to the server, and at this moment the server only echoes this message back to the client.

8.1 The client “functor” class implementation.

C++
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 Instantiate a common application

Copy the code from the server and just remove the line that tells it to be a service. By default, the application is a common application type.

C++
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. Testing Server and Client Application

For the test we need to start the service and then open the console to run the client.

9.1 Start your server application using SCM.

Image 11

9.2 Start your client, e.g.: client.exe -s "Hello Boost Application"

Image 12

You must receive back: Reply is: Hello Boost Application.

10. Handle pause event

Now we will add pause functionality to our server.

10.1 Tell to class that pause needs to be handled.

C++
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 Start service again to see “pause” link on SCM.

Image 13

10.2 Identify the paused status on the application

To do that, use ctrl->state() == boost::application::application_paused that tells the status of the application.

C++
// ...
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

When the service is paused, the client application will receive the message ‘application UUID engine is paused, try again later!’ instead of echo.

Image 14

To change the state of an application again to ‘application_running’, the user needs to click on Resume, and the service will answer with an echo message as before.

11. Add UUID engine on a plugin

An important addition of Boost.Application is a "Shared Library Class" that allows the user to extend the application using Dynamic Library Modules (DLL,SO/DSO) loaded at runtime. Using this feature the client can provide a plugin system to the application.

Image 15

11.1. Create a plug-in project, add new project: “Win32 Console Application”

Image 16

11.2. Select “DLL”, and set “Empty project”

Image 17

Note that you need to add boost directories to the project, refer to items 4.2 and 4.3 that show how you can do this.

11.3. Add new .cpp file called “plugin.cpp”

Image 18

11.3. Create plugin API interface

Crate a file called plugin_api.hpp”, this represents a plugin API interface. In this case we will build a plugin that will “transform” a string into a UUID using this interface, but other types can be done, e.g., “transform” a string into an MD5 hash, using some interface.

C++
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. Implement a plugin behavior on “plugin.cpp”

C++
#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. Use plugin on server

C++
// ...
// 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

When the client is called the result is a UUID of string, e.g.:

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

Image 19

12. Application Handles

Using Boost.Application allows you to respond to some handlers that are initiated by the user, thus handlers can be added directly to the functor class.

12.1 Change plugin with server running

In a hypothetical situation, you would like to change the behavior of your server (plugin). So you'd like to pause your server, when users connect, they would be advised to try later; you then change the behavior of the plugin and resume the service.

If you try to remove the plugin with the server in pause state now, you will receive the following message:

Image 20

12.2 Add ‘pause’ and ‘resume’ handlers to unload plugin, and load again.

C++
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

Now you can pause the service, replace the plug-in, and then resume. All connections will be served.

12.3 Supported Application Handlers

The next table shows the available handlers to the user.

Handler

Can be used to.

Called?

Obs.

 

setup

Add setup logic to application, e.g. add windows service installation functionality.

Before Main (functor)

f user returns 0 from this handler, the execution continues, else program is terminated.

stop

Do some clean up or other finish task.

After Main (functor)

If user returns 0 from this handler, the execution continues, else program is terminated.

pause

Do some application specific logic.

When user clicks on pause link on SCM.

Change internal status of application to application_paused! use ctrl.status() to check the current status.

resume

Do some application specific logic.

When user clicks on resume link on SCM.

Change internal status of application to application_running! use ctrl.status() to check the current status.

limit_single_instance

Uniquely identify the application using a UUID.

Before Main (functor)

Called to check if there is already an application instance running on the system.

single_instance

Do some application specific logic, if application instance is already running.

Before Main (functor), if application instance is already running.

If user returns 0 from this handler, the execution continues, else program is terminated.

The following diagram shows the order of calling of each available handler.

Image 21

13. Add a Common Application to Server

In this final session a common application will be added to our service, this will make it easy to debug some parts of the application.

C++
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;
}

Now you can instantiate an application as console, e.g.:

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

14. Conclusion

Boost.Application can save time when the task is to build a service for Windows, otherwise the developer must work directly with a complex API provided for that. Furthermore Boost.Application provides an extension mechanism for an application (based on plugins) simple and efficient, and many other ready-to-use features.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Systems Engineer
Brazil Brazil
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionBoost in a service? Pin
Cristian Amarie9-Nov-13 20:21
Cristian Amarie9-Nov-13 20:21 
AnswerRe: Boost in a service? Pin
Renato Tegon Forti10-Nov-13 2:58
Renato Tegon Forti10-Nov-13 2:58 
GeneralRe: Boost in a service? Pin
Cristian Amarie10-Nov-13 3:05
Cristian Amarie10-Nov-13 3:05 
Ok, if we're talking about something of MongoDB complexity, it can do it. Although in this case service just encompasses SCM communication and perhaps security, and it's the inner core of service - presumably, an application in itself - which does all the job.
Nuclear launch detected

GeneralRe: Boost in a service? Pin
Renato Tegon Forti10-Nov-13 3:35
Renato Tegon Forti10-Nov-13 3:35 
NewsVersion 0.4 Docs Pin
Renato Tegon Forti6-Nov-13 6:00
Renato Tegon Forti6-Nov-13 6:00 
NewsNew "aspect" experimental version of this library already can be downloaded! Pin
Renato Tegon Forti29-Oct-13 3:55
Renato Tegon Forti29-Oct-13 3:55 

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

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