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

 

妙哉!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM