2013-01-04 38 views
0

我試圖學習如何從Fortran可執行文件在Windows中調用fortran dll中的函數。我在eclipse中使用gfortran 4.7和photran。如何使用gfortran的loadlibrary和getprocaddress?

我的測試DLL在hello.f90單一功能:

hello.f90

subroutine hello 
    implicit none 
    print *, "Hello World!" 
end subroutine hello 

與下面的Makefile:

all: 
    gfortran -Wall -c hello.f90 
    gfortran -shared -o hello.dll hello.o 

的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 

的makefile

all: 
    gfortran -Wall -pedantic -fcray-pointer main.f90 

錯誤消息是那個函數LoadLibrary(和getprocaddress)沒有IMPLICIT類型。我懷疑這意味着這些函數沒有定義,我需要以某種方式包含它們的頭文件。是對的嗎?我發現在C調用LoadLibrary聲明:\ MinGW的\包括\ WINBASE.H

歡呼聲,

馬克

+0

我不再使用Windows,所以我不是100%確定,但不應該在「hello.dll」和「hello_」之後有一個'char(0)'使它結束行?? –

回答

4

LoadLibrary和GetProcAddress的是Windows API的程序。與任何非內在函數一樣,您需要聲明這些函數的類型,並且鑑於這些API的性質,還需要進一步提供完整的接口。

如果您正在編譯32位Windows,那麼這些API使用stdcall調用約定。你需要使用gfortran源代碼指令擴展來指定。

(在64位Windows STDCALL被定義爲同C調用約定 - 源指令沒有任何效果。)

對於調用約定的控制,如果我改變你的DLL的代碼:

SUBROUTINE hello() BIND(C, NAME='hello') 
    IMPLICIT NONE 
    PRINT *, 'Hello' 
END SUBROUTINE hello 

然後下面的主程序將加載生成的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 
+0

還必須鏈接DLL的靜態導入庫('.lib')。 –

+0

@HristoIliev你指的是哪個DLL? – IanH

+0

包含「GetProcAddressA」和「LoadLibraryA」的文件,即'kernel32.dll'。該代碼必須與Win32 SDK中的'kernel32.lib'鏈接。 –