实战经验:WM_COPYDATA在不同权限进程中的接收问题

实战经验:WM_COPYDATA在不同权限进程中的接收问题

作者:BlogUpdater |  时间:2019-05-25 |  浏览:1623 |  评论已关闭 条评论

问题
在一次开发中,需要使用到WM_COPYDATA方式来实现两个进程之间的数据传输。在网络上可以找到很多关于WM_COPYDATA的示例代码,而且代码结构也比较简单易懂,所以WM_COPYDATA的示例代码不是今天要详细讨论的内容。
今天的问题存在于两个不同权限的进程,例如发送端进程运行在普通用户账户下,而接收端进程则运行在管理员账户下。在这种情况下,发送端发送的WM_COPYDATA消息,将不会被目标进程的窗口所接收到。

我们先来简单看一下WM_COPYDATA的发送端和接收端的示例代码

发送端代码

int arrData[] = {1, 2, 3, 4, 5};
COPYDATASTRUCT  stCopyData;
stCopyData.dwData = 0;
stCopyData.cbData = sizeof(arrData);
stCopyData.lpData = arrData;
SendMessage(hTargetWnd, WM_COPYDATA, NULL, 
		reinterpret_cast<LPARAM>(&stCopyData));

接收端代码

void OnCopyData(WPARAM wParam, LPARAM lParam)
{
	COPYDATASTRUCT * pCopyData = reinterpret_cast<COPYDATASTRUCT *>(lParam);
	int * pData = reinterpret_cast<int *>(pCopyData->lpData);
	// TODO: Deal with data
}

解决方法
Windows Vista开始,微软引入一个安全机制:UIPI(User Interface Privilege Isolation)。此安全机制阻止低级别权限进程发送消息至高权限进程。但是,“只读”类消息不受此安全机制影响,例如用于获取目标窗口文本的消息WM_GETTEXT可以发送,但是用于设置文本的消息WM_SETEXT则会受到UIPI的影响。

为了解决上述WM_COPYDATA在高权限进程中收不到的问题,可以在接收端进程中调用ChangeWindowMessageFilterEx函数允许WM_COPYDATA通过目标窗口的消息过滤器。

具体调用方式如下所示:
ChangeWindowMessageFilterEx(hTargetWnd, WM_COPYDATA, MSGFLT_ALLOW, NULL);

此函数的作用:修改UIPI(User Interface Privilege Isolation)消息过滤器。
第一个参数:目标窗口句柄,表示此窗口的消息过滤器即将被修改。
第二个参数:标识具体是哪一个消息被允许或阻止,这里是WM_COPYDATA。
第三个参数:标识修改类型:允许/阻止/重置。
第四个参数:一个指向CHANGEFILTERSTRUCT结构体的指针,此结构体可以用来返回一些关于执行结果的信息。

总结
使用WM_COPYDATA消息,需要注意以下几点:
1) 使用WM_COPYDATA发送的数据中,不可以包含目标进程访问不了的对象指针或者引用。
2) 在发送WM_COPYDATA时,发送的数据不应该被发送进程的另一个线程修改。
3) 接收端进程应该视WM_COPYDATA携带的数据为只读,原则上,接收端进程不应该修改WM_COPYDATA携带的数据。
4) 发送端需要使用SendMessage函数来进行同步发送,防止数据离开作用域后销毁,进而导致接收端收到无效数据。
5) 建议接收端收到WM_COPYDATA携带的数据后,将其拷贝到本地缓冲区中,防止发送端数据无效。

标签:

评论已关闭。