Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Операционная система Microsoft Windows 3.1 для программиста

© Александр Фролов, Григорий Фролов
Том 12, М.: Диалог-МИФИ, 1993, 255 стр.

[Назад] [Содеожание] [Дальше]

1.2. Таблица текстовых строк

Мы начнем изучение ресурсов с самого простого в использовании - таблицы строк. Таблица строк содержит текстовые строки, закрытые двоичным нулем, на которые можно ссылаться по идентификатору. Идентификатор представляет собой обыкновенное целое число. Вместо чисел обычно используют символические имена, определенные с помощью директивы #define.

Создание таблицы

Для создания таблицы строк текстовый файл описания ресурсов должен содержать оператор STRINGTABLE:

STRINGTABLE [параметры загрузки][тип памяти]
BEGIN
StringID, строка
...
...
...
END

В качестве параметров загрузки можно указывать значения PRELOAD или LOADONCALL (используется по умолчанию). Ресурс с параметром загрузки LOADONCALL загружается в память при обращении к нему со стороны приложения. Ресурс типа PRELOAD загружается сразу после запуска приложения.

Тип памяти, выделяемой при загрузки ресурса, может быть FIXED или MOVABLE. Дополнительно для ресурсов типа можно указать MOVABLE тип DISCARDABLE. Если указан тип FIXED, ресурс будет находиться в памяти по постоянному адресу. Ресурс типа MOVABLE может перемещаться Windows при необходимости уплотнения памяти. Если для перемещаемого ресурса указан тип DISCARDABLE, Windows может забрать у приложения память, выделенную для ресурса. Если ресурс потребуется приложению, Windows загрузит его повторно из exe-файла приложения.

Операторы BEGIN и END определяют границы таблицы строк в файле описания ресурсов. Между ними находятся строки с идентификаторами StringID:

STRINGTABLE
BEGIN
1, "Файл %s не найден"
2, "Ошибка при записи в файл %s"
3, "Ошибка ввода/вывода"
END

Загрузка строки из таблицы

Для загрузки строки в оперативную память необходимо использовать функцию LoadString:

int WINAPI LoadString(
  HINSTANCE hInst,      // идентификатор приложения
  UINT idResource,      // идентификатор ресурса
  LPSTR lpszBuffer,     // адрес буфера
  int cbBuffer);        // размер буфера в байтах

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

Параметр idResource указывает идентификатор нужной строки. Вы должны использовать одно из значений, заданных в файле описания ресурсов.

Указатель lpszBuffer определяет адрес буфера, в который будет загружена строка. Размер буфера должен быть задан через параметр cbBuffer. Если размер строки окажется больше указанного размера буфера, строка будет обрезана.

Функция LoadString возвращает количество символов, записанных в буфер, или 0, если файл загрузочного модуля не содержит строки с указанным идентификатором (или если в этом файле вообще нет таблицы строк).

Приложение STRING

Приложение STRING (листинг 1.1) демонстрирует использование таблицы строк для хранения названия приложения, заголовка окна и строки формата для вывода текста сообщения.


Листинг 1.1. Файл string\string.cpp


// ----------------------------------------
// Работа с таблицей строк 
// ----------------------------------------

#define STRICT
#include <windows.h>
#include "string.hpp"

// Прототип функции обработки ошибки
void Error(void);

