====== Передача строк в библиотеку dll, и получение результата в Delphi ======
Знаю очень многие топорничают при работе со строками в Delphi, вот решил выложить пример как на всамом деле передаються PChar между библиотекой .dll и исполняемым файлом .exe
** Код самой библиотеки :**
library Project1;
{$R *.res}
uses System.SysUtils, System.Classes, Winapi.Windows;
// Паскальная версия функция, то с чем обычно работаем.
function HelloWorldP(Param1: string): string;
begin
if Param1 = 'hello' then
Result := 'Hello World!'
else
Result := 'Say `hello` for me!';
end;
// WinAPI Exports PWideСhar версия функци
function HelloWorldW(Param1: PWideChar; lpBuffer: PWideChar; nSize: Integer): Integer; stdcall;
var
sBuffer : string;
iBuffSz : Integer;
iCopySz : Integer;
begin
sBuffer := HelloWorldP(StrPas(Param1)); // Получаем строку
iBuffSz := Length(sBuffer) * sizeof(Char); // Получаем длинну строки
if nSize < iBuffSz then
iCopySz := iBuffSz // Если размера буффера хватает, то всё суппер копируем всю строку
else
iCopySz := iBuffSz; // Если не хватает, то копируем не более чем длинна буффера
try
CopyMemory(lpBuffer, PWideChar(sBuffer), iCopySz); // Копируем в буффер, из строки, байт
Result := iBuffSz; // Результат, реальная длинна строки которую залили в буффер
except
Result := -1; // Обезательно обрабатываем ошибки, например буффера не было, а nSize дали
end;
end;
exports // Таблица экспортов
HelloWorldW name 'HelloWorldW';
begin {-} end.
**А теперь код маленькой программки которая вызывает этот код:**
program Project2;
{$R *.res}
uses System.SysUtils, Winapi.Windows;
const DLL_FILE_PATH = 'project1.dll';
function HelloWorldW(Param1: PWideChar; lpBuffer: PWideChar; nSize: Integer): Integer; stdcall;
external DLL_FILE_PATH name 'HelloWorldW';
var
sDllQuestion : WideString;
lpBuffer : PWideChar;
nBufferSz : Integer;
nRetnSz : Integer;
sLibrarySays : WideString;
begin
// Спрашиваем сказать привет `hello`?
if MessageBox(0, 'Say `hello` for dll?', 'Hello dll test', MB_ICONQUESTION or MB_YESNO ) = ID_YES then
sDllQuestion := 'hello'
else
sDllQuestion := 'i have no question';
nBufferSz := 1024; // Размер буффера 1024 байта
lpBuffer := AllocMem(nBufferSz); // Занять у Windows 1024 пайта памяти
try
// Сделать запрос
// Параметр 1 : Сам возпрос
// Параметр 2 : Выделенная у нас память
// Параметр 3 : Сколько памяти для помещения строки
nRetnSz := HelloWorldW(PWideChar(sDllQuestion), lpBuffer, nBufferSz);
// Если результат -1, то произошла херня
if nRetnSz = -1 then
raise Exception.Create('Something wrong with params for dll')
// Если размера буффера не хватило
else if nRetnSz > nBufferSz then
begin
FreeMem(lpBuffer, nBufferSz); // Освобождаем память
nBufferSz := nRetnSz + 2; // Берём длинну строки + 1 Буква (sizeof(WideChar) == 2)
lpBuffer := AllocMem(nBufferSz); // Заготавливаем буффер
// Второй раз спрашиваем у dll строку, но размер буффера мы уже увеличили до длинна_строки + 1 буква
nRetnSz := HelloWorldW( PWideChar(sDllQuestion), lpBuffer, nBufferSz);
end;
// Всё окей, получили строку
sLibrarySays := Copy(lpBuffer, 0, nRetnSz);
// Выводим результат
MessageBoxW(0, PWideChar(sLibrarySays), 'Response from dll', MB_ICONINFORMATION);
finally
FreeMem(lpBuffer, nBufferSz); // На забываем отдать Windows, память
end;
end.
** Исходный код программки и библиотеки для Delphi XE2 **
{{works:programmer:delphi:simpledll.zip}}