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

发布于 2024-09-03 08:25:10 字数 2140 浏览 3 评论 0原文

我有一个用 Fortran 编写的子例程,我需要从 VB.NET 调用该子例程,其中编写了所有其他函数。我没写过fortran,也几乎不懂fortran。我在 dll 函数调用中遇到以下异常,但不知道如何修复它。我想知道这是否是由于变量长度不一致造成的?

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

无论如何,下面是我得到的异常:

System.AccessViolationException 是 未处理的消息=尝试读取 或写保护内存。这是 通常表明其他记忆 是腐败的。来源=PTPWrapper
堆栈跟踪: 在 PTPWrapper.Module1.pointtopoint(Single& IELEVAT,单人& IDIST,单身&频率, 单& HTAMSL,单& DLOSS,单一& 杂乱) 在 C:\Documents and Settings\SGoldman\my 中的 PTPWrapper.Module1.Main() 文件\视觉工作室 2010\项目\PTPWrapper\PTPWrapper\Module1.vb:行 18 在 System.AppDomain._nExecuteAssembly(RuntimeAssembly 程序集,String[] args) 在 System.AppDomain.ExecuteAssembly(字符串 汇编文件、证据 assemblySecurity,String[] args) 在 Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 在 System.Threading.ThreadHelper.ThreadStart_Context(对象 状态) 在 System.Threading.ExecutionContext.Run(ExecutionContext 执行上下文、上下文回调 回调、对象状态、布尔值 忽略SyncCtx) 在 System.Threading.ExecutionContext.Run(ExecutionContext 执行上下文、上下文回调 回调,对象状态) 在 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

有什么想法可以让调用正常工作并取回我的数据吗?谢谢!

I have a subroutine that was written in fortran that I need to call from VB.NET where all of my other functions are written. I did not write the fortran, and hardly know fortran. I am getting the below exception on my dll function call and don't know how to fix it. I wonder if it is due to incongruent variable lengths?

I have the source for my fortran and compiled it using the g95 compiler. I have tried compiling it with a flag on which is supposed to force all of the reals to 32 bits (-r4). It weirds me out that you don't seem to be required to initialize variables before use in fortran. I thought it was supposed to be a ridged language.

Anyway, below is the exception I am getting:

System.AccessViolationException was
unhandled Message=Attempted to read
or write protected memory. This is
often an indication that other memory
is corrupt. Source=PTPWrapper
StackTrace:
at PTPWrapper.Module1.pointtopoint(Single&
IELEVAT, Single& IDIST, Single& FREQ,
Single& HTAMSL, Single& DLOSS, Single&
CLUTTER)
at PTPWrapper.Module1.Main() in C:\Documents and Settings\SGoldman\my
documents\visual studio
2010\Projects\PTPWrapper\PTPWrapper\Module1.vb:line
18
at System.AppDomain._nExecuteAssembly(RuntimeAssembly
assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String
assemblyFile, Evidence
assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object
state)
at System.Threading.ExecutionContext.Run(ExecutionContext
executionContext, ContextCallback
callback, Object state, Boolean
ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext
executionContext, ContextCallback
callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:

here is my VB function declaration and function call:

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)

all of the variables are defined as 32-bit singles here in VB.

and here are the first few lines of the fortran code:

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

any ideas how i can get the call to work and get my data back? Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦里人 2024-09-10 08:25:10

看来你已经快到了。

首先,我想指出您可以在 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,这可能会导致您看到的内存访问冲突。 无论发送的数字是什么,都会被解释为 INTEGER,并且很可能超出 IELEVAT 数组的范围。

此外,我注意到的另一件事(这可能不是错误 -我无法判断,因为整个子例程似乎没有发布)是子例程接收变量 HTAMSL,然后使用 HRAMSL。这看起来可能是一个拼写错误,程序员实际上想使用 HTAMSL。 HTAMSL 和 HRAMSL 是两个完全不同的变量。这是不使用 IMPLICIT NONE 的另一个副作用 - 拼写错误会被忽视,最终会得到意想不到的结果。

It looks like you are almost there.

First, I want to point out you can force required declarations in Fortran and it is encouraged. To do so add IMPLICIT NONE after the Subroutine declaration:

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

This may be a good idea in your case because it looks like there is some variable type confusion. If IMPLICIT NONE is not used the Fortran compiler makes assumptions as to what the variable type is by the first character of the variable name. Any variable that begins with an I, J, K, L, M, or N is assumed to be INTEGER and all else is assumed REAL. So the first problem I see is IDIST - you are sending a Single from VB and this probable causing the memory access violation you are seeing. Whatever number is being sent as the Single is being interpreted as an INTEGER and is most likely out of the bounds of the IELEVAT array.

Also, one other thing I notice (and this may not be an error - I can't tell because the whole subroutine doesn't appear to be posted) is that the subroutine receives the variable HTAMSL and later on uses HRAMSL. This looks like a possible typo where the programmer actually wanted to used HTAMSL. HTAMSL and HRAMSL are two completely different variables. This is another side effect of not using IMPLICIT NONE - typos go unnoticed and you'll end up with unexpected results.

俏︾媚 2024-09-10 08:25:10

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

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

Re " It weirds me out that you don't seem to be required to initialize variables before use in fortran." -- you are required in Fortran to initialize variables before using them. Initializing and declaring are different. Old FORTRAN frequently used "implicit typing", in which the variables were implicitly typed by the first letter of their name. Modern practice is to explicitly type each variable, but to allow legacy code to compile the old method is permitted. As already answered by @brady, you can cause the compiler to require explicit declarations of each variable by including "implicit none". Most compilers also have a compiler option for the same effect.

As @brady wrote, from implicit typing IDIST is an integer, and being used as an array index. IELEVAT should be large enough for the value of IDIST that you are passing. If this isn't enough to make it work, you can get more control over the calling using the ISO C Binding of Fortran 2003, which is widely available in Fortran 95 compilers. This will tell Fortran to use the C calling conventions for the subroutine, which are more likely to match the expectations of VB. And you can control whether the argument passing is by value or by reference.

Something like:

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

The gfortran manual has some documentation: http://gcc.gnu.org/onlinedocs/gfortran/Mixed_002dLanguage-Programming.html For MS Windows, you might need an extension to select between calling conventions: http://gcc.gnu.org/onlinedocs/gfortran/GNU-Fortran-Compiler-Directives.html#GNU-Fortran-Compiler-Directives

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文