2010-05-27 70 views
0

調用Fortran DLL我有一個Fortran語言編寫的,我需要從那裏我所有的其他功能都寫VB.NET調用的子程序。我沒有寫fortran,也幾乎不知道fortran。我得到了我的dll函數調用的下面的異常,並不知道如何解決它。我不知道這是否是由於不一致的可變長度?AccessViolationException是未處理的,從VB網

我有我的FORTRAN源,並使用G95編譯器編譯它。我試着用一個標誌來編譯它,它應該強制所有的實數都是32位(-r4)。它讓我感到奇怪,你似乎沒有必要在Fortran中使用之前初始化變量。我認爲它應該是一種脊背語言。

不管怎樣,下面是我得到異常:

System.AccessViolationException是 未處理消息=試圖讀取 或寫入保護內存。這是 通常表示其他內存 已損壞。源= PTPWrapper
堆棧跟蹤: 在PTPWrapper.Module1.pointtopoint(單& IELEVAT,一& IDIST,一& FREQ, 單& HTAMSL,一& DLOSS,一& 雜波) 在PTPWrapper.Module1.Main( )在C:\ Documents和Settings \ SGoldman \我的文檔 \視覺工作室 2010 \項目\ PTPWrapper \ PTPWrapper \ Module1.vb中:行在System.AppDomain._nExecuteAssembly(RuntimeAssembly 組件,字串[] args) 在System.AppDomain.ExecuteAssembly(字符串 assemblyFile,證據 assemblySecurity,字串[] args) 在Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 在System.Threading.ThreadHelper.ThreadStart_Context(對象 狀態) 在系統.Threading.ExecutionContext.Run(的ExecutionContext 的ExecutionContext,ContextCallback 回調,對象的狀態,布爾 ignoreSyncCtx) 在System.Threading.ExecutionContext.Run(的ExecutionContext 的ExecutionContext,ContextCallback 回調,對象狀態) 在System.Threading.ThreadHelper .ThreadStart() 內部例外:這裏

是我的VB函數聲明和函數調用:

Declare Sub pointtopoint Lib "diff5z11.dll" (ByRef IELEVAT As Single, ByRef IDIST As Single, ByRef FREQ As Single, ByRef HTAMSL As Single, ByRef DLOSS As Single, ByRef CLUTTER As Single) 

pointtopoint(elevation(0), distance, freq, height, dlo, clut) 

所有的變量都被定義爲在這裏VB 32位單打。

和這裏的Fortran代碼的前幾行:

subroutine pointtopoint(IELEVAT, IDIST, FREQ, HTAMSL, DLOSS, CLUTTER) 

     real ielevat(*) 
     dimension oblim(2) 

     dd  = 0.1 
     EK  = 1.333   ! Earth curvature (4/3 earth) 
     HR  = 9.1    ! Rcvr Ant ht (m), for 30 feet 
     HRAMSL = IELEVAT(IDIST) + HR 
     DIST = float(idist)*dd 
     FRESMIN = HR + 1.0 
     DLOSS = 0.0 
     TDLOSS = 0.0 
     RDLOSS = 0.0 
     ADJ = 0.0 

任何想法如何,我可以得到電話工作,讓我的數據?謝謝!

回答

1

它看起來像你幾乎在那裏。

首先,我想指出,你可以強制要求的聲明在Fortran和它是鼓勵。要做到子程序聲明後,所以加IMPLICIT NONE:

subroutine pointtopoint(IELEVAT, IDIST, FREQ, HTAMSL, DLOSS, CLUTTER) 
    IMPLICIT NONE 
    [variable declarations] 
    ... 
end subroutine pointtopoint 

這可能是你的情況是個好主意,因爲它看起來像有一些變量類型混淆。如果不使用IMPLICIT NONE,則Fortran編譯器根據變量名稱的第一個字符假設變量類型是什麼。任何以I,J,K,L,M或N開頭的變量都假定爲INTEGER,其他假設爲REAL。所以我看到的第一個問題是IDIST - 你從VB發送一個Single,這可能導致你看到的內存訪問衝突。 由於Single被解釋爲INTEGER並且很可能超出了IELEVAT數組的範圍,因此無論發送什麼數字。

另外,我注意到的另一件事(這可能不是一個錯誤 - 我不能告訴,因爲整個子程序似乎沒有公佈)是子程序接收變量HTAMSL和更高版本使用HRAMSL。這看起來像程序員實際上想要使用HTAMSL的可能的錯字。 HTAMSL和HRAMSL是兩個完全不同的變量。這是另一個不使用IMPLICIT NONE的副作用 - 錯別字會被忽視,最終會出現意想不到的結果。

+0

非常感謝,我將不得不亂與子程序一起,看看我是否無法澄清其中的一些含糊之處。 HTAMSL - 發射機高於平均海平面的高度 HRAMSL - 接收機高於平均海平面的高度 所以至少這不是打破了這一點。我會讓每個人都知道我是否工作。再次感謝。 – 2010-05-27 14:30:40

0

Re「它讓我感到很奇怪,在Fortran中使用之前,您似乎不需要初始化變量。」 - Fortran中需要您在使用它們之前初始化變量。初始化和聲明是不同的。舊FORTRAN經常使用「隱式鍵入」,其中變量是通過名稱的第一個字母隱式輸入的。現代的做法是明確地輸入每個變量,但允許遺留代碼編譯舊方法是允許的。正如@brady已經回答的那樣,您可以通過包含「implicit none」來讓編譯器要求顯式聲明每個變量。大多數編譯器也有相同效果的編譯器選項。

正如@brady寫的,從隱式輸入IDIST是一個整數,並被用作數組索引。 IELEVAT應該足夠大以適應您傳遞的IDIST的價值。如果這還不足以使其發揮作用,則可以使用Fortran 95編譯器中廣泛使用的Fortran 2003的ISO C Binding來更好地控制調用。這將告訴Fortran使用子程序的C調用約定,這更符合VB的期望。你可以控制參數傳遞是通過值還是通過引用。

喜歡的東西:

subroutine pointtopoint (IELEVAT, IDIST, FREQ, HTAMSL, DLOSS, CLUTTER) bind (C, name="pointtopoint") 

implicit none ! optional 
real (c_float), dimension (*) :: IELEVAT 
integer (c_int) :: IDIST 
real (c_float) :: FREQ, HTAMSL, DLOSS, CLUTTER 

的gfortran手冊中有一些文檔:http://gcc.gnu.org/onlinedocs/gfortran/Mixed_002dLanguage-Programming.html對於MS Windows,您可能需要延長調用約定之間進行選擇:http://gcc.gnu.org/onlinedocs/gfortran/GNU-Fortran-Compiler-Directives.html#GNU-Fortran-Compiler-Directives