2011-11-08 4 views
3

P/Invokeを使用して文字列を返すVB.NetコードからC++関数を呼び出そうとしていますが、1文字のみを返しています。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 

私はDLLIMPORTにCharSet:=CharSet.Ansiを追加しました。あなたのC++コードはUnicode文字を使用していませんが、VBはおそらくそれになるので、おそらくそれを入れる必要はありませんが、これらのことを明示的にするのが好きです。

Stringの代わりにStringBuilderを使用することに注意してください。文字列は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

...私はあなたのアプローチを使用しています....しかし、1つの問題が来ています...バッファの余分なスペースに不均一な文字が来ている...私はアンマネージコードから返されたテキストを表示しています – sachin

関連する問題