VB.NET调用Fortran:如何修复PInvoke异常?

时间:2017-03-12 15:56:05

标签: vb.net fortran

在编写VB调用fortran的简单示例时,我会根据我尝试采用的方法获得两个错误。虽然下面的小型可重复示例很简单,但它是更大问题的前兆。

这个简单示例的主要目标是调整传递给Fortran代码的参数的值(在本例中为" SUMMATION"),然后使用VB中返回的(和调整的)值。

我首先提供简单的fortran代码,然后显示用于调用它的VB代码的两种变体以及每种方法产生的错误消息。

VB调用的Fortran代码:

SUBROUTINE MFNWT_RUN(KSTP,KPER,SUMMATION) 

    !DEC$ ATTRIBUTES DLLEXPORT :: MFNWT_RUN
    !DEC$ ATTRIBUTES ALIAS: "MFNWT_RUN" :: MFNWT_RUN

    IMPLICIT NONE

    INTEGER, Intent(in) :: KPER, KSTP
    INTEGER, Intent(inout) :: SUMMATION

    INTEGER kkper, kkstp
    INTEGER add_em_up

    kkper = KPER
    kkstp = KSTP

    add_em_up = kkper + kkstp

    SUMMATION = add_em_up 

END SUBROUTINE

调用VB代码(第一种方法):

Imports System.Collections
Imports System
Imports System.Runtime.InteropServices
Imports System.IO
Imports System.Data

Module Module1

    <DllImport("example_fortran_directory.dll", CallingConvention:=CallingConvention.StdCall)>
    Public Function MFNWT_RUN(ByVal a As Integer, ByVal b As Integer, ByRef Divs As Integer)  'ref bool AdvFlwRdr
    End Function

    ' Private Declare Sub MFNWT_RUN Lib "example_fortran_directory.dll" Alias "MFNWT_RUN" (<[In](), Out()> ByRef A As Integer, ByRef B As Integer, ByRef C As Integer)
    'Declare Sub MFNWT_RUN Lib "example_fortran_directory" (ByRef A As Integer, ByRef B As Integer, ByRef C As Integer)

    Sub Main()
        Dim first As Integer
        Dim second As Integer

        Dim answer As Integer

        first = 6
        second = 7
        answer = 0
        Call MFNWT_RUN(first, second, answer)

        MsgBox(answer)

    End Sub

End Module

给出错误:

enter image description here

如果相反,我会尝试“&#39;连线”&#39;对Fortran DLL的调用有点不同(注释掉DllImport代码并取消注释声明代码),我得到了一个不同的错误。

调用VB代码(第二种方法):

Imports System.Collections
Imports System
Imports System.Runtime.InteropServices
Imports System.IO
Imports System.Data

Module Module1

    ' Private Declare Sub MFNWT_RUN Lib "example_fortran_directory.dll" Alias "MFNWT_RUN" (<[In](), Out()> ByRef A As Integer, ByRef B As Integer, ByRef C As Integer)
    Declare Sub MFNWT_RUN Lib "example_fortran_directory" (ByRef A As Integer, ByRef B As Integer, ByRef C As Integer)

    Sub Main()
        Dim first As Integer
        Dim second As Integer

        Dim answer As Integer

        first = 6
        second = 7
        answer = 0
        Call MFNWT_RUN(first, second, answer)

        MsgBox(answer)

    End Sub

End Module

给出以下例外:

enter image description here

第二种方法有效 - 这意味着如果我承认错误我可以通过它,但如果有人可以指示我如何操作,我宁愿修复潜在的问题?我想要解决的更大问题是从VB进行数千次对Fortran的调用,因此以正确的方式修复堆栈不平衡错误似乎是至关重要的(而不仅仅是关闭警告消息)。

追加另一个也导致PInvokeStackImbalance错误的尝试。

首先是fortran:

   SUBROUTINE MFNWT_RUN(KSTP,KPER,SUMMATION)

    !DEC$ ATTRIBUTES DLLEXPORT, ALIAS: 'MFNWT_RUN' :: MFNWT_RUN
    !DEC$ ATTRIBUTES REFERENCE :: KSTP
    !DEC$ ATTRIBUTES REFERENCE :: KPER
    !DEC$ ATTRIBUTES REFERENCE :: SUMMATION

    IMPLICIT NONE

    INTEGER, value :: KPER, KSTP
    INTEGER, value :: SUMMATION

    INTEGER kkper, kkstp
    INTEGER add_em_up

    kkper = KPER
    kkstp = KSTP

    add_em_up = kkper + kkstp

    SUMMATION = add_em_up 

END SUBROUTINE MFNWT_RUN

调用VB:

Imports System.Collections
Imports System
Imports System.Runtime.InteropServices
Imports System.IO
Imports System.Data

Module Module1

Private Declare Sub MFNWT_RUN Lib "example_fortran_directory.dll" Alias "MFNWT_RUN" (<[In](), Out()> ByRef A As Integer, ByRef B As Integer, ByRef C As Integer)

Sub Main()
    Dim first As Integer
    Dim second As Integer

    Dim answer As Integer

    first = 6
    second = 7
    answer = 0
    Call MFNWT_RUN(first, second, answer)

    MsgBox(answer)

End Sub

End Module

此方法也在抛出PInvokeStackImbalance异常时结束。首先,我想知道这个异常是否是一个大问题(也就是说,我应该简单地取消选中它 - 这意味着代码应该继续运行而不会在抛出此异常时对我产生热情)?如果它是应该修复的东西(我会认为是这种情况),你看到我的问题是什么,请帮助。

1 个答案:

答案 0 :(得分:0)

使用以下方法找到解决方案:

<DllImport("example_fortran_directory.dll", CallingConvention:=CallingConvention.Cdecl)>
Public Sub MFNWT_RUN(ByRef a As Integer, ByRef b As Integer, ByRef c As Integer)  
End Sub

以前我有Public Function...而不是Public Sub...

我从来没有能够采用其他方法:

Private Declare Sub MFNWT_RUN Lib "example_fortran_directory.dll" Alias "MFNWT_RUN" (<[In](), Out()> ByRef A As Integer, ByRef B As Integer, ByRef C As Integer)