dangeroushobo
dangeroushobo

Reputation: 1401

Calling C function with pointers from F#

I'm new to F# and trying to communicate with a C-library from F#. I'm able to use several of the functions it provides but the Read() function is proving tricky since it has two parameters which are pointer and return the read content.

Here is the C function definition:

TPCANStatus __stdcall CAN_Read(
        TPCANHandle Channel, 
        TPCANMsg* MessageBuffer, 
        TPCANTimestamp* TimestampBuffer);

And here is the C# definition:

        [DllImport("PCANBasic.dll", EntryPoint = "CAN_Read")]
        public static extern TPCANStatus Read(
            [MarshalAs(UnmanagedType.U2)]
            TPCANHandle Channel,
            out TPCANMsg MessageBuffer,
            out TPCANTimestamp TimestampBuffer);

And here is the F# version I'm working on:

module PCANBasic =
    type TPCANHandle = uint16

    [<Struct>]
    type TPCANTimestamp =
        val millis : uint32
        val millisOverflow : uint16
        val micros : uint16
        new (_millis, _overflow, _micros) = {millis = _millis; millisOverflow = _overflow; micros = _micros}

    [<Struct>]
    type TPCANMsg =
        val mutable id : uint32
        [<MarshalAs(UnmanagedType.U1)>]
        val mutable mstype : byte
        val mutable len : byte
        [<MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)>]
        val mutable data : byte array
        new (_id, _mstype, _len, _data) = {id = _id; mstype = _mstype; len = _len; data = _data}
        new (_id, _data) = {id = _id; mstype = 0x00uy; len = byte (Array.length _data); data = Array.concat [| _data; (Array.zeroCreate 8) |]}

    module private Imported =
        [<DllImport("PCANBasic.dll", EntryPoint="CAN_Read")>]
        extern TPCANStatus Read(
                [<MarshalAs(UnmanagedType.U2)>]
                TPCANHandle Channel,
                [<Out>]
                TPCANMsg MessageBuffer,
                [<Out>]
                TPCANTimestamp TimestampBuffer)

    let read (chan : TPCANHandle, [<Out>] msgbuf : TPCANMsg byref, [<Out>] tsbuf : TPCANTimestamp byref) = 
        Imported.Read(chan, msgbuf, tsbuf)
let main argv =
    ….
     let mbuf = ref (PCANBasic.TPCANMsg(0x010u, Array.zeroCreate 8))
     let tbuf = ref (PCANBasic.TPCANTimestamp(0u,0us,0us))
     let status = PCANBasic.read(handle, mbuf, tbuf)           //Error here

The last line shows an error:

Severity    Code    Description Project File    Line    Suppression State
Error   FS0001  This expression was expected to have type
    'byref<PCANBasic.TPCANMsg>'    
but here has type
    'PCANBasic.TPCANMsg ref'    CANTestApp  C:\Users\source\repos\CANTestApp\CANTestApp\Program.fs  189 Active

How can I correctly call this C function with pointers from F#? Do you need the [<Out>] attribute when you use byref?

Upvotes: 3

Views: 442

Answers (1)

rob.earwaker
rob.earwaker

Reputation: 1286

Couple of options for this.

Option #1

Create a byref or outref rather than a ref by binding mbuf and tbuf as mutable values and then passing them "by reference" using &.

let main argv =
    ...
    let mutable mbuf = PCANBasic.TPCANMsg(0x010u, Array.zeroCreate 8)
    let mutable tbuf = PCANBasic.TPCANTimestamp(0u,0us,0us)
    let status = PCANBasic.read(handle, &mbuf, &tbuf)

Option #2

Define read as a member rather than a function to allow it to be invoked with ref arguments rather than byref. Your main function can then stay the same other than referencing the static Reader.Read method rather than the read function.

type Reader =
    static member Read (chan : TPCANHandle, [<Out>] msgbuf : TPCANMsg byref, [<Out>] tsbuf : TPCANTimestamp byref) =
        Imported.Read(chan, msgbuf, tsbuf)

[<Out>] Attribute

Looking at F# RFC FS-1053 indicates that a byref<T> argument with the [<Out>] attribute is equivalent to an outref<T> argument, so your read function/member definition could be (slightly) shortened to:

let read (chan : TPCANHandle, msgbuf : TPCANMsg outref, tsbuf : TPCANTimestamp outref) =
    Imported.Read(chan, msgbuf, tsbuf)

Upvotes: 3

Related Questions