考虑 WM_SETTEXT 消息的实现,这个消息将lParam这个参数指向的字符串,设置为窗口的标题,我们可以在不同的进程中发送这个消息。那么这个消息如何实现呢? 考虑进程1中的字符串 LPCTSTR str = TEXT("Hello,World"),我们要把该字符串发送到进程2中该如何去做。我们知道每一个Win32进程都有其私有的进程地址空间,这些地址空间是虚拟的,所以同一个地址在不同的进程中起实际指向的物理内存是不同的,对于变量str,它实际是进程1中的一个虚拟地址,所以我们如果直接把该虚拟地址发送到进程2中,在进程2中通过该虚拟地址进行寻址,肯定不可能得进程1中字符串TEXT("Hello,World")所在的位置。所以我们不能直接传递地址。再考虑进程是由操作系统创建的,操作系统完成了进程的虚拟地址空间和物理地址空间之间的转换,所以系统对进程的信息了如指掌,我们可以将传递字符串的这个工作交给系统来做。我们将进程1中的字符串TEXT("Hello,World"),保存到系统的地址空间中,并给该字符串提供一个系统级别的索引(Index),这个索引使用整数来标示,从而在系统中建立起一个索引和字符串(也可以是其他复杂的数据结构)的映射表。 然后进程2使用这个索引在系统地址空间中获得这个字符串。这样就完成的字符串在不同的进程地址空间中的传递。 Windows操作系统确实提供了这么一个功能。其中我们提出的索引就是ATOM,那个映射表就是ATOM表。
2. what is atomtypedef unsigned short WORD; typedef WORD ATOM;ATOM类型实际就是一个2字节整数。
2.1 Atom表的分类:① Global Atom Table(全局原子表) 当一个进程将一个字符串保存到全局原子表中时,系统生成一个在系统范围内唯一的atom,来标示该字符串。在系统范围之内所有的进程都可以通过该atom(索引),来获得这个字符串。由于全局原子表,在系统范围内是唯一的,所以我们常常利用全局原子表来实现进程间数据的交换。② Local Atom Table(本地原子表) 本地原子表存在的意义。为了实现不同进程间数据的交换,我们使用全局原子表,那么我们为什么要在一个进程内使用原子表呢,或者说本地原子表存在的意义是什么? 答:An application requiring the same string in a number of structures can reduce memory usage by using a local atom table. Rather than copying the string into each structure, the application can place the string in the atom table and include the resulting atom in the structures. In this way, a string appears only once in memory but can be used many times in the application.
答:在许多结构中需要相同字符串的应用程序可以通过使用本地atom表来减少内存使用。应用程序不需要将字符串复制到每个结构中,而是可以将字符串放在atom表中,并将生成的原子包含在结构中。这样,字符串在内存中只出现一次,但在应用程序中可以多次使用
2.2 原子表的实现原子表内部使用hash table来实现的 Atom tables are implemented as hash tables. By default, a local atom table uses 37 buckets for its hash table. However, you can change the number of buckets used by calling the InitAtomTable function. If the application calls InitAtomTable, however, it must do so before calling any other atom-management functions.
原子表被实现为哈希表。默认情况下,本地atom表的哈希表使用37个存储桶。但是,可以通过调用InitAtomTable函数来更改使用的存储桶数。但是,如果应用程序调用InitAtomTable,那么它必须在调用任何其他atom管理函数之前调用InitAtomTable。
2.3 原子表的形式我们说的 atom(key) 就是原子表中item的索引,我们说 atom name(value) 就是该item所对应的值。 atom就是2个字节的整数,所以atom的取值范围是:0x0000 -- 0xFFFF atom的类型有两种:string atoms和integer atoms这两种不同的atom其可索引的 atom name,具有不同的特点。① string atoms (atom name(value) 是 string 类型的 atom(key)) 其中的,重要一点,atom name在atom table中执行搜索时是大小写不敏感的。② integer atoms (atom name(value) 是 integer 类型的 atom(key))
例如:桌面的窗口类的值是:"#32769" 对话框窗口类的值是:"#32770"
① 全局原子表的 CURD(Create Update Research Delete) GlobalAddAtom GlobalDeleteAtom GlobalFindAtom GlobalGetAtomName① 本地原子表的 CURD AddAtom DeleteAtom FindAtom GetAtomName
3. Win32 中窗口类结构和CreateWindow函数中的信息被保存进程地址空间还是系统地址空间?RegisterClass函数的声明如下: 这个函数返回的 ATOM 是全局原子表中的atom还是本地原子表中的atom? 应该是本地原子表中的atom,窗口类(WNDCLASS)这个结构是在本地原子表中保存着。因为只有本地需要他。
Windows操作系统支持三种类型的窗口类,System Classes, Application Global Classes, Application Local Classes。这三种窗口类的区别在与,不同类型的窗口类其有效作用域,以及何时被注册,何时被销毁都是不同的。
4.1 窗口类的类型① 系统窗口类(System Classes) 系统窗口类是由操作系统为我们注册的,大部分的系统窗口类被系统中的所有进程所共享。当一个进程中的线程第一次调用User或者GDI函数时系统就注册这些系统类。 可以被任何进程使用的系统窗口类: 只有系统可以使用的系统窗口类:
② Application Global Classes An application global class is a window class registered by an executable or DLL that is available to all other modules in the process. The .dll must register the class during its initialization procedure and must specify the CS_GLOBALCLASS style。 To remove an application global class and free the storage associated with it, use the UnregisterClass function. 如果我们在一个dll文件中创建一个窗口类,然后将其加载到exe文件中,在exe中创建该窗口类的是一个实例(CreateWindow),我们就必须在dll中的在指定WNDCLASS的窗口类风格是添加 CS_GLOBALCLASS 。 每一个窗口类都与一个Module相关联,模块的句柄和窗口类的名称共同表示了一种窗口类,模块的句柄和窗口类的名称相当于一个联合主键。所以在不同的模块中窗口类的命称可以相同。③ Application Local Classes The system destroys a local class when the module that registered it closes. An application can also use the UnregisterClass function to remove a local class and free the storage associated with it. 窗口类名是保存在系统私有的atom表中的。