質問

私は、C#フロントエンドを備えたC ++で記述されたいくつかのCOMインターフェイスで構成される既存のコードベースを使用しています。追加する必要がある新しい機能があるので、COM部分を変更する必要があります。特定のケースでは、配列(C#から割り当てられた)をコンポーネントに渡す必要があります。

私がやりたいのは、C#からintの配列をメソッドに渡すことができるようにすることです:

// desired C# signature
void GetFoo(int bufferSize, int[] buffer);

// desired usage
int[] blah = ...;
GetFoo(blah.Length, blah);

作業中のいくつかのレンチ:

  • C ++ / CLIまたはManaged C ++は使用できません(この場合、COMは廃止できます)。
  • C#側を/ unsafeでコンパイルすることはできません(マーシャルの使用は許可されています)。

COMインターフェースはC#部分でのみ使用されるため(これまで使用されることはありません)、他のCOMコンシューマーとの相互運用性についてはあまり関心がありません。 32ビットと64ビット間の移植性も問題になりません(すべてが32ビットマシンでコンパイルおよび実行されているため、コードジェネレーターはポインターを整数に変換しています)。最終的には、C ++ / CLIに置き換えられますが、それは道のりです。


最初の試み

は次のようなものです:

HRESULT GetFoo([in] int bufferSize, [in, size_is(bufferSize)] int buffer[]);

また、出力TLB定義は次のとおりです(合理的なようです):

HRESULT _stdcall GetFoo([in] int bufferSize, [in] int* buffer);

次のようにC#によってインポートされる(それほど合理的ではない):

void GetFoo(int bufferSize, ref int buffer);

一緒に使用できました

int[] b = ...;
fixed(int *bp = &b[0])
{
    GetFoo(b.Length, ref *bp);
}

... / unsafeでコンパイルできないことを除いて。


現時点

私は使用しています:

HRESULT GetFoo([in] int bufferSize, [in] INT_PTR buffer);

インポート対象:

void GetFoo(int bufferSize, int buffer);

そして次のように使用する必要があります:

int[] b = ...;
GCHandle bPin = GCHandle.Alloc(b, GCHandleType.Pinned);
try
{
    GetFoo(b.Length, (int)Marshal.UnsafeAddrOfPinnedArrayElement(b, 0));
}
finally
{
    bPin.Free();
}

どのように機能しますか...しかし、よりクリーンな方法を見つけたいです。


だから、質問は

この場合、TLBジェネレーターからのC#インポートに適したIDL定義はありますか?そうでない場合は、C#側で何ができると少し安全になりますか?

役に立ちましたか?

解決 3

うーん...私は私を近づける情報を見つけました...

マーシャリングの変更-適合Cスタイルアレイ

このIDL宣言(C ++)

HRESULT GetFoo([in] int bufferSize, [in, size_is(bufferSize)] int buffer[]);

(MSIL)としてインポートされます

method public hidebysig newslot virtual instance void GetFoo([in] int32 bufferSize, [in] int32& buffer) runtime managed internalcall

そして(MSIL)に変更した場合

method public hidebysig newslot virtual instance void GetFoo([in] int32 bufferSize, [in] int32[] marshal([]) buffer) runtime managed internalcall

(C#)のように使用できます

int[] b = ...;
GetFoo(b.Length, b);

まさに私が求めていたもの

しかし、tlbimportによって生成されるランタイム呼び出し可能ラッパーのMSILを修正する必要のない他のソリューションはありますか?

他のヒント

つまり、32ビットマシンでは32ビット、64ビットマシンでは64ビットのIDLデータ型を要求しています。しかし、マーシャリングコードでポインターのように、ちょうどintとして扱う必要はありません。では、64ビットプロセスから32ビットプロセスに呼び出すときに、余分な32ビットに何が起こると思いますか?

物理学の違反のように聞こえます。

インプロセスのみの場合は、このディスカッションの最後を参照してください: http://www.techtalkz.com/vc-net/125190-how-interop-net-client-com-dll.html

推奨事項は、inttptrの代わりにvoid *を使用して[local]でフラグを立て、マーシャラーが関与しないようにすることです。

C#COMの操作性についてあまり知りませんが、SAFEARRAY(INT_PTR)などを使用してみましたか?

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top