How to use loadlibrary and getprocaddress from gfortran?

老子叫甜甜 提交于 2019-12-04 21:49:35

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