Передача данных из динамически подключаемой библиотеки (DLL), написанной на C++, в программу на Delphi может быть непростой задачей, особенно когда речь идет о передаче указателей на данные. В данном случае рассматривается ситуация, когда необходимо сохранить данные в DLL и передать в Delphi программу ссылку на эти данные и их размер.
Проблема
Разработчик столкнулся с проблемой, при которой не удавалось получить доступ к данным, передаваемым из C++ DLL в Delphi программу. В C++ DLL была реализована функция, которая должна была вернуть ссылку на строку и её длину. Однако, в Delphi коде, который явно загружал DLL и вызывал эту функцию, данные не были доступны.
Исходный код
Код C++ DLL функции выглядел следующим образом:
void __stdcall exportClass::getDataReference(char* data, int* bufferLength)
{
charArray = "Pass this Array of Char By Reference";
data = charArray;
bufferLength = sizeof(charArray) / sizeof(charArray[0]);
}
В Delphi коде для вызова функции был использован следующий подход:
procedure callDllFunction();
var
dynamicCharArray : array of AnsiChar;
pData: PAnsiChar;
length: Integer;
pInt: ^Integer;
begin
pData := @dynamicCharArray[0];
length := 10;
pInt := @length;
explicitDllLoaderClass.callGetDataReference(pData, pInt);
SetLength(dynamicCharArray, length);
end;
Анализ проблемы
В приведенном коде есть несколько ошибок:
В C++ коде параметр data передается по значению, что означает, что изменения, внесенные в этой переменной внутри функции, не будут доступны вызывающему коду. Необходимо передать параметр по ссылке или указателю.
В C++ коде используется sizeof(charArray) для определения длины строки, что некорректно, так как sizeof возвращает размер массива в памяти, а не фактическую длину строки.
В Delphi коде массив dynamicCharArray выделяется после вызова функции, что приводит к потере данных.
В Delphi коде не учитывается, что C++ функция является методом класса, и не создается объект класса для вызова этого метода.
Подтвержденное решение
Для корректной работы необходимо:
Передать параметры data и bufferLength по ссылке в C++ функции.
В C++ коде использовать функцию strlen для определения длины строки.
В Delphi коде выделить память для массива перед вызовом функции.
В Delphi коде учитывать, что C++ функция является методом класса, и создать объект класса для вызова этого метода.
Альтернативное решение
В качестве альтернативы можно экспортировать из DLL функцию на C, которая будет копировать данные в переданный буфер или возвращать указатель на данные.
Пример C++ кода для DLL:
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved )
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
extern "C" __declspec(dllexport) void __stdcall getDataReference(char* data, int* bufferLength)
{
char charArray[] = "Pass this Array of Char By Reference";
if ((data == NULL) || (bufferLength == NULL) || (*bufferLength <= 0))
return;
strncpy(data, charArray, *bufferLength);
*bufferLength = strlen(charArray);
}
Пример Delphi кода для использования DLL:
program CallMyDll;
{$APPTYPE CONSOLE}
{$R *.res}
uses
Winapi.Windows,
System.SysUtils;
type
TGetDataReference = procedure (var Data: PAnsiChar; var BufferLength: PInteger); stdcall;
var
DllHandle: THandle;
GetDataReference: TGetDataReference;
...
begin
...
GetDataReference := GetProcAddress(DllHandle, '_getDataReference@8');
...
procedure callDllFunction();
var
DynamicCharArray: array of AnsiChar;
DataLength: Integer;
S: String;
begin
DataLength := 1000;
SetLength(DynamicCharArray, DataLength);
GetDataReference(PAnsiChar(DynamicCharArray), @DataLength);
SetLength(DynamicCharArray, DataLength);
S := String(PAnsiChar(DynamicCharArray));
WriteLn(S);
end;
end.
Заключение
При передаче данных из C++ DLL в Delphi программу важно учитывать особенности работы с указателями и передачу параметров по ссылке. Обеспечение корректной работы с памятью и использование правильных функций для работы со строками позволит избежать типичных ошибок и успешно решить поставленную задачу.
Разработчик сталкивается с трудностями при передаче данных из динамически подключаемой библиотеки (DLL), написанной на C++, в программу на Delphi, особенно с передачей указателей на данные и их размер.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.