简体   繁体   中英

F# syntax for P/Invoke signature using MarshalAs

I'm unsure of the syntax for this. I'm trying to translate this C# code into 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);
}

This is what I have so far.

type LASTINPUTINFO = {
    cbSize : UInt32;
    dwTime : UInt32;
}

type IdleTimer =
    [<DllImport("User32.dll")>]
    [<return: MarshalAs(UnmanagedType.Bool)>]
    extern GetLastInputInfo(plii : LASTINPUTINFO ref)

除了 Brian 的评论之外,可能值得指出的是 F# extern 签名相当忠实地反映了 C 签名,因此,与其在引用上使用[<In>][<Out>]属性,您可能只需将参数声明为LASTINPUTINFO* plii ,然后在调用函数时使用 && 运算符传递对本地实例的引用。

Honestly I haven't tried to run or use this, but this compiles, and hopefully will steer you in the right direction.

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)

In addition to kvb's comment, I found that declaring parameters as pointers messes up the current FSharp Power Tools refactor engine. You can use an IntPtr to get around that:

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

An updated answer:

For the most part, when using P/Invoke, one may simply copy-and-paste the signatures from a C header file (sans-semi-colons, of course). However, there is at least one scenario where naïvely doing so produces code which is not verifiably type-safe. Let's look at a specific example. Given the follow function prototype in C:

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

One might use the following P/Invoke signature (and associated call) in 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

However, that isn't quite right. Turns out, when dealing with the CLR, there are two types of pointers: unmanaged and managed. The latter are what you use when passing around CLR types by-reference (ie “byref<'T>“ in F#, or “ref“ in C#, or “ByRef“ in VB). It also happens that you should use the managed variety if you want your F# code to be verifiably type-safe — and this includes P/Invoke calls. If you think about it, this makes sense. The runtime can only guarantee the bits it can control (ie the parts which are “managed”). So here's what the F# code looks like using managed pointers instead:

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

Handy table:

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

In nearly all cases, a .NET developer should prefer the managed pointer. Leave the unmanaged risks with the C code.

Edited Source : P/Invoke Gotcha in f#

As an extra note, to be passed in as a byref the variable must be marked as mutable. Passing a non mutable object, even with mutable properties, is a readonly inref. Handy for passing read only value types by reference. F# ByRef and InRef

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM