Calling C dll from Fortran - dll

How to call C DLL from Fortran? I don't code in Fortran but I need to do some testing on it.
Let say in the test.dll have functions:
Open()
Close()
How can I tell Fortran to use the test.dll?
I mean like C# we may use
[DllImport("test.dll")]
static extern uint Open();
I could not find any example that can help me. I would also prefer if you could provide a compiler that you use.
Update
I use Plato compiler.
I tried to load test.dll using this method. However, it popped up error message saying Error 29, Call to missing routine: _LOADLIBRARY
Here is the code. I found it online. So not sure if I'm doing it correctly.
program test
integer :: p
pointer :: q
p = loadlibrary ("test.dll"C) ! the C at the end says -
! add a null byte as in C
q = getprocaddress (p, "Open"C)
end
EDIT
Sorry. The DLL is using C and not C++

Related

Compaq Visual Fortran 6.6, Dynamic-Link Library (DLL) and Module

I need to create and use dynamic-link library (DLL) for Fortran application using Compaq Visual Fortran 6.6. The following code works just fine:
PROGRAM AMAIN1
IMPLICIT NONE
REAL(8):: A,B,S
A = 1D0
B = 2D0
CALL SUBRO1(A,B,S)
PRINT*, 'S = ', S
END PROGRAM AMAIN1
SUBROUTINE SUBRO1(A,B,S)
!DEC$ ATTRIBUTES DLLEXPORT :: SUBRO1
IMPLICIT NONE
REAL(8):: A,B,S
S = A + B
RETURN
END SUBROUTINE SUBRO1
The result is correct:
S = 3.00000000000000
Press any key to continue
However, if I implement the same algorithm using the module, I get inconsistent result (i.e. zero):
PROGRAM AMAIN2
USE MODUL2
A = 1D0
B = 2D0
CALL SUBRO2
PRINT*, 'S = ', S
END PROGRAM AMAIN2
MODULE MODUL2
IMPLICIT NONE
REAL(8):: A,B,S
END MODULE MODUL2
SUBROUTINE SUBRO2
!DEC$ ATTRIBUTES DLLEXPORT :: SUBRO2
USE MODUL2
S = A + B
RETURN
END SUBROUTINE SUBRO2
The result is incorrect:
S = 0.000000000000000E+000
Press any key to continue
As can be seen above, DLL contains only subprogram in both cases (SUBRO1 and SUBRO2, respectively). I have built DLL and LIB files from the visual development environment. The second case (with the use of module) represents the structure of my large source-code so I need to resolve this issue. Any advice would be greatly appreciated.
BTW, the same algorithm without using the DLL works well and gives correct result:
PROGRAM AMAIN3
USE MODUL3
A = 1D0
B = 2D0
CALL SUBRO3
PRINT*, 'S = ', S
END PROGRAM AMAIN3
MODULE MODUL3
IMPLICIT NONE
REAL(8):: A,B,S
END MODULE MODUL3
SUBROUTINE SUBRO3
USE MODUL3
S = A + B
RETURN
END SUBROUTINE SUBRO3
The result is correct:
S = 3.00000000000000
Press any key to continue
You need to add:
!DEC$ ATTRIBUTES DLLEXPORT :: A,B,S
to the module, so that the main program can see the module variables from the DLL. Otherwise A, B and S are local variables.
Edit: January 16, 2019
I was able to log in to Bakhbergen's PC and eventually figured out the problem.
In CVF 6.6C (and the later Intel compilers), when you USE a module that has a DLLEXPORT directive, that turns into a DLLIMPORT, hence my advice above. But it wasn't always this way, and the version he has doesn't have that behavior. Before that change (which my memory says I lobbied for), you had to supply a separately compiled .mod where the source had DLLIMPORT instead of DLLEXPORT. When I did this, the program worked. I don't remember exactly which update had this change.
So what he needs to do is have two versions of MODUL2.f90, one with DLLEXPORT and one with DLLIMPORT. The DLLEXPORT version gets built into the DLL. The DLLIMPORT version would just be compiled (/c) and only the .mod used, not the ,obj, when linking the main program. Messy, I know, which is why we changed it.

Using C++ DLL in VB6 app

