Home > OS >  Calling Fortran from C# in VS2019 with iFort
Calling Fortran from C# in VS2019 with iFort

Time:10-23

I am trying to call Fortran code from C#. I am using Visual Studio 2019 and the Intel Fortran Compiler (iFort).

I created a fortran DLL project with the following code that compiles without issue (project set to 'release', 'x64'):

module Fortran_DLL_Lib
    implicit none
contains
    subroutine adder(a,b,x,y)
        !DEC$ ATTRIBUTES DLLEXPORT, ALIAS:'adder' :: adder
        !DEC$ ATTRIBUTES REFERENCE :: x,y
        implicit none
        integer, intent(in) :: a,b
        integer, intent(out) :: x,y
        y = a   b
        x = 2*a 3*b
    end subroutine
end module

I then created a C# console application with the following code (project also set to 'Release', 'x64'):

using System;
using System.Runtime.InteropServices;

namespace Call_Fortran_Dll_FromCS_Test
{
    class Program
    {
        [DllImport("Fortran_DLL_Lib.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern void adder(int a, int b, [Out] int x, [Out] int y);
        static void Main(string[] args)
        {
            int a = 4;
            int b = 3;
            int x = 0;
            int y = 0;
            Console.WriteLine(a);
            Console.WriteLine(b);
            Console.WriteLine(x);
            Console.WriteLine(y);

            adder(a, b, x, y); //error occurs here
            Console.WriteLine(a);
            Console.WriteLine(b);
            Console.WriteLine(x);
            Console.WriteLine(y);
            Console.ReadKey();
        }
    }
}

The program runs up until the line that calls the fortran function, then returns the error

Exception thrown: 'System.DllNotFoundException' in Call_Fortran_Dll_FromCS_Test.dll
An unhandled exception of type 'System.DllNotFoundException' occurred in Call_Fortran_Dll_FromCS_Test.dll
Unable to load DLL 'Fortran_DLL_Lib.dll' or one of its dependencies: Access is denied. (0x80070005 (E_ACCESSDENIED))

I have copied both the 'Fortran_DLL_Lib.dll' and 'Fortran_DLL_Lib.lib' files into both the folder that contains the c# project files, as well as the location where the executable project is located, neither seems to help/matter.

This is just based on example code I found trying to find ways to do this and isn't specific to what I'm doing. I'm just trying to get a 'proof of concept' together before jumping into more complex applications. The solution doesn't even necessarily be a DLL, that's just what I saw people recommending as the solution to this (in 7 year old questions on this site). Open to any solutions that successfully call Fortran code from a C# project (eventually, a C# project with a WPF GUI, if that matters).

I am in a situation where I can't install Dependency Walker, change environment variables, or pretty much anything that requires elevated privileges.

Any help would be greatly appreciated!

Update: The very thorough and detailed answer by @JAlex below works perfectly, for both .NET Framework and .NET Core. My ongoing issues are due to user account policies at my workplace that prevent running *.dll files (apparently). Trying the solution on a normal, un-restricted system worked perfectly without issue.

CodePudding user response:

First make sure the dll is next to the C# driver binary, add the dll into the CSharp solution. Use add-existing and then add as link

fig2

then select the link in the solution and set to copy if newer

fig3

this will place the dll in the output folder

fig4

additionally, I set the calling convention in Fortran as CVF, although I think this is optional as I specify explicitly which argument is REFERENCE and which is VALUE.

fig5

I checked the DLL export using dumpbin /exports

fig6

The following code works as indented:

Fortran Project

Note the addition of the VALUE attributes as well as the REFERENCE ones.

module mod_Fortran_dll
    use iso_c_binding
    implicit none
contains
    subroutine adder(a,b,x,y)
        !DEC$ ATTRIBUTES DLLEXPORT, alias:'adder' :: adder
        !DEC$ ATTRIBUTES VALUE :: a,b
        !DEC$ ATTRIBUTES REFERENCE :: x,y
        implicit none
        integer, intent(in) :: a,b
        integer, intent(out) :: x,y
        y = a   b
        x = 2*a 3*b
    end subroutine
end module

CSharp Project

Note the removal of the CDecl calling convention, and the specific EntryPoint specification.

static class Program
{
    #region Fortran
    [DllImport("FortranLib.dll", EntryPoint = "adder")]
    public static extern void adder(int a, int b, [Out] out int x, [Out] out int y);

    #endregion
    static void Main(string[] args)
    {
        int a = 4;
        int b = 3;
        int x = 0;
        int y = 0;

        Console.WriteLine($"a={a}, b={b}, x={x}, y={y}");
        // a = 4, b = 3, x = 0, y = 0

        adder(a, b, out x, out y);

        Console.WriteLine($"a={a}, b={b}, x={x}, y={y}");
        // a = 4, b = 3, x = 17, y = 7
    }
}

Note that the [Out] attribute is required for structure types, but not for primitive types.

  • Related