Дослідження структури windows-додатка

 

Ціль лабораторної роботи - одержання практичних навичок у побудові базового додатка для 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