МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ
Дніпропетровський національний університет залізничного транспорту імені академіка В. Лазаряна
Лабораторна робота №5
з предмету: «Операційні системи»
на тему: «Вивчення механізму повідомлень ОС Windows»
Вивчення механізму повідомлень ОС Windows
Мета роботи:
- вивчити організацію Win32 GUI додатки;
- ознайомитися з механізмом повідомлень Windows (види повідомлень, способи і засоби обміну повідомленнями, програми обробки повідомлень, черги повідомлень)
- отримати практичні навики програмування передачі і обробки повідомлень;
- ознайомитися з особливостями межпроцессной і міжпоточної передачі повідомлень;
- отримати практичні навики межпроцессного обміну даними за допомогою апарату повідомлень.
Короткі теоретичні відомості
Windows використовує для передачі повідомлення окну чергу повідомлень. Кожен потік має свою чергу повідомлень. Потік повинен переглядати свою чергу повідомлень і направляти повідомлення на обробку відповідному вікну. Для цього потік повинен організувати цикл обробки повідомлень, що складається з функцій:
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
int GetMessage(
LPMSG lpMsg,
HWND hWnd,
UINT wMsgFilterMin,
UINT wMsgFilterMax
);
Функція витягує повідомлення з черги. Вона приймає наступні параметри:
LPMSG lpMsg – покажчик на структуру повідомлення, в яку GetMessage поверне результат.
HWND hWnd – описувач вікна, від якого GetMessage прийме повідомлення (NULL означає, що GetMessage приймає повідомлення від всіх вікон, що належать потоку).
UINT wMsgFilterMin – найменший ідентифікатор повідомлення, яке прийме GetMessage.
UINT wMsgFilterMax – найбільший ідентифікатор повідомлення, яке прийме Getmessage (якщо в значеннях параметрів wMsgFilterMin і wMsgFilterMax передати 0, функція прийматиме ВСІ повідомлення).
Функція GetMessage не віддає управління програмі, поки не прийде яке-небудь повідомлення. Якщо повідомлення, що прийшло, – Wm_quit, функція GetMessage поверне 0. Тоді цикл урветься, і програма завершить свою роботу. При будь-якому іншому повідомленні функція GetMessage повертає значення більше нуля, і начинатся виконання тіла циклу. При помилці GetMessage повертає -1.
BOOL TranslateMessage(
CONST MSG *lpMsg
);
Функція переводить повідомлення формату віртуальних клавіш в повідомлення символи.
lpMsg - це структура отримана в результаті виклику функцій GetMessage().
Функція поверне значення відмінне від нуля у випадку, якщо переведення вироблене. Якщо повідомлення типа WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, або WM_SYSKEYUP, то повертане значення завжди відмінне від нуля. Ця функція не змінює структуру MSG, а додає нові повідомлення.
LRESULT DispatchMessage(
CONST MSG * lpMsg
);
Функція пересилає повідомлення віконної процедури. lpmsg - це структура отримана в результаті виклику функцій GetMessage(). Повертане значення є тим, яке поверне віконна процедура. Але зазвичай це значення ігнорується.
Для постановки повідомлення в чергу використовується функція PostMessage() або функція SendMessage().Потік, що викликав SendMessage()припиняється до завершення обробки повідомлення.
Є два принципово різних способу посилки повідомлень: синхронний (send) і асинхронний (post). Посилаючи повідомлення синхронно, відправник чекає закінчення його обробки, перш ніж продовжити роботу. Асинхронна посилка нагадує опускання листа в поштову скриньку: опустив і забув. Система синхронним способом посилає вікну повідомлення про створення, зміну стану і закриття (наприклад, WM_CREATE, WM_ACTIVATE, WM_SETFOCUS, WM_SETCURSOR, WM_DESTROY) а також багато інших повідомлень. До асинхронних повідомлень відносяться повідомлення від клавіатури і миші, з деякою обмовкою до них можна віднести також WM_PAINT і WM_TIMER. Програма користувача може посилати будь-які повідомлення синхронним або асинхронним способом, як визнає потрібним розробник.
Асинхронна посилка повідомлень, тобто приміщення повідомлення в чергу повідомлень, може бути виконана за допомогою однієї з наступних функції:
BOOL PostMessage(
HWND hWnd, // описувач вікна
UINT Msg, // тип сообщения
WPARAM wParam, // перший параметр повідомлення
LPARAM lParam // другий параметр повідомлення
);
Синхронна посилка виконується за допомогою функції:
LRESULT SendMessage(
HWND hWnd, // Описатель окна-приемника
UINT Msg, // тип повідомлення
WPARAM wParam, // перший параметр повідомлення
LPARAM lParam // другий параметр повідомлення
);
Для посилки більших за об’ємом повідомлень використовивають WM_COPYDATA, а також оскільки кожен процес має власний адресний простір, то при передачі даних за допомогою повідомлень необхідно створити ділянку пам'яті, що розділяється, і використовувати її.
Текст програми:
Прога1
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "prog.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
if(!FindWindow(0,"Two")){
StatusImage->Canvas->Brush->Color=clRed;
actFlag=false;
}else{
StatusImage->Canvas->Brush->Color=clLime;
actFlag=true;
}
StatusImage->Canvas->Rectangle(0,0,StatusImage->Width,StatusImage->Height);
}
//---------------------------------------------------------------------------
void TForm1::MsgP(TMessage &Msg){
COPYDATASTRUCT *data = PCOPYDATASTRUCT(Msg.LParam);
if(data->dwData==1){
actFlag=true;
StatusImage->Canvas->Brush->Color=clLime;
StatusImage->Canvas->Rectangle(0,0,Form1->StatusImage->Width,Form1->StatusImage->Height);
}else if(data->dwData==2){
actFlag=false;
StatusImage->Canvas->Brush->Color=clRed;
StatusImage->Canvas->Rectangle(0,0,Form1->StatusImage->Width,Form1->StatusImage->Height);
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::GoButtonClick(TObject *Sender)
{
if(!actFlag){
ShowMessage("Второе приложение не запущено!");
return;
}
COPYDATASTRUCT data;
data.dwData=0;
data.cbData=MessEdit->Text.Length();
data.lpData=MessEdit->Text.c_str();
HWND Two=FindWindow(0,"Two");
SendMessage(Two, WM_COPYDATA, WPARAM(&data), LPARAM(&data));
}
//---------------------------------------------------------------------------
Прога2
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "progr2.h"
#include <windows.h>
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TTwo *Two;
//---------------------------------------------------------------------------
__fastcall TTwo::TTwo(TComponent* Owner)
: TForm(Owner)
{
COPYDATASTRUCT data;
data.dwData=1;
data.cbData=0;
data.lpData=0;
HWND One=FindWindow(0,"One");
SendMessage(One, WM_COPYDATA, WPARAM(&data), LPARAM(&data));
}
//---------------------------------------------------------------------------
void __fastcall TTwo::FormClose(TObject *Sender, TCloseAction &Action)
{
COPYDATASTRUCT data;
data.dwData=2;
data.cbData=0;
data.lpData=0;
HWND One=FindWindow(0,"One");
SendMessage(One, WM_COPYDATA, WPARAM(&data), LPARAM(&data));
}
//---------------------------------------------------------------------------
void TTwo::MsgP(TMessage &Msg){
COPYDATASTRUCT *data = PCOPYDATASTRUCT(Msg.LParam);
char *text=new char[data->cbData];
StrCopy(text, (char*)data->lpData);
text[data->cbData]='\0';
this->MesEdit->Text=text;
}
Результати виконання програми
/
Висновок: під час виконання даної лабораторної роботи було ознайомлено з механізмом повідомлень Windows (види повідомлень, способи і засоби обміну повідомленнями, черги повідомлень).