How do I call a VB6 COM object from C # with dynamic if it has a ref parameter?

I have the following VB6 function that I want to call from C #.

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

I use the following C # code, but get an exception:

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

The exception is:

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

I tried changing the ref to out , but getting the same error. If I omit ref , the method is executed without errors, but, of course, miscRepayment is still null and does not contain the object that should have been deleted.


Update

I tried other ways, including using VB.NET (since it was always more COM friendly than C #).

With the following VB.NET code:

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

It throws the following similar, but another exception:

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

Interestingly, if I change the call in the C # or VB.NET code example to use null / Nothing instead of miscRepayment , then the code is executed without exception. I even set a breakpoint in the code of the VB6 COM object and I can confirm that the code was executed correctly for this purpose. Obviously, when you set the miscRepayment parameter to null / Nothing in .NET, there is no way to get the created object. The problem should be sorting the parameters.

I also tried using Type.InvokeMember with the ParameterModifier argument, which marks miscRepayment as the ref parameter, but gets the following exception:

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

Finally, I tried the following VB.NET code:

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

It throws the following exception:

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

With all the code that throws an exception, the VB6 COM object is never called. The COM interaction code should suffocate when trying to marshal the ref parameter.

On my Google search engines, I have come across several examples using Type.InvokeMember , but the ref parameters are always for simple types such as integers and strings.

+4
source share
2 answers

In .NET, there is no way to call a method on a COM object that accepts a ref parameter with a complex type.

I filed a bug at Microsoft. Vote it if this problem also affects you.

Update 04/30/2013

There is a comment on the bug report from Microsoft stating that it has been fixed. It is not mentioned which version of .NET was affected.

+2
source

Actually not the answer, but a workaround.

It seems to me that when you change the way you access COM objects from dynamic to static, the problem disappears. In a static way, I want to prepare a dll for a COM object using C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\TlbImp.exe . I guess this is an early binding.

0
source

Source: https://habr.com/ru/post/1386634/


All Articles