从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.5

PS2。我非常感谢您对此提出的任何意见/想法。我的项目完成了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);