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(...));

 

妙哉!

你可能感兴趣的:(Invalid)