博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Simple Windows Service in C++
阅读量:4674 次
发布时间:2019-06-09

本文共 7453 字,大约阅读时间需要 24 分钟。

     本文是来自CodeProject中的一篇名为Simple Windows Service in C++的译文,原文地址为:,作者为:Mohit Arora。

这是一篇使用C++展示如何创建简单的Windows服务的文章。

源代码下载地址为:或者

介绍

这篇文章展示如何使用C++创建一个基本的Windows服务程序。根据应用程序的体系结构,服务在许多开发方案中非常有用。

背景

我在C++中找到的Windows服务示例并不多。我使用MSDN编写这个非常基本的Windows服务。

使用代码

(1)主入口点(与任何应用程序一样)
(2)服务入口点
(3)服务控制处理程序
你可以使用Visual Studio模板项目来帮助你入门。我刚创建了一个空的Win32控制台应用程序。

在我们开始主入口程序点之前,我们需要声明一些将在整个服务中使用的全局变量。为了更加面向对象,你始终可以创建一个表示服务的类,并使用类成员代表全局变量。为了简单起见,我将使用全局变量。

我们需要一个SERVICE_STATUS结构体,将用于向Windows服务控制管理器(SCM)报告服务的状态。

SERVICE_STATUS g_ServiceStatus = {0};

我们同样需要一个SERVICE_STATUS_HANDLE句柄,用于在SCM注册后引用我们的Windows服务实例。

SERVICE_STATUS_HANDLE g_StatusHandle = NULL;

下面是一些额外的全局变量和函数声明,随着我们的继续将被使用和解释。

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")

主函数入口

 

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;

}

 

 在主函数入口点中,你可以快速调用StartServiceCtrlDispatcher,以便SCM可以调用你的服务入口点(上例中的ServiceMain)。 你希望将任何初始化推迟到你接下来定义的服务入口点。

 

服务入口点

