c# - 当 VB6 COM 对象具有 ref 参数时,如何使用动态从 C# 调用它?

标签 c# dynamic vb6 com-interop late-binding

我想从 C# 调用以下旧版 VB6 函数。

Public Function CreateMiscRepayment(ByRef objMiscRepayment As MiscRepayment) As Variant
   ' Code that sets objMiscRepayment here
End Function

我在 C# 中使用以下代码但出现异常:

dynamic vb6ComObject = Activator.CreateInstance(Type.GetTypeFromProgID(progId));
dynamic miscRepayment = null;
dynamic result = vb6ComObject.CreateMiscRepayment(ref miscRepayment);

异常(exception)情况是:

System.ArgumentException: Could not convert argument 0 for call to CreateMiscRepayment.
at System.Dynamic.ComRuntimeHelpers.CheckThrowException(Int32 hresult, ExcepInfo& excepInfo, UInt32 argErr, String message)
at CallSite.Target(Closure , CallSite , ComObject , Object& )
at CallSite.Target(Closure , CallSite , ComObject , Object& )
at CallSite.Target(Closure , CallSite , Object , Object& )
at CallSite.Target(Closure , CallSite , Object , Object& )
Application\ApplicationClasses.cs(65,0): at ApplicationClasses.CanInstantiateMiscRepayment()

我试过将 ref 更改为 out 但得到了同样的错误。如果我省略 ref,该方法执行时不会出错,但当然 miscRepayment 仍然是 null 而不是包含应该传递出去的对象。


更新

我已经尝试了一些其他方法,包括使用 VB.NET(因为它总是比 C# 对 COM 更友好)。

使用以下 VB.NET 代码:

Dim vb6ComObject = Activator.CreateInstance(System.Type.GetTypeFromProgID(progId))
Dim miscRepayment = Nothing
Dim result = vb6ComObject.CreateMiscRepayment(miscRepayment)

它抛出以下类似但不同的异常:

System.Runtime.InteropServices.COMException: Type mismatch. (Exception from HRESULT: 0x80020005 (DISP_E_TYPEMISMATCH))
    at Microsoft.VisualBasic.CompilerServices.LateBinding.LateGet(Object o, Type objType, String name, Object[] args, String[] paramnames, Boolean[] CopyBack)
    at Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateGet(Object Instance, Type Type, String MemberName, Object[] Arguments, String[] ArgumentNames, Type[] TypeArguments, Boolean[] CopyBack)
    UnitTest1.vb(19,0): at TestProject1.UnitTest1.TestMethod1()

有趣的是,如果我将 C# 或 VB.NET 示例代码中的调用更改为使用 null/Nothing 而不是 miscRepayment 那么代码执行时不会抛出异常。我什至在 VB6 COM 对象的代码中设置了一个断点,并且可以确认该代码已在该端正确执行。显然,将 miscRepayment 参数设置为 null/Nothing 后,.NET 就无法接收创建的对象。问题一定与参数的编码有关。

我也尝试过将 Type.InvokeMemberParameterModifier 参数一起使用,将 miscRepayment 标记为 ref 参数,但得到以下异常:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Runtime.InteropServices.COMException: Type mismatch. (Exception from HRESULT: 0x80020005 (DISP_E_TYPEMISMATCH))

     --- End of inner exception stack trace ---
    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)
    UnitTest1.vb(18,0): at TestProject1.UnitTest1.TestMethod1()

最后,我尝试了以下 VB.NET 代码:

Dim vb6ComObject = Activator.CreateInstance(System.Type.GetTypeFromProgID(progId))
Dim args(0) As Object
Microsoft.VisualBasic.CompilerServices.LateBinding.LateCall(vb6ComObject, type, "CreateMiscRepayment", args, Nothing, New Boolean() {True})

它抛出以下异常:

System.Runtime.InteropServices.COMException: Type mismatch. (Exception from HRESULT: 0x80020005 (DISP_E_TYPEMISMATCH))
    at Microsoft.VisualBasic.CompilerServices.LateBinding.InternalLateCall(Object o, Type objType, String name, Object[] args, String[] paramnames, Boolean[] CopyBack, Boolean IgnoreReturn)
    at Microsoft.VisualBasic.CompilerServices.LateBinding.LateCall(Object o, Type objType, String name, Object[] args, String[] paramnames, Boolean[] CopyBack)
    UnitTest1.vb(17,0): at TestProject1.UnitTest1.TestMethod1()

所有抛出异常的代码都不会调用 VB6 COM 对象。尝试编码 ref 参数时,COM 互操作代码必须阻塞。

在我的 Google 搜索中,我遇到了一些使用 Type.InvokeMember 的示例,但 ref 参数始终用于简单类型,例如整数和字符串。

最佳答案

在 .NET 中似乎没有办法调用 COM 对象的方法,该对象采用复杂类型的 ref 参数。

我已经 filed a bug与微软。投票 it如果这个问题也影响到您,请联系我们。

2013 年 4 月 30 日更新

Microsoft 对错误报告的评论说它已被修复。但没有提及哪个版本的 .NET 受到了影响。

关于c# - 当 VB6 COM 对象具有 ref 参数时,如何使用动态从 C# 调用它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8529313/

相关文章:

c# - 处理未使用的 IDisposable 返回值是否重要?

sql - 替换动态文本 SQL

javascript - JavaScript 是 "dynamic"是什么意思?

c# - 动态获取参数类型的默认值

c# - 如何延长http响应的时间长度

c# - 从 Windows Phone 8 的内部存储中读取?

c# - 如何防止 iOS Safari 输入标签中的自动大写?

c# - VB6/COM 互操作 : where do these events come from?

vb6 - 为什么每次启动visual basic 6时windows安装程序都会启动

multithreading - 在多线程VB6中使用互斥锁