带指针的GetClientRect上的f#p/invoke可以工作,但不带OutAttribute

带指针的GetClientRect上的f#p/invoke可以工作,但不带OutAttribute,f#,pinvoke,F#,Pinvoke,我可以让它工作: [<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 faile

我可以让它工作:

[<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
当然,使用指针的问题是我得到了警告FS0051:使用本机指针可能会导致无法验证的.NET IL代码,这是可以理解的

我会错过什么

编辑:即使已经回答了,对于记录,结构定义:

[<Struct>]
type RECT =
    val left:int
    val top:int
    val right:int
    val bottom:int
[]
类型RECT=
左:int
val-top:int
右:int
val底部:int

虽然没有很好的文档记录,但在F#p/Invoke签名中使用符号和(&)是通过引用传递值的正确(也是最好的)方法。它编译为与C#
ref
参数相同的类型签名;将
[]
添加到参数中会产生与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

您对
RECT
的定义是什么?类型定义中可能存在值与引用类型的问题。当然,请注意,只有当
RECT
是一个结构时,这才起作用。对于记录,至少在这种情况下,在返回类型上指定封送似乎没有必要。@ildjarn您为什么这么说?ptr(*)运算符仅限于结构,但byref不是。bool参数默认情况下获取MarshalAs(UnmanagedType.bool)属性,这就是为什么您不需要在这里显式封送它的原因。这是正确的——但将
marshallas
属性显式应用于
bool
参数或返回类型被认为是一种良好的做法,因为有几种不同的封送方式:
[<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
[<DllImport("user32.dll")>]
extern [<return: MarshalAs(UnmanagedType.Bool)>] bool GetClientRect(
    nativeint hWnd, [<Out>] RECT& rect)