写一个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. linux查看压缩包的文件列表

    网上看到了一篇文章: Using bzip2 with less 这篇文章介绍了一个脚本,脚本功能就是列出压缩包所压缩的文件,本文算是原文搬运,不过减少点东西以适用我日常系统运用. #!/bin/ba ...

  2. Arbitrage HDU

    Arbitrage                                              Time Limit: 2000/1000 MS (Java/Others)    Mem ...

  3. Tree 使用方式

    Traditional Ways of Tree Traversal This page contains examples of some “standard” traversal algorith ...

  4. 布尔值(Boolean values)

    布尔值是特殊的整数. 尽管布尔值由常量 True 和 False 来表示, 如果将布尔值放到一 个数值上下文环境中(比方将 True 与一个数字相加), True 会被当成整数值 1, 而 False ...

  5. Scala学习笔记--隐式转换

    隐式转换的规则:1.无歧义规则:隐式转换唯有不存在其他可插入转换的前提下才能插入  若编译器有两种方法修正x+y 如convert1(x)+y,convert2(x)+y,会报错2.单一调用规则:只尝 ...

  6. Scala学习笔记--枚举

    枚举 scala不用关注枚举的特别语法,取而代之的是标准库中的类, scala.Enumeration 想要创建新的枚举,只需要拓展这个类的对象即可 object Color extends Enum ...

  7. 转载--http协议学习和总结

    http的了解一直停留在一知半解的程度,今天看到阿蜜果大大的博客,果断学习了,这里做个转载,希望阿蜜果大大不要怪罪~~ 3.1 Cookie和Session Cookie和Session都为了用来保存 ...

  8. AFNetworking实现 断点续传

    用AFNetworking实现断点续传,暂停,继续   AFNetworking断点续传暂停恢复 AFNetworking的版本:platform:ios,'7.0' pod "AFNetw ...

  9. js与objective-c的交互-备

    在写 JavaScript 的时候,可以使用一个叫做 window 的对象,像是我们想要从现在的网页跳到另外一个网页的时候,就会去修改 window.location.href 的位置:在我们的 Ob ...

  10. find之exec和args

    本来以为以前的差不多够用了.呵呵,看到很多高手用高技巧,心痒痒的觉得我自己还可以提升啊..哈哈哈. 这个实践起来之后,,SED,AWK也得深化一下,,,SHELL和PYTHON,作运维的两样都不能废. ...