简体   繁体   中英

Calling Fortran from C# in VS2019 with iFort

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!

a and b are still reference arguments, unless you add the VALUE attribute in their definition in Fortran.

So in C# you need to change your declaration to

public static extern void adder(ref int a, ref int b, out int x, out int y);

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

Also to 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

图2

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

图3

this will place the dll in the output folder

图4

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 .

图5

I checked the DLL export using dumpbin /exports

图6

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
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM