Finden Sie heraus, welcher Prozess einen globalen Hotkey registriert hat? (Windows API)


113

Soweit ich herausfinden konnte, bietet Windows keine API-Funktion, um festzustellen, welche Anwendung einen globalen Hotkey registriert hat (über RegisterHotkey). Ich kann nur herausfinden, dass ein Hotkey registriert ist, wenn RegisterHotkey false zurückgibt, aber nicht, wem der Hotkey "gehört".

Könnte es ohne eine direkte API einen Umweg geben? Windows behält das Handle bei, das jedem registrierten Hotkey zugeordnet ist - es ist ein wenig verrückt, dass es keine Möglichkeit geben sollte, an diese Informationen zu gelangen.

Beispiel für etwas, das wahrscheinlich nicht funktioniert: Senden (simulieren) Sie einen registrierten Hotkey und fangen Sie dann die Hotkey-Nachricht ab, die Windows an den Prozess sendet, der sie registriert hat. Erstens glaube ich nicht, dass das Abfangen der Nachricht das Handle des Zielfensters enthüllen würde. Zweitens, selbst wenn es möglich wäre, wäre es eine schlechte Sache, da das Senden von Hotkeys alle Arten von potenziell unerwünschten Aktivitäten aus verschiedenen Programmen auslösen würde.

Es ist nicht kritisch, aber ich habe häufige Anfragen nach solchen Funktionen gesehen und bin selbst Opfer von Anwendungen geworden, die Hotkeys registrieren, ohne sie irgendwo in der Benutzeroberfläche oder in den Dokumenten offenzulegen.

(Wenn Sie in Delphi arbeiten und nicht mehr als ein Lehrling bei WinAPI sind, seien Sie bitte freundlich.)

Antworten:


20

Ihre Frage hat mein Interesse geweckt, also habe ich ein bisschen gegraben und obwohl ich leider keine richtige Antwort für Sie habe, dachte ich, ich würde teilen, was ich habe.

Ich fand dieses Beispiel für Tastatur - Hook zu schaffen (in Delphi) im Jahr 1998 geschrieben, aber ist übersetzbar in Delphi 2007 mit ein paar Verbesserungen.

Es ist eine DLL mit einem Aufruf SetWindowsHookEx, der eine Rückruffunktion durchläuft, die dann Tastenanschläge abfangen kann: In diesem Fall wird zum Spaß daran herumgebastelt, der linke Cursor wird nach rechts geändert usw. Eine einfache App ruft dann die DLL auf und meldet sich zurück seine Ergebnisse basieren auf einem TTimer-Ereignis. Wenn Sie interessiert sind, kann ich den Delphi 2007-basierten Code veröffentlichen.

Es ist gut dokumentiert und kommentiert, und Sie können es möglicherweise als Grundlage verwenden, um herauszufinden, wohin ein Tastendruck führt. Wenn Sie das Handle der Anwendung erhalten könnten, die die Tastenanschläge gesendet hat, könnten Sie es auf diese Weise zurückverfolgen. Mit diesem Handle können Sie ganz einfach die Informationen abrufen, die Sie benötigen.

Andere Apps haben versucht, Hotkeys anhand ihrer Verknüpfungen zu ermitteln, da sie eine Verknüpfungstaste enthalten können, die nur ein weiterer Begriff für Hotkey ist. Die meisten Anwendungen neigen jedoch nicht dazu, diese Eigenschaft festzulegen, sodass sie möglicherweise nicht viel zurückgibt. Wenn Sie an dieser Route interessiert sind, hat Delphi Zugriff auf die IShellLinkCOM-Schnittstelle, über die Sie eine Verknüpfung laden und deren Hotkey abrufen können:

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;

Wenn Sie Zugriff auf Safari Books Online haben , finden Sie im Borland Delphi 6-Entwicklerhandbuch von Steve Teixeira und Xavier Pacheco einen guten Abschnitt zum Arbeiten mit Verknüpfungen / Shell-Links . Mein Beispiel oben ist eine geschlachtete Version von dort und dieser Seite .

Hoffentlich hilft das!


58

Eine Möglichkeit ist die Verwendung des Visual Studio-Tools Spy ++ .

