每天面對 Word 內建的幾個 Office Assistant(如回形針 Clippy),久而久之難免感到乏味。Microsoft Agent 技術提供了豐富的動畫角色(如 Merlin、Genie、Robby 等),並支援語音輸出、氣球提示等互動方式。本文示範如何透過全域鉤子攔截 Word 視窗訊息,並結合 COM 技術在 Word 中嵌入 MSAgent 角色,實現自訂的功能提示與互動。
#pragma data_seg(".SHARED")),儲存被監視程序(Word)的視窗控制代碼 gs_hClient、伺服器視窗控制代碼 gs_hServer、DLL 實例句柄 g_hInst 及鉤子句柄 g_hHook。SetWindowsHookEx(WH_CALLWNDPROC, MsgHookProc, g_hInst, threadId),針對 Word 所在執行緒安裝「呼叫視窗程序」鉤子。MsgHookProc 接收 CWPSTRUCT*(指向 MSG 結構),篩選感興趣的訊息(如 WM_DESTROY),轉發給伺服器視窗處理。CoInitialize),建立 IAgent、IAgentCharacter 介面,載入角色檔(.acs),播放動畫、顯示氣球提示。#pragma data_seg(".SHARED")
HWND gs_hClient = NULL; // 被監視程序視窗 (Word)
HWND gs_hServer = NULL; // 處理訊息的伺服器視窗
HINSTANCE g_hInst;
HHOOK g_hHook;
#pragma data_seg()
#pragma comment(linker, "/SECTION:.SHARED,RWS")
// 安裝鉤子
g_hHook = ::SetWindowsHookEx(
WH_CALLWNDPROC,
(HOOKPROC)MsgHookProc,
g_hInst,
::GetWindowThreadProcessId(gs_hClient, NULL)
);
LRESULT CALLBACK MsgHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode >= 0) {
LPMSG pMsg = (LPMSG)lParam;
if (pMsg->message == WM_DESTROY) {
// 轉發給伺服器視窗,觸發 MSAgent 反應
::SendMessage(gs_hServer, pMsg->message, pMsg->wParam, pMsg->lParam);
}
}
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
// 伺服器視窗訊息處理中
CoInitialize(NULL);
IAgent* pAgent;
CoCreateInstance(CLSID_Agent, NULL, CLSCTX_INPROC_SERVER,
IID_IAgent, (void**)&pAgent);
pAgent->Load(...); // 載入角色
IAgentCharacter* pChar;
pAgent->GetCharacter(...); // 取得角色介面
pChar->Show(...); // 顯示角色
pChar->Speak(...); // 說話/顯示氣球
// ... 互動邏輯 ...
pChar->Release();
pAgent->Release();
CoUninitialize();
WM_COMMAND、WM_NOTIFY、選單選取等)。gs_hClient 有效。WM_COMMAND),在使用者點選「儲存」時由 Agent 提醒「別忘了備份!」