在Visual C++头文件中有关句柄的定义如下:
#ifdef STRICT
typedef void *HANDLE;
#define DECLARE_HANDLE(name) struct name##__ { int unused; };
typedef struct name##__ *name
#else
typedef PVOID HANDLE;
#define DECLARE_HANDLE(name) typedef HANDLE name
#endif
在afxv_w32.h中有如下语句:
#ifndef STRICT
#define STRICT 1
#endif
因此,通常情况下,句柄的定义应该是:
typedef void *HANDLE;
#define DECLARE_HANDLE(name) struct name##__ { int unused; };
typedef struct name##__ *name
定义中包含了两种句柄的定义,一种是定义为void *的句柄HANDLE,另一种是定义为name##__ *的句柄name。
可以发现返回HANDLE句柄的多是创建内核对象的函数,例如,CreateThread,CreateFile,CreateFileMapping,CreateSemaphore,因此依个人理解,HANDLE句柄是用来指向内核对象的指针。之所以定义成void型,估计是微软不想让人知道内核对象的真实内容。句柄指向内存中的内核对象,这个内核对象包含很多字段,其中有一个字段保存了真正要使用的对象的地址,其他字段还保存了对象的统计信息。
举例来说,当我们调用CreateThread时,创建了一个线程内核对象,并返回了一个线程句柄,这个句柄实际上指向了这个线程内核对象,而这个线程内核对象中包含了实际线程的许多信息,是用来管理线程的数据结构而已。当我们想访问这个线程时,只需要传递线程的句柄就可以,Windows知道该如何去解析。
另一种定义应该是用户对象句柄的定义,查看Visual C++源代码可以看到:
DECLARE_HANDLE(HDC);
DECLARE_HANDLE(HICON);
DECLARE_HANDLE(HMENU);
DECLARE_HANDLE(HMETAFILE);
DECLARE_HANDLE(HINSTANCE);
DECLARE_HANDLE(HPALETTE);
DECLARE_HANDLE(HPEN);
DECLARE_HANDLE(HRGN);
以DECLARE_HANDLE(HDC)为例来说,将宏展开可以得到如下的定义:
struct HDC__ { int unused; };
typedef struct HDC_ *HDC;
可以知道,HDC实际上是一个指向HDC_结构的指针,HDC_结构包含了一个整型变量,这个整型变量的值标识了一个要使用的对象。