为Windows 3.1改造WM_COPY­DATA消息

The Old New Thing (Raymond Chen) 新闻

摘要

本文解释如何利用共享地址空间,将针对32位Windows引入的WM_COPYDATA消息改造到16位Windows 3.1上,使得16位程序间的通信无需任何更改。

<p>不久前,我讨论了<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">如何从<code>WM_<wbr />COPY­DATA</code>消息返回结果</a>。这让我想起了一段巧妙的历史。</p> <p><code>WM_<wbr />COPY­DATA</code>消息是在32位Windows中引入的。在16位Windows中不需要它,因为所有16位程序都在同一个地址空间中运行。一个进程中的远指针在任何进程中都有效。你可以将其放在窗口消息的<code>lParam</code>中,并发送给任何其他窗口,无论是同一进程还是不同进程,都没关系。但是32位程序运行在独立的地址空间中,因此这个技巧不再适用。因此需要<code>WM_<wbr />COPY­DATA</code>来传递数据,不仅在32位程序之间,还在32位程序和16位程序之间。</p> <p>这个消息是如何被改造到16位Windows中,以便Win32s能够支持它的?</p> <p>很简单:它已经在无意中被实现了。</p> <p>如果源窗口和目标窗口都是16位窗口,那么指向<code>COPY­DATASTRUCT</code>的指针在两个进程中已经有效,<code>COPY­DATASTRUCT</code>内部的指针也是。并且<code>wParam</code>中的窗口句柄对于两个进程也是相同的。因此,不对<code>wParam</code>和<code>lParam</code>做任何处理,只是让它们从16位程序传递到另一个16位程序,仍然会按预期工作。</p> <p>而恰好Windows 3.1已经这样做了:Windows 3.1总是原封不动地传递<code>wParam</code>和<code>lParam</code>,即使消息发送者和接收者位于不同的进程中,因为所有程序共享相同的地址空间。</p> <p>这只是一种巧妙的设计:将<code>WM_<wbr />COPY­DATA</code>消息设计成当在16位程序之间发送时,空编组器就是正确的行为。</p> <p>本文《<a href="https://devblogs.microsoft.com/oldnewthing/20260616-00/?p=112430">为Windows 3.1改造<code>WM_<wbr />COPY­DATA</code>消息</a>》最先出现在<a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>上。</p>
查看原文
查看缓存全文

缓存时间: 2026/06/17 12:54

# 将 WM_COPYDATA 消息反向移植到 Windows 3.1 - 《The Old New Thing》 来源:https://devblogs.microsoft.com/oldnewthing/20260616-00?p=112430 不久前,我讨论过如何从 `WM_COPYDATA` 消息返回结果(https://devblogs.microsoft.com/oldnewthing/20251114-00/?p=111792)。这让我想起了一段巧妙的历史。 `WM_COPYDATA` 消息是在 32 位 Windows 中引入的。16 位 Windows 并不需要它,因为所有 16 位程序都运行在同一个地址空间中。一个远指针在一个进程中有效,在所有进程中也同样有效。你可以把它放在窗口消息的 `lParam` 中,发送给任何其他窗口,无论是同一进程还是不同进程,都没有关系。但 32 位程序运行在独立的地址空间中,因此这个技巧行不通。于是就需要 `WM_COPYDATA` 来在 32 位程序之间以及 32 位程序与 16 位程序之间传递数据。 那么,这个消息是如何被反向移植到 16 位 Windows 中,以便 Win32s 能够支持它的呢? 很简单:它实际上已经被实现了,只是无意中而已。 如果源窗口和目标窗口都是 16 位窗口,那么指向 `COPYDATASTRUCT` 的指针在两个进程中都已经有效,`COPYDATASTRUCT` 内部的指针也是如此。`wParam` 中的窗口句柄在两个进程中也相同。因此,对 `wParam` 和 `lParam` 不做任何处理,只是简单地让它们从 16 位程序传递到另一个 16 位程序,仍然会按预期工作。 而恰好 Windows 3.1 已经做到了这一点:Windows 3.1 总是原封不动地传递 `wParam` 和 `lParam`,即使消息发送者和接收者位于不同的进程中,也是如此,因为所有程序共享同一个地址空间。 这只是一个巧妙的把戏:设计 `WM_COPYDATA` 消息时,使得在 16 位程序之间发送时,空编组器就是正确的行为。 ### 分类 ### 主题 ## 作者 Raymond Chen Raymond 参与 Windows 的发展已有 30 多年。2003 年,他创办了一个名为 The Old New Thing 的网站,其受欢迎程度远超他最疯狂的想象,这一发展至今仍让他感到不安。该网站还衍生出一本书,巧合的是书名也叫《The Old New Thing》(Addison Wesley 2007 年出版)。他偶尔会出现在 Windows Dev Docs 的 Twitter 账号上,讲述一些毫无用处的故事。

相似文章

如何在Windows运行时中使用Win32结构?

The Old New Thing (Raymond Chen)

本文解释了如何通过声明具有相同布局的影子结构在Windows运行时中使用Win32结构,包括具体示例和常见结构的替代方案。

如何告知Windows我正在写入二进制文件?

The Old New Thing (Raymond Chen)

本文解释了Windows在操作系统层面并没有内置二进制与文本模式的概念;这种区别是由运行时库(如C运行时)处理的。它澄清了Windows将所有文件视为字节,内容转换必须手动执行或通过库来完成。

在64位Alpha AXP Windows NT上的Pinball

Lobsters Hottest

探讨了Windows内置Pinball游戏的历史、导致其无法在64位Windows(特别是Alpha AXP版本)上运行的碰撞检测Bug,以及近期模拟技术突破使得稀有的64位Alpha NT构建能够运行该游戏。