Some time ago, I talked about how to return results back from the WM_ message. Which reminded me of a clever bit of history.
The WM_ message was introduced in 32-bit Windows. There was no need for it in 16-bit Windows because all 16-bit programs ran in the same address space. A far pointer in one process was good in any process. You could put it in the lParam of a window message and send it to any other window, same process or different process, doesn’t matter. But 32-bit programs ran in separate address spaces, so this trick didn’t work. Hence the need for WM_ to pass data not only between 32-bit programs, but also between 32-bit programs and 16-bit programs.
How did this message get retrofitted into 16-bit Windows so that Win32s could support it?
Easy: It was already implemented, unwittingly.
If the source and destination windows are both 16-bit windows, then the pointer to the COPYÂDATAÂSTRUCT is already valid in both processes, as is the pointer inside the COPYÂDATAÂSTRUCT. And the window handle in the wParam is also the same for both processes. Therefore, doing absolutely nothing with the wParam and lParam and simply allowing it to pass from a 16-bit program to another 16-bit program will still behave as expected.
And it so happens that Windows 3.1 already did that: Windows 3.1 always passed the wParam and lParam unmodified, even when the message sender and receiver are in different processes, because all programs shared the same address space.
It was just a sneaky trick to design the WM_ message in such a way that the null marshaler is the correct behavior when it is sent between 16-bit programs.
@Jimc, in the days of cooperative multitasking, I think SendMessage() was fully synchronous to ensure use-after-free didn’t happen.
Ah, but what concurrency “fun” if either 16-bit sender or receiver decided to modify the data or the sender deallocated it after sending. The joys of a 16-bit OS.
While I would have to do some more research, I don't think the constraints of WM_COPYDATA has changed that much since the early years.
WM_COPYDATA has three major constraints. First, The sender must not modify the buffer until the receiver has finished. Second, the receiver must see the sent data as read only. Third, the data is only guaranteed to exist while the call to SendMessage is in progress, meaning that the receiver must copy the data before it returns or calls ReplyMessage. Finally, the current documentation heavily suggests that this message is only ever used with SendMessage. So if you...
Isn’t that impossible due to the cooperative scheduling?
@Jimc I don’t think the scenario you describe is possible using SendMessage, it blocks until the message is processed at the other end, no?
No. It was very much possible. The hardware of the time was single core CPUs which could only execute one thread at a time. Consequently, only one of the programs would be executing at a time and on Win 3.x they would be sharing cooperatively. This may lead you to think it was safe to transfer data using WM_COPYDATA with the data in memory accessible to both sender and receiver. However, imagine the scenario where sender sends data and then yields. There is no guarantee the data will be received and *processed* before the sender was executed again. At this...