Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sending/Receiving a string through PostMessage

Although there are already a few resources online that address this rough topic, I still haven't found an answer that works for me.

I desire to have full communication between my VB.net process and my C++ process. I would like to be able to send a string to and from the C++ process, but for the time being I need to achieve:

Sending a string to the C++ process, and handling it.

This creates a few points that I am uncertain on, but I'll try to keep this as simple as possible...

Using the following function declaration in VB;

Declare Function PostMessage Lib "user32" Alias "PostMessageA" ( _
    ByVal hWnd As IntPtr, _
    ByVal Msg As UInteger, _
    ByVal wParam As IntPtr, _
    ByVal lParam As String _
) As Boolean

And sending the message like so;

PostMessage(hWnd, SM_PING, Nothing, "schlampe")

With the following method declaration for capturing the message in C++;

LRESULT CALLBACK newWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

And for a test of whether I can access the string using;

char buffer[50];
sprintf(buffer, "Received: %s", (char *)lParam);
MsgBox(buffer);


I skimmed over a lot of the details that I believe to be unnecessary, but ask and it shall be given unto you.

My problem is that the message is received and "handled"... but the message box created by the C++ process does not contain my test message (it reads: "Recieved: ").

So, how can I send a string via PostMessage/SendMessage from VB to C++?




Solution:

See the accepted answer for the solution... but furthermore, here is how I receive the string (C++):

LRESULT CALLBACK newWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch(uMsg) {
        case WM_COPYDATA:
            MsgBox("Received a WM_COPYDATA message");
            COPYDATASTRUCT * pcds = (COPYDATASTRUCT *)lParam;
            LPCTSTR lpszString = (LPCTSTR)(pcds->lpData);
            MsgBox(lpszString);
            return 1L;
    }
    return CallWindowProc(instance->OriginalProcessor(), hwnd, uMsg, wParam, lParam);
}


And finally, I used the IPC example here to send the message. This example sends the message using C#, but the concept was all I needed (not to mention that it's a walk in the park to convert such code to VB). Note that in my VB implementation, I didn't need to terminate the string with a null character.

like image 447
Spooky Avatar asked May 16 '12 13:05

Spooky


1 Answers

When using Windows messages, you should use WM_COPYDATA to transfer string data between processes. If you use custom message IDs then the string data will not be marshalled between the two distinct process address spaces.

And this is why your current code fails. The receiving process is passed in lParam a pointer to memory in the address space of the calling processes. And of course that is meaningless in the other process.

Whilst there are other ways to marshal data like this between processes with Windows messages, WM_COPYDATA is by far the simplest. If your requirement becomes much more complex then you may need to consider a more comprehensive IPC approach than Windows messages.

like image 89
David Heffernan Avatar answered Oct 14 '22 04:10

David Heffernan