65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 CHandleX 进行句柄处理

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.50/5 (4投票s)

2003年6月15日

2分钟阅读

viewsIcon

49920

downloadIcon

411

句柄处理——另一种方式

引言

你了解孤立句柄的问题吗? CHandleX 是一个通用的句柄类,可以帮助你处理句柄。

背景

ATL 已经包含一个句柄类 (CHandle)。 但这个类总是使用 CloseHandle() 来关闭句柄。 CHandleX 允许调用者指定应该使用哪个关闭句柄函数。

使用代码

使用这段代码非常简单。 构造函数接受 2 个参数

class CHandleX
{
public:
    inline CHandleX(void* pCloseHandleFunction = CloseHandle, 
                    UINT iCallType = CHandleX::CALL_TYPE_WINAPI);
};

第一个参数是指向 CloseHandle 函数的指针,第二个是调用类型。 默认参数是 CloseHandleCHandleX::CALL_TYPE_WINAPI

iCallType 取决于关闭句柄函数。 有效参数是

  • CHandleX::CALL_TYPE_WINAPI // (__stdcall)

  • CHandleX::CALL_TYPE_CDECL // (__cdecl)

  • CHandleX::CALL_TYPE_FASTCALL // (__fastcall)

大多数 WINAPI 调用使用 __stdcall。 在这种情况下,你不需要指定 CHandleX::CALL_TYPE_WINAPI,因为它默认值就是它。

重要提示

如果你为 "iCallType" 声明了错误的调用类型,Visual Studio 的标准调试器将无法检测到这一点。 你需要第三方工具来检测这一点。 例如,DevPartner。

假设关闭句柄函数总是如下所示

int CloseHandleFunction(void *pHandle).

示例

以下示例演示了如何使用 CHandleX 类。

//
// Normal Handle Sample
//
void Sample1()
{
    //normal handle -> uses CloseHandle()
    CHandleX hDrive;

    hDrive = CreateFile(L"\\\\.\\PhysicalDrive0",
                        0,
                        FILE_SHARE_READ | FILE_SHARE_WRITE,
                        NULL,
                        OPEN_EXISTING,
                        0,
                        NULL
                );
    // .
    // .
    // .
    // here, the destructor of hDrive (CHandleX) will use 
    // CloseHandle() to free up the handle
}

// Service Handle Sample
//
bool Sample2()
{
    // hScm will use CloseServiceHandle() to close the handle
    CHandleX hSCM(CloseServiceHandle, 0);

    hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

    if (!hSCM.IsValid())
        return false;

    // .
    // .
    // .
    return true;
}
// here, the destructor of hSCM (CHandleX) will use CloseServiceHandle() 
// to free up the handle

//
// Bitmap Handle Sample
//
void Sample3()
{
    // hScm will use DeleteObject() to close the handle
    CHandleX hBitmap(DeleteObject);

    hBitmap = ::CreateBitmap(100, 100, 1,8, NULL);
    // .
    // .
    // .
}

// here, the destructor of hBitmap (CHandleX) will use DeleteObject() 
// to free up the handle

int main()
{
    Sample1();    //normal file handle
    Sample2();    //service handle
    Sample3();    //bitmap handle

    return 0;
}

还有很多可能性。 HANDLE 被定义为 void*

此外,可以使用以下函数管理内存块:free()LocalFree() 等。

// Memory Buffer Sample using malloc/free (__cdecl)
//
void Sample4()
{
    CHandleX hBuffer(free , CHandleX::CALL_TYPE_CDECL); //free uses __cdecl

    hBuffer = malloc(1024);
}

// Memory Buffer Sample using LocalAlloc/LocalFree
//
void Sample5()
{
    CHandleX hBuffer(LocalFree);

    hBuffer = LocalAlloc(LMEM_ZEROINIT, 1024);
}

//
// Main
//
int main()
{
    Sample4();	//memory buffer with __cdecl
    Sample5();	//memory buffer
    return 0;
}          

CHandleX 类的代码

CHandleX 类的整个代码非常简单
#pragma once

#include <stdexcept>

#ifdef __NEVER_DEFINED_00FFAAD3_C204_4c95_8607_4E7D9CD05C0F__
    #ifndef START_HIDE
        #define START_HIDE {
    #endif
    #ifndef END_HIDE
        #define END_HIDE }
    #endif