Probieren Sie es aus:

  1. Führen Sie das Tool aus (für mich ist es bei C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\spyxx_amd64.exe)
  2. Wählen Sie in der Menüleiste Spion -> Nachrichten protokollieren ... (oder drücken Sie Ctrl+ M).
  3. Überprüfen Sie Alle Windows im System im Rahmen Zusätzliches Windows
  4. Wechseln Sie zur Registerkarte Nachrichten
  5. Klicken Sie auf die Schaltfläche Alle löschen
  6. Wählen Sie WM_HOTKEYim Listenfeld aus oder aktivieren Sie die Option Tastatur in Nachrichtengruppen (wenn Sie mit mehr potenziellem Rauschen einverstanden sind).
  7. Klicken Sie auf die Schaltfläche OK
  8. Drücken Sie den betreffenden Hotkey ( z. B. Win+ R).
  9. Wählen Sie die WM_HOTKEYZeile im Fenster Nachrichten (Alle Fenster) aus, klicken Sie mit der rechten Maustaste und wählen Sie im Kontextmenü die Option Eigenschaften
  10. Im Nachrichteneigenschaften Dialog klicken Sie auf den Fenstergriff Link (dies wird der Griff für das Fenster, das die Nachricht empfangen)
  11. Klicken Sie im Dialogfeld Fenstereigenschaften auf die Schaltfläche Synchronisieren . Dies zeigt das Fenster in der Hauptbaumansicht des Spy ++ - Fensters.
  12. Auf der Fenstereigenschaften Dialog wählen Sie den Prozess Registerkarte
  13. Klicken Sie auf den Link Prozess-ID . Dies zeigt Ihnen den Prozess (In meinem Win+ RFall: EXPLORER)

6
Gute Antwort! Nur ein Hinweis, dass die 64-Bit-Version von Spy ++ nur Nachrichten für 64-Bit-Anwendungen abfängt. Wenn Sie WM_HOTKEYdie Nachricht nach dem Drücken des Hotkeys nicht im Nachrichtenprotokoll sehen , müssen Sie möglicherweise die 32-Bit-Version von Spy ++ ausführen .
David Ferenczy Rogožan

ICH DANKE DIR SEHR!!! Ich habe es im Grunde aufgegeben, einige Verknüpfungen zu verwenden, bis ich diese gefunden habe.
Thewindev

3
In Schritt 8 wird kein Hotkey abgefragt. Das Nachrichtenfenster bleibt nach dem Drücken eines Hotkeys leer. Verwendete 32- und 64-Bit-Versionen von github.com/westoncampbell/SpyPlusPlus (in Windows 10).
CoolMind

9

Nach einigen Recherchen scheint es, dass Sie Zugriff auf die interne Struktur benötigen, die MS zum Speichern der Hotkeys verwendet. ReactOS verfügt über eine Reinraumimplementierung, die den GetHotKeyAufruf implementiert, indem eine interne Liste iteriert und der Hotkey extrahiert wird, der den Parametern des Aufrufs entspricht.

Abhängig davon, wie nah die Implementierung von ReactOS an der MS-Implementierung ist, können Sie möglicherweise im Speicher stöbern, um die Struktur zu finden, aber das geht mir über den Kopf ...

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

Ich nehme an , dass dieser Thread zu sysinternals von jemandem gestellt wurde, der mit dieser Frage zu tun hat , aber ich dachte, ich würde trotzdem darauf verlinken, um die beiden zusammenzuhalten. Der Thread sieht sehr faszinierend aus, aber ich vermute, dass einige tiefe Tauch-Höhlenforschungen erforderlich wären, um dies herauszufinden, ohne Zugriff auf die MS-Interna.


3

Auf den ersten Blick könnten Sie versuchen, alle Fenster mit EnumWindows aufzulisten, und dann im Rückruf WM_GETHOTKEY an jedes Fenster senden.

Edit: Anscheinend habe ich mich geirrt. MSDN hat weitere Informationen:

WM_HOTKEY hat keine Beziehung zu den Hotkeys WM_GETHOTKEY und WM_SETHOTKEY. Die WM_HOTKEY-Nachricht wird für generische Hotkeys gesendet, während sich die WM_SETHOTKEY- und WM_GETHOTKEY-Nachrichten auf Hotkeys zur Fensteraktivierung beziehen.

