I am trying to get below working C++ DLL code in C# using Marshal. It has two structures which are passed as pointer parameters in the API which is exported, but the structure response values it is giving out in C# is not in correct sequence. Whereas it is working fine in VC++.
//C++ Code - Working
//Structure 1
typedef struct
{
bool bExist;
bool bAvailable;
int iNoteNumber;
int iDispenseNumber;
int iOutNoteNumber;
char cStatus;
char acBoxID[6];
} tHopperStatus;
//Structure 2
typedef struct
{
char acCurrency[4];
int lDenomination;
int iRemainCount;
int iCount;
int iOutCount;
int iRejectCount;
int iPurgeCount;
BYTE byHopper;
char cStatus;
char cLastStatus;
char acBoxID[6];
BYTE byBoxType;
char acReserved1[10];
char acReserved2[10];
int iReserverd1;
int iReserverd2;
} tCashBox;
//API using above two structures
int iGetCassette(tCashBox* p_psCashBox,tDevReturn* p_psStatus);
//Calling API by passing pointer of Structure Array
tCashBox l_asBox[8] = {0};
tDevReturn l_asReturn[8] = {0};
int l_iRes = l_pDev->iGetCassette(l_asBox, l_asReturn);
What I implemented in C#:
//C# Code
//Structure 1
[StructLayout(LayoutKind.Sequential)]
unsafe public struct tDevReturn
{
public tDevReturn(int param)
{
iLogicCode = 0;
iPhyCode = 0;
iHandle = 0;
iType = 0;
acDevReturn = new char[128];
acReserve = new char[128];
}
public int iLogicCode;
public int iPhyCode;
public int iHandle;
public int iType;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public char[] acDevReturn;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public char[] acReserve;
}
//Structure 2
[StructLayout(LayoutKind.Sequential)]
unsafe public struct tCashBox
{
public tCashBox(int param)
{
acCurrency = new char[4];
lDenomination = 0;
iRemainCount = 0;
iCount = 0;
iOutCount = 0;
iRejectCount = 0;
iPurgeCount = 0;
byHopper = 0;
cStatus = '\0';
cLastStatus = '\0';
acBoxID = new char[6];
byBoxType = 0;
acReserved1 = new char[10];
acReserved2 = new char[10];
iReserverd1 = 0;
iReserverd2 = 0;
}
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public char[] acCurrency;
public long lDenomination;
public int iRemainCount;
public int iCount;
public int iOutCount;
public int iRejectCount;
public int iPurgeCount;
public byte byHopper;
public char cStatus;
public char cLastStatus;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public char[] acBoxID;
public byte byBoxType;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public char[] acReserved1;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public char[] acReserved2;
public int iReserverd1;
public int iReserverd2;
}
//API Import Declaration
[DllImport("xxxxxxxxxx.dll", CallingConvention = CallingConvention.StdCall)]
public static extern int CDM_iGetCassette([In, Out] tCashBox[] p_psCashBox, [In, Out] tDevReturn[] p_psStatus);
//API Call - but filling up the structure array with random values and incorrect sequence
tDevReturn[] response = new tDevReturn[8];
tCashBox[] cashboxData = new tCashBox[8];
int ret = Wrapper.CDM_iGetCassette(cashboxData, response);
I have a doubt, whether passing Array of Structure in this way is allowed or not in C#, where as in C++ it is working. If someone can help me in this would be a great help. Thanks in advance.
EDIT : I changed data type of 'lDenomination' from long to int. Now, the array first element is getting filled up properly. But the remaining seven element of struct array are not getting filled up.
If someone can help me, How to create Structure Array with all elements having memory in sequence.
Solved the issue finally with below updated Structure 2: 1. Changed data type of 'lDenomination' from long to int. 2. Added Pack=1 and CharSet=CharSet.Ansi in struct layout parameters.
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct tCashBox
{
public tCashBox(int param)
{
acCurrency = new char[4];
lDenomination = 0;
iRemainCount = 0;
iCount = 0;
iOutCount = 0;
iRejectCount = 0;
iPurgeCount = 0;
byHopper = 0;
cStatus = '\0';
cLastStatus = '\0';
acBoxID = new char[6];
byBoxType = 0;
acReserved1 = new char[10];
acReserved2 = new char[10];
iReserverd1 = 0;
iReserverd2 = 0;
}
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public char[] acCurrency;
public int lDenomination;
public int iRemainCount;
public int iCount;
public int iOutCount;
public int iRejectCount;
public int iPurgeCount;
public byte byHopper;
public char cStatus;
public char cLastStatus;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public char[] acBoxID;
public byte byBoxType;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public char[] acReserved1;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public char[] acReserved2;
public int iReserverd1;
public int iReserverd2;
}