Ціль лабораторної роботи - одержання практичних навичок у побудові базового додатка для Win32, дослідження параметрів віконних процедур.
Перед виконанням лабораторної роботи студент повинен знати: принципи й логіку роботи Windows-додатка; порядок і засоби формування структури класу вікна, реєстрації класу, написання віконної процедури, створення й відображення вікна, циклу обробки повідомлень.
Після виконання лабораторної роботи студент повинен уміти: розробляти базові процедурні Windows-додатки мовою C++.
Короткі теоретичні відомості
Розглянемо ситуацію, коли користувач додатка натискає клавішу, а система виробляє повідомлення про цю подію. Windows забезпечує підтримку клавіатури, що не залежить від типу пристрою (device-independent support). Для кожного типу клавіатури вона встановлює відповідний драйвер, тобто спеціальну програму, що служить посередником між клавіатурою й операційною системою. Клавіатурна підтримка Windows не залежить від мови спілкування із системою. Це досягається використанням спеціальної клавіатурної розкладки (layout), що користувач вибрав у цей момент. Кожній клавіші на рівні апаратур привласнене унікальне значення - ідентифікатор клавіші, що залежить від типу пристрою й називав скан-кодом.
Клавіатурний драйвер інтерпретує скан-код і перетворить його в
обумовлений Windows код віртуальної клавіші (virtual-key code), що не залежить від типу пристрою й ідентифікуючий функціональний зміст клавіші. Після цього перетворення скан-кода драйвер створює повідомлення, у яке включає: скан-код, віртуальний код й іншу супутню інформацію. Потім він поміщає повідомлення в спеціальну чергу системних повідомлень. Windows вибирає повідомлення із цієї черги й посилає в чергу повідомлень відповідного потоку (thread). Зрештою, цикл вибірки повідомлень даного потоку передає його відповідній віконній процедурі для обробки. Модель уведення із клавіатури в системі Windows представлена на Рис.6.1.
Рис.6.1. Модель уведення із клавіатури в системі Windows
Тут буфер клавіатури служить сполучною ланкою між прикладною програмою й одним із сервисiв ОС. Так само формують (або можуть формуватися) свої специфічні дані оброблювачі інших подій. При цьому використовується універсальна структура даних MSG (повідомлення), що описує будь-яку подію. Вона містить супровідну інформацію, достатню для того, щоб повідомленням можна було скористатися. Наприклад, для повідомлення від клавіатури це повинен бути код натиснутої клавіші, для повідомлення від миші - координати її покажчика, для повідомлення WM_SIZE - розміри вікна.
Кожен оброблювач події (драйвер) поміщає сформоване повідомлення в певну динамічну структуру даних у пам'яті. Інші апаратні й програмні оброблювачі точно так само формують свої повідомлення, ставлячи їх у чергу за вже існуючими. Так формується системна черга повідомлень.
Розглянута модель вироблення й проходження повідомлень допомагає зрозуміти структуру, прийняту для всіх Windows-додатків. Останні два блоки в розглянутій схемі (мал.1) визначають особливості будови будь-якого Windows-додатка. Найпростіше з них повинне складатися як мінімум із двох функцій:
- функції WinMain, з якої починається виконання програми і яка "закручує" цикл очікування повідомлень (message pump);
- віконної процедури, що викликає система, направляючи їй відповідні повідомлення.
Кожен додаток у системі, заснованої на повідомленнях, повинне вміти одержувати й обробляти повідомлення зі своєї черги. Основу такого додатка й системі Windows представляє функція WinMain, що містить стандартну послідовність дій. Однак обробляється більшість повідомлень вікном - об'єктом операційної системи Windows.
З погляду користувача, вікно - це прямокутна область екрана, що відповідає якомусь додатку або його частині. Додаток може управляти декількома вікнами, серед яких звичайно виділяють одне головне вікно (Frame Window).
З погляду операційної системи, вікно - це в більшості випадків кінцевий пункт, якій направляються повідомлення.
З погляду програміста, вікно - це об'єкт, атрибути якого (тип, розмір, положення на екрані, вид курсору, меню, значок, заголовок) повинні бути спочатку сформовані, а потім зареєстровані системою.
Маніпуляція вікном здійснюється за допомогою спеціальної віконної функції, що має цілком певну, устояну структуру.
Функція WinMain() виконується першої в будь-якому додатку. Її ім'я зарезервоване операційною системою. Ім'я віконної процедури довільно й вибирається розроблювачами. Система Windows реєструє це ім'я, зв'язуючи його з додатком.
Таким чином, головною метою функції WinMain() є:
- реєстрація віконного класу;
- створення вікна;
- запуск циклу очікування повідомлень.
Далі розглянемо більш докладно структуру традиційного Windows-додатка, що повинне бути взяте за основу при рішенні свого варіанта завдання.
// Визначає крапку входу додатка
#include <windows.h>
//=== Глобальні змінні:
HINSTANCE hInst; //Дескриптор додатка
LPCTSTR lpszAppName = "MyApp"; //Покажчик на рядок, що містить
//ім'я вікна
LPCTSTR lpszTitle = "My Programm"; //Текст заголовка вікна
LPCTSTR lpszClassName = "Hello";
//=======Прототипи функцій, що входять у даний модуль
int APIENTRY WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
MSG msg;
HWND hWnd;
// Реєстрація віконного класу
WNDCLASSEX wc;
wc.style = CS_HREDRAW | CS_VREDRAW; //стиль вікна
wc.lpfnWndProc = (WNDPROC)WndProc; //віконна процедура
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance; //опис додатка
wc.hIcon = LoadIcon( hInstance, lpszAppName );//визначення іконки
wc.hCursor = LoadCursor(NULL, IDC_ARROW); //визначення курсору
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);//установка тла
wc.lpszMenuName = lpszAppName; //визначення меню
wc.lpszClassName = lpszClassName; //імена класу вікна
wc.cbSize = sizeof(WNDCLASSEX); //розмір структури в байтах
wc.hIconSm = NULL; //дескриптор піктограми
if ( !RegisterClassEx( &wc ) )
return( FALSE );
// Запам'ятовування дескриптора (хэндла) додатка
hInst = hInstance;
//======= Створення головного вікна
hWnd = CreateWindow
(lpszClassName, //ім'я класу вікна
lpszTitle, //ім'я додатка
WS_OVERLAPPEDWINDOW, //стилі вікна
CW_USEDEFAULT, //положення по горизонталі верхнього лівого кута
CW_USEDEFAULT, //положення по вертикалі верхнього лівого кута
CW_USEDEFAULT, //ширина вікна
CW_USEDEFAULT, //висота вікна
NULL, //дескриптор батьківського вікна
NULL, //дескриптор меню вікна
hInstance, //дескриптор додатка
NULL //покажчик на додаткові параметри
);
if ( !hWnd )
return( FALSE );
//======= Показ вікно
ShowWindow( hWnd, nCmdShow );
//======= Відновлення вікна
UpdateWindow( hWnd );
//===== Цикл очікування й обробки повідомлень
while( GetMessage( &msg, NULL, 0, 0) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
return( msg.wParam );
}
// FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
// ПРИЗНАЧЕННЯ: Обробка повідомлень головного вікна.
// WM_CREATE - повідомлення ініціалізації при створенні вікна
// WM_COMMAND - обробка команд меню
// WM_DESTROY - посилка повідомлення про завершення й вихід
LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch( uMsg )
{
case WM_CREATE: //повідомлення ініціалізації
break;
case WM_COMMAND : //повідомлення від меню, гарячих клавіш і т.д.
//====== Розшифровка вибору в меню:
switch( LOWORD( wParam ) )
{
case IDM_TEST :
{
//====== Сюди міститься код реакції на вибір пункту меню
}
break;
case IDM_EXIT :
DestroyWindow( hWnd );
break;
}
break;
case WM_DESTROY : // Повідомлення закриття вікна
PostQuitMessage(0);
break;
//обробка повідомлень, які не оброблені користувачем
default :
return( DefWindowProc( hWnd, uMsg, wParam, lParam ) );
}
return (FALSE);
}
Особливість першої лабораторної роботи полягає у варіюванні параметрами функцій реєстрації й створення вікна, віконної процедури для рішення індивідуального завдання.
До таких параметрів ставляться:
1. Вид створюваного вікна на екрані монітора.
2. Стиль класу вікна.
3. Системні піктограми (іконки).
4. Системні курсори миші.
5. Стиль вікна.
Розглянемо їх докладніше.
1. Вид створюваного вікна описується в останньому параметрі функції WinMain(), а також у другому параметрі функції показу вікна ShowWindow(). Можливі значення задаються виходячи з таблиці 6.1.
Таблиця 6.1
Можливі значення другого параметра функції ShowWindow()
Параметр | Значення | Опис |
SW_HIDE | Вікно сховане | |
SW_SHOWNORMAL | Вікно показане в його нормальних розмірах | |
SW_NORMAL | ||
SW_SHOWMINIMIZED | Вікно згорнуте й показане як піктограма | |
SW_SHOWMAXIMIZED | Вікно розгорнуте | |
SW_MAXIMIZE | ||
SW_SHOWNOACTIVE | Вікно відображається в його розмірах і позиції, установлених безпосередньо перед поточними значеннями розмірів і позиції. Активне вікно залишається активним | |
SW_SHOW | Вікно відображається в його поточних розмірах і позиції. | |
SW_MINIMIZE | Вікно згорнуте й активізує вікно верхнього рівня в списку системи | |
SW_SHOWMINNOACTIVE | Вікно згорнуте. Активне вікно залишається активним | |
SW_SHOWNA | Вікно показане в його поточному стані. Активне вікно залишається активним | |
SW_RESTORE | Активізувати й відобразити вікно. Якщо вікно згорнуте або розгорнуте, йому будуть повернуті його первісні розміри й позиція. | |
SW_SHOWDEFAULT | Застосовується при запуску додатка за замовчуванням |
2. Найменування стилів класу вікна починається з ідентифікаторів CS_. Для стилю вікна відведено 16 битов і тільки один із цих битов установлений в одиницю. Таким чином, стилі використаються як бітові прапори, тобто із цими стилями можна робити операції логічного додавання й логічного множення для одержання комбінованих стилів. Перелік прапорів наведений у табл.6.2.
Таблиця 6.2