2

I am trying to call an unmanaged function that looks like this (DATA is my C# struct):

[DllImport("data.dll")]
internal static unsafe extern int MyExternalFunction(DATA* pData, uint numElements);

This is how I'm calling the function from C#:

DATA[] data = new DATA[64];
fixed (DATA* pData = data )
{
    MyExternalFunction(pData, 64);
}

[StructLayout(LayoutKind.Sequential)]
internal struct DATA
{
    internal uint a;
    internal uint b;
    internal uint c;
    internal POINT pos;
}

[StructLayout(LayoutKind.Sequential)]
internal struct POINT 
{
    internal int x;
    internal int y;
}

Unfortunately I get this error: "Cannot marshal 'parameter #1': Pointers cannot reference marshaled structures."

If it makes any difference, my DATA struct has nested structs inside it. I have no control over how this external method is designed. What is the correct way to call this function and receive an array of structs?

4
  • Based on what you've posted, AZ's answer is correct. Omit the unsafe, skipped the fixed block and declare the external function argument to be DATA[]. However, can you show us how DATA is defined on the C# side? That might clarify things even further. Commented Sep 9, 2011 at 15:27
  • Exactly. No need for unsafe or fixed. Show us the C++ and C# definitions of DATA. Commented Sep 9, 2011 at 15:36
  • The declaration makes little sense, there's no way for the unmanaged code to figure out how many elements are in the array. Post the native declaration. Commented Sep 9, 2011 at 15:53
  • I've updated the code, I forgot to include the "numElements" parameter in this sample, sorry. I also included the struct layout. Commented Sep 9, 2011 at 16:09

2 Answers 2

6

You should declare it like this:

[DllImport("data.dll")]
public static extern int MyExternalFunction(
    [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)]
    DATA[] Data, 
    uint numElements
);

And call it like this:

MyExternalFunction(myArray, myArray.Length);

No need for unsafe or fixed. Do remove all of that.

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

Comments

1

try this:

[DllImport("data.dll")]
internal static unsafe extern int MyExternalFunction(DATA[] pData);

and omit the C# pointer altogether.

Edit: I did not test that but it makes sense that the pointer way will not work as the memory layout of managed arrays is not the same as unmanaged ones. The marshaller has to get the chance of taking your array and transform it in native format then back again. I'm not sure if a ref modifier should be required in this case but it might be an option.

8 Comments

The function (MyExternalFunction) is expecting a pointer. I tried your suggestion, and it didn't generate an error but the struct array is all 0's. It looks like it didn't work.
When I add a ref modifier the program just exits without any exceptions or errors, it just closes.
I don't think ref is correct here, this would be equivalent to a native declaration of int MyExternalFunction(DATA ** pData), i.e. an array passed by reference.
if the only initialization you do on the input array is DATA[] data = new DATA[64]; then it's logically to have it contain only zeroes on native side
@Justin - you are right. I was thinking that the OP wants to have the array data back from native into managed with changed values. Somehow this translated as ref in my mind but i was just silly. I don't think there is a way of getting the data back from native into managed. The marshaller should somehow know to do the transformation back once the method existed. I'm not an expert on these things though
|

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.