内存损坏从VB.NET调用C ++ DLL

时间:2017-03-08 20:41:43

标签: c++ vb.net

我试图从vb.net调用C ++ dll中的函数,但遇到以下错误:

  

托管调试助手' PInvokeStackImbalance'已在“D:... \ calling_project_in_VB.vshost.exe'”中检测到问题。

     

附加信息:调用PInvoke函数' calling_project_in_VB!   calling_project_in_VB.Module1 ::添加'堆栈不平衡。这很可能是因为托管PInvoke签名与非托管目标签名不匹配。检查PInvoke签名的调用约定和参数是否与目标非托管签名匹配。

我希望有人能够熟悉这些东西,找出我出错的地方?我很感激任何建议,到目前为止谷歌一直没有效果,帮助我找出问题所在。以下是我尝试运行的小型可重现示例:

C ++的设置如下:

called_c.h:

extern "C"  __declspec( dllexport ) 
                   int add(int* a, int* b); 

called_c.cpp:

#include "stdafx.h"
#include "called_c.h"
#include <string>

using namespace std;
// using namespace System;

int add(int* a, int* b)
{
    int Aa = *a;
    int Bb = *b;

    return Aa + Bb;
}

这是试图调用C的VB函数(其中&#34; ...&#34;是我机器上的路径):

Imports System.Runtime.InteropServices
Imports System

Module Module1

    'Public Class called_c
      <DllImport("D:\...\called_c.dll", EntryPoint:="add", ExactSpelling:=False)>
    Public Function add(ByRef a As Int32, ByRef b As Int32) As Int32
    End Function

    'End Class

    Sub Main()

        Dim val1 As Int32
        Dim val2 As Int32
        Dim answer As Int32

        val1 = 3
        val2 = 4

        answer = add(val1, val2)

        MsgBox(answer)

    End Sub

End Module

2 个答案:

答案 0 :(得分:1)

在.NET世界中,几乎所有C ++中的指针都等于IntPtr,因此您的参数应该属于该类型。但是,正如crashmstr所说,如果你只是在一起添加两个数字,为​​什么你甚至需要它们作为指针?

ByVal

另请注意,参数应作为Dim Result As Integer = add(New IntPtr(3), New IntPtr(6)) MessageBox.Show(Result) 'Should display "9". 传递,因为C ++函数当前不包含预期通过引用传递的参数。

用法示例:

id     | year     | amount
-------+----------+--------
1      | 2016     | 4000
1      | 2017     | 3000
2      | 2016     | 12000
2      | 2017     | 15000
3      | 2016     | 100
3      | 2017     | 200

答案 1 :(得分:1)

DllImportAttribte的默认调用约定列为:

  

CallingConvention字段的默认值是Winapi,后者默认为StdCall约定。

但是,C ++程序的默认值为__cdecl

您的C ++代码似乎使用此默认值而未指定替代项,因此VB签名应为:

<DllImport("D:\...\called_c.dll", EntryPoint:="add", ExactSpelling:=False, CallingConvention:=CallingConvention.Cdecl)>
Public Function add(ByRef a As Int32, ByRef b As Int32) As Int32
End Function

或者,您可能希望将InAttribute添加到参数中,以防止由互操作封送程序复制值。

<DllImport("D:\...\called_c.dll", EntryPoint:="add", ExactSpelling:=False, CallingConvention:=CallingConvention.Cdecl)>
Public Function add(<[In]()> ByRef a As Int32, <[In]()> ByRef b As Int32) As Int32
End Function