вернуть строку из функции c ++ в VB .Net - PullRequest
3 голосов
/ 08 ноября 2011

Я пытаюсь вызвать функцию C ++ из кода VB.Net, который возвращает строку, используя P / Invoke, но возвращает только один символ.

Объявление функции 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 Ответ

4 голосов
/ 08 ноября 2011
extern "C" __declspec(dllexport) LPSTR Get_GetDescription(HANDLE)

Возвращать такой указатель довольно опасно, так как неясно, кто владеет памятью и, следовательно, кто должен нести ответственность за ее освобождение.

Было бы безопаснее создать буфер в вашемVB-код и передать его в DLL, где значение может быть записано в memcpy. Таким образом, мы можем переписать сторону 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 ++ не использует символы Юникода, тогда как VB, вероятно, будет, поэтому лучше указать, что вам, вероятно, не нужно его вставлять, но я хотел бы сделать эти вещи явными.

Обратите внимание на использование StringBuilder вместо String, поскольку строки неизменяемы в VB.Наконец, вам нужно быть осторожным, чтобы выделить достаточно места в строителе строк для описания:

Dim buffer As StringBuilder = New StringBuilder(512)

Вы можете сделать это, используя большое число в своем VB-коде, как я только что сделал.Это, однако, вызовет проблемы, если ваш код C ++ когда-либо скопирует больше символов, чем выделено.

Другими лучшими вариантами будет либо передача размера буфера в код C ++, чтобы он знал, сколько ему разрешенонаписать или иметь функцию get size в коде C ++, которая может использоваться для определения того, сколько места должно быть выделено для буфера.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...