2010-07-20 21 views
7

J'écris une application C# qui doit intercepter les messages de fenêtre qu'une autre application envoie. La société qui a écrit l'application que je surveille m'a envoyé un exemple de code, mais c'est en C++ que je ne connais pas vraiment.C# - Capture de messages Windows à partir d'une application spécifique

Dans l'exemple de code C++ j'ai qu'ils utilisent le code suivant:

UINT uMsg = RegisterWindowMessage(SHOCK_MESSAGE_BROADCAST); 
ON_REGISTERED_MESSAGE(WM_SHOCK_BROADCAST_MESSAGE, OnShockStatusMessage) 
LRESULT OnShockStatusMessage(WPARAM wParam, LPARAM lParam); 

Si je comprends bien ce récupère un identifiant de Windows pour le message spécifique que nous voulons écouter. Ensuite, nous demandons à C++ d'appeler OnShockStatusMessage à chaque fois qu'un message correspondant à l'ID est intercepté.

Après un peu de recherche, je l'ai mis en place les éléments suivants en C#

[DllImport("user32.dll", SetLastError = true)] 
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); 

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] 
static extern uint RegisterWindowMessage(string lpString); 

private IntPtr _hWnd; // APS-50 class reference 
private List<IntPtr> _windowsMessages = new List<IntPtr>(); // APS-50 messages 

private const string _className = "www.AuPix.com/SHOCK/MessageWindowClass"; 

// Windows Messages events 
private const string _messageBroadcast = "www.AuPix.com/SHOCK/BROADCAST"; 
private const string _messageCallEvents = "www.AuPix.com/SHOCK/CallEvents"; 
private const string _messageRegistrationEvents = "www.AuPix.com/SHOCK/RegistrationEvents"; 
private const string _messageActions = "www.AuPix.com/SHOCK/Actions"; 

private void DemoProblem() 
{ 
    // Find hidden window handle 
    _hWnd = FindWindow(_className, null); 

    // Register for events 
    _windowsMessages.Add(new IntPtr(RegisterWindowMessage(_messageActions))); 
    _windowsMessages.Add(new IntPtr(RegisterWindowMessage(_messageBroadcast))); 
    _windowsMessages.Add(new IntPtr(RegisterWindowMessage(_messageCallEvents))); 
    _windowsMessages.Add(new IntPtr(RegisterWindowMessage(_messageRegistrationEvents))); 
} 

protected override void WndProc(ref Message m) 
{ 
    base.WndProc(ref m); 

    // Are they registered Windows Messages for the APS-50 application? 
    foreach (IntPtr message in _windowsMessages) 
    { 
     if ((IntPtr)m.Msg == message) 
     { 
      Debug.WriteLine("Message from specified application found!"); 
     } 
    } 

    // Are they coming from the APS-50 application? 
    if (m.HWnd == shock.WindowsHandle) 
    { 
     Debug.WriteLine("Message from specified application found!"); 
    } 

} 

Si je comprends bien cela devrait faire la même chose de base, en ce qu'elle:

  1. Trouve l'application I souhaite surveiller
  2. Enregistre les messages de fenêtre que je souhaite intercepter
  3. Montres pour tous les messages de fenêtre - puis supprime ceux dont j'ai besoin

Cependant, dans mon remplacement de la WndProc() méthode ni de mes chèques intercepter l'un des messages spécifiques ou tout message de l'application que je suis suivi.

Si je Debug.WriteLine pour tous les messages qui viennent à travers, je peux voir qu'il les surveille. Cependant, il ne filtre jamais les messages que je veux. En exécutant l'application de surveillance d'exemple écrite en C++, je peux voir que les messages de fenêtre sont envoyés et ramassés - c'est juste mon implémentation C# ne fait pas la même chose.

Répondre

1

Il s'avère que j'avais également besoin d'envoyer un autre PostMessage l'autre application en lui demandant d'envoyer mon application les messages de la fenêtre.

PostMessage((int)_hWnd, _windowsMessages[0], SHOCK_REQUEST_ACTIVE_CALLINFO, (int)_thisHandle); 
PostMessage((int)_hWnd, _windowsMessages[0], SHOCK_REQUEST_ALL_REGISTRATIONINFO, (int)_thisHandle); 
PostMessage((int)_hWnd, _windowsMessages[0], SHOCK_REQUEST_CALL_EVENTS, (int)_thisHandle); 
PostMessage((int)_hWnd, _windowsMessages[0], SHOCK_REQUEST_REGISTRATION_EVENTS, (int)_thisHandle); 

Code Pas assez, mais assez bon pour prouver qu'il fonctionne, qui est tout ce que je dois pour l'instant :)

0

Je pense que le problème est avec votre définition P/Invoke pour RegisterWindowMessage(). pinvoke.net suggère d'utiliser les éléments suivants:

[DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)] 
static extern uint RegisterWindowMessage(string lpString); 

En utilisant uint comme la valeur de retour au lieu de IntPtr devrait faire la différence. Généralement vous voulez utiliser IntPtr lorsque la valeur de retour est un handle (tel qu'un HWND ou HANDLE), mais lorsque la valeur de retour peut être directement convertie en un type C#, il est préférable d'utiliser ce type.

+0

Le code exemple que vous avez donné ici est en fait ce que je suis en utilisant au moment :) –

+0

@Peter Ah, manqué ça. Pourquoi avez-vous fait de la liste une liste de IntPtr? Pourquoi ne pas simplement le faire Liste ? – Andy

+0

Je pensais que c'était juste pour copier les instructions [DllImport] de différents sites Web, voir si cela faisait une différence, mais chacun avait de légères différences. –