Configuration de Hook sur les messages Windows

J’essaie de créer une application qui notifiera le nom et l’artiste de la piste en cours de lecture à l’utilisateur pour que je surveille l’ track change event .

J’ai utilisé Winspector et Winspector découvert qu’à chaque changement de WM_SETTEXT message WM_SETTEXT de WM_SETTEXT est envoyé.

entrer la description de l'image ici

Pour cela, je crois que je dois configurer un HOOK via mon application pour rechercher le message WM_SETTEXT envoyé par l’autre application.

Maintenant, le problème auquel je suis confronté est que je ne suis pas en mesure d’obtenir un exemple de code de travail pour travailler avec. J’ai lu la documentation de setwindowshookex et j’ai aussi fait des recherches sur Google mais je suis vraiment perdu car je n’ai aucun arrière-plan de C # et que je traite des messages / événements Windows.

Donc, si vous pouvez me fournir un petit code de travail pour comprendre comment setting up hook sur une autre application ou si vous pouvez me diriger vers un article intéressant sur la manière de réaliser cela.

Voici une approche différente: ignorez l’API SetWindowsHook et utilisez plutôt WinEvents , qui utilise SetWinEventHook à la place. Celles-ci sont quelque peu similaires aux hooks de Windows, dans la mesure où elles impliquent une fonction de rappel appelée lors d’événements spécifiques, mais que WinEvents est beaucoup plus facile à utiliser depuis C #: vous pouvez spécifier que WinEvents est fourni hors contexte. Retour à votre propre processus, vous n’avez donc pas besoin d’une DLL distincte. (Votre code doit cependant exécuter une boucle de message sur le même thread qui a appelé SetWinEventHook.)

Il se trouve que l’un des types d’événements pris en charge par WinEvent est un événement «changement de nom», qui est automatiquement déclenché par USER32 chaque fois que le texte du titre d’un HWND change, ce qui semble être ce que vous recherchez. (WinEvents peut également être utilisé pour suivre les modifications de focus et les différents types de modifications d’état; voir MSDN pour plus d’informations.) Il est également déclenché par d’autres contrôles lorsque leur interface utilisateur interne change, par exemple par une listbox nous devons faire du filtrage.

Voici un exemple de code qui imprime les modifications de titre sur un HWND sur le bureau – vous le verrez par exemple imprimer une notification lorsque le texte de l’horloge de la barre des tâches change. Vous souhaitez modifier ce code pour filtrer uniquement le HWND que vous suivez dans Spotify. En outre, ce code écoute les changements de nom sur tous les processus / threads; vous devriez obtenir le threadID du HWND cible en utilisant GetWindowThreadProcessId et écouter uniquement les événements de ce thread.

Notez également qu’il s’agit d’une approche fragile. Si Spotify modifie la façon dont il affiche le texte ou en modifie le format, vous devez modifier votre code pour suivre ses modifications.

 using System; using System.Windows; using System.Windows.Forms; using System.Runtime.InteropServices; class NameChangeTracker { delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime); [DllImport("user32.dll")] static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags); [DllImport("user32.dll")] static extern bool UnhookWinEvent(IntPtr hWinEventHook); const uint EVENT_OBJECT_NAMECHANGE = 0x800C; const uint WINEVENT_OUTOFCONTEXT = 0; // Need to ensure delegate is not collected while we're using it, // storing it in a class field is simplest way to do this. static WinEventDelegate procDelegate = new WinEventDelegate(WinEventProc); public static void Main() { // Listen for name change changes across all processes/threads on current desktop... IntPtr hhook = SetWinEventHook(EVENT_OBJECT_NAMECHANGE, EVENT_OBJECT_NAMECHANGE, IntPtr.Zero, procDelegate, 0, 0, WINEVENT_OUTOFCONTEXT); // MessageBox provides the necessary mesage loop that SetWinEventHook requires. // In real-world code, use a regular message loop (GetMessage/TranslateMessage/ // DispatchMessage etc or equivalent.) MessageBox.Show("Tracking name changes on HWNDs, close message box to exit."); UnhookWinEvent(hhook); } static void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) { // filter out non-HWND namechanges... (eg. items within a listbox) if(idObject != 0 || idChild != 0) { return; } Console.WriteLine("Text of hwnd changed {0:x8}", hwnd.ToInt32()); } } 

Vous pouvez essayer de remplacer WndProc dans votre formulaire principal, par exemple:

 protected override void WndProc(ref Message m) { base.WndProc(ref m); if (m.Msg == WM_SETTEXT) { // Call to your logic here } } 

Pour des conseils sur l’utilisation de SetWindowHookEx, voir la question 214022 de SO . Pour le code de travail en C #, voir SO question 1811383 .

En général, si vous souhaitez accéder aux fonctions WinAPI à partir de C #, vous devez effectuer un appel de plateforme ( PInvoke court). pinvoke.net est une bonne ressource sur les signatures dont votre source a besoin pour y parvenir, mais cela a déjà été couvert dans la question 1811383.

Comme je n’ai jamais compris toute la queue de messagerie Windows, je ne sais pas si la méthode proposée par zabulus fonctionnera lorsque le message est généré par un processus différent. Mais j’ai trouvé un exemple de code ici: http://en.serialcoder.net/Winforms/527/533/Interoperability%20Win32/How%20can%20I%20use%20%20Hooks%20%20in%20.NET.aspx Hope qui aide.