HANDLE的无效值:NULL还是INVALID_HANDLE_VALUE? 以及对HANDLE的RAII封装

打开/创建一个HANDLE而忘记close的情况时有发生。利用RAII的思想,将HANDLE封装为一个类,在其析构函数中进行close,是一个不错

的方法。

ATL提供了一个CHandle类,但是提出了以下使用注意事项:

Some API functions will use NULL as an empty or invalid handle, while others use INVALID_HANDLE_VALUE. CHandle only uses NULL and will treat INVALID_HANDLE_VALUE as a real handle. If you call an API which can return INVALID_HANDLE_VALUE, you should check for this value before calling CHandle::Attach or passing it to the CHandle constructor, and instead pass NULL.

即:有些API将NULL作为无效的HANLDE,但有些则将INVALID_HANDLE_VALUE作为无效值。CHandle只使用NULL作为无效HANDLE,

而将INVALID_HANLDE_VALUE视为一个真正的HANDLE.

看看相关定义:

HANDLE定义为:typedef void *HANDLE;(在WinNt.h中定义的更详细一些)

NULL定义为:#define NULL 0 (在stddef.h中定义的更详细一些)

INVALID_HANDLE_VALUE定义为:#define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1) . 其实就是补码表示的-1解释为

无符号数,就是0xFFFFFFFF.

比如,CreateThread返回的无效HANDLE是NULL,而CreateFile则以INVALID_HANDLE_VALUE表示无效HANDLE.因此使用返回

HANDLE的API需查看MSDN以保证安全.

下面这篇文章分析了HANDLE无效值不统一表示的历史原因以及相关注意:

Why are HANDLE return values so inconsistent?

那么,对HANDLE的封装怎么处理为好?

看看下例http://stackoverflow.com/questions/13028872/proper-way-close-winapi-handles-avoiding-of-repeated-closing):

基本类模板:

template< class traits >
class HandleWrapper
{
private:
    traits::HandleType FHandle;
public:
    HandleWrapper():
        FHandle(traits::InvalidValue)
    {
    }
    HandleWrapper(const traits::HandleType value):
        FHandle(value)
    {
    }
    ~HandleWrapper()
    {
        Close();
    }
    void Close()
    {
        if (FHandle != traits::InvalidValue)
        {
            traits::Close(FHandle);
            FHandle = traits::InvalidValue;
        }
    }
    bool operator !() const {
        return (FHandle == traits:::InvalidValue);
    }
    operator bool() const {
        return (FHandle != traits:::InvalidValue);
    }
    operator traits::HandleType() {
        return FHandle;
    }
};

针对不同的Windows对象,提供不同的特化traits:

struct KernelHandleTraits
{
    typedef HANDLE HandleType;
    static const HANDLE InvalidValue = INVALID_HANDLE_VALUE;
    static void Close(HANDLE value)
    {
        CloseHandle(value);
    }
};
HandleWrapper<KernelHandleTraits> hFile(CreateFile(...));
struct NullKernelHandleTraits
{
    typedef HANDLE HandleType;
    static const HANDLE InvalidValue = NULL;
    static void Close(HANDLE value)
    {
        CloseHandle(value);
    }
};
HandleWrapper<NullKernelHandleTraits> hMapping(CreateFileMapping(...));
struct FileMapViewTraits
{    
    typedef void* HandleType;
    static const void* InvalidValue = NULL;
    static void Close(void *value)
    {
        UnmapViewOfFile(value);
    }
};
HandleWrapper<FileMapViewTraits> hView(MapViewOfFile(...));
struct GDIBitmapHandleTraits
{    
    typedef HBITMAP HandleType;
    static const HBITMAP InvalidValue = NULL;
    static void Close(HBITMAP value)
    {
        DeleteObject(value);
    }
};
HandleWrapper<GDIBitmapTraits> hBmp(CreateBitmap(...));

妙哉!

原文地址:https://www.cnblogs.com/qinfengxiaoyue/p/3088795.html