2

私はこれを機能させることができます:

[<DllImport("user32.dll")>]
extern bool GetClientRect(nativeint, RECT*)

let getClientRect hwnd =
    let mutable r = RECT()
    if GetClientRect(hwnd, &&r) = false then
        raise <| System.Exception("GetClientRect failed")
    r

しかし、何らかの理由で、これrは例外がスローされることなく、ゼロのままになります。

[<DllImport("user32.dll")>]
extern bool GetClientRect(nativeint, [<Out>] RECT rect)

let getClientRect hwnd =
    let mutable r = RECT()
    if GetClientRect(hwnd, r) = false then
        raise <| System.Exception("GetClientRect failed")
    r

もちろん、ポインタを使用する際の問題は、警告が表示warning FS0051: The use of native pointers may result in unverifiable .NET IL codeされることです。当然のことながらそうです。

何が欠けている可能性がありますか?

編集:それはすでに答えられていますが、記録のために、構造体の定義:

[<Struct>]
type RECT =
    val left:int
    val top:int
    val right:int
    val bottom:int
4

1 に答える 1

5

十分に文書化されていませんが、F#P / Invokeシグニチャでアンパサンド(&)記号を使用することは、参照によって値を渡すための正しい(そして最良の)方法です。refC#パラメーターと同じ型シグネチャにコンパイルされます。パラメータに追加[<Out>]すると、C#パラメータと同じ署名が与えられoutます。

[<DllImport("user32.dll")>]
extern bool GetClientRect(nativeint hWnd, [<Out>] RECT& rect)

let getClientRect hwnd =
    let mutable r : RECT = Unchecked.defaultOf<_>
    if GetClientRect(hwnd, &r) = false then
        raise <| System.Exception("GetClientRect failed")
    r

byref<RECT>の代わりに使用するようにP/Invoke署名をnativeptr<RECT>変更したら、使用した演算子のアドレス(&&)をr単一のアンパサンド(&)に変更する必要があることに注意してください。

から値を取得するだけなので、可変結果値をに初期化して、それがで上書きされることを意図していることを明確にすることをお勧めします。GetClientRectUnchecked.defaultOf<_>GetClientRect

編集:byref(&)を使用するようにP / Invoke署名を変更しても機能しない場合は、リターンタイプでマーシャリング動作を明示的に指定してみることもできます。GetClientRectのMSDNドキュメントには、BOOLが返されると記載されていますが、これは.NETブール値とはまったく同じではありません(BOOLは4バイトの整数値です)。

それを試してみたい場合:

[<DllImport("user32.dll")>]
extern [<return: MarshalAs(UnmanagedType.Bool)>] bool GetClientRect(
    nativeint hWnd, [<Out>] RECT& rect)
于 2012-06-22T02:40:17.417 に答える