Click here to Skip to main content
15,888,579 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
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:
C++
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:
C++
[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.

C++
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];

    // call the C function to get the data into the byte array
    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:
C#
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:
C++
[StructLayoutAttribute(LayoutKind::Sequential, Size=72, Pack=1)]
public value struct Message_Lines
{
	[MarshalAs(UnmanagedType::ByValArray,SizeConst=24)]
	//static array<char>^ c_MessageLine1; 
	static char	^c_MessageLine1 = gcnew char[24]; 
	[MarshalAs(UnmanagedType::ByValArray,SizeConst=24)]
	//static array<char>^ c_MessageLine2; 
	static char	^c_MessageLine2 = gcnew char[24]; 
	[MarshalAs(UnmanagedType::ByValArray,SizeConst=24)]
	//static array<char>^ c_MessageLine3; 
	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;
	//[MarshalAs(UnmanagedType::ByValArray,SizeConst=72)]
	//static char	^c_MessageLines = gcnew char[3][24]; 
	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!
Posted

Have a look at:Using ACE with C++ CLI[^]

Why not create a mixed mode C++/CLI dll? Declare structures that are convenient to use in c# and just copy from the original c structures to your new structures ...

Best regards
Espen Harlinn
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 1-Mar-12 15:43pm    
ACE with .NET? Sure, that's great, a 5.
--SA
Espen Harlinn 1-Mar-12 15:47pm    
Thank you Sergey!
Hi,
I haven't used marshalling in C#, so I am just taking a stab in the dark with this but is there any particular reason why you are using static? Maybe that is the root of your problem? The reason why I come to this conclusion is because I see this here:

A static method, field, property, or event is callable on a class even when no instance of the class has been created. If any instances of the class are created, they cannot be used to access the static member. Only one copy of static fields and events exists, and static methods and properties can only access static fields and static events. Static members are often used to represent data or calculations that do not change in response to object state; for instance, a math library might contain static methods for calculating sine and cosine.

Hope that helps...
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900