如何在F#中访问COM Variant类型的ActiveX控件属性
问题根因
你遇到的DISP_E_TYPEMISMATCH错误是两个问题共同导致的:
- 调用
InvokeMember时没有指定参数修饰符,运行时无法识别第二个参数是引用传递,COM层无法匹配VARIANT*类型的参数声明 - 你构造参数数组的写法有误,
[|propertyName, x|]实际创建了单个元素为元组的数组,和方法要求的两个入参不匹配
修正后的可运行代码
open System open System.Reflection open System.Runtime.InteropServices let getParamVal (legacyType: Type, instance: obj, propertyName: string, x: byref<obj>) = // 构造参数数组,注意是两个独立元素,不是元组 let args = [| propertyName :> obj; x |] // 定义参数修饰符:第二个参数(索引为1)是引用传递 let modifiers = ParameterModifier(2) modifiers.[1] <- true // 调用时传入修饰符参数 let res = legacyType.InvokeMember( "Get", BindingFlags.InvokeMethod ||| BindingFlags.Instance ||| BindingFlags.Public, null, instance, args, [|modifiers|], null, null) // 把修改后的参数值写回byref变量 x <- args.[1] res [<EntryPoint>] let main argv = let axLegacyType = Type.GetTypeFromProgID("Legacy.ProgID.1") let axLegacy = Activator.CreateInstance(axLegacyType) // 无参方法调用示例(原逻辑可用,保留即可) let res = axLegacyType.InvokeMember("MethodNoParams", BindingFlags.InvokeMethod ||| BindingFlags.Instance ||| BindingFlags.Public, null, axLegacy, null) // 有参方法调用示例(原逻辑可用,保留即可) let res2 = axLegacyType.InvokeMember("MethodWithParam", BindingFlags.InvokeMethod ||| BindingFlags.Instance ||| BindingFlags.Public, null, axLegacy, [|"method param value goes here"|]) // 修正后的属性读取逻辑 let mutable propertyVal = VariantWrapper(0.0) :> obj let res = getParamVal(axLegacyType, axLegacy, "PropertyName", &propertyVal) // 读取返回结果:需要把WrappedObject转成你需要的类型 let colorVal = (propertyVal :?> VariantWrapper).WrappedObject :?> float 0
关键修改说明
- 修正了参数数组构造方式,把元组写法改为两个独立的object元素
- 新增
ParameterModifier声明,明确告知运行时第二个参数为引用传递,匹配COM接口的VARIANT*要求 - 调用完成后手动把参数数组里修改后的第二个元素值写回输入的byref变量,保证外层可以拿到返回的属性值
- 修正了原代码中变量名错误(原调用
getParamVal时传的&magVal没有定义,改为实际声明的&propertyVal)
内容的提问来源于stack exchange,提问作者Ian Ormesher
相关产品推荐
相关产品推荐

