从 C# 调用 FORTRAN dll 并将值分配给结构数组

发布于 2024-11-11 16:49:37 字数 1890 浏览 4 评论 0原文

我可以将 C# 结构传递到 FORTRAN 中。我什至可以将 C# 结构数组作为 FORTRAN 中的 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);
    }
}

结果:

Initialize
  A=0
  A=1
  A=2
  A=3
Call Fortran
  A=0
  A=1
  A=2
  A=3

通过 FORTRAN 代码进行调试,我看到从 C# 传递的初始值> 到 FORTRAN 就可以了。这些值被新值覆盖,并且控制权被传递回 C#,其中旧值仍然包含在 ValueRef 实例中。

为什么我可以以类似的方式传递和返回 floatint 数组,就很好了。我可以使用 ref 关键字传递和返回单数结构,并且我可以传递但不能返回和 struct 数组?

PS。我正在使用 Compaq Visual Fortran 6.5 & .NET 3.5
PS2。我很感激对此的任何评论/想法。我的项目完成了 95%,现在遇到了这个问题。这个项目的重点是尽可能多地使用结构来减少传递给函数的参数 #of 并保留 OOP 设计的某些方面。

I can pass a C# struct into FORTRAN just fine. I can even pass an array of a C# struct as an array of TYPE() in FORTRAN. Where I run into trouble is when I tried to return values back into C#. Here is an example:

The fortran dll is:

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

and the C# calling function that expects results is:

[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);
    }
}

With results:

Initialize
  A=0
  A=1
  A=2
  A=3
Call Fortran
  A=0
  A=1
  A=2
  A=3

Debugging through the FORTRAN code, I see the initial values pass from C# to FORTRAN just fine. The the values get overridden with new values and control is passed back into C# where the old values are still contained within the ValueRef instances.

Why is it that I can pass and return an array of float, or int in a similar fashion, just fine. and I can pass and return singular structures with ref keyword, and I can pass but not return and array of struct?

PS. I am using Compaq Visual Fortran 6.5 & .NET 3.5
PS2. I appreciate any comments/ideas on this. I am 95% done with my project, and now I run into this issue. The whole point of this project is to use structures as much as possible to reduce the #of arguments passed to functions and retain certain aspects of OOP design.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

黒涩兲箜 2024-11-18 16:49:37

我过去使用指针而不是数组来完成此操作。我认为您的结构正在为 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);

Here is a MSDN 有关数组编组的参考,以及它们如何默认[In]

I have done this in the past using a pointer, not an array. I think that your structures are being copied for the P/Invoke call:

[DllImport("mathlib.dll")]
static extern void TEST_REF(ValueRef* t, int n);

You will need to pin your array before calling the method.

fixed (ValueRef* pointer = t)
{
  TEST_REF(pointer, n);
}

Edit:
Based on the comments the solution is to declare the external as

[DllImport("mathlib.dll")]
static extern void TEST_REF([Out] ValueRef[] t, int n);

Here is a MSDN reference on Marshaling of arrays, and how they default to [In].

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文