从 C# 中的调用函数更改 Fortran 中的引用参数值
Changing reference parameter value in fortran from calling function in c#
我有一个用 fortran 编写的 dll,其中包含一个将逻辑参数作为输入的子例程。我想用它来控制子例程的取消,并有可能在调用 c# 代码中更改它的值。下面是我测试过的一个小例子。
C#代码:
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace TestConsApp
{
internal static class Program
{
private static bool _b;
[DllImport(dllName: "TestFortran.dll", CallingConvention = CallingConvention.Cdecl)]
internal static extern void TestBool(ref bool b);
private static void Main(string[] args)
{
TestFortranBool();
Console.ReadLine();
}
private static void TestFortranBool()
{
_b = true;
var t = Task.Factory.StartNew(() => TestBool(ref _b));
Console.WriteLine($"C# :{_b}");
Thread.Sleep(5000);
_b = false;
Console.WriteLine($"C# :{_b}");
Thread.Sleep(5000);
_b = true;
Console.WriteLine($"C# :{_b}");
Thread.Sleep(5000);
_b = false;
Console.WriteLine($"C# :{_b}");
Thread.Sleep(5000);
_b = true;
Console.WriteLine($"C# :{_b}");
t.Wait();
}
}
}
和 Fortran 代码:
module FortranTesting
use iso_c_binding
implicit none
contains
subroutine TestBool(b)
! Expose subroutine TestFortran to users of this DLL
!
!DEC$ ATTRIBUTES DLLEXPORT::TestBool
!DEC$ ATTRIBUTES DECORATE,ALIAS:"TestBool" :: TestBool
logical(c_bool),intent(in) :: b
write(*,*) "Inside fortran"
write(*,*) "F :", b
call sleep(5)
write(*,*) "F : ", b
call sleep(5)
write(*,*) "F : ", b
call sleep(5)
write(*,*) "F : ", b
end subroutine TestBool
end module FortranTesting
我从中得到的是:
C# :True
Inside fortran
F : T
C# :False
F : T
C# :True
F : T
C# :False
F : T
C# :True
我想要的是 F (fortran) 与 C# 交替使用。
当从 C# 读取变量并在 Fortran 中更改变量时,我尝试了相反的方法,这按预期工作。
我不会C#,所以在这方面帮不了你。但是,只要您可以将 C# 与 C 接口,也可以通过一种方法将 Fortran 代码连接到 C#。为此,您必须将 bind(C)
属性添加到您的 Fortran 代码中,
module FortranTesting
use iso_c_binding
implicit none
contains
subroutine TestBool(b) bind(C, name = "TestBool")
! Expose subroutine TestFortran to users of this DLL
!DEC$ ATTRIBUTES DLLEXPORT :: TestBool
use, intrinsic :: iso_c_binding, only: c_bool
implicit none
logical(c_bool), intent(in) :: b
write(*,*) "Inside Fortran:"
write(*,*) "F :", b
call sleep(5)
write(*,*) "F : ", b
call sleep(5)
write(*,*) "F : ", b
call sleep(5)
write(*,*) "F : ", b
end subroutine TestBool
end module FortranTesting
此代码现在应该可以从 C 调用为 TestBool(b)
,输入参数 b
的类型为 _Bool
.
我终于找到了解决取消的方法。
我给出了一个示例代码,该代码 returns 是 fortran 代码的一个值(因此可用于取消 fortran subroutine/function):
c#代码:
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace TestConsApp
{
internal static class Program
{
[DllImport(dllName: "TestFortran.dll", CallingConvention = CallingConvention.Cdecl)]
internal unsafe static extern void TestCallBack([MarshalAs(UnmanagedType.FunctionPtr)] ActionRefInt callBack);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ActionRefInt(ref int i);
private static void Main(string[] args)
{
TestCallBack();
Console.ReadLine();
}
private static void TestCallBack()
{
var callbackHandler = new ActionRefInt(OnCallBackInt);
TestCallBack(callbackHandler);
}
private static void OnCallBackInt(ref int i)
{
Console.WriteLine($"C#: Value before change: {i}");
i++;
Console.WriteLine($"C#: Value after change: {i}");
}
}
}
和 Fortran 代码:
module FortranTesting
use iso_c_binding
implicit none
contains
subroutine TestCallBack(callBack)
!DEC$ ATTRIBUTES DLLEXPORT::TestCallBack
!DEC$ ATTRIBUTES DECORATE,ALIAS:"TestCallBack" :: TestCallBack
external :: callBack
integer :: test
test = 1
write(*,*) "F: Test before callback: ", test
call callBack(test)
write(*,*) "F: Test after callback: ", test
end subroutine TestCallBack
end module FortranTesting
此代码产生以下输出:
F: Test before callback: 1
C#: Value before change: 1
C#: Value after change: 2
F: Test after callback: 2
我有一个用 fortran 编写的 dll,其中包含一个将逻辑参数作为输入的子例程。我想用它来控制子例程的取消,并有可能在调用 c# 代码中更改它的值。下面是我测试过的一个小例子。
C#代码:
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace TestConsApp
{
internal static class Program
{
private static bool _b;
[DllImport(dllName: "TestFortran.dll", CallingConvention = CallingConvention.Cdecl)]
internal static extern void TestBool(ref bool b);
private static void Main(string[] args)
{
TestFortranBool();
Console.ReadLine();
}
private static void TestFortranBool()
{
_b = true;
var t = Task.Factory.StartNew(() => TestBool(ref _b));
Console.WriteLine($"C# :{_b}");
Thread.Sleep(5000);
_b = false;
Console.WriteLine($"C# :{_b}");
Thread.Sleep(5000);
_b = true;
Console.WriteLine($"C# :{_b}");
Thread.Sleep(5000);
_b = false;
Console.WriteLine($"C# :{_b}");
Thread.Sleep(5000);
_b = true;
Console.WriteLine($"C# :{_b}");
t.Wait();
}
}
}
和 Fortran 代码:
module FortranTesting
use iso_c_binding
implicit none
contains
subroutine TestBool(b)
! Expose subroutine TestFortran to users of this DLL
!
!DEC$ ATTRIBUTES DLLEXPORT::TestBool
!DEC$ ATTRIBUTES DECORATE,ALIAS:"TestBool" :: TestBool
logical(c_bool),intent(in) :: b
write(*,*) "Inside fortran"
write(*,*) "F :", b
call sleep(5)
write(*,*) "F : ", b
call sleep(5)
write(*,*) "F : ", b
call sleep(5)
write(*,*) "F : ", b
end subroutine TestBool
end module FortranTesting
我从中得到的是:
C# :True
Inside fortran
F : TC# :False
F : TC# :True
F : TC# :False
F : TC# :True
我想要的是 F (fortran) 与 C# 交替使用。 当从 C# 读取变量并在 Fortran 中更改变量时,我尝试了相反的方法,这按预期工作。
我不会C#,所以在这方面帮不了你。但是,只要您可以将 C# 与 C 接口,也可以通过一种方法将 Fortran 代码连接到 C#。为此,您必须将 bind(C)
属性添加到您的 Fortran 代码中,
module FortranTesting
use iso_c_binding
implicit none
contains
subroutine TestBool(b) bind(C, name = "TestBool")
! Expose subroutine TestFortran to users of this DLL
!DEC$ ATTRIBUTES DLLEXPORT :: TestBool
use, intrinsic :: iso_c_binding, only: c_bool
implicit none
logical(c_bool), intent(in) :: b
write(*,*) "Inside Fortran:"
write(*,*) "F :", b
call sleep(5)
write(*,*) "F : ", b
call sleep(5)
write(*,*) "F : ", b
call sleep(5)
write(*,*) "F : ", b
end subroutine TestBool
end module FortranTesting
此代码现在应该可以从 C 调用为 TestBool(b)
,输入参数 b
的类型为 _Bool
.
我终于找到了解决取消的方法。 我给出了一个示例代码,该代码 returns 是 fortran 代码的一个值(因此可用于取消 fortran subroutine/function):
c#代码:
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace TestConsApp
{
internal static class Program
{
[DllImport(dllName: "TestFortran.dll", CallingConvention = CallingConvention.Cdecl)]
internal unsafe static extern void TestCallBack([MarshalAs(UnmanagedType.FunctionPtr)] ActionRefInt callBack);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ActionRefInt(ref int i);
private static void Main(string[] args)
{
TestCallBack();
Console.ReadLine();
}
private static void TestCallBack()
{
var callbackHandler = new ActionRefInt(OnCallBackInt);
TestCallBack(callbackHandler);
}
private static void OnCallBackInt(ref int i)
{
Console.WriteLine($"C#: Value before change: {i}");
i++;
Console.WriteLine($"C#: Value after change: {i}");
}
}
}
和 Fortran 代码:
module FortranTesting
use iso_c_binding
implicit none
contains
subroutine TestCallBack(callBack)
!DEC$ ATTRIBUTES DLLEXPORT::TestCallBack
!DEC$ ATTRIBUTES DECORATE,ALIAS:"TestCallBack" :: TestCallBack
external :: callBack
integer :: test
test = 1
write(*,*) "F: Test before callback: ", test
call callBack(test)
write(*,*) "F: Test after callback: ", test
end subroutine TestCallBack
end module FortranTesting
此代码产生以下输出:
F: Test before callback: 1
C#: Value before change: 1
C#: Value after change: 2
F: Test after callback: 2