
C++ pod Windows / Úvod do programovania pod Windows / 2. časť
Späť na úvod >> Späť na programovanie >> Späť na seriál
Mesiac uplynul a ja vás opäť vítam pri druhej časti seriálu C++ pod Windows. V predošlej časti sme si spomenuli základné pojmy z programovania pod Windows a uviedli sme si rozdiely medzi programami pod DOS a Windows. Teraz vaše vedomosti rozšírime a uvedieme a rozoberieme si aj nejaký program pod Windows.
RADY, UZLY A RUTINY SPRÁV. Už viete, že keď operačný systém zistí používateľom spôsobenú udalosť, vygeneruje na ňu správu. Túto správu potom pošle do radu správ, ktorá prislúcha spustenej aplikácii. Rady správ využíva aplikácia, keď chce zistiť, či bola používateľom vygenerovaná správa a o aký druh správy ide. Zistí to tak, že prehľadá všetky správy v rade správ.
Uzol správ je cyklus, ktorý neustále prehľadáva rad správ a zisťuje, či nedošlo k nejakej udalosti. Prvá inštrukcia tohto uzla je volanie API funkcie s názvom GetMessage. Táto funkcia vracia informácie o každej správe, ktorá čaká v rade správ. Po zavolaní tejto funkcie obyčajne uzol správ volá niekoľko ďalších funkcií, ktoré obsluhujú prvky, ako sú vstupy a výstupy z klávesnice. Nakoniec volá uzol správ ďalšiu API funkciu, a to funkciu DispatchMessage. Táto funkcia volá vám už známu funkciu okna WndProc. WndProc oznámi, aký druh udalosti nastal, a odpovie na ňu volaním ďalších funkcií, ktoré zaisťuje váš program. Tieto funkcie sa volajú rutiny správ.
Rutiny správ určujú, akým spôsobom bude správa spracovaná. Aplikácie Windows sú vybavené rôznymi druhmi správ, ktoré sú určené na spracovanie jednotlivých druhov správ. Napríklad ak chcete, aby poklepanie myšou na okno spustilo zvukový signál, musíte na to vytvoriť inú rutinu správy, ako keď chcete, aby toto poklepanie spôsobilo vypísanie nejakého textu. Na obr. 1 môžete vidieť dve rutiny správ. Jedna má názov WM_PAINT a druhá WM_DESTROY. Ich funkciu si vysvetlíme nabudúce.
Obr. 1 K vysvetleniu spolupráce radu a uzla správ
Príklad. Po dlhom teoretickom úvode je načase, aby sme si uviedli príklad, na ktorom si objasníme preberané pojmy. Príkladom je jednoduchá aplikácia Hello, ktorej jedinou úlohou je vypísanie textu Hello, world! do okna s názvom Program Hello.
Vysvetlenie programu Hello. Aby ste dokonale pochopili, ako program Hello pracuje, musíme si spomenúť ešte niečo o handle. Handle je ukazovateľ na ukazovateľ a ukazuje na adresu uloženú v tabuľke. Handle sa využíva na prístup k objektom systému Windows (pozor, nie k takým objektom, aké poznáme z C++). Veľa API funkcií vracia handle a ďalšie používajú handle ako parameter. Keď sa pozrieme na funkciu WinMain, tá obsahuje hneď dva handle, a to hInstance, čo je handle spustenej aplikácie, a hPrevInstance, čo je handle predchádzajúcej aplikácie. Ďalším parametrom funkcie WinMain je lpszCmdParam, čo je ukazovateľ na reťazec príkazového riadka, ktorý bol použitý pri spúšťaní aplikácie (niečo podobné ako parameter char* argv[ ] funkcie main v programoch pod DOS). Posledným parametrom je konštanta nCmdShow (môže ich byť aj viac, v takom prípade tieto konštanty oddeľujeme pomocou bitového operátora OR {|}), ktorá môže byť použitá na určenie veľkosti okna, jeho súradníc a podobne.
Po spustení programu Hello funkcia WinMain zistí, či nie je spustená iná kópia programu. Ako iste viete, vo Windows môžu bežať naraz aj dve a viac rovnakých aplikácií. WinMain to zistí práve podľa obsahu handle s názvom hPrevInstance. Ak sa nezistila prítomnosť ďalšej aplikácie Hello, WinMain zaregistruje novú triedu okna (opäť pozor, nejde o triedu, ako ju poznáme z C++, v terminológii Windows je to určitý typ okna, ktorý je registrovaný na použitie našou aplikáciou). Registrácia novej triedy okna sa vykonáva pomocou funkcie RegisterClass, ktorá je volaná zvnútra bloku if(!hPrevInstance) a štruktúry WNDCLASS. Práve príkaz if(!hPrevInstance) zaručuje, že registrácia triedy okna sa nevykoná, ak je už rovnaká aplikácia spustená (a tá už triedu okna zaregistrovala). V tele cyklu „napĺňame“ štruktúru WNDCLASS dátami. Robíme tak pomocou nami deklarovanej štruktúry wndclass, ktorá je založená na štruktúre WNDCLASS (príkaz: WNDCLASS wndclass). Na konci tohto cyklu je už spomínaná funkcia RegisterClass, ktorá na základe získaných informácií štruktúry wndclass zaregistruje novú triedu okna a dá jej meno (v našom prípade szMeno).
Ak už máme okno zaregistrované, môžeme ho zobraziť. Najprv však musíme okno vytvoriť. Na to slúži funkcia CreateWindow. Opis jej parametrov tu nebudem uvádzať (môže ich mať veľmi veľa), nájdete ich v príklade Hello a rovnako aj v helpe. Tak teda po tom, ako sme vytvorili okno (CreateWindow), stačí ho už len zobraziť. Na to slúži funkcia ShowWindow, ktorá ako parametre má okno, ktoré bolo vytvorené pomocou CreateWindow (v našom prípade hwnd), a konštantu nCmdShow (jej opis sme už uviedli). Posledná funkcia, ktorú použijeme, je UpdateWindow. Túto funkciu použijeme vždy, keď chcem nejakým spôsobom zmeniť obsah okna (pripísať doň text, zmeniť farbu pozadia a pod.). Funkcie CreateWindow, ShowWindow a UpdateWindow sú API funkcie, takže nikde ich nemusíme deklarovať ani nič podobné.
Po tom, ako WinMain zaregistruje novú triedu pre naše okno, spustí hlavný uzol správ pomocou kódu:
V našom programe uzol správ spracúva operácie opakovaným volaním funkcií GetMessage, TranslateMessage, DispatchMessage. Uzol a zároveň aj program sa končí po prevzatí správy WM_QUIT, ktorú zašle funkcia PostQuitMessage.
Všetky tieto funkcie obsahujú ako parameter štruktúru msg. Je to opäť ako v prípade štruktúry WNDCLASS nami deklarovaná štruktúra (príkaz: MSG msg). Funkcia GetMessage používa túto štruktúru na odovzdávanie informácií o správach. Štruktúra MSG je definovaná v súbore windows.h, a preto ju tu nebudem uvádzať. Uvediem len opis jej členských premenných. V premennej hwnd sú uložené informácie o okne, ktorému bola správa poslaná. V premennej message je uložené číslo správy (aká je to správa). V premenných wParam a lParam sú uložené informácie o type udalosti, o ktorej jej správa, a o zdroji, ktorý udalosť vyvolal. Obidve tieto premenné sú závislé od premennej message. Klasický prípad je, keď udalosť bola spôsobená stlačením tlačidla myši, potom štruktúra MSG obsahuje v premennej wParam informáciu o tom, ktoré tlačidlo myši bolo stlačené, a v premennej lParam môže byť informácia o tom, ktorý riadiaci kláves bol stlačený zároveň s tlačidlom myši. V premennej time je uložený čas, keď bola správa zaznamenaná, a v premennej pt je uložená pozícia (súradnice) kurzora, keď bola správa zaznamenaná.
Tipy na doma. Skúste si doma pozrieť v súbore windows.h definíciu štruktúr MSG a WNDCLASS. Rovnako si v helpe pozrite presný opis funkcií GetMessage, TranslateMessage, DispatchMessage, CreateWindow, ShowWindow, UpdateWindow a RegisterClass. Zaexperimentujte s funkciou CreateWindow (zmeňte počiatočné nastavenia okna, zväčšite alebo zmenšite okno a pod., skúste aj niečo so štýlom okna).