如何将 StructureToPtr 与 F# 结构结合使用?麻烦类型
我有结构:
type OneDevice = {
mutable id : System.UInt16
mutable typeDev : byte
mutable portNum : byte
mutable Parity : byte
mutable StopBits : byte
mutable BaudRate : byte
mutable addr1 : byte
mutable addr2 : byte
mutable useCanal : byte
mutable idGroup1 : byte
mutable idGroup2 : byte
mutable idGroup3 : byte
mutable idGroup4 : byte
mutable idGroupSos1 : byte
mutable idGroupSos2 : byte
mutable idGroupSos3 : byte
mutable idGroupSos4 : byte
mutable idSosReserv : byte
mutable addrModbus : byte
mutable offsetModbus : System.UInt16
mutable pwd : byte array
mutable offsetInModbus : System.UInt16
mutable reserv : System.UInt16
}
我需要复制一些将其用作字节数组。在 C# 中,我可以在这里声明字节数组的大小,但现在我不知道 pwd 的大小。
我正在尝试使用:
let memcp(device : OneDevice, bytes : byte array) =
Array.zeroCreate <| Marshal.SizeOf(typeof<OneDevice>)
|> fun (array : byte array) ->
GCHandle.Alloc(array, GCHandleType.Pinned) |> fun handle ->
Marshal.StructureToPtr(device, handle.AddrOfPinnedObject(), true)
handle.Free()
但收到错误消息:
错误无法将类型“Model + OneDevice”打包为非托管类型 结构;无法计算有意义的大小或偏移。
我认为这是因为我不知道这里的 pwd 大小。那么我该如何在 F# Structure 上使用它呢?或者也许我可以以某种方式声明静态大小数组类型?
谢谢
I've got structure :
type OneDevice = {
mutable id : System.UInt16
mutable typeDev : byte
mutable portNum : byte
mutable Parity : byte
mutable StopBits : byte
mutable BaudRate : byte
mutable addr1 : byte
mutable addr2 : byte
mutable useCanal : byte
mutable idGroup1 : byte
mutable idGroup2 : byte
mutable idGroup3 : byte
mutable idGroup4 : byte
mutable idGroupSos1 : byte
mutable idGroupSos2 : byte
mutable idGroupSos3 : byte
mutable idGroupSos4 : byte
mutable idSosReserv : byte
mutable addrModbus : byte
mutable offsetModbus : System.UInt16
mutable pwd : byte array
mutable offsetInModbus : System.UInt16
mutable reserv : System.UInt16
}
And I need to copy some use it as byte array. In C# I can declare the size of byte array here, but for now I don't know the size of pwd.
I'm trying to use :
let memcp(device : OneDevice, bytes : byte array) =
Array.zeroCreate <| Marshal.SizeOf(typeof<OneDevice>)
|> fun (array : byte array) ->
GCHandle.Alloc(array, GCHandleType.Pinned) |> fun handle ->
Marshal.StructureToPtr(device, handle.AddrOfPinnedObject(), true)
handle.Free()
But got error message :
Error Unable to package type "Model + OneDevice" as an unmanaged
structure; impossible to calculate the size or offset that make sense.
I think that is because I don't know the pwd size here. So how can I use it on F# Structure then ? Or maybe I can declare static-size array type somehow ?
Thank you
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您需要使用
StructLayout
属性确保要封送的结构与本机结构具有相同的布局,例如。此外,如果任何字段需要使用非默认封送行为(例如数组)进行封送,则需要使用
MarshalAs
属性显式标记它们。数组的默认封送行为是LPArray
,但听上去,您的本机结构需要ByValArray
。最后,将
GCHandle.Alloc
替换为Marshal.AllocHGlobal
来分配非托管内存,并使用Marshal.FreeHGlobal
释放它。注意:我不确定 F# 记录类型是否可以接受这些属性,但我希望它们能够工作。如果没有,那么您需要将它们与 jpalmer 使用
struct
的建议结合使用。编辑:
编辑:
以上用于将填充的 OneDevice 结构复制到空字节数组中。如果您想做相反的事情 - 将填充的字节数组转换为结构,这在很大程度上是相同的事情。
You need to ensure that the structure you're marshaling has the same layout as the native structure using the
StructLayout
attribute, eg.In addition, you need to explicitly mark any fields with the
MarshalAs
attribute if they require marshaling with non-default marshaling behavior, such as arrays. The default marshaling behavior for arrays isLPArray
, but by the sounds of it, your native structure is expecting aByValArray
.Lastly, replace
GCHandle.Alloc
withMarshal.AllocHGlobal
for allocating unmanaged memory, and useMarshal.FreeHGlobal
to free it.Note: I'm uncertain whether F# record types can accept these attributes, but I would expect them to work. If not, then you would need to use them in combination with jpalmer's suggestion of using a
struct
.Edit:
Edit:
The above is for copying a populated OneDevice structure into an empty byte array. If you want to do the reverse - converting a populated byte array into a structure, it's largely the same thing.
我认为你想要的是创建一个结构。在 F# 中,您可以使用
I think what you want is to creat a struct. In F# you do this with