Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I marshall a pointer to a pointer of an array of structures?

My C declarations are as follows:

int myData(uint myHandle, tchar *dataName, long *Time, uint *maxData, DATASTRUCT **data);

typedef struct {
  byte Rel;
  __int64 Time;
  char Validated;
  unsigned char Data[1];
} DATASTRUCT ;

My C# declarations are as follows:

[DllImport("myData.dll", EntryPoint = "myData")]
public static extern int myData(uint myHandle, [MarshalAs(UnmanagedType.LPTStr)] string dataName, out long Time, out uint maxData, ref DATASTRUCT[] data);

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct DATASTRUCT
{
    public sbyte Rel;
    public long Time;
    public byte Validated;
    public double Data;
}

I then call the managed function as follows:

string dataToShow = "description";
long Time;
uint maxData; // How many structs will be returned, i.e. how much data is available
uint myHandle = 1;

DATASTRUCT[] dataInformation = new DATASTRUCT[3]; // doesn't matter what I specify as the array size?

myData(myHandle, dataToShow, out Time, out maxData, ref dataInformation);

Upon execution the above function will return successfully with only one structure even though there are 3 to return. Why is this so?

Additional information; I have tried passing the pointer to a pointer of an array of structs the following ways:

- ref DATASTRUCT[] data; // Works but only returns one struct
- [Out, MarshalAs(UnmanagedType.LPArray)] DATASTRUCT[] data; // returns the number of defined structs with garbage

As I understand it I might need to do some manual marshalling using IntPtr, I do not know how to implement this however, so any advice would be appreciated.

like image 545
user1470994 Avatar asked Jun 21 '12 04:06

user1470994


People also ask

How many bytes is a pointer to a struct?

Pointers usually take either 4 or 8 bytes. If you wanted to know the size of the struct itself, you would use sizeof (*p_struct).

How many bytes is a pointer to a struct in C?

As is the size of the struct. On 32-bit machine sizeof pointer is 32 bits 4 bytes On 64 bit machine it's 8 byte.

Can a pointer act as an array?

An array is a pointer, and you can store that pointer into any pointer variable of the correct type. For example, int A[10]; int* p = A; p[0] = 0; makes variable p point to the first member of array A.

What is array pointer structure in C?

Master C and Embedded C Programming- Learn as you go Unary operator ( * ) is used to declare a variable and it returns the address of the allocated memory. Pointers to an array points the address of memory block of an array variable. The following is the syntax of array pointers. datatype *variable_name[size];


1 Answers

A pointer to a pointer could be represented in your dllimport declaration as ref IntPtr data, so your declaration would become:

[DllImportAttribute("myData.dll", EntryPoint = "myData")]
public static extern int myData(uint myHandle, [MarshalAs(UnmanagedType.LPTStr)] string dataName, out long Time, out uint maxData, ref IntPtr data);

(As an aside, I think a long in C is just equivalent to an int in C#. Long in C# is an Int64, which would be a long long in C)

Marshalling your DATASTRUCT[] to an IntPtr can be done using the GCHandle class

DATASTRUCT [] dataInformation = new DATASTRUCT[3];
GCHandle gch = GCHandle.Alloc(dataInformation , GCHandleType.Pinned);
IntPtr ptr = gch.AddrOfPinnedObject();
myData(myHandle, dataToShow, out Time, out maxData, ref ptr);
//It's absolutely essential you do this next bit so the object can be garbage collected again, 
//but it should only be done once the unmanaged code is definitely done with the reference.    
gch.Free(); 

Using the Marshal class and the StructureToPtr or Copy methods of it would also be an option but for the purposes of proving the concept at least the GCHandle should do the trick, it's just not ideal for scenarios where the unmanaged code does long running operations because you've pinned this object in place and the GC can't move it until you free it.

like image 57
Nanhydrin Avatar answered Oct 17 '22 14:10

Nanhydrin