Вопрос, поставленный пользователем, касается взаимодействия между библиотекой, созданной в среде Delphi 2007, и приложениями на Visual Basic 6 и Visual Basic 2010. Основная проблема заключается в передаче строковых данных из Delphi DLL в Visual Basic приложение и освобождении памяти, выделенной через функцию GetMem в Delphi.
Описание проблемы
В коде Visual Basic используется декларация функции из DLL:
Declare Function TstCharReturn Lib "myLib" Alias "TstCharReturn" (ByVal c As System.Text.StringBuilder) As Boolean
И вызов этой функции:
Private Sub Button1_Click(ByVal sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim s As String
Dim builder As New System.Text.StringBuilder
Dim r As Boolean
r = TstCharReturn(builder)
LogIt(s) ' Предполагается, что строка из builder должна быть передана сюда'
LogIt(r)
End Sub
Автор вопроса получил рекомендацию использовать System.Text.StringBuilder вместо String, так как строки в .NET не изменяемы, но обе структуры данных работают аналогично.
В коде Delphi DLL функция выглядит так:
Function TstCharReturn(var c: pChar): Boolean; stdcall;
var
BuffSize: Integer;
sOut: string;
begin
sOut:='abcdefghijklmnoprst';
BuffSize:=SizeOf(Char) * (Length(sOut) + 1);
GetMem(c, BuffSize);
FillChar(c^, BuffSize, 0);
Result := Length(sOut) > 0;
if Result then
begin
Move(sOut[1], PChar(c)^, BuffSize);
end;
end;
Автор вопроса получает "мусор" в выводе Visual Basic. Он также задает вопрос о необходимости освобождения памяти, выделенной функцией GetMem, и о различиях между Visual Basic 6 и 2010, поскольку DLL должна работать с обоими версиями.
Подтвержденный ответ
Проблема заключается в неправильной реализации функции TstCharReturn в Delphi. Вместо выделения новой памяти для возвращаемой строки, необходимо использовать уже существующий буфер, переданный в параметре c. Также необходимо передать размер этого буфера в качестве дополнительного параметра функции.
Исправленный код Visual Basic будет выглядеть так:
Declare Function TstCharReturn Lib "myLib" Alias "TstCharReturn" _
(ByVal c As System.Text.StringBuilder, ByVal cchSize As Integer) As Boolean
И вызов функции с указанием начальной емкости буфера:
Dim sb As New System.Text.StringBuilder(50) ' Начальная емкость буфера: 50
TstCharReturn(sb, sb.Capacity)
Код Delphi также должен быть изменен:
Function TstCharReturn(const c: pChar; cchSize: Integer): Boolean; stdcall;
var
sOut: string;
begin
sOut:='abcdefghijklmnoprst';
if Length(sOut) <= cchSize then
begin
Move(sOut[1], c, Length(sOut));
Result := True;
end
else
begin
Result := False;
end;
end;
Альтернативный ответ
При вызове неmanaged кода из .NET, StringBuilder не будет автоматически передан как буфер, способный принять произвольное количество данных. Необходимо убедиться, что начальная емкость буфера достаточна для возвращаемых данных.
Также, в Delphi процедуре с var ожидается указатель на указатель на char, а в декларации Visual Basic — указатель на char. Удаление var из объявления функции в Delphi позволяет процедуре ожидать указатель на char. Это изменение позволяет записывать данные в область памяти, на которую указывает c.
При использовании P/Invoke важно явно указать, что StringBuilder должен быть маршалирован как ANSI, а не Unicode, используя атрибут MarshalAs(UnmanagedType.LPStr) или установив свойство Charset декларации DLL в Charset.Ansi.
По умолчанию P/Invoke использует ANSI кодировку для строковых параметров, но это может быть платформо-зависимо, поэтому следует быть внимательным при работе с кросс-платформенными вызовами.
Комментарии
Пользователь отмечает, что после внесения рекомендуемых изменений код работает корректно, но остается вопрос о причинах возникновения проблемы и ресурсах для более глубокого понимания работы с указателями и памятью.
Рекомендуется обратиться к ресурсам, посвященным работе с указателями в C++ для лучшего понимания этих концепций.
Заключение
Работа с памятью в DLL на Delphi 2007 для приложений на Visual Basic 6 и Visual Basic 2010 требует особого внимания к деталям, таким как управление памятью, передача строковых данных и правильное использование указателей. Следуя рекомендациям и правильно настроив взаимодействие между языками и средами, можно добиться корректной работы кроссплатформенных приложений.
Вопрос связан с передачей строковых данных из библиотеки, созданной в среде Delphi 2007, в приложения на Visual Basic 6 и Visual Basic 2010, с особым вниманием к управлению памятью и использованию указателей.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.