首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

Microsoft Agent COM 介面程式設計:從初始化到事件接收完整實作

     編輯:關於C語言

Microsoft Agent 提供動畫角色互動,支援語音輸出、動作控制。本文介紹純 COM 介面程式設計 (不使用 ActiveX 控制項),涵蓋 `CoCreateInstance` 建立 Agent 伺服器、`IAgent::Load` 載入角色、`IAgentCharacter::Show/Speak/MoveTo` 控制角色、`IAgentNotifySink` 接收事件,並提供版本檢查與資源釋放完整流程。

必要準備

  • 標頭/庫:`AgtSvr.h`、`AgtSvr_i.c` (含 `CLSID_AgentServer`、`IID_IAgent`),來自 Microsoft Agent SDK
  • 連結:`ole32.lib` `oleaut32.lib` `uuid.lib` `odbc32.lib` `odbccp32.lib`
  • 系統需安裝 Microsoft Agent 核心與角色檔 (`.acs`)

核心流程代碼


// 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();

版本檢查函數 IsValidAgentVersion


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;
}

事件接收:實作 IAgentNotifySink

  • SDK 提供 `Notify.h`/`Notify.cpp` 預設實作,需覆寫關心的事件
  • 關鍵事件:`OnClick`、`OnDblClick`、`OnDragStart/Complete`、`OnKeyPress`、`OnCommand` (角色選單命令)、`OnMove`、`OnRequestStart/Complete` (非同步命令完成)
  • 註冊:`pAgent->Register(pSink, &lSinkID)`,註銷:`pAgent->Unregister(lSinkID)`

字串處理提醒

  • 所有傳入 COM 的字串必須用 `SysAllocString` 配置 `BSTR` (Unicode),用完 `SysFreeString`
  • `VARIANT` 傳遞字串時 `vt = VT_BSTR`,`bstrVal` 指向 `BSTR`
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved