底層硬體開發、即時資料接收等場景中,DLL 需主動通知 EXE 處理結果。自訂訊息是最標準、解耦的方式。本文詳細說明 EXE 內部自訂訊息與 DLL→EXE 跨模組訊息傳遞的完整實作步驟。
在 stdafx.h 或 View/Dialog 標頭檔:
#define WM_MYMSG (WM_USER + 101) // 保留 WM_USER~WM_USER+100 給系統控件
// CMyView.h / CTestMessageDLLDlg.h
protected:
// {{AFX_MSG(CMyView)
afx_msg LRESULT OnMyMsg(WPARAM wParam, LPARAM lParam);
// }}AFX_MSG
DECLARE_MESSAGE_MAP()
BEGIN_MESSAGE_MAP(CMyView, CView)
// {{AFX_MSG_MAP(CMyView)
ON_MESSAGE(WM_MYMSG, OnMyMsg)
// }}AFX_MSG_MAP
END_MESSAGE_MAP()
LRESULT CMyView::OnMyMsg(WPARAM wParam, LPARAM lParam)
{
AfxMessageBox(_T("收到自訂訊息!"));
return 0;
}
::PostMessage(hWnd, WM_MYMSG, 0, 1); // 非同步,不等待
// 或
::SendMessage(hWnd, WM_MYMSG, 0, 1); // 同步,等待處理完成
關鍵差異:DLL 與 EXE 必須定義相同訊息值,且 EXE 需將接收視窗句柄 HWND 傳給 DLL。
// stdafx.h (DLL 專案)
#define WM_MYMSG (WM_USER + 102) // 與 EXE 完全一致
// MessageDLL.h
class CMessageDLLApp : public CWinApp
{
public:
void SendMessage(HWND hWnd); // 匯出函數實作
};
// MessageDLL.cpp
CMessageDLLApp theApp;
extern "C" __declspec(dllexport) void StartSendMessage(HWND hWnd)
{
theApp.SendMessage(hWnd);
}
void CMessageDLLApp::SendMessage(HWND hWnd)
{
::PostMessage(hWnd, WM_MYMSG, 0, 1);
}
// stdafx.h (EXE 專案) - 訊息值必須相同
#define WM_MYMSG (WM_USER + 102)
// CTestMessageDLLDlg.h - 同樣宣告 OnMyMsg、ON_MESSAGE 映射
// 對話框按鈕點擊:動態載入 DLL 並呼叫
void CTestMessageDLLDlg::OnBnClickedButton1()
{
typedef void (_cdecl* STARTSENDMESSAGE)(HWND);
HMODULE hDll = LoadLibrary(_T("MessageDLL.dll"));
if (!hDll) { AfxMessageBox(_T("載入 DLL 失敗")); return; }
STARTSENDMESSAGE pfn = (STARTSENDMESSAGE)GetProcAddress(hDll, "StartSendMessage");
if (!pfn) { FreeLibrary(hDll); AfxMessageBox(_T("取得函數位址失敗")); return; }
HWND hWnd = GetSafeHwnd();
pfn(hWnd); // 呼叫 DLL 匯出函數,DLL 內部 PostMessage 給此視窗
FreeLibrary(hDll);
}
| 項目 | 說明 |
|---|---|
| 訊息值定義 | DLL/EXE 完全一致,建議用共用標頭檔避免不一致 |
| HWND 傳遞 | EXE 必須將接收視窗句柄傳給 DLL(透過匯出函數參數) |
| 呼叫約定 | 匯出函數建議用 __cdecl 或 __stdcall 明確指定 |
| PostMessage vs SendMessage | PostMessage 非阻塞;SendMessage 同步阻塞,跨模組慎用避免死結 |
| 錯誤處理 | LoadLibrary/GetProcAddress 必須檢查回傳值 |
RegisterWindowMessage 取得系統唯一訊息 ID,避免衝突。IsWindow(hWnd)。WM_COPYDATA 或共享記憶體配合訊息通知。自訂訊息是 DLL/EXE 解耦通訊的基石。掌握「定義相同訊息值、傳遞 HWND、動態載入 DLL 呼叫匯出函數」三步驟,即可靈活實現模組間非同步通知。