在控制台上从C#调用Fortran子程序

在控制台上从C#调用Fortran子程序,c#,fortran,interop,C#,Fortran,Interop,我想使用在控制台输入的命令从C#调用Fortran子程序。 我已经试了两天了,读了很多网页,也听了很多建议,但都没有成功 这是我多次失败尝试的典型例子 我使用文本编辑器(记事本)创建了这个名为“fdll.f90”的文件 在MS-DOS控制台(CMD.EXE),我键入以下命令并按“回车”: 出现两个新文件,分别名为“fdll.dll”和“fdll.mod” 使用Monodevelop C#文本编辑器,我创建了以下名为“DLLImport.cs”的C#源文件 在控制台中,我输入以下命令: C:\W

我想使用在控制台输入的命令从C#调用Fortran子程序。 我已经试了两天了,读了很多网页,也听了很多建议,但都没有成功

这是我多次失败尝试的典型例子

我使用文本编辑器(记事本)创建了这个名为“fdll.f90”的文件

在MS-DOS控制台(CMD.EXE),我键入以下命令并按“回车”:

出现两个新文件,分别名为“fdll.dll”和“fdll.mod”

使用Monodevelop C#文本编辑器,我创建了以下名为“DLLImport.cs”的C#源文件

在控制台中,我输入以下命令:

 C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /t:exe /out:go.exe DLLImport.cs 
此时会出现一个名为“go.exe”的新文件。我输入“go”

结果是弹出一个窗口,告诉我“go.exe已停止工作”。它给了我关闭程序的选项。在MS-DOS控制台上,出现以下消息:

 Unhandled Exception: System.BadImageFormatException: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
 at Fortran.Lib.testFDLL(String Plea)
 at DLLImport.Main(String[] args)
我做错了什么?我怎样才能做到这一点

我使用的是运行Windows8.1的64位索尼笔记本电脑。我正在使用gfortran的最新版本(i686-w64-mingw32)

更新:我修改了Fortran源代码以允许ISO_C_绑定(遵循Pierre的建议)。新版本为:

 module fdll
 contains
 subroutine testFDLL(char) bind(C)
     USE ISO_C_BINDING
     character (C_CHAR) :: char(20)
    write(6,*)" Hello FORTRAN : let us do something ..."
 return
 end subroutine
 end module
我还修改了C#源代码,使其将字符串作为数组发送到Fortran中(如下所述:)。新的C#代码是:

