AccessViolationException未处理,从vb net调用fortran dll

时间:2010-05-27 13:44:20

标签: vb.net fortran

我有一个用fortran编写的子程序,我需要从VB.NET调用其中编写所有其他函数。我没有写过fortran,也几乎不知道fortran。我在我的dll函数调用上得到以下异常,并且不知道如何修复它。我想知道是否是由于不一致的变长?

我有我的fortran的源代码并使用g95编译器编译它。我已经尝试用一个标志来编译它,该标志应该强制所有的实数为32位(-r4)。令我觉得奇怪的是,在fortran中使用之前似乎不需要初始化变量。我以为它应该是一种山脊语言。

无论如何,下面是我得到的例外:

  

System.AccessViolationException是   未处理的消息=尝试阅读   或写保护的内存。这是   经常表明其他记忆   腐败的。来源= PTPWrapper
  堆栈跟踪:          在PTPWrapper.Module1.pointtopoint(Single&   IELEVAT,Single& IDIST,Single& FREQ,   单&安培; HTAMSL,Single& DLOSS,Single&   杂波)          在C:\ Documents and Settings \ SGoldman \ my中的PTPWrapper.Module1.Main()   文件\视觉工作室   2010 \项目\ PTPWrapper \ PTPWrapper \ Module1.vb中:行   18          在System.AppDomain._nExecuteAssembly(RuntimeAssembly   assembly,String [] args)          在System.AppDomain.ExecuteAssembly(String   assemblyFile,Evidence   assemblySecurity,String [] args)          在Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()          在System.Threading.ThreadHelper.ThreadStart_Context(Object   州)          在System.Threading.ExecutionContext.Run(ExecutionContext   executionContext,ContextCallback   回调,对象状态,布尔值   ignoreSyncCtx)          在System.Threading.ExecutionContext.Run(ExecutionContext   executionContext,ContextCallback   回调,对象状态)          在System.Threading.ThreadHelper.ThreadStart()   的InnerException:

这是我的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

我是如何获得工作电话并获取数据的任何想法?谢谢!

2 个答案:

答案 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的另一个副作用 - 拼写错误被忽视,你最终会得到意想不到的结果。

答案 1 :(得分:0)

重新说“我很奇怪你在使用fortran之前似乎不需要初始化变量。” - 在使用它们之前,Fortran需要初始化变量。初始化和声明是不同的。旧FORTRAN经常使用“隐式类型”,其中变量由其名称的第一个字母隐式输入。现代实践是显式键入每个变量,但允许遗留代码编译旧方法。正如@brady已经回答的那样,您可以通过包含“implicit none”来使编译器要求对每个变量进行显式声明。大多数编译器也有相同效果的编译器选项。

正如@brady所写,从隐式类型开始,IDIST是一个整数,并被用作数组索引。 IELEVAT应该足够大,以便您传递的IDIST值。如果这还不足以使其工作,您可以使用Fortran 2003的ISO C绑定来更好地控制调用,Fortran 2003在Fortran 95编译器中广泛使用。这将告诉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