tags:

views:

393

answers:

5

I'm writing a C++ DLL that needs to notify client applications. In C++ (MFC), I can register a client window handle inside the DLL, then call PostMessage when I need to notify the client about something. What can I do when the client is a C# application?

+1  A: 

PostMessage is just telling windows to issue a message to the main application loop of another application. You're almost certainly going to do the same thing if the client is a C# app, so the question more properly is, how do I read a message sent to the main application loop in C#.

Jherico
Right. And the answer is...?
Curtis
Is there a better way than using PostMessage?
Curtis
Would a Callback work for you?
cdonner
A: 

You can override the WndProc method in the C# window to handle this specific message

protected override void WndProc(ref Message m)
{
    if (m.Msg = YOUR_MESSAGE)
    {
        // handle the notification
    }
    else
    {
        base.WndProc(ref m);
    }
}
Thomas Levesque
A: 

If you want to implement a poor man's publish-subscribe pattern, callbacks are the way to go. There is some good info in this thread.

cdonner
+1  A: 

It would be possible to do by posting a message to a windows handle. In your dotnet class create a dummy window that can intercept messages, then fire a message.

Here's some code, you'd just have to fill in the spots where I used WM_MYMESSAGE, to reference a proper windows message, Now in your C++ dll you could post a message to it. Note, I'm sure there are better/other ways to do what you want, but this would probably work too.

//Dummy window classes.  Because we don't have access to the wndproc method of a form, we create
//dummy forms and expose the method to the SystemHotKeyHook class as an event.

/// <summary>
/// Inherits from System.Windows.Form.NativeWindow. Provides an Event for Message handling
/// </summary>
private class NativeWindowWithEvent : System.Windows.Forms.NativeWindow
{
    public event MessageEventHandler ProcessMessage;
    protected override void WndProc(ref Message m)
    {
        //Intercept the message you are looking for...
        if (m.Msg == (int)WM_MYMESSAGE)
        {
            //Fire event which is consumed by your class
            if (ProcessMessage != null)
            {
                bool Handled = false;
                ProcessMessage(this, ref m, ref Handled);
                if (!Handled)
                {
                    base.WndProc(ref m);
                }
            }
            else
            {
                base.WndProc(ref m);
            }
        }
        else
        {
            base.WndProc(ref m);
        }
    }
}
/// <summary>
/// Inherits from NativeWindowWithEvent and automatic creates/destroys of a dummy window
/// </summary>
private class DummyWindowWithEvent : NativeWindowWithEvent, IDisposable
{
    public DummyWindowWithEvent()
    {
        CreateParams parms = new CreateParams();
        this.CreateHandle(parms);
    }
    public void Dispose()
    {
        if (this.Handle != (IntPtr)0)
        {
            this.DestroyHandle();
        }
    }
}

Class to intercept messages:

// <summary>
/// System hotkey interceptor
/// </summary>
public class MessageIntercept: IDisposable
{
    private delegate void MessageEventHandler(object Sender, ref System.Windows.Forms.Message msg, ref bool Handled);

    //Window for WM_MYMESSAGE Interceptor
    private DummyWindowWithEvent frmDummyReceiver_m;

    /// <summary>
    /// Default constructor
    /// </summary>
    public MessageIntercept()
    {
        this.frmDummyReceiver_m = new DummyWindowWithEvent();
        this.frmDummyReceiver_m.ProcessMessage += new MessageEventHandler(this.InterceptMessage);
    }

    private void InterceptMessage(object Sender, ref System.Windows.Forms.Message msg, ref bool Handled)
    {
        //Do something based on criteria of the message
        if ((msg.Msg == (int)WM_MYMESSAGE) && 
            (msg.WParam == (IntPtr)xyz))
        {
            Handled = true;
            System.Diagnostics.Debug.WriteLine("Message intercepted.");
        }
    }
}
Jeremy
+1  A: 

Depending on how closely the two work together, I'd probably use a callback/event approach.

To me the whole "PostMessage" approach, seems like a bit of a hack (depends on what you want to do, if it's a standard message you're posting, it's obviously fine)

You can make a managed C++ wrapper for your native class, the managed wrapper can handle the callback and issue a managed (C# compatible) event, which the C# class can listen for.

In general I'm a big fan of linking native C++ to C# through a managed C++ layer - that way your C# application doesn't need to know all the "ugly" low-level details of the native C++ code.

Steffen