views:

117

answers:

2

I'm writing a C# application which needs to intercept Window Messages that another applications is sending out. The company who wrote the application I'm monitoring sent me some example code, however it's in C++ which I don't really know.

In the C++ example code I've got they use the following code:

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

As I understand it this retrieves an Id from Windows for the specific message we want to listen for. Then we're asking C++ to call OnShockStatusMessage whenever an message matching the Id is intercepted.

After a bit of research I've put together the following 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!");
    }

}

As I understand this should do the same basic thing, in that it:

  1. Finds the application I wish to monitor
  2. Registers the Window Messages I wish to intercept
  3. Watches for all Window Messages - then strips out the ones I need

However in my override of the WndProc() method neither of my checks intercept any of the specific messages or any message from the application I'm monitoring.

If I Debug.WriteLine for all messages that come through it, I can see that it's monitoring them. However it never filters out the messages that I want.

By running the example monitoring application written in C++ I can see that Window Messages are being sent and picked up - it's just my C# implemention doesn't do the same.

A: 

I think the problem is with your P/Invoke definition for RegisterWindowMessage(). pinvoke.net suggests using the following:

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

Using uint as the return value instead of IntPtr should make the difference. Typically you want to use IntPtr when the return value is a handle (such as an HWND or HANDLE), but when the return value can be directly converted to a C# type it is better to use that type.

Andy
The example code you've given here is actually what I'm using at the moment :)
Peter Bridger
@Peter Ah, missed that. Why did you make the List a List of IntPtr? Why not just make it List<uint>?
Andy
I expect it was just to copying the [DllImport] statements from different website, seeing if it made any difference, but each one had slight differences.
Peter Bridger
A: 

Turns out I also needed to send the other application a PostMessage asking it to send my application the Window Messages.

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

Not pretty code, but good enough to prove it works which is all I need for now :)

Peter Bridger