写一个Windows上的守护进程(6)Windows服务
写一个Windows上的守护进程(6)Windows服务
守护进程因为要开机启动,还要高权限,所以我就把它做成Windows服务了。
关于Windows服务的官方文档,大家可以看https://msdn.microsoft.com/en-us/library/windows/desktop/ms686953(v=vs.85).aspx。
总的来说,服务的行为区别于普通应用程序的地方有以下几点:
1. 一般来说,服务是运行于System用户下的,当然也可以自己指定。也就是说服务可以在无用户登录的情况下运行
2. 一般来说,服务是没有用户交互的
3. 服务可以通过服务管理器管理(启动、停止等等)
服务程序的编写区别于普通应用程序的地方有以下几点:
1. 服务程序执行的主体是ServiceMain函数,你需要在main函数中调用StartServiceCtrlDispatcher注册你的ServiceMain函数。也就是说你的功能代码应写在你的ServiceMain函数中。StartServiceCtrlDispatcher直到服务停止才会返回
2. 在ServiceMain函数中,你要及时向服务管理器报告自己的状态,好让其向用户展示自己。一般来说,ServiceMain函数的流程是这样的:

3. 作为一个正常的服务,要响应用户的请求,比如停止,这要调用RegisterServiceCtrlHandler注册自己的处理函数,也可以处理自定义的control code;要响应系统请求,比如关机,这要调用SetConsoleCtrlHandler注册自己的处理函数
4. 要想自己的程序成为服务,还得向Windows注册,这要调用CreateService,还有停止服务,启动服务之类的,详情参看MSDN,上面都有例子
我把这些步骤封装了下,做成了一个单例类——很显然,单例很适用,一个进程对应一个服务——CWin32Service:
class CWin32Service : public Singleton<CWin32Service>
{
friend class Singleton<CWin32Service>; private:
CWin32Service(void); public:
~CWin32Service(void); public:
bool init(const ServiceInfo& info); typedef std::vector<tstring> ArgList;
typedef boost::function<bool(const ArgList&)> StartingFunction;//ArgList是应用程序的命令行参数
typedef boost::function<void(const ArgList&)> ServiceFunction; void register_starting_function(const StartingFunction& f);
void register_running_function(const ServiceFunction& f);
void register_control_code_function(const DWORD c, const ServiceFunction& f); bool go();
};
上面是其主要对外接口,接口基本上对应于上面ServiceMain的流程:
l Init:告知服务名称等信息
l StartingFunction:通常都是做好初始化工作,加载配置什么的,然后启动工作线程
l running_function:通常都是等待退出信号,等待工作线程结束什么的。此函数返回意味着服务结束了
l control_code_function:这是要处理的控制代码。一般我们都会要处理stop control code的,不过你不设置也没关系
l go:这个就是调用StartServiceCtrlDispatcher注册ServiceMain函数。直到服务结束才会返回。ServiceMain中就是按流程调用上面注册的函数和报告状态
当然我们不能只完成服务程序的编写,还要让用户能安装服务、启动服务、通知服务、卸载服务的方法,我把这些提供在了命令行里:
l DaemonSvc.exe –intsall
l DaemonSvc.exe –start
l DaemonSvc.exe –stop
l DaemonSvc.exe –remove
这些动作的实现都被我拎出来放到了ServiceUtil里面。
服务是没办法在VC里直接按F5调试的,你那样启动起来的不是服务,是普通应用程序。为了方便调试,我把服务分了两种模式:普通模式,服务模式:不带参数启动起来的是普通模式,带-svc参数起来的是服务模式(所以你会看到我实现服务安装的时候,给的命令行后面是有-svc的)。普通模式下,不走StartServiceCtrlDispatcher,直接ServiceMain,并且不和服务管理器打交道。
普通模式开发调试完毕后,可以安装启动服务,看下服务模式下是不是正常,此时也可以用VC附加到服务进程上调试。
服务类的使用示例:
int main(int argc, char * argv[])
{
InitLog("", , LOG_DEBUG);
//try to enable debug privilege for querying other processes' info
WindowsUtil::set_privilege(SE_DEBUG_NAME, true); ServiceInfo si;
si.name = TSTR("DaemonSvc");
si.display_name = si.name; CWin32Service& svc = CWin32Service::get_instance_ref(); if (!svc.init(si))
{
ErrorLog("init service fail");
}
else
{
InfoLog("init service success"); svc.register_starting_function(starting);
svc.register_running_function(running);
svc.register_control_code_function(SERVICE_CONTROL_STOP, stopping);
svc.register_control_code_function(, restart); if (!svc.go())
{
ErrorLog("make service go fail");
}
else
{
InfoLog("everything is OK");
}
} return ;
}
源码:https://git.oschina.net/mkdym/DaemonSvc.git (主)&& https://github.com/mkdym/DaemonSvc.git (提升逼格用的)。
2015年11月7日星期六
写一个Windows上的守护进程(6)Windows服务的更多相关文章
- 写一个Windows上的守护进程(8)获取进程路径
写一个Windows上的守护进程(8)获取进程路径 要想守护某个进程,就先得知道这个进程在不在.我们假设要守护的进程只会存在一个实例(这也是绝大部分情形). 我是遍历系统上的所有进程,然后判断他们的路 ...
- 写一个Windows上的守护进程(7)捕获异常并生成dump
写一个Windows上的守护进程(7)捕获异常并生成dump 谁都不能保证自己的代码不出bug.一旦出了bug,最好是崩溃掉,这样很快就能被发现,若是不崩溃,只是业务处理错了,就麻烦了,可能很长时间之 ...
- 写一个Windows上的守护进程(5)文件系统重定向
写一个Windows上的守护进程(5)文件系统重定向 在Windows上经常操作文件或注册表的同学可能知道,有"文件系统/注册表重定向"这么一回事.大致来说就是32位程序在64位的 ...
- 写一个Windows上的守护进程(4)日志其余
写一个Windows上的守护进程(4)日志其余 这次把和日志相关的其他东西一并说了. 一.vaformat C++日志接口通常有两种形式:流输入形式,printf形式. 我采用printf形式,因为流 ...
- 写一个Windows上的守护进程(3)句柄的管理
写一个Windows上的守护进程(3)句柄的管理 在Windows中编程,跟HANDLE打交道是家常便饭.为了防止忘记CloseHandle,我都是使用do-while-false手法: void f ...
- 写一个Windows上的守护进程(2)单例
写一个Windows上的守护进程(2)单例 上一篇的日志类的实现里有个这: class Singleton<CLoggerImpl> 看名字便知其意--单例.这是一个单例模板类. 一个进程 ...
- 写一个Windows上的守护进程(1)开篇
写一个Windows上的守护进程(1)开篇 最近由于工作需要,要写一个守护进程,主要就是要在被守护进程挂了的时候再把它启起来.说起来这个功能是比较简单的,但是我前一阵子写了好多现在回头看起来比较糟糕的 ...
- 创建Android守护进程(底层服务)【转】
本文转载自:https://blog.csdn.net/myfriend0/article/details/80016739 创建Android守护进程(底层服务) 前言 Android底层服务,即运 ...
- 写一个限制上传文件大小和格式的jQuery插件
在客户端上传文件,通常需要限制文件的尺寸和格式,最常用的做法是使用某款插件,一些成熟的插件的确界面好看,且功能强大,但美中不足的是:有时候会碰到浏览器兼容问题.本篇就来写一个"原生态&quo ...
随机推荐
- birt报表图标中文显示为框框的解决方法
birt报表中图标部分的中文显示为框框,其他部分中文显示正常 解决办法:修改jdk中的字体设置/jdk1.6.0_13/jre/lib /fonts/fonts.dir 1.将宋体字体copy到/jd ...
- http_load压力测试
http_load是基于linux平台的性能测试工具,它体积非常小,仅100KB.它以并行复用的方式运行,可以测试web服务器的吞吐量与负载. 一.安装http_load A.进入/usr/local ...
- PHP命名空间(Namespace)的使用详解(转)
对于命名空间,官方文档已经说得很详细[查看],我在这里做了一下实践和总结. 命名空间一个最明确的目的就是解决重名问题,PHP中不允许两个函数或者类出现相同的名字,否则会产生一个致命的错误.这种情况下只 ...
- 【7】python核心编程 第十一章-函数和函数式编程
1.*函数(与方法)装饰器 装饰器背后的主要动机源自python 面向对象编程.装饰器是在函数调用之上的修饰.这些修饰 仅是当声明一个函数或者方法的时候,才会应用的额外调用. 装饰器的语法以@开头,接 ...
- GestureDetector和SimpleOnGestureListener的使用教程
1. 当用户触摸屏幕的时候,会产生许多手势,例如down,up,scroll,filing等等,我们知道View类有个View.OnTouchListener内部接口,通过重写他的onTouch(Vi ...
- 2015第16周六学习java建议
学习Java 建议: 尽量用 google 查找技术资料. 有问题在 stackoverflow 找找,大部分都已经有人回答. 多看官方的技术文档. ibm developerworkers 的文章质 ...
- Source insight添加工具自动排版
当在网上找了一些别人的程序拿来学习,用Source insight来看时,会不会因为代码太乱看了义愤填膺呢? 有很多集成的开发环境可以自动排版,但source insight却不行!不过,有工具和配置 ...
- thinkpad t530 centos 6.4 有线网卡 设置
由于新装的系统没有安装网卡驱动,各大厂商的标准又不一样,有的电脑在linux下不用安装无线网卡驱动,而很不幸,我的电脑是ret的网卡,只能自行安装,在安装无线网卡的过程中使用到了chkconfig的命 ...
- UESTC_方老师和农场 2015 UESTC Training for Graph Theory<Problem L>
L - 方老师和农场 Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) Submi ...
- Linux常用命令及使用技巧
本文重点讲述Linux命令的使用,命令是学习Linux必须熟练掌握的一个部分.Linux下的命令大概有600个,而常用的命令其实只有80个左右,这些常用的命令是需要灵活掌握的.虽然Linux的各个发行 ...