A basic Windows service in C++ (CppWindowsService)

This code sample demonstrates creating a basic Windows Service application in VC++

 
 
 
评级

 
 
 
 
 
 
(14)
已下载49,480 次
上次更新日期2012/3/2
许可证

共享

    
 

SERVICE APPLICATION (CppWindowsService)

Introduction

This code sample demonstrates creating a very basic Windows Service application in Visual C++. The example Windows Service logs the service start and stop information to the Application event log, and shows how to run the main function of the service in a thread pool worker thread. You can easily extend the Windows Service skeleton to meet your own business requirement.

Running the Sample

The following steps walk through a demonstration of the Windows Service sample.

Step1. After you successfully build the sample project in Visual Studio 2008, you will get a service application: CppWindowsService.exe.

Step2. Run a command prompt as administrator, navigate to the output folder of the sample project, and enter the following command to install the service.

CppWindowsService.exe -install

The service is successfully installed if the process outputs:

If you do not see this output, please look for error codes in the ouput, and investigate the cause of failure. For example, the error code 0x431 means that the service already exists, and you need to uninstall it first.

Step3. Open Service Management Console (services.msc). You should be able to find "CppWindowsService Sample Service" in the service list.

Step4. Right-click the CppWindowsService service in Service Management Console and select Start to start the service. Open Event Viewer, and navigate to Windows Logs / Application. You should be able to see this event from CppWindowsService with the information:

Step5. Right-click the service in Service Management Console and select Stop to stop the service. You will see this new event from CppWindowsService in Event Viewer / Windows Logs / Application with the information:

Step6. To uninstall the service, enter the following command in the command prompt running as administrator.

CppWindowsService.exe -remove

If the service is successfully removed, you would see this output:

Using the Code

Step1. In Visual Studio 2008, add a new Visual C++ / Win32 / Win32 Console Application project named CppWindowsService. Unselect the "Precompiled header" option in Application Settings of the Win32 Application Wizard, and delete stdafx.h, stdafx.cpp, targetver.h files after the project is created.

Step2. Define the settings of the service in CppWindowsService.cpp.

C++
  1. // Internal name of the service 
  2.    #define SERVICE_NAME             L"CppWindowsService" 
  3.  
  4.  
  5.    // Displayed name of the service 
  6.    #define SERVICE_DISPLAY_NAME     L"CppWindowsService Sample Service" 
  7.  
  8.  
  9.    // Service start options. 
  10.    #define SERVICE_START_TYPE       SERVICE_DEMAND_START 
  11.  
  12.  
  13.    // List of service dependencies - "dep1\0dep2\0\0" 
  14.    #define SERVICE_DEPENDENCIES     L"" 
  15.  
  16.  
  17.    // The name of the account under which the service should run 
  18.    #define SERVICE_ACCOUNT          L"NT AUTHORITY\\LocalService" 
  19.  
  20.  
  21.    // The password to the service account name 
  22.    #define SERVICE_PASSWORD         NULL 
  23.  
 

Security Note: In this code sample, the service is configured to run as LocalService, instead of LocalSystem. The LocalSystem account has broad permissions. Use the LocalSystem account with caution, because it might increase your risk of attacks from malicious software. For tasks that do not need broad permissions, consider using the LocalService account, which acts as a non-privileged user on the local computer and presents anonymous credentials to any remote server.

Step3. Replace the application's entry point (main) in CppWindowsService.cpp with the code below. According to the arguments in the command line, the function installs or uninstalls or starts the service by calling into different routines that will be declared and implemented in the next steps

C++
  1. int wmain(int argc, wchar_t *argv[]) 
  2.     { 
  3.         if ((argc > 1) && ((*argv[1] == L'-' || (*argv[1] == L'/')))) 
  4.         { 
  5.             if (_wcsicmp(L"install", argv[1] + 1) == 0) 
  6.             { 
  7.                 // Install the service when the command is  
  8.                 // "-install" or "/install". 
  9.                 InstallService( 
  10.                     SERVICE_NAME,               // Name of service 
  11.                     SERVICE_DISPLAY_NAME,       // Name to display 
  12.                     SERVICE_START_TYPE,         // Service start type 
  13.                     SERVICE_DEPENDENCIES,       // Dependencies 
  14.                     SERVICE_ACCOUNT,            // Service running account 
  15.                     SERVICE_PASSWORD            // Password of the account 
  16.                     ); 
  17.             } 
  18.             else if (_wcsicmp(L"remove", argv[1] + 1) == 0) 
  19.             { 
  20.                 // Uninstall the service when the command is  
  21.                 // "-remove" or "/remove". 
  22.                 UninstallService(SERVICE_NAME); 
  23.             } 
  24.         } 
  25.         else 
  26.         { 
  27.             wprintf(L"Parameters:\n"); 
  28.             wprintf(L" -install  to install the service.\n"); 
  29.             wprintf(L" -remove   to remove the service.\n"); 
  30.  
  31.  
  32.             CSampleService service(SERVICE_NAME); 
  33.             if (!CServiceBase::Run(service)) 
  34.             { 
  35.                 wprintf(L"Service failed to run w/err 0x%08lx\n", GetLastError()); 
  36.             } 
  37.         } 
  38.  
  39.  
  40.         return 0; 
  41.     } 
  42.  
 

