0

WF4アクティビティからアクセスする必要のあるCOMライブラリがいくつかあるのでtlbimp、それらのマネージラッパーを生成していました。これは正常に機能しますが、いくつかのケースでは、引数の1つとしてVariantsの配列を期待するCOMメソッドがあり、配列の要素の1つは別のDLLからのCOMクラスのインスタンスです。同じオブジェクトを表すマネージラッパーへの参照がある場合でも、への参照を取得する方法を確認してください。

例として、とという2つのCOMライブラリがABCありDEF、そのためにと呼ばれるマネージラッパーを作成し、を使用しているABCManagedとします。次のシグニチャを持つメソッドがあるとします(VBスタイルのシグニチャを許可します。これは、ドキュメントに記載されている方法です)。DEFManagedtlbimpDEF

CallFunction (parmArray() as Variant) as Long

これは次のように表さDEFManagedれます。

int CallFunction(ref object parmArray)

ここまでは順調ですね。さて、引数であるVariantsの配列の要素はCallFunction()異なるタイプであるため、私の場合、最初の要素はadoubleで、2番目の要素はのインスタンスですABC。これが、管理対象に渡すためにアレイを構築する方法ですCallFunction()

// obtain our managed ABC from the workflow context
ABCManaged abc = context.GetValue(this.InputABC);
object[] parameters =  new object[2];
parameters[0] = new double();
parameters[1] = abc;

DEFManaged def = new DEFManaged();
def.CallFunction(parameters);

これは正常にコンパイルされますが、機能しません-を呼び出すと、次のCallFunction()例外がスローされます。

System.ArgumentException: Value does not fall within the expected range.

私の推測では、おそらく署名にの配列があり、配列の要素の実際の型を決定するロジックがCOMメソッドの実装のどこかにあるためdef、基になるアンマネージ型に正しくマーシャリングされていません。オブジェクトを配列に貼り付けてマネージドに渡す前に、オブジェクトをアンマネージドタイプに手動でマーシャリングする方法がわかりません。DEFobjectCallFunction()defDEFCallFunction()

ここでも、ストレートP/Invokeを使用することはできません。私は確かにコードを書くことができますが、要件の1つは、WF4アクティビティのユーザーがオブジェクトのプロパティとメソッドにアクセスできることDEFManagedです。したがって、それらは管理対象オブジェクトである必要があります。

4

1 に答える 1

0

配列内の個々のオブジェクトは正しくマーシャリングされていましたが、配列自体は参照ではなく値で渡されていました(COMオブジェクトでは参照で渡される必要がありました- VT_BYREF)。これは、COMオブジェクトにデバッガーをアタッチできたときに表面化しました。

参照によって配列をC#からCOMに渡すのは簡単ではありません。私は最初、参照渡しを必要としないVB6(!)に中間プロキシCOMオブジェクトを用意し、プロキシオブジェクトから元のCOMオブジェクトを呼び出すことでこれを回避しました(VB6は常に参照渡しします)。

これは理想的ではありませんでしたが、トピックに関する私の質問へのこの回答で概説されているように、リフレクションとParameterModifierを介した遅延バインディングを使用して、参照によってC#に強制的にCOMメソッドに引数を渡すことも可能です。

仕組みは次のとおりです。

// obtain our managed ABC from the workflow context
ABCManaged abc = context.GetValue(this.InputABC);

object[] parameters =  new object[2]; // method argument, i.e. parmArray value
parameters[0] = new double();
parameters[1] = abc;

DEFManaged d = new DEFManaged(); // managed wrapper for our COM object

var t = typeof(DEFManaged);
object[] args = new object[1]; // array which will contain all method arguments
args[0] = data; // data is the first argument, i.e. first element of args array

ParameterModifier[] pms = new ParameterModifier[1];
ParameterModifier pm = new ParameterModifier(1);
pm[0] = true; // pass the 1st argument by reference
pms[0] = pm;  // add pm to the array of modifiers 

// invoke CallFunction by name via IDispatch interface
var ret = t.InvokeMember("CallFunction", System.Reflection.BindingFlags.InvokeMethod, null, d, args, pms, null, null);
Console.Out.WriteLine("Result = " + ret);

元の回答で示唆されているように、これをDEFManagedインターフェイスの拡張メソッドにしたので、マネージラッパーのユーザーは拡張メソッドを直接呼び出すだけで、リフレクションを処理できます。

于 2013-03-16T14:37:41.780 に答える