2017-03-08 78 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'調用約定。 –