【发布时间】:2019-07-08 07:04:45
【问题描述】:
我想使用在控制台输入的命令从 C# 调用 Fortran 子例程。 我已经尝试了两天,阅读了很多网页,并听取了很多建议,但没有成功。
这是我多次失败尝试的典型例子。
我使用文本编辑器(记事本)创建了这个名为“fdll.f90”的文件
module fdll
implicit none
contains
subroutine testFDLL(char)
character(12) :: char
write(6,*)" Hello FORTRAN : let us do something ...",char
return
end
end module
在 MS-DOS 控制台 (CMD.EXE),我输入以下命令并按“Enter”:
C:\Compilers\fortran\mingw32\bin\gfortran.exe -shared -o fdll.dll fdll.f90
出现两个新文件,名为“fdll.dll”和“fdll.mod”。
使用 Monodevelop C# 文本编辑器,我创建了以下名为“DLLImport.cs”的 C# 源文件
using System;
using System.Runtime.InteropServices;
public static class DLLImport
{
public static void Main(string[] args)
{
RunFortranDLL ();
}
public static void RunFortranDLL()
{
FortranLib.testFDLL("Please work!");
}
}
public static class FortranLib
{
private const string dllName = "fdll.dll";
[DllImport(dllName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern void testFDLL(string Plea);
}
在控制台,我输入以下命令:
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)
我做错了什么?我怎样才能做到这一点?
我使用的是运行 Windows 8.1 的 64 位 SONY 笔记本电脑。我正在使用最新版本的 gfortran (i686-w64-mingw32)。
更新:我修改了 Fortran 源代码以允许 ISO_C_BINDING(遵循 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(此处解释为:http://www.luckingtechnotes.com/calling-fortran-dll-from-csharp/)。新的 C# 代码是:
using System;
using System.Runtime.InteropServices;
public static class DLLImport
{
public static void Main(string[] args)
{
RunFortranDLL ();
}
public static void RunFortranDLL()
{
FortranLib.testFDLL(ToCharacterArrayFortran("Please work!",20));
}
public static char[] ToCharacterArrayFortran(this string source, int length)
{
var chars = new char[length];
int sourceLength = source.Length;
for (int i = 0; i < length; i++)
{
if (i < sourceLength)
chars[i] = source[i];
else
chars[i] = ' '; // Important that these are blank for Fortran compatibility.
}
return chars;
}
}
public static class FortranLib
{
private const string dllName = "fdll.dll";
[DllImport(dllName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern void testFDLL(char[] Plea);
}
我没有更改运行编译器的命令行参数; compile、gfortan 和 csc 都没有抱怨这些变化。
结果:当我运行程序时(输入“go”),出现相同的错误消息。
有人可以解释一下我所做的事情有什么问题或遗漏。让 C# 将字符串发送到 Fortran 子程序中真的很难吗?
【问题讨论】:
-
您是否了解过 Fortran 的
iso_c_binding功能? -
谢谢。如果您能告诉我源代码或命令的位置,我将不胜感激。
-
iso_c_binding是一组功能,包括安排 Fortran 和 C 之间的 C 风格调用约定 (ABI) 的说明符(不是 C#,您必须将代码视为 C)。这是一个众所周知的话题,因此您的任务是至少在任何人提供进一步帮助之前尝试并在此处发布您修改后的代码。 -
当然。我会试试看。在我对这个主题(C# 和 FORTRAN 的互操作性)的所有研究中,都没有提到“iso_c_binding”。但我会调查的。
-
Fortran 没有直接的“C#”功能。您需要将其视为 C 接口。