如何使用gfortran的loadlibrary和getprocaddress? [英] How to use loadlibrary and getprocaddress from gfortran?
问题描述
我试图学习如何从Fortran可执行文件在Windows上调用fortran dll中的函数。我在Eclipse中使用gfortran 4.7和photran。
我的测试dll在hello.f90中有一个函数:
hello.f90
子程序hello
隐式无
打印*,Hello World!
结束子程序hello
包含以下makefile:
全部:
gfortran -Wall -c hello.f90
gfortran -shared -o hello.dll hello.o
code>
Dependency Walker确认导出了函数hello_。
现在我试图建立一个动态调用它的程序。我已经根据我在网上找到的例子构建了以下内容,但它不能编译:
程式主
隐式无
整型:: p
指针(q,hello)
p = loadlibrary(hello.dll)
q = getprocaddress(p,hello_)
调用hello
结束程序main
makefile
all:
gfortran -Wall -pedantic -fcray-pointer main.f90
错误消息是该函数LoadLibrary(和getprocaddress)没有IMPLICIT类型。我怀疑这意味着这些函数没有定义,我需要以某种方式包含它们的头文件。是对的吗?我发现在c:\\\\\\\\\\\\\\\\\\\\\\\\\\'\\\\\\\\\\\\\\\\\\ b
Marc
LoadLibrary和GetProcAddress是Windows API例程。与任何非内在函数一样,您需要声明这些函数的类型,并且鉴于这些API的性质,还需要进一步提供完整的接口。
如果您正在编译32位Windows,那么这些API使用stdcall调用约定。您需要使用gfortran源代码指令扩展来指定。
(在64位Windows上,stdcall被定义为与C调用约定相同 - source指令没有效果。)
对于调用约定控制,如果我将您的DLL代码更改为:
SUBROUTINE hello()BIND(C,NAME ='hello')
IMPLICIT NONE
PRINT *,'Hello'
END SUBROUTINE hello
然后下面的主程序将加载生成的DLL并执行该过程。
程序主
USE,INTRINSIC :: ISO_C_BINDING,ONLY:&
C_F_PROCPOINTER,C_FUNPTR,C_INTPTR_T,&
C_NULL_CHAR,C_CHAR,C_ASSOCIATED
IMPLICIT NONE
$ b INTERFACE
功能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
隐NONE
!GCC $ ATTRIBUTES STDCALL :: GetProcAddress的
型(C_FUNPTR):: GetProcAddress的
INTEGER(C_INTPTR_T),VALUE :: hModule
CHARACTER(KIND = C_CHAR):: lpProcName(*)
END FUNCTION GetProcAddress
END 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'无法加载DLL'
proc_address = GetProcAddress(module_handle,&
C_CHAR_'hello'// C_NULL_CHAR)
IF(.NOT。C_ASSOCIATED(proc_address))&
STOP'无法获得程序地址'
CALL C_F_PROCPOINTER(proc_address,my_proc)
CALL my_proc
END PROGRAMM
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
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
这篇关于如何使用gfortran的loadlibrary和getprocaddress?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!