使用JNA(Kotlin)调用带Variant*参数的COM函数时出现类型不匹配异常的排查与解决
使用JNA(Kotlin)调用带Variant*参数的COM函数时出现类型不匹配异常的排查与解决
嘿,我来帮你搞定这个COM调用的问题!首先咱们先拆解这个异常的意思,再一步步解决。
异常含义解析
你遇到的COMInvokeException错误码80020005是COM标准错误DISP_E_TYPEMISMATCH,直白说就是你传的参数类型和COM函数期望的类型对不上。而puArgErr=4表示问题出在第5个参数(因为COM的参数索引是从0开始计数的)——对应你调用里的d参数,不过本质上是可选参数的类型包装出了问题,咱们慢慢捋。
问题根源分析
你的COM函数签名是long GetValue(VARIANT* v, short a, short b, [optional] VARIANT c, [optional] VARIANT d);,这里有两个关键坑:
- 第一个参数
VARIANT* v是输出参数,必须传递VARIANT的指针(也就是JNA里的ByReference类型),你后来改成Variant.VARIANT.ByReference()是对的,但还不够; - 可选参数
c和d的类型是VARIANT,但你直接传了Kotlin的String——JNA不会自动把普通String包装成COM需要的VT_BSTR类型的VARIANT,这就导致了类型不匹配。
解决方案
咱们一步步来修正代码:
1. 确保输出参数的正确传递与资源清理
输出参数必须用Variant.VARIANT.ByReference(),而且调用完成后要手动清理VARIANT的资源,避免内存泄漏:
val valOutput = Variant.VARIANT.ByReference()
2. 手动将字符串包装为VARIANT类型
COM函数期望的是VARIANT对象,所以你需要把c和d这两个字符串手动包装成VT_BSTR类型的VARIANT:
// 包装字符串c为VT_BSTR类型的VARIANT val cVariant = Variant.VARIANT() cVariant.vt = OleAuto.VT_BSTR cVariant.bstrVal = NativeString("0", true).pointer // 包装字符串d为VT_BSTR类型的VARIANT val dVariant = Variant.VARIANT() dVariant.vt = OleAuto.VT_BSTR dVariant.bstrVal = NativeString("m", true).pointer
3. 正确调用函数并清理资源
现在用包装好的VARIANT参数调用函数,记得最后清理所有VARIANT资源:
try { o.GetValue(valOutput, 1.toShort(), 101.toShort(), cVariant, dVariant) // 调用成功后,从valOutput里获取结果,比如val result = valOutput.value } finally { // 清理所有VARIANT,释放COM资源 OleAuto.INSTANCE.VariantClear(valOutput) OleAuto.INSTANCE.VariantClear(cVariant) OleAuto.INSTANCE.VariantClear(dVariant) }
额外注意:可选参数的不传值处理
如果某个可选参数你不想传递,不要传null,而是要初始化一个VT_EMPTY类型的VARIANT:
val emptyVariant = Variant.VARIANT() emptyVariant.vt = OleAuto.VT_EMPTY // 调用时把对应参数换成emptyVariant即可
补充排查点
如果还是不行,检查一下JNA生成的COM代理接口是否正确——有时候自动生成的代理对VARIANT指针或可选参数的处理有偏差,你可以手动定义接口方法签名:
interface IMyComInterface : IUnknown { fun GetValue( output: Variant.VARIANT.ByReference, a: Short, b: Short, c: Variant.VARIANT, d: Variant.VARIANT ): Int }
然后通过JNA的COM工厂获取这个接口的代理再调用,确保参数类型完全匹配。
内容来源于stack exchange
相关产品推荐
相关产品推荐

