当前位置:C++技术网 > 资讯 > Windows零基础入门:4.2 获取窗口类信息之查询窗口类名称ID

Windows零基础入门:4.2 获取窗口类信息之查询窗口类名称ID

更新时间:2015-10-16 15:51:29浏览次数:1+次

    上一节课《Windows零基础入门:4.1 获取窗口类信息之查询窗口类函数详细介绍》,我们详细介绍了获取窗口类信息的函数的参数等知识。函数的使用很简单,关键是函数背后的技术知识背景,很少有人深入了解过。我们就对此做深入的探讨学习。
    在注册窗口类的时候,在窗口类结构体的成员lpszClassName填写的是窗口类的名称,就是一个字符串。通过这个窗口类名称字符串,我们就可以找到窗口类,进而可以使用窗口类名称来创建一个窗口。
    那么,在窗口类有效的范围内,窗口类名字是唯一的。只要我们用这个窗口类名称来创建窗口,总会创建出这个特定样式的窗口。
    然而窗口类信息注册好后,生成了一个ID,是一个数字,就像一个表格的序号一样的,这个ID的类型就是ATOM类型。我们现在来认识一下ATOM类型。
    ATOM英文是原子的意思,表示最小的意思。我们可以理解为这个类型是Windows中的基本类型,就好像C/C++中的int类型一样。我们看看ATOM类型最根本的数据类型是什么,从语言级别来看。
    在VS2015中,我们查看ATOM的定义,如下:


typedef WORD ATOM;//BUGBUG - might want to remove this from minwin
typedef unsigned short WORD;
    对于ATOM,没有找到直接的解释,但是我们通过在VS中查看定义,可以看到这个类型是这么定义的。ATOM时友WORD类型重定义的,而WORD是由unsigned short类型重定义的,所以根本上,ATOM就是unsigned short类型的。然而注释中却标注BUGBUG,并解释说可能将这个类型从minWin系统版本中移除。


    我们可以肯定的是,ATOM是一个整数,至于具体多少位,是哪一种整型类型,我们就不细究了。也没有必要,因为从注释可以看出,这个类型可能会变化,但是一定会是整型类型。知道这些我们就够了。
    这个ATOM类型出现在注册窗口类函数中,是注册窗口类函数的返回值类型。如果注册失败,则返回0,注册成功,则返回一个窗口类的唯一ID。可以说,这个ID和注册的窗口类是一一对应的。
    那么返回的这个ATOM值可以在以下这些函数中使用:
CreateWindow,CreateWindowEx,GetClassInfo,GetClassInfoEx, FindWindow, FindWindowEx,UnregisterClass 和 IActiveIMMap::FilterClientWindows方法中。
    使用的地方,其实都是和窗口窗口类有关,而窗口类也就是用于这些地方。因为注册窗口类返回的ATOM值就代表关联了唯一的窗口类信息,可以说,就是注册窗口类后再窗口类信息列表中的一个索引值(序号)。
    好了,我们现在知道这个类型的知识背景了。那么我们来继续看看这个类型是怎么使用在这些函数的呢?
    我们就以CreateWindow函数举例说明。在CreateWindow函数中的第一个参数,就是要传入的窗口类的名称。而CreateWindow函数第一个参数只能是LPCTSTR,即字符串指针类型,那么我们如何来使用这个整型的值呢?
    Windows中提供了一个宏,会将一个资源整型值转换为对应的字符串类型,这样就可以传入CreateWindow函数了。这个宏为MAKEINTRESOURCE。看着大写不直观,我们写成正常的单词来看,在代码中必须全部大写哦。MakeIntResource,意思是,是一个整型的ID转换成资源的字符串ID。其实就是做一个对应的转换。

    我们来看一下MAKEINTRESOURCE定义:


#define MAKEINTRESOURCEA(i) ((LPSTR)((ULONG_PTR)((WORD)(i))))
#define MAKEINTRESOURCEW(i) ((LPWSTR)((ULONG_PTR)((WORD)(i))))
#ifdef UNICODE
#define MAKEINTRESOURCE  MAKEINTRESOURCEW
#else
#define MAKEINTRESOURCE  MAKEINTRESOURCEA
#endif // !UNICODE
    它也是和其他Windows函数一样有两个版本,一个Unicode版本和ANSI版本。从声明的类型中可以看到,最后一个i表示传入的参数,被强转为WORD类型,然后再转成ULONG_PTR,然后再转成了字符串类型返回。


    从这类可以看出,ATOM的类型实际上就是对应的字符串类型的低一个WORD,高一个WORD为0.这个在MSDN解释了。然后我们看ULONG_PTR类型:
typedef _W64 unsigned long ULONG_PTR;
    它也是一个整型类型,不过会根据系统的版本来决定具体的长度。我们可以看到,从转到WORD,再到ULONG_PTR类型,实际上就是做一个数据位数的处理,然后到LPWSTR或者LPSTR,则从整型类型变成了字符指针类型。而在这个过程中,就将一个整型的资源ID变成了字符串指针类型。
    前面我们说了,这个窗口类名称是唯一的,这里我们又可以从ATOM类型的转换,看到了ATOM值就是取了窗口类名称的低WORD长度的值变成整数作为ATOM,这个就是窗口类的整型ID了。

    而从WORD长度的ATOM值到字符串地址的转换,我们可以看到,ATOM其实就是窗口类名称字符串的地址了。而这个地址通过WORD类型这个长度就可以找到了。如下图所示:

    窗口类信息表示意图

    所以,ATOM本身的类型是WORD整型类型,而在窗口类资源这里代表的是窗口类名称字符串存储位置的地址。而这个转换其实就是基于这个原理转换的。
    所以,我们可以这么使用ATOM类型的窗口类ID,来创建窗口,代码如下:
CreateWindow(MAKEINTRESOURCE(atomCls), L"主窗口_C++技术网", WS_OVERLAPPEDWINDOW , 100, 100, 600, 600, NULL, NULL, hInstance, NULL);
    而我们要使用GetClassLong来获取窗口类,就是获取窗口类的ATOM类型的ID。那么如果使用获取到的窗口类ID,上面已经讲过了。获取ATOM类型的窗口类ID代码如下:
WORD wClsID = (WORD)GetClassLong(hwnd,GCW_ATOM);
    因为ATOM是WORD类型的,返回的是DWORD类型,所以类型转换,不过默认复制,也是会默认转换的。

    ATOM类型的窗口类ID就对应的注册窗口类的窗口类名称,窗口类结构体中的每一个成员都可以获取和修改。因为ATOM是大家所不熟悉的,前面也没有介绍,这里就花了很大的篇幅来详细介绍了。同时也详细介绍了INT资源ID转换宏MAKEINTRESOURCE的定义和使用方法。

    如果你有任何问题,请留言。鉴于本人水平有限,如果发现问题,请指出,共同学习。