Image
22.6.2016 0 Comments

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.

// Hello.c
#include <windows.h>
 
long FAR PASCAL _export WndProc(HWND hwnd,
UINT message, UINT wParam, LONG lParam)
{
 HDC   hdc;
 HPEN  hpen, hpenOld;
 PAINTSTRUCT ps;
 RECT  rect;  
 switch (message) {
  case WM_PAINT:
   hdc = BeginPaint(hwnd, &ps);
   GetClientRect(hwnd, &rect);
   hpen = CreatePen(PS_SOLID, 6, RGB(0, 0, 255));
   hpenOld = SelectObject(hdc, hpen);    
   DrawText(hdc, "Hello, world!", -1, &rect,  DT_SINGLELINE | DT_LEFT | DT_TOP);     
   SelectObject(hdc, hpenOld);
   DeleteObject(hpen);
   EndPaint(hwnd, &ps);
   return 0;
  case WM_DESTROY:
   PostQuitMessage(0);
   return 0;
 }
 return DefWindowProc(hwnd, message, wParam, lParam);
}
 
int PASCAL WinMain(HANDLE hInstance,
  HANDLE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)
{
 static char szMeno [] = "Hello";
 HWND  hwnd;
 MSG     msg;
 WNDCLASS wndclass;
 
 if (!hPrevInstance) {
  wndclass.style   = CS_HREDRAW | CS_VREDRAW;      // typ okna
  wndclass.lpfnWndProc   = WndProc;  // meno funkcie, ktorá je spojená  s triedou okna
  wndclass.cbClsExtra = 0;
  wndclass.cbWndExtra = 0;
  wndclass.hInstance  = hInstance;
  wndclass.hIcon   = LoadIcon(NULL, IDI_APPLICATION); // natiahnutie ikony aplikácie (ak ste...
    // nedefinovali vlastnú, natiahne sa default
  wndclass.hCursor    = LoadCursor(NULL, IDC_ARROW);   // natiahnutie kurzora (ak ste...
    // nedefinovali vlastný, natiahne sa default
  wndclass.hbrBackground = GetStockObject(WHITE_BRUSH);  // pozadie okna
  wndclass.lpszMenuName  = NULL;    // informácie o menu, ak ste nejaké vytvorili
  wndclass.lpszClassName = szMeno;  // meno, pod akým sa trieda okna zaregistruje
  RegisterClass(&wndclass);
 }
 hwnd = CreateWindow(szMeno,        // meno triedy okna
  "Program Hello",            // názov okna
  WS_OVERLAPPEDWINDOW,       // štýl okna       
  CW_USEDEFAULT,             // pozícia okna na osi x
  CW_USEDEFAULT,             // pozícia okna na osi y
  CW_USEDEFAULT,       // začiatočná veľkosť na osi x
  CW_USEDEFAULT,            // začiatočná veľkosť na osi y
  NULL,                     // handle na rodiča ( v našom prípade žiadne nie je, preto NULL)
  NULL,                   // handle na menu okna ( v našom prípade žiadne nie je, preto NULL)
  hInstance,                // handle na inštanciu programu
  NULL);      
   ShowWindow(hwnd, nCmdShow);
   UpdateWindow(hwnd);
   while (GetMessage(&msg, NULL, 0, 0)) {
    TranslateMessage(&msg);
    DispatchMessage(&msg); }
   return msg.wParam;
}

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:

while (GetMessage(&msg, NULL, 0, 0)) {
            TranslateMessage(&msg);
DispatchMessage(&msg); }

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).

Nabudúce. Nabudúce si dokončíme rozbor príkladu Hello a uvedieme si, ako sa vlastne dá do okna kresliť, resp. písať. Opíšeme si kontext zariadení a GDI objekty. Ak nám zostane priestor, začneme si opisovať aj knižnicu MFC.
Zobrazit Galériu

Nechajte si posielať prehľad najdôležitejších správ emailom

Mohlo by Vás zaujímať

Ako na to

Ako zbaviť fotky hmly

08.12.2016 11:59

Hmla alebo dym sú často veľmi kreatívne nástroje. No všetkého veľa škodí. Fotka potom stráca kontrast a v podstate na nej nič nevidieť. Hmlu môžete neraz následnými úpravami odstrániť alebo zredukovať ...

Ako na to

Užitočné SW nástroje

08.12.2016 11:53

AllDup v4.0.3 Určenie: program na vyhľadávanie a odstraňovanie duplicitných súborov Vlastnosti: duplicitné súbory sa vyhľadávajú len na zvolených diskových jednotkách alebo len v rámci vybraných ...

Ako na to

Fotografovanie s bleskom

08.12.2016 11:47

Ak máte moderný fotoaparát so vstavaným alebo externým bleskom, zdá sa vám téma článku triviálna. Jednoducho nastavíte vhodný režim, vyberiete najlepšiu kompozíciu záberu, exponujete a o zvyšok sa už ...

Žiadne komentáre

Vyhľadávanie

Kyocera - prve-zariadenia-formatu-a4-s-vykonom-a3

Najnovšie videá