#pragma argsused
int PASCAL
WinMain(HINSTANCE hInstance,
        HINSTANCE hPrevInstance,
        LPSTR     lpszCmdLine,
        int       nCmdShow)
{
  // Буфера для работы со строками
  BYTE szAppName[20];
  BYTE szWindowName[80];
  BYTE szMsg[80];
  BYTE szBuf[80];
  int  cb;

  // Загружаем строку с идентификатором IDS_APPNAME
  cb = LoadString(hInstance, IDS_APPNAME,
    szAppName, sizeof(szAppName));

  // Если в буфер записано 0 символов,
  // это означает, что ресурс не найден.
  // В этом случае мы вызываем функцию обработки
  // ошибки и завершаем работу приложения 
  if(!cb)
  {
    Error(); return -1;
  }

  // Загружаем строку с идентификатором IDS_WINDOWNAME
  cb = LoadString(hInstance, IDS_WINDOWNAME,
    szWindowName, sizeof(szWindowName));

  if(!cb)
  {
    Error(); return -1;
  }

  // Загружаем строку с идентификатором IDS_MESSAGE
  cb = LoadString(hInstance, IDS_MESSAGE,
    szMsg, sizeof(szMsg));

  if(!cb)
  {
    Error(); return -1;
  }

  // Подготавливаем буфер для вывода сообщения
  wsprintf(szBuf, szMsg, (LPSTR)szAppName, 1994);

  // Выводим сообщение, составленное из строк
  // и числа 1994
  MessageBox(NULL, szBuf, szWindowName,
     MB_OK | MB_ICONINFORMATION);

  return 0;
}

// --------------------------------------------
// Функция обработки ошибки загрузки ресурса
// --------------------------------------------
void Error(void)
{
  MessageBox(NULL, "Ошибка при загрузке ресурса",
    "Error", MB_OK | MB_ICONSTOP);
}

В главный файл исходного текста приложения включается include-файл string.hpp (листинг 1.2), в котором описаны символические константы для идентификации строк.


Листинг 1.2. Файл string\string.hpp


#define IDS_APPNAME    1
#define IDS_WINDOWNAME 2
#define IDS_MESSAGE    3

Этот же файл включается и в файл описания ресурсов (листинг 1.3). При этом для идентификации строк можно будет использовать символические имена, определенные в файле string.hpp.


Листинг 1.3. Файл string\string.rc


#include "string.hpp"
/* Таблица строк */
STRINGTABLE
BEGIN
IDS_APPNAME,    "String"
IDS_WINDOWNAME, "String Application"
IDS_MESSAGE,    "%s Demo, (C) Frolov A.V., %d"
END

Как и для любого приложения Windows, в проект включается файл определения модуля (листинг 1.4).


Листинг 1.4. Файл string\string.def


; =============================
; Файл определения модуля
; =============================
NAME        STRING
DESCRIPTION 'Приложение STRING, (C) 1994, Frolov A.V.'
EXETYPE     windows
STUB        'winstub.exe'
STACKSIZE   5120
HEAPSIZE    1024
CODE        preload moveable discardable
DATA        preload moveable multiple

Для загрузки текстовой строки из таблицы строк приложение вызывает функцию LoadString, передавая ей в качестве параметров идентификатор текущей копии приложения, идентификатор загружаемой строки, адрес и размер буфера:

cb = LoadString(hInstance, IDS_APPNAME,
  szAppName, sizeof(szAppName));

Обратите внимание на последнюю строку в таблице строк:

IDS_MESSAGE,    "%s Demo, (C) Frolov A.V., %d"

Эта строка содержит описание формата для функции wsprintf. После загрузки строки формата приложение передает ее адрес функции wsprintf, которая выполняет окончательное формирование сообщения, включая в него еще одну текстовую строку (также загруженную из таблицы строк) и число:

wsprintf(szBuf, szMsg, (LPSTR)szAppName, 1994);

Сообщение, которое будет выведено на экран приложением STRING, показано на рис. 1.2.

Рис. 1.2. Сообщение приложения STRING

С помощью этой методики вы можете организовать, например, выдачу сообщений об ошибках. Текст сообщения в виде строки формата будет храниться в таблице строк. Перед выводом сообщения приложение загрузит строку формата и вставит в сообщение код ошибки и другую необходимую информацию, описывающую ошибку.

Редактирование таблицы строк

