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

Is it safe to use WM_COPYDATA between 64-and 32-bit (WOW64) apps?

有一个很好的SO Q/A session 关于一般使用WM_COPYDATA 消息here, and a 'discussion' about whether or not this will work between apps of different 32/64-bitness here。然而,后者似乎专注于可能滥用 'data pointer' 被传递。所以,我在这里提出一个新问题。

我正在努力让两个 Windows 应用程序相互 communicate/synchronize,作为第一轮方法,我正在使用 Windows 消息来实现它。目前一切 似乎 都正常……但我正在使用 WM_COPYDATA 消息在应用程序之间传递信息。

我的问题:当两个应用程序有不同的(32/64)位数?我已经使用下面的代码对 'client' 和 'server' 之间的 32 与 64 构建的所有四种可能组合进行了一些测试,并且所有工作都按预期进行;但这仅仅是因为我得到 'lucky' 结果(来自可能的未定义行为),还是 WOW64 系统(特别是当服务器是 64 位且客户端是 32 位时)处理所有必要的编组?

如果有人能确认它一定能正常工作,我将非常感激 'official' link/reference 确认。

共享头文件:

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 位数据地址。内置 'marshalling' 是否在 WOW64 情况下处理此问题?

遵守使用规范才是安全的。请参考下方WM_COPYDATA留言的备注:

The data being passed must not contain pointers or other references to objects not accessible to the application receiving the data.

While this message is being sent, the referenced data must not be changed by another thread of the sending process.

The receiving application should consider the data read-only. The lParam parameter is valid only during the processing of the message. The receiving application should not free the memory referenced by lParam. If the receiving application must access the data after SendMessage returns, it must copy the data into a local buffer.

例如,如果我们尝试传递数据类型: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