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

COM 組件調用 C++ 回調函數:參數傳遞完整指南

     編輯:程式設計綜合問答

問題背景

在開發 COM 組件時,常需讓組件回調 C++ 函數。核心難點在於如何將 C++ 回調函數指標正確傳遞給 COM 組件的 SetCallBackFun 方法。本文將詳細拆解實現步驟、代碼示例及常見坑點。

一、COM 組件接口實現

1. 成員變量定義

使用 CComPtr<IDispatch> 保存回調函數的派生介面指標:

private:
    // 回調函數指標
    CComPtr<IDispatch> m_pChangeTempCallbackFun; // 更換模板回調函數

2. 設置回調函數的方法

驗證傳入的 VARIANT 類型是否為 VT_DISPATCH,再賦值給智能指標:

bool CDllHelper::SetCallBackFun(VARIANT vaJsFun)
{
    if (vaJsFun.vt != VT_DISPATCH)
    {
        return false;
    }
    m_pChangeTempCallbackFun = vaJsFun.pdispVal;
    return true;
}

二、C++ 回調函數定義

定義標準呼叫慣例的回調函數:

void CALLBACK OnChangeTempEvent()
{
    // 其他業務代碼
}

三、核心問題:如何將函數指標傳給 SetCallBackFun?

由於 SetCallBackFun 接受 VARIANT 參數,需將 C++ 函數指標封裝為 IDispatch 介面。常見做法有二:

方案 A:使用 ATL 的 CComObject 實現派生介面

  1. 定義一個繼承 IDispatch 的類,實現 Invoke 方法內部調用 OnChangeTempEvent。
  2. 創建該類實例,查詢 IDispatch 指標。
  3. 構造 VARIANT,類型設為 VT_DISPATCH,指標指向該介面。

方案 B:利用 IDispatch 動態調用(適用於腳本引擎)

若回調源自 JavaScript/VBScript,直接傳遞腳本函數物件即可;若為純 C++,需自行實現 IDispatch 包裝器。

四、完整代碼示例

// 1. 定義回調包裝類
class CCallbackWrapper : public IDispatch
{
public:
    // IUnknown 方法
    STDMETHOD(QueryInterface)(REFIID riid, void** ppv) { ... }
    STDMETHOD_(ULONG, AddRef)() { ... }
    STDMETHOD_(ULONG, Release)() { ... }

    // IDispatch 方法
    STDMETHOD(GetTypeInfoCount)(UINT* pctinfo) { return E_NOTIMPL; }
    STDMETHOD(GetTypeInfo)(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) { return E_NOTIMPL; }
    STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) { return E_NOTIMPL; }
    STDMETHOD(Invoke)(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr)
    {
        if (dispIdMember == DISPID_VALUE)
        {
            OnChangeTempEvent(); // 調用實際回調
            return S_OK;
        }
        return DISP_E_MEMBERNOTFOUND;
    }
};

// 2. 客戶端調用代碼
CCallbackWrapper* pWrapper = new CCallbackWrapper();
CComPtr<IDispatch> spDispatch;
pWrapper->QueryInterface(IID_IDispatch, (void**)&spDispatch);

VARIANT var;
VariantInit(&var);
var.vt = VT_DISPATCH;
var.pdispVal = spDispatch;

CDllHelper helper;
helper.SetCallBackFun(var);

五、常見錯誤與注意事項

  • 引用計數:確保 CComPtr 正確管理生命週期,避免過早釋放導致崩潰。
  • 線程模型:回調執行線程需與 COM 組件線程模型一致,必要時用 CoMarshalInterThreadInterfaceInStream 跨線程封送。
  • 參數封送:若回調需傳參,Invoke 的 DISPPARAMS 需正確填充,並處理 VT_BYREF 等類型。

總結

將 C++ 函數指標傳遞給 COM 組件,關鍵在於實現 IDispatch 包裝器並正確構造 VARIANT。掌握此模式,即可實現 COM 與原生 C++ 代碼的雙向通訊。

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