64位进程和32位进程通信问题,接收方接收到的数据错误

项目场景:

最近遇到一个问题,64位程序向32位程序发送一个WM_COPYDATA消息传递指针字符串, 发现传递的数据和收到的数据不一致。同样代码,64位程序编译成32位再发送消息的话,能正常收到数据。


问题描述

接收方和发送方的主体代码如下

发送方(64位程序)

// 消息构造体
typedef struct tagCOPYDATASTRUCT {
    ULONG_PTR dwData; //用户定义数据
    DWORD cbData; //用户定义数据的长度
    __field_bcount(cbData) PVOID lpData; //指向用户定义数据的指针
} COPYDATASTRUCT, *PCOPYDATASTRUCT;
// 消息发送函数实现
void CSendDlg::OnDataSend()
{
    CWnd *pWnd = CWnd::FindWindow(NULL,"接收窗口的标题");

    TCHAR msg[255] = "HELLO";
    COPYDATASTRUCT cpd;
    cpd.dwData = 0;
    cpd.cbData = 255 + 1;//多加一个长度,防止乱码
    cpd.lpData = @msg;
    pWnd->SendMessage(WM_COPYDATA,NULL,(LPARAM)&cpd);
}

接收方(32位程序)

// 声明
afx_msg BOOLOnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct);

// 添加消息映射
ON_WM_COPYDATA()

// 函数实现
BOOL CReceiveDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值

	//return CDialogEx::OnCopyData(pWnd, pCopyDataStruct);

	TCHAR msgReceive[256];
	memset(msgReceive, 0, sizeof(msgReceive));
	wcscpy_s(msgReceive, (TCHAR*)pCopyDataStruct->lpData);

	return CDialogEx::OnCopyData(pWnd, pCopyDataStruct);
}

原因分析:

这个问题是因为64位程序和32位程序在内存地址表示上的差异导致的。在64位程序中指针的大小是8字节,而在32位程序中指针的大小是4字节。当64位程序试图将一个指针发送给32位程序时,它实际上只发送了指针的低4字节,而高4字节则被截断,即指针截断。

假设我们有一个64位指针 0x12345678abcdefgh,这个指针在传递给32位程序时,会被截断为32位指针 0x12345678。这意味着,原本在64位程序中通过该指针可以访问到的内存地址,在32位程序中只能访问到 0x12345678 对应的内存地址。因此,如果32位程序试图通过这个截断后的指针来访问原本64位程序可以访问到的内存地址,就可能会发生访问越界的错误。

在16进制表示法中,一个4字节的指针地址通常表示为8个十六进制数字的序列(每个字节是2个十六进制数字)


解决方案:

可以考虑改变设计,避免直接在消息中传递指针,而是选择传递其他类型的数据。

你可能感兴趣的:(进程通信,c++)