Step4. Add the ServiceBase.h and ServiceBase.cpp files to provide a base class for a service that will exist as part of a service application. The class is named "CServiceBase". It must be derived from when creating a new service class.

The service base class has these public functions:

C++
  1. // It register the executable for a service with SCM. 
  2.   static BOOL CServiceBase::Run(CServiceBase &service) 
  3.  
  4.  
  5.   // This is the constructor of the service class. The optional parameters  
  6.   // (fCanStop, fCanShutdown and fCanPauseContinue) allow you to specify  
  7.   // whether the service can be stopped, paused and continued, or be  
  8.   // notified when system shutdown occurs. 
  9.   CServiceBase::CServiceBase(PWSTR pszServiceName,  
  10.       BOOL fCanStop = TRUE,  
  11.       BOOL fCanShutdown = TRUE,  
  12.       BOOL fCanPauseContinue = FALSE) 
  13.  
  14.  
  15.   // This is the virtual destructor of the service class. 
  16.   virtual ~CServiceBase::CServiceBase(void); 
  17.    
  18.   // Funtion that stops the service. 
  19.   void CServiceBase::Stop(); 
  20.  
 

The class also provides these virtual member functions. You can implement them in a derived class. The functions execute when the service starts, stops, pauses, resumes, and when the system is shutting down.

C++
  1. virtual void OnStart(DWORD dwArgc, PWSTR *pszArgv); 
  2.  virtual void OnStop(); 
  3.  virtual void OnPause(); 
  4.  virtual void OnContinue(); 
  5.  virtual void OnShutdown(); 
  6.  
 

Step5. Add the SampleService.h and SampleService.cpp files to provide a sample service class that derives from the service base class - CServiceBase. The sample service logs the service start and stop information to the Application log, and shows how to run the main function of the service in a thread pool worker thread.

CSampleService::OnStart, which is executed when the service starts, calls CServiceBase::WriteEventLogEntry to log the service-start information. And it calls CThreadPool::QueueUserWorkItem to queue the main service function (CSampleService::ServiceWorkerThread) for execution in a worker thread.

NOTE: A service application is designed to be long running. Therefore, it usually polls or monitors something in the system. The monitoring is set up in theOnStart method. However, OnStart does not actually do the monitoring. The OnStart method must return to the operating system after the service's operation has begun. It must not loop forever or block. To set up a simple monitoring mechanism, one general solution is to create a timer in OnStart. The timer would then raise events in your code periodically, at which time your service could do its monitoring. The other solution is to spawn a new

thread to perform the main service functions, which is demonstrated in this code sample.

C++
  1. void CSampleService::OnStart(DWORD dwArgc, LPWSTR *lpszArgv) 
  2.    { 
  3.        // Log a service start message to the Application log. 
  4.        WriteEventLogEntry(L"CppWindowsService in OnStart",  
  5.            EVENTLOG_INFORMATION_TYPE); 
  6.  
  7.  
  8.        // Queue the main service function for execution in a worker thread. 
  9.        CThreadPool::QueueUserWorkItem(&CSampleService::ServiceWorkerThread, this); 
  10.    } 
  11.  
 

CSampleService::OnStop, which is executed when the service stops, calls CServiceBase::WriteEventLogEntry to log the service-stop information. Next, it sets the member varaible m_fStopping as TRUE to indicate that the service is stopping and waits for the finish of the main service function that is signaled by the m_hStoppedEvent event object.

C++
  1. void CSampleService::OnStop() 
  2.    { 
  3.        WriteEventLogEntry(L"CppWindowsService in OnStop",  
  4.            EVENTLOG_INFORMATION_TYPE); 
  5.  
  6.  
  7.        // Indicate that the service is stopping and wait for the finish of the  
  8.        // main service function (ServiceWorkerThread). 
  9.        m_fStopping = TRUE; 
  10.        if (WaitForSingleObject(m_hStoppedEvent, INFINITE) != WAIT_OBJECT_0) 
  11.        { 
  12.            throw GetLastError(); 
  13.        } 
  14.    } 
  15.  
 

