0

I have a c++ .dll exporting a function with the following signature:

extern int __stdcall foobar(long ptr, unsigned int *array, unsigned int arraySize);

From c++ Code, I can use it like so:

std::vector<unsigned int> FooBar(6);
int res = foobar(ptr, &FooBar[0], (unsigned int)FooBar.size());

I'd like to use the dll from C# and I've tried this:

[DllImport("mydll.dll")]
public static extern int foobar(long ptr, uint[] arr, uint arrSize);

Call:

uint[] arr = new uint[6];
int count = Obj.foobar(ptr, arr, (uint)arr.GetLength(0)*32)

This throws an "PInvokeStackImbalance" error. What would the correct PInvoke signature look like?

5
  • Have you tried public static extern unsafe Int32 foobar(void* ptr, UInt32* array, UInt32 arraySize) and performing the marshalling yourself? Commented Jan 3, 2014 at 23:40
  • That ptr is not long, it is IntPtr. size is wrong too, it is * 4. What it actually means is hard to guess at, raw pointers are usually trouble. Commented Jan 3, 2014 at 23:40
  • @Dai : Do you have an example for that? I would prefer going without unsafe code if that's possible... Commented Jan 3, 2014 at 23:46
  • @HansPassant ptr comes from a different function returning long: extern long __stdcall createPtr(int val); Commented Jan 3, 2014 at 23:47
  • The translation of C++ long to .NET is System.Int32. Using C# long, which is System.Int64, will not work. Also std::vector's size() member returns the number of elements, not the number of bytes, so multiplying GetLength(0) * 32 is wrong. Not sure where 32 came from to begin with. Just (uint)arr.Length will be correct there. Commented Jan 3, 2014 at 23:55

1 Answer 1

1

You're going to need to make use of the MarshalAs attribute, for your array parameter. This essentially describes to the marshalling system how to convert between the C# managed type and your raw C++ function parameter.

[DllImport("mydll.dll")]
public static extern int foobar(
    IntPtr ptr, //Need more details on this parameter
    [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=2)] uint[] arr,
    uint arrSize);

Your "ptr" parameter is a bit confusing, since it's not mentioned in your question, but it's most likely just something you can treat as a regular old C++ pointer, in which case IntPtr is the appropriate type.

In the MarshalAs attribute, we are telling the marshalling system to convert your "uint array" into a raw, long-pointer-compatible C++ array. The SizeParamIndex tells it to use the "arrSize" parameter, when allocating the array's size during conversion.

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.