使用CoCreateInstance调用COM函数遇参数数量错误(0x8002000e)求助
别把[out,retval]参数塞进参数数组
[out,retval]是单独作为Invoke的返回值接收的,不需要放到DISPPARAMS的参数列表里。你有5个[in,out]参数,那DISPPARAMS.cArgs必须设为5,而不是6。很多人会误把retval参数也算进去,直接导致参数数量不匹配。参数顺序必须严格逆序(排除retval)
IDispatch调用的参数数组顺序是原函数参数的逆序。比如原函数声明是:HRESULT YourFunc([in,out] VARIANT* p1, [in,out] SAFEARRAY(double)* p2, [in,out] long* p3, [in,out] BSTR* p4, [in,out] VARIANT* p5, [out,retval] long* pResult);
那你的参数数组rgvarg里的顺序应该是p5, p4, p3, p2, p1,也就是从原函数的最后一个[in,out]参数往前排。SAFEARRAY参数的VARIANT包装必须合规
对于[in,out]的SAFEARRAY(double):- 初始化VARIANT时,
vt要设为VT_ARRAY | VT_R8 - 用
SafeArrayCreate创建类型为VT_R8的数组,确保维度、元素数量符合要求;如果是[in,out]方向,要提前分配好足够的数组空间 - 调用完成后记得用
SafeArrayDestroy释放数组,用VariantClear清理VARIANT
- 初始化VARIANT时,
验证DISPID的正确性
不要硬编码DISPID,通过IDispatch::GetIDsOfNames动态获取目标函数的DISPID,避免OleView显示的函数顺序和实际COM对象的DISPID映射不匹配:DISPID dispid; LPOLESTR funcName = OLESTR("YourTargetFunc"); HRESULT hr = pDispatch->GetIDsOfNames(IID_NULL, &funcName, 1, LOCALE_USER_DEFAULT, &dispid); if (FAILED(hr)) { /* 处理DISPID获取失败 */ }检查所有VARIANT参数的初始化和类型匹配
每个[in,out]参数对应的VARIANT都要先调用VariantInit初始化,然后设置正确的vt类型:- 整数用
VT_I4,双精度用VT_R8,字符串用VT_BSTR(要分配BSTR) - 不要出现未初始化的VARIANT,或者类型不匹配的情况——比如把int值塞到
VT_R8的VARIANT里,这种错误会触发参数校验失败,表现为参数数量错误的报错。
- 整数用
确认DISPPARAMS结构体的正确设置
调用Invoke时的DISPPARAMS必须严格对应:VARIANT args[5]; // 依次初始化args[0]到args[4],对应原函数逆序的[in,out]参数 DISPPARAMS dp = { args, NULL, 5, 0 }; // cArgs=5,cNamedArgs=0 VARIANT retval; VariantInit(&retval); HRESULT hr = pDispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dp, &retval, NULL, NULL);
内容的提问来源于stack exchange,提问作者Gary

