Komunikaty Windows
Jacek Matulewski
20 lutego 2012 Programowanie Windows
http://www.fizyka.umk.pl/~jacek/dydaktyka/winprog_v2/
Komunikaty Windows
• Komunikaty Windows (ang. Windows messages) to
mechanizm przekazywania informacji od systemu do aplikacji (ew. między aplikacjami) – układ nerwowy Windows
• Przykładowe komunikaty:
WM_LBUTTONDOWN, WM_LBUTTONUP WM_MOUSEMOVE, WM_NCMOUSEMOVE,
WM_KEYDOWN, WM_KEYUP, WM_KEYCHAR, WM_DROPFILES, WM_CLOSE, WM_PAINT WM_DISPLAYCHANGE, WM_DEVICECHANGE WM_QUERYENDSESSION, WM_ENDSESSION, WM_SYSCOMMAND, WM_USER
• http://www.autohotkey.com/docs/misc/SendMessageList.htm
Pętla główna
• Każda aplikacja Windows musi mieć funkcję zwrotną (ang.
callback) o nazwie WinMain. W niej umieszcza się pętlę główną aplikacji, której zasadniczym zadaniem jest odbieranie
komunikatów z kolejki komunikatów aplikacji.
WPARAM Run() {
MSG msg;
while(GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
Pętla główna
• Każda aplikacja Windows musi mieć funkcję zwrotną (ang.
callback) o nazwie WinMain. W niej umieszcza się pętlę główną aplikacji, której zasadniczym zadaniem jest odbieranie
komunikatów z kolejki komunikatów aplikacji.
WPARAM Run() {
MSG msg;
while(GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
Zwraca 0 tylko dla WM_QUIT; alt. PeekMessage typedef struct tagMSG
{
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG, *PMSG, *LPMSG;
Przekształcanie komunikatów (klawiatury)
Rozsyłanie komunikatów do okien-adresatów (w tym kontrolek)
Obsługa komunikatu
• Etap 1:
Działanie użytkownika lub sytuacja w systemie
System tworzy strukturę komunikatu MSG z numerem WM_
Wysyła komunikat do adresata (okno aplikacji lub jego dziecko)
• Etap 2:
Struktura zostaje umieszczona w kolejce komunikatów aplikacji Istnieje jednak możliwość pominięcia kolejki i przesłania
bezpośrednio do okna-adresata (kontrolki).
Komunikat może być też rozsyłany do wszystkich okien (ang. broadcast)
• Etap 3:
Aplikacja odbiera komunikat z kolejki i przesyła do właściwego pod-okna – a właściwie do tzw. procedury okna WndProc.
• Procedura okna to funkcja zwrotna wskazywana w momencie rejestracji klasy okna, która jest wywoływana w momencie otrzymania przez okno komunikatu.
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam) { switch (uMsg)
{
case WM_SIZE:
{
int width = LOWORD(lParam);
int height = HIWORD(lParam);
OnSize(hwnd, (UINT)wParam, width, height);
}
break;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
Procedura okna
• Procedura okna to funkcja zwrotna wskazywana w momencie rejestracji klasy okna, która jest wywoływana w momencie otrzymania przez okno komunikatu.
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam) { switch (uMsg)
{
case WM_SIZE:
{
int width = LOWORD(lParam);
int height = HIWORD(lParam);
OnSize(hwnd, (UINT)wParam, width, height);
}
break;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
Procedura okna
W kodzie C++ okno zazwyczaj reprezentowane jest przez klasę ze zdefiniowaną metodą WndProc:
LRESULT CALLBACK WndProc(HWND hWnd,UINT message,
WPARAM wParam,LPARAM lParam) {
return okno.WndProc(hWnd,message,wParam,lParam);
}
Filtrowanie komunikatów
LOWORD i HIWORD – makra:
#define HIWORD(l) ((WORD)((DWORD_PTR)(l) >> 16))
#define LOWORD(l) ((WORD)((DWORD_PTR)(l) & 0xFFFF)) OnSize to zdefiniowana przez nas funkcja dedykowana do obsługi komunikatu WM_SIZE
Funkcja DefWindowProc wywołuje domyślną procedurę okna obsługującą wszystkie te komunikaty, które nas nie interesują (bez tego zamiast okna pojawia się tylko biała plama!).
„Def” od default, a nie od definition.
hwnd – uchwyt okna, czyli jednoznaczny identyfikator w danej sesji systemu
Odczytywanie danych z kom.
• Komunikaty zwykle przekazują dodatkowe informacje o zdarzeniu (parametry lParam i wParam).
• Przykład zdarzeń związanych z myszką:
wchar_t txt_x[256];
wchar_t txt_y[256];
_itow_s(LOWORD(lParam),txt_x,256,10);
_itow_s(HIWORD(lParam),txt_y,256,10);
edit1.SetWindowText(txt_x);
edit2.SetWindowText(txt_y);
Odczytywanie danych z kom.
• Komunikaty zwykle przekazują dodatkowe informacje o zdarzeniu (parametry lParam i wParam).
• Odczytanie klawiatury:
BOOL CKomunikatyDlg::PreTranslateMessage(MSG* pMsg) {
//tu nie bedzie WM_CHAR
if (pMsg->message == WM_KEYDOWN &&
pMsg->wParam == VK_ESCAPE) {
Beep(300,200);
} ...
Wysyłanie komunikatów
• Uwaga!
Standardowe funkcje WinAPI mają opakowania w klasie
CWnd (MFC), które często „przesłaniają” zasadnicze funkcje.
• Wysyłanie komunikatów: PostMessage vs SendMessage.
Pierwsza wysyła komunikat tradycyjnie tj. do kolejki
komunikatów okna/kontrolki, druga – pomija kolejkę i wysyła bezpośrednio do okna/kontrolki.
this->PostMessage(WM_CLOSE); //metoda klasy CWnd
::PostMessage( //funkcja czystego WinAPI this->m_hWnd, //uchwyt okna-adresata
WM_CLOSE, //identyfikator komunikatu 0,0); //lParam i wParam
Wysyłanie komunikatów
• Uwaga!
Standardowe funkcje WinAPI mają opakowania w klasie
CWnd (MFC), które często „przesłaniają” zasadnicze funkcje.
• Wysyłanie komunikatów: PostMessage vs SendMessage.
Pierwsza wysyła komunikat tradycyjnie tj. do kolejki
komunikatów okna/kontrolki, druga – pomija kolejkę i wysyła bezpośrednio do okna/kontrolki.
this->SendMessage(WM_SYSCOMMAND,SC_SCREENSAVE,0);
::SendMessage(
this->m_hWnd, WM_SYSCOMMAND,
SC_SCREENSAVE,0); Niektóre aplikacje pozwalają na ich kontrolowanie za pomocą komunikatów (np. WinAmp i Adobe).
Znajdywanie uchwytu okna
• Uchwyty okien (w tym kontrolek) można szukać korzystając z funkcji FindWindow podając tytuł okna lub nazwę jego klasy (zob. też FindWindowEx):
::PostMessage(
::FindWindow(NULL,L"Komunikaty"), WM_CLOSE,
0,0);
• Przeszukiwanie okien w poszukiwaniu tych o konkretnych własnościach: EnumWindow i EnumChildWindows
• WindowFromPoint, ChildWindowFromPoint
• GetDesktopWindow, GetForegroundWindow, GetNextWindow, IsWindow, IsWindowVisible
Haki
• Można napisać bibliotekę DLL, która będzie ładowana do przestrzeni adresowej aplikacji w momencie np. wystąpienia zdarzenia związanego z klawiaturą lub myszą
(po zarejestrowaniu tzw. haka – ang. hook).
W takiej sytuacji nastąpi wywołanie funkcji zdefiniowanej w bibliotece DLL (potencjalnie niebezpieczne! - podsłuch).