找出哪个进程注册了全局热键? (Windows API)

据我所知,Windows不提供API函数来告诉哪个应用程序注册了一个全局热键(通过RegisterHotkey)。 我只能发现,如果RegisterHotkey返回false,而没有“拥有”热键,则注册一个热键。

在没有直接的API的情况下,会不会有一个迂回的方式? Windows维护与每个注册热键相关的句柄 – 有点让人发疯,因为应该没有办法获取这些信息。

可能不起作用的示例:发送(模拟)一个已注册的热键,然后截获Windows将发送到注册它的进程的热键消息。 首先,我不认为拦截消息会显示目标窗口句柄。 其次,即使有可能,这也是一件坏事,因为发送热键会触发各种程序的各种可能有害的活动。

这并不重要,但是我经常看到这样的function需求,而且我自己也是注册热键的应用程序的牺牲品,甚至没有在UI或文档中的任何地方透露它。

(在delphi工作,只不过是在WinAPI的学徒,请善待。)

你的问题激起了我的兴趣,所以我做了一些挖掘,而不幸的是,我没有给你一个正确的答案,我想我会分享我有什么。

我发现这个创build键盘钩子(在Delphi中)的例子是 1998年编写的,但是在Delphi 2007中编译并进行了一些调整。

这是一个调用SetWindowsHookEx的DLL,它通过一个callback函数,然后可以拦截关键笔划:在这种情况下,它是修补他们的乐趣,改变左侧的光标,等等。一个简单的应用程序然后调用DLL和报告支持基于TTimer事件的结果。 如果你有兴趣,我可以发布基于Delphi 2007的代码。

这是很好的文件和评论,你可能可以使用它作为一个关键的新闻发生的地方的基础。 如果你能得到发送击键的应用程序的句柄,你可以用这种方式追踪它。 有了这个手柄,你就可以很容易地获得你需要的信息。

其他应用程序试图通过快捷键来确定快捷键,因为它们可以包含快捷键,这只是快捷键的另一个术语。 但是大多数应用程序不倾向于设置这个属性,所以它可能不会返回太多。 如果你IShellLink条路线感兴趣,Delphi可以访问IShellLink COM接口,你可以使用它来加载一个快捷键并获得它的热键:

 uses ShlObj, ComObj, ShellAPI, ActiveX, CommCtrl; procedure GetShellLinkHotKey; var LinkFile : WideString; SL: IShellLink; PF: IPersistFile; HotKey : Word; HotKeyMod: Byte; HotKeyText : string; begin LinkFile := 'C:\Temp\Temp.lnk'; OleCheck(CoCreateInstance(CLSID_ShellLink, nil, CLSCTX_INPROC_SERVER, IShellLink, SL)); // The IShellLink implementer must also support the IPersistFile // interface. Get an interface pointer to it. PF := SL as IPersistFile; // Load file into IPersistFile object OleCheck(PF.Load(PWideChar(LinkFile), STGM_READ)); // Resolve the link by calling the Resolve interface function. OleCheck(SL.Resolve(0, SLR_ANY_MATCH or SLR_NO_UI)); // Get hotkey info OleCheck(SL.GetHotKey(HotKey)); // Extract the HotKey and Modifier properties. HotKeyText := ''; HotKeyMod := Hi(HotKey); if (HotKeyMod and HOTKEYF_ALT) = HOTKEYF_ALT then HotKeyText := 'ALT+'; if (HotKeyMod and HOTKEYF_CONTROL) = HOTKEYF_CONTROL then HotKeyText := HotKeyText + 'CTRL+'; if (HotKeyMod and HOTKEYF_SHIFT) = HOTKEYF_SHIFT then HotKeyText := HotKeyText + 'SHIFT+'; if (HotKeyMod and HOTKEYF_EXT) = HOTKEYF_EXT then HotKeyText := HotKeyText + 'Extended+'; HotKeyText := HotKeyText + Char(Lo(HotKey)); if (HotKeyText = '') or (HotKeyText = #0) then HotKeyText := 'None'; ShowMessage('Shortcut Key - ' + HotKeyText); end; 

如果您可以访问Safari Books Online ,在Steve Teixeira和Xavier Pacheco的Borland Delphi 6开发人员指南中有关于快捷方式/shell链接的很好的部分 。 我上面的例子是从那里和这个网站的屠杀版本。

希望有所帮助!

经过一番研究,看来你需要访问MS用来存储热键的内部结构。 ReactOS有一个clean room实现,通过迭代内部列表并提取与参数匹配的热键来实现GetHotKey调用。

