Write a daemon for Windows (3) handle management, daemon handle
Write a daemon process on Windows (3) handle management
In Windows programming, it is common to deal with HANDLE. To prevent forgetting CloseHandle, I use do-while-false:
void f(){ HANDLE h = NULL; do { } while (false); if (h) { CloseHandle(h); h = NULL; }}
If you have more than one HANDLE, you have to write several sections of the same Code, which is troublesome. After thinking about it, it is easy to write a close tool -- automatically close it when the scope is out:
class closer : public boost::noncopyable{public: closer(HANDLE h) : h_(h) { } ~closer() { if (h_) { CloseHandle(h_); h_ = NULL; } }private: HANDLE h_;};
After creating or opening a handle, delegate the close action to closer.
This is what I thought of when writing this article. When writing code, I used another method: scoped_handle. This is learned from classes using RAII in boost, such as scoped_ptr and scoped_array. The name is also learned:
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_;};
There is a template parameter invalid_value, which is the handle's invalid value. I have seen two types: NULL, INVALID_HANDLE_VALUE.
Example:
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()){ //...}
I have found a reason for not using closer for myself: I don't like asking others to help me do what I can. Closer is like a person who has a new object, and then gives the pointer to another person, asking him to "wipe his ass". However, his "wipe his ass" is just a hand-lifting. However, this reason is not strong, and closer's convenience is far greater than its dislike of "wiping your ass.
Here is a todo: I want to customize the Close action, that is, the Close action as a template parameter, so that I can also mention HANDLE to the location of the template parameter, the application scope of this item is wider, but I don't know how to refer the Close action to the location of the template parameter.
Presumably, the eye-catching person saw a last_error_recover in the above Code. This is a very simple class. The comment has already explained its purpose. The following is the implementation:
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_;};
Source code: https://git.oschina.net/mkdym/DaemonSvc.git (main) & https://github.com/mkdym/DaemonSvc.git (to improve the Force Grid ).
Saturday, October 31, 2015