arrays, structs, pointers, casting - help!

K

kelli

i am new to c# so if this is a trivial problem, forgive me! i've
searched the web and after 2 days still cannot solve it. i am
converting a c++ application to c# - the problem code is listed below.
the c++ code uses a byte array (msg[256]) to hold a serial message.
since the message can be of different layouts, the array is cast to the
appropriate layout "type" (struct SERIAL_CAN_MSG_TYPE, in this
example). to complicate things, there is an array at the end of the
SERIAL_CAN_MSG_TYPE struct, data[], which can hold variable data types
(byte, ushort, and uint) -AND- can be of variable length (more than 2
elements). with that said, here's the c++ code:

---------- start c++ code -------------
typedef unsigned char INT_8U;
typedef unsigned short int INT_16U;
typedef short int INT_16;
....
typedef struct
{
INT_8U priority;
INT_16 dlc;
INT_8U messageType;
INT_8U channel;
INT_8U data[2];
}SERIAL_CAN_MSG_TYPE;
....
INT_8U msg[256];
SERIAL_CAN_MSG_TYPE* msgPtr;
msgPtr = (SERIAL_CAN_MSG_TYPE*)&(msg[0]);
....
// uses casting to assign a ushort to the byte array (data)
for(i = 0; i < 64; i++)
{
*((INT_16U *)&msgPtr->data[i*4]) = spoolChannel.address;
}
------- end c++ code --------

..... and here's my attempt at converting to c#:

----------- start c# code ------------
[StructLayout(LayoutKind.Explicit)]
unsafe public struct SERIAL_CAN_MSG_TYPE
{
[FieldOffset(0)]public byte priority;
[FieldOffset(1)]public short dlc;
[FieldOffset(3)]public byte messageType;
[FieldOffset(4)]public byte channel;
// to take care of diff element types in 1 array,
// since i can't cast on left-hand side of equation
[FieldOffset(5)]public byte [] dataBytePtr;
[FieldOffset(5)]public ushort [] dataUshortPtr;
[FieldOffset(5)]public uint [] dataUintPtr;
};
....
byte [] msg = new byte[256];
fixed(SERIAL_CAN_MSG_TYPE * msgPtr = (SERIAL_CAN_MSG_TYPE*) msg[0])
{
...
for(i = 0; i < 64; i++)
{
// assigns a ushort to the data array using ushort ptr
msgPtr->dataUshortPtr = spoolChannel.address;
}
...
}
----------- end c# code --------

above c# code produces error:
"Cannot take the address or size of a variable of a managed
type('SERIAL_CAN_MSG_TYPE')"
on the "fixed" line.

i've read that in c#, a pointer is not permitted to point to a struct
that contains references (arrays). i'm sure it has something to do
with managed/unmanaged code, but i don't understand it deep enough to
figure out a solution!

thanks for any help...
 
K

kelli

oops, forgot the "&" in the c# line:
fixed(SERIAL_CAN_MSG_TYPE * msgPtr = (SERIAL_CAN_MSG_TYPE*) &msg[0])
kelli
 
F

Franco, Gustavo

Doesn't it work for you?

[StructLayout(LayoutKind.Explicit)]
unsafe public struct SERIAL_CAN_MSG_TYPE
{
[FieldOffset(0)]public byte priority;
[FieldOffset(1)]public short dlc;
[FieldOffset(3)]public byte messageType;
[FieldOffset(4)]public byte channel;
// to take care of diff element types in 1 array,
// since i can't cast on left-hand side of equation
[FieldOffset(5)]public byte [] dataBytePtr;
[FieldOffset(5)]public ushort [] dataUshortPtr;
[FieldOffset(5)]public uint [] dataUintPtr;
};

public unsafe void test()
{
byte [] msg = new byte[256];

fixed(byte *msgPtr = msg)
{
SERIAL_CAN_MSG_TYPE newStruct = new SERIAL_CAN_MSG_TYPE();

Marshal.PtrToStructure((IntPtr) msgPtr, newStruct);

fixed(ushort *ushortPtr = newStruct.dataUshortPtr)
{
for(int i = 0; i < 64; i++)
{
// assigns a ushort to the data array using ushort ptr
*(ushortPtr + i) = 0;//spoolChannel.address;
}
}
}
}

It doesn't cast you msg[256] into a SERIAL_CAN_MSG_TYPE, PtrToStructure
(basically a memcpy) fill the new struct and from there work with it.

Is it mandatory to modificate the values on the original msg[256] or can you
use the newStruct???

Gustavo.
 
K

kelli

gustavo - thank you so much - it does seem to work (compiles anyway!).

you may be right - i think i can fill the structure, then use
Marshal.Copy (maybe?) to get the data into a byte array which is passed
to the next function.
 
F

Franco, Gustavo

If you need back the array then may be you can use



Marshal.StructureToPtr(newStruct, (IntPtr) msgPtr, true);



Marshal.Copy also should work, but I don't know if it could have some
problem.



Gustavo.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top