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
You need to ensure that the structure you’re marshaling has the same layout as the native structure using the
StructLayoutattribute, eg.In addition, you need to explicitly mark any fields with the
MarshalAsattribute 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.AllocwithMarshal.AllocHGlobalfor allocating unmanaged memory, and useMarshal.FreeHGlobalto 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.