yohhoyの日記

技術的メモをしていきたい日記

P/Invokeとパラメータ方向属性

C#からのP/Invokeにおけるパラメータの方向属性*1についてメモ。

C#における既定の方向属性は下表のとおり。呼び出し元/呼び出し先はマネージド(C#)/アンマネージド(native)いずれかになる。つまりexternメソッド呼び出しであればC#→nativeとなり、アンマネージ関数ポインタからのC#デリゲート呼び出しであればnative→C#となる。

C#パラメータ 既定値 効果
(修飾なし) [In] 呼び出すとき(前)に引数データをマーシャリング
out修飾 [Out] 呼び出し先から戻るときに引数データをマーシャリング
ref修飾 [In,Out] 上記2つを両方とも適用する
StringBuilder [In,Out] (StringBuilderはCLRマーシャラから特殊扱い)*2

ref修飾パラメータの既定値はIn,Out属性となっているため、参照渡しするC#構造体(値型)が呼び出し先で変更されないと分かっている場合は、該当パラメータに対してIn属性を明示指定する方が実行効率が良い。もしくは、既定でIn属性かつ参照渡しが行われるC#クラス(参照型)を使用する。

// native.dll
//   void WINAPI SetSomeInfo(const SomeStruct *ps);

struct SomeStruct { ... }
[DllImport("native.dll")]
extern void SetSomeInfo([In] ref SomeStruct s);
// または
class SomeStruct { ... }
[DllImport("native.dll")]
extern void SetSomeInfo(SomeStruct s);

関連URL

*1:InAttribute, OutAttributeが正式名称だが、C#(とVB)では語末のAttributeを省略したIn, Outも利用できる。詳細はMSDN参照。

*2:P/InvokeのパラメータではStringBufferクラスは通常ref/out修飾なしで利用する。詳細は"CLR Inside Out"記事を参照のこと。