You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确填充DISPPARAMS和VARIANT,让mock IDispatch被foo函数正确读取?

问题分析与解决方案

咱们先揪出核心问题:你代码里的数组索引越界直接导致rgvarg[1].vt的值是随机垃圾数据,自然匹配不上VT_DISPATCH。

具体问题拆解

你创建的args数组长度是1,dp.cArgs = 1,这意味着rgvarg的有效索引只有0,但foo函数里却访问了rgvarg[1]——这属于未定义行为,内存里这个位置的值完全是随机的,所以条件永远不成立。

另外还要注意COM里DISPPARAMS的一个常见坑:参数是逆序存储的。比如如果方法需要两个参数(param1, param2),那么rgvarg[0]对应param2,rgvarg[1]对应param1。不过从你的场景看,你只需要传一个参数,所以这个点暂时不是核心问题,但必须记下来避免后续踩坑。

正确的代码实现步骤

下面是修正后的完整代码,我会标注关键要点:

  1. 修正数组索引:让foo访问正确的索引0,如果确实需要多个参数,再对应扩展数组长度并初始化。
  2. 正确填充VARIANT与DISPPARAMS:确保Mock对象的COM接口引用计数正确(GMock的Mock类继承IDispatch时,要正确实现AddRef和Release)。
  3. 清理资源:记得释放VARIANT数组并调用VariantClear清理每个VARIANT。

修正后的测试代码

// 栈上创建mock对象,注意:如果foo里会持有这个指针,要确保mock对象生命周期覆盖函数调用
Mock_Item mock_Item; 

DISPPARAMS dp = { nullptr, nullptr, 0, 0 };
const int argCount = 1; // 实际需要的参数数量
VARIANT* args = new VARIANT[argCount];
for (int i = 0; i < argCount; ++i) {
    VariantInit(&args[i]);
}

// 填充参数(因为只有一个参数,直接用索引0)
args[0].vt = VT_DISPATCH;
// COM接口必须调用AddRef,确保mock对象正确实现该方法
args[0].pdispVal = &mock_Item;
args[0].pdispVal->AddRef();

dp.rgvarg = args;
dp.cArgs = argCount;

// 调用待测试函数
foo(&dp, nullptr);

// 清理资源
for (int i = 0; i < argCount; ++i) {
    VariantClear(&args[i]);
}
delete[] args;

修正后的foo函数代码

void foo(DISPPARAMS* pDispParams, VARIANT* pVarResult) {
    IDispatch* pCtrl(nullptr);
    // 先检查参数数量是否足够,再访问正确的索引0
    if (pDispParams != nullptr 
        && pDispParams->rgvarg != nullptr 
        && pDispParams->cArgs >= 1 
        && VT_DISPATCH == pDispParams->rgvarg[0].vt) {
        pCtrl = pDispParams->rgvarg[0].pdispVal;
        // 如果foo需要持有pCtrl,记得最后调用Release
        // pCtrl->Release();
    }
}

额外注意事项

  • COM接口引用计数:IDispatch是COM接口,把mock_Item的指针赋值给pdispVal时必须调用AddRef,否则如果foo里调用Release,会导致栈上的mock对象被错误销毁。
  • Mock类的正确实现:你的Mock_Item必须实现IDispatch的所有纯虚函数,包括AddRef、Release、QueryInterface,示例如下:
    class Mock_Item : public IDispatch {
    public:
        MOCK_METHOD(HRESULT, QueryInterface, (REFIID riid, void** ppvObject), (override));
        MOCK_METHOD(ULONG, AddRef, (), (override));
        MOCK_METHOD(ULONG, Release, (), (override));
        // 其他IDispatch方法的mock实现...
    };
    
    测试时可以设置对应的调用期望:
    EXPECT_CALL(mock_Item, AddRef()).WillOnce(Return(1));
    EXPECT_CALL(mock_Item, Release()).WillOnce(Return(0));
    

内容的提问来源于stack exchange,提问作者rranjik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 06:41:38