Hi All,
After a lot of searching the web and trying different things, I am still no closer to solving the following:
I have written a c++ managed dll that is supposed to act as a wrapper for legacy c code. The c code uses a lot of structures that is filled with data from a host system.
My final GUI application that needs to process this data is written in C#
My c structure:
typedef struct
{
unsigned short u16_RecordType;
unsigned short u16_RecordCode;
char c_MessageType;
unsigned char uc_Filler;
unsigned long u32_MessageCode;
char c_InfoMessage[3][24];
unsigned short u16_CheckSum;
} THE_C_STRUCT;
Which I have declared in my c++ dll as:
[StructLayoutAttribute(LayoutKind::Sequential, Pack=1)]
public value struct MyManagedStruct
{
unsigned short u16_RecordType;
unsigned short u16_RecordCode;
char c_MessageType;
unsigned char uc_Filler;
unsigned long u32_MessageCode;
[MarshalAs(UnmanagedType::ByValArray,SizeConst=72)]
static char ^c_MessageLines = gcnew char[3][24];
unsigned short u16_CheckSum;
};
And then the c++ code to get me the data using the legacy C function. Notice that I use a generic function to convert the byte array of data to the structure object. This function has up to now worked perfectly on all other structures.
Object ^MyWrapperClass::ByteArrayToStructure(array<unsigned char> ^bytearray, int offset, Type ^objType)
{
Object ^returnObj;
int len = Marshal::SizeOf(objType);
IntPtr intPtr = Marshal::AllocHGlobal(len);
Marshal::Copy(bytearray, offset, intPtr, len);
returnObj = Marshal::PtrToStructure(intPtr, objType);
Marshal::FreeHGlobal(intPtr);
return returnObj;
}
int MyWrapperClass::GetStructure([Out] Wrapper_Record %p_s_RecordData)
{
int i_RC;
Type ^t_RecordType = p_s_RecordData.GetType();
array<unsigned char> ^uc_RecordDataArr = gcnew array<unsigned char>(Marshal::SizeOf(p_s_RecordData));
pin_ptr<unsigned char> pp_RecordBuffer = &uc_RecordDataArr[0];
i_RC = LC_GetRecord(pp_RecordBuffer);
if (I_RC == SUCCESS)
p_s_RecordData = (Wrapper_Record)ByteArrayToStructure(uc_RecordDataArr, 0, t_RecordType);
return I_RC;
}
Finally, I am calling the dll from my c# code:
Wrapper_Record wrapperRecord;
MyWrapperClass s = new MyWrapperClass();
int i = s.GetStructure(out wrapperRecord);
My problem:
1. When debugging the function ByteArrayToStructure(), the value of
len is 10! (the structure is supposed to be 84 bytes?)
2. I suspected the array in the structure is the problem, so I changed the structure to:
[StructLayoutAttribute(LayoutKind::Sequential, Size=72, Pack=1)]
public value struct Message_Lines
{
[MarshalAs(UnmanagedType::ByValArray,SizeConst=24)]
static char ^c_MessageLine1 = gcnew char[24];
[MarshalAs(UnmanagedType::ByValArray,SizeConst=24)]
static char ^c_MessageLine2 = gcnew char[24];
[MarshalAs(UnmanagedType::ByValArray,SizeConst=24)]
static char ^c_MessageLine3 = gcnew char[24];
};
[StructLayoutAttribute(LayoutKind::Sequential, Pack=1)]
public value struct MyManagedStruct
{
unsigned short u16_RecordType;
UINT16 u16_RecordCode;
CHAR c_MessageType;
unsigned char uc_Filler;
UINT16 u32_MessageCode;
Message_Lines s_MessagLines;
unsigned short u16_CheckSum;
};
So the length issue was solved, but when looking at my output object, the structure fields are populated, but the Message_Lines structure values are all zero. I confirmed in debugging that the byte array is populated correctly before calling ByteArrayToStructure().
What is the correct way of implementing this structure and properly populate the return object?
Am I using Marshal::PtrToStructure correctly?
Does anybody have a good link where I can learn more about marshalling structures that have arrays as elements?
Please help!