这是你的类 - 你知道你要把它放在哪里。
如果你不需要共享它,那么只需选择一个小于0xBFFF的ID即可。
如果你的类属于可以被多个应用程序共享的DLL... 或者仅仅可以被你无法控制并且因此无法为其排序ID的代码共享... 那么使用GlobalAddAtom()
来获取一个ID(记得在注销热键之后调用GlobalDeleteAtom()
)。
说明
也许值得花一分钟时间思考为什么有两个不同的ID范围,以及为什么API文档建议在共享DLL中使用GlobalAddAtom()
获取后者范围内的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的上限范围,你将不得不像DLL一样使用GlobalAddAtom()
- 否则你将有可能与从DLL加载的第三方代码以这种方式生成的ID发生冲突。这是某种社会契约。
摘要:
"共享DLL"这一点在这里是一个转移话题;如果你能知道应用程序注册的所有热键的ID,那么只需选择一个小于0xBFFF的数字并使用它即可。如果你不能,因为你的代码将被多个调用者使用(就像你的代码一样...),那么使用GlobalAddAtom()
获取一个ID并使用它。
建议
出于以下原因,我建议您在设计类时使用GlobalAddAtom()
,因为目前看来您不知道它是否将被构建到自己设计的应用程序中(在这种情况下,您可以控制使用的ID),还是被其他应用程序加载的DLL(在这种情况下,您不能)。不要担心-只要遵循为DLL调用者设置的规则,您就不会违反合同而假装成DLL。
1好的,所以有一些系统定义的热键ID需要注意...
GlobalAddAtom()
。从来没有一个场景可以让你在运行时决定使用哪个ID范围;如果你无法提前决定,你将始终使用高范围(和GlobalAddAtom())。 - Shog9GlobalAddAtom()
。但如果是你的应用程序,你知道哪些低范围内的ID可用,可以直接从其中选择,而不一定非要使用GlobalAddAtom()
。MSDN的意思是,“如果你不是该应用程序,请勿覆盖为该应用程序保留的ID”,并建议使用GlobalAddAtom()
作为可靠的选择ID的方法,以避免与其他应用程序冲突。如果无法保证你的代码不会被使用其他选择ID的应用程序使用,则使用GlobalAddAtom()
来选择它们。 - Shog9WM_APP
到0xBFFF。否则,您可以使用RegisterWindowMessage()
从字符串生成0xC000到0xFFFF范围内的ID。如果这些范围看起来很熟悉,那是因为RegisterWindowMessage()
在幕后只是调用GlobalAddAtom()
...;-) - Shog9