Calling FORTRAN function or subroutine in DLL from C# code

Calling FORTRAN function or subroutine in DLL from C# code

Intel Fortran does not support generate managed code. To call a FORTRAN function or subroutine from C# code you need build Fortran code into a DLL (Dynamic Link Library), and then use Platform Invoke, a service that enables managed code to call the unmanaged function or subroutines inside the DLL. Platform Invoke service locates and calls unmanaged code as an exported function. It also marshals the call's arguments, such as input and output parameters, integers, strings, arrays, and structures, as needed. To use the service, add below line into your C# code:

 

using System.Runtime.InteropServices;

 

It is recommended to wrap the Fortran function or subroutine in a managed class. Within the class, you define a static method for each Fortran function or subroutine you want to call. Use the DllImportAttribute to identify the DLL and function. Mark the method with the static and extern modifiers. The definition can include additional information, such as the calling convention used in passing method arguments.

 

Example:

 

Fortran Function and Subroutine:

 

INTERFACE

    SUBROUTINE FSUB (A,B)

           !DEC$ ATTRIBUTES DLLEXPORT :: FSUB

        INTEGER :: A,B

END SUBROUTINE

 

    FUNCTION FOO(A)

           !DEC$ ATTRIBUTES DLLEXPORT :: FOO

            INTEGER :: A

            INTEGER :: FOO

    END FUNCTION

END INTERFACE

 

C# Wrapper Class:

 

    publicclassFortranDllWrap

    {

        // CallingConvention.Cdecl must be used since the stack is

        // cleaned up by the caller in Intel Fortran by default

        //

        [DllImport("FDll.dll", CallingConvention = CallingConvention.Cdecl)]

        publicstaticexternvoid FSUB(refint A, refint B);

        [DllImport("FDll.dll", CallingConvention = CallingConvention.Cdecl)]

        publicstaticexternint FOO(refint A);

    }   

 

For more complete information about compiler optimizations, see our Optimization Notice.

16 comments

Top
Duan, Xiaoping (Intel)'s picture

The error looks not like a coding error or compiler error. Would you please refer to
http://blogs.msdn.com/b/arvindsh/archive/2009/06/21/tip-of-the-day-an-attempt-was-made-to-load-a-program-with-an-incorrect-format-net-p-invoke-issue.aspx
and check if your Fortran and C# code were built for 32-bit?

anonymous's picture

Please ignore the last. It came about when a 64-bit C# exe attempted to link with a 32-bit Fortran dll.

The current problem comes with attempting to extract data from the 32-bit dll. I am running into memory violations and the stack being wiped out after calls to the dll. Is there a specific need for marshaling the data in order to get data OUT of the dll?

slippery's picture

With the current Fortran compiler, I am having trouble with this example. I code a Fortran SUBROUTINE with the following:

SUBROUTINE DLL1(MOEBIUS, N)

! Expose subroutine Dll1 to users of this DLL
!
!DEC$ ATTRIBUTES DLLEXPORT :: Dll1

! Variables
INTEGER, DIMENSION(N, N) :: MOEBIUS !, INTENT(OUT)
INTEGER :: N !, INTENT(IN)

I code a class in C# as follows:

public class FortranDLLs
{
// Declares a managed prototype for a matrix of integers by value.
[DllImport("<path>/Dll1.dll")]
public static extern void DLL1([In, Out] int[,] pMatrix, ref int N);
}

Inside C#, I attempt to make the following call:

int N = 5;
int[,] myMoebius = new int[ 5, 5 ];
FortranDLLs.DLL1(myMoebius, ref N);

When I hit the call to DLL1 in code, I get the following:

System.BadImageFormatException was unhandled
Message="An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)"
Source="WindowsFormsApplication2"
StackTrace:
at FortranDLLs.Dll1(Int32[,] pMatrix, Int32& N)
...
InnerException:

Is there a compile option or something else I am missing on the Fortran or the C# side?

anonymous's picture

could you please provide the example for calling this DLL code in fortran90

Duan, Xiaoping (Intel)'s picture

Hi Mark,

C# code:
//Example of passing array
[DllImport("FDLL.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern void ARR_SUB([In,Out] float[,] fArr, ref int row, ref int col);

...

float[,] fArr = new float[3, 4];
int row = 3;
int col = 4;

...
// Call the Fortran subroutine

FortranDllWrap.ARR_SUB(fArr, ref row, ref col);

Fortran code:

subroutine Arr_Sub (var,row,col)
!DEC$ ATTRIBUTES DLLEXPORT :: Arr_Sub
integer :: row,col
real var(col,row)
integer :: i, j

write(*,*) "Array var received from C# as array is"

write(*,*) var

! do something to change the value of var

end subroutine

Please note that in above example Fortran subroutine uses an implicit interface allowing the array argument to be passed without an Intel Fortran descriptor so the array parameter declaration in C# is a simple array. In some case Intel Fortran subroutine may require an array descriptor. In such case you should correctly interpret the array descriptor in C# so that Intel Fortran subroutine can obtain the information it needs. More information about Intel Fortran descriptor and how to handle it between Intel Fortran and non-Fortran code can be found under topic "Handling Arrays and Fortran Array Descriptors" of Intel Fortran Compiler documentation.

anonymous's picture

Could you please provide an example where pass an array from C# to Fortran and then back to C# again.

Following your example, I tried to get this working, but could not do. The array returned rubbish in Fortran.

However, If I removed the ref attribute from the C# methods, it appeared to work ok, which I do not understand.

Please advise

Pages

Add a Comment

Have a technical question? Visit our forums. Have site or software product issues? Contact support.