tags:

views:

173

answers:

1

I am writing a managed wrapper around an unmanaged DLL, and am unable to get the following method and structure to marshal correctly. Here's what's in the .h file for the unmanaged code:

typedef struct {
 WORD PI_code;
 DWORD grpStat[31]; 
 BYTE PTY_code;
 char* PS;
 char* RT;
} RdsData_t;

COMPANYNAME_API void COMPANY_get_rds_data(RdsData_t* rds_data);

and here's what I've come up with, with some help from PInvoke Interop Assistant:

[StructLayoutAttribute(LayoutKind.Sequential)]
public struct RdsData_t
{

    /// WORD->unsigned short
    public ushort PI_code;

    /// DWORD[31]
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 31, ArraySubType = UnmanagedType.U4)]
    public uint[] grpStat;

    /// BYTE->unsigned char
    public byte PTY_code;

    /// char*
    [MarshalAsAttribute(UnmanagedType.LPStr)]
    public string PS;

    /// char*
    [MarshalAsAttribute(UnmanagedType.LPStr)]
    public string RT;
}        
[DllImport("companyname.dll", EntryPoint = "?COMPANYNAME_get_rds_data@@YAXPAURdsData_t@@@Z")]
    private static extern void COMPANYNAME_get_rds_data(ref RdsData_t data);

However, as-is this throws an AccessViolationException when called. Through searching, and experimentation, I am able to come up with something that does not throw an exception, but then the data is incorrect or missing, leading me to believe those are not correct either.

What interop code should I use for the above struct? Are there any tools besides PInvoke Assistant that I could use to help me?

Thanks in advance!

A: 

Try the following

    [StructLayoutAttribute(LayoutKind.Sequential)]
    public unsafe struct RdsData_t
    {

        /// WORD->unsigned short
        public ushort PI_code;

        /// DWORD[31]
        [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 31, ArraySubType = UnmanagedType.U4)]
        public fixed uint grpStat[31];

        /// BYTE->unsigned char
        public byte PTY_code;

        /// char*
        [MarshalAsAttribute(UnmanagedType.LPStr)]
        public string PS;

        /// char*
        [MarshalAsAttribute(UnmanagedType.LPStr)]
        public string RT;
    }

Note: however, you will need to allow your library/app to execute unsafe code in order for that to work.

Jason D
Still playing with it, but as-is, I'm getting the error "TypeLoadException: Cannot marshal field 'grpStat' of type 'GSS.UsbRadio.RdsData_t': Invalid managed/unmanaged type combination (this value type must be paired with Struct)."
Daniel
Interesting ... I'll take a look again tomorrow... this time running as well as compiling.... (I only got it to compile last time based on another SO question for a different struct type... it appears I misunderstood something...)
Jason D