Партнерка на США и Канаду по недвижимости, выплаты в крипто
- 30% recurring commission
- Выплаты в USDT
- Вывод каждую неделю
- Комиссия до 5 лет за каждого referral
Как же такое сложное поведение обеспечивается всего шестью строками исходного текста? Суть скрыта в понятиях цикл обработки сообщений и оконная процедура. В данном простейшем приложении не видно ни того, ни другого. Приложение создает стандартное диалоговое окно, внутри которого скрыта реализация наблюдаемого поведения. Поэтому для ясного понимания структуры этих компонент приложения следует рассмотреть более сложный пример.
2. Приложение с циклом обработки сообщений
В программе 2.1 практически вся функциональность приложения сосредоточена (и скрыта) внутри функции MessageBox. Для лучшего понимания структуры приложения сделаем реализацию поведения видимой, другими словами, создадим окно, которым будем управлять сами, а не доверять это функции MessageBox.
Окно новой версии hello. cpp показано на рис. 2.2. Теперь слова "Hello, World!" выводятся как надпись на кнопке, занимающей всю клиентскую область окна (они также появляются в строке заголовка окна).

Рис. 2.2. Приложение "Hello, World!" с собственным циклом обработки сообщений.
"Типичное" приложение Windows в процессе инициализации сначала регистрирует новый оконный класс для своего главного окна. Затем приложение создает свое главное окно. Сейчас пока не будем регистрировать новый оконный класс, а используем один из стандартных оконных классов, BUTTON ("Кнопка"). Поведение этого класса не позволит в точности повторить приложение из п.1. В данный момент это не важно, главное, что в приложении можно будет увидеть назначение цикла обработки сообщений (программа 2.2).
#include <windows. h>
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE d2, LPSTR d3, int d4 )
{
HWND hwnd;
hwnd = CreateWindow( "BUTTON", "Hello, World!",
WS_VISIBLE | BS_CENTER, 100, 100, 100, 80,
NULL, NULL, hInstance, NULL );
MSG msg;
while ( GetMessage( &msg, NULL, 0, 0 ) )
{
if ( msg. message == WM_LBUTTONUP )
{
DestroyWindow( hwnd );
PostQuitMessage( 0 );
}
DispatchMessage( &msg );
}
return msg. wParam;
}
Программа 2.2. Приложение "Hello, World!" с циклом обработки сообщений.
В данном примере виден цикл обработки сообщений. После создания окна программа входит в цикл while, в котором выполняется вызов функции Windows API для получения очередного сообщения – GetMessage. Эта функция возвращает значение FALSE только при получении сообщения WM_QUIT о завершении приложения. В цикле обрабатывается единственное сообщение, WM_LBUTTONUP, об отпускании левой кнопки мыши. Функция DestroyWindow уничтожает окно приложения, а PostQuitMessage посылает приложению сообщение WM_QUIT. Поэтому при очередном вызове GetMessage цикл обработки сообщений завершится. Все сообщения, кроме WM_LBUTTONUP, передаются функции DispatchMessage.
Диспетчеризация с помощью функции DispatchMessage означает передачу сообщений в оконную процедуру, "по умолчанию" приписанную оконному классу BUTTON. Как и в случае функции MessageBox, содержание оконной процедуры "по умолчанию" скрыто, т. к. она является частью операционной системы.
Обратите внимание, что приложение из п.1 завершает работу, только если указатель в момент отпускания левой кнопки находится над кнопкой. В новой версии приложения выход из программы осуществляется по сообщению об отпускании левой кнопки, независимо от положения указателя.
Рассмотренный пример не продемонстрировал строение оконной процедуры. Поэтому еще раз усложним "Hello, World!", чтобы в этом приложении был виден и цикл обработки сообщений, и оконная процедура.
3. Приложение с циклом обработки сообщений и оконной процедурой
Новая версия hello. cpp (программа 2.3) регистрирует собственный оконный класс. Это делается частично для косметических улучшений (чтобы отказаться от неестественного применения класса BUTTON для вывода сообщения), но главным образом для того, чтобы установить собственную оконную процедуру.

