我正在尝试学习如何从 Windows 上的 fortran 可执行文件调用 fortran dll 中的函数。我正在 Eclipse 中使用 gfortran 4.7 和 photran。
我的测试 dll 在 hello.f90 中有一个函数:
你好.f90
subroutine hello
implicit none
print *, "Hello World!"
end subroutine hello
Run Code Online (Sandbox Code Playgroud)
使用以下生成文件:
all:
gfortran -Wall -c hello.f90
gfortran -shared -o hello.dll hello.o
Run Code Online (Sandbox Code Playgroud)
Dependency Walker 确认已导出函数“hello_”。
现在我正在尝试构建一个动态调用它的程序。我根据在网上找到的示例构建了以下内容,但无法编译:
main.f90
program main
implicit none
integer :: p
pointer (q, hello)
p = loadlibrary("hello.dll")
q = getprocaddress(p, "hello_")
call hello
end program main
Run Code Online (Sandbox Code Playgroud)
生成文件
all:
gfortran -Wall -pedantic -fcray-pointer main.f90
Run Code Online (Sandbox Code Playgroud)
错误消息是函数 LoadLibrary(和 getprocaddress)没有 IMPLICIT 类型。我怀疑这意味着这些函数没有定义,我需要以某种方式包含它们的标题。那正确吗?我在 c:\mingw\include\winbase.h 中找到了 loadlibrary 的声明
干杯,
马克
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
Run Code Online (Sandbox Code Playgroud)
然后下面的主程序将加载生成的 DLL 并执行该过程。
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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4311 次 |
| 最近记录: |