IT-Блог о программировании и операционных системах

Динамическая загрузка строк из STRINGTABLE

Как вы знаете, таблицы строк имеют неоспоримые преимущества перед строками, которые вы вставляете в свою программу непосредственно на этапе проектирования. Таких преимуществ, по крайней мере, два:

1. Для таких строк память не будет выделяться до того момента, когда этого не потребует ваше приложение или этого не захотите вы.

2. При помощи библиотек (DLL) со строковыми ресурсами, вы сможете легко и непринуждённо разрабатывать локализованное программное обеспечение, не используя сторонних компонентов (я видел только один компонент по этой теме, который мне всё-таки пришёлся по душе, кажется из пакета VGLib, но точно сказать не могу).

Приведу пример программы, которая в зависимости от выбора пользователя, устанавливает тот, или иной язык интерфейса. Нарисуйте форму следующего вида:


Имена управляющих элементов дефолтные, для удобства. Определим новые методы в классе TForm1:

• Procedure SetLanguage (LangFile:String);
• Procedure SelectLanguage (Language:TLang);

Так же определим новый тип: TLang = (lgRUS,lgENG); И запрограммируем наши новые методы:

procedure TForm1.SetLanguage(LangFile: String);
const
  NULL = 0;
var
  DLLHwnd:THandle;
  chBuff:array [0..255] of Char;
  i:integer;
begin
  DLLHwnd := LoadLibrary(PChar(ExtractFilePath(Application.ExeName)+'\lang\'+LangFile));
  if DLLHwnd <= NULL then
    Application.MessageBox('Не удаётся загрузить файл языка!','Ошибка!',MB_ICONERROR)
  else
   begin
    try
      for i := 1 to 5 do
        begin
          LoadString(DLLHwnd,i,@chBuff,sizeof(chBuff));
          case i of
            1: Button1.Caption := StrPas(chBuff);
            2: Button2.Caption := StrPas(chBuff);
            3: Form1.Caption   := StrPas(chBuff);
            4: Button3.Caption := StrPas(chBuff);
            5: Button4.Caption := StrPas(chBuff);
          end;
        end;
    except
     Application.MessageBox('Вы уж простите но чёт случилось! =)','Ошибка!',MB_ICONERROR)
    end;
   end;
end;

procedure TForm1.SelectLanguage(Language: TLang);
begin
  case Language of
    lgRUS: Self.SetLanguage('Russian.dll');
    lgENG: Self.SetLanguage('English.dll');
  end;
end;
На событие OnChange управляющего элемента ComboBox1 напишите следующий код:
procedure TForm1.ComboBox1Change(Sender: TObject);
begin
  if ComboBox1.Text = 'Русский' then Self.SelectLanguage(lgRUS)
    else if ComboBox1.Text = 'English' then Self.SelectLanguage(lgENG);
end;
В ComboBox1 у нас два элемента: Русский и English. При выборе одного из двух значений, происходит обращение к методу SelectLanguage с определённым параметром, который в свою очередь обращается к методу SetLanguage и передаёт в него строку. Эта строка является именем той библиотеки, которая содержит строки на выбранном языке.

В общем, метод SetLanguage и загружает строки для определённого языка, а так же устанавливает заголовки всех элементов управления. Код достаточно прост для понимания, так что комментариев приводить больше нет смысла. Единственное замечание: если вы впервые используете функцию LoadString, уточните её описание в MSDN. Скажу только, что 2,3 и 4 – это номер ресурса-строки в библиотеке, указатель на буфер, в который будет считана строка, размер буфера.

Теперь давайте посмотрим, как создать DLL со строковыми ресурсами:
Прежде всего в директории с проектом необходимо создать файл с расширением *.rc следующего содержания:
STRINGTABLE
{
1, "&Удалить"
2, "&Добавить"
3, "Простое приложение для демонстрации таблиц строк"
4, "Вы&ход"
5, "О программе..."
}
Как вы видите, это сами строки и их номера. Теперь следует откомпилировать этот файл компилятором ресурсов BRCC32.EXE который естественно входит в поставку Delphi. После компиляции, новоиспечённый файл *.res можно как обычно прилинковывать к проекту DLL. Следует сказать, что сама библиотека может и не содержать ни одной экспортируемой функции, в этом случаи DLL будет содержать только ресурсы.

2 комментария:

  1. >Следует сказать, что сама библиотека может и не содержать ни одной экспортируемой функции, в этом случаи DLL будет содержать только ресурсы.

    Примером такой dll является, например, graph.dll, которая хранит графические ресурсы QIP Infium :)

    ОтветитьУдалить
  2. Не помню как в ранних версиях Delphi, но с Delphi 7 точно есть: просто добавить *.rc в проект и компиляцию и линковку среда сделает самостоятельно.

    Анваров Сергей (anvarovsr)

    ОтветитьУдалить