CSampleService::ServiceWorkerThread runs in a thread pool worker thread. It performs the main function of the service such as the communication with client applications through a named pipe. In order that the main function finishes gracefully when the service is about to stop, it should periodically check the m_fStopping varaible. When the function detects that the service is stopping, it cleans up the work and signal the m_hStoppedEvent event object.

C++
  1. void CSampleService::ServiceWorkerThread(void) 
  2.    { 
  3.        // Periodically check if the service is stopping. 
  4.        while (!m_fStopping) 
  5.        { 
  6.            // Perform main service function here... 
  7.  
  8.  
  9.            ::Sleep(2000);  // Simulate some lengthy operations. 
  10.        } 
  11.  
  12.  
  13.        // Signal the stopped event. 
  14.        SetEvent(m_hStoppedEvent); 
  15.    } 
  16.  
 

Step6. Add the ServiceInstaller.h and ServiceInstaller.cpp files to declare and implement functions that install and uninstall the service:

C++
  1. InstallService          Installs the service 
  2. UninstallService        Uninstalls the service  
  3.  
 

More Information

��         MSDN: About Services

��         MSDN: The Complete Service Sample

��         MSDN: Creating a Simple Win32 Service in C++

ng » Hardware & System » Windows Services
 
Article
Browse Code
Stats
Revisions (7)
Alternatives (1)
Comments (39)
Add your own
alternative version
Tagged as

C++
Windows
Win32
Win64
VS2008
Dev
Stats

159.7K views
13.4K downloads
143 bookmarked
Posted 28 Nov 2012
Simple Windows Service in C++

Mohit Arora, 30 May 2013 CPOL

4.90 (56 votes)
Rate this:
vote 1vote 2vote 3vote 4vote 5
An article that shows how to create a simple Windows service in C++.
Download sample - 3.3 KB
Introduction
This article shows how to create a basic Windows Service in C++. Services are very useful in many development scenarios depending on the architecture of the application.

Background
There are not many Windows Service examples that I found in C++. I used MSDN to write this very basic Windows service.

Using the code
At a minimum a service requires the following items:

A Main Entry point (like any application)
A Service Entry point
A Service Control Handler
You can use a Visual Studio template project to help you get started. I just created an "Empty" Win32 Console Application.

Before we get started on the Main Entry Point, we need to declare some globals that will be used throughout the service. To be more object oriented you can always create a class that represents your service and use class members instead of globals. To keep it simple I will use globals.

We will need a SERVICE_STATUS structure that will be used to report the status of the service to the Windows Service Control Manager (SCM).

Hide   Copy Code
SERVICE_STATUS g_ServiceStatus = {0};
We will also need a SERVICE_STATUS_HANDLE that is used to reference our service instance once it is registered with the SCM.

Hide   Copy Code
SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
Here are some additional globals and function declarations that will be used and explained as we go along.

Hide   Copy Code
SERVICE_STATUS g_ServiceStatus = {0};
SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
HANDLE g_ServiceStopEvent = INVALID_HANDLE_VALUE;

VOID WINAPI ServiceMain (DWORD argc, LPTSTR *argv);
VOID WINAPI ServiceCtrlHandler (DWORD);
DWORD WINAPI ServiceWorkerThread (LPVOID lpParam);

#define SERVICE_NAME _T("My Sample Service")
Main Entry Point

Hide   Copy Code
int _tmain (int argc, TCHAR *argv[])
{
SERVICE_TABLE_ENTRY ServiceTable[] =
{
{SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain},
{NULL, NULL}
};

if (StartServiceCtrlDispatcher (ServiceTable) == FALSE)
{
return GetLastError ();
}

return 0;
}
In the main entry point you quickly call StartServiceCtrlDispatcher so the SCM can call your Service Entry point (ServiceMain in the example above). You want to defer any initialization until your Service Entry point, which is defined next.

Service Entry Point

