У меня есть c++.dll, экспортирующая функцию со следующей подписью:
extern int __stdcall foobar(long ptr, unsigned int *array, unsigned int arraySize);
Из кода c++ я могу использовать его так:
std::vector<unsigned int> FooBar(6);
int res = foobar(ptr, &FooBar[0], (unsigned int)FooBar.size());
Я хотел бы использовать dll из С#, и я пробовал это:
[DllImport("mydll.dll")]
public static extern int foobar(long ptr, uint[] arr, uint arrSize);
Вызов:
uint[] arr = new uint[6];
int count = Obj.foobar(ptr, arr, (uint)arr.GetLength(0)*32)
Это вызывает ошибку "PInvokeStackImbalance". Как выглядит правильная подпись PInvoke?
Вам понадобится использовать атрибут MarshalAs для вашего параметра массива. Это, по существу, описывает систему сортировки, как конвертировать между управляемым типом С# и вашим параметром функции C++.
[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);
Ваш параметр "ptr" немного запутан, так как он не упоминается в вашем вопросе, но скорее всего это то, что вы можете рассматривать как обычный старый указатель C++, и в этом случае IntPtr является подходящим типом.
В атрибуте MarshalAs мы говорим системе сортировки, чтобы преобразовать ваш "массив uint" в исходный массив с длинным указателем C++. SizeParamIndex сообщает ему использовать параметр "arrSize" при распределении размера массива во время преобразования.
MarshalAs
сделали MarshalAs
дело! :-)
public static extern unsafe Int32 foobar(void* ptr, UInt32* array, UInt32 arraySize)
и выполняли маршалинг самостоятельно?IntPtr
. размер тоже неправильный, это* 4
. Трудно догадаться, что это на самом деле означает , сырые указатели обычно являются проблемой.