繁体   English   中英

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

[英]How do I call a VB6 COM object from C# with dynamic when it has a ref parameter?

我有以下想要从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);

例外是:

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当然仍然为空,而不是包含应该传递的对象。


更新资料

我尝试了其他方法,包括使用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参数一起使用,该ParameterModifiermiscRepayment标记为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中似乎没有一种方法可以在带有复杂类型的ref参数的COM对象上调用方法。

我已经 Microsoft 提出了错误 投票了,如果这个问题也影响到你。

更新30/4/2013

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

实际上不是答案,而是一种解决方法。

在我看来,当您将访问COM对象的方式从dynamic更改为静态时,问题就消失了。 通过静态方式,我的意思是使用C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.0A\\Bin\\TlbImp.exe为COM对象准备一个dll。 我想这是早期约束力。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM