| 特性 | PostMessage | SendMessage |
|---|---|---|
| 模式 | **異步** (非阻塞) | **同步** (阻塞) |
| 返回時機 | 消息入隊列**立即返回** | 目標窗口進程**處理完畢**後返回 |
| 消息流向 | 投遞到目標線程**消息隊列** | 直接調用目標窗口**窗口過程** |
| 返回值 | BOOL (是否成功入隊) | LRESULT (目標窗口處理結果) |
| 跨線程行為 | 線程繼續執行,目標線程稍後處理 | 發送線程**阻塞**,直到目標線程處理完 (需目標線程有消息泵) |
| 典型用途 | 通知、觸發不關心結果的操作、避免死鎖 | 需要立即獲得結果、狀態同步、UI 強制刷新 |
// PostMessage
BOOL PostMessage(
HWND hWnd, // 目標窗口句柄,HWND_BROADCAST=廣播
UINT Msg, // 消息 ID
WPARAM wParam, // 參數 1
LPARAM lParam // 參數 2
);
// SendMessage
LRESULT SendMessage(
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam
);
hWnd 特殊值HWND_BROADCAST (0xFFFF):發送/投遞給**所有頂層窗口** (含不可見、非擁有、彈出式),**不含子窗口**。NULL:PostMessage 相當於 PostThreadMessage(GetCurrentThreadId(), ...);SendMessage 不常用 NULL。#include
int main() {
HWND hWnd = FindWindow(NULL, L"QQ2010"); // 類名/標題
if (hWnd) SendMessage(hWnd, WM_CLOSE, 0, 0);
return 0;
}
// 拉下列表
SendMessage(hCombo, CB_SHOWDROPDOWN, TRUE, 0);
// 收起列表
SendMessage(hCombo, CB_SHOWDROPDOWN, FALSE, 0);
SendMessage(hEdit, WM_COPY, 0, 0);
SendMessage(hEdit, WM_CUT, 0, 0);
SendMessage(hEdit, WM_PASTE, 0, 0);
// 發送端
std::string str = "VC知識庫";
COPYDATASTRUCT cds = { 0, (DWORD)str.size()+1, (PVOID)str.c_str() };
SendMessage(hTarget, WM_COPYDATA, (WPARAM)hSource, (LPARAM)&cds);
// 接收端 (窗口過程)
case WM_COPYDATA: {
COPYDATASTRUCT *p = (COPYDATASTRUCT*)lParam;
std::string recv((char*)p->lpData, p->cbData);
// 處理數據...
return TRUE;
}
注意: SendMessage 配合 WM_COPYDATA 可確保接收端讀完前發送端不釋放緩衝區。
SendMessage 給自身或同進程其他 UI 線程,若目標線程正等待發送線程的鎖 → **死鎖**。PostMessage 或 SendMessageTimeout。PostMessage`/`SendNotifyMessage` 發送**系統保留消息 (WM_USER 以下)**時,**不能**在 wParam/lParam 傳遞指針 (內存可能在目標處理前被釋放)。
→ 解決:自定義消息 >= WM_USER,或用 WM_COPYDATA、共享內存。WM_COPYDATA、管道、共享內存、RPC 等。SendMessage 要求目標線程運行消息循環 (GetMessage/DispatchMessage);純工作線程無消息泵會導致發送線程永久阻塞。PostThreadMessage + 自定義消息處理,或建立隱藏窗口跑消息泵。HWND_BROADCAST` 配合 `SendMessage` 會**依次阻塞等待每個頂層窗口處理**,極易導致系統假死。
→ 解決:廣播**只用** PostMessage,並註冊唯一消息 RegisterWindowMessage。postMessage 補充瀏覽器端 window.postMessage(data, targetOrigin) 實現**跨文檔/跨域通信** (Cross-Document Messaging),屬異步,類似 PostMessage。監聽:
window.addEventListener('message', e => {
if (e.origin !== 'https://trusted.com') return; // 安全校驗
console.log('收到:', e.data);
});
支持 IE8+, Firefox 3+, Chrome 3+, Safari 4+, Opera 9+。
PostMessage** — 非阻塞、解耦、避免死鎖。SendMessage,並考慮 SendMessageTimeout 設置超時防卡死。RegisterWindowMessage 獲取全局唯一 ID,避免衝突。WM_COPYDATA (小數據) 或 共享內存/命名管道 (大數據)。PostMessage = **發並忘** (異步);SendMessage = **發並等** (同步)。理解二者在**線程模型、消息隊列、阻塞語義**上的本質差異,是 Windows GUI 程序穩健、高效的基石。