Я пытаюсь обернуть библиотеку glmnet (http://cran.r-project.org/web/packages/glmnet/index.html), поэтому я могу решить модели редкие общие линейные модели в C#. Однако исходная функция имеет несколько 20 параметров, поэтому я начал (совершенно новый для Fortran) с крошечной подпрограммой для тестирования того, как передавать данные. К сожалению, я всегда получаю AccessViolationException.AccessViolationException вызов Fortran из C#
Вот код:
Фортран подпрограммой. Я скомпилирую его в dll, используя компилятор gfortran, который поставляется с Rtools (http://cran.r-project.org/bin/windows/Rtools/), используя опцию -m64 (да, требуется 64 бит, поскольку я обрабатываю довольно большие фрагменты данных). Да, использование i могло привести к запредельным ... но это только для тестирования.
subroutine testaaa (f,i,fa,ia)
real fa(i)
integer ia(i)
ia(1) = 1337
ia(i) = 666
fa(1) = 8.15
fa(i) = 333
end subroutine testaaa
код C# PInvoke:
[DllImport("ftest.dll", EntryPoint = "testaaa_", CallingConvention = CallingConvention.StdCall)]
public static extern void Test(
[MarshalAs(UnmanagedType.R4)] float f,
[MarshalAs(UnmanagedType.I4)] int i,
IntPtr fa,
IntPtr ia);
А вот как это называется:
var fa = new float[4];
var ia = new int[4];
IntPtr faPtr = Marshal.AllocHGlobal(fa.Length * sizeof(float));
Marshal.Copy(fa, 0, faPtr, fa.Length);
IntPtr iaPtr = Marshal.AllocHGlobal(ia.Length * sizeof(float));
Marshal.Copy(ia, 0, iaPtr, ia.Length);
GlmnetDllWrapper.Test(0.4f, 4,faPtr,iaPtr);
Я также попытался прохождения массивы непосредственно и давая им [MarshalAs (UnmanagedType.LPArray)]. Ничто не сработало для меня.
Есть ли у вас какие-либо предложения, с чего начать или что изменить?
Update 1: Даже прохождение только поплавка и ИНТ уже вызывает исключение:
subroutine testbbb (f,i)
i = 815
f = 8.15
return
end subroutine testbbb
C# PInvoke и вызова изменяется соответственно. Что я делаю не так?
Возможно ли, что ваша библиотека Fortan получает параметры указателем? Кроме того, почему вы все тестируете сразу. Почему вы не упростили? Можете ли вы передать один параметр типа 'int'? Тип 'float'? Затем попробуйте массив. Не проверяйте сначала самую сложную вещь. Как вы можете сказать, какая часть терпит неудачу? –
ОК, ваше обновление и мой комментарий перешли. Хорошо сделано для упрощения. Попробуйте передать в качестве указателей: 'public static extern void Test (ref float f, ref int i)' –
Как только вы пройдете блокировку на простых типах, мы можем показать вам, как делать массивы. И нет необходимости в 'IntPtr'.Мы можем заставить маркерщика pinvoke подключить массивы и сделать код вызова очень простым. –