Search code examples
c#winformsc++-cliwndproc

Send String from C++ to C# processes using WndProc


I'm trying to send a String from C++/CLI to C#/WinForms

Here is my PostMessage

void Browser::NavigateTo(System::String^ address){
    GCHandle gch = GCHandle::Alloc(address, GCHandleType::Pinned);
    auto GCPin = gcHandle.AddrOfPinnedObject();
    ::PostMessage(procWndHandle, WM_NAVTO, 0, (LPARAM &GCPin);
}

In the Winform Function, i'm trying to marshal it like this

[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name="FullTrust"]
protected override void WndProc(ref Message m)
switch (m.Msg) {
    case WM_NAVTO:
        string s = Marshal.PtrToStringUni(m.LParam);
        break;
    }
}   

I'm not getting an exception, however I'm not getting the address I sent, instead I'm getting Unicode Garbage.

I'm sure I'm missing something fundamental, but I can't seem to see it. Can anyone help?


Solution

  • There's a couple issues with your current code:

    1. PostMessage does not wait for the receiving application before returning. Therefore, the pinned object becomes unpinned before the message has been processed, and may be moved to a new location in memory. (This is probably not the major issue here.)
    2. Assuming that your C++/CLI and C# components are completely separate processes, what you're doing is sending a pointer in one process space to another process. That pointer is no longer valid.

    To fix #2, you need to copy the memory from one process to the other, somehow.

    1. As Hans Passant said in the comments, you could use a named pipe to send whatever data you like to the other application. This is probably the best solution, and is definitely the most full-featured.
    2. If you have to stick with windows messages, use the WM_COPYDATA message. This message will have Windows copy your data (the string contents, in this case) from one process to the other. See the Using Data Copy example on MSDN.