2

There is a C++ library which contains

  • structure SimpleStruct
  • function GetSimpleStructs returning pointer to array of this structs

Like 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

1
  • You need to tell the marshaler how many items are being returned. You are also going to need to know how that buffer is being allocated so that you can properly deallocate after the call returns Commented Jun 14, 2020 at 4:08

1 Answer 1

4

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!

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.