error LNK2019: 無法解析的外部符號 "public: static long __stdcall CMFCApplication2Dlg::JournalRecordProc(...)
**.cpp 定義時保留了 static 關鍵字**,導致函式具有**內部連結**,類別外部 (如 SetWindowsHookEx) 無法取得其位址;且類別宣告為 static 成員函式,定義需加上類別作用域 CMFCApplication2Dlg:: 且**不加 static**。
// ❌ 錯誤:.cpp 中
static LRESULT CALLBACK JournalRecordProc(int nCode, WPARAM wparam, LPARAM lparam) { ... }
// ✅ 正確:.cpp 中
LRESULT CALLBACK CMFCApplication2Dlg::JournalRecordProc(int nCode, WPARAM wparam, LPARAM lparam) {
// 實作...
}
// ✅ 正確:.h 中宣告
class CMFCApplication2Dlg : public CDialogEx {
// ...
static LRESULT CALLBACK JournalRecordProc(int nCode, WPARAM wparam, LPARAM lparam);
static LRESULT CALLBACK JournalPlaybackProc(int nCode, WPARAM wparam, LPARAM lparam);
};
// CMFCApplication2Dlg.h
class CMFCApplication2Dlg : public CDialogEx {
// ...
static LRESULT CALLBACK JournalRecordProc(int nCode, WPARAM wparam, LPARAM lparam);
static LRESULT CALLBACK JournalPlaybackProc(int nCode, WPARAM wparam, LPARAM lparam);
HHOOK hHook;
CList EventMsgList;
};
// CMFCApplication2Dlg.cpp
LRESULT CALLBACK CMFCApplication2Dlg::JournalRecordProc(int nCode, WPARAM wparam, LPARAM lparam) {
if (nCode < 0) return CallNextHookEx(NULL, nCode, wparam, lparam);
EVENTMSG* pmsg = (EVENTMSG*)lparam;
switch (nCode) {
case HC_ACTION: {
EVENTMSG* pEventMsg = new EVENTMSG;
memcpy(pEventMsg, pmsg, sizeof(EVENTMSG));
// 需取得 dlg 實例存取 EventMsgList,可用全域指標或 Thread Local Storage
// 此處略過實際存取邏輯
} break;
// ...
}
return CallNextHookEx(NULL, nCode, wparam, lparam);
}
LRESULT CALLBACK CMFCApplication2Dlg::JournalPlaybackProc(int nCode, WPARAM wparam, LPARAM lparam) {
// 類似實作...
}
void CMFCApplication2Dlg::OnBnClickedButton3() {
hHook = SetWindowsHookEx(WH_JOURNALRECORD,
JournalRecordProc, // 直接用函式名稱,編譯器解析為 &CMFCApplication2Dlg::JournalRecordProc
AfxGetApp()->m_hInstance, 0);
}
void CMFCApplication2Dlg::OnBnClickedButton1() {
hHook = SetWindowsHookEx(WH_JOURNALPLAYBACK,
JournalPlaybackProc,
AfxGetApp()->m_hInstance, 0);
}
JournalRecordProc 為 **靜態成員函式**,無 this 指標,若需存取對話方塊成員 (如 EventMsgList),需透過**全域/靜態指標**指向當前對話方塊實例,或使用 TlsSetValue 存儲實例指標。WH_JOURNALRECORD 為全域鉤子,**必須放在 DLL**,否則僅對當前執行緒有效。上述代碼僅供演示連結修正,**實際全域鉤子需建立獨立 DLL 專案**。