我不确定这个的语法。我正在尝试将这个C#代码翻译成F#。
struct LASTINPUTINFO
{
public uint cbSize;
public uint dwTime;
}
public class IdleTimer
{
[DllImport("User32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
}
这是我到目前为止所做的。
type LASTINPUTINFO = {
cbSize : UInt32;
dwTime : UInt32;
}
type IdleTimer =
[<DllImport("User32.dll")>]
[<return: MarshalAs(UnmanagedType.Bool)>]
extern GetLastInputInfo(plii : LASTINPUTINFO ref)
答案 0 :(得分:10)
除了Brian的评论之外,可能值得指出的是,F#extern签名相当忠实地反映了C签名,因此您可以将参数声明为{{[<In>][<Out>]
,而不是在引用上使用LASTINPUTINFO* plii
属性。 1}},然后使用&amp;&amp ;;传递对本地实例的引用调用函数时的运算符。
答案 1 :(得分:8)
老实说,我没有尝试过运行或使用它,但这会编译,并希望能引导你朝正确的方向发展。
open System
open System.Runtime.InteropServices
[<Struct>]
type LASTINPUTINFO =
val cbSize : UInt32
val dwTime : UInt32
module IdleTimer =
[<DllImport("User32.dll")>]
extern [<MarshalAs(UnmanagedType.Bool)>] bool GetLastInputInfo([<In>][<Out>] LASTINPUTINFO plii)
答案 2 :(得分:3)
除了kvb的评论之外,我发现将参数声明为指针会混淆当前的FSharp Power Tools重构引擎。您可以使用IntPtr
来解决这个问题:
open System
open System.Runtime.InteropServices
open Microsoft.FSharp.NativeInterop
[<Struct>]
type LASTINPUTINFO =
val mutable cbSize : uint32
val dwTime : uint32
[<DllImport("user32.dll")>]
extern bool GetLastInputInfo(IntPtr p)
let getLastInputTime() =
let mutable time = LASTINPUTINFO(cbSize = 8u)
GetLastInputInfo(NativePtr.toNativeInt &&time) |> ignore
time.dwTime
答案 3 :(得分:0)
最新答案:
在大多数情况下,使用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* minor, int* patch)
let mutable major,minor,patch = 0,0,0
getVersion(&&major,&&minor,&&patch)
printfn "Version: %i.%i.%i" major minor patch
但是,这不太正确。事实证明,在处理CLR时,有两种类型的指针:非托管和托管。后者是在按引用传递CLR类型时使用的内容(即F#中的“ byref <'T>”或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,minor,patch = 0,0,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代码。
作为额外的注释,必须将变量标记为可变的,以作为byref传递。传递具有可变属性的非可变对象是只读的inref。方便通过引用传递只读值类型。 F# ByRef and InRef