4

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、もちろんnull のままです。miscRepayment


アップデート

私は、VB.NET を使用するなど、他の方法をいくつか試しました (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.InvokeMemberする引数を使用してみましたが、次の例外が発生します。ParameterModifiermiscRepaymentref

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 オブジェクトが呼び出されることはありません。パラメータをマーシャリングしようとすると、COM 相互運用コードが詰まる必要がありrefます。

Google 検索で を使用した例をいくつか見つけましたType.InvokeMemberが、refパラメーターは常に整数や文字列などの単純な型用です。

4

2 に答える 2

2

ref複雑な型のパラメーターを受け取る COM オブジェクトでメソッドを呼び出す方法が .NET にないようです。

Microsoft にバグを報告しました。この問題があなたにも影響している場合は、投票してください。

2013 年 4 月 30 日更新

Microsoft からのバグ レポートには、修正されたというコメントがあります。ただし、影響を受けた .NET のバージョンについては言及されていません。

于 2011-12-19T04:55:27.190 に答える
0

実際には答えではありませんが、回避策です。

COM オブジェクトへのアクセス方法dynamicを static から変更すると、問題が解決するように思えます。静的な方法とは、を使用して COM オブジェクトの dll を準備することを意味しますC:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\TlbImp.exe。これはアーリーバインディングだと思います。

于 2016-05-21T19:54:02.660 に答える