Я довольно новичок в P / Invoke (и очень ржавый на C), и я потратил немало времени, пытаясь решить проблему фоллинга:
Я хочу вызвать неуправляемую функцию C из управляемого C #. Функция C должна создать массив со значениями и вернуть его, чтобы я мог использовать эти значения в C #. (Обратное работает нормально, то есть передавая массив из C # в C.) Т.е. Я хочу сделать параметры передачи в качестве ссылок с массивами. Вот простой пример кода, который, по моему мнению, должен работать (но не работает):
C:
int __declspec(dllexport) __stdcall AllocateMemory(int **values, const unsigned int N)
{
int sum = 0;
free(*values);
*values = (int*) malloc(N*sizeof(int));
for(unsigned int i = 0; i < N; i++) {
(*values)[i] = i;
sum += (*values)[i];
}
Это отлично работает прямо из консольного тестового приложения C:
int main( int argc, char** argv)
{
int* values;
int sum = AllocateMemory(&values, 4);
printf ("Sum: %d\n", sum);
}
Однако выполнение этого вызова непосредственно из C # приводит к (памяти) System.AccessVioaltionException:
[DllImport("Test.dll", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention = CallingConvention.Winapi)]
public static extern int AllocateMemory([Out, MarshalAs(UnmanagedType.LPArray, SizeConst = 10)] out int[] someValues, int N);
private static void RunCalculation(string message)
{
int[] someValues;
int sum = AllocateMemory(out someValues, 4);
}
Я безуспешно пробовал разные версии подписи DllImport, и сейчас я продолжу свое расследование. Однако, если у кого-то есть подсказка, я буду очень признателен!
(Ниже добавлено примерно час спустя (после некоторых комментариев ниже), поскольку мне не разрешено оставлять ответ сам до завтра)
Я обнаружил, что смог использовать следующий код C #:
[DllImport("FrontAuction2.dll", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention = CallingConvention.Winapi)]
public static extern float AllocateCudaMemory(out IntPtr someValues, int N);
private static IntPtr AllocateCudaMemory()
{
IntPtr temp;
float sum = AllocateCudaMemory(out temp, 4);
//NOTE: If you'd actually want to get the value and just not want to pass the IntPtr to another P/Invoke method (as I do), this is one way:
//var values = new int[4];
//Marshal.Copy(temp, values, 0, 4);
return temp;
}
Однако в комментариях ниже есть несколько интересных моментов, которые я прокомментировал.
Цель всего этого в моей учетной записи - разрешить передачу ссылки на память графического процессора CUDA в C # для дальнейшего использования. Я думаю, что лучший способ сделать это, вероятно, состоит в том, чтобы сохранить ссылку на сервере состояний COM C ++ вместо передачи ее в C #. Но решение этой проблемы, по крайней мере, позволит мне сосредоточиться на вещах на GPU прямо сейчас, а не на взаимодействии.