取决于ReactOS的实现与MS实现的接近程度,你可以在内存中查找结构,但是这已经过去了。

 BOOL FASTCALL GetHotKey (UINT fsModifiers, UINT vk, struct _ETHREAD **Thread, HWND *hWnd, int *id) { PHOT_KEY_ITEM HotKeyItem; LIST_FOR_EACH(HotKeyItem, &gHotkeyList, HOT_KEY_ITEM, ListEntry) { if (HotKeyItem->fsModifiers == fsModifiers && HotKeyItem->vk == vk) { if (Thread != NULL) *Thread = HotKeyItem->Thread; if (hWnd != NULL) *hWnd = HotKeyItem->hWnd; if (id != NULL) *id = HotKeyItem->id; return TRUE; } } return FALSE; } 

我认为sysinternals上的这个线程是由与这个问题有关的人问的,但是我想我会链接到它以保持这两个在一起。 该线程看起来非常有趣,但是我怀疑需要进行一些深入探索,以便在不访问MS内部结构的情况下进行parsing。

closures我的头顶,你可能会尝试使用EnumWindows枚举所有窗口,然后在callback中,将WM_GETHOTKEY发送到每个窗口。

编辑:显然,我错了。 MSDN有更多的信息:

WM_HOTKEY与WM_GETHOTKEY和WM_SETHOTKEY热键无关。 WM_HOTKEY消息是为通用热键发送的,而WM_SETHOTKEY和WM_GETHOTKEY消息是与窗口激活热键相关的。

注意: 这是一个程序,声称有你正在寻找的function。 你可以尝试反编译它。

这似乎告诉你很多: http : //hkcmdr.anymania.com/help.html

一种可能的方法是使用Visual Studio工具Spy ++

试试这个:

  1. 运行该工具(对于我来说,它位于C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\spyxx_amd64.exe
  2. 在菜单栏中,selectSpy – > Log messages … (或者按Ctrl + M
  3. 附加Windows框架中检查系统中的所有窗口
  4. 切换到信息选项卡
  5. 点击全部清除button
  6. 在列表框中selectWM_HOTKEY ,或者select消息组中的 键盘 (如果你有更多潜在的噪音,那么确定)
  7. 点击确定button
  8. 按有问题的热键(例如Win + R
  9. Messages(All Windows)窗口中selectWM_HOTKEY行,右键单击,然后在上下文菜单中selectProperties …
  10. 在“ 消息属性”对话框中,单击“ 窗口句柄”链接(这将成为接收消息的窗口的句柄)
  11. 单击“ 窗口属性”对话框上的“ 同步”button。 这将显示主Spy ++窗口树视图中的窗口。
  12. 在“ 窗口属性”对话框中,select“ 处理”选项卡
  13. 点击进程ID链接。 这将告诉你的过程(在我的Win + R的情况下: EXPLORER

另一个线程提到了一个全局的NT级键盘钩子:

重新分配/覆盖热键(Win + L)locking窗口

也许你可以通过这种方式获得调用钩子的进程的句柄,然后你可以parsing为进程名称

(免责声明:我已经在我的书签中,没有真正尝试/testing过)

我知道你可以在你自己的进程中的任何窗口拦截消息stream – 我们用VB6调用子类。 (虽然我不记得函数,也许SetWindowLong?)我不确定你是否可以在你自己的进程之外的窗口中执行此操作。 但为了这个职位,让我们假设你find了一个方法来做到这一点。 然后,您可以简单地截取所有顶级窗口的消息,监视WM_HOTKEY消息。 你不能直接知道所有的键,但是当他们被按下时,你可以很容易地知道应用程序正在使用它们。 如果每次运行监视器应用程序时将结果保存到磁盘并重新加载,则可以随着时间的推移提高应用程序的性能。

这并不完全回答有关Windows API问题的部分,但它回答了有关全局热键列表和“拥有”它们的应用程序的问题。

http://hkcmdr.anymania.com/上的免费Hotkey Explorer显示了所有全局热键和拥有它们的应用程序的列表。 这只是帮助我找出为什么特定于应用程序的快捷键停止工作,以及如何解决它(通过重新configuration已注册的应用程序中注册的全局热键),在几秒钟内。

几年来,我一直都不是核心的Windows用户(我改用Mac)。 但我曾经发誓由Process Explorer找出正在使用我正试图删除的特定文件的进程。 也许它有助于找出哪个进程使用热键?