我有一个用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#:真 内福特兰 F:T C#:假 F:T C#:真 F:T C#:假 F:T C#:真
我想要的是F (fortran)与C#交替使用。在从C#读取变量和在Fortran中更改变量时,我尝试了相反的方法,而Fortran的工作原理是预期的。
发布于 2020-01-22 12:52:59
我终于找到了解决取消的办法。我给出了一个示例代码,它向fortran代码返回一个值(因此可以用来取消fortran子例程/函数):
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:回调前的测试:1 C#:变化前的价值:1 C#:更改后的值:2 F:回调后的测试:2
发布于 2019-08-13 23:22:44
我不认识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),并带有一个具有_Bool类型的输入参数b。
https://stackoverflow.com/questions/57478125
复制相似问题