C # - захват сообщений Windows из определенного приложения - PullRequest
7 голосов
/ 20 июля 2010

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

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

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

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

После небольшого исследования я собрал следующее в 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. Находит приложение, которое я хочу отслеживать
  2. Регистрирует сообщения окна, которые я хочу перехватить
  3. Следит за всеми оконными сообщениями - затем удаляет те, которые мне нужны

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

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

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

Ответы [ 2 ]

1 голос
/ 20 июля 2010

Оказывается, мне также нужно было отправить другому приложению 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 голосов
/ 20 июля 2010

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

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

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

...