TL;DR
StructLayout属性でSizeを指定した構造体を用意する。- それを
refとSpan構造体で読み出す。
unsafeステートメントとマーシャラーを使用する場合
P/Invokeで、固定長サイズ配列を含む構造体を受け渡す場合、主に下記の2つの方法を用いると思います。GetMonitorInfoとMONITORINFOを例にすると、下記のような定義です。
ネイティブの定義(UNICODEビルド前提で簡略可)
#define CCHDEVICENAME 32
structMONITORINFOEX{DWORDcbSize;RECTrcMonitor;RECTrcWork;DWORDdwFlags;WCHARszDevice[CCHDEVICENAME];};BOOLWINAPIGetMonitorInfo(HMONITORhMonitor,LPMONITORINFOlpmi);unsafeステートメントの場合
[StructLayout(LayoutKind.Sequential)]unsafestructMONITORINFOEX{publicintcbSize;publicRECTrcMonitor;publicRECTrcWork;publicuintdwFlags;publicfixedcharszDevice[32];};[DllImport("User32.dll",CharSet=CharSet.Unicode)]staticexternboolGetMonitorInfo(IntPtrhMonitor,refMONITORINFOEXlpmi);この後、unsafeコンテキストでMONITORINFOEX.szDeviceから文字列などにコピーする必要があります。
マーシャリングする場合
[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Unicode)]structMONITORINFOEX{// ...省略...[MarshalAs(UnmanagedType.ByValArray,SizeConst=32)]publicchar[]szDevice;};[DllImport("User32.dll",CharSet=CharSet.Unicode)]staticexternboolGetMonitorInfo(IntPtrhMonitor,refMONITORINFOEXlpmi);※MONITORINFOEX.szDeviceはstring/ByValTStrにしたほうが扱いやすいですが、対比のためchar[]/ByValArrayにしています。
問題点
unsafeを使った方がヒープにオブジェクトを作成しない分効率がいいんですが、呼び出し元でもunsafeコンテキストが必要になるので、取り扱いづらいです。
(まぁP/Invokeを使う時点でパフォーマンスを気にしないほうがいいんですが。)
StructLayout属性でSizeを指定した構造体を用意する。
ここからが本題です。
昔からですが、StructLayout属性にはSizeフィールドがあり、構造体のサイズを設定出来ます。
[StructLayout(LayoutKind.Sequential,Size=32*sizeof(char),CharSet=CharSet.Unicode)]publicstructFixedLengthCharArray32{publiccharFirst;}ただサイズを設定できるだけで、中身を参照を参照しようとするとunsafeステートメントが必要なので、この構造体を使う意義がありませんでした。
refとSpan構造体で読み出す
そこでrefとSpan構造体です。
フィールドの参照からSpan構造体を構築すれば、後はToStringなりインデクサーでアクセス出来ます。
unsafeコンテキストも要らないので扱いやすいです。
varmonitorInfo=newMONITORINFOEX{cbSize=Unsafe.SizeOf<MONITORINFOEX>()};GetMonitorInfo(hMonitor,refmonitorInfo);vars=MemoryMarshal.CreateReadOnlySpan(refmonitorInfo.szDevice.First,32);残念ながら.NetStandard 2.0(.NET Framework)だとMemoryMarshal.CreateReadOnlySpanが無いので、相当するメソッドをunsafeコンテキストで実装する(もしくはライブラリを使用する等の)必要があります。
一般化
配列の型とサイズ毎に構造体を用意する必要があり定型コードが多いので、自動生成などをしたほうがいいでしょう。
T4テンプレート等で作成してみたバージョンはこちら。