問題
在一次開發中,需要使用到WM_COPYDATA方式來實作兩個程序之間的資料傳輸。在網絡上可以找到很多關于WM_COPYDATA的示例代碼,而且代碼結構也比較簡單易懂,是以WM_COPYDATA的示例代碼不是今天要詳細讨論的内容。
今天的問題存在于兩個不同權限的程序,例如發送端程序運作在普通使用者賬戶下,而接收端程序則運作在管理者賬戶下。在這種情況下,發送端發送的WM_COPYDATA消息,将不會被目标程序的視窗所接收到。
我們先來簡單看一下WM_COPYDATA的發送端和接收端的示例代碼
發送端代碼

接收端代碼
解決方法
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攜帶的資料後,将其拷貝到本地緩沖區中,防止發送端資料無效。