#else
    #ifndef START_HIDE
        #define START_HIDE
    #endif
    #ifndef END_HIDE
        #define END_HIDE
    #endif
#endif

START_HIDE
typedef BOOL (__stdcall *LPFN_WINAPI_HANDLE_CLOSE_FUNCTION)(void*);
typedef BOOL (__cdecl *LPFN_CDELC_HANDLE_CLOSE_FUNCTION)(void*);
typedef BOOL (__fastcall *LPFN_FASTCALL_HANDLE_CLOSE_FUNCTION)(void*);
END_HIDE

class CHandleX
{
public: //static CALL type constants
    static const UINT CALL_TYPE_WINAPI   = 1;
    static const UINT CALL_TYPE_CDECL    = 2;
    static const UINT CALL_TYPE_FASTCALL = 3;

public:
    inline CHandleX(void* pCloseHandleFunction = CloseHandle, 
                    UINT iCallType = CHandleX::CALL_TYPE_WINAPI)
    {
        m_bAttached    = false;
        m_hHandle = NULL;
        this->SetCloseHandleFunction(pCloseHandleFunction, iCallType);
    }

    inline ~CHandleX()
    {
        if (this->IsValid())
        {
            switch (m_iCallType)
            {
            case CALL_TYPE_WINAPI:
                ((LPFN_WINAPI_HANDLE_CLOSE_FUNCTION) m_pCloseHandleFunction)
                    (m_hHandle);
                break;

            case CALL_TYPE_CDECL:
                ((LPFN_CDELC_HANDLE_CLOSE_FUNCTION) m_pCloseHandleFunction)
                    (m_hHandle);
                break;

            case CALL_TYPE_FASTCALL:
                ((LPFN_FASTCALL_HANDLE_CLOSE_FUNCTION)m_pCloseHandleFunction)
                    (m_hHandle);
                break;

            default:
                break;
            }
        }
    }

    inline void operator=(HANDLE hHandle)
    {
        m_bAttached = true;
        m_hHandle = hHandle;
    }

    inline void Attach(HANDLE hHandle)
    {
        if (hHandle==NULL || hHandle==INVALID_HANDLE_VALUE)
        {
            m_bAttached = false;
            m_hHandle = NULL;
            return;
        }

        m_bAttached = true;
        m_hHandle = hHandle;
    }

    inline void Detach()
    {
        m_bAttached = false;
        m_hHandle = NULL;
    }

    inline operator HANDLE() const
    {
        return m_hHandle;
    }

    inline HANDLE GetHandle()
    {
        return m_hHandle;
    }

    inline bool IsValid()
    {
        if (m_bAttached == false)
            return false;

        if (m_hHandle == NULL || m_hHandle == INVALID_HANDLE_VALUE)
            return false;

        return true;
    }

    inline void SetCloseHandleFunction(
                    void* pCloseHandleFunction=CloseHandle,
                    UINT iCallType = CHandleX::CALL_TYPE_WINAPI)
    {
        m_iCallType    = iCallType;
        m_pCloseHandleFunction = pCloseHandleFunction;

        if (pCloseHandleFunction == NULL)
        {
            RaiseException(ERROR_INVALID_DATA, EXCEPTION_NONCONTINUABLE, 0, 
                           NULL);
            return;
        }

        switch (m_iCallType)
        {
        case CALL_TYPE_WINAPI:
        case CALL_TYPE_CDECL:
        case CALL_TYPE_FASTCALL:
            break;

        default:
            RaiseException(ERROR_INVALID_DATA, EXCEPTION_NONCONTINUABLE, 0, 
                           NULL);
            break;
        }
    }

    START_HIDE
private:
    void *m_pCloseHandleFunction;
    HANDLE m_hHandle;
    bool m_bAttached;
    UINT m_iCallType;
    END_HIDE
};

重要说明

CHandleX 非常通用,但绝不用于
  • 封装 new/delete
  • 封装类/结构体

其他处理句柄的方法

CHandleX 的缺点是它不是类型安全的。 另一种方法是使用宏自动生成类。 这将是类型安全的,但会使其更加复杂。

历史

  • 2002年6月10日,初始版本 1.0
  • 2002年6月13日,更新版本 1.0 至 1.1(文档 - 添加了 LocalAlloc/malloc 的示例)
© . All rights reserved.