Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Marshal C pointer to C# array of struct

I am trying to turn a pointer from a c dll into its equivelant C# struct array.

C Code

RECORD       locked[MAX+1]; //MAX is a constant

typedef struct
{
  State state; //enum
  unsigned long allocated;
  unsigned long lastUsed;
  unsigned int  useCount;
} RECORD;

API RECORD* __stdcall GetLocks( char* password )
{
  if(strcmp(password, secret) == 0)
    return locked;
  else
    return 0;
}

C# Code

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] // Pretty sure CharSet isnt actually needed here
public struct RECORD
{
    public State state;
    public UInt32 allocated;
    public UInt32 lastUsed;
    public UInt16 useCount;
}

    [DllImport("gatewayapi.dll", CharSet = CharSet.Ansi)] // or here
    static extern IntPtr GetLocks(string password);
    public RECORD[] GetLocks(string password)
    {
        RECORD[] recs = new RECORD[MAX+1];

        recs =(RECORD[])Marshal.PtrToStructure( GetLocks(password), typeof(RECORD[]));

        if (recs.Length == 0)
        {
            throw new Exception();
        }
        return recs;
    }

The above unfortunetly returns me a MissingMethodException -> No parameterless constructor defined for this object.

So in all im 100% new to Marshalling and would appreciate some advice on how to turn the pointer I receive from C into the actual C# struct array it represents.

Thanks

like image 821
Zholen Avatar asked Dec 14 '25 13:12

Zholen


1 Answers

Given the originally posted C code, here is the answer I came up with that doesn't require compiling the code in unsafe mode:

    [DllImport("gatewayapi.dll", CharSet = CharSet.Ansi)]
    static extern IntPtr AMTgetLocks(string password);
    public RECORD[] GetLocks(string password)
    {
        var channels = new RECORD[MAXCHANS + 1];
        try
        {
            var c = AMTgetLocks(password);
            var crSize = Marshal.SizeOf(typeof(RECORD));
            for (int i = 0; i < MAXCHANS + 1; i++)
            {
                channels[i] = (CHANNELRECORD)Marshal.PtrToStructure(c, typeof(RECORD));
                c = new IntPtr(c.ToInt64() + crSize);
            }
        }
        catch (Exception)
        {
            throw new Exception();
        }
        if (channels.Length == 0)
        {
            throw new Exception();
        }
        return channels;
    }
like image 185
Zholen Avatar answered Dec 17 '25 02:12

Zholen