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