写一个Windows上的守护进程(3)句柄的管理

在Windows中编程,跟HANDLE打交道是家常便饭。为了防止忘记CloseHandle,我都是使用do-while-false手法:

void f()
{
HANDLE h = NULL; do
{
} while (false); if (h)
{
CloseHandle(h);
h = NULL;
}
}

HANDLE一多,就得写好几段长得一样的清理代码,比较麻烦。仔细一想,这个其实很容易写一个关闭器——在出作用域时自动关闭:

class closer : public boost::noncopyable
{
public:
closer(HANDLE h)
: h_(h)
{ } ~closer()
{
if (h_)
{
CloseHandle(h_);
h_ = NULL;
}
} private:
HANDLE h_;
};

创建或打开一个句柄后,将其关闭动作委托给closer。

这是我在写这篇文章的时候想到的,写代码的时候我用的是另一个办法:scoped_handle。这是从boost里边那些运用RAII手法的类上学到得,比如scoped_ptr,scoped_array,名字也是学过来的:

template<HANDLE invalid_value = NULL>
class scoped_handle : public boost::noncopyable
{
public:
scoped_handle()
: h_(invalid_value)
{
} scoped_handle(const HANDLE &h)
: h_(h)
{
} ~scoped_handle()
{
destory();
} //you should ensure not self-assignment
void reset(const HANDLE &h)
{
destory();
h_ = h;
} void destory()
{
if (h_ != invalid_value)
{
//CloseHandle will set last error code
//so we should recover it
//someone may use reset(CreateFile(...))
last_error_recover r; CloseHandle(h_);
h_ = invalid_value;
}
} bool valid() const
{
return h_ != invalid_value;
} HANDLE& get_ref()
{
return h_;
} HANDLE* get_ptr()
{
return &h_;
} private:
HANDLE h_;
};

有一个模板参数invalid_value,这是句柄的无效值,我现在见到的有两种:NULL,INVALID_HANDLE_VALUE。

用法举例:

scoped_handle<> hProcess(OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid));
if (!hProcess.valid())
{
ErrorLogLastErr("OpenProcess[%lu] fail", pid);
}
else
{
s = query(hProcess.get_ref(), native_name);
}
scoped_handle<> hToken;
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, hToken.get_ptr()))
{
//...
}
scoped_handle<> m_exit_event;
m_exit_event.reset(CreateEvent(NULL, TRUE, FALSE, NULL));
if (!m_exit_event.valid())
{
//...
}

我现在为自己找了一个不使用closer的理由:我不喜欢让别人帮助我做力所能及的事。closer就像是某人new了一个对象,然后把指针给了另一个人,让他去“擦屁股”,然而自己“擦屁股”不过是举手之劳。不过,这个理由不强劲,closer的便利性远远大于对“擦屁股”的厌恶。

这里有一个todo:我希望能定制Close动作,就是Close动作作为一个模板参数,这样一来,我就可以把HANDLE也提到模板参数的位置上,这个东西的适用范围就更广了,但是我不知道如何把Close动作提到模板参数的位置上。

想必眼尖的同学看到了上面的代码里有个last_error_recover,这是一个很简单的类,注释已经说明了它的用途,下面是实现:

class last_error_recover : public boost::noncopyable
{
public:
last_error_recover()
: code_(GetLastError())
{
} last_error_recover(const DWORD code)
: code_(code)
{
} ~last_error_recover()
{
SetLastError(code_);
} private:
const DWORD code_;
};

源码:https://git.oschina.net/mkdym/DaemonSvc.git (主)&& https://github.com/mkdym/DaemonSvc.git (提升逼格用的)。

2015年10月31日星期六

