Topic: Calling Fortran from C#

I recently received a request from a user to provide an example of calling Fortran code from a C# program.  This procedure is similar to calling Fortran with modern Visual Basic implementations.  For this example, we can work with a 32-bit example.  Starting with a simple Fortran subroutine:

subroutine timestwo(x, n)
use iso_c_binding
implicit none
!GCC$ ATTRIBUTES dllexport, stdcall :: timestwo

real(kind=c_double), intent(inout), dimension(n)::x
integer(kind=c_int), value::n

    x = 2*x

end subroutine timestwo

In the Fortran code, the subroutine  has two attributes assigned, dllexport and stdcall.  The former instructs the compiler that this subroutine will be a public DLL function, and the latter specifies the calling convention.  This code can be compiled as a 32-bit "Shared Library" project in Simply Fortran.

The C# code is relatively straightforward as well:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace callf
{
    class Program
    {
        [DllImport("timestwo.dll", EntryPoint=@"timestwo@8", CallingConvention=CallingConvention.StdCall)]
        static extern void timestwo(double[] x, int n);

        static void Main(string[] args)
        {
            double[] values = new double[] { 1.0, 3.0, 5.0, 7.0, 9.0 };
            timestwo(values, values.Length);
            foreach(double x in values) {
                System.Console.WriteLine(x);
            }
            
            System.Console.ReadKey();
        }
    }
}

The oddest part is the "DllImport" statement.  In this example, we need to specify two extra bits of information to our "DllImport" statement in order to call our "timestwo" subroutine. First, we need to specify the decorated name of the DLL function.  If one opens the resultant DLL compiled with Simply Fortran, the editor will list functions in the DLL, once of which will appear similar to:

66781460 T _timestwo@8 

The "EntryPoint" argument to "DllImport" needs to reflect part of the decoration, namely the "@8" portion.  Much of the confusion surrounding decorations will actually disappear if a 64-bit DLL is used instead.

The above code will actually run fine as long as the Fortran DLL is in a proper directory.  For simplicity, it should be located in the same directory as the C# executable itself.

This post is just a simple example of calling Fortran from C#.

Jeff Armstrong
Approximatrix, LLC

Re: Calling Fortran from C#

What do we do for the case of several connected subroutines ?

Re: Calling Fortran from C#

It depends what you mean by "connected subroutines."  If you're asking about the case where, for example, your Fortran subroutine calls additional Fortran subroutines in the same DLL, then there really isn't an issue.  Let's assume the ridiculous case where our timestwo subroutine will actually call a Fortran function to determine the value of 2 in a separate module:

module numbers
contains
    pure function twovalue()
    implicit none
        twovalue = 1.0 + 1.0
    end function twovalue
end module numbers

subroutine timestwo(x, n)
use iso_c_binding
use numbers
implicit none
!GCC$ ATTRIBUTES dllexport, stdcall :: timestwo

real(kind=c_double), intent(inout), dimension(n)::x
integer(kind=c_int), value::n

    x = twovalue()*x

end subroutine timestwo

So when Fortran calls Fortran in the same DLL, there really isn't anything the programmer has to do to allow this to proceed.  The Fortran compiler knows how to call Fortran already.  The interface in the C# code remains the same because it doesn't need to know about our new function, twovalue.

Things can get mildly more complex if you're calling a Fortran subroutine in another DLL, but not substantially more complex. 

Does that answer your question?

Jeff Armstrong
Approximatrix, LLC