问题
I'm trying to learn how to call a function in a fortran dll from a fortran executable on windows. I'm working with gfortran 4.7 and photran in eclipse.
My test dll has a single function in hello.f90:
hello.f90
subroutine hello
implicit none
print *, "Hello World!"
end subroutine hello
with the following makefile:
all:
gfortran -Wall -c hello.f90
gfortran -shared -o hello.dll hello.o
Dependency Walker confirms that the function "hello_" is exported.
Now I'm trying to build a program that calls it dynamically. I've built the following based on examples I've found online, but it doesn't compile:
main.f90
program main
implicit none
integer :: p
pointer (q, hello)
p = loadlibrary("hello.dll")
q = getprocaddress(p, "hello_")
call hello
end program main
makefile
all:
gfortran -Wall -pedantic -fcray-pointer main.f90
The error message is that function LoadLibrary (and getprocaddress) has no IMPLICIT type. I suspect that means those functions aren't defined and I need to include their headers somehow. Is that right? I've found a declaration for loadlibrary in c:\mingw\include\winbase.h
cheers,
Marc
回答1:
LoadLibrary and GetProcAddress are Windows API routines. Like any non-intrinsic function, you need to declare the type of those functions and, given the nature of those API's, you also need to go further and provide the full interface.
If you are compiling for 32 bit Windows then those API's use the stdcall calling convention. You need to use gfortran source directive extensions to designate that.
(On 64 bit Windows stdcall is defined to be the same as the C calling convention - the source directive has no effect.)
For calling convention control, if I change your DLL code to:
SUBROUTINE hello() BIND(C, NAME='hello')
IMPLICIT NONE
PRINT *, 'Hello'
END SUBROUTINE hello
then the following main program will load the resulting DLL and execute that procedure.
PROGRAM Main
USE, INTRINSIC :: ISO_C_BINDING, ONLY: &
C_F_PROCPOINTER, C_FUNPTR, C_INTPTR_T, &
C_NULL_CHAR, C_CHAR, C_ASSOCIATED
IMPLICIT NONE
INTERFACE
FUNCTION LoadLibrary(lpFileName) BIND(C,NAME='LoadLibraryA')
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_INTPTR_T, C_CHAR
IMPLICIT NONE
CHARACTER(KIND=C_CHAR) :: lpFileName(*)
!GCC$ ATTRIBUTES STDCALL :: LoadLibrary
INTEGER(C_INTPTR_T) :: LoadLibrary
END FUNCTION LoadLibrary
FUNCTION GetProcAddress(hModule, lpProcName) &
BIND(C, NAME='GetProcAddress')
USE, INTRINSIC :: ISO_C_BINDING, ONLY: &
C_FUNPTR, C_INTPTR_T, C_CHAR
IMPLICIT NONE
!GCC$ ATTRIBUTES STDCALL :: GetProcAddress
TYPE(C_FUNPTR) :: GetProcAddress
INTEGER(C_INTPTR_T), VALUE :: hModule
CHARACTER(KIND=C_CHAR) :: lpProcName(*)
END FUNCTION GetProcAddress
END INTERFACE
ABSTRACT INTERFACE
SUBROUTINE hello_intf() BIND(C)
IMPLICIT NONE
END SUBROUTINE hello_intf
END INTERFACE
INTEGER(C_INTPTR_T) :: module_handle
TYPE(C_FUNPTR) :: proc_address
PROCEDURE(hello_intf), BIND(C), POINTER :: my_proc
!****
module_handle = LoadLibrary(C_CHAR_'hello.dll' // C_NULL_CHAR)
IF (module_handle == 0) STOP 'Unable to load DLL'
proc_address = GetProcAddress( module_handle, &
C_CHAR_'hello' // C_NULL_CHAR )
IF (.NOT. C_ASSOCIATED(proc_address)) &
STOP 'Unable to obtain procedure address'
CALL C_F_PROCPOINTER(proc_address, my_proc)
CALL my_proc
END PROGRAM Main
来源:https://stackoverflow.com/questions/14165801/how-to-use-loadlibrary-and-getprocaddress-from-gfortran