写一个Windows上的守护进程(3)句柄的管理的更多相关文章

  1. 写一个Windows上的守护进程(8)获取进程路径

    写一个Windows上的守护进程(8)获取进程路径 要想守护某个进程,就先得知道这个进程在不在.我们假设要守护的进程只会存在一个实例(这也是绝大部分情形). 我是遍历系统上的所有进程,然后判断他们的路 ...

  2. 写一个Windows上的守护进程(7)捕获异常并生成dump

    写一个Windows上的守护进程(7)捕获异常并生成dump 谁都不能保证自己的代码不出bug.一旦出了bug,最好是崩溃掉,这样很快就能被发现,若是不崩溃,只是业务处理错了,就麻烦了,可能很长时间之 ...

  3. 写一个Windows上的守护进程(6)Windows服务

    写一个Windows上的守护进程(6)Windows服务 守护进程因为要开机启动,还要高权限,所以我就把它做成Windows服务了. 关于Windows服务的官方文档,大家可以看https://msd ...

  4. 写一个Windows上的守护进程(5)文件系统重定向

    写一个Windows上的守护进程(5)文件系统重定向 在Windows上经常操作文件或注册表的同学可能知道,有"文件系统/注册表重定向"这么一回事.大致来说就是32位程序在64位的 ...

  5. 写一个Windows上的守护进程(4)日志其余

    写一个Windows上的守护进程(4)日志其余 这次把和日志相关的其他东西一并说了. 一.vaformat C++日志接口通常有两种形式:流输入形式,printf形式. 我采用printf形式,因为流 ...

  6. 写一个Windows上的守护进程(2)单例

    写一个Windows上的守护进程(2)单例 上一篇的日志类的实现里有个这: class Singleton<CLoggerImpl> 看名字便知其意--单例.这是一个单例模板类. 一个进程 ...

  7. 写一个Windows上的守护进程(1)开篇

    写一个Windows上的守护进程(1)开篇 最近由于工作需要,要写一个守护进程,主要就是要在被守护进程挂了的时候再把它启起来.说起来这个功能是比较简单的,但是我前一阵子写了好多现在回头看起来比较糟糕的 ...

  8. 写一个Windows服务

    做了两个和Windows服务有关的项目了,最开始的时候没做过,不懂,现在明白了许多.需要注意的是,如果不想登录什么的,最后在添加安装程序的那里选择那个字长的右键属性,把启动方式改为local syst ...

  9. 写一个限制上传文件大小和格式的jQuery插件

    在客户端上传文件,通常需要限制文件的尺寸和格式,最常用的做法是使用某款插件,一些成熟的插件的确界面好看,且功能强大,但美中不足的是:有时候会碰到浏览器兼容问题.本篇就来写一个"原生态&quo ...

随机推荐

  1. [QT]QT概述

    QT概述 基于C++的GUI开发框架,跨平台.Qt 是一个用于桌面系统和嵌入式开发的跨平台应用程序框架. QT是挪威TROLLTECH公司开发的跨平台C++工具,在UNIX下非常出名:他的宗旨是“一次 ...

  2. jquery 1.9 之后toggle不能用的问题

    今天用到toggle这个方法,发现不是自己想要的效果,之前有用过好多次,一直都没有问题. 网上查了原因,才知道是版本的问题,jquery1.9之后toggle取消了.那么如果想要继续用toggle的这 ...

  3. 【Nutch基础教程之七】Nutch的2种运行模式:local及deploy

    在对nutch源代码运行ant runtime后,会创建一个runtime的目录,在runtime目录下有deploy和local 2个目录. [jediael@jediael runtime]$ l ...

  4. CSS: Table-Layout & Word-Break 设置表和列的宽度固定不变

    1. 设置Table的列宽由表格宽度和列宽度设定(指定表格宽度,各个列宽度): table#tbl_id{table-layout:fixed;} 2. 设置TD内容根据宽度进行换行,即使字符串之间无 ...

  5. inline-block样式间距

    原始问题和解决方法请参考 淘宝UED官方博客:inline-block 前世今生 布局时采用行内块display:inline-block,发现元素之间有空隙,原因是由于空白字符引起的,详细见上面链接 ...

  6. C语言一维指针的深入理解

    指针是C语言中广泛使用的一种数据类型.运用指针编程是C语言最主要的风格之一. 利用指针变量可以表示各种数据结构:能很方便地使用数组和字符串:并能象汇编语言一样处理内存地址,从而编出精练而高效的程序.指 ...

  7. IOS 面试 --- 网络部分

    网络部分 3 做过的项目是否涉及网络访问功能,使用什么对象完成网络功能? 答案:ASIHTTPRequest与NSURLConnection 4 简单介绍下NSURLConnection类及+ sen ...

  8. [TYVJ] P1423 GF和猫咪的玩具

    GF和猫咪的玩具 描述 Description GF同学和猫咪得到了一个特别的玩具,这个玩具由n个金属环(编号为1---n),和m条绳索组成,每条绳索连接两个不同的金属环,并且长度相同.GF左手拿起金 ...

  9. Altium designer PCB king (收录各种版本)

    不要再留念protel99se这么古老的PCB软件了,宝刀也经不起岁月的磨练. 相比Altium Designer,protel99se逊色多了.虽然很多人还是用这把已经快老的刀.作为新时代的新人,我 ...

  10. Cocos2d-x程序Windows下VC中文乱码的解决(用MultiByteToWideChar进行转换,VC2010有非常厉害的execution_character_set)

    Cocos2d-x默认字符串常量编码都是UTF8的,而Windows中的VC默认都是跟系统相同,比如简体Windows是GB2312或者GBK.繁体就是BIG5编码.而我们大多数中国人用VC编译出来的 ...