从C#调用FORTRAN DLL并将值分配给结构数组 [英] Calling FORTRAN dll from C# and assigning values to array of structures

查看:248
本文介绍了从C#调用FORTRAN DLL并将值分配给结构数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我可以将 C#结构传递给 FORTRAN 就好了。我甚至可以将一个 C#结构的数组作为 TYPE()的数组传递给 FORTRAN 。当我试图将值返回到 C#时,我遇到了麻烦。这里是一个例子:

Fortran dll是:

  MODULE测试

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

结果:

 初始化
A = 0
A = 1
A = 2
A = 3
呼叫Fortran
A = 0
A = 1
A = 2
A = 3

通过FORTRAN代码调试,我发现初始值从 C#传递给 FORTRAN 正好。这些值被新的值覆盖,并且控制被传回到 C#中,旧值仍包含在 ValueRef 实例。

为什么我可以传递并返回一个 float 或<$ c $的数组c> int 以类似的方式,就好了。我可以通过并返回带有 ref 关键字的单数结构,并且我可以通过但不是返回和 struct



PS 。我正在使用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);

这是关于数组封装的MSDN 参考,以及它们如何默认 [In]


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.

解决方案

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].

这篇关于从C#调用FORTRAN DLL并将值分配给结构数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