当前位置:首页 > Windows程序 > 正文

深入Windows句柄本质

2021-03-29 Windows程序

3. https://msdn.microsoft.com/en-us/library/windows/desktop/aa383681%28v=vs.85%29.aspx

微软官网中关于STRICT的内容

4.?url=j0ubLizIjhgmxthACfwBa4IpXrdqyyFg84a9MPmwusN4XhalR94kVaDAeR6GlFCMVD_AQORTLyfEC84-tqUWo27dziBXKjNdAqXe8Ich0eu

C语言宏中"#"和"##"的用法

5.

typedef和#define的用法与区别

6.

void及void指针含义的深刻解析

写在前面:

本文是对在下上一篇文章《图解说明——究竟什么是Windows句柄》的扩充。同样地,本文依然是面向初学者的。让编程语言变得平易,让初学者学起来你更加舒服,在交流中与广大读者同勉共进,是在下的一贯宗旨和追求。所以,在对源码的解释中,在下会尽可能做到详细,具体到句,对于与句柄不是特别相关的内容,也会加以解释说明。和上一篇一样,我们仍然把窗口、位图、画笔等统称为对象。

还有一点必须要交代,在下对Windows句柄这一细节的研究,还存在一些疑问,这将在文末进一步说明。

先看winnt.h中关于HANDLE(句柄)的定义:

typedef void *PVOID;

#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

以上代码typedef void *PVOID;来自winnt.h(参考资料2)中的第178行,其余代码来自winnt.h中的第285~293行,考虑到易读性,在下对代码格式稍稍做了调整。

在分析源代码之前,再说一点,那就是typedef和#define的区别的问题。typedef用来定义一个标识符及关键字的别名,而#define是宏定义,简单说,就是字符串替换。如果有读者还不是很明白,可以参阅参考资料5。在下面的叙述中,我们将两者都译为“定义”。因为在下觉得这样可以带来叙述上的方便,并且如果大家理解了typedef和#define的区别,这样做并不会造成理解上的误会。

下面我们开始逐句分析代码。

首先,typedef void *PVOID;,这里将PVOID定义为void*型,以后,PVOID a,b;就相当于void *a,*b;(注意不是void *a,b;)。这里再简单说一下void*,简单说,void *就是“无类型指针”,可以指向任何数据类型,详情可参阅参考资料6。

下面的一段总体上是if——else结构。我们先看if部分。

#ifdef STRICT

如果定义了STRICT,就执行后面的代码。关于STRICT,在后面我们还会进行详细的讲解,这里我们暂时将其跳过,先看条件成立时的代码。

#define DECLARE_HANDLE(name) struct name##__ {

int unused;

};

这里是一个带参数的宏定义,name是参数,##为粘贴符号,,表示把左右两边的内容连接起来。关于带参数的宏定义和##,读者可以参阅参考资料4。

这里将结构体

struct name##__

{

int unused;

};

定义为

DECLARE_HANDLE(name)。

接下来,

typedef struct name##__ *name

定义一个指针name,指向上面的结构体name##__。

下面我们以窗口句柄HWND为例,进一步说明。

在windef.h头文件(见参考资料1)的第196行有代码

DECLARE_HANDLE            (HWND);

我们将宏展开,就是

struct HWND__

{

int unused;

};

同样,根据typedef struct name##__ *name

有typedef struct HWND__ *HWND。

即句柄HWND是一个指针,指向结构体struct HWND__。

其它句柄的定义与HWND类似,这里不再赘述,读者可以参阅参考资料1中从195行往后的代码。

注意这里我们忽略了一个细节,那就是结构体中的int unused。关于这一点,我们先暂时忽略,在后面的“尚未解决”板块,在下将对这一问题作出交代。

有了前边的经验,分析else部分的代码就变得容易了,让我们一起来看。

typedef PVOID HANDLE;

由于前边有typedef void *PVOID;,所以这里HANDLE被定义为void*型。

接着,

#define DECLARE_HANDLE(name) typedef HANDLE name

这里将

typedef HANDLE name

定义为

DECLARE_HANDLE(name)。

还以HWND为例,在这种情况下,

DECLARE_HANDLE            (HWND);

宏展开为

typedef HANDLE HWND,

即此时HWND为void*型。

好了,说完这些,我们着重说一下STRICT。相关内容请参阅参考资料3。

在windef.h头文件的第13~17行定义了STRICT,源代码如下:

#ifndef NO_STRICT

#ifndef STRICT

#define STRICT 1

#endif

#endif /* NO_STRICT */

这里仅仅是将STRICT定义为数值1,看不出什么名堂。关键在于编译器(注意不是系统)对STRICT的“解释”。

温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/69625.html