.net 使用来自F的指针调用C函数#
我是F#的新手,试图与F#的C库进行通信。我可以使用它提供的几个函数,但是Read()函数很棘手,因为它有两个参数,即指针和返回读取内容 以下是C函数定义:.net 使用来自F的指针调用C函数#,.net,f#,.net,F#,我是F#的新手,试图与F#的C库进行通信。我可以使用它提供的几个函数,但是Read()函数很棘手,因为它有两个参数,即指针和返回读取内容 以下是C函数定义: TPCANStatus __stdcall CAN_Read( TPCANHandle Channel, TPCANMsg* MessageBuffer, TPCANTimestamp* TimestampBuffer); [DllImport("PCANBasic.dl
TPCANStatus __stdcall CAN_Read(
TPCANHandle Channel,
TPCANMsg* MessageBuffer,
TPCANTimestamp* TimestampBuffer);
[DllImport("PCANBasic.dll", EntryPoint = "CAN_Read")]
public static extern TPCANStatus Read(
[MarshalAs(UnmanagedType.U2)]
TPCANHandle Channel,
out TPCANMsg MessageBuffer,
out TPCANTimestamp TimestampBuffer);
这里是C#的定义:
TPCANStatus __stdcall CAN_Read(
TPCANHandle Channel,
TPCANMsg* MessageBuffer,
TPCANTimestamp* TimestampBuffer);
[DllImport("PCANBasic.dll", EntryPoint = "CAN_Read")]
public static extern TPCANStatus Read(
[MarshalAs(UnmanagedType.U2)]
TPCANHandle Channel,
out TPCANMsg MessageBuffer,
out TPCANTimestamp TimestampBuffer);
这是我正在研究的F版本:
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)
最后一行显示一个错误:
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
严重性代码描述项目文件行抑制状态
错误FS0001此表达式应具有类型
“拜里夫”
但这里有一种类型
“PCANBasic.TPCANMsg ref”CANTestApp C:\Users\source\repos\CANTestApp\CANTestApp\Program.fs 189处于活动状态
如何使用F#中的指针正确调用此C函数?使用
byref
时是否需要[]
属性?为此提供了两个选项
选项1
通过将mbuf
和tbuf
绑定为可变值,然后使用和通过引用传递它们,创建byref
或outref
而不是ref
let main argv=
...
让可变mbuf=PCANBasic.TPCANMsg(0x010u,Array.zeroCreate 8)
设可变tbuf=PCANBasic.TPCANTimestamp(0u,0us,0us)
let status=PCANBasic.read(句柄、&mbuf、&tbuf)
选项2
将read
定义为成员而不是函数,以允许使用ref
参数而不是byref
调用它。然后,您的main
函数可以保持不变,而不是引用静态Reader.Read
方法,而不是Read
函数
类型读取器=
静态成员读取(chan:TPCANHandle,[]msgbuf:TPCANMsg byref,[]tsbuf:TPCANTimestamp byref)=
导入。读取(chan、msgbuf、tsbuf)
[]
属性
查看表明带有[]
属性的byref
参数等同于outref
参数,因此您的read
函数/成员定义可以(稍微)缩短为:
let read(chan:TPCANHandle,msgbuf:TPCANMsg outref,tsbuf:TPCANTimestamp outref)=
导入。读取(chan、msgbuf、tsbuf)
我尝试了选项1,这消除了我看到的错误,但mbuf不包含函数调用后预期的数据。啊,我认为[]
外部定义中的参数需要包含&
,也就是说,TPCANMsg&MessageBuffer
和TPCANTimestamp&TimestampBuffer
在函数调用后仍然没有获得预期的数据。我注意到函数立即返回,而不是暂停输入。这可能是由于mbuf
中的初始值造成的吗?在没有看到更多C#实现的情况下,我唯一能建议的是检查结构是否定义正确(字段名称、字段类型等)。您使用的TPCANMsg
构造函数看起来也有点可疑,因为您将输入数组与另一个长度为8的数组连接起来,然后分配给一个总长度应仅为8的字段。字段类型看起来不错,但您需要更新字段名,使其与C#字段完全匹配,否则C实现将无法正确引用它们。