Fortran Wiki
C# Interoperability

C# is able to call Fortran DLLs using P/Invoke.

The following example shows how to call an Intel Fortran 12.1 DLL using a C# console application. The DLL function also features a simple call back function so that the C# application can display the progress of the Fortran method to the user. The example was adapted from xTechNotes. See also Calling FORTRAN function or subroutine in DLL from C# code

Fortran DLL

First, create a Dynamic-link Library project in Intel Fortran. The DoWork function passes a 2-D array of known size. The contents of the array are modified in the method.

Make sure to add a post-build event to copy the DLL to the C# application directory. copy (ProjectDir)\Debug\(TargetName).dll $(SolutionDir)\CSharpClient\bin\Debug

module FortranCallBack

    implicit none

contains

    subroutine DoWork(n, A, progressCallBack)

        !DEC$ ATTRIBUTES DLLEXPORT :: DoWork
        !DEC$ ATTRIBUTES ALIAS: 'DoWork' :: DoWork
        !DEC$ ATTRIBUTES REFERENCE :: n, A, progressCallBack

        external progressCallBack
        integer, intent(in) :: n
        real(8), dimension(n, n), intent(inout) :: A

        integer :: i

        do i = 1, n
            write (*,*) "Fortran says: ", i
            call progressCallBack(i)
            A(i, i) = i**2
        end do

        return

    end subroutine

end module

C# Client

Next, make a C# console application named CSharpClient. Copy and pasted the code into the Program class.

  • A common mistake is failing pass the parameters to the DLL by reference (ref). Failing to do so will usually cause memory access violations.

  • Also make sure that you get the name of the Fortran DLL method correct. In the Fortran code we used the ALIAS attribute to override any Fortran compiler name mangling. You can verify the name of the DLL method using the DUMPBIN utility included with Visual Studio. To use DUMPBIN, open the Visual Studio Command Prompt and type DUMPBIN /EXPORTS [filename.dll].

  • You can step into the Fortran DLL while debugging. In the C# project properties page, go to Debug and select Enable unmanaged code debugging.

  • Strings can be passed from C# to Fortran using character arrays (char[]). When converting C# strings to character arrays make sure that any unused characters are initialized to blanks.

      using System;
      using System.Runtime.InteropServices;
    
      namespace CSharpClient
      {
          class Program
          {
              // Delegate type.
              [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
              public delegate void ActionRefInt(ref int progress); // Important the int is passed by ref (else we could use built-in Action<T> instead of delegate).
    
              // Delegate variable.
              public ActionRefInt callbackHandler;
    
              public Program()
              {
                  callbackHandler = new ActionRefInt(OnUpdateProgress);
              }
    
              static void Main(string[] args)
              {
                  Program myProg = new Program();
                  
                  int n = 10;
                  var A = new double[n, n];
                  for (int i = 0; i < n; i++)
                  {
                      for (int j = 0; j < n; j++)
                      {
                          A[i, j] = 0.0;
                      }
                  }
    
                  DoWork(ref n, A, myProg.callbackHandler);
    
                  for (int i = 0; i < n; i++) Console.WriteLine("A(" + (i + 1) + ", " + (i + 1) + ") = " + A[i, i]);
              }
    
              public void OnUpdateProgress(ref int progress)
              {
                  Console.WriteLine("C# says: " + progress);
              }
    
              // Fortran DLL interface.
              [DllImport("FortranCallBack.dll", EntryPoint = "DoWork", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
              public static extern void DoWork(ref int n, [In, Out] double[,] A, [MarshalAs(UnmanagedType.FunctionPtr)] ActionRefInt callBack);
          }
      }