programing tip

어떤 프로세스가 글로벌 핫키를 등록했는지 알아보세요?

itbloger 2020. 8. 14. 07:30
반응형

어떤 프로세스가 글로벌 핫키를 등록했는지 알아보세요? (Windows API)


내가 알 수있는 한, Windows는 (RegisterHotkey를 통해) 전역 단축키를 등록한 응용 프로그램을 알려주는 API 기능을 제공하지 않습니다. RegisterHotkey가 false를 반환하는 경우에만 핫키가 등록되었음을 알 수 있지만 누가 핫키를 "소유"하는지 알 수 없습니다.

직접 API가없는 경우 원형 교차로가있을 수 있습니까? Windows는 등록 된 각 핫키와 관련된 핸들을 유지합니다.이 정보를 얻을 수있는 방법이 없어야한다는 것은 다소 놀랍습니다.

작동하지 않을 가능성이있는 예 : 등록 된 핫키를 전송 (시뮬레이션) 한 다음 Windows가이를 등록한 프로세스로 보낼 핫키 메시지를 가로 채십시오. 첫째, 메시지를 가로 채면 대상 창 핸들이 드러나지 않는다고 생각합니다. 둘째, 가능하더라도 핫키를 보내는 것은 다양한 프로그램에서 잠재적으로 원치 않는 모든 종류의 활동을 유발하기 때문에 나쁜 일입니다.

중요한 것은 아니지만 이러한 기능에 대한 요청을 자주 보았으며 UI 또는 문서의 어디에도 공개하지 않고 단축키를 등록하는 애플리케이션의 희생양이되었습니다.

(Delphi에서 일하고 WinAPI의 견습생 이상은 친절하십시오.)


귀하의 질문이 내 관심을 불러 일으켰 기 때문에 나는 약간의 파고를했으며 불행히도 적절한 대답이 없지만 내가 가진 것을 공유 할 것이라고 생각했습니다.

1998 년에 작성된 키보드 후크 (Delphi에서)를 만드는예제를 찾았 지만 Delphi 2007에서 몇 가지 조정을 통해 컴파일 할 수 있습니다.

SetWindowsHookEx콜백 함수를 통해 전달 되는 호출이있는 DLL로, 키 입력을 가로 챌 수 있습니다.이 경우 재미를 위해 조작하고 왼쪽 커서를 오른쪽으로 변경하는 등의 작업을 수행합니다. 그런 다음 간단한 앱이 DLL을 호출하고 다시보고합니다. TTimer 이벤트를 기반으로 한 결과. 관심이 있으시면 Delphi 2007 기반 코드를 게시 할 수 있습니다.

잘 문서화되고 주석이 달렸으며 잠재적으로 키 누름이 진행되는 위치를 파악하는 기초로 사용할 수 있습니다. 키 입력을 보낸 응용 프로그램의 핸들을 가져올 수 있다면 그 방법으로 추적 할 수 있습니다. 이 핸들을 사용하면 필요한 정보를 아주 쉽게 얻을 수 있습니다.

다른 앱은 단축키의 또 다른 용어 인 단축키를 포함 할 수 있기 때문에 단축키를 통해 단축키를 결정하려고 시도했습니다. 그러나 대부분의 응용 프로그램은이 속성을 설정하지 않으므로 많이 반환하지 않을 수 있습니다. 해당 경로에 관심이 있다면 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;

If you've got access to Safari Books Online, there is a good section about working with shortcuts / shell links in the Borland Delphi 6 Developer's Guide by Steve Teixeira and Xavier Pacheco. My example above is a butchered version from there and this site.

Hope that helps!


One possible way is to use the Visual Studio tool Spy++.

Give this a try:

  1. Run the tool (for me, it's at C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\spyxx_amd64.exe)
  2. In the menu bar, select Spy -> Log messages... (or hit Ctrl + M)
  3. Check All Windows in System in the Additional Windows frame
  4. Switch to the Messages tab
  5. Click the Clear All button
  6. Select WM_HOTKEY in the listbox, or check Keyboard in Message Groups (if you're OK with more potential noise)
  7. Click the OK button
  8. Press the hotkey in question (Win + R, for example)
  9. Select the WM_HOTKEY line in the Messages (All Windows) window, right click, and select Properties... in the context menu
  10. In the Message Properties dialog, click the Window Handle link (this will be the handle for the window that received the message)
  11. Click the Synchronize button on the Window Properties dialog. This will show the window in the main Spy++ window treeview.
  12. On the Window Properties dialog, select the Process tab
  13. Click the Process ID link. This will show you the process (In my Win + R case: EXPLORER)

After some research, it appears that you'd need to get access to the internal structure that MS uses to store the hotkeys. ReactOS has a clean room implementation that implements the GetHotKey call by iterating an internal list and extracting the hotkey that matches the parameters to the call.

Depending on how close ReactOS' implementation is to the MS implementation, you may be able to poke around in memory to find the structure, but that's over my head...

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;
}

I presume this thread on sysinternals was asked by someone related to this question, but I thought I'd link to it anyway to keep the two together. The thread looks very intriguing, but I suspect that some deep dive spelunking would need to happen to figure this out without access to the MS internals.


Off the top of my head, you might try enumerating all windows with EnumWindows, then in the callback, send WM_GETHOTKEY to each window.

Edit: Apparrently I was wrong about that. MSDN has more information:

WM_HOTKEY is unrelated to the WM_GETHOTKEY and WM_SETHOTKEY hot keys. The WM_HOTKEY message is sent for generic hot keys while the WM_SETHOTKEY and WM_GETHOTKEY messages relate to window activation hot keys.

Note: Here is a program purporting to have the functionality you are looking for. You could try decompiling it.


This seems to tell you a lot: http://hkcmdr.anymania.com/help.html


Another thread mentions a global NT level keyboard hook:

Re-assign/override hotkey (Win + L) to lock windows

maybe you can get the handle of the process that called the hook that way, which you can then resolve to the process name

(disclaimer: I had it in my bookmarks, haven't really tried/tested)


I know you can intercept the stream of messages in any window within your own process - what we used to call subclassing in VB6. (Though I do not remember the function, perhaps SetWindowLong?) I am unsure if you can do this for windows outside your own process. But for the sake of this post lets assume you find a way to do that. Then you can simply intercept the messages for all top level windows, monitor for the WM_HOTKEY message. You wouldn't be able to know all the keys right off the bat, but as they were pressed you could easily figure out what application was using them. If you persisted your results to disk and reloaded each time your monitor application was run you could increase the performance of your application over time.


This doesn't exactly answer the part of the question that is about the Windows API, but it answers the part of the question that is about a list of global hotkeys and the applications that "own" them.

The free Hotkey Explorer at http://hkcmdr.anymania.com/ shows a list of all global hotkeys and the applications that own them. This just has helped me figure out why an application-specific shortcut key stopped working and how to fix it (by reconfiguring the registered global hotkey in the app that had it registered), within a few seconds.

참고URL : https://stackoverflow.com/questions/829007/find-out-what-process-registered-a-global-hotkey-windows-api

반응형