原子
原子表是一个系统定义的用于存放字符串和相应的标识符的表。程序把一个字符串放入原子表,获得一个相应的16位整数,这个整数就叫原子,可以用来访问该字符串。一个被放进原子表的字符串叫做原子名称。

★原子表

系统提供了许多原子表。每个表有不同的目的。比如,DDE应用程序使用全局原子表来与其它应用程序共享item-name和topic-name字符串。它传递全局原子,而非实际的字符串,到对端的应用程序中。对端应用程序使用原子来从原子表里获得字符串。
应用程序可以使用本地原子表来存储它们自己的item-name关联。
系统使用的原子表不会被应用程序直接访问,然而,程序可以调用一系列的函数来使用原子。比如,注册的剪贴板格式保存在一个系统内部的原子表中。应用程序通过RegisterClipboardFormat函数来把原子加入到该原子表。同样,注册了的类也保存在一个系统内部原子表里。应用程序通过RegisterClass/RegisterClassEx函数来添加原子到该原子表。

★全局原子表

全局原子表可供所有应用程序使用。当一个应用程序在全局原子表中放入一个字符串,系统将产生一个系统全局唯一的原子。任何拥有该原子的应用程序都可以通过查询全局原子表来获取它所标识的字符串。
应用程序在定义了用于与其他程序共享数据的私有DDE数据格式之后,应该将该格式的名称放入全局原子表。这项技术防止格式名称与系统及其他应用程序定义的格式名称冲突,使格式消息的标识符(原子)对其他应用程序可用。

★本地原子表

应用程序可以使用本地原子表来有效地管理大量只用于程序内部的字符串。这些字符串,以及相关联的原子,只对创建该原子表的应用程序可用。
一个在许多数据结构中需要相同字符串的应用程序,可以通过使用本地原子表来减少内存使用。程序可以把字符串放入原子表,把相关的原子放入结构,而无需把字符串拷到每个结构中。这样,一个字符串在内存中只出现一次,但可以在程序中多次使用。
应用程序也可以使用本地原子表来快速搜索特定的字符串。要实现这样的搜索,程序只需把要搜索的字符串放入原子表中,然后把结果原子与相关数据结构中的原子相比较。通常情况下,比较原子要比比较字符串要快得多。
原子表是用哈希表实现的。默认时,一个本地原子表使用37个bucket的哈希表。不过,你可以通过调用InitAtomTable函数来改变桶数。如果程序准备调用InitAtomTable,那它必须在调用任何其他原子管理函数前调用它。

★原子的类型

应用程序可以创建两种类型的原子:字符串原子和整数原子。整数原子与字符串原子的值不会重叠,因此两种类型的原子可以用于同一段代码。
有一些接受字符串或原子作为参数的函数。当传递原子到这些函数时,应用程序可以使用宏MAKEINTATOM来把原子转换为可供函数使用的形式。

★字符串原子

当应用程序传递'\0'结尾的字符串到GlobalAddAtom, AddAtom, GlobalFindAtom,以及FindAtom函数时,他们收到字符串原子(16位整数)返回值。字符串原子有下列属性:
·取值范围介于0xC000(MAXINTATOM)到0xFFFF。
·在原子表中搜索原子名称时大小写不敏感。同时,执行的是整个字符串匹配,而非子字符串匹配。
·与字符串原子相关联的字符串大小不能超过255个字节。这个限制适用于所有的原子函数。
·每个原子名称都有相关联的引用计数。这个计数在原子名称被加入表中时增加,在从表中删除时减少。从而防止使用同一原子名称的不同用户销毁彼此的原子名称。当引用计数为零时,系统把原子和原子名称从表中移除。

★整数原子

整数原子在几个方面与字符串原子不同,如下所示:
·整数原子的取值范围介于0x0001到0xBFFF(MAXINTATOM-1)。
·整数原子的字符串表示为#dddd,其中dddd是十进制的数字(数字前的0将被忽略)
·整数原子没有引用计数或存储开支。

