如何正确填充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。不过从你的场景看,你只需要传一个参数,所以这个点暂时不是核心问题,但必须记下来避免后续踩坑。
正确的代码实现步骤
下面是修正后的完整代码,我会标注关键要点:
- 修正数组索引:让
foo访问正确的索引0,如果确实需要多个参数,再对应扩展数组长度并初始化。 - 正确填充VARIANT与DISPPARAMS:确保Mock对象的COM接口引用计数正确(GMock的Mock类继承
IDispatch时,要正确实现AddRef和Release)。 - 清理资源:记得释放
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
相关产品推荐
相关产品推荐

