zoukankan      html  css  js  c++  java
  • 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(...));

    妙哉!

  • 相关阅读:
    Go语言
    Go语言
    electron-builder vue3 用户自定义安装目录
    提取页面中的style标签内容
    px2rpx | px转rpx
    js EventBus
    select 下拉选择多个值
    keep-alive页面缓存
    js适配移动端页面
    vue日常问题记录
  • 原文地址:https://www.cnblogs.com/qinfengxiaoyue/p/3088795.html
Copyright © 2011-2022 走看看