Как мне вызвать COM-объект VB6 из C # с динамическим, когда у него есть параметр ref? - PullRequest
4 голосов
/ 16 декабря 2011

У меня есть следующая унаследованная функция 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 по-прежнему равен нулю, а не содержит объект, который должен был быть передан.


Обновление

Я пробовал некоторые другие способы, включая использование VB.NET (поскольку он всегда был более дружественным к COM, чем 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, тогда код выполняется без исключения. Я даже установил точку останова в коде COM-объекта VB6 и могу подтвердить, что код выполняется правильно с этой стороны. Очевидно, что при установке для параметра 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()

Со всем кодом, который выдает исключение, COM-объект VB6 никогда не вызывается. Код COM-взаимодействия должен задыхаться при попытке маршалинга параметра ref.

В своих поисках в Google я натолкнулся на некоторые примеры использования Type.InvokeMember, но параметры ref всегда предназначены для простых типов, таких как целые числа и строки.

Ответы [ 2 ]

2 голосов
/ 19 декабря 2011

Кажется, в .NET нет способа вызвать метод для COM-объекта, который принимает параметр ref со сложным типом.

Я подал ошибку в Microsoft. Проголосуйте за , если эта проблема также затрагивает вас.

Обновление от 30.04.2013

Есть комментарий к сообщению об ошибке от Microsoft, в котором говорится, что оно исправлено. Никакого упоминания о том, какая версия .NET была затронута, хотя.

0 голосов
/ 21 мая 2016

На самом деле не ответ, а обходной путь.

Мне кажется, что когда вы меняете способ доступа к COM-объектам с dynamic на статический, проблема исчезает.Статическим способом я имею в виду подготовить dll для COM-объекта, используя C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\TlbImp.exe.Я предполагаю, что это раннее связывание.

...