★原子的创建与使用计数

应用程序通过调用AddAtom函数来创建本地原子;通过调用GlobalAddAtom函数来创建全局原子。两者都要求一个字符串指针。系统在相应的原子表中搜索该字符串,然后返回相应的原子。在字符串原子的情况下,如果字符串已经存在于原子表中,则系统加大该字符串的引用计数。
重复添加相同的原子名称将返回同一个原子。如果该原子名称不存在,则将原子名称添加到表中后返回新添加的原子。如果是字符串原子,还会将引用计数被设为1。
应用程序应该在不再需要一个本地原子时调用DeleteAtom函数;在不再需要一个全局原子时调用GlobalDeleteAtom函数。在字符串原子的情况下,这些函数都将把相应原子的引用计数减1。当引用计数为0时,系统把该原子名称从表中删除。
只要全局字符串原子的引用计数大于0,其原子名称将保留在全局原子表中,即使把它放入表中的应用程序终结了。一个本地的原子表在应用程序终结时被销毁,而不管其中原子的引用计数是多少。

★原子表查询

应用程序可以通过FindAtom或GlobalFindAtom函数来查询一个特定的字符串是否已经在原子表中。这些函数在原子表中搜索该字符串,如果找到,就返回其相应的原子。
应用程序可以用GetAtomName或GlobalGetAtomName函数来从原子表中获得原子名称。这些函数在原子表中搜索指定的字符串,如果找到,返回相应的原子。
应用程序可以使用GetAtomName和GlobalGetAtomName函数来从原子表中获取原子名称,如果应用程序拥有与之对应的原子值。两个函数都把指定原子的名称字符串拷贝到缓冲区中,然后返回该字符串的长度。
GetAtomName从本地原子表中获取原子名称字符串,GlobalGetAtomName从全局原子表中获取原子名称字符串。

★原子字符串格式

AddAtom, GlobalAddAtom, FindAtom 和 GlobalFindAtom函数用一个'\0'结尾的字符串指针作参数。应用程序可以用下面的方式指定:
·#dddd 十进制整数字符串,用于创建或查询一个整数原子。
·字符串原子名称 用于添加把字符串原子名添加到原子表或接收返回的原子。

★使用原子

原子最典型的用法是在DDE应用程序中。在DDE协议中,应用程序使用全局原子来标识交换数据的应用程序,正在交换的数据的状态,以及正在交换的实际数据。

★API函数说明

☆AddAtom

ATOM AddAtom(
  LPCTSTR lpString   // string to add
);

返回0表示失败

☆DeleteAtom

ATOM DeleteAtom(
  ATOM nAtom   // atom to delete
);

函数对整数原子无效。
返回0表示失败

☆FindAtom

ATOM FindAtom(
  LPCTSTR lpString   // string to find
);

☆GetAtomName

UINT GetAtomName(
  ATOM nAtom,       // atom identifying character string
  LPTSTR lpBuffer,  // buffer for atom string
  int nSize         // size of buffer
);

☆GlobalAddAtom

ATOM GlobalAddAtom(
  LPCTSTR lpString   // string to add
);

☆GlobalDeleteAtom

ATOM GlobalDeleteAtom(
  ATOM nAtom   // atom to delete
);

☆GlobalFindAtom

ATOM GlobalFindAtom(
  LPCTSTR lpString   // string to find
);

☆GlobalGetAtomName

UINT GlobalGetAtomName(
  ATOM nAtom,       // atom identifier
  LPTSTR lpBuffer,  // buffer for atom string
  int nSize         // size of buffer
);

☆InitAtomTable

BOOL InitAtomTable(
  DWORD nSize   // size of atom table
);

调用成功则返回True(如果已Init过,仍返回成功)。

☆MAKEINTATOM

LPTSTR MAKEINTATOM(
  WORD wInteger  // integer to make into atom
);

转换指定的原子到字符串,以便使之可以传入接收原子或字符串的函数(尽管返回值为LPTSTR,但只应在与原子相关的函数中使用)。