Hide   Shrink   Copy Code
VOID WINAPI ServiceMain (DWORD argc, LPTSTR *argv)
{
DWORD Status = E_FAIL;

// Register our service control handler with the SCM
g_StatusHandle = RegisterServiceCtrlHandler (SERVICE_NAME, ServiceCtrlHandler);

if (g_StatusHandle == NULL)
{
goto EXIT;
}

// Tell the service controller we are starting
ZeroMemory (&g_ServiceStatus, sizeof (g_ServiceStatus));
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwServiceSpecificExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;

if (SetServiceStatus (g_StatusHandle , &g_ServiceStatus) == FALSE)
{
OutputDebugString(_T(
"My Sample Service: ServiceMain: SetServiceStatus returned error"));
}

/*
* Perform tasks necessary to start the service here
*/

// Create a service stop event to wait on later
g_ServiceStopEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
if (g_ServiceStopEvent == NULL)
{
// Error creating event
// Tell service controller we are stopped and exit
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = GetLastError();
g_ServiceStatus.dwCheckPoint = 1;

if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE)
{
OutputDebugString(_T(
"My Sample Service: ServiceMain: SetServiceStatus returned error"));
}
goto EXIT;
}

// Tell the service controller we are started
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;

if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE)
{
OutputDebugString(_T(
"My Sample Service: ServiceMain: SetServiceStatus returned error"));
}

// Start a thread that will perform the main task of the service
HANDLE hThread = CreateThread (NULL, 0, ServiceWorkerThread, NULL, 0, NULL);

// Wait until our worker thread exits signaling that the service needs to stop
WaitForSingleObject (hThread, INFINITE);

/*
* Perform any cleanup tasks
*/

CloseHandle (g_ServiceStopEvent);

// Tell the service controller we are stopped
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 3;

if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE)
{
OutputDebugString(_T(
"My Sample Service: ServiceMain: SetServiceStatus returned error"));
}

EXIT:
return;
}
The Service Main Entry Point performs the following tasks:

Initialize any necessary items which we deferred from the Main Entry Point.
Register the service control handler which will handle Service Stop, Pause, Continue, Shutdown, etc control commands. These are registered via the dwControlsAccepted field of the SERVICE_STATUS structure as a bit mask.
Set Service Status to SERVICE_PENDING then to SERVICE_RUNNING. Set status to SERVICE_STOPPED on any errors and on exit. Always set SERVICE_STATUS.dwControlsAccepted to 0 when setting status to SERVICE_STOPPED or SERVICE_PENDING.
Perform start up tasks. Like creating threads/events/mutex/IPCs/etc.
Service Control Handler

Hide   Shrink   Copy Code
VOID WINAPI ServiceCtrlHandler (DWORD CtrlCode)
{
switch (CtrlCode)
{
case SERVICE_CONTROL_STOP :

if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING)
break;

/*
* Perform tasks necessary to stop the service here
*/

g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 4;

if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE)
{
OutputDebugString(_T(
"My Sample Service: ServiceCtrlHandler: SetServiceStatus returned error"));
}

// This will signal the worker thread to start shutting down
SetEvent (g_ServiceStopEvent);

break;

default:
break;
}
}
The Service Control Handler was registered in your Service Main Entry point. Each service must have a handler to handle control requests from the SCM. The control handler must return within 30 seconds or the SCM will return an error stating that the service is not responding. This is because the handler will be called in the context of the SCM and will hold the SCM until it returns from the handler.

I have only implemented and supported the SERVICE_CONTROL_STOP request. You can handle other requests such as SERVICE_CONTROL_CONTINUE, SERVICE_CONTROL_INTERROGATE, SERVICE_CONTROL_PAUSE, SERVICE_CONTROL_SHUTDOWN and others supported by the Handler or HandlerEx function that can be registered with the RegisterServiceCtrlHandler(Ex) function.

Service Worker Thread

Hide   Copy Code
DWORD WINAPI ServiceWorkerThread (LPVOID lpParam)
{
// Periodically check if the service has been requested to stop
while (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0)
{
/*
* Perform main service function here
*/

// Simulate some work by sleeping
Sleep(3000);
}

return ERROR_SUCCESS;
}
This sample Service Worker Thread does nothing but sleep and check to see if the service has received a control to stop. Once a stop control has been received the Service Control Handler sets the g_ServiceStopEvent event. The Service Worker Thread breaks and exits. This signals the Service Main routine to return and effectively stop the service.

Installing the Service
You can install the service from the command prompt by running the following command:

Hide   Copy Code
C:\>sc create "My Sample Service" binPath= C:\SampleService.exe
A space is required between binPath= and the value[?]. Also, use the full absolute path to the service executable.

You should now see the service in the Windows Services console. From here you can start and stop the service.

Uninstalling the Service
You can uninstall the service from the command prompt by running the following command:

Hide   Copy Code
C:\>sc delete "My Sample Service"
History
11/28/2012: Initial release of article and code.
11/29/2012: Improved code and fixed one typo in article sample code.
11/03/2015: Updated details on how to install the service based on user comments.

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

Share

https://code.msdn.microsoft.com/windowsapps/CppWindowsService-cacf4948

