【问题标题】:How to access COM variant properties with F#如何使用 F# 访问 COM 变体属性
【发布时间】:2021-08-28 04:24:01
【问题描述】:

我可以通过 ActiveX 控件访问旧系统。我可以在 F# 中使用它的 ProgID 创建此控件的实例,然后成功调用各种方法。但是,我在尝试使用它的属性时遇到了问题。这些已被声明为 Variant 类型。

我可以像这样在 C# 中成功地做到这一点:

using System.Runtime.InteropServices;

// asuming I have already created an instance of the Legacy ActiveX control - axLegacy
object v = new VariantWrapper(0.0);
axLegacy.Get("Color", ref v);

在 F# 中,除了属性之外,我可以让其他一切工作:

open System
open System.Reflection
open System.Runtime.InteropServices

let getParamVal (legacyType: Type, instance: obj, propertyName: string, x: byref<obj>)  =
    let res = legacyType.InvokeMember(name = "Get", invokeAttr = (BindingFlags.InvokeMethod ||| BindingFlags.Instance ||| BindingFlags.Public), binder = null, target = instance, args = [|propertyName, x|])
    res

[<EntryPoint>]
let main argv =
    let axLegacyType = Type.GetTypeFromProgID("Legacy.ProgID.1")
    let axLegacy = Activator.CreateInstance(axLegacyType)  // create an instance of the type
    // calling a method with no parameters - works
    let res = axLegacyType.InvokeMember(name = "MethodNoParams", invokeAttr = (BindingFlags.InvokeMethod ||| BindingFlags.Instance ||| BindingFlags.Public), binder = null, target = axLegacy, args = null)
    // calling a method with parameters - works
    let res2 = axLegacyType.InvokeMember(name = "MethodWithParam", invokeAttr = (BindingFlags.InvokeMethod ||| BindingFlags.Instance ||| BindingFlags.Public), binder = null, target = axLegacy, args = [|"method param value goes here"|])
    // accessing a property - does not work
    let mutable propertyVal = new VariantWrapper(0.0) :> obj  // downcast to an Object
    // this throws the COM exception
    let res = getParamVal(axLegacyType, instance, "PropertyName", &magVal)

我快到了,如果有人可以帮助我,将不胜感激。我知道一个明显的答案是只使用 C#,但 F# 实际上更符合我的要求。另外,F# 是一种很酷的语言:)

=编辑= 我设法整理了 byref 位并添加了 getParamVal 函数。在 cmets 之后,我还为控件生成了 IDL,并包括以下重要位:

    [
      uuid(XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX),
      helpstring("Dispatch interface for AxLegacy Control"),
      hidden
    ]
    dispinterface AxLegacy {
        methods:
            [id(0x00000002)]
            long Get(
                            BSTR lpszParam, 
                            VARIANT* vValue);
    };

我收到的实际错误是这样的:

System.Reflection.TargetInvocationException
  HResult=0x80131604
  Message=Exception has been thrown by the target of an invocation.
  Source=System.Private.CoreLib
  StackTrace:
   at System.RuntimeType.InvokeDispMethod(String name, BindingFlags invokeAttr, Object target, Object[] args, Boolean[] byrefModifiers, Int32 culture, String[] namedParameters)
   at System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParams)
   at System.Type.InvokeMember(String name, BindingFlags invokeAttr, Binder binder, Object target, Object[] args)
   at Program.getParamVal(Type legacyType, Object instance, String cmd, Object& x) in C:\Source\F#\AxLegacyConsole\AxLegacyConsole\Program.fs:line 12
   at Program.main(String[] argv) in C:\Source\F#\AxLegacyConsole\AxLegacyConsole\Program.fs:line 25

Inner Exception 1:
COMException: Type mismatch. (0x80020005 (DISP_E_TYPEMISMATCH))

【问题讨论】:

  • 这很难回答,因为(有充分的理由!)我们无法运行代码 - 你能想到任何 ActiveX 对象在典型的 Windows 机器上都有类似的结构并且可能是用来调试这个?
  • 你能显示你收到的编译器错误吗?
  • 您确定要使用 BindingFlags.InvokeMethod 吗?通常在 COM 中通过 IDispatch 调用时,会有不同的标志。原始 C 代码值是 DISPATCH_PROPERTYGET ... 因此,无论 BindingFlags 的等效映射是什么,都可能是您想要使用的。
  • 你试过 FSharp.ComProvider 了吗? fsprojects.github.io/FSharp.Interop.ComProvider
  • @TomasPetricek 我一直在想一些等效的东西,但到目前为止还没有想到。我已更新问题以包含 IDL 定义的重要部分。使用调度接口访问该属性。

标签: c# f# com


【解决方案1】:

我实际上解决了这个问题,并且花了很多功夫!这是一个简短的大纲:

  • 我必须先在 Visual Studio 2017 中创建东西(它完全支持 F# .NET Framework 项目)
  • 我创建了一个 F# 控制台应用程序 (.NET Framework)
  • 创建了一个虚拟 C# 库 (.NET Framework)
  • 将 ActiveX 控件添加到 C# 项目中
  • 将用于构建 Interop 程序集的部分从 CSPROJ 复制到 FSPROJ 文件
  • 将生成的互操作 DLL 复制到 F# 控制台应用的构建输出文件夹中

我在这里发布了有关我如何做到这一点的更详细信息: Using an ActiveX Control in F#

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-12
    • 2010-12-12
    • 2020-07-05
    • 1970-01-01
    相关资源
    最近更新 更多