【发布时间】:2013-04-12 00:57:39
【问题描述】:
我正在尝试包装 glmnet 库 (http://cran.r-project.org/web/packages/glmnet/index.html),以便我可以在 C# 中解决 models 稀疏一般线性模型。然而,原始函数有大约 20 个参数,所以我开始(对于 Fortran 来说是全新的)用一个很小的子例程来测试如何传递数据。不幸的是,我总是收到 AccessViolationException。
代码如下:
Fortran 子例程。我使用 Rtools (http://cran.r-project.org/bin/windows/Rtools/) 附带的 gfortran 编译器,使用 -m64 选项将其编译为 dll(是的,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)] 属性。没有什么对我有用。
你有什么建议从哪里开始或改变什么?
更新 1: 即使只传递 float 和 int 也已经导致异常:
subroutine testbbb (f,i)
i = 815
f = 8.15
return
end subroutine testbbb
C# Pinvoke 和 call 相应更改。我做错了什么?
【问题讨论】:
-
您的 Fortan 库是否有可能通过指针接收参数?另外,您为什么要一次测试所有内容。为什么不简化?你能传递
int类型的单个参数吗?类型为float?然后尝试一个数组。不要先测试最复杂的东西。你怎么知道哪个部分失败了? -
好的,你的更新和我的评论交叉了。简化工作做得很好。尝试作为指针传递:
public static extern void Test(ref float f, ref int i) -
一旦你克服了简单类型的障碍,我们可以向你展示如何做数组。并且不需要
IntPtr。我们可以让 pinvoke marshaller 固定数组并使调用代码非常简单。 -
@DavidHeffernan
ref完成了这项工作。传递没有任何属性的数组有效。添加LPArray属性也一样好。操作数组也很好。现在尝试更复杂的场景。当有更多要说的时候会发表评论。
标签: c# fortran pinvoke marshalling access-violation