程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 寫一個Windows上的守護進程(3)句柄的管理,守護進程句柄

寫一個Windows上的守護進程(3)句柄的管理,守護進程句柄

編輯:C++入門知識

寫一個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日星期六

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved