# How can I deploy DLL files created by a Fortran function and call them from Mathematica

This is my Fortran function, established by Intel visual Fortran 11.1

FUNCTION MYADD(X,Y)
!DEC$ATTRIBUTES DLLEXPORT::MYADD REAL(8) X,Y,MYADD MYADD=X+Y end FUNCTION  A corresponding .dll file is created,MDLL.dll (64bit version) and I put this file in the $Path directory.

In a Mathematica notebook, I input:

Needs["NETLink"]
fun[1.0,2.0]


But it gives me an error:

 NET::netexcptn: A .NET exception occurred: System.DllNotFoundException:
unable to load DLL"MDLL.dll": can not find corresponding module
(error form HRESULT:0x8007007E).

-
It may mean that your dll can't be found. Try adding the directory where you store it, to the PATH environmental variable, and see if that helps. You will have to reboot or at least log off your machine after changing PATH, to see the effect. –  Leonid Shifrin May 11 '12 at 19:04
Or even simpler, just specify the full pathname in the second argument. –  Ajasja May 11 '12 at 19:28
@Ajasja This won't work if the dll in question is loaded not directly but from some other dll (which may or may not be the case, I don't know). –  Leonid Shifrin May 11 '12 at 19:47
If I remember right, NetLink can call only C DLL's. –  asim May 12 '12 at 4:23
@asim No, a DLL is a DLL, it does not matter which program produced it. The calling convention may need to be specified, but most are cdecl or stdcall anyway. –  Ajasja May 12 '12 at 19:30

Even the path is corrected, it still cannot run, since the argument type should {"double*", "double*"}. Here is my memo on calling dll created by gortran using NETLink:

1. FORTRAN functions and subroutines can be called using .NET/Link without writing additional C wrapper which is necessary in Mathlink.
2. NETLink can access all the functions and subroutines in the FORTRAN code by calling the dll file, not only one.

• Calling a FORTRAN function

Suppose we have a fortran code testfunction.f90

REAL(8) FUNCTION testfunction(x,y)
REAL(8), DIMENSION(2) :: x
REAL(8) :: y
testfunction = (x(1)+x(2)) * y
END FUNCTION


We can compile it and build a dll

gfortran -c testfunction.f90
gfortran -shared -mrtd -o testfunction.dll testfunction.o


Now the function testfunction(x,y) in testfunction.dll can be called after loading the NETLink package

Needs["NETLink"]
ReinstallNET["Force32Bit" -> True]; (* or InstallNET["Force32Bit"->True] *)

(* set to the directory of the notebook, and the dll file is in the same dir *)
SetDirectory[NotebookDirectory[]];
path = FileNameJoin[{Directory[], "testfunction.dll"}];
TestFunction = DefineDLLFunction["testfunction_", path, "double", {"double[]", "double*"}];


TestFunction[{1.0, 2.0}, 3.0] gives the correct result 9.0.

Explanations:

DefineDLLFunction: the first argument is the function name to be called. It has changed from testfunction to testfunction_, and might be TESTFUNCTION or other depending on the fortran compiler. path is the complete path to the dll file. "double" is the return type. The last argument contains the types of the arguments. Note the presence of [] for an array and * for others. If * is missing, there will be an error message saying

NET::netexcptn: A .NET exception occurred:
System.AccessViolationException: Attempted to read or write protected memory.
This is often an indication that other memory is corrupt.


If [] is missing or written as * by mistake, the error message is

NET::methodargs: Improper arguments supplied for method named testfunction_."


Before making revisions to the dll file, one should use ReinstallNET["Force32Bit" -> True] to quit and restart the .NET runtime

• Calling a FORTRAN subroutine

testsubroutine.f90

SUBROUTINE testsubroutine(x,y,z)
REAL(8), DIMENSION(2), INTENT(in) :: x
REAL(8), INTENT(in) :: y
REAL(8), DIMENSION(2), INTENT(out) :: z
z(1) = x(1) * y
z(2) = x(2) * y
RETURN
END SUBROUTINE


testsubroutine.dll can be built as before. In Mathematica, after loading NETLink and ReinstallNET["Force32Bit" -> True],

path2 = FileNameJoin[{Directory[], "testsubroutine.dll"}]
TestSubroutine = DefineDLLFunction["testsubroutine_", path2, "void",
{"Double[]", "Double*", "Double[]"}]


Now we should create a .NET object, which is to be sent to testsubroutine_ at the place of z to store the results

(* Any real or integer numbers can be put in the list.
"System.Double[]" is necessary if any of the numbers is an integer. *)
res = MakeNETObject[{0, 0.}, "System.Double[]"]


Now let's test a case:

TestSubroutine[{1., 2.}, 3., res] (* res receives the calculated results *)

(* translate the .NET object results into a Mathematica expression  *)
NETObjectToExpression[res]


The results are the desired {3., 6.}.

-
What a wonderful answer! Thank you very much! –  Guanghui HE May 17 '12 at 8:57
Good answer! BTW (probably you have known this), in practice, we can also put different functions and subroutines together in the same .dll file. –  luyuwuli Dec 3 '13 at 2:41
You are definitely right. You can put whatever number of functions in the same dll. –  unstable Jan 27 at 14:40