2017-03-08 90 views
1
DLL

我试图调用在C++从vb.net DLL函数,但我遇到了以下错误:内存损坏调用C++从VB.NET

Managed Debugging Assistant 'PInvokeStackImbalance' has detected a problem in 'D:...\calling_project_in_VB.vshost.exe'.

Additional information: A call to PInvoke function 'calling_project_in_VB! calling_project_in_VB.Module1::add' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.

我希望有人可能精通这些东西来发现我要去哪里错了?我会很感激任何建议,到目前为止,Google帮助我确定问题的实质并非毫无用处。下面是我试图运行小型可重复的例子:

的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; 
} 

这里是VB函数试图调用C(其中“。 ..”是我的机器上的路径):

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 
+1

为什么地球上你想要通过INT指针只是增加他们(你*不*引用无论如何需要这些)。 – crashmstr

+0

@crashmstr这只是一个小的可重复的例子,我希望能够成为一个更复杂的问题的前兆,其中0填充的向量将被传入c代码,填充并返回到VB。如果你有一个小例子,如果你能分享它,我会非常感激。 – user2256085

+0

我不知道这是否有帮助,但可以尝试添加['<[In]()>'属性](https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.inattribute(v = vs.110).aspx)转换为'ByRef'参数,以防止Marshaler将该值复制回来。 – TnTinMn

回答

1

默认呼吁DllImportAttribte惯例被列为:

The default value for the CallingConvention field is Winapi, which in turn defaults to StdCall convention.

不过对于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 
+0

我刚才建议他会使用StdCall,虽然两者都可以。 :) –

+0

@VisualVincent,我很好奇你在编辑中改变了什么?我的眼睛很累,但我看到的是代码块被删除然后放回去。 – TnTinMn

+0

这是一个隐形代码标签。我在你的第一个代码块上添加了<! - language-all:vb.net - >'。它会发生变化,以便您的所有代码块都使用VB.NET的语法高亮显示。 –

1

几乎任何在C的指针++等于在.NET世界IntPtr,因此你的参数应该是那种类型的。然而,正如crashmstr所说,如果只是将两个数字加在一起,为什么你甚至需要它们首先成为指针呢?

<DllImport("D:\...\called_c.dll", EntryPoint:="add", ExactSpelling:=False)> 
Public Function add(ByVal a As IntPtr, ByVal b As IntPtr) As Integer 
End Function 

还要注意,参数应为ByVal通过,因为C++函数目前不包括预计通过引用传递的参数。

用例:

Dim Result As Integer = add(New IntPtr(3), New IntPtr(6)) 
MessageBox.Show(Result) 'Should display "9". 
+0

采纳你的建议改变了错误信息,这样看起来像是进步。而不是得到我原来的问题中引用的PInvoke错误,现在我得到:“处理异常的类型'System.AccessViolationException'发生在calling_project_in_VB.exe 附加信息:试图读取或写入受保护的内存。表示其他内存已损坏。“ – user2256085

+0

@ user2256085:这通常是您在C++代码中出现问题时得到的结果。参数应该是'IntPtr'类型,所以我宁愿认为你在C++部分中缺少某些东西。尝试在'__declspec(dllexport)'之前/之后添加'__stdcall'调用约定。 –