0

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

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

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

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

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

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

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# 側で何ができるでしょうか?

4

3 に答える 3

1

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

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

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

intptr の代わりに void * を使用し、[local] でフラグを付けて、マーシャラーが関与しないようにすることをお勧めします。

于 2008-10-14T15:52:12.210 に答える
0

C# COM の操作性についてはよくわかりませんが、SAFEARRAY(INT_PTR) などを使用したことはありますか?

于 2008-10-14T01:24:28.857 に答える
0

うーん...私を近づけるいくつかの情報を見つけました...

マーシャリングの変更 - 準拠した 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 を修正する必要のない他のソリューションはありますか?

于 2008-10-14T01:57:40.583 に答える