I have a dll written in fortran with a subroutine that takes a logical parameter as input. I want to use this to control cancellation of the subroutine, and have the possibility to change it's value in the calling c# code. Below is a small example of what I have tested with.
C# code:
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();
}
}
}
and fortran code:
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
What I get from this is:
C# :True
Inside fortran
F : TC# :False
F : TC# :True
F : TC# :False
F : TC# :True
What I would like is that F (fortran) alternates with C#. I have tried the opposite when reading the variable from C# and changing the variable in Fortran, which works as expected.
I have finally found an way to solve the cancellation. I give an exampel code that returns a value to the fortran code (and hence can be used to cancel the fortran subroutine/function):
c# code:
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}");
}
}
}
And Fortran code:
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
This code produce the following output:
F: Test before callback: 1
C#: Value before change: 1
C#: Value after change: 2
F: Test after callback: 2