微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在F#中正确使用带有指针的P /调用

如何解决在F#中正确使用带有指针的P /调用

我正在尝试将此c#代码转换为f#:

[DllImport("psapi.dll",SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetPerformanceInfo([Out] out Performanceinformation Performanceinformation,[In] int Size);

这是我到目前为止所拥有的:

[<DllImport("psapi.dll",SetLastError = true)>]
extern [<return: MarshalAs(UnmanagedType.Bool)>] bool GetPerformanceInfo(PerfInfo Performanceinformation,int Size)

传递必要参数的正确方法是什么?指针,byrefs或其他东西。 另外,[Out]和[In]属性在做什么?

编辑:我已经回答了一些问题,但还有几个问题。 我是否需要为Size参数指定一个[],一个inref,还是简单地推断出来?

解决方法

这是我研究的部分答案。

在大多数情况下,使用P / Invoke时,您可以简单地从C头文件(当然是sans-semi-colons)中复制并粘贴签名。但是,至少有一种情况天真地这样做会产生不是可验证类型安全的代码。我们来看一个具体的例子。给定C语言中的follow函数原型:

__declspec(dllexport) void getVersion (int* major,int* minor,int* patch);

一个人可能会在F#中使用以下P / Invoke签名(和相关的调用):

[<DllImport("somelib",CallingConvention=CallingConvention.Cdecl)>]
extern void getVersion (int* major,int* patch)

let mutable major,minor,patch = 0,0
getVersion(&&major,&&minor,&&patch)
printfn "Version: %i.%i.%i" major minor patch

但是,这不太正确。事实证明,在处理CLR时,有两种类型的指针:非托管和托管。后者是在按引用传递CLR类型时使用的内容(即F#中的“ byref ”或C#中的“ ref”或VB中的“ ByRef”)。如果您希望F#代码具有可验证类型安全性,还应该使用托管品种,其中包括P / Invoke调用。如果您考虑一下,这是有道理的。运行时只能保证它可以控制的位(即被“管理”的部分)。因此,下面是使用托管指针的F#代码的样子:

[<DllImport("somelib",CallingConvention=CallingConvention.Cdecl)>]
extern void getVersion (int& major,int& minor,int& patch)

let mutable major,0
getVersion(&major,&minor,&patch)
printfn "Version: %i.%i.%i" major minor patch

方便的桌子:

Pointer    F#             Type Declaration      Invocation
Unmanaged  nativeint      <type>*               &&<type>
Managed    byref <type>   <type>&               &type

在几乎所有情况下,.NET开发人员都应该首选托管指针。将不受管理的风险留给C代码。

编辑源:P/Invoke Gotcha in f#

作为额外的注释,必须将变量标记为可变的,以作为byref传递。传递具有可变属性的非可变对象是只读的inref。方便通过引用传递只读值类型。 F# ByRef and InRef

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。