First attempts and ideas
If you read the MSDN help about WM_COYDATA you can see that it is possible to use it in order to communicate between 16-bit and 32-bit apps, but not how. My Problem was the following: I had to include a 16-bit-dll into a 32-bit-Application, as there is no newer version of the dll available. If you really want to solve this problem, you have to either build a real thunk using the thunk compiler (see other articles for details) or cheat a little using the function QT_Thunk() which has been described on the web several times. Both ideas are rather complicated since you have to write at least a few lines of assembly code. I didn't dare to do this, because I thought it would be too complicated.
My next approach to the problem was to build up a DDE-Client-Server-Architecture. But also this possibility seemed to be too great an effort. When I first saw the documentation of WM_COPYDATA I thought it couldn't work between 16-bit and 32-Bit apps and first tried another thing: I let two apps communicate via Windows Messages and sent pointers pointing to data arrays via this channel. This lead to the problem of the translation between flat 32-bit Pointers and generic far 16-bit-Pointers. I advise you to never try a thing like that, it's really awful!
How it works
At last I tried just to use WM_COPYDATA, even though I thought there were still two problems to solve, which I saw no solution for: The first one is the same problem I encountered trying to use my own Windows Messages. I thought it would be necessary to translate the pointers. But to my surprise this seems to be done automatically. The second problem I expected was the following: I thought it would not be possible to get access to a pointer outside the adress space of an application by directly dereferecing it. Normally this leads to Windows exceptions, but it does not in the case of using WM_COPYDATA. The pointer you send by this message is allowed to be dereferenced by some magic way.
So what do you have to do? I can only answer this question for my special case. I used Visual C++ 6.0 for the 32-bit-app and Visual C++ 1.52 for the 16-bit-App on Windows 2000. As my solution works for running the 16-bit-app in both a shared and a seperate virtual dos machine, I guess that it also works on Windows 98 / ME, but I have not tested that. In order to have the two apps communicate I have them get handles to each other using the API-Function FindWindow(NULL,"name"). When they have handles, they can send messages to each other using the API-Function (NOT the CWnd-member) SendMessage(). In order to avoid timing problems you should never use PostMessage() instead of SendMessage(). It's a good idea to choose a small set of common messages for the two apps and have them register by the API-Function RegisterWindowMessage(). I only built up a data transfer from 16-bit to 32-bit but not vice versa. For that pupose I had to include the following piece of code in my 16-bit-app, as WM_COPYDATA and COPYDATASTRUCT are not defined in the headers of the old 16-bit-API:
In order to transfer data I just had to create an instance of the COPYDATASTRUCT (let's call it cpstruct), assign values to its members and then send the message WM_COPYDATA like
::SendMessage(handle, WM_COPYDATA, 0, (LPARAM) (LPVOID) &cpstruct);
The receiving 32-bit-app needn't do any pointer translation and can directly get access to the data by dereferencing the pointer in the MessageHandler. The MessageHandler for WM_COPYDATA in the 32-bit-app looks like:
BOOL CCCDClient::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)<BR>
{<BR>
memcpy(m_pReceiveData, pCopyDataStruct->lpData, <BR> pCopyDataStruct->cbData);<BR>
return CFrameWnd::OnCopyData(pWnd, pCopyDataStruct);<BR>
}
It is necessary to copy the data (e.g. using memcpy() as shown here) within the MessageHandler. I first tried to store the pointer and copy the data in a different function, but this doesn't work. So as you can see it's quite easy to communicate and exchange data between 16-bit and 32-bit-apps.