带指针的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)