2014-01-09 90 views
2

我有問題與delphi代碼。我想調用delphi中的函數來處理fortran函數,但我已轉移到DLL。這裏是代碼的Fortran如何從delphi中的Fortran DLL調用函數?

SUBROUTINE c_zsn(m,d,k,f,zsn,nf) 

    ! Specify that the routine name is to be made available to callers of the 
    ! DLL and that the external name should not have any prefix or suffix 

    !MS$ ATTRIBUTES DLLEXPORT :: c_zsn 
    !MS$ ATTRIBUTES ALIAS:'c_zsn' :: c_zsn 
    !MS$ ATTRIBUTES VALUE :: m,d,k,nf 
    !MS$ ATTRIBUTES REFERENCE :: f,zsn 
    IMPLICIT NONE 

    INTEGER :: nf,i 
    REAL(KIND(0.D0)) :: m,d,k,f(0:(nf-1)),zsn(0:(nf-1)),om,pi 
    COMPLEX(KIND(0.D0)) :: j 

    j = (0.d0, 1.d0) 
    pi = 4.d0 * datan(1.d0) 

    do i=0,nf-1 
    om = 2.d0*pi*f(i) 
    zsn(i) = abs(-om**2*m-j*om*d+k) 
    end do 

    END SUBROUTINE 

,這裏是爲Delphi代碼,我用

procedure TForm1.Button2Click(Sender: TObject); 
    type tarray=array[0..10]of double; 
    var a:thandle; 
     fcn:function(s,d,f:double;var g,h:tarray;n:integer):double; 
     e,f,d,g,h,i,j:double; 
     k:tarray; 
     l,o:tarray; 
     n,m:integer; 
    begin 
     a:=LoadLibrary('dllsub.dll'); 
     if (A=0) then 
     begin 
     Application.MessageBox('Failed to open library','Error', MB_OK or MB_ICONEXCLAMATION); 
     exit; 
     end; 
     @fcn:=GetProcAddress(a, 'c_zsn'); 
     if @b=nil then 
     begin 
     ShowMessage('Failed to open function'); 
     exit; 
     end; 

     e:=2; 
     f:=200; 
     d:=0.01; 
     n:=10; 
     for m:=0 to n do 
     l[m]:=m; 

     fcn(e,d,f,l,o,n);  // this is the problem 

     FreeLibrary(a); 
    end; 

我不能調用函數(粗體之一)。

+0

C是DLL的「通用語言」。我認爲有很多教程可以爲你的Fortran文件製作C頭文件(* .h)。然後有很多教程如何將C頭文件翻譯成Pascal。 –

+0

@ Arioch'The不需要將接口轉換爲C. –

+0

@DavidHeffernan當然,直接翻譯總是可以比使用中間語「通用語法」更好的結果。但是後者有時候是「足夠好」的,並且還有更多的產品:-)這僅僅是某種意義上的「分而治之」的情況 –

回答

1

我想聲明的功能是這樣的:

procedure c_zsn(
    m: Double; 
    d: Double; 
    k: double; 
    f: PDouble; 
    zsn: PDouble; 
    n: Integer 
); stdcall; external 'dllsub.dll'; 

你需要指定調用約定。您忽略了這意味着您的代碼使用Delphi私有的默認register調用約定。我猜測呼叫約定是stdcall,但它可能是cdecl。檢查編譯器文檔以確保。

而且這對我來說並不是很明顯,爲什麼你聲明瞭一個返回double的函數。 Fortran不這樣做。

除此之外,我更改了參數名稱以匹配Fortran代碼。我也切換到加載時間更容易編碼的鏈接。您可以跳過呼叫LoadLibraryGetProcAddress並讓加載器解析鏈接。

最後,我認爲這兩個數組最好傳遞爲PDouble(即指向Double),而不是在編譯時提交給固定大小的數組。

您可以調用該函數是這樣的:

c_zsn(e,d,f,@l[0],@o[0],n); 

請注意,您已聲明長度爲11的陣列,而不是長度10.您是不是要做到這一點?我認爲你應該這樣聲明數組:

var 
    l, o: array [0..9] of Double; 

最後一點是Fortran代碼非常簡單。把它翻譯成德爾福是非常容易的。