2010-07-20 16 views
7

Sto scrivendo un'applicazione C# che deve intercettare Messaggi finestra che un'altra applicazione sta inviando. La società che ha scritto l'applicazione che sto monitorando mi ha mandato un codice di esempio, tuttavia è in C++ che non conosco.C# - Catturare messaggi Windows da un'applicazione specifica

Nel codice di esempio C++ Ho usano il seguente codice:

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

A quanto mi risulta questo recupera un ID da Windows per il messaggio specifico che vogliamo ascoltare. Quindi chiediamo al C++ di chiamare OnShockStatusMessage ogni volta che viene intercettato un messaggio che corrisponde all'Id.

Dopo un po 'di ricerca ho messo insieme il seguente in 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!"); 
    } 

} 

quanto ho capito questo dovrebbe fare la stessa cosa di base, in quanto:

  1. di trovare l'applicazione che ho desidera monitorare
  2. Registra i messaggi della finestra che desidero intercettare
  3. Orologi per tutti i messaggi della finestra - quindi elimina quelli di cui ho bisogno

Tuttavia nel mio override della WndProc() metodo di nessuno dei miei assegni intercettare uno dei messaggi specifici o qualsiasi messaggio dall'applicazione sto monitoraggio.

Se I Debug.WriteLine per tutti i messaggi che lo attraversano, posso vedere che li sta monitorando. Tuttavia non filtra mai i messaggi che voglio.

Eseguendo l'applicazione di monitoraggio di esempio scritta in C++, posso vedere che i messaggi di Windows vengono inviati e prelevati - è solo il mio C# che l'implementazione non fa lo stesso.

risposta

1

Risulta inoltre necessario inviare l'altra domanda a PostMessage chiedendogli di inviare la mia applicazione i messaggi di finestra.

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

Non abbastanza codice, ma abbastanza buono per dimostrare che funziona, che è tutto quello che serve per ora :)

0

Penso che il problema sia con la definizione P/Invoke per RegisterWindowMessage(). pinvoke.net suggerisce usando la seguente:

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

Uso uint come valore di ritorno invece di IntPtr dovrebbe fare la differenza. In genere si desidera utilizzare IntPtr quando il valore restituito è un handle (ad esempio HWND o HANDLE), ma quando il valore restituito può essere convertito direttamente in un tipo C# è preferibile utilizzare tale tipo.

+0

Il codice di esempio che hai dato qui è in realtà quello che sto usando in questo momento :) –

+0

@Peter Ah, mi sono perso. Perché hai fatto la lista una lista di IntPtr? Perché non basta che lo faccia List ? – Andy

+0

Mi aspetto che si trattasse solo di copiare le istruzioni [DllImport] da un sito Web diverso, per vedere se ha fatto qualche differenza, ma ciascuna ha avuto lievi differenze. –

Problemi correlati