Правильное использование DllImport - PullRequest
7 голосов
/ 13 июля 2010

Предположим, есть метод c ++ int NativeMethod(double, double *) в Native.dll. Моя первая попытка вызова этого метода из управляемого кода была (при условии, что мне не нужно указывать точку входа)

[DllImport("Native.dll")]
private static extern int NativeMethod(double inD, IntPtr outD);

Затем, чтобы использовать DLL, я сделал

IntPtr x = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)));
NativeMethod(2.0, x);

//do stuff with x

Marshal.FreeHGlobal(x);  //crash

Я хотел бы понять, почему это происходит здесь. Мое первое предположение состоит в том, что это проблема кучи из-за того, что DLL и мое приложение могут использовать разные CRT. Но если бы это было так, почему бы вместо этого не вызвать вызов сбоя NativeMethod? Метод вернул x, из которого я мог успешно извлечь double.

Я могу заставить импорт работать, передавая двойное по ссылке

[DllImport("Native.dll")]
private static extern int NativeMethod(double inD, IntPtr outD);

Почему происходит сбой FreeHGlobal с первой попытки и каков рекомендуемый способ передачи указателей на нативные методы? Ключевое слово out может хорошо работать в этой ситуации, но что, если мне нужно маршалировать строку? Я не думаю, что смогу обойти AllocH и FreeH ...

Ответы [ 3 ]

7 голосов
/ 13 июля 2010

Возможно, я неправильно понимаю вашу цель, но, кажется, вы делаете ее более сложной, чем необходимо.Просто передайте его по ссылке, и пусть маршаллинг под ним позаботится об этом.

[DllImport("Native.dll")]
private static extern int NativeMethod(double inD, ref double outD);

double x;

x = 1;
NativeMethod( 2.0, ref x );
5 голосов
/ 13 июля 2010

Проблема в том, что метод принимает double*, который является указателем на двойное число. Вы передаете указатель, который указывает на IntPtr. Это важно только потому, что существует разница в размере между double (8 байт) и IntPtr, который имеет переменный размер (4 или 8 байт). Вам нужно выделить указатель на double

IntPtr x = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(double));
2 голосов
/ 13 июля 2010

Я не эксперт, но не должно ли это быть:

IntPtr x = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(double)));
...