Рис. 2.3. Версия приложения "Hello, World!" с собственным оконным классом.
#include <windows. h>
void DrawHello( HWND hwnd )
{
PAINTSTRUCT paintStruct;
HDC hDC = BeginPaint( hwnd, &paintStruct );
if ( hDC!= NULL )
{
RECT clientRect;
GetClientRect( hwnd, &clientRect );
DPtoLP( hDC, (LPPOINT)&clientRect, 2 );
DrawText( hDC, "Hello, World!", -1, &clientRect,
DT_CENTER | DT_VCENTER | DT_SINGLELINE );
EndPaint( hwnd, &paintStruct );
}
}
LRESULT CALLBACK WndProc( HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam )
{
switch(uMsg)
{
case WM_PAINT : DrawHello( hwnd ); break;
case WM_DESTROY : PostQuitMessage( 0 ); break;
default : return DefWindowProc( hwnd, uMsg, wParam, lParam );
}
return 0;
}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR d3, int nCmdShow )
{
if ( hPrevInstance == NULL )
{
WNDCLASS wndClass;
memset( &wndClass, 0, sizeof(wndClass) );
wndClass. style = CS_HREDRAW | CS_VREDRAW;
wndClass. lpfnWndProc = WndProc;
wndClass. hInstance = hInstance;
wndClass. hCursor = LoadCursor( NULL, IDC_ARROW );
wndClass. hbrBackground = (HBRUSH)( COLOR_WINDOW + 1 );
wndClass. lpszClassName = "HELLO";
if ( !RegisterClass( &wndClass ) )
return FALSE;
}
HWND hwnd;
hwnd = CreateWindow( "HELLO", "HELLO", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
NULL, NULL, hInstance, NULL );
ShowWindow( hwnd, nCmdShow );
UpdateWindow( hwnd );
MSG msg;
while( GetMessage( &msg, NULL, 0, 0 ) )
DispatchMessage( &msg );
return msg. wParam;
}
Программа 2.3. Приложение "Hello, World!" с собственным оконным классом.
Новая версия приложения содержит примерно 60 строк исходного текста. Но оно выглядит как "полноценное" Windows-приложение (рис. 2.3), у которого есть системное меню, окно которого можно перемещать, изменять размер, сворачивать и разворачивать, оно умеет перерисовывать себя, реагировать на команду меню Закрыть и на комбинацию клавиш Alt+F4.
Как и раньше, выполнение программы начинается с функции WinMain. Сначала приложение проверяет, есть ли уже запущенный экземпляр данного приложения. Если есть, то оконный класс повторно регистрировать не надо. Иначе выполняется регистрация оконного класса, свойства и поведение которого описываются с помощью структуры WNDCLASS. В переменную lpfnWndProc этой структуры помещается адрес оконной процедуры. В нашем примере это будет функция WndProc.
Далее, вызывается функция CreateWindow для создания окна. После вывода окна на экран WinMain входит в цикл обработки сообщений. Этот цикл завершится, когда GetMessage вернет FALSE в результате получения сообщения WM_QUIT.
Функция WndProc демонстрирует назначение и структуру оконной процедуры, которая не была видна в предыдущих версиях "Hello, World!". Типичная оконная процедура на языке Си состоит из большого оператора switch. В зависимости от полученного сообщения, из этого оператора вызываются различные функции для обработки конкретных сообщений. В нашем примере обрабатываются только два сообщения: WM_PAINT и WM_DESTROY.
Сообщение WM_PAINT требует от приложения частично или полностью перерисовать содержимое окна. Большинство приложений перерисовывают только те области окна, которые нуждаются в перерисовке. В нашем случае, для простоты, на каждое сообщение WM_PAINT всегда выполняется вывод всей строки "Hello, World!".
Сообщение WM_DESTROY поступает в результате действий пользователя, которые приводят к уничтожению окна приложения. В качестве реакции наше приложение вызывает функцию PostQuitMessage. Т. о. гарантируется, что функция GetMessage в WinMain получит сообщение WM_QUIT и главный цикл обработки сообщений завершится.
Сообщения, которые не обрабатываются нашей оконной процедурой, с помощью функции DefWindowProc передаются в оконную процедуру по умолчанию. Эта функция реализует поведение окна приложения и многих компонент его неклиентской области (например, строки заголовка).
4. Регистрация оконного класса и создание окна
4.1 Функция RegisterClass и структура WNDCLASS
Оконный класс задает общее поведение окон нового типа, главное, он содержит адрес оконной процедуры. Для регистрации нового оконного класса предназначена функция:
ATOM RegisterClass( CONST WNDCLASS* lpwc );
Единственный параметр этой функции, lpwc, является указателем на структуру типа WNDCLASS, описывающую новый тип окна. Возвращаемое значение имеет тип Windows atom, это 16-разрядное число, являющееся идентификатором уникальной символьной строки в служебной внутренней таблице Windows. Структура WNDCLASS имеет следующее описание:
typedef struct _WNDCLASS {
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HANDLE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
} WNDCLASS;
Смысл некоторых переменных очевиден. Например, hIcon является дескриптором пиктограммы, используемой для отображения окон данного класса в свернутом виде. hCursor – это дескриптор стандартного указателя мыши, который устанавливается при перемещении указателя над областью окна; hbrBackground – дескриптор кисти (это объект модуля GDI), применяемой для рисования фона окна. Cтрока lpszMenuName является идентификатором ресурса меню (символьное имя меню или целочисленный идентификатор, присваиваемый с помощью макроса MAKEINTRESOURCE), которое будет стандартным верхним меню для окон данного класса. Строка lpszClassName является именем оконного класса.
|
Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |


