Microsoft Agent 提供動畫角色互動,支援語音輸出、動作控制。本文介紹純 COM 介面程式設計 (不使用 ActiveX 控制項),涵蓋 `CoCreateInstance` 建立 Agent 伺服器、`IAgent::Load` 載入角色、`IAgentCharacter::Show/Speak/MoveTo` 控制角色、`IAgentNotifySink` 接收事件,並提供版本檢查與資源釋放完整流程。
// 1. 初始化 COM
if (FAILED(OleInitialize(NULL))) return -1;
// 2. 建立 Agent 伺服器實例
IAgent* pAgent = NULL;
HRESULT hr = CoCreateInstance(CLSID_AgentServer, NULL, CLSCTX_SERVER,
IID_IAgent, (LPVOID*)&pAgent);
if (FAILED(hr)) { OleUninitialize(); return -1; }
// 3. 檢查版本 (可選但建議)
if (!IsValidAgentVersion(pAgent)) { pAgent->Release(); OleUninitialize(); return -1; }
// 4. 載入角色
VARIANT vPath; VariantInit(&vPath);
vPath.vt = VT_BSTR;
vPath.bstrVal = SysAllocString(L"C:\\Windows\\MsAgent\\Chars\\Merlin.acs"); // 路徑
long lCharID, lReqID;
hr = pAgent->Load(vPath, &lCharID, &lReqID);
SysFreeString(vPath.bstrVal);
if (FAILED(hr)) { pAgent->Release(); OleUninitialize(); return -1; }
// 5. 取得角色介面
IDispatch* pDisp = NULL;
hr = pAgent->GetCharacter(lCharID, &pDisp);
IAgentCharacter* pChar = NULL;
if (SUCCEEDED(hr)) hr = pDisp->QueryInterface(IID_IAgentCharacter, (LPVOID*)&pChar);
if (pDisp) pDisp->Release();
if (FAILED(hr) || !pChar) { pAgent->Unload(lCharID); pAgent->Release(); OleUninitialize(); return -1; }
// 6. 控制角色
pChar->Show(VARIANT_TRUE, &lReqID); // 顯示
pChar->MoveTo(320, 240, 100, &lReqID); // 移動至螢幕中心
BSTR bstr = SysAllocString(L"Hello, World!");
pChar->Speak(bstr, NULL, &lReqID); // 說話
SysFreeString(bstr);
// 7. 註冊事件接收 (IAgentNotifySink)
IAgentNotifySink* pSink = new CAgentNotifySink(); // 自訂類別繼承 IAgentNotifySink
pSink->AddRef();
long lSinkID;
pAgent->Register((IUnknown*)pSink, &lSinkID);
// ... 程式主迴圈 ...
// 8. 清理
if (pSink) { pAgent->Unregister(lSinkID); pSink->Release(); }
if (pChar) { pChar->Release(); pAgent->Unload(lCharID); }
pAgent->Release();
VariantClear(&vPath);
OleUninitialize();
BOOL IsValidAgentVersion(IAgent* pAgent) {
IDispatch* pDisp = NULL;
ITypeInfo* pTI = NULL;
ITypeLib* pTL = NULL;
TLIBATTR* pTLA = NULL;
BOOL bValid = FALSE;
pAgent->QueryInterface(IID_IDispatch, (LPVOID*)&pDisp);
pDisp->GetTypeInfo(0, 0, &pTI);
pTI->GetContainingTypeLib(&pTL, NULL);
pTL->GetLibAttr(&pTLA);
// AGENT_VERSION_MAJOR/MINOR 定義於 AgtSvr.h
if (pTLA->wMajorVerNum > AGENT_VERSION_MAJOR ||
(pTLA->wMajorVerNum == AGENT_VERSION_MAJOR &&
pTLA->wMinorVerNum >= AGENT_VERSION_MINOR))
bValid = TRUE;
if (pTL) { if (pTLA) pTL->ReleaseTLibAttr(pTLA); pTL->Release(); }
if (pTI) pTI->Release();
if (pDisp) pDisp->Release();
return bValid;
}