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


    写一个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日星期六

  • 相关阅读:
    gitlab 升级
    通过 备份文件 恢复/迁移 gitlab
    gitlab 远程 定时备份
    PHP 中替换若干字符串字串为数组中的值,不用循环,非常高效
    php 在客户端生成txt文件并且下载
    Mysql时间戳函数
    mysql中在表中insert数据时,有重复主键id时,变成update
    css中解决img在a元素中使得a元素撑大写法
    php以excel的形式将数据输出
    css中常用的hack
  • 原文地址:https://www.cnblogs.com/mkdym/p/4925346.html
Copyright © 2020-2023  润新知