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

COM 可連接物件深度解析:事件、連接點、接收器與 IDispatch 實戰

     編輯:關於C++

前言

COM 可連接物件 (Connectable Objects) 實現了物件與客戶端的雙向通訊:物件主動觸發事件、通知或請求,客戶端透過實作輸出介面 (接收器) 來響應。本文系統闡述 COM 高階特性、入/出介面、連接點架構、枚舉器、事件激發、IDispatch 晚期繫結與 MFC 實作支援。

一、COM 高階特性概覽

  • 可連接物件 (雙向通訊)
  • 持久化儲存
  • 一致性資料傳輸
  • 這些是 OLE/ActiveX 基礎,廣泛應用於 Windows 系統

二、核心概念辨析

三、可連接物件架構

1. 連接點容器 IConnectionPointContainer

  • 物件實作此介面管理所有出介面
  • EnumConnectionPoints → 列舉所有連接點
  • FindConnectionPoint → 依 IID 尋找特定連接點

2. 連接點 IConnectionPoint

  • 每個出介面對應一個連接點物件
  • 管理與該介面相關的所有接收器連接
  • Advise / Unadvise : 建立/移除連接 (返回 Cookie)
  • EnumConnections : 列舉現有連接

3. 兩層枚舉器架構

來源物件
  └─ IConnectionPointContainer
       └─ 連接點枚舉器 (IEnumConnectionPoints)
            ├─ 連接點 A (IConnectionPoint) → 連接枚舉器 (IEnumConnections) → 接收器 1, 2...
            └─ 連接點 B (IConnectionPoint) → 連接枚舉器 → 接收器 3...

分離連接點物件提供獨立性與擴展性。

四、事件激發與處理流程

  1. 來源物件內部邏輯決定觸發事件
  2. 遍歷連接點的所有接收器
  3. 呼叫接收器對應的出介面方法
  4. 跨程序/跨機器時經由 Proxy/Stub 封送 (符合 COM 執行緒模型)
  5. 單執行緒模型 (STA) 下直接呼叫

五、IDispatch 作為通用出介面

動機

  • 靜態出介面需編譯期綁定 vtable,腳本語言/動態語言難以支援
  • IDispatch 提供 GetIDsOfNames + Invoke 晚期繫結
  • 字串名稱 → DISPID → 動態調用

優勢

  1. 名稱存取簡單易用
  2. 固定 vtable,無指標語言也能用
  3. 支援晚期繫結 (執行期綁定)
  4. 系統提供標準 Proxy/Stub,跨程序免開發

Invoke 實作模式:事件對應表


// 靜態事件對應表 (編譯期已知)
struct EventMapEntry {
    DISPID dispid;
    void (CMySink::*handler)();
};

EventMapEntry eventMap[] = {
    { DISPID_ONCLICK, &CMySink::OnClick },
    { DISPID_ONDATA,  &CMySink::OnData },
    // ...
};

STDMETHODIMP CMySink::Invoke(DISPID dispid, REFIID, LCID, WORD, 
                             DISPPARAMS* pParams, VARIANT* pResult, 
                             EXCEPINFO*, UINT*) {
    for (auto& entry : eventMap) {
        if (entry.dispid == dispid) {
            (this->*entry.handler)();  // 呼叫對應處理函數
            return S_OK;
        }
    }
    return DISP_E_MEMBERNOTFOUND;
}

MFC COleControl 即採用此模式處理 ActiveX 控制項事件。

六、MFC 連接點與事件支援

術語定義實作方方向
入介面 (Incoming)物件暴露給客戶端呼叫物件客戶端 → 物件
出介面 (Outgoing)物件主動呼叫客戶端客戶端 (接收器)物件 → 客戶端
接收器實作出介面的客戶端物件客戶端被動響應
可連接物件支援一或多個出介面的物件物件 (來源)雙向
事件/通知/請求出介面成員函數代表的語意-物件 → 客戶端
類別/巨集功能
CConnectionPoint實作 IConnectionPoint,陣列枚舉器管理連接
CCmdTarget 巨集BEGIN_CONNECTION_PART, END_CONNECTION_PART 宣告連接點
m_xConnPtContainerCCmdTarget 內嵌結構,存放 IConnectionPointContainer vtable
COleDispatchDriver客戶端 IDispatch 呼叫包裝,簡化參數處理

七、接收器實作要點

  • 客戶端內部物件,new 建立,無需 CLSID/ClassFactory
  • 實作出介面 (或 IDispatch)
  • 獨立 COM 物件:有參考計數、QueryInterface
  • 來源物件不應對接收器呼叫 QueryInterface (除 IUnknown)
  • 一對多 / 多對一 連接關係均支援

八、總結

COM 可連接物件機制以連接點容器/連接點/接收器三層架構,實現了型別安全、跨程序/機器透明、支援靜態/動態 (IDispatch) 介面的雙向通訊。理解其核心介面 (IConnectionPointContainer, IConnectionPoint, IEnumConnections)、事件對應表模式與 MFC 封裝,是開發 ActiveX 控制項、COM 事件來源與腳本宿主的必備基礎。

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