Calling RANDOM_NUMBER in a Fortran DLL

Viewed 142

I want to compile and link a dynamic link library (dll) from a Fortran code using gfortran (mingw - 64bit) in windows. I test generated dlls in Excel 64-bit. I noticed, Excel does not return any result (it returns: #VALUE!) for the below Fortran code:

Function RANDGF()  bind(c)
use ISO_C_BINDING
implicit none
!GCC$ ATTRIBUTES DLLEXPORT :: RANDGF
Double Precision  :: RANDGF
Double Precision  :: A

Call RANDOM_NUMBER(A)
RANDGF = 2.0
END

However, if I comment the Call RANDOM_NUMBER(A) line, the DLL returns the expected result. The command that I use for the compilation is:

gfortran -shared -fpic -o randgf.dll randgf.f90 

Here is my VBA Code in Excel:

Private Declare PtrSafe Function randgf Lib "randgf.dll" () As Double
Public Function gfort_res() As Double
   gfort_res = randgf()
End Function

What should I do in order to call functions like RANDOM_NUMBER in my code, if I want to use them in a DLL?

2 Answers

There are two main issues that leads to Excel to not execute the function:


One of them, is that Excel can't find the DLL file, and this is because, even if the dll file is at the same folder of the excel worksheet, the Excel's process current dir is not the same.

For this issue, there are two possible solutions:

First: At the function declaration, you can put the full path to the DLL file:

Private Declare PtrSafe Function randgf Lib "C:\myexcellib\randfunc\randgf.dll" () As Double

Second: Before calling the function, you can change the current dir to the dll folder:

Private Declare PtrSafe Function randgf Lib "randgf.dll" () As Double
Public Function gfort_res() As Double
   ChDrive "C"
   ChDir "\myexcellib\randfunc"
   gfort_res = randgf()
End Function

The second issue is that Excel can't find the function inside the DLL file.

And for this issue, there are two possible solutions, as well:

First: You can indicate the ordinal number of the funcition as an "alias" at the declare clause (e.g. if the ordinal number is 1):

Private Declare PtrSafe Function RANDFG Lib "randfg.dll" Alias "#1" () As Double

Second: If you are using fortran 2003 or later, you can indicate the binding name that will be exported:

function RANDGF()  bind(c, name="RANDGF")
  use ISO_C_BINDING
  implicit none
  !GCC$ ATTRIBUTES DLLEXPORT :: RANDGF
  Double Precision  :: RANDGF
  Double Precision  :: A

  call RANDOM_NUMBER(A)
end function RANDGF

Important: All of the VBA code should be inside a Module, otherwise it won't work.

I found the reason of this behaviour. Before running my DLL, I had to copy gfortran libraries to my target computer. I simply copied all the lib*.dll files form mingw64\bin directory to windows\system32 folder of my target computer and now the dll works fine and Excel returns the desired result.

Is there any way to automatically load required DLLs from mingw64\bin into my own DLL (randgf.dll) during compilation and linking at my source computer? I want to avoid copying all the lib*.dll files from mingw64\bin.

Related