2010-07-20 27 views
7

Estoy escribiendo una aplicación C# que necesita interceptar Mensajes de ventana que están enviando otras aplicaciones. La compañía que escribió la aplicación que estoy monitoreando me envió un código de ejemplo, sin embargo, está en C++, que realmente no sé.C# - Capturar mensajes de Windows desde una aplicación específica

En el ejemplo de código C++ Tengo que utilizan el siguiente código:

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

Tengo entendido que este recupera un ID de Windows para el mensaje específico que queremos escuchar. Luego le pedimos a C++ que llame al OnShockStatusMessage siempre que se intercepte un mensaje que coincida con el Id.

Después de un poco de investigación he elaborado la siguiente 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!"); 
    } 

} 

Según entiendo esto debería hacer la misma cosa básica, en la que:

  1. Finds la aplicación I desea monitorear
  2. Registra los mensajes de la ventana Deseo interceptar
  3. Relojes para todos los mensajes de la ventana - luego quita los que necesito

Sin embargo en mi anulación de la WndProc() método de ninguno de mis cheques de interceptación de los mensajes específicos o cualquier mensaje de la aplicación que estoy monitoreo.

If I Debug.WriteLine para todos los mensajes que vienen a través de él, puedo ver que los está monitoreando. Sin embargo, nunca filtra los mensajes que quiero.

Ejecutando la aplicación de supervisión de ejemplo escrita en C++, puedo ver que los mensajes de la ventana se envían y recogen, es solo que mi implementación de C# no hace lo mismo.

Respuesta

1

Resulta que también necesitaba enviar la otra aplicación a PostMessage pidiéndole que envíe mi aplicación a los mensajes de la ventana.

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

No es bastante código, pero lo suficientemente bueno para demostrar que funciona, que es todo lo que necesito por ahora :)

0

Creo que el problema está en la definición de P/Invoke para RegisterWindowMessage(). pinvoke.net sugiere utilizar el siguiente:

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

Usando uint como valor de retorno en lugar de IntPtr debería hacer la diferencia. Normalmente desea utilizar IntPtr cuando el valor devuelto es un identificador (como HWND o HANDLE), pero cuando el valor devuelto se puede convertir directamente a un tipo C#, es mejor usar ese tipo.

+0

El código de ejemplo que ha dado aquí es en realidad lo que estoy usando en este momento :) –

+0

@Peter Ah, se perdió eso. ¿Por qué hiciste que la lista fuera una lista de IntPtr? ¿Por qué no simplemente hacer que sea List ? – Andy

+0

Supongo que fue solo para copiar las declaraciones [DllImport] de diferentes sitios web, ver si hacía alguna diferencia, pero cada una tenía pequeñas diferencias. –

Cuestiones relacionadas