I have a fortran subroutine that I call from C# and want to be able to terminate. This I can do using an integer variable that I alter in C# as the fortran routine runs. However changing this to a bool
/ logical(c_bool)
does not work. (In the code below is also an option where I change a value in a callback function.)
Working code (with int
parameters)
C#:
using System.Runtime.InteropServices;
Console.WriteLine("C# starting");
var cb = new Natives.ActionRefInt(OnUpdateProgress);
var terminate = 0;
var t = Task.Run(() => Natives.TestCallBackAndVariable(cb, ref terminate));
for (int i = 0; i < 4; i++)
{
await Task.Delay(900);
terminate = i * 100;
Console.WriteLine($"C# loop i = {i}, terminate = {terminate}");
}
terminate = -1;
await t;
static void OnUpdateProgress(ref int val2)
{
Console.WriteLine($"C# OnUpdateProgress received val2 = {val2}");
val2 += 10;
Console.WriteLine($"C# OnUpdateProgress setting val2 = {val2}");
}
public static class Natives
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ActionRefInt(ref int progress);
[DllImport(dllName: "FortranLib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void TestCallBackAndVariable(
[MarshalAs(UnmanagedType.FunctionPtr)] ActionRefInt callBack,
ref int terminate);
}
Fortran:
subroutine TestCallBackAndVariable(callBack, terminate)
!DEC$ ATTRIBUTES DLLEXPORT::TestCallBackAndVariable
!DEC$ ATTRIBUTES DECORATE,ALIAS:"TestCallBackAndVariable" :: TestCallBackAndVariable
use ISO_C_BINDING
implicit none
! Variables
external :: callBack
integer(C_INT),intent(inout) :: terminate
integer(C_INT) :: ii
integer(C_INT) :: val2
! Body of TestCallBackAndVariable
write(*,*) "Starting TestCallBackAndVariable in fortran lib"
do ii = 1,10
call sleep(1)
val2 = ii
call callBack(val2)
write(*,*) "Fortran loop ii = ",ii,", and terminate = ", terminate, ", and val from callback = ", val2
if (terminate<0) exit
end do
write(*,*) "Finished TestCallBackAndVariable in fortran lib"
end subroutine TestCallBackAndVariable
Not working as expected code (with bool
/ logical
)
C#:
using System.Runtime.InteropServices;
Console.WriteLine("C# starting");
var cb = new Natives.ActionRefBool(OnUpdateProgress);
var terminate = false;
var t = Task.Run(() => Natives.TestCallBackAndVariable(cb, ref terminate));
for (int i = 0; i < 4; i++)
{
await Task.Delay(900);
Console.WriteLine($"C# loop i = {i}, terminate = {terminate}");
}
terminate = true;
await t;
static void OnUpdateProgress(ref bool val2)
{
Console.WriteLine($"C# OnUpdateProgress received val2 = {val2}");
val2 = true;
Console.WriteLine($"C# OnUpdateProgress setting val2 = {val2}");
}
public static class Natives
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ActionRefBool(ref bool progress);
[DllImport(dllName: "FortranLib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void TestCallBackAndVariable(
[MarshalAs(UnmanagedType.FunctionPtr)] ActionRefBool callBack,
ref bool terminate);
}
Fortran:
subroutine TestCallBackAndVariable(callBack, terminate)
!DEC$ ATTRIBUTES DLLEXPORT::TestCallBackAndVariable
!DEC$ ATTRIBUTES DECORATE,ALIAS:"TestCallBackAndVariable" :: TestCallBackAndVariable
use ISO_C_BINDING
implicit none
! Variables
external :: callBack
logical(C_BOOL),intent(inout) :: terminate
integer(C_INT) :: ii
logical(C_BOOL) :: val2
! Body of TestCallBackAndVariable
write(*,*) "Starting TestCallBackAndVariable in fortran lib"
do ii = 1,10
call sleep(1)
val2 = .false.
call callBack(val2)
write(*,*) "Fortran loop ii = ",ii,", and terminate = ", terminate, ", and val from callback = ", val2
if (terminate) exit
end do
write(*,*) "Finished TestCallBackAndVariable in fortran lib"
end subroutine TestCallBackAndVariable
subroutine TestArray(i,j,arr)
In the bool/logical variant does not c# modify value of the logical terminate
fortran variable. However, changing the logical value in the OnUpdateProgress
does work. (propagates back to fortran)
Help on this is, as always, much appreciated.
(VS 2022 NET 6, IFORT 2021.6.0 64bit)