How to use loadlibrary and getprocaddress from gfortran?

你离开我真会死。 提交于 2020-01-01 20:27:25

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!