2011-11-08 81 views
3

我想從VB.Net代碼中調用C++函數,它返回使用P/Invoke的字符串,但它只返回單個字符。從C++函數返回字符串到VB .net

C函數聲明

extern "C" __declspec(dllexport) LPSTR Get_GetDescription(HANDLE) 

C函數定義

LPSTR Get_GetDescription(HANDLE resultBreakDown){ 
    return LPSTR(((CalcBreakDown*)resultBreakDown)->GetDescription().c_str()); 
} 

VB.Net代碼

<DllImport("FeeEngineDll.dll", CallingConvention:=CallingConvention.Cdecl)> _ 
    Public Shared Function Get_GetDescription(ByVal resultBreakDown As IntPtr, ByVal indexSubs As Integer, ByVal indexLine As Integer) As <MarshalAsAttribute(LPStr)> String 
    End Function 

返回類型或編組有沒有問題?

+1

兩者。 C++代碼基本上被破壞,它返回一個懸掛指針。此外,這是Vista和Win7中的硬件崩潰,作爲函數返回返回的字符串緩衝區必須使用CoTaskMemAlloc()進行分配。 –

回答

4
extern "C" __declspec(dllexport) LPSTR Get_GetDescription(HANDLE) 

返回像這樣的指針是相當危險的,因爲不清楚誰擁有內存,因此誰應該負責釋放它。

這將是更安全的在你的VB代碼來創建緩衝區,並將其傳遞到其中值可以在memcpy'ed的DLL所以,我們可以把C++方面,如:。

extern "C" __declspec(dllexport) void Get_GetDescription(HANDLE, LPSTR) 

void Get_GetDescription(HANDLE resultBreakDown, LPSTR buffer){ 
    memcpy(buffer, 
      ((CalcBreakDown*)resultBreakDown)->GetDescription().c_str(), 
      ((CalcBreakDown*)resultBreakDown)->GetDescription().length()+1); 
} 

然後重做VB代碼如下:

<DllImport("FeeEngineDll.dll", CharSet:=CharSet.Ansi, CallingConvention:=CallingConvention.Cdecl)> _ 
Public Shared Sub Get_GetDescription(ByVal resultBreakDown As IntPtr, <MarshalAs(UnmanagedType.LPStr)> ByVal szFilename As StringBuilder) 
End Sub 

我已經加入CharSet:=CharSet.Ansi到的DllImport。你的C++代碼不使用Unicode字符,而VB可能會,所以最好指定,你可能不需要把它放入,但我喜歡明確這些東西。

注意使用StringBuilder而不是String,因爲字符串在VB中是不可變的。最後,你需要小心在你的字符串生成器分配足夠的空間描述:

Dim buffer As StringBuilder = New StringBuilder(512) 

您可以通過在你的VB代碼使用了大量的,做到這一點,我剛纔做。但是,如果您的C++代碼複製的字符多於您分配的字符數,則會導致問題。

其他更好的選擇是將緩衝區大小傳遞給C++代碼,以便知道它允許寫入多少,或者在C++代碼中具有get size函數以用於確定應該爲緩衝區分配很多空間。

+0

..非常感謝您對問題的深入瞭解...我還可以在非託管C++中編寫代碼,以釋放內存給eg.Void FreeUmanagedString(void * p){delete [] p;} .....並從我的VB.Net代碼調用此函數....這種方法更好,或者您在答案中提到的方法更好。 – sachin

+0

我仍然非常喜歡我概述的方法。正如Hans在他對這個問題的評論中指出的那樣,在DLL中分配內存並在其他地方使用它還有其他潛在的缺陷。 –

+0

...我用過你的方法....但是有一個問題來了......不均勻的字符進入緩衝區的額外空間....當我顯示從非託管代碼返回的文本 – sachin