Reputation: 823
I have a C++ function in a DLL which takes a pointer to a struct, JPInfo, which in the function is filled with data received from a server, the layout of the C++ struct is as seen below:
typedef struct JP
{
unsigned char type;
DWORD value;
} JP;
typedef struct JPInfo
{
JP jps[3];
_int16 ConT;
_int16 CallT;
unsigned char ret;
unsigned char count;
unsigned char JPOffset;
unsigned char JPPeriod;
} JPInfo;
The function is exported in the DLL like so:
__declspec(dllexport) DWORD __stdcall GetJPInfo(JPInfo* jpi, DWORD time);
The function takes a pointer to a JPInfo struct, I have tried to emulate this struct in C#
[StructLayout(LayoutKind.Sequential, Size = 5), Serializable]
public struct JP
{
byte type;
int value;
}
[StructLayout(LayoutKind.Sequential,Size=23),Serializable]
public struct JPInfo
{
JP[] jps;
Int16 ConT;
Int16 CallT;
byte ret;
byte count;
byte JPOffset;
byte JPPeriod;
}
I attempt to call the function from C# like so:
[DllImport("DLLImp.dll")]
unsafe public static extern int GetJP(ref JPInfo jpi, int time);
// then in main...
JPInfo jpi = new JPInfo;
GetJackpotValues(ref jpi, 4000);
I get an unhandled exception of type "System.ExecutionEngineException". I can't have a fixed size array of JP structs in my JPInfo struct, so I don't know how to approach this.
Thanks.
Upvotes: 2
Views: 5408
Reputation: 612804
Assuming that the C++ structs are packed, your C# structs should look like this:
[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct JP
{
byte type;
uint value;
}
[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct JPInfo
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst=3)]
JP[] jps;
Int16 ConT;
Int16 CallT;
byte ret;
byte count;
byte JPOffset;
byte JPPeriod;
}
On the other hand, if they are not packed then remove the Pack
parameter to the StructLayout
attribute. You should look for a #pragma pack
statement in the C++ header file to understand whether or not the C++ structs are packed.
I'm guessing that the C++ structs are packed because you said that they are mapped onto data received from the server.
Your import should be like so:
[DllImport("DLLImp.dll")]
public static extern uint GetJP(ref JPInfo jpi, uint time);
A DWORD
translates to uint
rather than int
and there is no need for unsafe code here.
Upvotes: 2
Reputation: 10346
Have you tried removing your Size attributes on your structs? I haven't had to specify a Size when doing something similar. For your array properties, try attributing them like:
[StructLayout(LayoutKind.Sequential)]
public struct JPInfo
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
JP[] jps;
Int16 ConT;
Int16 CallT;
byte ret;
byte count;
byte JPOffset;
byte JPPeriod;
}
Upvotes: 4