Visual C++ 7.1Visual C++ 7.0Visual Studio .NET 2003Windows 2003Windows 2000Visual C++ 6.0Windows XP中级开发Visual StudioWindowsC++
使用 CHandleX 进行句柄处理






3.50/5 (4投票s)
2003年6月15日
2分钟阅读

49920

411
句柄处理——
引言
你了解孤立句柄的问题吗? CHandleX
是一个通用的句柄类,可以帮助你处理句柄。
背景
ATL 已经包含一个句柄类 (CHandle
)。 但这个类总是使用 CloseHandle()
来关闭句柄。 CHandleX
允许调用者指定应该使用哪个关闭句柄函数。
使用代码
使用这段代码非常简单。 构造函数接受 2 个参数
class CHandleX
{
public:
inline CHandleX(void* pCloseHandleFunction = CloseHandle,
UINT iCallType = CHandleX::CALL_TYPE_WINAPI);
};
第一个参数是指向 CloseHandle
函数的指针,第二个是调用类型。 默认参数是 CloseHandle
和 CHandleX::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 的示例)