7

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.

Spooky
  • 2,966
  • 8
  • 27
  • 41
  • Is the requirement of using window messages specific? Or is passing data between processes the ultimate goal? For the latter, there are [better ways](http://en.wikipedia.org/wiki/Inter-process_communication) to achive that. – ulidtko May 16 '12 at 13:20
  • 2
    You probably should do some basic validation of the `COPYDATASTRUCT` before using it. Some malicious application could send you bogus `WM_COPYDATA` messages. – jamesdlin May 17 '12 at 05:27

1 Answers1

6

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.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • I'd necessarily mention the generic ways to do IPC: pipes, shared memory + mutexes, sockets, etc. – ulidtko May 16 '12 at 13:21
  • 1
    @ulidtko I've researched into other methods, and I concluded that windows messages would cause me less hassle, but thanks for your concern. – Spooky May 16 '12 at 13:35
  • Is it necessary to use `OnCopyData` to receive the data? It is important to note that my C++ DLL is injected into another process, and I am unsure as to whether I can still receive the `COPYDATASTRUCT` – Spooky May 16 '12 at 14:45
  • Furthermore, I would rather not have to make an invisible window from my C++ DLL (to receive the OnCopyData)... but if there isn't another way then I'll yield. – Spooky May 16 '12 at 14:57
  • 1
    You need an invisible window. – David Heffernan May 16 '12 at 15:08
  • @DavidHeffernan See my modified first post to see how I achieved this without an invisible window. Can you think of a downside of using this method? – Spooky May 16 '12 at 15:30
  • You are re-using an existing window handle? That is also fine. – David Heffernan May 16 '12 at 15:57
  • I have "detoured" the window's `WndProc` using [`SetWindowLong`](http://msdn.microsoft.com/en-us/library/windows/desktop/ms633591%28v=vs.85%29.aspx) with the `GWL_WNDPROC` offset, in order to "subclass" the window (?) (see: [this](http://msdn.microsoft.com/en-us/library/windows/desktop/ms633570%28v=vs.85%29.aspx#subclassing_window) example) – Spooky May 16 '12 at 17:18
  • @Spooky: You could use a *message-only* window if it makes you feel any better. – jamesdlin May 17 '12 at 05:24