При разработке приложения, когда вам доступны его исходные тексты, таблицу строк лучше всего редактировать в файле описания ресурсов обычным текстовым редактором, например, входящим в состав системы разработки приложений Borland C++ for Windows. Однако иногда возникает необходимость отредактировать содержимое таблицы строк или другие ресурсы готового приложения. В этом случае мы рекомендуем вам воспользоваться приложением Resource Workshop.

Этот инструмент обладает широкими возможностями. С его помощью вы можете создать новые ресурсы или отредактировать имеющиеся в загрузочном файле приложения, текстовом или двоичном файле описания ресурсов. Из-за ограниченного объема книги мы не можем привести полное описание приложения Resource Workshop, однако постепенно мы расскажем вам о том, как его использовать для создания или редактирования основных типов ресурсов.

Для начала давайте попробуем использовать Resource Workshop для редактирования строк только что описанного приложения STRING.

Запустите приложение Resource Workshop. Его пиктограмма должна находиться в группе системы разработки приложений Borland C++ for Windows.

Затем из меню "File" выберите строку "Open Project...". На экране появится диалоговая панель "Open Project" (рис. 1.3).

Рис. 1.3. Диалоговая панель "Open Project"

При помощи меню "File Type" вы можете выбрать тип файла, из которого собираетесь загрузить ресурсы для редактирования. Как видно из рисунка, ресурсы могут содержаться в файлах разных типов, например, в библиотеке динамической загрузки DLL или в драйвере устройства DRV.

Так как мы собираемся изменить таблицу строк в готовом приложении Windows, выберите в меню "File Type" строку "EXE application". Затем с помощью меню "Path", "Files" и "Directories" укажите путь к загрузочному файлу приложения. В нашем случае надо выбрать файл string.exe. После этого в главном окне приложения Resource Workshop появится окно с заголовком "string.exe", в котором будут перечислены все имеющиеся в файле ресурсы (рис. 1.4).

Рис. 1.4. Ресурсы из файла string.exe

Файл string.exe содержит только один тип ресурсов - таблицу строк STRINGTABLE. Для редактирования таблицы сделайте двойной щелчок левой клавишей мыши по цифре 1, расположенной в окне "string.exe". В главном окне приложения Resource Workshop появится окно "STRINGTABLE:1" (рис. 1.5).

Рис. 1.5. Окно "STRINGTABLE:1"

В этом окне в столбце "String" вы можете отредактировать текстовые строки.

После редактирования сохраните изменения, выбрав в меню "File" строку "Save Project".

На рис. 1.6 представлен результат "локализации" приложения STRING описанным выше образом. Мы перевели сообщение и заголовок окна на русский язык, не меняя файл описания ресурсов и не выполняя повторную сборку проекта.

Рис. 1.6. Измененное приложение STRING

Однако есть одна небольшая проблема. К сожалению, Resource Workshop, который поставляется вместе с системой разработки Borland C++ for Windows версии 3.1, не понимает русские буквы "ю" и "я". При вводе строк, содержащих эти буквы, на экране появляется сообщение об ошибке (рис. 1.7).

Рис. 1.7. Сообщение об ошибке приложения Resource Workshop

Возможно, в следующих версиях Resource Workshop эта ошибка (или особенность!) будет исправлена, а пока вместо букв "ю" и "я" мы рекомендуем указывать соответствующие им восьмеричные коды. Букве "ю" соответствует код \376, букве "я" - код \377. При этом строка будет выглядеть так:

Возможно, в следу\376щих верси\377х это будет исправлено

Функции для работы с текстовыми строками

Для работы с текстовыми строками приложения Windows могут вызывать стандартные функции библиотеки компилятора, такие как strcat или strcopy. Однако лучше использовать функции для работы с текстовыми строками, определенные в программном интерфейсе Windows. Эти функции используют дальние указатели на строки и учитывают специфику национальных алфавитов. Кроме того, указанные функции находятся в ядре Windows, поэтому при их использовании не происходит увеличения размера файла загрузочного модуля приложения.

