tags:

views:

52

answers:

2

I have such a C++ structure:

typedef struct _FILE_OP_BLOCK
{                                                                                                                          
    unsigned short fid;     // objective file ID 
    unsigned short offset;  // operating offset
    unsigned char len;      // buffer length(update)
                            // read length(read)        
    unsigned char buff[240];
} FILE_OP_BLOCK;

And now I want to map it in .Net. The tricky thing is that the I should pass a 2 byte array for fid, and integer for len, even though in C# fid is an unsigned short and len is an unsigned char

I wonder whether my structure ( in C#) below is correct?

   [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Auto)]
   public struct File_OP_Block 
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        public byte[] fid;

        public ushort offset;

        public byte length;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 240)]
        public char[] buff;
    }
A: 

Given that the C++ short data type is actually two bytes, a two byte array should work. The integer sizes in C/C++ are not strictly defined, so the standard only says that a short is at least two bytes.

The C# char data type is a 16 bit unicode character, so that doesn't match the C++ char data type which is an 8 bit data type. You either need an attribute to specify how the characters are encoded into bytes, or use a byte array.

You might need an attribute to specify the packing, so that there is no padding between the members.

Guffa
I've put on an attribute, not sure whether that's correct or not.
Ngu Soon Hui
@Ngu Soon Hui: The layout settings looks correct. You should use Charset.Ansi to get an 8 bit character set.
Guffa
@Guffa, just wonder, how to use byte array, instead of attribute?
Ngu Soon Hui
+1  A: 

Your CharSet property on the [DllImport] attribute is definitely wrong, you need CharSet.Ansi to get the P/Invoke marshaller to convert it to a char[]. Declare the buff member as a string for easier usage. While declaring the fid member as a byte[] isn't wrong, I really don't see the point of it. That the unmanaged code copies a char[] into it is an implementation detail. Thus:

[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct File_OP_Block 
{
    public ushort fid;
    public ushort offset;
    public byte length;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 240)]
    public string buff;
}
Hans Passant