gpt4 book ai didi

f# p/invoke on GetClientRect with pointers works 但不适用于 OutAttribute

转载 作者:行者123 更新时间:2023-12-02 22:38:05 25 4
gpt4 key购买 nike

我可以让它工作:

[<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

最佳答案

它没有很好的文档记录,但在 F# P/Invoke 签名中使用与符号 (&) 是通过引用传递值的正确(也是最佳)方法。它编译为与 C# 相同的类型签名 ref范围;添加[<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

请注意,一旦您将 P/Invoke 签名更改为使用 byref<RECT>而不是 nativeptr<RECT> ,您还需要更改在 r 上使用的地址运算符 (&&)到单个与号 (&)。

因为您只能得到 GetClientRect 值, 将可变结果值初始化为 Unchecked.defaultOf<_> 是一个好习惯所以很明显它会被 GetClientRect 覆盖.

编辑:如果将 P/Invoke 签名更改为使用 byref (&) 不起作用,您还可以尝试在返回类型上显式指定编码行为。 GetClientRect 的 MSDN 文档说它返回一个 BOOL,这与 .NET bool 不太一样(BOOL 是一个 4 字节整数值)。

如果你想尝试一下:

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

关于f# p/invoke on GetClientRect with pointers works 但不适用于 OutAttribute,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11149250/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com