如何使用gfortran的loadlibrary和getprocaddress? [英] How to use loadlibrary and getprocaddress from gfortran?

查看:323
本文介绍了如何使用gfortran的loadlibrary和getprocaddress?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图学习如何从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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