Bill Walton
Bill Walton

Reputation: 823

Sending pointer to C# struct into C++ DLL

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

Answers (2)

David Heffernan
David Heffernan

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

Stealth Rabbi
Stealth Rabbi

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

Related Questions