works:programmer:delphi:pchar-for-dlls

Передача строк в библиотеку 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

simpledll.zip

works/programmer/delphi/pchar-for-dlls.txt · Last modified: 2018/12/15 17:18 (external edit)