Функция lstrcmp сравнивает строки, заданные параметрами:

int WINAPI lstrcmp(LPCSTR lpszString1, LPCSTR lpszString2);

Функция возвращает отрицательное значение, если строка lpszString1 меньше чем строка lpszString2, положительное в противоположном случае, и равное нулю при равенстве сравниваемых строк. При сравнении учитываются особенности национального алфавита для указанной при помощи приложения Control Panel страны. Функция способна сравнивать строки с двухбайтовыми кодами символов. Учитываются также заглавные и прописные буквы. Размер сравниваемых строк не может превышать 64 Кбайт.

Функция lstrcmpi предназначена для сравнения двух строк, но без учета заглавных и прописных букв:

int WINAPI lstrcmpi(LPCSTR lpszString1, LPCSTR lpszString2);

В остальном она полностью аналогична функции lstrcmp.

Учтите, что известные вам функции strcmp и strcmpi не учитывают особенности национальных алфавитов и поэтому их не следует использовать в приложениях Windows.

Для копирования текстовых строк вы должны пользоваться функцией lstrcpy:

LPSTR WINAPI lstrcpy(LPSTR lpszString1, LPCSTR lpszString2);

Эта функция копирует строку lpszString2 в строку lpszString1, возвращая указатель на первую строку или NULL при ошибке. В отличие от своего аналога из библиотеки функций MS-DOS (функции strcpy) эта функция способна работать со строками, содержащими двухбайтовые коды символов. Размер копируемой строки не должен превышать 64 Кбайт.

В программном интерфейсе Windows версии 3.1 появилась еще одна функция, предназначенная для копирования заданного количества символов из одной строки в другую. Эта функция имеет имя lstrcpyn:

LPSTR WINAPI lstrcpyn(LPSTR lpszString1, LPCSTR lpszString2,
   int cChars);

Она копирует cChars символов из строки lpszString2 в строку lpszString1.

Для объединения двух строк в приложениях Windows следует применять функцию lstrcat:

LPSTR WINAPI lstrcat(LPSTR lpszString1, LPCSTR lpszString2);

Функция lstrcat добавляет строку lpszString2 к строке lpszString1. Размер строки, получившейся в результате объединения, не должен превышать 64 Кбайт. Функция возвращает указатель на строку lpszString1.

Длину текстовой строки (без учета закрывающего строку двоичного нуля) можно получить при помощи функции lstrlen, аналогичной известной вам функции strlen:

int WINAPI lstrlen(LPCSTR lpszString);

Для классификации символов на строчные, прописные, буквенные или цифровые приложения должны использовать специально предназначенные для этого функции из программного интерфейса Windows.

Функция IsCharAlpha возвращает значение TRUE, если символ, заданный параметром chTest, является буквой:

BOOL WINAPI IsCharAlpha(char chTest);

Функция IsCharAlphaNumeric возвращает значение TRUE, если символ, заданный параметром chTest, является буквой или цифрой:

BOOL WINAPI IsCharAlphaNumeric(char chTest);

Функция IsCharUpper возвращает значение TRUE, если символ, заданный параметром chTest, является прописным (заглавным):

BOOL WINAPI IsCharUpper(char chTest);

Функция IsCharLower возвращает значение TRUE, если символ, заданный параметром chTest, является строчным:

BOOL WINAPI IsCharLower(char chTest);

В предыдущем томе "Библиотеки системного программиста" мы рассказывали вам о том, что Windows и MS-DOS используют разные наборы символов. Приложения Windows обычно работают с наборами в стандарте ANSI, программы MS-DOS - в стандарте OEM. Там же мы описали функции, предназначенные для преобразования строк из одного стандарта в другой. Для удобства изучения материала кратко перечислим эти функции еще раз.

Для перекодировки строки символов, закрытой двоичным нулем, из набора ANSI в набор OEM предназначена функция AnsiToOem:

void WINAPI AnsiToOem(const char _huge* hpszWindowsStr,
    char _huge* hpszOemStr);

Параметр hpszWindowsStr представляет собой указатель типа _huge на преобразуемую строку, параметр hpszOemStr - указатель на буфер для записи результата преобразования.

Похожая по назначению функция AnsiToOemBuff выполняет преобразование массива заданного размера:

void WINAPI AnsiToOemBuff(LPCSTR lpszWindowsStr,
   LPSTR lpszOemStr, UINT cbWindowsStr);

Первый параметр этой функции (lpszWindowsStr) является дальним указателем на массив, содержащий преобразуемые данные, второй (lpszOemStr) - на буфер для записи результата. Третий параметр (cbWindowsStr) определяет размер входного массива, причем нулевой размер соответствует 64 Кбайт (65536 байт).

Обратное преобразование выполняется функциями OemToAnsi и OemToAnsiBuff:

void WINAPI OemToAnsi(const char _huge* hpszOemStr, 
   char _huge* lpszWindowsStr);
void WINAPI OemToAnsiBuff(LPCSTR lpszOemStr, 
   LPSTR lpszWindowsStr, UINT cbOemStr);

Назначение параметров этих функций аналогично назначению параметров функций AnsiToOem и AnsiToOemBuff.

Для преобразований символов в строчные или прописные приложение Windows должно пользоваться функциями AnsiLower, AnsiLowerBuff, AnsiUpper, AnsiUpperBuff.

Функция AnsiLower преобразует закрытую двоичным нулем текстовую строку в строчные (маленькие) буквы:

LPSTR WINAPI AnsiLower(LPSTR lpszString);

Единственный параметр функции - дальний указатель на преобразуемую строку.

Функция AnsiUpper преобразует закрытую двоичным нулем текстовую строку в прописные (большие) буквы:

LPSTR WINAPI AnsiLower(LPSTR lpszString);

Параметр функции lpszString - дальний указатель на преобразуемую строку.

Функция AnsiLowerBuff позволяет преобразовать в строчные (маленькие) буквы заданное количество символов:

UINT WINAPI AnsiLowerBuff(LPSTR lpszString, UINT cbString);

Первый параметр функции (lpszString) является указателем на буфер, содержащий преобразуемые символы, второй (cbString) определяет количество преобразуемых символов (размер буфера). Нулевой размер соответствует буферу длиной 64 Кбайт (65536 байт).

Функция возвращает количество преобразованных символов.

Функция AnsiUpperBuff позволяет преобразовать в прописные (большие) буквы заданное количество символов:

UINT WINAPI AnsiUpperBuff(LPSTR lpszString, UINT cbString);

Первый параметр функции lpszString(lpszString) является указателем на буфер, содержащий преобразуемые символы, второй (cbString) определяет количество преобразуемых символов (размер буфера). Нулевой размер соответствует буферу длиной 64 Кбайт (65536 байт).

Эта функция, как и предыдущая, возвращает количество преобразованных символов.

Функция AnsiNext возвращает новое значение для указателя, передвинутое вперед по строке на одни символ:

LPSTR WINAPI AnsiNext(LPCSTR lpchCurrentChar);

Параметр функции указывает на текущий символ. Возвращаемое значение является указателем на следующий символ в строке или на закрывающий строку двоичный ноль.

Функция AnsiPrev выполняет передвижение указателя в направлении к началу строки:

LPSTR WINAPI AnsiPrev(LPCSTR lpchStart, 
   LPCSTR lpchCurrentChar);

Первый параметр функции указывает на начало строки (на первый символ строки). Второй параметр - указатель на текущий символ. Функция возвращает значение указателя, соответствующее предыдущему символу или первому символу в строке, если при продвижении достигнуто начало строки.

[Назад] [Содеожание] [Дальше]