1 VOID WINAPI ServiceMain (DWORD argc, LPTSTR *argv)  2   3     {  4   5         DWORD Status = E_FAIL;  6   7   8   9         // Register our service control handler with the SCM 10  11         g_StatusHandle = RegisterServiceCtrlHandler (SERVICE_NAME, ServiceCtrlHandler); 12  13  14  15         if (g_StatusHandle == NULL) 16  17         { 18  19             goto EXIT; 20  21         } 22  23  24  25         // Tell the service controller we are starting 26  27         ZeroMemory (&g_ServiceStatus, sizeof (g_ServiceStatus)); 28  29         g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; 30  31         g_ServiceStatus.dwControlsAccepted = 0; 32  33         g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING; 34  35         g_ServiceStatus.dwWin32ExitCode = 0; 36  37         g_ServiceStatus.dwServiceSpecificExitCode = 0; 38  39         g_ServiceStatus.dwCheckPoint = 0; 40  41  42  43         if (SetServiceStatus (g_StatusHandle , &g_ServiceStatus) == FALSE) 44  45         { 46  47             OutputDebugString(_T( 48  49               "My Sample Service: ServiceMain: SetServiceStatus returned error")); 50  51         } 52  53  54  55         /* 56  57         * Perform tasks necessary to start the service here 58  59         */ 60  61  62  63         // Create a service stop event to wait on later 64  65         g_ServiceStopEvent = CreateEvent (NULL, TRUE, FALSE, NULL); 66  67         if (g_ServiceStopEvent == NULL) 68  69         {  70  71             // Error creating event 72  73             // Tell service controller we are stopped and exit 74  75             g_ServiceStatus.dwControlsAccepted = 0; 76  77             g_ServiceStatus.dwCurrentState = SERVICE_STOPPED; 78  79             g_ServiceStatus.dwWin32ExitCode = GetLastError(); 80  81             g_ServiceStatus.dwCheckPoint = 1; 82  83  84  85             if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) 86  87     { 88  89         OutputDebugString(_T( 90  91           "My Sample Service: ServiceMain: SetServiceStatus returned error")); 92  93     } 94  95             goto EXIT; 96  97         }    98  99 100 101         // Tell the service controller we are started102 103         g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;104 105         g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;106 107         g_ServiceStatus.dwWin32ExitCode = 0;108 109         g_ServiceStatus.dwCheckPoint = 0;110 111 112 113         if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE)114 115         {116 117             OutputDebugString(_T(118 119               "My Sample Service: ServiceMain: SetServiceStatus returned error"));120 121         }122 123 124 125         // Start a thread that will perform the main task of the service126 127         HANDLE hThread = CreateThread (NULL, 0, ServiceWorkerThread, NULL, 0, NULL);128 129 130 131         // Wait until our worker thread exits signaling that the service needs to stop132 133         WaitForSingleObject (hThread, INFINITE);134 135 136 137 138 139         /*140 141         * Perform any cleanup tasks142 143         */144 145 146 147         CloseHandle (g_ServiceStopEvent);148 149 150 151         // Tell the service controller we are stopped152 153         g_ServiceStatus.dwControlsAccepted = 0;154 155         g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;156 157         g_ServiceStatus.dwWin32ExitCode = 0;158 159         g_ServiceStatus.dwCheckPoint = 3;160 161 162 163         if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE)164 165         {166 167             OutputDebugString(_T(168 169               "My Sample Service: ServiceMain: SetServiceStatus returned error"));170 171         }172 173 174 175     EXIT:176 177         return;178 179     }

 

服务主入口点执行以下任务:

(1)初始化我们从主函数入口推迟的任何必要项目。

(2)注册服务控制处理程序,它将处理服务Stop,Pause,Continue,Shutdown**等控制命令。 这些是通过SERVICE_STATUS结构的dwControlsAccepted字段作为位掩码注册的。
(3)将服务状态设置为SERVICE_PENDING,然后设置为SERVICE_RUNNING。 在任何错误和退出时将状态设置为SERVICE_STOPPED。 当状态设置为SERVICE_STOPPED或SERVICE_PENDING时,始终将SERVICE_STATUS.dwControlsAccepted设置为0。
(4)执行启动任务。向创建线程/事件/互斥量/IPCs/等。

 服务控制处理程序

1 VOID WINAPI ServiceCtrlHandler (DWORD CtrlCode) 2 { 3 switch (CtrlCode)  4 { 5 case SERVICE_CONTROL_STOP : 6  7 if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING) 8 break; 9 10 /* 11 * Perform tasks necessary to stop the service here 12 */13 14 g_ServiceStatus.dwControlsAccepted = 0;15 g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;16 g_ServiceStatus.dwWin32ExitCode = 0;17 g_ServiceStatus.dwCheckPoint = 4;18 19 if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE)20 {21 OutputDebugString(_T(22 "My Sample Service: ServiceCtrlHandler: SetServiceStatus returned error"));23 }24 25 // This will signal the worker thread to start shutting down26 SetEvent (g_ServiceStopEvent);27 28 break;29 30 default:31 break;32 }33 }

 

服务控制处理程序已在你的服务主入口点注册。 每个服务都必须有一个处理程序来处理来自SCM的控制请求。 控制处理程序必须在30秒内返回,否则SCM将返回错误,该错误指出服务没有响应。 这是因为处理程序将在SCM的上下文中调用,并将保持SCM直到它从处理程序返回。
我只实现并支持SERVICE_CONTROL_STOP请求。 你可以处理其他请求,例如SERVICE_CONTROL_CONTINUE,SERVICE_CONTROL_INTERROGATE,SERVICE_CONTROL_PAUSE,SERVICE_CONTROL_SHUTDOWN以及可以使用RegisterServiceCtrlHandler(Ex)函数注册的Handler或HandlerEx函数支持的其他请求。

服务工作线程

1 DWORD WINAPI ServiceWorkerThread (LPVOID lpParam) 2 { 3 // Periodically check if the service has been requested to stop 4 while (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0) 5 {  6 /*  7 * Perform main service function here 8 */ 9 10 // Simulate some work by sleeping11 Sleep(3000);12 }13 14 return ERROR_SUCCESS;15 }

 

此示例服务工作线程除了休眠之外什么都不做,并检查服务是否已收到要停止的控制。 一旦收到停止服务的控制信息,服务控制处理程序就会设置g_ServiceStopEvent事件。 接着服务工作者线程断开并退出。 这将通知Service Main例程返回并有效地停止服务。

安装服务

你可以通过在命令行提示符中运行一下命令来安装服务(**注意要以管理员身份运行**):

C:\>sc create "My Sample Service" binPath= C:\SampleService.exe

在binPath=和值[?]之间需要一个空格。此外,要使用服务可执行程序的绝对路径。

你现在应该在Windows服务控制台中看到该服务。 从这里你可以开始和停止服务。

## 卸载服务

你可以从命令提示符通过运行以下命令卸载服务:

C:\>sc delete "My Sample Service"

历史

11/28/2012:文章和代码的初始版本。

11/29/2012:改进了代码并修复了文章示例代码中的一个拼写错误。
2015年11月11日:根据用户评论更新了有关如何安装服务的详细信息。

转载于:https://www.cnblogs.com/ccf19881030/p/10864096.html

你可能感兴趣的文章
hdu 3371 Connect the Cities(prim算法)
查看>>
《构建之法》读后感二
查看>>
HDU 4857 逃生 (反向拓扑排序 & 容器实现)
查看>>
hdu 2063 过山车(模板)
查看>>
qemu-kvm 代码分析
查看>>
maven安装 maven上传jar包到库里面
查看>>
C语言中volatile关键字的作用
查看>>
解决vs2005中文乱码问题
查看>>
logrotate工具日志切割
查看>>
Android Studio--按钮跳转新页
查看>>
解决Android图库不识别.nomedia的问题
查看>>
继续推荐几款VisualStudio的插件
查看>>
tslib-1.4.tar.gz安装和配置
查看>>
什么是301重定向与301重定向怎么做
查看>>
摄影基础1
查看>>
vux在ISO中异常 this.$vux.confirm.show
查看>>
shell脚本修改文本中匹配行之前的行的方法
查看>>
Uva 10817 校长的烦恼
查看>>
九度OJ-1112-导弹拦截-最长不增子序列
查看>>
详解java类的生命周期 .
查看>>