I am following the guide on: https://msdn.microsoft.com/en-us/library/ms235636.aspx
I have created a DLL as it was stated above and now i want to include it in my VB6 app
I have declared a function in the code:
Private Declare Function Add Lib "C:\WINDOWS\system32\Win32Project1.dll" (ByVal a As Double, ByVal b As Double)
In the form load I have declared some variables and called a function
Dim a As Double
Dim b As Integer
a = 7.4
b = 99
Call Add(a, b)
Each time I run program I get an error that file not found.
File is present in C:\WINDOWS\system32\ and I did try to register dll using:
regsvr32 Win32Project1.dll
But I keep getting error:
LoadLibrary("Win32Project1.dll") failed - The specified module could not be found.
How can this be resolved?
Update:
I have looked further into the issue, please refer to step 2 of "Martin Schlott" answer, and it happens that VC++ encodes DLL functions and because of that i would have a funny name of ever function within DLL.
Using dumpbin.exe, which can be found in the $\Visual Studio\VC\bin, i was able to read the function names that are stored in the DLL. This is what I would get originally:
1 0 00001050 ?Add#MyMathFuncs#MathFuncs##SANNN#Z = ?Add#MyMathFuncs
#MathFuncs##SANNN#Z (public: static double __cdecl MathFuncs::MyMathFuncs::Add(d
ouble,double))
"?Add#MyMathFuncs#MathFuncs##SANNN#Z" - is what I would have to call as a function in VB6 for things to work... and it wouldn't... so I had to decode the name which is done by creating a definition file (.def) within C++ DLL app
In the new Source.def file I have defined that I want to have "Add" function:
LIBRARY
EXPORTS
Add
After rebuilding solution in the "Release" mode dumpbin gave me a much better result. However, __cdecl is automatically added to every function in VC++, unless specified otherways, and it happens that __cdecl doesn't allow function to be used in the VB6. If you run VB6 app right now you would receive a new error "Bad DLL calling convention".
For this to be resolved I had to amend "MyMathFuncs.h" file where I have defined functions to export and change
"static MATHFUNCSDLL_API double Add(double a, double b);"
to
"static MATHFUNCSDLL_API double __stdcall Add(double a, double b);"
After that dumpbin.exe returned much nicer values:
1 3 00001050 Add
This however haven't resolved my problem fully, I would still get "Bad DLL calling convention" and it was due to how I have referenced library in the VB6
Private Declare Function Add Lib "Win32Project1.dll" (ByVal a As Double, ByVal b As Double)
The function "Add" returns a double and in the abovee declaration I declare that values should be pushed and no return given. So I have followed the function format that I have in C++ and added a return with a correct data type that matches the data type in C++ file:
Private Declare Function Add Lib "Win32Project1.dll" (ByVal a As Double, ByVal b As Double) As Double
Now when I run:
Dim a As Double
Dim b As Integer
a = 7.4
b = 99
MsgBox (Add(a, b))
I have a message box stating that result is 106.4!
There are several points wrong in that what you are doing. Funny thing is,nevertheless it should work.
If you specify a DLL directly, you do not need to register it with regsvr32.
Read:
https://msdn.microsoft.com/en-us/library/aa716201(v=vs.60).aspx
resvr32 expect special exported functions to COM Conform register the DLL in the registry. A COM able DLL can be used via for e.g. with CoCreateInstance not with your declare.
If you didn't know this, regsvr is failing.
Also do not copy DLL belonging to your Project into the system32 folder. It do not belong there and it is bad behavior nowadays. For disk memory reasons it was maybe necessary centuries ago, but not today.
Copy the DLL in the same folder where the VB program is. Correct the path to
Private Declare Function Add Lib "Win32Project1.dll" (ByVal a As Double, ByVal b As Double)
and as someone already suggest, use dependency walker. If a dll starting with "MS" is missing. Read my following answer:
https://stackoverflow.com/a/18600033/1922748
to install the proper redist.
UPDATE
You wrote you are missing the "MSVCR120D.DLL". This happens if you compiled the DLL in debug mode, not release mode. You cannot install the MSVCR120D.DLL without the Visual Studio. You need to compile your DLL in release mode and install the redist.
2. Second Update
Regarding to your last comment, the entry point is missing.
You have to export the function! Add
__declspec(dllexport)
before the function you want to export. Look here
https://msdn.microsoft.com/de-de/library/3y1sfaz2.aspx
Your declaration in C++ should look like:
__declspec(dllexport) double Add(double val);
You can forget about dllimport, you do not need that in your case.

Fortran subroutine called from Objective-C

I am calling a fortran subroutine from a cocoa application.
The application is building with success and working as expected but I have this semantic issue : *
Implicit declaration of function "_increment" is invalid in C99
increment.o is the compiled fortran subroutine (gfortran compiler)
subroutine increment(n)
integer :: n
n=n+1
end subroutine increment
What am I doing wrong ?
Thank you for your help.
You have to declare the type of the function. Something like:
void increment_(int * i);
(In C, but I assume it is the same and I am guessing the correct signature, you do not show its code).
BTW, I recommend the Fortran subroutine as bind(C) or even bind(C,name="increment") and you do not have to use the trailing _.
Edit: try this
in the .m file:
void increment(int * i);
int the .f90 file:
subroutine increment(n) bind(C,name="increment")
use iso_c_binding
integer(c_int),intent(inout) :: n
n = n+1
end subroutine
If it does not help, try to use a debugger, or try some debugging print statements in the subroutine if loc(n) is equal to &i or whatever.

Linking fortran module: "undefined reference"

