Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Programming_Windows_95_Part_I.pdf
Скачиваний:
96
Добавлен:
05.06.2014
Размер:
4.61 Mб
Скачать

305

wndclass.hbrBackground = hBrush;

Главное отличие между битовыми образами и остальными ресурсами в их практической важности и может быть легко выражено так: битовые образы являются объектами GDI. Хороший стиль составления программ рекомендует, что битовые образы должны быть удалены из программы, если в них отпадает нужда, или если программа завершается. В программе RESOURC2 это происходит по завершении работы функции WinMain:

DeleteObject((HGDIOBJ) hBrush);

DeleteObject((HGDIOBJ) hBitmap);

Символьные строки

Наличие ресурса для символьных строк может вначале показаться странным. Тем более, что не было никаких проблем при использовании привычных символьных строк, определенных в качестве переменных непосредственно в теле исходного текста нашей программы.

Ресурсы-символьные строки предназначены главным образом для облегчения перевода вашей программы на другие языки. Как будет рассказано в следующих двух главах, меню и окна диалога также являются частью описания ресурсов. Если вместо непосредственного использования строк в исходном тексте вашей программы, вы используете ресурсы-символьные строки, то весь текст вашей программы, окажется в одном файле — файле описания ресурсов. Если текст в файле описания ресурсов переводится, то все, что вам нужно сделать для иноязычной версии вашей программы, это перекомпоновать программу и добавить переведенные ресурсы в файл с расширением .EXE. Этот способ намного безопасней, чем возня с исходными кодами вашей программы. (Конечно, можно определить все символьные строки в качестве макросов и хранить их в заголовочном файле. Такой способ также позволяет избежать изменения исходного кода программы при переводе на другие языки.)

Использование ресурсов-символьных строк

Ресурсы-символьные строки определяются в описании ресурсов с помощью ключевого слова STRINGTABLE:

STRINGTABLE

{

id1, "character string 1"

id2, "character string 2"

[определения остальных строк]

}

В описании ресурсов может содержаться только одна таблица строк. Максимальный размер каждой строки — 255 символов. В строке не может быть управляющих символов языка С, за исключением \t (табуляция). Однако, символьные строки могут содержать восьмеричные константы:

Табуляция (Tab)

\011

Перевод строки (Linefeed)

\012

Возврат каретки (Carriage return)

\015

Эти управляющие символы распознаются функциями DrawText и MessageBox.

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

LoadString(hInstance, id, szBuffer, iMaxLength);

Параметр id соответствует идентификатору, который предшествует каждой строке в файле описания ресурсов; szBuffer — это указатель на символьный массив, в который заносится символьная строка; iMaxLength — это максимальное число передаваемых в szBuffer символов. Идентификаторы строк, которые предшествуют каждой строке, обычно являются идентификаторами макроопределений, которые задаются в заголовочном файле. Многие программисты, программирующие под Windows, для идентификаторов строк используют префикс IDS_. Иногда, при выводе на экран имени файла или другой информации, она должна быть помещена в строку. В этом случае вы помещаете в строку символы форматирования языка С и используете эту строку в качестве форматирующей в функциях sprintf или wsprintf.

Использование ресурсов-строк в функции MessageBox

Давайте рассмотрим пример программы, в которой для вывода на экран трех сообщений об ошибках в окне сообщений используются три символьные строки. В заголовочном файле, который мы назовем PROGRAM.H, для этих сообщений определяются три идентификатора:

#define IDS_FILENOTFOUND

1

306

#define

IDS_FILETOOBIG

2

#define

IDS_FILEREADONLY

3

Файл описания ресурсов выглядит следующим образом:

#include "program.h"

 

[описание других ресурсов]

 

STRINGTABLE

 

{

 

IDS_FILENOTFOUND,

"File %s not found."

IDS_FILETOOBIG,

"File %s too large to edit."

IDS_FILEREADONLY,

"File %s is read-only."

}

 

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

#include "program.h"

[другие строки программы]

OkMessage(HWND hwnd, int iErrorNumber, char *szFileName)

