2010-07-20 1 views
7

Я пишу приложение C#, которое необходимо перехватить Окно Сообщения, которые посылают другие приложения. Компания, которая написала приложение, которое я отслеживаю, прислала мне примерный код, однако это на C++, которого я действительно не знаю.C# - Захват сообщений Windows из определенного приложения

В примере кода C++ я получил их использовать следующий код:

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

Как я понимаю, это извлекает идентификатор из Windows, для конкретного сообщения, мы хотим слушать. Затем мы просим C++ вызывать OnShockStatusMessage всякий раз, когда сообщение, соответствующее идентификатору, перехватывается.

После немного исследований я соединил следующее 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!"); 
    } 

} 

Как я понимаю, это должно сделать то же основную вещь, в том, что он:

  1. Находит I приложения хочу отслеживать
  2. Регистрирует окна Сообщения, которые я хочу перехватить
  3. Часы для всех оконных сообщений - затем удаляет те, которые мне нужны

Однако в моем переопределении метода WndProc() ни один из моих проверок не перехватывает какое-либо конкретное сообщение или какое-либо сообщение из приложения, которое я контролирую.

Если у меня Debug.WriteLine для всех сообщений, которые проходят через него, я вижу, что он их контролирует. Однако он никогда не отфильтровывает сообщения, которые я хочу.

Запустив приложение для мониторинга приложений, написанное на C++, я вижу, что сообщения Window отправляются и собираются - это просто моя реализация C# не делает то же самое.

ответ

1

Оказывается, мне также нужно было отправить другое приложение PostMessage с просьбой отправить мое приложение в Окно сообщений.

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

не очень-код, но достаточно хорошо, чтобы доказать, что это работает, который все, что мне нужно сейчас :)

0

Я думаю, проблема связана с вашим определением P/Invoke для RegisterWindowMessage(). pinvoke.net предлагает использовать следующее:

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

Использование uint в качестве возвращаемого значения вместо IntPtr должны сделать разницу. Обычно вы хотите использовать , когда возвращаемое значение является дескриптором (например, HWND или HANDLE), но когда возвращаемое значение может быть напрямую преобразовано в тип C#, лучше использовать этот тип.

+0

Пример кода вы дали здесь на самом деле то, что я использую в данный момент :) –

+0

@ Питер, пропустил это. Почему вы сделали список List IntPtr? Почему бы просто не сделать это? Список ? – Andy

+0

Я ожидаю, что это было просто копирование заявлений [DllImport] с другого сайта, если бы это имело какое-либо значение, но у каждого из них были небольшие различия. –