180 likes | 298 Views
Programowanie Windows. Komunikaty Windows. Jacek Matulewski 22 września 2012. http://www.fizyka.umk.pl/~jacek/dydaktyka/winprog/. Zaliczenie. Lab.: projekt (obowiązkowy) Wybór z listy do końca października Własny po mojej akceptacji
E N D
Programowanie Windows Komunikaty Windows Jacek Matulewski 22 września 2012 http://www.fizyka.umk.pl/~jacek/dydaktyka/winprog/
Zaliczenie Lab.: projekt (obowiązkowy)Wybór z listy do końca październikaWłasny po mojej akceptacji Lab.: referat lub kolokwium (pisanie kodu)Wybór tematu referatu z listy do końca wrześniaReferat na lab. („ręce na klawiaturze”) lub na wykładziePrezentacja (ppt/pdf) + 2 pytania Wykład: egzaminTeoretyczny (bez programowania na żywo)
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_LBUTTONUPWM_MOUSEMOVE, WM_NCMOUSEMOVE,WM_KEYDOWN, WM_KEYUP, WM_KEYCHAR,WM_DROPFILES, WM_CLOSE, WM_PAINTWM_DISPLAYCHANGE, WM_DEVICECHANGEWM_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 typedef struct tagMSG { HWND hwnd; UINT message; WPARAM wParam; LPARAM lParam; DWORD time; POINT pt; } MSG, *PMSG, *LPMSG; • 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 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 systemieSystem 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 aplikacjiIstnieje 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 po otrzymaniu 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); } hwnd – uchwyt okna, czyli jednoznaczny identyfikator w danej sesji systemu Filtrowanie komunikatów 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;} 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.
Funkcja PreTranslateMessage (MFC) • Funkcja WindowProc uruchamiana jest dla ostatecznego okna-adresata (po rozdzieleniu w pętli obsługi komunikatów). • Jeżeli kontrolka (np. ListBox) przesłania część okna, to funkcja ta nie będzie „widzieć” komunikatów o ruchu myszy, gdy mysz jest nad kontrolką! • Do odczytu wszystkich komunikatów, jeszcze przed rozesłaniem ich do poszczególnych kontrolek/okien służy metoda CWnd::PreTranslateMessage wywoływana przed TranslateMessage w pętli głównej okna MFC.BOOL CKomunikatyDlg::PreTranslateMessage(MSG* pMsg) { if(pMsg->message == WM_KEYDOWN) Beep(100,10); return CDialogEx::PreTranslateMessage(pMsg);}
Demo (MFC) • Aplikacja MFC wyświetlająca komunikaty odbierane z kolejki komunikatów w liście ListBox. • Co się stanie, gdy „odetniemy” komunikaty (zablokujemy ich obsługę przez aplikację usuwając wywołanie funkcji DefWindowProc)?
Mapowanie komunikatów (MFC) W MFC metody można związać z komunikatami za pomocą mechanizmu mapowania komunikatów (domyślny sposób obsługi komunikatów przeznaczonych dla kontrolek w VS):BEGIN_MESSAGE_MAP(CKomDlg, CDialogEx) ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BUTTON1, &CKomDlg::OnBnClickedButton1) ON_BN_CLICKED(IDC_BUTTON2, &CKomDlg::OnBnClickedButton2) ON_BN_CLICKED(IDC_RADIO1, &CKomDlg::OnBnClickedRadio1) ON_BN_CLICKED(IDC_RADIO2, &CKomDlg::OnBnClickedRadio1) ON_BN_CLICKED(IDC_RADIO3, &CKomDlg::OnBnClickedRadio1) END_MESSAGE_MAP() W pliku nagłówkowym: DECLARE_MESSAGE_MAP()
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). • Uwaga! Przykład haka omówiony będzie na ćwiczeniach po tym, jak nauczymy się tworzyć biblioteki DLL z eksportowanymi funkcjami.
Przykładowe pytania • Jakich funkcji WinAPI można użyć do wysłania komunikatu? • Jaki komunikat służy do ukrycia/zamknięcia okna? • Jaka funkcja służy do pobrania komunikatu z kolejki komunikatów? A jaka do jego pobrania bez usunięcia z kolejki? • Jaka funkcja służy do znalezienia uchwytu okna o znanej nazwie klasy? • Jak wykonać pętlę po wszystkich oknach i ich oknach-dzieciach? • Opisz w jaki sposób haki mogą być zagrożeniem dla bezpieczeństwa użytkownika. • „Naszkicuj” kod funkcji zwracającej uchwyt okna znajdującego pod kursorem myszy. Opcjonalnie zrób go oknem aktywnym.