Hinweis: Hier ist ein Programm, das angeblich die von Ihnen gesuchte Funktionalität bietet. Sie könnten versuchen, es zu dekompilieren.


3
Die Verbindung zum Programm ist jetzt vollständig unterbrochen. Welches Programm war das? Es gibt so viele Male, bei denen ich herausfinden möchte, welches Programm meine Hotkeys registriert hat, weil sie plötzlich nicht mehr funktionieren oder nervige neue Dinge tun.
James Oltmans

(Oft kann die Wayback-Maschine beim Verschwinden von Webseiten helfen, aber hier hat sie auch nur einen 404 Not Found gespiegelt: http://web.archive.org/web/*/tds.diamondcs.com.au/dse/ Erkennung / hotkeys.php )
Aaron Thoma

2

Dies scheint Ihnen viel zu sagen: http://hkcmdr.anymania.com/help.html


1
Macht es? Eine als Treiber getarnte DLL? Die DLL-Funktion, die exportiert hoowird SetWindowHookEx, um zwei Hooks zu setzen, einen WH_KEYBOARD_LLund einen WH_GETMESSAGE... der Rest sollte ziemlich genau auf MSDN dokumentiert sein.
0xC0000022L

Verwenden Sie diese App nicht unter Windows 8 oder 10.
Jeff Lange


0

Ich weiß, dass Sie den Nachrichtenstrom in jedem Fenster Ihres eigenen Prozesses abfangen können - was wir in VB6 als Unterklasse bezeichnet haben. (Obwohl ich mich nicht an die Funktion erinnere, vielleicht an SetWindowLong?) Ich bin mir nicht sicher, ob Sie dies für Fenster außerhalb Ihres eigenen Prozesses tun können. In diesem Beitrag wird jedoch davon ausgegangen, dass Sie einen Weg finden, dies zu tun. Dann können Sie einfach die Nachrichten für alle Fenster der obersten Ebene abfangen und auf die WM_HOTKEY-Nachricht überwachen. Sie würden nicht in der Lage sein, alle Tasten auf Anhieb zu kennen, aber wenn sie gedrückt wurden, konnten Sie leicht herausfinden, welche Anwendung sie verwendete. Wenn Sie Ihre Ergebnisse bei jeder Ausführung Ihrer Monitoranwendung auf der Festplatte beibehalten und neu laden, können Sie die Leistung Ihrer Anwendung im Laufe der Zeit steigern.


-1

Dies beantwortet nicht genau den Teil der Frage, der sich auf die Windows-API bezieht, sondern den Teil der Frage, der sich auf eine Liste globaler Hotkeys und der Anwendungen bezieht, die sie "besitzen".

Der kostenlose Hotkey Explorer unter http://hkcmdr.anymania.com/ zeigt eine Liste aller globalen Hotkeys und der Anwendungen, deren Eigentümer sie sind. Dies hat mir nur geholfen, innerhalb weniger Sekunden herauszufinden, warum eine anwendungsspezifische Tastenkombination nicht mehr funktioniert und wie sie behoben werden kann (indem der registrierte globale Hotkey in der App, in der sie registriert wurde, neu konfiguriert wird).


4
installierte es und es verhielt sich wie ein Virus, zumindest ein Programm mit Mall-Intend, wie ein schlechter Witz. Öffnen aller Arten von Fenstern, Aktivieren von Voice Narator usw.
Flion

3
@Flion: Siehe Diskussion auf superuser.com/a/191090/3617 . Grundsätzlich funktionieren einige Hotkey-Dienstprogramme, indem sie jede mögliche Tastenkombination prüfen. Unter Windows 8+ (und in geringerem Maße unter Windows 7) löst diese Sondierungstechnik jede Tastenkombination aus, anstatt sie nur abzufragen.
Brian

@Flion FWIW, ich habe es mit Erfolg auf Win7 verwendet. Aber wenn ich Brian richtig verstehe, funktioniert dies möglicherweise nicht so gut mit späteren Versionen, und wie gut es funktioniert, hängt möglicherweise auch von benutzerdefinierten Hotkeys ab, die definiert sind.
Gerhard
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.