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

Win32 COM 實戰:建立通用 ActiveX 事件接收器響應 Dispatch 介面事件

     編輯:組合語言

ActiveX 控件透過連接點(Connection Point)機制發送事件。本文實作一個通用事件接收器 CGeneralEventSink,能自動枚舉控件所有連接點,針對繼承自 IDispatch 的事件介面(Dispatch 事件)動態建立接收器並建立連線,無需為每種控件撰寫專屬事件類別。

核心 COM 介面回顧

  • IConnectionPointContainer:控件實作,枚舉其支援的所有 IConnectionPoint。
  • IConnectionPoint:代表一組事件。Advise(pSink) 註冊接收器;GetConnectionInterface 回傳接收器必須實作的介面 IID。
  • 事件介面若繼承 IDispatch,控件透過 IDispatch::Invoke(dispid, ...) 觸發事件,而非直接呼叫 vtable 函數。

通用接收器實作關鍵點

1. 動態枚舉與 Advise


HRESULT AxAdviseAll(IUnknown *pUnk) {
    IConnectionPointContainer *pContainer;
    IEnumConnectionPoints *pEnum;
    pUnk->QueryInterface(IID_IConnectionPointContainer, (void**)&pContainer);
    pContainer->EnumConnectionPoints(&pEnum);
    IConnectionPoint *pCP;
    ULONG uFetched;
    while (S_OK == pEnum->Next(1, &pCP, &uFetched) && uFetched) {
        IID iid; pCP->GetConnectionInterface(&iid);
        IUnknown *pSink = new CGeneralEventSink(iid, pUnk); // 傳入控件指標用於取得 TypeInfo
        pCP->Advise(pSink, &dwCookie);
        pSink->Release(); pCP->Release();
    }
    // ... 清理 ...
}

2. 判斷是否為 Dispatch 介面

建構子中取得事件介面的 ITypeInfo,檢查 TYPEATTR::typekind == TKIND_DISPATCH。非 Dispatch 介面則設 m_iid = IID_NULL,導致 Advise 失敗,避免 vtable 呼叫錯誤。

3. QueryInterface 動態支援目標 IID


STDMETHOD(QueryInterface)(REFIID riid, void **ppv) {
    *ppv = NULL;
    if (riid == IID_IUnknown) *ppv = (IUnknown*)this;
    else if (riid == IID_IDispatch || riid == m_iid) *ppv = (IDispatch*)this;
    else return E_NOINTERFACE;
    AddRef(); return S_OK;
}

關鍵:宣稱支援控件要求的 m_iid,但實際僅實作 IDispatch vtable。控件呼叫 Invoke 時會查詢 DISPID,我們在 Invoke 中解析並記錄日誌。

4. 取得介面 TypeInfo 與 DISPID 對應名稱

  • 控件實作 IProvideClassInfo → 取得類別 ITypeInfo。
  • ITypeInfo::GetRefTypeOfImplType + GetRefTypeInfo → 取得事件介面 ITypeInfo。
  • 枚舉 FUNCDESC 取得 memid (DISPID) 對應函數名稱,建立查找表供 Invoke 記錄使用。
  • 從登錄檔 HKCR\Interface\{IID} 解析介面易讀名稱。

5. Invoke 實作

所有 IDispatch 方法回傳 E_NOTIMPL,僅 Invoke 解析 dispid、參數並輸出詳細日誌(介面名、方法名、參數值),滿足「被動通知」需求。

應用範例:Flash 控件事件

Flash 事件介面 _IShockwaveFlashEvents : IDispatch 包含 OnReadyStateChange, FSCommand, FlashCall 等。使用本通用接收器即可自動捕獲並記錄所有事件觸發細節,無需手寫 _IShockwaveFlashEvents 實作類別。

原始碼下載:files.cnblogs.com/Greatest/TestActiveX2.zip

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved