这是你的课——你知道你把它放在哪里。
如果你不共享它,那么只需选择一个低于 0xBFFF 的 ID 并完成它。
如果您的类属于可以由多个应用程序共享的 DLL ......或者可以简单地由您无法控制的代码共享,因此无法为GlobalAddAtom()......记得取消注册热键GlobalDeleteAtom()后打电话)。
解释
可能值得花一点时间思考为什么有两个不同的 ID 范围,以及为什么 API 文档建议使用GlobalAddAtom()在后一个范围内获取共享 DLL 的 ID。让我们从参数的文档开始RegisterHotKey():
id
[in] 指定热键的标识符。如果 hWnd 参数为 NULL,则热键与当前线程相关联,而不是与特定窗口相关联。如果已存在具有相同 hWnd 和 id 参数的热键,请参阅备注了解所采取的操作。
由此,我们可以推测热键由两个潜在的信息对之一唯一标识:线程或窗口句柄,以及任意 16 位数字。如果你指定了一个窗口句柄 ( HWND),那么消息被发送到那个窗口;否则,它被发送到线程。
所以...如果您只为给定窗口注册一个热键,则 ID 并不重要1;没有其他人可以为该窗口注册热键,其他窗口的热键事件将发布到这些窗口。同样,如果您只为给定线程注册一个无窗口热键,您将只会收到该热键的消息。如果您控制应用程序的所有代码,则可以使用您想要分配的任何技术为您的热键选择您想要的任何 ID;没有其他人会踩到它们,因为您拥有所有能够踩到它们的代码!
但是,如果您正在编写一个可以被其他代码调用的通用例程怎么办?你不能可靠地选择一个常量 ID,因为调用者可能已经在使用该 ID,并且如果他们也使用相同的窗口或线程,你最终会重新定义他们的热键。或者如果(如您的情况)您不知道在运行时之前将注册多少个热键怎么办?
您需要一种方法来确保您在运行时选择的 ID 不会被其他人使用。这就是GlobalAddAtom()发挥作用的地方:您将一个字符串传递给它,它会为您提供一个保证对应于该字符串而不是其他字符串的 ID;这对于系统来说实际上是唯一的,除非其他人传递了相同的字符串——你可能会想出一个唯一的字符串;只需使用您的公司名称或社会安全号码,以及为您需要的每个新原子增加的前缀。或者,如果您真的很偏执,请使用 GUID。
真相背后的真相
顺便说一句,让我试着澄清一点困惑:Windows 实际上并不关心调用的代码RegisterHotKey()是否在 DLL 中。它不能。考虑以下例程:
void RegisterSuperHappyFunHotKey(HWND hWnd, int id,
unsigned int fsModifiers, unsigned int vk)
{
RegisterHotKey(hWnd, id, fsModifiers, vk);
}
这个例程除了将它的参数转发到 WinAPI 函数之外什么都不做,这些函数都不能识别调用模块。如果它存在于 DLL 中,则其行为与编译到应用程序本身中的行为相同。Windows 没有可靠的方法来判断调用的来源,并且热键本身与窗口和线程(或单独的线程)相关联,其中任何一个都可以由 DLL 中的代码控制。现在当然,您可以有自己的应用程序或库特定要求:如果您的 DLL 创建一个窗口并为其设置一个热键,那么您需要在销毁窗口时取消注册该热键。 ..但这是您自己的问题,请按照您认为合适的方式处理。
MSDN 指定这两个 ID 范围有一个很好的理由:鼓励您,DLL 作者,避免踩到应用程序作者使用的 ID。如果您是应用程序的作者,那么世界就是您的牡蛎- 您(在大多数情况下)控制在您的应用程序进程中加载和执行哪些代码,因此可以决定您使用哪些 ID,但您认为合适: 从 0 开始并为每个新的热键递增是完全可以接受的。但是,一旦您冒险进入 ID 的上限范围,您将不得不像使用GlobalAddAtom()DLL 一样使用 - 否则您将面临与从 DLL 加载的第三方代码以这种方式生成的 ID 发生冲突的风险。这是一种……某种社会契约。
概括:
“共享 DLL”位在这里是一个红鲱鱼;如果您可以知道应用程序注册的所有热键的 ID,那么只需选择一个低于 0xBFFF 的数字并使用它。如果你不能,因为你的代码将被多个调用者使用(就像你的那样......),那么使用GlobalAddAtom()并使用它来获取一个 ID。
推荐
出于这些原因,我建议你为你正在设计的类使用GlobalAddAtom(),只是因为这听起来好像你现在不知道你是否会将它构建到你自己设计的应用程序中(其中您控制正在使用的 ID)或由其他应用程序加载的 DLL(您不控制)。不用担心 -只要您遵守为 DLL 调用者制定的规则,您就不会因为伪装成 DLL 而违反合同。
1好的,因此您必须注意几个系统定义的热键 ID...