使用系统;
使用System.Runtime.InteropServices;
公共静态类DLLImport
{       
公共静态void Main(字符串[]args)
{
RunFortranDLL();
}
公共静态void RunFortranDLL()
{
testFDLL(ToCharacterArrayFortran(“请工作!”,20));
}
公共静态字符[]ToCharacterArrayFortran(此字符串源,整数长度)
{
var chars=新字符[长度];
int sourceLength=source.Length;
for(int i=0;i
我没有更改运行编译器的命令行参数;无论是compile、gfortan还是csc,都没有对这些更改提出抱怨

结果:当我运行程序(输入“go”)时,会出现相同的错误消息


有人能解释一下我所做的错事或遗漏了什么吗。让C#将字符串发送到Fortran子例程中真的很难吗?

我只是尝试演示如何将此Fortran代码与C接口,这并不能完全回答您的问题,但如果您知道如何将C(假装Fortran为C)与C#接口,应该会有所帮助

!fortran code, named as x.f90
module fdll
    implicit none
contains

subroutine testFDLL(str, n) bind(c, name='testFDLL_as_C')
    use ISO_C_BINDING
    integer(c_int), value :: n
    character(kind=c_char), intent(in) :: str(n)
    write(6,*)" Hello FORTRAN : let us do something ...",str
    return
end
end module
以及调用FORTRAN子程序的C代码

//c code explicitly link. named as y.c
#include <stdio.h>
#include <string.h>

int main()
{
    void testFDLL_as_C(char *str, int n);
    char str[] = "Hello from C";
    testFDLL_as_C(str, strlen(str));
    return 0;
}
您还可以隐式链接动态库,如下所示(请注意,对于较短的示例,请忽略所有错误检查和关闭资源)

第二个程序的输出如下:

  Hello FORTRAN : let us do something ...Hello from C, again, using dynamic dlopen()
C#的定义不正确。应该是

public static extern void __MOD_fdll_testFDLL(byte[] Plea);

您可以使用nm(如果有的话)或依赖项遍历器来找出导出的符号是什么

请注意,C#char是2个字节,Fortran char是1个字节,数组的存储方式在Fortran和C#中都不同


如果这只是一个互操作性测试,请尝试先处理整数,并确保它可以工作。然后转到单个字符(字节),然后转到数组。不要在第一次尝试时继续使用数组。

您读过Fortran的
iso#U绑定
功能吗?谢谢。如果你能告诉我我的源代码,或者我的命令在哪里,我会很感激。<代码> ISOL.CXBION/<代码>是一组特性,包括在C和C之间安排C风格调用约定(ABI)的说明符(而不是C,你必须考虑代码为C)。这是一个众所周知的主题,所以在任何人提供进一步帮助之前,您的任务是至少尝试一下并在这里发布您的改编代码。当然。我试试看。在我关于这个主题(C#和FORTRAN的互操作性)的所有研究中,都没有提到“iso#C#绑定”。但我会研究一下。Fortran没有直接的“C#”功能。你需要把它看作是C接口。谢谢。我将我的FORTRAN代码更改为与您的相同,但错误消息仍然存在。你的C代码很有趣。我看不出如何修改我的C代码来镜像它。有什么想法吗?你需要确定是FORTRAN问题、C#问题、接口问题还是运行时环境问题。我假设您知道如何从C#调用C dll库,因为我不知道C#。您可以尝试使用C作为中间语言,首先从C#调用C dll以消除与FORTRAN无关的可能问题。我的例子就是与FORTRAN相关的部分。首先尝试隔离问题。您是如何编译FORTRAN代码的?你能告诉我控制台命令行的确切语法吗?我只是把它编译成gfortran-cx.f90来测试代码。它可能没有帮助,因为您希望将其编译到动态链接库中。正如我所说,这个例子只是展示了FORTRAIN和C的互操作性,您的确切问题可能在链的另一部分。
!fortran code, named as x.f90
module fdll
    implicit none
contains

subroutine testFDLL(str, n) bind(c, name='testFDLL_as_C')
    use ISO_C_BINDING
    integer(c_int), value :: n
    character(kind=c_char), intent(in) :: str(n)
    write(6,*)" Hello FORTRAN : let us do something ...",str
    return
end
end module
//c code explicitly link. named as y.c
#include <stdio.h>
#include <string.h>

int main()
{
    void testFDLL_as_C(char *str, int n);
    char str[] = "Hello from C";
    testFDLL_as_C(str, strlen(str));
    return 0;
}
  Hello FORTRAN : let us do something ...Hello from C
//implicit link. named as z.c
#include <stdio.h>
#include <string.h>
#include <dlfcn.h>

int main()
{
    void (*func_from_so_f90)(char *str, int n);
    char str[] = "Hello from C, again, using dynamic dlopen()";
    void *handle = dlopen("./libxf90.so", RTLD_LAZY);
    func_from_so_f90 = dlsym(handle, "testFDLL_as_C");
    func_from_so_f90(str, strlen(str));
    return 0;
}
gfortran -o libxf90.so -shared -fPIC x.f90
gcc -o yout y.c ./libxf90.so
gcc -o zout z.c -ldl
  Hello FORTRAN : let us do something ...Hello from C, again, using dynamic dlopen()
public static extern void __MOD_fdll_testFDLL(byte[] Plea);