在 64 位和 32 位 (WOW64) 应用程序之间使用 WM_COPYDATA 是不是安全?

Posted

技术标签:

【中文标题】在 64 位和 32 位 (WOW64) 应用程序之间使用 WM_COPYDATA 是不是安全?【英文标题】:Is it safe to use WM_COPYDATA between 64-and 32-bit (WOW64) apps?在 64 位和 32 位 (WOW64) 应用程序之间使用 WM_COPYDATA 是否安全? 【发布时间】:2019-11-07 15:02:31 【问题描述】:

有一个很好的SO关于WM_COPYDATA消息here的一般使用的问答环节,以及关于这是否适用于不同32 /的应用程序的“讨论” 64 位 here。然而,后者似乎专注于可能滥用正在传递的“数据指针”。所以,我在这里提出一个新问题。

我正在努力让两个 Windows 应用程序相互通信/同步,作为第一轮方法,我正在使用 Windows Messaging 来实现这一点。现在一切似乎都还好……但我正在使用WM_COPYDATA 消息在应用程序之间传递信息。

我的问题:当两个应用具有不同 (32/64) 位数时,这种方法是否保证安全?我已经使用下面的代码在“客户端”和“服务器”之间使用 32 与 64 构建的所有四种可能组合进行了一些测试,并且所有工作都按预期工作;但这仅仅是因为我得到了“幸运”的结果(来自可能的未定义行为),还是 WOW64 系统(尤其是当服务器是 64 位而客户端是 32 时)是否负责所有必要的编组?

如果有人可以确认它可以保证工作,我将非常感谢确认这一点的“官方”链接/参考。

共享头文件:

static const WPARAM nmIdFilePath = 0x00001100;

struct nmLockInfoType 
    char filePathID[1024];
    // More elements will be added later!
;
static const nmLockInfoType nmLockInfoDefault = 
    "<<<Uninitialised Image Data Path>>>",
    //...
;
extern nmLockInfoType nmLockInfo; // MUST be provided by each app!
///nmLockInfoType nmLockInfo = nmLockInfoDefault; // Use this code to instatiate it (once, somewhere)!

服务器程序代码(在RegisterWindowMessage(L"HANDSHAKE"); 消息的处理程序内):

//...
COPYDATASTRUCT cds;
cds.dwData = nmIdFilePath;           // Pre-defined ID
cds.cbData = sizeof(nmLockInfoType);
cds.lpData = &nmLockInfo;            // Pre-defined structure (see above)
//...
// Send a copy of the "Welcome Pack" data structure to the client app ...
::SendMessage(clientLock, WM_COPYDATA, WPARAM(m_hWnd), LPARAM(&cds)); // "clientLock is the HWND of the client app's MainWnd

客户端程序代码:

BOOL MyFrame::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)

    switch (pCopyDataStruct->dwData)
    
    case nmIdFilePath:
        memcpy(&nmLockInfo, pCopyDataStruct->lpData, pCopyDataStruct->cbData);
        return nmsSucceeded; // This is NON_ZERO so evaluates to TRUE
    // Other cases here ...
     
    return CMDIFrameWnd::OnCopyData(pWnd, pCopyDataStruct);

我特别关心client是32位而server是64位的情况;在这种情况下,它将向 32 位应用程序(尽管是 WOW64 应用程序)发送 64 位数据地址。内置的“编组”是否在 WOW64 情况下处理此问题?

【问题讨论】:

是的,系统消息会自动编组。但是 WM_COPYDATA 有效负载不会,因为操作系统不知道它包含什么。 char[] 没有问题,程序员通常知道要避免使用指针,因为它们无论如何都不能跨进程工作。 @Hans 好的,从你这里我会把它当作'确定'(我传递的数据结构将从不包含指针,只有“简单”类型)。您愿意发布答案(+ 相关 M/S 文档的链接)吗? 你想让我为一个不存在的问题做所有的工作吗?嗯,我会尝试帮助有实际问题的人。 它按照文档中的描述工作。没有什么可说的了。数据块按您定义的方式复制。由于 MSDN 规范中没有更多说明,因此它与 MSDN 中描述的所有其他功能一样“得到保证”。 @Adrian-ReinstateMonica 对于大数据共享跨进程推荐file mapping,对于小数据共享可能需要使用WM_COPYDATA自行处理数据。 【参考方案1】:

只有当我们遵循如何使用它的规则时它才是安全的。请参考下面WM_COPYDATA消息的备注:

传递的数据不得包含指针其他引用 接收数据的应用程序无法访问对象。

在发送此消息时,引用的数据不得 被发送进程的另一个线程更改

接收应用程序应将数据视为只读。这 lParam 参数仅在消息处理过程中有效。 接收应用程序不应释放所引用的内存 l 参数。如果接收应用程序必须在之后访问数据 SendMessage 返回,它必须将数据复制到本地缓冲区中。

例如,如果我们尝试传递数据类型:ULONG_PTR,那么从 64 位应用程序传递到 32 位应用程序时,数据副本可能无法正常工作。因为它在 32 位应用程序上是 32 位的,在 64 位应用程序上是 64 位的。

您可以通过修改下面的代码来测试它:

struct nmLockInfoType 
char filePathID[1024];
ULONG_PTR point64_32;
// More elements will be added later!
;

上面提到的场景,作为你测试的结果应该是安全的。如果您仍然担心,请随时告诉我。

此外,以下是一份关于开发 64 位应用程序的有用文档供您参考:

Common Visual C++ 64-bit Migration Issues

【讨论】:

以上是关于在 64 位和 32 位 (WOW64) 应用程序之间使用 WM_COPYDATA 是不是安全?的主要内容,如果未能解决你的问题,请参考以下文章

32位系统上的Wow64:还原[重复]

32 位和 64 位应用程序如何共享 HKLM 注册表设置?

WoW64子系统

Wow6432Node(32位程序的注册表内容都在这个节点下,也可直接使用%systemroot%syswow64 egedit进行编辑)

64位系统下注册32位dll文件

Wow64DisableWow64FsRedirection 在 32 位 Windows XP 上