I'm trying to write some functions/subroutines in a module that call another function in the same module and running into linker errors. A toy example displaying the same behavior:
!in test.f
module m1
implicit none
contains
real function mult(a, b)
real :: a
real :: b
mult = a * b
return
end function mult
real function sq(a)
real :: a, mult
sq = mult(a, a)
return
end function sq
end module m1
program main
use m1
write(*,*) sq(2.0)
end program
When I try to compile this, I run into trouble:
[christopher#archlinux metropolis]$ gfortran -ffree-form test.f
/tmp/ccpzdTLE.o: In function `__m1_MOD_sq':
test.f:(.text+0x20): undefined reference to `mult_'
collect2: error: ld returned 1 exit status
On the other hand, compiling only (gfortran -c -ffree-form test.f -Wall) runs with no complaint.
Now this looks for all the world like a compiler error---in the module it comes up with a reference to mult_ when it really ought to com up with __m1_MOD_sq---but I have a very hard time believing that this is a compiler bug rather than me doing something stupid.
DDG didn't turn up anything useful. Most of the similar problems ocurred in splitting the module off from one main file. In those cases, things worked when the module was in the same file as the program, which is not the case here. I looked at a number of pages on modules in Fortran and didn't see anything relevant.
Can anyone point me to appropriate documentation or, better yet, explain what's going on and how I can fix it?
You don't need to declare function mult in function sq, i.e., there is no need for "real :: mult". sq already "knows" about mult since it is in the same module. The interface of mult is known to sq since they are in the same module. The interface of mult and sq are known to the main program since it uses the module. Having both the module providing the interface and the declaration is confusing the compiler.

Possible to Pass an Object as a Parameter to a Fortran Method?

I'm currently working on being able to import a DLL written in Fortran into Visual Basic. I've got all the basics down, so now I'm trying to take it a step further. The title basically says it all, but I'll explain what it is I'm trying to do anyways.
For kicks and giggles, let's just assume I want to pass an object that has three double values in it, possibly representing a point in space in three dimensions. In my Fortran method, I want to take that object, print out the x value, then change the x value to 7.5. Here's my Fortran code that does just that.
module test
type Point
double precision x, y, z
end type Point
end module test
function ex1(ThreeDubs)
use test
type (Point) :: ThreeDubs
print *, ThreeDubs%x
ex1 = 1
return
end function
And this code works great!...For structures only. In other words, Let's assume I have the following structure and class in VB
Public Structure StructurePoint
Public x As Double
Public y As Double
Public z As Double
End Structure
Public Class ObjectPoint
Public x As Double
Public y As Double
Public z As Double
End Class
Creating an instance of StructurePoint yields perfect results: the Fortran method prints out the x value, and then modifies the value of x. Perfect. Now the problem. When I pass an instance of ObjectPoint, the program prints out a value similar to 1.523E-306. Basically, telling me that the location in which it thinks the x value is located is not the x value. So, herein lies my question. Is it even possible to pass an Object to a Fortran DLL and access it correctly, and if so, how would I go about doing so?
The Solution
Modifying the Class declaration is the ONLY thing that has to be done in order to pass this object to Fortran.
<StructLayout(LayoutKind.Sequential)> _
Public Class CustomPoint3d
Public x As Double
Public y As Double
Public z As Double
End Class
<DllImport("passPoint3d.dll")> _
Public Shared Function PrintX(ByVal point As CustomPoint3d) As Boolean
End Function
This might be difficult, and I don't think there's any benefit, so I advise you not to bother!
Here goes anyway! I think the VB.Net object will be marshalled as a pointer. There is some support for pointers in Fortran 90. It might work if you add pointer to the Fortran declaration of ThreeDubs.
function ex1(ThreeDubs)
use test
type (Point), pointer :: ThreeDubs ! Note additional pointer keyword
print *, ThreeDubs%x
ex1 = 1
return
end function
I doubt you would ever be able to call methods in the ThreeDubs object from the Fortran, so I'm not sure of the benefit of passing an object.
Here are two articles on PInvoke: PInvoke is the .Net name for calling oldschool "unmanaged" DLLs like your Fortran. The articles explain how .Net arguments are "marshalled" (translated) into the Fortran DLL. You have some control over the marshalling using attributes: the articles explain more. They tend to use C and C# for examples :(
I don't know about Visual Basic, but I've shared user-defined types between Fortran & C. This is supported by the ISO C Binding of Fortran 2003, which is already widely supported by Fortran 95 compilers. You declare a Fortran user-defined type and give it the bind C attribute and a bind name. As long as all of the sub-components of the type are inter-operable with C, then the user-defined type is also inter-operable with C. And this method is standard and portable. I've done this by passing the information with the Fortran user-defined type variable being a module variable, and the C structure variable being in global memory via being declared at the top of a file. Perhaps you can use the ISO C Binding on the Fortran side, and somehow tell Visual Basic to use a C-like interface?