3.1.2002
V minulém, úvodním díle jsme se kromě teoretického úvodu dostali pouze k vytvoření té asi nejjednodušší Win32 aplikace, která pro zobrazení textu použila API funkci MessageBox. Dnes již se začneme (pomalu ale jistě) zabývat skutečnou aplikací. Skutečnou v tom smyslu, že bude mít alespoň jedno běžné okno, tzv. hlavní okno aplikace. A toto okno na rozdíl od uvedeného dialogu MessageBox, i přesto, že nebude modální, bude moci zůstat v systému tak dlouho, jak si budeme přát, tedy i poté co ztratí fokus. Což je pro každého samozřejmě jasná záležitost, ale leckdo neví proč tomu tak je a jak to funguje uvnitř. Nejdříve bychom si měli říci trochu teorie o tom, jak jsou vlastně programy ve Windows řízeny a ovládány. Pod pojem programy budu mít dále na mysli pouze běžné Win32 aplikace, tedy nikoli konzolové aplikace běžící v okně, nebo nějaké speciální služby. Je to samozřejmě ne zcela přesné zjednodušení, ale pro výklad ho použijme. Takže: pod Windows jde o tzv. "událostmi řízené programování". Jde o to, že o jakékoli události v systému jsou posílány jednotlivým oknům (nebo více oknům "současně") jedna nebo i více zpráv, které tuto událost nějak popisují. Takovou událostí je jakákoli "myší akce", stisk klávesy, uplynutí nějakého aplikací definovaného timeru a mnoho dalších typů zpráv. A tyto zprávy jsou pak doručovány oknu (nebo oknům), kterých se nějak dotýkají, to znamená, že toto okna na ně musí, nebo "může pokud chce", nějak reagovat. A reakce na tyto zprávy (události) je vlastně ono událostmi řízené programování. Významným rysem takového programu je, že je schopen čekat na podněty z nejrůznějších směrů. V DOSovém programu většina aplikací po většinu doby svého "života" prostě čekala na klávesnicový vstup uživatele. Na něj nějak zareagovala a opět se čekalo. Pokud jsme chtěli současně "být na příjmu" i z jiných směrů, museli jsem nějak periodicky "osahávat" ostatní porty, ze kterých by mohlo "něco přijít". To byla pro většinu programátorů poměrně složitá záležitost. Dále neexistoval multitasking, takže čekající program stále zabíral prakticky 100% výkonu procesoru a počítač byl jinak "k nevyužití". Nyní máme Windows s multitaskingem a událostmi řízeným programováním. Brzy se sami naučíte velice jednoduše to, jak zařídit abychom byli připraveni přijmou uživatelský vstup "kdykoli a kdekoli". Uživatel může tutéž akci vyvolat myší, horkou klávesou, z nabídky, když budeme chtít tak třeba i joystickem apod. A kromě toho bude náš program současně připraven reagovat na různé systémové události či změny, které se ho mohou nějak týkat. Je to například změna rozlišeni obrazovky, změna barevné palety, požadavek na ukončení Windows nebo odhlášení uživatele apod. Pro představu o množství zpráv si můžete spustit program Spy++, který je součástí instalace Visual C++, popř. WinSight, který je v C++ Builderu (nebo samozřejmě jiný podobný). Nastavte si monitorování všech zpráv všem oknům v systému. A stačí pohnout myší (půjde to hůře ten monitor samozřejmě bere velké procento výkonu procesoru) a pomaleji odbíhající seznam zpráv se rázem rozeběhne jak o závod. Během několika sekund budete mít tisíce, spíše desetitisíce zpráv. A i když dáte "ruce pryč od počítače", stále tam budou, i když podstatně pomaleji, běžet zprávy různých timerů a dalších systémových zpráv. K čemu nám taková zpráva je a co s ní? Jak údaje z ní získat se samozřejmě dozvíme, nyní se pro představu podívejme třeba na zprávu oznamující stlačení levého tlačítka myši. Tato zpráva má identifikátor WM_LBUTTONDOWN. Tyto identifikátory zpráv (většina těch běžných začíná na WM_ (Windows Message)) jsou definovány v hlavičkových souborech, ty běžné konkrétně ve winuser.h, který sám je "inkludován" v souboru "windows.h", což je základní hlavičkový soubor, který musí být v každém Win32 programu. Naše zpráva konkrétně je definovaná takto:#define WM_LBUTTONDOWN 0x0201Podívejme se nyní na tuto zprávu do dokumentace. Zjistíme, že tato zpráva, stejně jako všechny ostatní má dva parametry: wParam typu WPARAM a lParam typu LPARAM1). Oba tyto parametry jsou ve Win32 32-ti bitová celá čísla. Řeknete si možná, že do 2 čísel, byť 32-ti bitových moc informací nevměstnáme. Jak uvidíte, většinou to co nás v tom okamžiku bude zajímat, se tam vejde a pokud ne, tak u mnoha zpráv je lParam adresou nějaké další datové struktury, která již může být libovolně velká. Vraťme se k naší zprávě WM_LBUTTONDOWN. Dokumentace nám říká, že wParam je indikátor virtuální klávesy. Zde je třeba vědět, že onou virtuální klávesou může být také některé z tlačítek myši. Pokud by nás totiž zajímalo, zda v okamžiku události byla současně stlačena některá "speciální" klávesa či nějaké další tlačítko myši, můžeme to zjistit z tohoto parametru. Ten může totiž být kombinací následujících hodnot:
POINTS ptMouse; ptMouse = MAKEPOINTS(lParam); int x = ptMouse.x; int y = ptMouse.yTrochu s předstihem ještě tolik, že často nastává situace, kdy (z hlediska uživatele) jedna událost vyvolá více zpráv. Jako příklad lze uvést uvolnění pravého tlačítka myši, při němž je poslána zpráva WM_RBUTTONUP a "současně" WM_CONTEXTMENU (tedy podnět k vyvolání kontextové nabídky). Ta "současnost" je samozřejmě v uvozovkách. Můžete si spustit již zmíněný program Spy++ či WinSight a zjistit, která z uvedených zpráv přijde dříve. Možná si řeknete: "Proboha, tolik zpráv, to musím myslet na všechno a všechno nějak ošetřovat?". Samozřejmě nikoliv. Ty stovky a tisíce zpráv, na které nechceme v programu nijak specificky reagovat, prostě necháme systému, ať se o ně postará. Příkladem může mýt třeba tažení okna za titulek. S nějakou implementací posunu okna v závislosti na myších zprávách v titulku si vůbec nebudeme dělat těžkou hlavu, pouze musíme příslušné zprávy "pustit" k "defaultnímu" zpracování, a Windows za nás udělá zbytek. Některým možná již připadá, že na úvod příliš teoretizuji a vykládám banální záležitosti. Ale tento seriál by měl být určen i těm, kteří třeba Windows prakticky neznají a chtějí problematiku pochopit. Většinou bývá lepší vědět jak a proč to tak funguje, než jenom jak to udělat. Když nevím v kterém parametru zprávy jsou souřadnice, podívám se do dokumentace, ale když neznám princip, budu jen bezmyšlenkovitě opisovat nějaké (snad) fungující ukázky kódu a doufat, že to nějak rozchodím. Ale nyní se již vrhneme i do praxe. Vytvoříme si nový projekt. Ve Visual C++ ("File -> New ->Projects") typu Win32 Application, dále zvolíme "prázdný projekt", vše si vytvoříme sami. V C++ Builderu zvolíme "File -> New -> "Console Wizard". Zde odškrtneme volby Use VCL a "Console Application", jak vidíme na obrázku. C++ Builder vám nyní vygeneruje hlavní zdrojový soubor aplikace i s funkcí WinMain. Ve Visual C++ si vše přidáme sami. Přidejme si tedy do projektu ("Project -> AddTo Project -> New" -> C/C++ Header File") hlavičkový soubor, nazvaný třeba "main.h" a obdobně zdrojový soubor (C/C++ Source File) nazvaný main.cpp. Zde si řekněme o významu koncovky. Ve standardním nastavení platí, že pokud zdrojovému souboru dáme koncovku .c, kompilátor ho považuje za céčko bez rozšíření C++. Pokud použijeme koncovku .cpp, můžeme použít i jazyk C++. Já jsem použil tu možnost s rozšířením na jazyk C++, i když v tomto "základním API" bychom si vystačili s jazykem C. Dovolíme si však ten luxus občas použít některé konstrukce specifické pro C++, jako pohodlnější definice proměnných uvnitř kódu apod. Navíc dnes již existuje jako součást Windows SDK sada tříd GDI+, které jsou vlastně také součástí Win API. Konkrétně jde o rozšíření grafického rozhraní GDI, které již podporuje formáty jako .jpg či .png a má i další "fajnovosti"... Ale my musíme nyní začít od základů. Nejdříve si do našeho hlavičkového souboru "main.h" přidáme základní hlavičkový soubor <windows.h>
#include <windows.h>Do zdrojovéhp souboru "main.cpp" si vložíme "main.h" a můžeme začít. Každý standardní program ve Windows musí mít jednu "hlavní" funkci, ve Windows nazvanou WinMain.V C++ Builderu ji již máte vygenerovanou. Ve Visual C++ si jí napíšeme takto.
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nShow) { return 0; }Co znamenají jednotlivé parametry?
Školení
Kontakt
739 219 991
live:radekchalupa_1
Nové články