19

次の C++ 関数定義があり、マネージ コードから PInvoke を介して呼び出そうとしています。

bool FooBar(SIZE_T* arg1);

私のマネージ宣言は次のようになりました。

[DllImport("mydll", SetLastError=true, CharSet=CharSet.Unicode)]
private static extern bool FooBar(ref uint arg1);

一部の人は、私が最終的に行ったのと同じバグに気付くかもしれません。これは 64 ビット ポータブルではありません。SIZE_T は可変サイズ (32 ~ 64 ビット) で、それへのポインタです。管理されたサイズでは、ポインターは 64 ビットに正しく変換されますが、uint は変換されず、arg1 の上位ビットにゴミが残る可能性があります。ゴミ箱はしばしばゼロだったので、これは特に永続的なエラーでした:(

私がうまくいった唯一の解決策は、次のマネージド宣言です。

[DllImport("mydll", SetLastError=true, CharSet=CharSet.Unicode)]
private static extern bool FooBar(ref IntPtr arg1);

IntPtr はそのサイズを正しく変更できるため、これはもちろん機能します。私のコードでは、IntPtr を整数として扱うだけで動作しますが、醜いハックのように見えます。おそらくUnmanagedType.SysUIntを使用して、これを適切に指定する方法があるはずですが、他の有効な解決策を思い付くことができませんでした。

4

2 に答える 2

22

適切に使用IntPtrおよび/または実行してUIntPtr いる- タイプはこの目的のために特別に用意されています! あなたがそれを「醜いハック」と考える理由がわかりません。また、提案された代替案がどうなるかわかりませんuint-C#はアーキテクチャに関係なく32ビットであることが保証されているため、値をマップできる属性は本質的に間違っていuintます.64ビットプラットフォームではそうです、それを正しくマーシャリングするには、その半分をトリミングする必要があり、データが失われ、結果が役に立たなくなる可能性があります。

于 2009-08-21T00:19:39.630 に答える
18

UIntPtrは、使用する正しい型です。

size_t は符号なしのポインタ サイズの整数であり、それはまさに UIntPtr の意味です。名前の「ptr」は少し紛らわしいかもしれませんが、同意します。実際には「これはポインターです」という意味ではなく、「これはポインターサイズの整数です」という意味です。したがって、宣言は次のようになります。

[DllImport("mydll", SetLastError=true, CharSet=CharSet.Unicode)]
private static extern bool FooBar(ref UIntPtr arg1);
于 2009-08-21T01:32:44.473 に答える