{

char szFormat[40]; char szBuffer[60];

LoadString(hInst, iErrorNumber, szFormat, 40);

sprintf(szBuffer, szFormat, szFileName);

return MessageBox(hwnd, szBuffer, szAppName, MB_OK | MB_ICONEXCLAMATION);

}

Для вывода на экран окна сообщений с сообщением "File not found." программа вызывает функцию:

OkMessage(hwnd, IDS_FILENOTFOUND, szFileName);

Ресурсы, определяемые пользователем

Ресурсы, определяемые пользователем (user-defined resourse) удобны для включения самых разнообразных данных в ваш файл с расширением .EXE и получения доступа в программе к этим данным. Данные могут содержаться в любом выбранном вами формате — текстовом или бинарном. При загрузке данных в оперативную память возвращаемым значением функций Windows, которые используются для доступа к определяемым пользователем ресурсам, является указатель на данные. С этими данными вы можете делать все, что угодно. Вы вероятно решите, что этот способ хранения и доступа к разнообразным данным удобнее, чем альтернативный, при котором данные хранятся в других файлах и доступ к ним осуществляется через функции файлового ввода.

Например, предположим, что у вас есть файл PROGHELP.TXT, в котором содержится текст "подсказок" для вашей программы. Такой файл не должен быть в чистом виде ASCII-файлом: в нем также могут содержаться бинарные данные, например, указатели, которые могли бы помочь при ссылках на различные части этого файла. Следующим образом опишите ссылку на этот файл в вашем файле описания ресурсов:

helptext TEXT proghelp.txt

Имена helptext (имя ресурса) и TEXT (тип ресурса) в этом выражении могут быть любыми. Слово TEXT написано прописными буквами просто, чтобы сделать его похожим на слова ICON, CURSOR и BITMAP. То, что мы здесь делаем, является созданием ресурса вашего собственного типа, который называется TEXT.

В процессе инициализации программы (например, при обработке сообщения WM_CREATE), можно получить описатель этого ресурса:

hResource = LoadResource(hInstance, FindResource(hInstance, "TEXT", "helptext"));

Переменная hResource определяется как имеющая тип HGLOBAL. Несмотря на свое имя, функция LoadResource фактически не загружает сразу ресурс в оперативную память. Используемые вместе, так как это было показано, функции LoadResource и FindResource по существу эквивалентны функциям LoadIcon и LoadCursor. Фактически,

функции LoadIcon и LoadCursor используют функции LoadResource и FindResource.

307

Вместо имен и типов ресурсов можно использовать числа. Числа могут быть преобразованы в дальние указатели при вызове функции FindResource с использованием MAKEINTRESOURCE. Числа, используемые в качестве типа ресурса, должны быть больше 255. (Числа от 1 до 9 при вызове функции FindResource используются в Windows для существующих типов ресурсов.)

Когда вам необходимо получить доступ к тексту, вызывайте функцию LockResource:

pHelpText = LockResource(hResource);

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

FreeResource:

FreeResource(hResource);

Даже если вы не вызовите функцию FreeResource, после завершения работы программы оперативная память все равно будет освобождена.

Давайте рассмотрим пример программы, в которой используется три ресурса — значок, таблица строк и ресурс, определяемый пользователем. В программе POEPOEM, представленной на рис. 9.3, на экран, в рабочую область окна программы, выводится текст поэмы Эдгара Алана По "Annabel Lee". Ресурс, определяемый пользователем — это файл POEPOEM.ASC, в котором находится текст поэмы. Текстовый файл заканчивается символом обратной косой черты

(\).

POEPOEM.MAK

#-----------------------

# POEPOEM.MAK make file

#-----------------------

poepoem.exe : poepoem.obj poepoem.res

$(LINKER) $(GUIFLAGS) -OUT:poepoem.exe poepoem.obj poepoem.res $(GUILIBS)

poepoem.obj : poepoem.c poepoem.h $(CC) $(CFLAGS) poepoem.c

poepoem.res : poepoem.rc poepoem.ico poepoem.asc poepoem.h $(RC) $(RCVARS) poepoem.rc

POEPOEM.C

/*-------------------------------------------------

 

POEPOEM.C --

Demonstrates User-Defined Resource

 

(c) Charles Petzold, 1996

-------------------------------------------------

*/

