小ネタです。一時的に配列の生ポインタが欲しかったので、RAIIでピン止めするクラスを作りました。

open System
open System.Runtime.InteropServices

type Pin(o) =
    let gch = GCHandle.Alloc(o, GCHandleType.Pinned)
    member x.Addr = gch.AddrOfPinnedObject()
    interface IDisposable with member x.Dispose() = gch.Free()

一行doで使う例を示します。

let a = [|0; 1; 2; 3|]
do use p = new Pin(a) in printfn "0x%x" p.Addr

P/Invoke

P/Invokeと組み合わせた例です。

[<DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)>]
extern int puts(nativeint s)

let s = [|'a'B; 'b'B; 'c'B; 0uy|]
do use p = new Pin(s) in puts p.Addr |> ignore

この例ではnativeintで渡すために無理矢理ピン止めしていますが、普通はそんなことをする必要はありません。

[<DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)>]
extern int puts(byte[] s)

let s = [|'a'B; 'b'B; 'c'B; 0uy|]
puts s |> ignore

ピン止めのことを意識していれば、byte[]を指定しても裏側ではマーシャリングでピン止めされている状況が想像できます。

引数にobjを指定してもコンパイルは通りますが、実行時にアクセス違反が発生します。

アクセス違反
[<DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)>]
extern int puts(obj s)

let s = [|'a'B; 'b'B; 'c'B; 0uy|]
puts s |> ignore

動機

OpenGLには glVertexPointer() の第4引数pointerのように、引数で渡す配列の型が可変な関数があります。型ごとに別のP/Invokeを定義する以外の方法として、一時的に生ポインタを取得することを試みました。

F#でのOpenGLについては以下の記事を参照してください。