Delphi: DLL библиотеки

КОМПЬЮТЕРНЫЕ КУРСЫ "ПОИСК"

[Главная страница] [Delphi] [DLL] [Контакты]

Передача строк между приложением и библиотекой DLL


Теперь мы попытаемся создать библиотеку DLL, которая будет использовать тип PChar для передачи строковых данных вызывающему приложению. Это приложение показано на рисунке ниже.

Текст диалогового окна MessageDlg, взятый из библиотеки DLL

Сначала нужно создать главное приложение:

  1. Создайте новый проект приложения VCL Forms.
  2. Добавьте в окно Designer Surface компонент TRadioGroup.
  3. Добавьте в каждый компонент TRadioGtoup элементы Английский, Немецкий и Хорватский.

После того как вы создадите интерфейс пользователя главного приложения, вы должны будете создать модуль для перечисления языков, которые будут использоваться главным приложением и библиотекой DLL, а затем добавить новый проект библиотеки DLL в проектную группу

Создаем модуль.

Ниже показан код модуля MyTypes, содержащий перечисление языков:

unit MyTypes;

interface

type
  TMyLanguage = (mlEnglish, mlGerman, mlCroatian);

implementation

end.

Если вы захотите организовать передачу указателя PChar (указатель на строку символов типа Char с нулевым символом в конце) между приложением и библиотекой DLL, то нам нужно будет определиться лишь с тем, как управлять памятью для PChar. Далее приведен перечень того, что вы можете делать, а что — нет:

  1. Вы можете выделять и освобождать указатель PChar в библиотеке DLL.
  2. Вы можете выделять и освобождать указатель PChar в вызывающем приложении (так принято в Windows API).
  3. Вы не можете выделять память указателя PChar в библиотеке DLL и освобождать ее в главном приложении, или наоборот.

В листинге 1 показано, как производится выделение и освобождение памяти PChar в библиотеке DLL. Листинг содержит две подпрограммы: функцию GetStringData, которая выделяет память и возвращает локализованную строку, и процедуру FreeStringData, которую необходимо использовать для освобождения памяти, выделенной функцией GetStringData.

Листинг 1. Подпрограммы, управляющие памятью в библиотеке DLL


library LanguageLib;

uses
  SysUtils,
  Classes, MyTypes;

const
  STRING_DATA: array[TMyLanguage] of string = ('Good morning', 'Guten Morgen',
            'Dobro jutro.');

{ Возвращаем локализованную строку }
function GetStringData(Language: TMyLanguage): PChar;
begin
  { Выделяем память для строки и символа #0 }
  GetMem(Result, Length(STRING_DATA[Language]) + 1);
  { Функция StrPCopy копирует строку в строку с нулевым символом в конце }
  StrPCopy(Result, STRING_DATA[Language]);
end;

{ Эта подпрограмма используется для освобождения указателей PChar,
  выделенных функцией GetStringData }
procedure FreeStringData(Data: PChar);
begin
  FreeMem(Data);
end;

exports GetStringData, FreeStringData;

begin
end.

В листинге 2 показано, как используются подпрограммы GetStringData и FreeStringData в главном приложении.

Листинг 2. Использование подпрограмм GetStringData и FreeStringData для получения локализованной строки из библиотеки DLL


procedure TForm1.RadioGroup1Click(Sender: TObject);
var
  DLLHandle: THandle;
  stringFunc: function(Language: TMyLanguage): PChar;
  freeProc: procedure(Data: PChar);
  buffer: PChar;
  selectedLang: TMyLanguage;
begin
  selectedLang := TMyLanguage(RadioGroup1.ItemIndex);
  DLLHandle := LoadLibrary('LanguageLib.dll');
  try
    { Находим обе подпрограммы }
    stringFunc := GetProcAddress(DLLHandle, 'GetStringData');
    freeProc := GetProcAddress(DLLHandle, 'FreeStringData');
    if not Assigned(stringFunc) or not Assigned(freeProc) then
    //Можно и так
    //if (@stringFunc = nil) or (@freeProc = nil) then    
      MessageDlg('Error Loading DLL!', mtError, [mbOK], 0)
    else begin
      buffer := stringFunc(selectedLang);
      try
        MessageDlg(string(buffer), mtInformation, [mbOK], 0);
      finally
        { Освобождаем память PChar с помощью подпрограммы DLL FreeStringdata }
        freeProc(buffer);
      end;  // Конец блока try..finally
    end;  // Конец блока условия if not Assigned
  finally
    FreeLibrary(DLLHandle);
  end;  // Конец блока try..finally
end;

Исходный код проекта (Delphi XE)

Используемая литература:
Иван Хладни. Внутренний мир Borland Delphi 2006.
А.Я. Архангельский. Приемы программирования Delphi на основе VCL. Версия Delphi 5 - Delphi 2006.