从C#调用FORTRAN dll并为结构数组赋值
我可以将从C#调用FORTRAN dll并为结构数组赋值,c#,interop,struct,fortran,C#,Interop,Struct,Fortran,我可以将C#结构传递到FORTRAN中。我甚至可以在FORTRAN中将C结构的数组作为TYPE()的数组传递。当我试图将值返回到C时,我遇到了麻烦。以下是一个例子: fortran dll是: MODULE TESTING TYPE VALUEREF INTEGER*4 :: A ENDTYPE VALUEREF CONTAINS SUBROUTINE TEST_REF(T,N) !DEC$ ATTRIBUTES DLLEXPORT :: TEST_REF
C#
结构传递到FORTRAN
中。我甚至可以在FORTRAN
中将C
结构的数组作为TYPE()
的数组传递。当我试图将值返回到C
时,我遇到了麻烦。以下是一个例子:
fortran dll是:
MODULE TESTING
TYPE VALUEREF
INTEGER*4 :: A
ENDTYPE VALUEREF
CONTAINS
SUBROUTINE TEST_REF(T,N)
!DEC$ ATTRIBUTES DLLEXPORT :: TEST_REF
!DEC$ ATTRIBUTES ALIAS:'TEST_REF' :: TEST_REF
!DEC$ ATTRIBUTES VALUE :: N
IMPLICIT NONE
INTEGER*4 :: A,I,N
TYPE(VALUEREF) :: T(N)
A = 100
DO I=1,N
T(I)%A = A + I
END DO
END SUBROUTINE
END MODULE
而预期结果的C#
调用函数是:
[StructLayout(LayoutKind.Sequential)]
public struct ValueRef
{
public int a;
}
[DllImport("mathlib.dll")]
static extern void TEST_REF(ValueRef[] t, int n);
void Main()
{
ValueRef[] T = new ValueRef[4];
for (int i = 0; i < T.Length; i++)
{
T[i].a = i;
}
Console.WriteLine("Initialize");
for (int i = 0; i < T.Length; i++)
{
Console.WriteLine(" A={0}", T[i].a);
}
Console.WriteLine("Call Fortran");
TEST_REF(T, T.Length);
for (int i = 0; i < T.Length; i++)
{
Console.WriteLine(" A={0}", T[i].a);
}
}
通过对FORTRAN代码进行调试,我看到初始值从C#
传递到FORTRAN
很好。值被新值覆盖,控制权被传递回C 35;
中,其中旧值仍包含在ValueRef
实例中
为什么我可以以类似的方式传递并返回一个float
数组,或者int
,很好。我可以传递和返回带有ref
关键字的奇异结构,我可以传递但不返回和struct的数组
另外,我正在使用Compaq Visual Fortran 6.5和.NET 3.5PS2。我非常感谢您对此提出的任何意见/想法。我的项目完成了95%,现在我遇到了这个问题。本项目的重点是尽可能多地使用结构,以减少传递给函数的参数数量,并保留OOP设计的某些方面。我过去使用指针而不是数组来实现这一点。我认为正在为P/Invoke调用复制您的结构:
[DllImport("mathlib.dll")]
static extern void TEST_REF(ValueRef* t, int n);
在调用该方法之前,需要固定数组
fixed (ValueRef* pointer = t)
{
TEST_REF(pointer, n);
}
编辑:
根据注释,解决方案是将外部
[DllImport("mathlib.dll")]
static extern void TEST_REF([Out] ValueRef[] t, int n);
这里有一个关于数组封送的参考,以及它们如何默认为
[In]
我想这取决于运行时如何封送您的值,这不应该是一个问题,它总是工作得很好,我很惊讶地看到FORTRAN/C混合格式,不幸的是,现实是,现代FORTRAN语言既简单又快速。我看不出有什么理由不仅保留旧代码,而且用FORTRAN开发新代码。当然对于GUI之类的,我把它留给C#/OpenTK。我只是想建议。。。请确保使用不安全标志编译代码,并使用不安全关键字标记方法和范围,否则会出现一系列编译器错误。当我传递单个结构byref时,它不会被复制,但当我传递数组时,它会被复制!?您可以尝试的第二件事是在P/Invoke签名上使用[Out]属性。因此,如果您编辑您的答案,我将予以奖励。我使用正确的解决方案编辑了答案,并添加了来自Microsoft的相关参考。
[DllImport("mathlib.dll")]
static extern void TEST_REF([Out] ValueRef[] t, int n);