{"id":112430,"date":"2026-06-16T07:00:00","date_gmt":"2026-06-16T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=112430"},"modified":"2026-06-16T20:08:09","modified_gmt":"2026-06-17T03:08:09","slug":"20260616-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20260616-00\/?p=112430","title":{"rendered":"Retrofitting the <CODE>WM_<WBR>COPY&shy;DATA<\/CODE> message onto Windows 3.1"},"content":{"rendered":"<p>Some time ago, I talked about <a title=\"I can use WM_COPYDATA to send a block of data to another window, but how does it send data back?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20251114-00\/?p=111792\"> how to return results back from the <code>WM_<wbr \/>COPY\u00adDATA<\/code> message<\/a>. Which reminded me of a clever bit of history.<\/p>\n<p>The <code>WM_<wbr \/>COPY\u00adDATA<\/code> 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 <code>lParam<\/code> of a window message and send it to any other window, same process or different process, doesn&#8217;t matter. But 32-bit programs ran in separate address spaces, so this trick didn&#8217;t work. Hence the need for <code>WM_<wbr \/>COPY\u00adDATA<\/code> to pass data not only between 32-bit programs, but also between 32-bit programs and 16-bit programs.<\/p>\n<p>How did this message get retrofitted into 16-bit Windows so that Win32s could support it?<\/p>\n<p>Easy: It was already implemented, unwittingly.<\/p>\n<p>If the source and destination windows are both 16-bit windows, then the pointer to the <code>COPY\u00adDATA\u00adSTRUCT<\/code> is already valid in both processes, as is the pointer inside the <code>COPY\u00adDATA\u00adSTRUCT<\/code>. And the window handle in the <code>wParam<\/code> is also the same for both processes. Therefore, doing absolutely nothing with the <code>wParam<\/code> and <code>lParam<\/code> and simply allowing it to pass from a 16-bit program to another 16-bit program will still behave as expected.<\/p>\n<p>And it so happens that Windows 3.1 already did that: Windows 3.1 always passed the <code>wParam<\/code> and <code>lParam<\/code> unmodified, even when the message sender and receiver are in different processes, because all programs shared the same address space.<\/p>\n<p>It was just a sneaky trick to design the <code>WM_<wbr \/>COPY\u00adDATA<\/code> message in such a way that the null marshaler is the correct behavior when it is sent between 16-bit programs.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>It was carefully designed to be trivial.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[26],"class_list":["post-112430","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-other"],"acf":[],"blog_post_summary":"<p>It was carefully designed to be trivial.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/112430","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=112430"}],"version-history":[{"count":1,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/112430\/revisions"}],"predecessor-version":[{"id":112431,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/112430\/revisions\/112431"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=112430"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=112430"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=112430"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}