#include <windows.h> #include "poepoem.h"

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

char

szAppName[10];

char

szCaption[35];

HINSTANCE

hInst;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)

{

 

HWND

hwnd;

MSG

msg;

WNDCLASSEX

wndclass;

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

LoadString(hInstance, IDS_CAPTION, szCaption, sizeof(szCaption));

wndclass.cbSize

= sizeof(wndclass);

wndclass.style

= CS_HREDRAW | CS_VREDRAW;

wndclass.lpfnWndProc

= WndProc;

wndclass.cbClsExtra

= 0;

308

wndclass.cbWndExtra

= 0;

wndclass.hInstance

= hInstance;

wndclass.hIcon

= LoadIcon(hInstance, szAppName);

wndclass.hCursor

= LoadCursor(NULL, IDC_ARROW);

wndclass.hbrBackground

=(HBRUSH) GetStockObject(WHITE_BRUSH);

wndclass.lpszMenuName

= NULL;

wndclass.lpszClassName

= szAppName;

wndclass.hIconSm

= LoadIcon(hInstance, szAppName);

RegisterClassEx(&wndclass);

hInst = hInstance;

hwnd = CreateWindow(szAppName, szCaption, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,

NULL, NULL, hInstance, NULL);

ShowWindow(hwnd, iCmdShow);

UpdateWindow(hwnd);

while(GetMessage(&msg, NULL, 0, 0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return msg.wParam;

}

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

 

static char

*pText;

static HGLOBAL hResource;

static HWND

hScroll;

static int

iPosition, cxChar, cyChar, cyClient, iNumLines, xScroll;

char

szPoemRes[15];

HDC

hdc;

PAINTSTRUCT

ps;

RECT

rect;

TEXTMETRIC

tm;

switch(iMsg)

{

case WM_CREATE :

hdc = GetDC(hwnd); GetTextMetrics(hdc, &tm); cxChar = tm.tmAveCharWidth;

cyChar = tm.tmHeight + tm.tmExternalLeading; ReleaseDC(hwnd, hdc);

xScroll = GetSystemMetrics(SM_CXVSCROLL);

hScroll = CreateWindow("scrollbar", NULL, WS_CHILD | WS_VISIBLE | SBS_VERT, 0, 0, 0, 0,

hwnd,(HMENU) 1, hInst, NULL); LoadString(hInst, IDS_POEMRES, szPoemRes, sizeof(szPoemRes));

hResource = LoadResource(hInst,

FindResource(hInst, szPoemRes, "TEXT"));

pText =(char *) LockResource(hResource);

309

iNumLines = 0;

while(*pText != '\\' && *pText != '\0')

{

if(*pText == '\n') iNumLines ++;

pText = AnsiNext(pText);

}

*pText = '\0';

SetScrollRange(hScroll, SB_CTL, 0, iNumLines, FALSE);

SetScrollPos (hScroll, SB_CTL, 0, FALSE);

return 0;

case WM_SIZE :

MoveWindow(hScroll, LOWORD(lParam) - xScroll, 0,

xScroll, cyClient = HIWORD(lParam), TRUE);

SetFocus(hwnd); return 0;

case WM_SETFOCUS : SetFocus(hScroll); return 0;

case WM_VSCROLL : switch(wParam)

{

case SB_TOP : iPosition = 0; break;

case SB_BOTTOM :

iPosition = iNumLines; break;

case SB_LINEUP : iPosition -= 1; break;

case SB_LINEDOWN : iPosition += 1; break;

case SB_PAGEUP :

iPosition -= cyClient / cyChar; break;

case SB_PAGEDOWN :

iPosition += cyClient / cyChar; break;

case SB_THUMBPOSITION : iPosition = LOWORD(lParam); break;

}

iPosition = max(0, min(iPosition, iNumLines));

if(iPosition != GetScrollPos(hScroll, SB_CTL))

{

SetScrollPos(hScroll, SB_CTL, iPosition, TRUE);

InvalidateRect(hwnd, NULL, TRUE);

}

return 0;

case WM_PAINT :

hdc = BeginPaint(hwnd, &ps);

pText =(char *) LockResource(hResource);

GetClientRect(hwnd, &rect);

310

rect.left += cxChar;

rect.top += cyChar *(1 - iPosition);

DrawText(hdc, pText, -1, &rect, DT_EXTERNALLEADING);

EndPaint(hwnd, &ps); return 0;

case WM_DESTROY : FreeResource(hResource); PostQuitMessage(0); return 0;

}

return DefWindowProc(hwnd, iMsg, wParam, lParam);

}

POEPOEM.RC

/*----------------------------

POEPOEM.RC resource script

----------------------------*/

#include "poepoem.h"

poepoem

ICON

poepoem.ico

AnnabelLee

TEXT

poepoem.asc

STRINGTABLE

{

IDS_APPNAME, "poepoem"

IDS_CAPTION, """Annabel Lee"" by Edgar Allen Poe"

IDS_POEMRES, "AnnabelLee"

}

POEPOEM.ICO

POEPOEM.H

/*-----------------------

POEPOEM.H header file

-----------------------*/

#define IDS_APPNAME 0 #define IDS_CAPTION 1 #define IDS_POEMRES 2

POEPOEM.ASC

It was many and many a year ago, In a kingdom by the sea,

That a maiden there lived whom you may know

By the name of Annabel Lee;

And this maiden she lived with no other thought Than to love and be loved by me. I was a child and she was a child

In this kingdom by the sea,

But we loved with a love that was more than love -I and my Annabel Lee -- With a love that the winged seraphs of Heaven Coveted her and me.

And this was the reason that, long ago,

In this kingdom by the sea,

A wind blew out of a cloud, chilling

My beautiful Annabel Lee;

So that her highborn kinsmen came And bore her away from me, To shut her up in a sepulchre

In this kingdom by the sea.

311

The angels, not half so happy in Heaven,

Went envying her and me --

Yes! that was the reason(as all men know,

In this kingdom by the sea)

That the wind came out of the cloud by night, Chilling and killing my Annabel Lee. But our love it was stronger by far than the love Of those who were older than we --

Of many far wiser than we --

And neither the angels in Heaven above

Nor the demons down under the sea

Can ever dissever my soul from the soul Of the beautiful Annabel Lee:

For the moon never beams, without bringing me dreams Of the beautiful Annabel Lee; And the stars never rise, but I feel the bright eyes Of the beautiful Annabel Lee:

And so, all the night-tide, I lie down by the side Of my darling -- my darling -- my life and my bride, In her sepulchre there by the sea --

In her tomb by the sounding sea.

[May, 1849]

Рис. 9.3 Программа POEPOEM, содержащая значок и ресурс, определяемый пользователем

В файле описания ресурсов POEPOEM.RC ресурсу, определяемому пользователем, присваивается тип TEXT и имя

AnnabelLee:

AnnabelLee TEXT poepoem.asc

При обработке в WndProc сообщения WM_CREATE описатель ресурса получается с использованием функций LoadResource и FindResource. Захватывается ресурс с помощью функции LockResource, а небольшая подпрограмма заменяет символ обратной косой черты (\) в конце файла на 0. Это сделано для адаптации текста к функции DrawText, которая позже, при обработке сообщения WM_PAINT, будет отображать его на экране.

Обратите внимание на использование полосы прокрутки-элемента управления вместо полосы прокрутки окна: в полосе прокрутки-элемента управления автоматически поддерживается интерфейс клавиатуры, поэтому в программе POEPOEM не требуется обрабатывать сообщение WM_KEYDOWN.

В программе POEPOEM также используются три символьные строки, идентификаторы которых определяются в заголовочном файле POEPOEM.H. Строки IDS_APPNAME и IDS_CAPTION с помощью функции LoadString заносятся в глобальные статические переменные:

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

LoadString(hInstance, IDS_CAPTION, szCaption, sizeof(szCaption));

Теперь, когда мы задали все символьные строки программы POEPOEM как ресурсы, мы упростили переводчикам их задачу. Конечно, им все равно придется переводить текст поэмы "Annabel Lee", и есть подозрение, что это будет несколько более трудной задачей.

Соседние файлы в предмете Операционные системы