Соглашение об использовании имен
Во многих текстах программ вы можете встретить, на первый взгляд, странные имена переменных. Дело в том, что эти имена переменных записаны с соблюдением так называемой венгерской нотации (введенной сотрудником Microsoft венгерского происхождения Ч.Шимони). При использовании этой нотации имена переменных предваряются префиксом, идентифицирующим их тип. Используемые префиксы типов приведены в табл. 2.2. |
Таблица 2.2.
Префиксы типов данных, используемые в венгерской нотации
Префикс |
Тип данных |
b |
ВООL (иногда BYTE) |
by |
ВУТЕ |
c |
char |
cb |
int (счетчик байтов) |
c |
класс |
w |
WORD |
dw |
DWORD |
n |
short int (или int) |
i |
int |
f |
флажок |
p |
указатель |
lp |
дальний указатель |
sz |
указатель на строку заканчивающуюся нулем |
lpsz |
дальний указатель на строку, заканчивающуюся нулем |
fn |
Функция |
lpfn |
дальний указатель на функцию |
pt |
Координаты точки, хранимые в виде длинного целого |
rgb |
Значение цвета, хранимое в виде длинного целого |
H |
дескриптор |
Использовать эти префиксы в программах или нет - дело программиста, но при чтении описаний функций Windows API вы их обязательно встретите, так как сама Microsoft их придерживается.
Структура приложения Windows
Простейшее GUI-приложение Windows, написанное на уровне Windows API, состоит из двух частей: функции WinMain(), которая является главной функцией, с которой начинается выполнение приложения, и оконной процедуры (или оконной функции), которая обрабатывает все сообщения, направляемые окну (которое в случае простейшего приложения является единственным).
Функция WinMain() обычно выполняет следующие задачи:
определяет класс окна;
регистрирует класс окна;
создает окно зарегистрированного класса;
отображает это окно;
запускает цикл обработки сообщений. Она имеет следующий прототип:
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
Параметры имеют такой смысл:
hInstance -. дескриптор текущего экземпляра приложения;
hPrevInstance - дескриптор предыдущего экземпляра приложения (запущенного на выполнение ранее); lpCmdLine -указатель на командную строку; nCmdShow - задает как окно должно быть отображено. Этот параметр может принимать одно из приведенных ниже значений:
SW_HIDE- скрывает это окно и актин
SW_MINIMIZE - минимизирует данное окно и активизирует окно верхнего уровня в системном списке;
SW_RESTORE - активизирует и отображает окно. Если окно минимизировано или максимизировано, система восстанавливает исходное состояние и позицию окна на экране (это значение эквивалентно значению SW_SHOWNORMAL);
SW_SHOW - активизирует окно и отображает его в текущем положении и размере;
SW_SHOWMAXIMIZED- активизирует окно и отображает его как максимальное окно;
SW_SHOWMINIMIZED - активизирует окно и отображает его в виде иконки;
SW_SHOWMINNOACTIVE - отображает окно в виде иконки. Активное окно остается активным;
SW_SHOWNA- отображает окно в его текущем состоянии. Активное окно остается активным;
SW_SHOWNOACTIVATE - отображает окно в его последних размерах и положении. Активное окно остается активным;
SW_SHOWNORMAL- активизирует и отображает окно. Если окно минимизировало или максимизировано, система восстанавливает его в исходных разме рах и позиции (эквивалентно значению SW_RESTORE).
Если функция завершилась успешно, она должна возвращать значение, которое имел параметр wParam последнего принятого сообщения (это – сообщение WM_QUIT). Если функция завершается до входа в цикл обработки сообщений, она должна возвращать ноль.
Оконная функция является CALLBACK-функцией, то есть функцией, вызываемой самой операционной системой для обработки сообщений, получаемых из очереди данного приложения. Она имеет стандартный прототип:
LRESULT CALLBACK wINDOWfUNC(HWND hWnd, UINT I Msg, WPARAM
wParam LPARAM lParam);
Ее параметры имеют следующий смысл: hWnd- дескриптор окна, которому направлено сообщение; iMsg- номер сообщения;
wParam- параметр сообщения;
lParam - параметр сообщения. Таким образом, с каждым сообщением функции передаются два параметра.
Мы не будем здесь вдаваться в подробности написания GUI-приложений на уровне Win32 API. Это довольно обширная тема, которая может увести нас в сторону от основной темы этой книги. Заинтересованный читатель может обратиться к ставшей классической книге Ч.Петзолда «Программирование для Windows 95», BHV – Санкт-Петербург, 1997. Вместо этого мы рассмотрим здесь пример простейшего GUI-приложения
#include <windows.h>
LRESULT CALLBACK
WindowFunc (HWND, UINT, WPARAM, LPARAM);
char *szWinName = "Простое okho";
int WINAPI WinMain(HINSTANCE hlnstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
HWND hWnd;
MSG msg;
WNDCLASS wcl;
//Заполняем структуру WNDCLASS
wcl.hlnstance = hlnstance;
wcl.lpszClassName = szWinName;
wcl.IpfnWndProc = WindowFunc;
wcl.style » 0;
wcl.hlcon = LoadIcon(NULL,
IDI_APPLICATION);
wcl.hCursor = LoadCursor(NULL, IDC_ARROW);
wcl.lpszMenuName = NULL;
wcl.cbClsExtra =0;
wcl.cbWndExtra = 0;
wcl.hbrBackground =
(HBRUSH) GetStockObject (WHITE_BRUSH) ;
//Зарегистрировать окно
if (!RegisterClass(&wcl)) return 0;
//Создать окно указанного класса
hWnd = CreateWindow(szWinName,
"Win32 API приложение",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFADLt,
HWND_DESKTOP, NULL,
hlnstance, NULL);
//отобразить окно и перерисовать его содержимое
ShowWindow(hWnd, nCmdShow) ;
UpdateWindow (hWnd) ;
//создать цикл обработки сообщений
while (GetMessage(&msg, NULL, 0,0))
{
//Разрешить обработку нажатий клавиш
TranslateMessage(&msg);
//Отправить сообщение нужному окну
DispatchMessage(&msg) ;
}
return msg.wParam; >
//Оконная функция
}
LRESULT CALLBACK WindowFunc(HWND hWnd, UINT iMsg,
WPARAM wParam, LP ARAM lParam)
{
switch (iMsg)
{
case WMJDESTROY: //Завершение работы программы
PostQuitMessage(0); break;
default: //Обработка всех остальных сообщений
return DeЈWindowProc(hWnd, iMsg, wParam, lParam);
}
return 0;
}
Прежде всего отметим, что все программы для Windows должны включать в себя файл <windows.h>. Этот файл содержит прототипы всех функций API, а также объявление типов данных, структур и макросов. Некоторые из объявленных в нем типов данных приведены в табл. 2.1. Упоминаемая в тексте примера структура WNDCLASS также объявлена в этом файле. Выполнение программы начинается с функции WinMain(), которой передается четыре параметра. Назначение этих параметров описано выше. Заметим здесь, что параметр hPrevInstance в Windows 95 и Windows NTвсегда равен NULL (В Windows 3.1 он мог принимать отличные от нуля значения, если ранее был запущен другой экземпляр данного приложения. Этот параметр сохранен только с целью совместимости). В рассматриваемом примере создается одно окно. С этой целью в функции WinMain() определяется и регистрируется класс окна. Имя класса окна определяется значением поля lpszClassName структуры WNDCLASS. В данном случае - это szWinName. Термин "класс окна" не следует путать с понятием "класс" языка С++. Класс окна характреризуется структурой WNDCLASS и не имеет ничего общего с объектно-ориентированным программированием. Ввиду особой важности этой структуры в программировании для Windows приведем здесь ее объявление:
Typedef struct_WNDCLASS
{
UINT style;
WNDPROC lpfnWndProc;
Int cbClsExtra;
Int cbWndExtra;
HANDLE hinstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCSTR lpszClassName;
} WNDCLASS;
Поля структуры имеют следующее назначение:
style - задает стиль (или стили) класса. Стили можно комбинировать с помощью побитовой операции "ИЛИ";
lpfnWndProc - указатель на оконную функцию, т.е.на функцию, которая будет обрабатывать сообщения, направляемые окну создаваемого класса;
cbClsExtra- задает число дополнительных байтов для класса, которые нужно распределить вслед за данной структурой.
Операционная система инициализирует эти байты значением 0;
cbWndExtra - задает число дополнительных байтов, которые дополнительно резервируются вслед за структурой окна и инициализируются операционной системой значением 0;
hInstance - дескриптор данного экземпляра приложения;
hIcon - дескриптор иконки, которая отображается при-минимизации окна данного класса;
hCursor - дескриптор курсора для окна данного класса;
hbrBackground - дескриптор кисти или значение цвета для закрашивания фона окна;
lpszMenuName - указатель на заканчивающуюся нулем строку, которая задает имя ресурса для меню данного окна. Если это поле равно NULL, окно не имеет меню;
lpszClassName - указатель на заканчивающуюся нулем строку, которая задает имя класса окна.
В нашем примере многие поля этой структуры проинициализированы значением 0. В качестве иконки окна задана стандартная иконка приложения Windows. Курсор окна имеет вид стрелки, а фон - закрашивается кистью белого цвета. Поле lpfnWndProc содержит указатель на функцию окна с именем WindowProc. Фактическую регистрацию класса окна в операционной системе выполняет функция RegisterClass(), которая возвращает ненулевое значение в случае успеха. После регистрации окна его можно создать. Эту задачу выполняет вызов функции CreateWindow(). Эта функция имеет следующий прототип:
HWND CreateWindow(LPCSTR lpClassName,
LPCSTR lpWindowName
DWORD dwStyle,
Int x,
Int y,
Int nWidth,
Int nHeight,
HWND hWndParent,
HMENU hMenu,
HANDLE hInstance,
LPVOID lpParam);
Назначение параметров:
lpClassName - указатель на заканчивающуюся нулем строку, задающую имя класса окна;
lpWindowName - указатель на заканчивающуюся нулем строку, задающую имя окна, появляющееся в его заголовке;
dwStyle - задает стиль создаваемого окна;
х - задает начальную позицию окна по горизонтали. Если этот параметр равен CW_USEDEFAULT, операционная система сама выбирает позицию по умолчанию и игнорирует значение параметра у;
y - задает начальную позицию окна по вертикали.
nWidth - задает ширину окна. Если этот параметр равен CW_USEDEFAULT, операционная система сама выбирает ширину окна по умолчанию. В этом случае значение параметра nHeight игнорируется;
nHeight - задает высоту окна;
hWndParent - задает дескриптор родительского окна или окна-владельца для создаваемого окна. Если этот параметр равен HWND_DESKTOP, создаваемое окно не имеет родительского;
hMenu - дескриптор меню или дочернего окна в зависимости от стиля окна. Если он равен ДОЬЬ, должно использоваться меню, заданное для всех окон данного класса;
hInstance - дескриптор приложения;
lpParam - указатель на структуру CREATESTRUCT; для клиентских окон многодокументного интерфейса этот параметр должен указывать на структуру CLIENTCREATESTRUCT.
Если функция завершается успешно, она возвращает дескриптор созданного окна. В противном случае она возвращает NULL.
В рассматриваемом примере создается окно класса szWinName с заголовком, содержащим строку "Заголовок окна". Координаты и размер окна определяются операционной системой. После создания окна оно, как правило, еще не отображается на экране. Для того, чтобы отобразить окно, следует вызвать функцию ShowWindow():
BOOL ShowWindow(HWND hWnd, int nCmdShow);
Параметр hWnd задает дескриптор окна, которое должно быть отображено, а параметр nCmdShow- способ отображения окна; он передается из функции WinMain(). Функция возвращает ненулевое значение, если до ее вызова окно отображалось на экране, иначе - ноль. Хотя это и не всегда нужно, тем не менее, мы включили в рассматриваемый пример вызов функции UpdateWindow(). Эта функция вызывает немедленную перерисовку окна.
Последней частью функции WinMain() является цикл обработки сообщений. Он реализован следующими строками программы:
//Создать цикл обработки сообщений
While(GetMessage(&msg, Null, 0, 0))
{
//Разрешить обработку нажатий клавиш
TranslateMessage(&msg);
//Отправить сообщение нужному окну
DispatchMessage(&msg)
}
Цикл обработки сообщений содержится во всех GUI-приложенияхWindows. Сообщения ставятся в очередь приложения операционной системой, а выбираются из нее функцией GetMessage():
BOOL
GetMessage(LPMSG msg, HWND hWnd, UINT min, UINT max);
Передаваемые этой функций сообщения сохраняются в переменной msg. Параметр hWnd задает дескриптор окна, которому направляются выбираемые сообщения. Если этот параметр равен NULL, функция выбирает из очереди все сообщения, адресованные приложению. Следующие два параметра определяют диапазон номеров получаемых сообщений. В примере эти параметры равны нулю. Это означает, что выбираются все сообщения. Если функция GetMessage() возвращает ноль, обработка сообщений прекращается. Это происходит при выходе из приложения. Внутри цикла сообщений вызываются две функции: функция DispatchMessage() направляет очередное сообщение оконной функции приложения, а функция TranslateMessage() транслирует виртуальные коды клавиш в клавиатурные сообщения. Вызов этой функции в цикле обработки сообщений не обязателен. Он нужен только в том случае, если в программе предусматривается ввод с клавиатуры. Как мы увидим впоследствии, для, ввода символьной информации Windows предоставляет специальные элементы интерфейса.
Рассмотрим теперь оконную функцию из этого примера. В нашем примере эта функция имеет имя WindowFunc(). В качестве параметров функции передаются первые четыре поля структуры MSG, которая хранит всю информацию о сообщении в системе. Эту структуру мы рассмотрим в следующем разделе, а здесь отметим, что наша оконная функция самостоятельно обрабатывает только одно сообщение –WM_DESTROY. Это сообщение посылается, когда нужно завершить работу программы. В ответ на это сообщение вызывается функция PostQuitMessage(). Параметр, передаваемый этой функции, определяет код возврата приложения.
Функция PostQuitMessage(), в свою очередь, посылает сообщение WM_QUIT в очередь сообщений приложения. Это сообщение будет выбрано из очереди в цикле обработки сообщений. При поступлении сообщения WM_QUIT функция GetMessage() возвратит ноль и произойдет выход из цикла обработки сообщений и завершение работы программы. Все другие сообщения в оконной функции обрабатываются стандартным образом путем передачи их функции обработки сообщений по умолчанию DefWindowProc(). Если оконная функция возвращает нулевое значение, это означает, что обработка сообщения завершена в ней самой, в противном случае возвращаемое значение зависит от обрабатываемого сообщения и определяется функцией DefWindowProc().
