LoginSignup
1
0

More than 5 years have passed since last update.

RAIIでピン止め

Last updated at Posted at 2017-02-01

小ネタです。一時的に配列の生ポインタが欲しかったので、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については以下の記事を参照してください。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0