im failing to define the correct C# code to work with a C++ library which defines a complex struct with union and arrays, i keep getting some memory exception while executing the C++ code, and im pretty sure its due to this.
The c++ struct is as follows, ignoring enums and other struct definition (i will post them if needed but they are pretty extense)
typedef struct
{
DG_CCTALK_APP_EVT_CODE eEventCode;
DG_CCTALK_APP_EVT_TYPE eEventType;
int iTime;
int iHandle;
unsigned char uchAddress;
DG_CCTALK_BILL_INFO sBillInfo;
int iBillAmount;
union
{
long lData;
int iData;
unsigned char ucArray[128];
char *cString;
void *pvoid;
} uData;
void *_private; // for use by cctalk app layer
} DG_CCTALK_APP_EVT, *PDG_CCTALK_APP_EVT;
And the C# code is this:
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Explicit)]
public struct Anonymous_92d21a81_2a8b_42f4_af32_f7606aa9cf40
{
//deberian llevar todos 0, pero el array genera problemas al ponerle 0, y cambiandolo explota en otro lado...
/// int
[System.Runtime.InteropServices.FieldOffsetAttribute(0)]
public int lData;
/// int
[System.Runtime.InteropServices.FieldOffsetAttribute(0)]
public int iData;
/// unsigned char[128]
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 128, ArraySubType = System.Runtime.InteropServices.UnmanagedType.I1)]
[System.Runtime.InteropServices.FieldOffsetAttribute(4)]
public byte[] ucArray;
/// char*
[System.Runtime.InteropServices.FieldOffsetAttribute(0)]
public System.IntPtr cString;
/// void*
[System.Runtime.InteropServices.FieldOffsetAttribute(0)]
public System.IntPtr pvoid;
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct DG_CCTALK_APP_EVT
{
/// DG_CCTALK_APP_EVT_CODE->_DG_CCTALK_APP_EVT_CODE
public DG_CCTALK_APP_EVT_CODE eEventCode;
/// DG_CCTALK_APP_EVT_TYPE->_DG_CCTALK_APP_EVT_TYPE
public DG_CCTALK_APP_EVT_TYPE eEventType;
/// int
public int iTime;
/// int
public int iHandle;
/// unsigned char
public byte uchAddress;
/// DG_CCTALK_BILL_INFO->_DG_CCTALK_BILL_INFO
public DG_CCTALK_BILL_INFO sBillInfo;
/// int
public int iBillAmount;
/// Anonymous_92d21a81_2a8b_42f4_af32_f7606aa9cf40
public Anonymous_92d21a81_2a8b_42f4_af32_f7606aa9cf40 uData;
/// void*
public System.IntPtr _private;
}
Delegates and a function import
public delegate void DG_CCTALK_APP_EVT_HANDLER(ref DG_CCTALK_APP_EVT pEVT);
[System.Runtime.InteropServices.DllImportAttribute("cctalk.dll", EntryPoint = "cctalk_app_enable_device", CallingConvention = CallingConvention.Cdecl)]
public static extern int cctalk_app_enable_device(ref DG_CCTALK_APP_EVT param0);
UPDATE: new code after an asnwer, still not working: The error is: "Attempt to read or write Protected Memory This is often an indicating that other memory is corrupt"
What is weird, is that i can use the struct on the first event call, i print all fields and they seem to be right (lData and iData have the same values, cData has a string I sent) but after the event ends the program dies. Seems like my C# code is breaking the struct or something...
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Ansi)]
public struct DG_CCTALK_APP_EVT
{
/// DG_CCTALK_APP_EVT_CODE->_DG_CCTALK_APP_EVT_CODE
public DG_CCTALK_APP_EVT_CODE eEventCode;
/// DG_CCTALK_APP_EVT_TYPE->_DG_CCTALK_APP_EVT_TYPE
public DG_CCTALK_APP_EVT_TYPE eEventType;
/// int
public int iTime;
/// int
public int iHandle;
/// unsigned char
public byte uchAddress;
/// DG_CCTALK_BILL_INFO->_DG_CCTALK_BILL_INFO
public DG_CCTALK_BILL_INFO sBillInfo;
/// int
public int iBillAmount;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public byte[] uData;
#region setters y getters para mapeo
public int lData
{
set
{
Array.Copy(BitConverter.GetBytes(value), uData, sizeof(int));
}
get
{
return BitConverter.ToInt32(uData, 0);
}
}
public int iData
{
set
{
Array.Copy(BitConverter.GetBytes(value), uData, sizeof(int));
}
get
{
return BitConverter.ToInt32(uData, 0);
}
}
public byte[] ucArray
{
set
{
Array.Copy(value, uData, 128);
}
get
{
return uData;
}
}
public IntPtr cString
{
set
{
Array.Copy(BitConverter.GetBytes(value.ToInt32()), uData, 32);
}
get
{
return (IntPtr)BitConverter.ToInt32(uData, 0);
}
}
public IntPtr pvoid
{
set
{
Array.Copy(BitConverter.GetBytes(value.ToInt32()), uData, 32);
}
get
{
return (IntPtr)BitConverter.ToInt32(uData, 0);
}
}
#endregion
/// void*
public System.IntPtr _private;
}
C++ declarations:
typedef void (*DG_CCTALK_APP_EVT_HANDLER)(PDG_CCTALK_APP_EVT pEVT);
DGCCTALK_PREFIX DG_ERROR cctalk_app_init(DG_CCTALK_APP_EVT_HANDLER pfnHandler);
DGCCTALK_PREFIX DG_ERROR cctalk_app_add_link(char *szPortName);
Note dad DGCCTALK_PREFIX is defined as __declspec(dllexport)
C# code for those:
public delegate void DG_CCTALK_APP_EVT_HANDLER(ref DG_CCTALK_APP_EVT pEVT);
[System.Runtime.InteropServices.DllImportAttribute("cctalk.dll", EntryPoint = "cctalk_app_init", CallingConvention = CallingConvention.Cdecl)]
public static extern int cctalk_app_init(DG_CCTALK_APP_EVT_HANDLER pfnHandler);
[System.Runtime.InteropServices.DllImportAttribute("cctalk.dll", EntryPoint = "cctalk_app_add_link", CallingConvention = CallingConvention.Cdecl)]
public static extern int cctalk_app_add_link(System.IntPtr szPortName);
C# code invoking them
var handler = new DG_CCTALK_APP_EVT_HANDLER(this._handler);
var resultado = cctalk_app_init(handler);
cctalk_app_add_link(Marshal.StringToHGlobalAnsi("port=" + port));
C# handler header
private void _handler(ref DG_CCTALK_APP_EVT pEVT)