当具有ref参数时,如何使用动态调用C#中的VB6 COM对象?

我有以下传统的VB6功能,我想从C#调用.

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);

例外是:

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#更友好).

使用以下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.InvokeMember和ParameterModifier参数,该参数将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日更新

有一条评论来自微软的错误报告说它已被修复.但是没有提到哪个版本的.NET受到了影响.

上一篇:PAT甲级 1099 Build A Binary Search Tree (30 分)


下一篇:【Leetcode二叉树的修改与构造一】105. 从前序与中序遍历序列构造二叉树 106. 从中序与后序遍历序列构造二叉树