Open7

C#でネイティブ・相互運用するときの道具箱

kenichiudakenichiuda

P/Invokeメソッドでref(またはout)引数がオプションの場合、null値を渡すためにIntPtr版のオーバーロードを追加するのがダルるかったのですが、回避方法を知ったのでメモ。(ただし、unsafeは必要)

詳しくは++C++; // 未確認飛行 C さんの参照渡しとポインターの相互変換を見てください。
っていうかほぼパクリです。

TL;DR

  • C# 7から、参照戻り値が使える。
  • Unsafe.AsRefメソッドで、null値を参照に変えられる。

下記のようなP/Invokeメソッドを考える。

[System.Runtime.InteropServices.DllImport("Kernel32.dll")]
static extern bool GetDiskFreeSpaceEx(
  string lpDirectoryName,
  out ulong lpFreeBytesAvailableToCaller,
  out ulong lpTotalNumberOfBytes,
  out ulong lpTotalNumberOfFreeBytes
);

System.Runtime.CompilerServices.Unsafe パッケージをプロジェクトに追加して、ユーティリティ関数を用意する。

unsafe static ref T NullRef<T>()
{
    return ref Unsafe.AsRef<T>(null);
}

下記の様に呼び出す。

GetDiskFreeSpaceEx("C:", out NullRef<ulong>(), out var lpTotalNumberOfBytes, out NullRef<ulong>());
kenichiudakenichiuda

戻り値がHRESULT型の関数でマーシャラー側でエラーチェックを行う場合、
[DllImport]PreserveSig = falseを付与して戻り値をvoidとすることができる。