COM 可連接物件 (Connectable Objects) 實現了物件與客戶端的雙向通訊:物件主動觸發事件、通知或請求,客戶端透過實作輸出介面 (接收器) 來響應。本文系統闡述 COM 高階特性、入/出介面、連接點架構、枚舉器、事件激發、IDispatch 晚期繫結與 MFC 實作支援。
| 術語 | 定義 | 實作方 | 方向 |
| 入介面 (Incoming) | 物件暴露給客戶端呼叫 | 物件 | 客戶端 → 物件 |
| 出介面 (Outgoing) | 物件主動呼叫客戶端 | 客戶端 (接收器) | 物件 → 客戶端 |
| 接收器 | 實作出介面的客戶端物件 | 客戶端 | 被動響應 |
| 可連接物件 | 支援一或多個出介面的物件 | 物件 (來源) | 雙向 |
| 事件/通知/請求 | 出介面成員函數代表的語意 | - | 物件 → 客戶端 |
三、可連接物件架構
1. 連接點容器 IConnectionPointContainer
- 物件實作此介面管理所有出介面
EnumConnectionPoints → 列舉所有連接點
FindConnectionPoint → 依 IID 尋找特定連接點
2. 連接點 IConnectionPoint
- 每個出介面對應一個連接點物件
- 管理與該介面相關的所有接收器連接
Advise / Unadvise : 建立/移除連接 (返回 Cookie)
EnumConnections : 列舉現有連接
3. 兩層枚舉器架構
來源物件
└─ IConnectionPointContainer
└─ 連接點枚舉器 (IEnumConnectionPoints)
├─ 連接點 A (IConnectionPoint) → 連接枚舉器 (IEnumConnections) → 接收器 1, 2...
└─ 連接點 B (IConnectionPoint) → 連接枚舉器 → 接收器 3...
分離連接點物件提供獨立性與擴展性。
四、事件激發與處理流程
- 來源物件內部邏輯決定觸發事件
- 遍歷連接點的所有接收器
- 呼叫接收器對應的出介面方法
- 跨程序/跨機器時經由 Proxy/Stub 封送 (符合 COM 執行緒模型)
- 單執行緒模型 (STA) 下直接呼叫
五、IDispatch 作為通用出介面
動機
- 靜態出介面需編譯期綁定 vtable,腳本語言/動態語言難以支援
IDispatch 提供 GetIDsOfNames + Invoke 晚期繫結
- 字串名稱 → DISPID → 動態調用
優勢
- 名稱存取簡單易用
- 固定 vtable,無指標語言也能用
- 支援晚期繫結 (執行期綁定)
- 系統提供標準 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 連接點與事件支援
| 類別/巨集 | 功能 |
CConnectionPoint | 實作 IConnectionPoint,陣列枚舉器管理連接 |
CCmdTarget 巨集 | BEGIN_CONNECTION_PART, END_CONNECTION_PART 宣告連接點 |
m_xConnPtContainer | CCmdTarget 內嵌結構,存放 IConnectionPointContainer vtable |
COleDispatchDriver | 客戶端 IDispatch 呼叫包裝,簡化參數處理 |
七、接收器實作要點
- 客戶端內部物件,
new 建立,無需 CLSID/ClassFactory
- 實作出介面 (或
IDispatch)
- 獨立 COM 物件:有參考計數、
QueryInterface
- 來源物件不應對接收器呼叫
QueryInterface (除 IUnknown)
- 一對多 / 多對一 連接關係均支援
八、總結
COM 可連接物件機制以連接點容器/連接點/接收器三層架構,實現了型別安全、跨程序/機器透明、支援靜態/動態 (IDispatch) 介面的雙向通訊。理解其核心介面 (IConnectionPointContainer, IConnectionPoint, IEnumConnections)、事件對應表模式與 MFC 封裝,是開發 ActiveX 控制項、COM 事件來源與腳本宿主的必備基礎。
- 上一篇文章: COM 原理與應用:基於 COM 的元件化程式設計與 MTS 架構
- 下一篇文章: COM 原理與應用:命名與綁定技術 (Moniker)
Copyright ©
程式碼之家 All Rights Reserved