1

ポインターを返すことができる MIDL で COM インターフェイスを宣言したいと考えています ( のようにID3D11Blob)。RPC 呼び出し用にスタブが生成されるため、COM ではポインタが特別なものであることを理解しています。RPC は必要ありませんが、C# から COM サーバーにアクセスしたいだけです。IntPtr問題は、C# スタブが?を返すような方法でインターフェイスを宣言できるかどうかです。[local]ポインターを有効にするために追加しようとしましvoidたが、それだけでは十分ではありません。

インターフェイスは、MIDL のように見える必要があります

[local] void *PeekData(void)

そしてC#のように

IntPtr PeekData()

これは可能ですか?もしそうなら、どのように?

前もって感謝します、クリストフ

編集:質問を言い換えると:なぜ

HRESULT GetData([in, out, size_is(*size)] BYTE data[], [in, out] ULONG *size);

なり

void GetData(ref byte, ref uint)

byteC#で最初のパラメータが単一になるのを避けるにはどうすればよいですか?

4

2 に答える 2

3

タイプ ライブラリから COM サーバー宣言をインポートしたため、これは正しくありません。タイプ ライブラリは、もともと "OLE オートメーション" と呼ばれていた COM のサブセットをサポートするために設計されました。メソッドの引数に使用できる型の種類を制限します。特に、生のポインタは許可されていません。配列は SAFEARRAY として宣言する必要があります。これにより、呼び出し元は常に安全に配列にインデックスを付けることができます。安全な配列には、配列のランクと下限/上限を説明する追加のメタデータがあります。

[size_is] 属性は MIDL によってのみ認識され、インターフェイスのプロキシとスタブを作成するために使用されます。配列に含まれる要素の数を知ることは、ワイヤ上でスタブに送信される相互運用パケットに配列をコピーする必要がある場合にも重要です。

タイプ ライブラリはこのような宣言をサポートしていないため、[size_is] 属性は削除され、タイプ ライブラリ インポーターは BYTE* のみを認識します。これはあいまいです。参照によって渡されたバイトであるか、バイト配列へのポインターである可能性があります。インポーターは、配列を機能させる見込みがなく、配列のサイズがわからないため、前者を選択します。だからあなたは得るref byte

この問題を解決するには、メソッドの適切な宣言を提供できるように、インポート ライブラリを変更する必要があります。[MarshalAs] 属性で byte[] 引数を SizeParamIndex プロパティが設定された LPArray として宣言する必要があるため、CLR に配列サイズがsize引数によって決定されることを伝えることができます。これには、次の 2 つの基本的な方法があります。

  • ildasm.exe で相互運用ライブラリを逆コンパイルし、.il ファイルを変更して、ilasm.exe で元に戻します。ildasm.exe で参照するサンプル C# 宣言を使用して、IL の編集方法を理解します。これは、 Microsoft が推奨するアプローチです。

  • IL を C# に逆コンパイルできる適切な逆コンパイラを使用します。Reflector と ILSpy が人気です。生成されたコードをプロジェクトのソース ファイルにコピー アンド ペーストし、[MarshalAs] 属性を適用してメソッドを編集します。利点は、編集が簡単になり、相互運用ライブラリに依存しなくなることです。

どちらの場合でも、頻繁に行う必要がないように、COM サーバーが安定していることを確認する必要があります。そうでない場合は、サーバー自体を変更することを強くお勧めします。セーフ アレイを使用してください。

于 2013-11-28T13:01:24.510 に答える
0

http://msdn.microsoft.com/en-gb/library/z6cfh6e6(v=vs.110).aspx#cpcondefaultmarshalingforarraysanchor2で解決策を見つけたと思います:これは、C スタイルの配列の既定の動作です。sを使用することでそれを回避できSAFEARRAYます。

于 2013-11-28T12:48:06.267 に答える