http://www.codeproject.com/Articles/499465/Simple-Windows-Service-in-Cplusplus


 

A basic Windows service in C++ (CppWindowsService)的更多相关文章

  1. Windows Service--Write a Better Windows Service

    原文地址: http://visualstudiomagazine.com/Articles/2005/10/01/Write-a-Better-Windows-Service.aspx?Page=1 ...

  2. Windows Service的官方描述,抄下来(不写obj就是LocalSystem)

    How to create a Windows service by using Sc.exe Email Print Support for Windows XP has ended Micro ...

  3. C#创建、安装、卸载、调试Windows Service(Windows 服务)的简单教程

    前言:Microsoft Windows 服务能够创建在它们自己的 Windows 会话中可长时间运行的可执行应用程序.这些服务可以在计算机启动时自动启动,可以暂停和重新启动而且不显示任何用户界面.这 ...

  4. 如何利用mono把.net windows service程序迁移到linux上

    How to migrate a .NET Windows Service application to Linux using mono? 写在最前:之所以用要把windows程序迁移到Linux上 ...

  5. 如何托管ASP.NET Core应用到Windows Service中

    (此文章同时发表在本人微信公众号"dotNET开发经验谈",欢迎右边二维码来关注.) 题记:正在构思一个中间件的设计,考虑是否既可以使用最新的技术,也可以兼顾传统的部署模式.所以有 ...

  6. 解决安装mysql的”A Windows service with the name MySQL already exists.“问题

    如果以前安装过mysql,卸载重装,很可能会碰到"A Windows service with the name MySQL already exists."这样的提示.即服务已经 ...

  7. 使用Windows Service Wrapper快速创建一个Windows Service

    前言 今天介绍一个小工具的使用.我们都知道Windows Service是一种特殊的应用程序,它的好处是可以一直在后台运行,相对来说,比较适合一些需要一直运行同时不需要过多用户干预的应用程序,这一类我 ...

  8. 使用Python写Windows Service服务程序

    1.背景 如果你想用Python开发Windows程序,并让其开机启动等,就必须写成windows的服务程序Windows Service,用Python来做这个事情必须要借助第三方模块pywin32 ...

  9. Install Jenkins Slave as Windows Service

    https://wiki.jenkins-ci.org/display/JENKINS/Installing+Jenkins+as+a+Windows+service SC 直接创建windows s ...

随机推荐

  1. php-redis扩展模块安装记录

    redis的安装可以参考:centos下部署redis服务环境的操作记录 下面记录下php-redis扩展模块的安装过程:php的安装目录是/Data/app/php5.6.26 下载phpredis ...

  2. JS中字符串倒序的两种方法

    var reverse = function( str ){ var stack = [];//生成一个栈 for(var len = str.length,i=len;i>=0;i-- ){ ...

  3. 032数值的整数次方(keep it up)

    剑指offer中题目:http://ac.jobdu.com/problem.php? pid=1514 题目描写叙述: 给定一个double类型的浮点数base和int类型的整数exponent. ...

  4. http to https automatic--weblogic/jboss/tomcat--reference

    weblogic reference from:http://middlewaremagic.com/weblogic/?p=2019 Many times we want to secure our ...

  5. 《UNIX网络编程》之read_timeout实验

    最近在做项目,需要做一个服务器和客户端的基于TCP的套接口网络编程,由于服务器端返回数据并不是那么的及时,因此,需要在客户端做些延迟,然后才能去读取数据,实验测试结果如下. 首先,我们先来看一下我们封 ...

  6. lab3

    lamp: 在阿里云linux(Ubuntu)上安装Apache mysql php : apt-get install mysql_server mysql_client php5 php_mysq ...

  7. HDU -1284钱币兑换

    这个是完全背包的基础题, 模拟换钱, 刚开始状态方程写错了,我直接写dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3], 然后想了想感觉太大了,不太对,后来看网上的代码 ...

  8. C# SqlHelper

    操作数据库时,经常会把常用的方法封装到一个类中,这里简单写了一个SQLHelper类,供我平时调用. public static class SqlHelper { private static re ...

  9. 美洽SDK

    简介 GitHub地址:https://github.com/Meiqia/MeiqiaSDK-Android 开发文档:http://meiqia.com/docs/meiqia-android-s ...

  10. 12 个 CSS 高级技巧汇总

    下面这些CSS高级技巧,一般人我可不告诉他哦. 使用 :not() 在菜单上应用/取消应用边框 给body添加行高 所有一切都垂直居中 逗号分隔的列表 使用负的 nth-child 选择项目 对图标使 ...