Reputation: 23
There is a C++ library which contains
SimpleStruct
GetSimpleStructs
returning pointer to array of this structsLike this:
typedef struct {
int value1;
int value2;
int value3;
} SimpleStruct;
extern SimpleStruct *GetSimpleStructs(int *count);
I have this implementation in C# .Net Core project:
[StructLayout(LayoutKind.Sequential)]
struct SimpleStruct
{
int value1;
int value2;
int value3;
}
[DllImport(LibName)]
public static extern IntPtr GetSimpleStructs(out int count);
And function that converts IntPtr
to SimpleStruct[]
:
SimpleStruct[] GetSimpleStructs()
{
var ptrToArray = GetSimpleStructs(out var count);
var arrayOfPtrs = new IntPtr[count];
var resultArray = new SimpleStruct[count];
Marshal.Copy(ptrToArray, arrayOfPtrs, 0, count);
for (var i = 0; i < count; i++)
resultArray[i] = Marshal.PtrToStructure<SimpleStruct>(arrayOfPtrs[i]); // HERE
return resultArray;
}
Everything works ok before the line with // HERE
. In the first iteration program just finishes with exit code 139 without any exceptions.
So what am I doing wrong?
Also, I don't have the ability to reference project with struct in the project with DllImport
Upvotes: 2
Views: 459
Reputation: 1064184
If your unmanaged method returns a pointer to a block of structs, you don't need the IntPtr[]
step - there is only one pointer (that would be useful if you were returning a SimpleStruct **
).
Instead, you need to first make sure you have the layout exactly right (including the size), by using explicit layout attributes, then: just go via the pointer:
unsafe
{
SomeStruct* ptr = (SomeStruct*)ptrToArray.ToPointer();
var resultArray = new SimpleStruct[count];
for (int i = 0 ; i < resultArray.Length ; i++)
resultArray[i] = *ptr[i];
}
If you are happy to use spans, this can be even easier. The copy step is just:
var resultArray = new Span<SomeStruct>(
ptrToArray.ToPointer(), count).ToArray();
In fact, you could just return Span<SomeStruct>
or Memory<SomeStruct>
(the latter requires an extra step, but is possible), to allow safe C# code to access the data directly from the unmanaged memory location without ever copying it into managed memory or allocating an array!
Upvotes: 4