21
$\begingroup$

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=DefineDLLFunction["MYADD", "MDLL.dll", "double", {"double", "double"}]
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).
     in Wolfram.NETLink.DynamicDLLNamespace.DLLWrapper1.MYADD(Double , Double).
$\endgroup$
7
  • 3
    $\begingroup$ 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. $\endgroup$ May 11, 2012 at 19:04
  • $\begingroup$ Or even simpler, just specify the full pathname in the second argument. $\endgroup$
    – Ajasja
    May 11, 2012 at 19:28
  • $\begingroup$ @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). $\endgroup$ May 11, 2012 at 19:47
  • $\begingroup$ If I remember right, NetLink can call only C DLL's. $\endgroup$
    – asim
    May 12, 2012 at 4:23
  • 2
    $\begingroup$ @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. $\endgroup$
    – Ajasja
    May 12, 2012 at 19:30

2 Answers 2

27
$\begingroup$

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 gfortran using NETLink:


Advantages of NETLink as compared to Mathlink:

  1. Fortran functions and subroutines can be called using NETLink without writing an 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.
  3. And it seems to me NETLink is faster than Mathlink.

    • 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 .NET/Link 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. 
at Wolfram.NETLink.DynamicDLLNamespace.DLLWrapper...testfunction_(Double[],Double).

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

see also the post here

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

$\endgroup$
8
  • 2
    $\begingroup$ What a wonderful answer! Thank you very much! $\endgroup$ May 17, 2012 at 8:57
  • $\begingroup$ Good answer! BTW (probably you have known this), in practice, we can also put different functions and subroutines together in the same .dll file. $\endgroup$
    – luyuwuli
    Dec 3, 2013 at 2:41
  • $\begingroup$ You are definitely right. You can put whatever number of functions in the same dll. $\endgroup$
    – unstable
    Jan 27, 2014 at 14:40
  • 1
    $\begingroup$ When using a 64 bit gfortran ReinstallNET["Force32Bit" -> True] is not needed. $\endgroup$ Dec 1, 2020 at 22:07
  • 1
    $\begingroup$ @sebhofer Sorry for the late answer for I haven't checked this for a long time... You can use an external tool "DLL export viewer" to see all the functions in a given dll file. $\endgroup$
    – unstable
    Feb 13, 2021 at 14:25
1
$\begingroup$

Using Mono 6.12.0.122 this works in Linux, with Mathematica 13.0.1 :

SetEnvironment["LD_LIBRARY_PATH" -> FileNameJoin[{$InstallationDirectory, "SystemFiles", "Libraries", $SystemID}]];
    SetEnvironment["DISPLAY" -> ":0"];
    Needs["NETLink`"];
    NETLink`InstallNET[];
    path2 = FileNameJoin[{Directory[], "testsubroutine.dll"}];
    TestSubroutine = DefineDLLFunction["testsubroutine_", path2,  "void", {"Double[]", "Double*", "Double[]"}];
    res = MakeNETObject[{0, 0.}, "System.Double[]"];
    TestSubroutine[{1.0, 2.0}, 3.0, res];
    NETObjectToExpression[res]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.