SlideShare a Scribd company logo
1 of 32
Download to read offline
Tworzenie aplikacji
dla Windows.
Od prostych programów
do gier komputerowych
Autor: Pawe³ Borkowski
ISBN: 978-83-246-1881-1
Format: 158x235, stron: 456



                     Poznaj tajniki tworzenia aplikacji dla Windows
    • Jak okreœliæ po³o¿enie, rozmiar i styl okna?
    • Jak tworzyæ w¹tki aplikacji za pomoc¹ funkcji CreateThread?
    • Jak definiowaæ biblioteki?
Dev-C++ to zintegrowane œrodowisko programistyczne, którego niew¹tpliwym atutem
s¹ tzw. DevPaki, czyli rozszerzenia programu, pozwalaj¹ce korzystaæ z ró¿nych
bibliotek, szablonów i narzêdzi. Œrodowisko Dev-C++ wspomaga tak¿e pracê
nad nowym projektem Windows — gotowym kodem tworz¹cym okno z obs³ug¹
podstawowych komunikatów. Wszystko to sprawia, ¿e mamy do czynienia z wygodnym
i funkcjonalnym œrodowiskiem, zarówno dla pocz¹tkuj¹cych, jak i zaawansowanych
programistów.
Z ksi¹¿ki „Tworzenie aplikacji dla Windows. Od prostych programów do gier
komputerowych” mo¿e skorzystaæ ka¿dy, kto chce nauczyæ siê programowania:
zarówno studenci kierunków informatycznych, jak i osoby, które nie maj¹ takiego
przygotowania. Podrêcznik kolejno ods³ania poszczególne elementy wiedzy
programistycznej — od najprostszych po najbardziej zaawansowane. Dowiesz siê wiêc,
jak wprowadzaæ niewielkie zmiany w kodzie, jak projektowaæ aplikacje wielow¹tkowe
i definiowaæ biblioteki, jak budowaæ du¿e, sk³adaj¹ce siê z kilku plików projekty, aby
na koniec samodzielnie stworzyæ grê komputerow¹.
    • Instalacja œrodowiska Dev-C++
    • Tworzenie narzêdzia pióro
    • Obs³uga map bitowych
    • Obs³uga komunikatów myszy i klawiatury
    • Obiekty steruj¹ce w oknie
    • Menu i plik zasobów
    • Projektowanie aplikacji wielow¹tkowych
    • Biblioteki statyczne i dynamiczne
    • Multimedia
    • Programowanie gier
                     Naucz siê programowania i twórz w³asne gry!
Spis treści
               Wstęp .............................................................................................. 7

Część I        Dla początkujących ........................................................ 9
Rozdział 1. Instalacja środowiska Dev-C++ ....................................................... 11
Rozdział 2. Pierwszy program ........................................................................... 13
               2.1.    Przygotowanie edytora ....................................................................................... 13
               2.2.    Kod wygenerowany przez Dev-C++ .................................................................. 15
               2.3.    Określanie tytułu okna ....................................................................................... 19
               2.4.    Określanie położenia i rozmiaru okna ................................................................ 19
               2.5.    Określanie stylu okna ......................................................................................... 21
               2.6.    Ćwiczenia ........................................................................................................... 22
Rozdział 3. Rysowanie w oknie ........................................................................ 23
               3.1.    Obsługa komunikatu WM_PAINT .................................................................... 23
               3.2.    Zestawienie funkcji graficznych. Program
                       z użyciem funkcji Ellipse i LineTo .................................................................... 25
               3.3.    Wyświetlanie tekstu w obszarze roboczym okna ............................................... 28
               3.4.    Pierwszy program z użyciem funkcji SetPixel — wykres funkcji sinus ............ 34
               3.5.    Tworzenie pióra ................................................................................................. 39
               3.6.    Drugi program z użyciem funkcji SetPixel — zbiór Mandelbrota ..................... 42
               3.7.    Trzeci program z użyciem funkcji SetPixel — prosta obsługa bitmap ............... 48
               3.8.    Ćwiczenia ........................................................................................................... 55
Rozdział 4. Obsługa komunikatów myszy .......................................................... 57
               4.1.    Program z obsługą komunikatu WM_MOUSEMOVE ...................................... 57
               4.2.    Obsługa komunikatów WM_LBUTTONDOWN
                       i WM_RBUTTONDOWN — zbiór Mandelbrota po raz drugi .......................... 62
               4.3.    Obsługa komunikatów WM_MOUSEMOVE, WM_LBUTTONDOWN
                       i WM_RBUTTONDOWN — zbiór Mandelbrota a zbiory Julii ........................ 66
               4.4.    Tajemnica przycisków okna ............................................................................... 75
               4.5.    Ćwiczenia ........................................................................................................... 86
Rozdział 5. Obsługa komunikatów klawiatury .................................................... 87
               5.1.    Komunikaty klawiatury. Obsługa komunikatu WM_CHAR .............................. 87
               5.2.    Obsługa komunikatu WM_KEYDOWN. Diagram Feigenbauma ...................... 90
               5.3.    Ćwiczenia ......................................................................................................... 101
4             Tworzenie aplikacji dla Windows. Od prostych programów do gier komputerowych


Rozdział 6. Obiekty sterujące w oknie ............................................................ 103
                6.1.       Obiekt klasy BUTTON .................................................................................... 103
                6.2.       Obsługa grafiki za pomocą obiektów klasy BUTTON ..................................... 109
                6.3.       Obiekt klasy edycji. Automaty komórkowe ..................................................... 116
                6.4.       Ćwiczenia ......................................................................................................... 128
Rozdział 7. Menu i plik zasobów ..................................................................... 131
                7.1.  Dodanie menu do okna ..................................................................................... 131
                7.2.  Obsługa bitmapy z pliku zasobów .................................................................... 138
                7.3.  Odczytywanie danych z pliku. Edytor bitmap .................................................. 143
                7.4.  Kopiarka wielokrotnie redukująca ................................................................... 154
                7.5.  Ćwiczenia ......................................................................................................... 169
                Podsumowanie części I ................................................................................................. 169

Część II        Dla średniozaawansowanych ....................................... 171
Rozdział 8. Projektowanie aplikacji wielowątkowych ....................................... 173
                8.1.       Tworzenie wątków za pomocą funkcji CreateThread ...................................... 173
                8.2.       Czy praca z wątkami przyspiesza działanie aplikacji?
                           Sekcja krytyczna i priorytety wątków .............................................................. 178
                8.3.       Wstrzymywanie pracy i usuwanie wątków ...................................................... 190
                8.4.       Ćwiczenia ......................................................................................................... 199
Rozdział 9. Definiowanie bibliotek .................................................................. 201
                9.1.       Biblioteki statyczne .......................................................................................... 201
                9.2.       Biblioteki dynamiczne — podejście strukturalne ............................................. 207
                9.3.       Biblioteki dynamiczne — podejście obiektowe ............................................... 220
                9.4.       Własny temat okna ........................................................................................... 225
                9.5.       Ćwiczenia ......................................................................................................... 254
Rozdział 10. Multimedia .................................................................................. 255
                10.1. Odtwarzanie plików wav — funkcja sndPlaySound ........................................ 255
                10.2. Odtwarzanie plików mp3 — biblioteka FMOD ............................................... 258
                10.3. Ćwiczenia ......................................................................................................... 269
                Podsumowanie części II ............................................................................................... 270

Część III Dla zaawansowanych .................................................. 273
Rozdział 11. Programowanie gier z użyciem biblioteki OpenGL .......................... 275
                11.1.  Podstawy obsługi biblioteki OpenGL .............................................................. 275
                11.2.  Prymitywy OpenGL ......................................................................................... 284
                11.3.  Bufor głębokości, perspektywa
                       — wzorzec kodu do programowania gier (pierwsze starcie) ............................ 298
                11.4. Animacja .......................................................................................................... 309
                11.5. Poruszanie się po scenie, funkcja gluLookAt
                       i wzorzec kodu do programowania gier (starcie drugie, decydujące) ............... 320
                11.6. Tekstury i mipmapy ......................................................................................... 334
                11.7. Listy wyświetlania i optymalizacja kodu ......................................................... 349
                11.8. Detekcja kolizji ................................................................................................ 361
                11.9. Światło, mgła, przezroczystość i inne efekty specjalne ....................................... 368
                       Uruchamianie gry w trybie pełnoekranowym .................................................. 368
                       Mgła ................................................................................................................. 371
                       Przezroczystość ................................................................................................ 374
                       Światło ............................................................................................................. 384
Spis treści                                                                                                                                5


              11.10.Jak ustawić stałą prędkość działania programu? .............................................. 390
              11.11.Gotowe obiekty OpenGL ................................................................................. 398
              11.12.Fonty ................................................................................................................ 406
              11.13.Dźwięk na scenie ............................................................................................. 416
              11.14.Budujemy grę! ................................................................................................. 419
                    Wprowadzenie i charakter gry ......................................................................... 419
                    Dane gracza ...................................................................................................... 420
                    Strzał z broni .................................................................................................... 423
                    Pozostali bohaterowie gry ................................................................................ 425
                    Odnawianie zasobów gracza ............................................................................ 428
                    Zakończenie programu (gry) ............................................................................ 430
              Podsumowanie części III .............................................................................................. 433

Dodatki ..................................................................................... 435
              Dodatek A ................................................................................... 437
              Dodatek B ................................................................................... 439
              Skorowidz .................................................................................... 441
Rozdziaä 8. i Projektowanie aplikacji wielowñtkowych                                    173




Rozdziaä 8.
Projektowanie aplikacji
wielowñtkowych
8.1. Tworzenie wñtków za pomocñ
     funkcji CreateThread
        Jeste my przyzwyczajeni do tego, e w systemie Windows mo emy pracowaü na wielu
        oknach jednocze nie. Jak du e jest to udogodnienie, nie trzeba nikogo przekonywaü.
        T cech systemu nazywamy wielozadaniowo ci . Jej najpo yteczniejszym zastosowa-
        niem jest mo liwo ü ukrycia przed pracodawc pod stosem otwartych okien jednego
        okienka z uruchomion ulubion gr . System Windows pozwala tak e na co wi cej —
        na wielow tkowo ü, czyli wykonywanie wielu zada równocze nie w ramach dziaáania
        jednego programu. Oczywi cie, poj cia pracy równoczesnej nie nale y traktowaü zbyt
        dosáownie. System dzieli czas pracy procesora i przyznaje po kolei pewn jego cz ü
        w celu obsáugi kolejnego w tku. Poniewa wspomniany proces wykonywany jest bardzo
        szybko, powstaje iluzja równolegáego dziaáania w tków.

        W tek tworzymy za pomoc funkcji CreateThread o nast puj cej skáadni:
          HANDLE CreateThread(LPSECURITY_ATTRIBUTES atrybuty_watku,
                              DWORD rozmiar_stosu,
                              LPTHREAD_START_ROUTINE adres_funkcji_watku,
                              LPVOID parametr,
                              DWORD flaga_watku,
                              LPDWORD identyfikator
                              );

        Pierwszy argument atrybuty_watku miaá zastosowanie w systemie Windows NT. Od tego
        czasu nie wykorzystuje si go i mo emy w jego miejsce wpisaü NULL. Drugi argument
        okre la rozmiar stosu w bajtach. Je eli nie mamy pomysáu dotycz cego jego wielko ci,
        wpiszmy zero, co oznacza zadeklarowanie stosu standardowego rozmiaru. W parametrze
174                                                   Czö è II i Dla redniozaawansowanych


      adres_funkcji_watku powinien znajdowaü si , zreszt zgodnie z pomysáowo nadan
      nazw , adres funkcji, która zawiera kod obsáugi w tku. Deklaracja funkcji musi mieü
      nast puj c postaü:
        DWORD NazwaFunkcji(LPVOID);

      Parametr, który mo emy przekazaü do funkcji w tku, przekazujemy jako czwarty argu-
      ment funkcji CreateThread. Argument flaga_watku okre la chwil uruchomienia w tku.
      Mo emy u yü jednej z dwóch warto ci:
         0 — w tek uruchamiany jest w chwili utworzenia,
         CREATE_SUSPENDED — uruchomienie w tku jest wstrzymane a do wywoáania
          funkcji ResumeThread.

      Ostatni parametr powinien zawieraü wska nik do zmiennej, w której zostanie umiesz-
      czony identyfikator w tku. Je eli uruchomienie w tku powiedzie si , funkcja Create
      ´Thread zwraca uchwyt utworzonego w tku, w przeciwnym przypadku zwracana jest
      warto ü NULL.

      Wszystko, co wáa nie przeczytali cie, jest niezwykle ciekawe, ale warto ju przyst piü
      do budowania programu. B dzie to aplikacja z dziedziny helmintologii, czyli nauki
      o robakach (niestety, paso ytniczych). Wyobra my sobie obszar roboczy naszego okna.
      Klikni cie lewego przycisku myszy powinno wywoáaü nowy w tek — robaka, którego
      pocz tek niszczycielskiej dziaáalno ci b dzie si znajdowaá w miejscu, w jakim aktualnie
      znajduje si kursor myszy. Tworzymy nowy projekt Windows o nazwie Program20.dev.
      Spójrzmy na prosty program realizuj cy wspomniane zadanie (plik Program20_main.cpp),
      a nast pnie omówi kluczowe punkty programu.
        #include <windows.h>

        /* Staáe rozmiaru obszaru roboczego okna */
        const int MaxX = 640;
        const int MaxY = 480;

        /* Zmienne globalne dla obsáugi w tków */
        int x, y;

        /* Funkcja w tku */
        DWORD Robak(LPVOID param);

        LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

        char szClassName[ ] = "WindowsApp";

        int WINAPI WinMain (HINSTANCE hThisInstance,
                            HINSTANCE hPrevInstance,
                            LPSTR lpszArgument,
                            int nFunsterStil)

        {
            HWND hwnd;
            MSG messages;
            WNDCLASSEX wincl;
Rozdziaä 8. i Projektowanie aplikacji wielowñtkowych                                  175


              wincl.hInstance = hThisInstance;
              wincl.lpszClassName = szClassName;
              wincl.lpfnWndProc = WindowProcedure;
              wincl.style = CS_DBLCLKS;
              wincl.cbSize = sizeof (WNDCLASSEX);
              wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
              wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
              wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
              wincl.lpszMenuName = NULL;
              wincl.cbClsExtra = 0;
              wincl.cbWndExtra = 0;
              wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

              if (!RegisterClassEx (&wincl))
                  return 0;

              hwnd = CreateWindowEx (
                     0,
                     szClassName,
                     "Program20 - aplikacja wielowætkowa",
                     WS_OVERLAPPEDWINDOW,
                     CW_USEDEFAULT,
                     CW_USEDEFAULT,
                     MaxX+8,
                     MaxY+34,
                     HWND_DESKTOP,
                     NULL,
                     hThisInstance,
                     NULL
                     );
              ShowWindow (hwnd, nFunsterStil);

              while (GetMessage (&messages, NULL, 0, 0))
              {
                  TranslateMessage(&messages);
                  DispatchMessage(&messages);
              }
              return messages.wParam;
          }

          LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam,
          ´LPARAM lParam)
          {
              static HDC hdc;
              PAINTSTRUCT ps;
              DWORD pointer;

              switch (message)
              {
                  case WM_PAINT:
                      hdc = BeginPaint(hwnd, &ps);
                      if(x>=5&&y>=5&&x<MaxX-5&&y<MaxY-5)
                          Ellipse(hdc, x-5, y-5, x+5, y+5);
                      EndPaint(hwnd, &ps);
                      break;
                  case WM_LBUTTONDOWN:
                      x = LOWORD(lParam);
176                                                        Czö è II i Dla redniozaawansowanych


                    y = HIWORD(lParam);
                    CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Robak, hwnd, 0,
                    ´&pointer);
                    break;
                case WM_DESTROY:
                    PostQuitMessage (0);
                    break;
                default:
                    return DefWindowProc (hwnd, message, wParam, lParam);
            }

            return 0;
        }

        DWORD Robak(LPVOID param)
        {
            int wx = x, wy = y;

            //uruchomienie liczb losowych
            srand(GetTickCount());

            //p tla niesko czona
            while(TRUE)
            {
                  //wylosuj ruch robaka
                  wx += (rand()%5) - 2;
                  wy += (rand()%5) - 2;
                  //sprawd , czy robak znajduje si w dozwolonym obszarze
                  if(wx<5) wx = 5;
                  if(wx>MaxX-5) wx = MaxX-5;
                  if(wy<5) wy = 5;
                  if(wy>MaxY-5) wy = MaxY-5;
                  //zaáaduj nowe wspóárz dne do zmiennej globalnej
                  x = wx;
                  y = wy;
                  //narysuj robaka w nowym poáo eniu
                  InvalidateRect((HWND)param, NULL, FALSE);
                  //zaczekaj 1/10 sekundy
                  Sleep(100);
            }
            return 0;
        }

      Program po uruchomieniu czeka na naci ni cie lewego przycisku myszy.
        case WM_LBUTTONDOWN:
            x = LOWORD(lParam);
            y = HIWORD(lParam);
            CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Robak, hwnd, 0, &pointer);
            break;

      Je eli procedura okna otrzyma komunikat o zaj ciu tego zdarzenia, tworzy w tek, którego
      obsáug powierza funkcji Robak. Wspóárz dne kursora myszy s áadowane do zmien-
      nych globalnych x i y w celu przekazania ich do funkcji obsáugi w tku. Aplikacja kon-
      tynuuje prac , a równolegle z ni zaczyna dziaáaü nowy w tek. Spójrzmy na kod funkcji
      Robak.
Rozdziaä 8. i Projektowanie aplikacji wielowñtkowych                                    177


          DWORD Robak(LPVOID param)
          {
              int wx = x, wy = y;

              //uruchomienie liczb losowych
              srand(GetTickCount());

              while(TRUE)
              {
                  //wylosuj ruch robaka
                  wx += (rand()%5) - 2;
                  wy += (rand()%5) - 2;
                  //sprawd , czy robak znajduje si w dozwolonym obszarze
                  if(wx<5) wx = 5;
                  if(wx>MaxX-5) wx = MaxX-5;
                  if(wy<5) wy = 5;
                  if(wy>MaxY-5) wy = MaxY-5;
                  //zaáaduj nowe wspóárz dne do zmiennej globalnej
                  x = wx;
                  y = wy;
                  //narysuj robaka w nowym poáo eniu
                  InvalidateRect((HWND)param, NULL, FALSE);
                  //zaczekaj 1/10 sekundy
                  Sleep(100);
              }

              return 0;
          }

        Pocz tkowe wspóárz dne obiektu zostaáy przekazane przy u yciu zmiennych global-
        nych x i y.
          int wx = x, wy = y;

        Pozostaáa cz ü kodu umieszczona jest w p tli niesko czonej, co oznacza, e w tek
        zostanie zniszczony dopiero w chwili zamkni cia aplikacji.

        Bardzo wa n cech robaka jest jego losowy ruch realizowany za pomoc uaktualniania
        wspóárz dnych.
          wx += (rand()%5) - 2;
          wy += (rand()%5) - 2;

        Poniewa w tym zadaniu korzystamy z funkcji rand, która zwraca liczby pseudolosowe,
        wa ne jest, by warto ü inicjalizuj ca tej funkcji ró niáa si dla ka dego w tku. Liczb
        pocz tkow dla oblicze funkcji rand przekazujemy za pomoc srand, której argumen-
        tem jest u nas funkcja GetTickCount podaj ca liczb milisekund liczon od chwili uru-
        chomienia systemu Windows.
          srand(GetTickCount());

        Po obliczeniu nowej wspóárz dnej poáo enia robaka i sprawdzeniu jej poprawno ci wy-
        muszamy odmalowanie obszaru roboczego okna.
          InvalidateRect((HWND)param, NULL, FALSE);
178                                                    Czö è II i Dla redniozaawansowanych


        W ten sposób w tek komunikuje si z aplikacj gáówn i zmusza do zainteresowania
        si kodem obsáugi komunikatu WM_PAINT.
           case WM_PAINT:
               hdc = BeginPaint(hwnd, &ps);
               if(x>=5&&y>=5&&x<MaxX-5&&y<MaxY-5)
                   Ellipse(hdc, x-5, y-5, x+5, y+5);
               EndPaint(hwnd, &ps);
               break;

        Wizualn cz ci dziaáania w tku jest narysowana w nowym poáo eniu elipsa. Przy-
        káadowy efekt dziaáania programu z uruchomionymi jednocze nie kilkudziesi cioma
        w tkami przedstawiam na rysunku 8.1.




Rysunek 8.1. Okno dziaáaj cej aplikacji Program20




8.2. Czy praca z wñtkami przyspiesza
     dziaäanie aplikacji? Sekcja
     krytyczna i priorytety wñtków
        Odpowied na pytanie postawione w tytule podrozdziaáu nie jest prosta. Wszystko
        zale y od rodzaju czynno ci realizowanych przez w tek. Pami tajmy, e ka dy utwo-
        rzony w tek korzysta z cz ci czasu pracy procesora. Dlatego bá dna jest my l, e
        skomplikowane obliczenie rozáo one na wiele w tków wykona si szybciej ni to samo
Rozdziaä 8. i Projektowanie aplikacji wielowñtkowych                                     179


        obliczenie w jednow tkowej aplikacji. Natomiast istniej sytuacje, w których procesor
        „czeka bezczynnie” lub jest tylko „nieznacznie zaj ty”, wtedy — oczywi cie — stoso-
        wanie w tków jest zasadne. Operowanie w tkami ma przede wszystkim uáatwiü prac
        nam, czyli programistom.

        Ilustracj do postawionego pytania b dzie aplikacja, w której na dwóch cz ciach obszaru
        roboczego okna wy wietlimy zbiór Mandelbrota i jeden ze zbiorów Julii. Wykonanie
        ka dego z tych zada bardzo mocno obci a procesor i kart graficzn . Nasza aplika-
        cja w pierwszej kolejno ci b dzie rysowaáa oddzielnie zbiór Mandelbrota i zbiór Julii,
        a nast pnie obydwa zadania zostan wykonane równolegáe w dwóch w tkach. Poli-
        czymy czas wykonania zada w wersji bez u ycia w tków i z ich u yciem.

        Tworzymy nowy projekt Program21.dev. Poniewa przewidujemy du ilo ü operacji
        graficznych, odpowiedni kod umie cimy w pliku Program21.h. Wygenerowany przez
        Dev-C++ kod (plik Program21_main.cpp) modyfikujemy tylko w czterech miejscach.
          1. Dodajemy plik nagáówkowy.
               #include "Program21.h"

          2. Zmieniamy parametry funkcji CreateWindowEx.
               hwnd = CreateWindowEx (
                      0,
                      szClassName,
                      "Program21",
                      WS_OVERLAPPEDWINDOW,
                      CW_USEDEFAULT,
                      CW_USEDEFAULT,
                      648,
                      340,
                      HWND_DESKTOP,
                      NULL,
                      hThisInstance,
                      NULL
                      );

          3. Dodajemy kod obsáugi komunikatu WM_PAINT.
               case WM_PAINT:
                   hdc = BeginPaint(hwnd, &ps);
                   MojaProcedura(hdc);
                   EndPaint(hwnd, &ps);
                   break;

          4. Dodajemy kod obsáugi komunikatu WM_LBUTTONDOWN. Dzi ki temu mo liwe
            b dzie áatwe od wie anie obszaru roboczego okna i tym samym wielokrotne
            powtórzenie do wiadczenia.
               case WM_LBUTTONDOWN:
                   InvalidateRect(hwnd, NULL, TRUE);
                   break;

        Plik Program21_main.cpp w caáo ci wygl da nast puj co (jak zwykle, pomini te zostaáy
        generowane przez Dev-C++ komentarze):
180                                              Czö è II i Dla redniozaawansowanych


      #include <windows.h>
      #include "Program21.h"

      LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

      char szClassName[ ] = "WindowsApp";

      int WINAPI WinMain (HINSTANCE hThisInstance,
                          HINSTANCE hPrevInstance,
                          LPSTR lpszArgument,
                          int nFunsterStil)
      {
          HWND hwnd;
          MSG messages;
          WNDCLASSEX wincl;

          wincl.hInstance = hThisInstance;
          wincl.lpszClassName = szClassName;
          wincl.lpfnWndProc = WindowProcedure;
          wincl.style = CS_DBLCLKS;
          wincl.cbSize = sizeof (WNDCLASSEX);
          wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
          wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
          wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
          wincl.lpszMenuName = NULL;
          wincl.cbClsExtra = 0;
          wincl.cbWndExtra = 0;
          wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

          if (!RegisterClassEx (&wincl))
              return 0;

          hwnd = CreateWindowEx (
                 0,
                 szClassName,
                 "Program21",
                 WS_OVERLAPPEDWINDOW,
                 CW_USEDEFAULT,
                 CW_USEDEFAULT,
                 648,
                 340,
                 HWND_DESKTOP,
                 NULL,
                 hThisInstance,
                 NULL
                 );

          ShowWindow (hwnd, nFunsterStil);

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

          return messages.wParam;
      }
Rozdziaä 8. i Projektowanie aplikacji wielowñtkowych                                     181


          LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam,
          ´LPARAM lParam)
          {
              HDC hdc;
              PAINTSTRUCT ps;

               switch (message)
               {
                   case WM_PAINT:
                       hdc = BeginPaint(hwnd, &ps);
                       MojaProcedura(hdc);
                       EndPaint(hwnd, &ps);
                       break;
                   case WM_LBUTTONDOWN:
                       InvalidateRect(hwnd, NULL, TRUE);
                       break;
                   case WM_DESTROY:
                       PostQuitMessage (0);
                       break;
                   default:
                       return DefWindowProc (hwnd, message, wParam, lParam);
               }

               return 0;
          }

        Kluczow cz ü programu, wraz z wywoáywan w kodzie obsáugi komunikatu WM_PAINT
        procedur MojaProcedura, umie cimy w pliku Program21.h. Zawarto ü procedury b d
        stanowiü:
          1. Obliczenie czasu potrzebnego do narysowania zbioru Mandelbrota i Julii
              za pomoc funkcji wywoáywanych w sposób sekwencyjny.
              a) Pobranie liczby milisekund, które upáyn áy od chwili uruchomienia
                 systemu Windows i umieszczenie tej wielko ci w zmiennej m1.
              b) Wywoáanie funkcji rysuj cej zbiór Mandelbrota.
              c) Wywoáanie funkcji rysuj cej zbiór Julii.
              d) Pobranie liczby milisekund, które upáyn áy od chwili uruchomienia
                 systemu Windows i umieszczenie tej wielko ci w zmiennej m2.
              e) Obliczenie i wy wietlenie ró nicy m2-m1. Wynik oznacza czas wykonania
                zada opisanych w punktach b i c.
          2. Obliczenie czasu potrzebnego do narysowania zbioru Mandelbrota i Julii
              za pomoc funkcji wywoáanych w równolegle pracuj cych w tkach.
              a) Pobranie liczby milisekund, które upáyn áy od chwili uruchomienia
                 systemu Windows, i umieszczenie tej wielko ci w zmiennej m1.
              b) Utworzenie w tku wywoáuj cego funkcj rysuj c zbiór Mandelbrota.
              c) Utworzenie w tku wywoáuj cego funkcj rysuj c zbiór Julii.
              d) Oczekiwanie na zako czenie pracy obu w tków.
182                                                 Czö è II i Dla redniozaawansowanych


          e) Pobranie liczby milisekund, które upáyn áy od chwili uruchomienia
             systemu Windows, i umieszczenie tej wielko ci w zmiennej m2.
           f) Obliczenie i wy wietlenie ró nicy m2-m1. Wynik oznacza czas wykonania
             zada opisanych w punktach b i c.

      Popatrzmy na pierwsz wersj procedury MojaProcedura.
        void MojaProcedura(HDC hdc)
        {
            char tab[32];
            DWORD pointer;
            DWORD m, m1, m2;

        //pobierz ilo ü milisekund od chwili uruchomienia systemu Windows
        //(czas startu zadania)
              m1 = GetTickCount();
        //wykonaj zadanie numer 1
              Zbior_Mandelbrota(hdc);
        //wykonaj zadanie numer 2
              Zbior_Julii(hdc);
        //pobierz ilo ü milisekund od chwili uruchomienia systemu Windows
        //(czas zako czenia zadania)
              m2 = GetTickCount();
        //wy wietl okres czasu potrzebny do wykonania zadania
              m = m2 - m1;
              TextOut(hdc, 10, 250, "Czas sekwencyjnego wykonania zada :", 35);
              itoa(m, tab, 10);
              TextOut(hdc, 300, 250, tab, strlen(tab));

        //wyczy ü fragment okna
              Rectangle(hdc, 0, 0, 640, 240);
        //wyzeruj zmienn globaln dla w tków
              zmienna_stop = 0;
        //pobierz ilo ü milisekund od chwili uruchomienia systemu Windows
        //(czas startu zadania)
              m1 = GetTickCount();
        //wywoáaj w tek wykonuj cy zadanie numer 1
              CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Z_M, hdc, 0, &pointer);
        //wywoáaj w tek wykonuj cy zadanie numer 2
              CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Z_J, hdc, 0, &pointer);
        //czekaj na zako czenie pracy w tków
              do{}while(zmienna_stop<2);
        //pobierz ilo ü milisekund od chwili uruchomienia systemu Windows
        //(czas zako czenia zadania)
              m2 = GetTickCount();
        //wy wietl okres czasu potrzebny do wykonania zadania
              m = m2 - m1;
              TextOut(hdc, 10, 270, "Czas równoleg ego wykonania zada :", 34);
              itoa(m, tab, 10);
              TextOut(hdc, 300, 270, tab, strlen(tab));
        }

      Procedura realizuje kolejno przedstawione w punktach zadania. Do obliczenia czasu
      dziaáania cz ci programu u ywamy znanej ju funkcji GetTickCount. Taki sposób licze-
      nia przedziaáów czasu jest caákiem bezpieczny, gdy zwracana przez funkcj wielko ü
Rozdziaä 8. i Projektowanie aplikacji wielowñtkowych                                     183


         jest 32-bitowa, co oznacza, e mo emy spodziewaü si zrestartowania licznika dopiero
         po 49 dniach nieprzerwanej pracy systemu Windows. Funkcje tworzonych w procedurze
         w tków maj nast puj c postaü:
            DWORD Z_M(LPVOID param)
            {
                Zbior_Mandelbrota((HDC)param);
                //zwi ksz wska nik zako czenia pracy
                zmienna_stop++;
                return 0;
            }

            DWORD Z_J(LPVOID param)
            {
                Zbior_Julii((HDC)param);
                //zwi ksz wska nik zako czenia pracy
                zmienna_stop++;
                return 0;
            }

         Kody funkcji Zbior_Mandelbrota i Zbior_Julii na razie w naszych rozwa aniach nie
         s istotne. Nale y zwróciü uwag na sposób zako czenia funkcji w tków, polegaj cy
         na inkrementacji zmiennej globalnej.
            zmienna_stop++;

         Dzi ki temu mo liwe staje si sprawdzenie zako czenia dziaáania obu w tków za po-
         moc p tli:
            do{}while(zmienna_stop<2);

         Mo emy przyj ü, e mamy pierwsz podstawow wersj aplikacji. Nie jest to jeszcze
         wersja optymalna. Popatrzmy na rysunek 8.2, na którym przedstawiam rezultat dziaáania
         programu.

Rysunek 8.2.
Okno aplikacji
Program21
w dziaáaniu
(wersja pierwsza,
niepoprawna)




         Na pocz tek nale y zauwa yü, e narysowanie zbiorów Mandelbrota i Julii za pomoc
         w tków wykonaáo si szybciej ni zadanie analogiczne, zrealizowane za pomoc sekwen-
         cyjnego wywoáania funkcji. Dzieje si tak dlatego, gdy okresy oblicze wykorzystu-
         j ce procesor s przerywane dáugimi okresami obci ania karty graficznej, podczas
184                                                   Czö è II i Dla redniozaawansowanych


      których wy wietlany jest piksel o danej wspóárz dnej w odpowiednim kolorze. Istniej
      wi c krótkie przedziaáy czasowe maáego obci enia procesora, które mo e wykorzystaü
      dla wáasnych oblicze drugi w tek. Jednak niebezpiecze stwo pracy z w tkami polega
      na tym, e system mo e zarz dziü wstrzymanie pracy w tku i przekazanie sterowania
      drugiemu w najmniej spodziewanym momencie. Je eli obydwa w tki korzystaj
      w tym czasie ze wspólnych zasobów systemowych, a tak jest w przypadku operacji
      graficznych korzystaj cych z obiektów GDI, dane mog ulec zatraceniu, czego wyni-
      kiem s niezamalowane obszary, pokazane na rysunku 8.2.

      Na szcz cie, potrafimy przeciwdziaáaü przerwaniu pracy w tku w chwili dla nas niepo-
         danej (co za ulga!). Do tego celu sáu y sekcja krytyczna, a dokáadniej obiekty sekcji
      krytycznej. W celu przybli enia sensu istnienia tego rewelacyjnego rozwi zania pro-
      gramistycznego posáu si przykáadem. Wyobra my sobie bibliotek , w której znajduje
      si jeden egzemplarz starego manuskryptu. Wyobra my sobie tak e, e setka biblio-
      filów chce w danym momencie ów egzemplarz przeczytaü. Mo e to robiü na raz tylko
      jeden fanatyk starego pi miennictwa, natomiast reszta, obgryzaj c ze zdenerwowania
      palce, mo e tylko czekaü, a szcz liwy chwilowy posiadacz obiektu zako czy prac .
      Podobn rol w pracy w tków odgrywa obiekt sekcji krytycznej: w jego posiadanie
      mo e w danej chwili wej ü tylko jeden w tek, natomiast pozostaáe w tki zawieszaj
      prac do czasu przej cia obiektu sekcji krytycznej. Oczywi cie, czekaj tylko te w tki,
      w których zaznaczono konieczno ü wej cia w posiadanie obiektu sekcji krytycznej
      w celu wykonania fragmentu kodu.

      Praca z obiektami sekcji krytycznej jest niezwykle prosta i skáada si z kilku punktów.
      Oto one.
        1. Deklaracja obiektu sekcji krytycznej. Nazwa obiektu jest dowolna, mo emy
           zadeklarowaü dowoln liczb obiektów.
             CRITICAL_SECTION critical_section;

        2. Inicjalizacja obiektu sekcji krytycznej.
             InitializeCriticalSection(&critical_section);

        3. Nast pne dwa podpunkty umieszczamy w funkcji w tków, s to:
           a) przej cie obiektu sekcji krytycznej:
             EnterCriticalSection(&critical_section);

           b) zwolnienie obiektu sekcji krytycznej:
             LeaveCriticalSection(&critical_section);

        4. Zako czenie pracy z obiektem sekcji krytycznej powinno byü zwi zane z jego
           usuni ciem.
             DeleteCriticalSection(&critical_section);

      Sposób u ycia obiektów sekcji krytycznej zobaczymy na przykáadzie kodu poprawionej
      procedury MojaProcedura i jednej z funkcji w tków Z_M. Rezultat dziaáania tak popra-
      wionego programu przedstawiam na rysunku 8.3.
Rozdziaä 8. i Projektowanie aplikacji wielowñtkowych                                     185


Rysunek 8.3.
Okno aplikacji
Program21
dziaáaj cej
z wykorzystaniem
obiektu sekcji
krytycznej




           /* Obiekt sekcji krytycznej */
           CRITICAL_SECTION critical_section;

           void MojaProcedura(HDC hdc)
           {
               char tab[32];
               DWORD pointer, m, m1, m2;

           //pobierz ilo ü milisekund od chwili uruchomienia systemu Windows
           //(czas startu zadania)
                 m1 = GetTickCount();
           //wykonaj zadanie numer 1
                 Zbior_Mandelbrota(hdc);
           //wykonaj zadanie numer 2
                 Zbior_Julii(hdc);
           //pobierz ilo ü milisekund od chwili uruchomienia systemu Windows
           //(czas zako czenia zadania)
                 m2 = GetTickCount();
           //wy wietl okres czasu potrzebny do wykonania zadania
                 m = m2 - m1;
                 TextOut(hdc, 10, 250, "Czas sekwencyjnego wykonania zada :", 35);
                 itoa(m, tab, 10);
                 TextOut(hdc, 300, 250, tab, strlen(tab));

           //wyczy ü fragment okna
                 Rectangle(hdc, 0, 0, 640, 240);
           //wyzeruj zmienn globaln dla w tków
                 zmienna_stop = 0;
           //zainicjalizuj obiekt sekcji krytycznej
                 InitializeCriticalSection(&critical_section);
           //pobierz ilo ü milisekund od chwili uruchomienia systemu Windows
           //(czas startu zadania)
                 m1 = GetTickCount();
           //wywoáaj w tek wykonuj cy zadanie numer 1
                 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Z_M, hdc, 0, &pointer);
           //wywoáaj w tek wykonuj cy zadanie numer 2
                 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Z_J, hdc, 0, &pointer);
           //czekaj na zako czenie pracy w tków
                 do{}while(zmienna_stop<2);
           //pobierz ilo ü milisekund od chwili uruchomienia systemu Windows
           //(czas zako czenia zadania)
                 m2 = GetTickCount();
186                                                 Czö è II i Dla redniozaawansowanych


        //usu obiekt sekcji krytycznej
             DeleteCriticalSection(&critical_section);
        //wy wietl okres czasu potrzebny do wykonania zadania
             m = m2 - m1;
             TextOut(hdc, 10, 270, "Czas równoleg ego wykonania zada :", 34);
             itoa(m, tab, 10);
             TextOut(hdc, 300, 270, tab, strlen(tab));
        }

        DWORD Z_M(LPVOID param)
        {

            double a_lewy = -2.0, a_prawy = 2.0;
            double b_gora = 1.5, b_dol = -1.5;
            double krokX = (a_prawy - a_lewy)/320.0;
            double krokY = (b_gora - b_dol)/240.0;
            int kolor;

            for(int y=0; y<240; y++)
                 for(int x=0; x<320; x++)
                 {
                      kolor = Kolor(a_lewy+double(x)*krokX, b_gora-double(y)*krokY);
                      //wejd w sekcj krytyczn
                      EnterCriticalSection(&critical_section);
                      //ustaw piksel
                      SetPixel((HDC)param, x, y, kolor);
                      //opu ü sekcj krytyczn
                      LeaveCriticalSection(&critical_section);
                 }
            //zwi ksz wska nik zako czenia pracy
            zmienna_stop++;
            return 0;
        }

      Poniewa funkcje graficzne zostaáy w aplikacji zamkni te w sekcje krytyczne, nie ma
      na wykresie obszarów bá dnych. Wy wietlane przez program liczby mog si ró niü
      od zaprezentowanych na ilustracji, co jest wynikiem ró nej mocy obliczeniowej kom-
      putera, a nawet ilo ci procesów korzystaj cych w danej chwili z procesora. Ostatnie
      udoskonalenie programu b dzie zwi zane ze zmian priorytetu wykonywanych w tków.

      Uruchomione w aplikacji w tki musz wspóádzieliü czas pracy procesora nie tylko
      mi dzy siebie, ale te z wywoáuj c je aplikacj gáówn i innymi uruchomionymi
      w systemie w tkami. To wydáu a czas dziaáania w tków. Zmiana tej sytuacji jest mo liwa
      za pomoc zmiany priorytetu uruchomionych w tków. Do tego zadania sáu y funkcja
      SetThreadPriority o nast puj cej deklaracji:
        BOOL SetThreadPriority(HANDLE uchwyt_watku, int priorytet);

      Parametr uchwyt_watku powinien zawieraü uchwyt w tku, którego priorytet chcemy
      zmieniü, a argumentem priorytet okre lamy warto ü priorytetu w tku. Zestawienie
      mo liwych do wyboru warto ci priorytetu przedstawiam w tabeli 8.1.

      W naszej aplikacji u yjemy najwy szego priorytetu THREAD_PRIORITY_HIGHEST, czego
      wynikiem b dzie prawie dwukrotne przyspieszenie czasu rysowania wykresów zbioru
      Mandelbrota i Julii. Oto gotowy plik Program21.h.
Rozdziaä 8. i Projektowanie aplikacji wielowñtkowych                                 187


Tabela 8.1. Priorytety uruchamianych w tków
 Staäa priorytetu                   Warto è priorytetu
 THREAD_PRIORITY_HIGHEST            +2
 THREAD_PRIORITY_ABOVE_NORMAL       +1
 THREAD_PRIORITY_NORMAL             0
 THREAD_PRIORITY_BELOW_NORMAL       -1
 THREAD_PRIORITY_LOWEST             -2

           #include <math.h>

           //zmienna globalna do sprawdzenia stanu w tków
           int zmienna_stop;

           /* Deklaracja procedur */
           void MojaProcedura(HDC);
           void Zbior_Mandelbrota(HDC);
           void Zbior_Julii(HDC);

           /* Funkcje w tków */
           DWORD Z_M(LPVOID);
           DWORD Z_J(LPVOID);

           /* Obiekt sekcji krytycznej */
           CRITICAL_SECTION critical_section;

           void MojaProcedura(HDC hdc)
           {
               char tab[32];
               DWORD pointer, m, m1, m2;
               HANDLE h;

           //pobierz ilo ü milisekund od chwili uruchomienia systemu Windows
           //(czas startu zadania)
                 m1 = GetTickCount();
           //wykonaj zadanie numer 1
                 Zbior_Mandelbrota(hdc);
           //wykonaj zadanie numer 2
                 Zbior_Julii(hdc);
           //pobierz ilo ü milisekund od chwili uruchomienia systemu Windows
           //(czas zako czenia zadania)
                 m2 = GetTickCount();
           //wy wietl okres czasu potrzebny do wykonania zadania
                 m = m2 - m1;
                 TextOut(hdc, 10, 250, "Czas sekwencyjnego wykonania zada :", 35);
                 itoa(m, tab, 10);
                 TextOut(hdc, 300, 250, tab, strlen(tab));

           //wyczy ü fragment okna
                 Rectangle(hdc, 0, 0, 640, 240);
           //wyzeruj zmienn globaln dla w tków
                 zmienna_stop = 0;
           //zainicjalizuj obiekt sekcji krytycznej
                 InitializeCriticalSection(&critical_section);
188                                               Czö è II i Dla redniozaawansowanych


      //pobierz ilo ü milisekund od chwili uruchomienia systemu Windows
      //(czas startu zadania)
            m1 = GetTickCount();
      //wywoáaj w tek wykonuj cy zadanie numer 1
            h = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Z_M, hdc, 0, &pointer);
            SetThreadPriority(h, THREAD_PRIORITY_HIGHEST);
      //wywoáaj w tek wykonuj cy zadanie numer 2
            h = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Z_J, hdc, 0, &pointer);
            SetThreadPriority(h, THREAD_PRIORITY_HIGHEST);
      //czekaj na zako czenie pracy w tków
            do{}while(zmienna_stop<2);
      //pobierz ilo ü milisekund od chwili uruchomienia systemu Windows
      //(czas zako czenia zadania)
            m2 = GetTickCount();
      //usu obiekt sekcji krytycznej
            DeleteCriticalSection(&critical_section);
      //wy wietl okres czasu potrzebny do wykonania zadania
            m = m2 - m1;
            TextOut(hdc, 10, 270, "Czas równoleg ego wykonania zada :", 34);
            itoa(m, tab, 10);
            TextOut(hdc, 300, 270, tab, strlen(tab));
      }

      int Kolor(double a0, double b0)
      {
          double an, a = a0, b = b0;
          int k = 0;
          while((sqrt(a*a+b*b)<2)&&(k<256))
          {
              an = a*a - b*b + a0;
              b = 2.0*a*b + b0;
              a = an;
              k++;
          }
          return 0xF8*k;
      }

      void Zbior_Mandelbrota(HDC hdc)
      {
          double a_lewy = -2.0, a_prawy = 2.0;
          double b_gora = 1.5, b_dol = -1.5;
          double krokX = (a_prawy - a_lewy)/320.0;
          double krokY = (b_gora - b_dol)/240.0;

          for(int y=0; y<240; y++)
              for(int x=0; x<320; x++)
                  SetPixel(hdc, x, y, Kolor(a_lewy+double(x)*krokX,
                                            b_gora-double(y)*krokY));
      }

      int jKolor(double a0, double b0)
      {
          double an, a = a0, b = b0;
          int k = 0;
          while((sqrt(a*a+b*b)<2)&&(k<256))
          {
              an = a*a - b*b + 0.373;
              b = 2.0*a*b + 0.133;
Rozdziaä 8. i Projektowanie aplikacji wielowñtkowych                                   189


                  a = an;
                  k++;
              }
              return 0xF8*k;
          }

          void Zbior_Julii(HDC hdc)
          {
              double a_lewy = -2.0, a_prawy = 2.0;
              double b_gora = 1.5, b_dol = -1.5;
              double krokX = (a_prawy - a_lewy)/320.0;
              double krokY = (b_gora - b_dol)/240.0;

              for(int y=0; y<240; y++)
                  for(int x=0; x<320; x++)
                      SetPixel(hdc, 320+x, y, jKolor(a_lewy+double(x)*krokX,
                                                     b_gora-double(y)*krokY));
          }

          DWORD Z_M(LPVOID param)
          {


              double a_lewy = -2.0, a_prawy = 2.0;
              double b_gora = 1.5, b_dol = -1.5;
              double krokX = (a_prawy - a_lewy)/320.0;
              double krokY = (b_gora - b_dol)/240.0;
              int kolor;

              for(int y=0; y<240; y++)
                  for(int x=0; x<320; x++)
                  {
                      kolor = Kolor(a_lewy+double(x)*krokX, b_gora-double(y)*krokY);
                      //wejd w sekcj krytyczn
                      EnterCriticalSection(&critical_section);
                      //zapal piksel
                      SetPixel((HDC)param, x, y, kolor);
                      //opu ü sekcj krytyczn
                      LeaveCriticalSection(&critical_section);
                  }

              //zwi ksz wska nik zako czenia pracy
              zmienna_stop++;
              return 0;
          }

          DWORD Z_J(LPVOID param)
          {
              double a_lewy = -2.0, a_prawy = 2.0;
              double b_gora = 1.5, b_dol = -1.5;
              double krokX = (a_prawy - a_lewy)/320.0;
              double krokY = (b_gora - b_dol)/240.0;
              int kolor;

              for(int y=0; y<240; y++)
                  for(int x=0; x<320; x++)
190                                                     Czö è II i Dla redniozaawansowanych


                    {
                         kolor = jKolor(a_lewy+double(x)*krokX, b_gora-double(y)*krokY);
                         //wejd w sekcj krytyczn
                         EnterCriticalSection(&critical_section);
                         //ustaw piksel
                         SetPixel((HDC)param, 320+x, y, kolor);
                         //opu ü sekcj krytyczn
                         LeaveCriticalSection(&critical_section);
                    }

                //zwi ksz wska nik zako czenia pracy
                zmienna_stop++;
                return 0;
           }

        Rezultat dziaáania programu przedstawiam na rysunku 8.4.

Rysunek 8.4.
Okno aplikacji
Program21
dziaáaj cej
z wykorzystaniem
obiektu sekcji
krytycznej
i ustawionym
najwy szym
priorytetem pracy
w tków




8.3. Wstrzymywanie pracy
     i usuwanie wñtków
        Zapewne przynajmniej raz spotkali cie si z irytuj cym edytorem tekstowym, który —
        doskonale wiedz c, co chcemy napisaü — z zadziwiaj cym uporem poprawiaá postaü
        wpisywanego tekstu. Oto nadszedá czas zemsty i w niniejszym podrozdziale zajmiemy
        si konstruowaniem podobnego, tylko jeszcze bardziej záo liwego edytora. Niezwykle
        pomocna przy tym b dzie umiej tno ü tworzenia w tków, które niczym duch b d
         ledziáy wpisywany przez u ytkownika tekst, dokonuj c jego modyfikacji.

        Znamy ju trzy czynno ci zwi zane z w tkami.
           1. Utworzenie w tku. Do tego zadania sáu y funkcja CreateThread.
           2. Obsáuga obiektów sekcji krytycznej. Wykorzystywane do tego celu funkcje to:
              InitializeCriticalSection, EnterCriticalSection, LeaveCriticalSection
              i DeleteCriticalSection.
           3. Zmiana priorytetu w tku. Do tego zadania sáu y funkcja SetThreadPriority.
Rozdziaä 8. i Projektowanie aplikacji wielowñtkowych                                      191


        Je eli chcemy chwilowo zawiesiü dziaáanie w tku, posáu ymy si funkcj Suspend
        ´Thread o nast puj cej skáadni:
          DWORD SuspendThread(HANDLE uchwyt_watku);

        Jedynym parametrem funkcji jest uchwyt wstrzymywanego w tku. Wznowienie pracy
        w tku jest mo liwe za pomoc funkcji ResumeThread:
          DWORD ResumeThread(HANDLE uchwyt_watku);

        Gdy dziaáalno ü w tku zupeánie nam zbrzydáa, mo emy go usun ü za pomoc funkcji
        TerminateThread:
          BOOL TerminateThread(HANDLE uchwyt_watku, DWORD kod_wyjscia);

        Argument uchwyt_watku to — oczywi cie — uchwyt usuwanego w tku. Posáuguj c
        si parametrem kod_wyjscia, mo emy wysáaü kod zako czenia pracy w tku. Ten pa-
        rametr najcz ciej nie b dzie nas interesowaá i w jego miejsce b dziemy wpisywaü
        liczb zero.

        Przyst pujemy do budowania aplikacji uwzgl dniaj cej nowo poznane funkcje: Sus
        ´pendThread i ResumeThread. Otwieramy nowy projekt o nazwie Program22.dev. Obszar
        roboczy okna podzielimy na dwie cz ci: w cz ci pierwszej umie cimy okno potomne
        klasy edycji, w cz ci drugiej — przyciski typu BS_AUTORADIOBUTTON. Okno potomne
        tworzymy za pomoc funkcji CreateWindow. Okno klasy edycji wykreujemy przy u y-
        ciu nast puj cego kodu:
          static HWND hwndEdytora = CreateWindowEx(
                 0,
                 "EDIT",
                 NULL,
                 WS_VISIBLE | WS_CHILD | WS_BORDER | ES_MULTILINE | WS_VSCROLL | WS_HSCROLL,
                 0, 0, 400, 200,
                 hwnd, NULL, hInst, NULL);

        Nazw klasy okna potomnego podajemy jako drugi parametr funkcji CreateWindow.
        Natomiast styl okna zdefiniowany za pomoc staáych:
          WS_VISIBLE | WS_CHILD | WS_BORDER | ES_MULTILINE | WS_VSCROLL | WS_HSCROLL

        utworzy edytor wielowierszowy o poziomym i pionowym pasku przewijania. Podsta-
        wowe wáasno ci okna klasy edycji to mo liwo ü edycji tekstu, jego pobierania i wstawia-
        nia tekstu nowego. Zaáó my, e chcemy pobraü wpisany w oknie tekst. T niezwyká
        ch ü mo emy zaspokoiü na dwa sposoby: wykorzystuj c funkcj GetWindowText lub
        wysyáaj c komunikat WM_GETTEXT. Kod programu, w którym zastosowali my funkcj
        GetWindowText, b dzie wygl daü nast puj co:
          const int MaxT = 0xFFFF;
          char tekst[MaxT];
          GetWindowText(hwndEdytora, tekst, MaxT);

        Analogiczny efekt uzyskamy, wysyáaj c komunikat WM_GETTEXT:
          const int MaxT = 0xFFFF;
          char tekst[MaxT];
          SendMessage(hwndEdytora, WM_GETTEXT, MaxT, (LPARAM)tekst);
192                                                     Czö è II i Dla redniozaawansowanych


      Parametrem MaxT oznaczamy maksymaln liczb pobieranych znaków.

      Wysáanie tekstu do okna edycji równie mo emy zrealizowaü na dwa sposoby. Pierw-
      szym z nich jest u ycie funkcji SetWindowText:
        SetWindowText(hwndEdytora, tekst);

      Drugim sposobem jest wysáanie komunikatu WM_SETTEXT:
        SendMessage(hwndEdytora, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)tekst);

      Do ü káopotliw wáasno ci klasy edycji jest resetowanie pozycji karetki po ka dora-
      zowym wysáaniu tekstu do okna edycji. Do ustawienia pozycji karetki sáu y funkcja
      SetCaretPos, jednak — zgodnie z opisem Pomocy Microsoft Windows — funkcja
      dziaáa tylko dla karetek utworzonych przez okno, czyli nie dziaáa dla obiektów klasy
      edycji. Posáu ymy si wybiegiem, a dokáadniej wysáaniem komunikatu EM_SETSEL.
        SendMessage(hwndEdytora, EM_SETSEL, poczatek, koniec);

      Komunikat EM_SETSEL jest wysyáany w celu zaznaczenia bloku tekstu, pocz wszy od
      litery o indeksie poczatek i ko cu oznaczonym indeksem koniec. Po wykonaniu tego
      zadania karetka jest ustawiana w punkcie oznaczonym indeksem koniec. U ycie komu-
      nikatu w nast puj cy sposób:
        SendMessage(hwndEdytora, EM_SETSEL, x, x);

      jest áatwym sposobem przemieszczania pozycji karetki do pozycji x w oknie edycji.

      Przejd my do omawiania kluczowej cz ci programu, czyli do obsáugi w tków. W chwili
      uruchomienia aplikacji tworzone s dwa w tki, z których aktywny mo e byü tylko jeden
      lub aden.
        //uruchom pierwszy w tek sprawdzania pisowni
        watek1 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PisowniaPierwszaDuza,
                                   hwndEdytora, 0, &p);
        //uruchom drugi w tek sprawdzania pisowni
        watek2 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PisowniaWszystkieDuze,
                                   hwndEdytora, 0, &p);
        //wstrzymaj dziaáanie w tku drugiego
        SuspendThread(watek2);
        //ustaw wska nik uruchomionego w tku
        flaga = 1;

      Zmienna globalna flaga sáu y do zaznaczenia aktywno ci w tku. Przeá czanie aktyw-
      no ci w tków, zgodnie z konfiguracj przycisków klasy BS_AUTORADIOBUTTON, zostaáo
      zaimplementowane w kodzie obsáugi komunikatu WM_COMMAND.
        case WM_COMMAND:
            switch(LOWORD(wParam))
            {
                case 1001:
                    switch(flaga)
                    {
                        case 2:
                            //wstrzymaj dziaáanie w tku drugiego
                            SuspendThread(watek2);
Rozdziaä 8. i Projektowanie aplikacji wielowñtkowych                                                193


                           case 3:
                               //pocz tek nowego formatowania ustawiany jest
                               //na ostatni wprowadzony znak
                               GetWindowText(hwndEdytora, tekst, MaxT);
                               pocz_format = strlen(tekst);
                               //ponownie uruchom w tek pierwszy
                               ResumeThread(watek1);
                               break;
                      }
                      flaga = 1;
                      break;
                  case 1002:
                      switch(flaga)
                      {
                          case 1:
                              //wstrzymaj dziaáanie w tku pierwszego
                              SuspendThread(watek1);
                          case 3:
                              //pocz tek nowego formatowania ustawiany jest na ostatni wprowadzony znak
                              GetWindowText(hwndEdytora, tekst, MaxT);
                              pocz_format = strlen(tekst);
                              //ponownie uruchom w tek drugi
                              ResumeThread(watek2);
                              break;
                      }
                      flaga = 2;
                      break;
                  case 1003:
                      switch(flaga)
                      {
                          case 1:
                              //wstrzymaj dziaáanie w tku pierwszego
                              SuspendThread(watek1);
                              break;
                          case 2:
                              //wstrzymaj dziaáanie w tku drugiego
                              SuspendThread(watek2);
                              break;
                      }
                      flaga = 3;
                      break;
                  case 1010:
                      SendMessage(hwnd, WM_DESTROY, 0, 0);
                      break;
              }
              break;

        Dzi ki uwzgl dnieniu zmiennej pocz_poz modyfikacje tekstu nie wywoáuj zmian
        w tek cie wpisanym przed wybraniem kolejnego sposobu formatowania. Staáe parametru
        wParam odpowiadaj identyfikatorom okien potomnych klasy BS_AUTORADIOBUTTON.
        Aktywny w tek co sekund sprawdza wpisany tekst, generuj c zmiany zgodne z wybra-
        nym sposobem formatowania. Dzi ki zastosowanym w tkom kod pliku Program22_
        main.cpp nie jest skomplikowany, w caáo ci wygl da nast puj co:
194                                                 Czö è II i Dla redniozaawansowanych


      #include <windows.h>

      const int MaxT = 0xFFFF;
      char tekst[MaxT];

      /* znacznik uruchomionego w tku*/
      int flaga;
      /* Uchwyty w tków*/
      HANDLE watek1, watek2;
      /* wska nik pocz tku formatowania tekstu */
      int pocz_format;

      /* Deklaracja funkcji w tku */
      DWORD PisowniaPierwszaDuza(LPVOID parametr);
      DWORD PisowniaWszystkieDuze(LPVOID parametr);

      LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
      char szClassName[ ] = "WindowsApp";

      int WINAPI WinMain (HINSTANCE hThisInstance,
                          HINSTANCE hPrevInstance,
                          LPSTR lpszArgument,
                          int nFunsterStil)
      {
          HWND hwnd;
          MSG messages;
          WNDCLASSEX wincl;

          wincl.hInstance = hThisInstance;
          wincl.lpszClassName = szClassName;
          wincl.lpfnWndProc = WindowProcedure;
          wincl.style = CS_DBLCLKS;
          wincl.cbSize = sizeof (WNDCLASSEX);
          wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
          wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
          wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
          wincl.lpszMenuName = NULL;
          wincl.cbClsExtra = 0;
          wincl.cbWndExtra = 0;
          wincl.hbrBackground = (HBRUSH) COLOR_BTNSHADOW;

          if (!RegisterClassEx (&wincl))
              return 0;

          hwnd = CreateWindowEx (
                 0,
                 szClassName,
                 "Program22",
                 WS_OVERLAPPEDWINDOW,
                 CW_USEDEFAULT,
                 CW_USEDEFAULT,
                 410,
                 375,
                 HWND_DESKTOP,
                 NULL,
                 hThisInstance,
Rozdziaä 8. i Projektowanie aplikacji wielowñtkowych                                      195


                     NULL
                     );

              ShowWindow (hwnd, nFunsterStil);

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

              return messages.wParam;
          }

          LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam,
          ´LPARAM lParam)
          {
              DWORD p;

              switch (message)
              {
                  case WM_CREATE:
                      static HINSTANCE hInst = (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE);

                      //utwórz okno edycji
                      static HWND hwndEdytora = CreateWindowEx(
                      0, "EDIT", NULL,
                      WS_VISIBLE | WS_CHILD | WS_BORDER | ES_MULTILINE | WS_VSCROLL |
                      ´WS_HSCROLL,
                      0, 0, 400, 200, hwnd, NULL, hInst, NULL);

                      CreateWindowEx(0, "BUTTON", "Opcje formatowania tekstu",
                      WS_VISIBLE | WS_CHILD | BS_GROUPBOX,
                      5, 210, 220, 110, hwnd, NULL, hInst, NULL);

                      static HWND hwndRadio1 = CreateWindowEx(
                      0, "BUTTON", "Du e pierwsze litery",
                      WS_VISIBLE | WS_CHILD | WS_GROUP | BS_AUTORADIOBUTTON,
                      10, 240, 170, 20, hwnd, (HMENU)1001, hInst, NULL);

                      static HWND hwndRadio2 = CreateWindowEx(
                      0, "BUTTON", "Du e wszystkie litery",
                      WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON,
                      10, 260, 170, 20, hwnd, (HMENU)1002, hInst, NULL);

                      static HWND hwndRadio3 = CreateWindowEx(
                      0, "BUTTON", "Bez modyfikacji",
                      WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON,
                      10, 280, 170, 20, hwnd, (HMENU)1003, hInst, NULL);

                      CreateWindowEx(0, "BUTTON", "Koniec",
                      WS_VISIBLE | WS_CHILD, 260, 230, 110, 80,
                      hwnd, (HMENU)1010, hInst, NULL);

                      //uruchom pierwszy w tek sprawdzania pisowni
                      watek1 = CreateThread(NULL, 0,
                            (LPTHREAD_START_ROUTINE)PisowniaPierwszaDuza, hwndEdytora, 0, &p);
196                                         Czö è II i Dla redniozaawansowanych


          //uruchom drugi w tek sprawdzania pisowni
          watek2 = CreateThread(NULL, 0,
                (LPTHREAD_START_ROUTINE)PisowniaWszystkieDuze, hwndEdytora, 0, &p);
          //wstrzymaj dziaáanie w tku drugiego
          SuspendThread(watek2);
          //ustaw wska nik uruchomionego w tku
          flaga = 1;
          //ustaw domy ln opcj
          SendMessage(hwndRadio1, BM_SETCHECK, 1001, 0);
          //ustaw zakres zmian tekstu
          pocz_format = 0;
          break;
      case WM_COMMAND:
          switch(LOWORD(wParam))
          {
                case 1001:
                    switch(flaga)
                    {
                         case 2:
                              //wstrzymaj dziaáanie w tku drugiego
                              SuspendThread(watek2);
                         case 3:
                              //pocz tek nowego formatowania ustawiany jest na ostatni
                              //wprowadzony znak
                              GetWindowText(hwndEdytora, tekst, MaxT);
                              pocz_format = strlen(tekst);
                              //ponownie uruchom w tek pierwszy
                              ResumeThread(watek1);
                              break;
                    }
                    flaga = 1;
                    break;
                case 1002:
                    switch(flaga)
                    {
                         case 1:
                              //wstrzymaj dziaáanie w tku pierwszego
                              SuspendThread(watek1);
                         case 3:
                              //pocz tek nowego formatowania ustawiany jest na ostatni
                              //wprowadzony znak
                              GetWindowText(hwndEdytora, tekst, MaxT);
                              pocz_format = strlen(tekst);
                              //ponownie uruchom w tek drugi
                              ResumeThread(watek2);
                              break;
                    }
                    flaga = 2;
                    break;
                case 1003:
                    switch(flaga)
                    {
                         case 1:
                              //wstrzymaj dziaáanie w tku pierwszego
                              SuspendThread(watek1);
                              break;
Rozdziaä 8. i Projektowanie aplikacji wielowñtkowych                                         197


                                     case 2:
                                         //wstrzymaj dziaáanie w tku drugiego
                                         SuspendThread(watek2);
                                         break;
                               }
                               flaga = 3;
                               break;
                           case 1010:
                               SendMessage(hwnd, WM_DESTROY, 0, 0);
                               break;
                      }
                      break;
                  case WM_DESTROY:
                      PostQuitMessage (0);
                      break;
                  default:
                      return DefWindowProc (hwnd, message, wParam, lParam);
              }

              return 0;
          }

          DWORD PisowniaPierwszaDuza(LPVOID parametr)
          {
              int i, pozycja;

              //dziaáaj a do odwoáania
              while(TRUE)
              {
                    //pobierz tekst okna
                    GetWindowText((HWND)parametr, tekst, MaxT);

                  //popraw tekst
                  i = pocz_format;
                  while(tekst[i])
                  {
                       //postaw du liter , gdy jest to pierwszy znak
                       if((i==pocz_format)&&(tekst[i]>=97&&tekst[i]<=122)) tekst[i] -= 32;
                       //lub jest to znak po spacji, lub znaku nowej linii
                       if(tekst[i]==32||tekst[i]=='n')
                       {
                             if(tekst[i+1]>=97&&tekst[i+1]<=122) tekst[i+1] -= 32;
                             //sprawd polskie znaki
                             if(tekst[i+1]=='æ') tekst[i+1] = 'ä';
                             if(tekst[i+1]=='è') tekst[i+1] = 'ç';
                             if(tekst[i+1]=='ú') tekst[i+1] = 'ù';
                             if(tekst[i+1]==' ') tekst[i+1] = ' ';
                             if(tekst[i+1]==' ') tekst[i+1] = ' ';
                             if(tekst[i+1]=='ó') tekst[i+1] = 'Ó';
                             if(tekst[i+1]==' ') tekst[i+1] = ' ';
                             if(tekst[i+1]==' ') tekst[i+1] = ' ';
                             if(tekst[i+1]==' ') tekst[i+1] = ' ';
                       }

                      //zwi ksz licznik
                      i++;
198                                                Czö è II i Dla redniozaawansowanych


              }

              //wy lij poprawiony tekst do okna edycji
              SetWindowText((HWND)parametr, tekst);
              //ustaw karetk na koniec tekstu
              SendMessage((HWND)parametr, EM_SETSEL, i, i);

              //zaczekaj
              Sleep(1000);
          }

          return 0;
      }

      DWORD PisowniaWszystkieDuze(LPVOID parametr)
      {
          int i, pozycja;

          //dziaáaj a do odwoáania
          while(TRUE)
          {
                //pobierz tekst okna
                GetWindowText((HWND)parametr, tekst, MaxT);

              //popraw tekst
              i = pocz_format;
              while(tekst[i])
              {
                   //postaw du liter w miejsce maáej
                   if(tekst[i]>=97&&tekst[i]<=122) tekst[i] -= 32;
                   //sprawd polskie znaki
                   if(tekst[i]=='æ') tekst[i] = 'ä';
                   if(tekst[i]=='è') tekst[i] = 'ç';
                   if(tekst[i]=='ú') tekst[i] = 'ù';
                   if(tekst[i]==' ') tekst[i] = ' ';
                   if(tekst[i]==' ') tekst[i] = ' ';
                   if(tekst[i]=='ó') tekst[i] = 'Ó';
                   if(tekst[i]==' ') tekst[i] = ' ';
                   if(tekst[i]==' ') tekst[i] = ' ';
                   if(tekst[i]==' ') tekst[i] = ' ';

                  //zwi ksz licznik
                  i++;
              }

              //wy lij poprawiony tekst do okna edycji
              SetWindowText((HWND)parametr, tekst);
              //ustaw karetk na koniec tekstu
              SendMessage((HWND)parametr, EM_SETSEL, i, i);

              //zaczekaj
              Sleep(1000);
          }

          return 0;
      }
Rozdziaä 8. i Projektowanie aplikacji wielowñtkowych                                                199


           Okno gáówne dziaáaj cej aplikacji prezentuj na rysunku 8.5. W celu zilustrowania dzia-
           áania programu wykorzystaáem fragment wspaniaáej powie ci Arkadija i Borysa Stru-
           gackich Poniedziaáek zaczyna si w sobot 1.

Rysunek 8.5.
Okno gáówne aplikacji
Program22




8.4. çwiczenia
           ûwiczenie 13. Zaprojektuj aplikacj , w której w obszarze roboczym okna wy wietlany
           b dzie czas systemowy. W lewej cz ci obszaru okna czas b dzie wy wietlany w postaci
           cyfrowej, praw cz ü okna zajmie tarcza zegara o klasycznej postaci (patrz rysunek 8.6).
           Do obsáugi zegarów u yj dwóch w tków.

Rysunek 8.6.
Okno gáówne aplikacji
Cwiczenie13




           ûwiczenie 14. Uruchomione w aplikacji Program22 w tki sáu yáy do automatycznego
           poprawiania pisowni w edytorze tekstowym. Zaprojektuj podobn aplikacj dziaáaj c
           w edytorze graficznym, w której uruchomiony w tek b dzie zamieniaá narysowane linie
           krzywe w linie proste (sposób dziaáania programu zilustrowano na rysunku 8.7).




1
    Arkadij Strugacki, Borys Strugacki, Poniedziaáek zaczyna si w sobot , táum. Irena Piotrowska,
    Warszawa 1970, s. 17.
200                                                      Czö è II i Dla redniozaawansowanych




Rysunek 8.7. Ilustracja dziaáania programu Cwiczenie14

More Related Content

What's hot

Po prostu Mac OS X 10.5 Leopard PL
Po prostu Mac OS X 10.5 Leopard PLPo prostu Mac OS X 10.5 Leopard PL
Po prostu Mac OS X 10.5 Leopard PLWydawnictwo Helion
 
Po prostu Windows Vista PL. Wydanie II
Po prostu Windows Vista PL. Wydanie IIPo prostu Windows Vista PL. Wydanie II
Po prostu Windows Vista PL. Wydanie IIWydawnictwo Helion
 
Windows XP PL. Ilustrowany przewodnik
Windows XP PL. Ilustrowany przewodnikWindows XP PL. Ilustrowany przewodnik
Windows XP PL. Ilustrowany przewodnikWydawnictwo Helion
 
Java. Współbieżność dla praktyków
Java. Współbieżność dla praktykówJava. Współbieżność dla praktyków
Java. Współbieżność dla praktykówWydawnictwo Helion
 
Photoshop CS3/CS3 PL. Warstwy. Biblia
Photoshop CS3/CS3 PL. Warstwy. BibliaPhotoshop CS3/CS3 PL. Warstwy. Biblia
Photoshop CS3/CS3 PL. Warstwy. BibliaWydawnictwo Helion
 
Informatyka Europejczyka. Zeszyt ćwiczeń dla szkoły podstawowej. Część I
Informatyka Europejczyka. Zeszyt ćwiczeń dla szkoły podstawowej. Część IInformatyka Europejczyka. Zeszyt ćwiczeń dla szkoły podstawowej. Część I
Informatyka Europejczyka. Zeszyt ćwiczeń dla szkoły podstawowej. Część IWydawnictwo Helion
 
Visual Basic 2008. Warsztat programisty
Visual Basic 2008. Warsztat programistyVisual Basic 2008. Warsztat programisty
Visual Basic 2008. Warsztat programistyWydawnictwo Helion
 
Fotografia cyfrowa. Poradnik bez kantów
Fotografia cyfrowa. Poradnik bez kantówFotografia cyfrowa. Poradnik bez kantów
Fotografia cyfrowa. Poradnik bez kantówWydawnictwo Helion
 
Flash CS3 Professional PL. Klatka po klatce
Flash CS3 Professional PL. Klatka po klatceFlash CS3 Professional PL. Klatka po klatce
Flash CS3 Professional PL. Klatka po klatceWydawnictwo Helion
 
Visual Studio 2005. Programowanie z Windows API w języku C++
Visual Studio 2005. Programowanie z Windows API w języku C++Visual Studio 2005. Programowanie z Windows API w języku C++
Visual Studio 2005. Programowanie z Windows API w języku C++Wydawnictwo Helion
 
Flash CS3 Professional PL. Techniki zaawansowane. Klatka po klatce
Flash CS3 Professional PL. Techniki zaawansowane. Klatka po klatceFlash CS3 Professional PL. Techniki zaawansowane. Klatka po klatce
Flash CS3 Professional PL. Techniki zaawansowane. Klatka po klatceWydawnictwo Helion
 
Microsoft Visual Studio 2008. Księga eksperta
Microsoft Visual Studio 2008. Księga ekspertaMicrosoft Visual Studio 2008. Księga eksperta
Microsoft Visual Studio 2008. Księga ekspertaWydawnictwo Helion
 
Adobe Illustrator 10. Ćwiczenia
Adobe Illustrator 10. ĆwiczeniaAdobe Illustrator 10. Ćwiczenia
Adobe Illustrator 10. ĆwiczeniaWydawnictwo Helion
 
Photoshop Elements 2. Szybki start
Photoshop Elements 2. Szybki startPhotoshop Elements 2. Szybki start
Photoshop Elements 2. Szybki startWydawnictwo Helion
 

What's hot (20)

Po prostu Mac OS X 10.5 Leopard PL
Po prostu Mac OS X 10.5 Leopard PLPo prostu Mac OS X 10.5 Leopard PL
Po prostu Mac OS X 10.5 Leopard PL
 
Po prostu Windows Vista PL. Wydanie II
Po prostu Windows Vista PL. Wydanie IIPo prostu Windows Vista PL. Wydanie II
Po prostu Windows Vista PL. Wydanie II
 
CorelDraw X3 PL. Kurs
CorelDraw X3 PL. KursCorelDraw X3 PL. Kurs
CorelDraw X3 PL. Kurs
 
Windows XP PL. Ilustrowany przewodnik
Windows XP PL. Ilustrowany przewodnikWindows XP PL. Ilustrowany przewodnik
Windows XP PL. Ilustrowany przewodnik
 
Blender. Podstawy modelowania
Blender. Podstawy modelowaniaBlender. Podstawy modelowania
Blender. Podstawy modelowania
 
Linux. Kurs. Wydanie II
Linux. Kurs. Wydanie IILinux. Kurs. Wydanie II
Linux. Kurs. Wydanie II
 
Java. Współbieżność dla praktyków
Java. Współbieżność dla praktykówJava. Współbieżność dla praktyków
Java. Współbieżność dla praktyków
 
Photoshop CS3/CS3 PL. Warstwy. Biblia
Photoshop CS3/CS3 PL. Warstwy. BibliaPhotoshop CS3/CS3 PL. Warstwy. Biblia
Photoshop CS3/CS3 PL. Warstwy. Biblia
 
Informatyka Europejczyka. Zeszyt ćwiczeń dla szkoły podstawowej. Część I
Informatyka Europejczyka. Zeszyt ćwiczeń dla szkoły podstawowej. Część IInformatyka Europejczyka. Zeszyt ćwiczeń dla szkoły podstawowej. Część I
Informatyka Europejczyka. Zeszyt ćwiczeń dla szkoły podstawowej. Część I
 
Visual Basic 2008. Warsztat programisty
Visual Basic 2008. Warsztat programistyVisual Basic 2008. Warsztat programisty
Visual Basic 2008. Warsztat programisty
 
Fotografia cyfrowa. Poradnik bez kantów
Fotografia cyfrowa. Poradnik bez kantówFotografia cyfrowa. Poradnik bez kantów
Fotografia cyfrowa. Poradnik bez kantów
 
Po prostu Flash MX 2004
Po prostu Flash MX 2004Po prostu Flash MX 2004
Po prostu Flash MX 2004
 
Flash CS3 Professional PL. Klatka po klatce
Flash CS3 Professional PL. Klatka po klatceFlash CS3 Professional PL. Klatka po klatce
Flash CS3 Professional PL. Klatka po klatce
 
C++BuilderX. Ćwiczenia
C++BuilderX. ĆwiczeniaC++BuilderX. Ćwiczenia
C++BuilderX. Ćwiczenia
 
Visual Studio 2005. Programowanie z Windows API w języku C++
Visual Studio 2005. Programowanie z Windows API w języku C++Visual Studio 2005. Programowanie z Windows API w języku C++
Visual Studio 2005. Programowanie z Windows API w języku C++
 
Flash CS3 Professional PL. Techniki zaawansowane. Klatka po klatce
Flash CS3 Professional PL. Techniki zaawansowane. Klatka po klatceFlash CS3 Professional PL. Techniki zaawansowane. Klatka po klatce
Flash CS3 Professional PL. Techniki zaawansowane. Klatka po klatce
 
Microsoft Visual Studio 2008. Księga eksperta
Microsoft Visual Studio 2008. Księga ekspertaMicrosoft Visual Studio 2008. Księga eksperta
Microsoft Visual Studio 2008. Księga eksperta
 
Adobe Illustrator 10. Ćwiczenia
Adobe Illustrator 10. ĆwiczeniaAdobe Illustrator 10. Ćwiczenia
Adobe Illustrator 10. Ćwiczenia
 
Photoshop Elements 2. Szybki start
Photoshop Elements 2. Szybki startPhotoshop Elements 2. Szybki start
Photoshop Elements 2. Szybki start
 
Po prostu Flash MX
Po prostu Flash MXPo prostu Flash MX
Po prostu Flash MX
 

Similar to Tworzenie aplikacji dla Windows. Od prostych programów do gier komputerowych

Master Thesis - Comparative analysis of programming Environments based on Rub...
Master Thesis - Comparative analysis of programming Environments based on Rub...Master Thesis - Comparative analysis of programming Environments based on Rub...
Master Thesis - Comparative analysis of programming Environments based on Rub...Adam Skołuda
 
Informatyka Europejczyka. Zeszyt ćwiczeń dla szkoły podstawowej. Część II
Informatyka Europejczyka. Zeszyt ćwiczeń dla szkoły podstawowej. Część IIInformatyka Europejczyka. Zeszyt ćwiczeń dla szkoły podstawowej. Część II
Informatyka Europejczyka. Zeszyt ćwiczeń dla szkoły podstawowej. Część IIWydawnictwo Helion
 
Serwer SQL 2008. Administracja i programowanie
Serwer SQL 2008. Administracja i programowanieSerwer SQL 2008. Administracja i programowanie
Serwer SQL 2008. Administracja i programowanieWydawnictwo Helion
 
Pajączek 5 NxG. Oficjalny podręcznik
Pajączek 5 NxG. Oficjalny podręcznikPajączek 5 NxG. Oficjalny podręcznik
Pajączek 5 NxG. Oficjalny podręcznikWydawnictwo Helion
 
Mgr Paweł Traczyński 3266 - Praca dypl
Mgr Paweł Traczyński 3266 - Praca dyplMgr Paweł Traczyński 3266 - Praca dypl
Mgr Paweł Traczyński 3266 - Praca dyplPawe? Traczy?ski
 
.Net. Najpilniej strzeżone tajemnice
.Net. Najpilniej strzeżone tajemnice.Net. Najpilniej strzeżone tajemnice
.Net. Najpilniej strzeżone tajemniceWydawnictwo Helion
 
Aplikacje w Visual C++ 2005. Przykłady
Aplikacje w Visual C++ 2005. PrzykładyAplikacje w Visual C++ 2005. Przykłady
Aplikacje w Visual C++ 2005. PrzykładyWydawnictwo Helion
 
Komputer PC w biurze i nie tylko
Komputer PC w biurze i nie tylkoKomputer PC w biurze i nie tylko
Komputer PC w biurze i nie tylkoWydawnictwo Helion
 
Niezawodne strategie-wygrywania-w-sieci
Niezawodne strategie-wygrywania-w-sieciNiezawodne strategie-wygrywania-w-sieci
Niezawodne strategie-wygrywania-w-sieciPrzemysław Wolny
 
Visual C# 2005 Express Edition. Od podstaw
Visual C# 2005 Express Edition. Od podstawVisual C# 2005 Express Edition. Od podstaw
Visual C# 2005 Express Edition. Od podstawWydawnictwo Helion
 
Core Java Servlets i JavaServer Pages. Tom II. Wydanie II
Core Java Servlets i JavaServer Pages. Tom II. Wydanie IICore Java Servlets i JavaServer Pages. Tom II. Wydanie II
Core Java Servlets i JavaServer Pages. Tom II. Wydanie IIWydawnictwo Helion
 
Linux. Niezbędnik programisty
Linux. Niezbędnik programistyLinux. Niezbędnik programisty
Linux. Niezbędnik programistyWydawnictwo Helion
 
Adobe Dreamweaver CS3/CS3 PL. Oficjalny podręcznik
Adobe Dreamweaver CS3/CS3 PL. Oficjalny podręcznikAdobe Dreamweaver CS3/CS3 PL. Oficjalny podręcznik
Adobe Dreamweaver CS3/CS3 PL. Oficjalny podręcznikWydawnictwo Helion
 
Photoshop CS2/CS2 PL. Prosto do celu
Photoshop CS2/CS2 PL. Prosto do celuPhotoshop CS2/CS2 PL. Prosto do celu
Photoshop CS2/CS2 PL. Prosto do celuWydawnictwo Helion
 
CATIA V5. Podstawy budowy modeli autogenerujących
CATIA V5. Podstawy budowy modeli autogenerującychCATIA V5. Podstawy budowy modeli autogenerujących
CATIA V5. Podstawy budowy modeli autogenerującychWydawnictwo Helion
 

Similar to Tworzenie aplikacji dla Windows. Od prostych programów do gier komputerowych (19)

Master Thesis - Comparative analysis of programming Environments based on Rub...
Master Thesis - Comparative analysis of programming Environments based on Rub...Master Thesis - Comparative analysis of programming Environments based on Rub...
Master Thesis - Comparative analysis of programming Environments based on Rub...
 
Informatyka Europejczyka. Zeszyt ćwiczeń dla szkoły podstawowej. Część II
Informatyka Europejczyka. Zeszyt ćwiczeń dla szkoły podstawowej. Część IIInformatyka Europejczyka. Zeszyt ćwiczeń dla szkoły podstawowej. Część II
Informatyka Europejczyka. Zeszyt ćwiczeń dla szkoły podstawowej. Część II
 
Serwer SQL 2008. Administracja i programowanie
Serwer SQL 2008. Administracja i programowanieSerwer SQL 2008. Administracja i programowanie
Serwer SQL 2008. Administracja i programowanie
 
Pajączek 5 NxG. Oficjalny podręcznik
Pajączek 5 NxG. Oficjalny podręcznikPajączek 5 NxG. Oficjalny podręcznik
Pajączek 5 NxG. Oficjalny podręcznik
 
C++Builder 6. Ćwiczenia
C++Builder 6. ĆwiczeniaC++Builder 6. Ćwiczenia
C++Builder 6. Ćwiczenia
 
Mgr Paweł Traczyński 3266 - Praca dypl
Mgr Paweł Traczyński 3266 - Praca dyplMgr Paweł Traczyński 3266 - Praca dypl
Mgr Paweł Traczyński 3266 - Praca dypl
 
.Net. Najpilniej strzeżone tajemnice
.Net. Najpilniej strzeżone tajemnice.Net. Najpilniej strzeżone tajemnice
.Net. Najpilniej strzeżone tajemnice
 
Contribute 2. Szybki start
Contribute 2. Szybki startContribute 2. Szybki start
Contribute 2. Szybki start
 
mgr
mgrmgr
mgr
 
Aplikacje w Visual C++ 2005. Przykłady
Aplikacje w Visual C++ 2005. PrzykładyAplikacje w Visual C++ 2005. Przykłady
Aplikacje w Visual C++ 2005. Przykłady
 
Komputer PC w biurze i nie tylko
Komputer PC w biurze i nie tylkoKomputer PC w biurze i nie tylko
Komputer PC w biurze i nie tylko
 
Niezawodne strategie-wygrywania-w-sieci
Niezawodne strategie-wygrywania-w-sieciNiezawodne strategie-wygrywania-w-sieci
Niezawodne strategie-wygrywania-w-sieci
 
Visual Basic .NET. Ćwiczenia
Visual Basic .NET. ĆwiczeniaVisual Basic .NET. Ćwiczenia
Visual Basic .NET. Ćwiczenia
 
Visual C# 2005 Express Edition. Od podstaw
Visual C# 2005 Express Edition. Od podstawVisual C# 2005 Express Edition. Od podstaw
Visual C# 2005 Express Edition. Od podstaw
 
Core Java Servlets i JavaServer Pages. Tom II. Wydanie II
Core Java Servlets i JavaServer Pages. Tom II. Wydanie IICore Java Servlets i JavaServer Pages. Tom II. Wydanie II
Core Java Servlets i JavaServer Pages. Tom II. Wydanie II
 
Linux. Niezbędnik programisty
Linux. Niezbędnik programistyLinux. Niezbędnik programisty
Linux. Niezbędnik programisty
 
Adobe Dreamweaver CS3/CS3 PL. Oficjalny podręcznik
Adobe Dreamweaver CS3/CS3 PL. Oficjalny podręcznikAdobe Dreamweaver CS3/CS3 PL. Oficjalny podręcznik
Adobe Dreamweaver CS3/CS3 PL. Oficjalny podręcznik
 
Photoshop CS2/CS2 PL. Prosto do celu
Photoshop CS2/CS2 PL. Prosto do celuPhotoshop CS2/CS2 PL. Prosto do celu
Photoshop CS2/CS2 PL. Prosto do celu
 
CATIA V5. Podstawy budowy modeli autogenerujących
CATIA V5. Podstawy budowy modeli autogenerującychCATIA V5. Podstawy budowy modeli autogenerujących
CATIA V5. Podstawy budowy modeli autogenerujących
 

More from Wydawnictwo Helion

Tworzenie filmów w Windows XP. Projekty
Tworzenie filmów w Windows XP. ProjektyTworzenie filmów w Windows XP. Projekty
Tworzenie filmów w Windows XP. ProjektyWydawnictwo Helion
 
Blog, więcej niż internetowy pamiętnik
Blog, więcej niż internetowy pamiętnikBlog, więcej niż internetowy pamiętnik
Blog, więcej niż internetowy pamiętnikWydawnictwo Helion
 
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczne
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktycznePozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczne
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczneWydawnictwo Helion
 
E-wizerunek. Internet jako narzędzie kreowania image&#39;u w biznesie
E-wizerunek. Internet jako narzędzie kreowania image&#39;u w biznesieE-wizerunek. Internet jako narzędzie kreowania image&#39;u w biznesie
E-wizerunek. Internet jako narzędzie kreowania image&#39;u w biznesieWydawnictwo Helion
 
Makrofotografia. Magia szczegółu
Makrofotografia. Magia szczegółuMakrofotografia. Magia szczegółu
Makrofotografia. Magia szczegółuWydawnictwo Helion
 
Java. Efektywne programowanie. Wydanie II
Java. Efektywne programowanie. Wydanie IIJava. Efektywne programowanie. Wydanie II
Java. Efektywne programowanie. Wydanie IIWydawnictwo Helion
 
Ajax, JavaScript i PHP. Intensywny trening
Ajax, JavaScript i PHP. Intensywny treningAjax, JavaScript i PHP. Intensywny trening
Ajax, JavaScript i PHP. Intensywny treningWydawnictwo Helion
 
PowerPoint 2007 PL. Seria praktyk
PowerPoint 2007 PL. Seria praktykPowerPoint 2007 PL. Seria praktyk
PowerPoint 2007 PL. Seria praktykWydawnictwo Helion
 
Serwisy społecznościowe. Budowa, administracja i moderacja
Serwisy społecznościowe. Budowa, administracja i moderacjaSerwisy społecznościowe. Budowa, administracja i moderacja
Serwisy społecznościowe. Budowa, administracja i moderacjaWydawnictwo Helion
 
USB. Praktyczne programowanie z Windows API w C++
USB. Praktyczne programowanie z Windows API w C++USB. Praktyczne programowanie z Windows API w C++
USB. Praktyczne programowanie z Windows API w C++Wydawnictwo Helion
 
Rewizor GT. Prowadzenie ewidencji księgowej
Rewizor GT. Prowadzenie ewidencji księgowejRewizor GT. Prowadzenie ewidencji księgowej
Rewizor GT. Prowadzenie ewidencji księgowejWydawnictwo Helion
 
Windows Vista. Naprawa i optymalizacja. Ćwiczenia praktyczne
Windows Vista. Naprawa i optymalizacja. Ćwiczenia praktyczneWindows Vista. Naprawa i optymalizacja. Ćwiczenia praktyczne
Windows Vista. Naprawa i optymalizacja. Ćwiczenia praktyczneWydawnictwo Helion
 
FreeBSD 7. Instalacja i konfiguracja
FreeBSD 7. Instalacja i konfiguracjaFreeBSD 7. Instalacja i konfiguracja
FreeBSD 7. Instalacja i konfiguracjaWydawnictwo Helion
 

More from Wydawnictwo Helion (20)

Tworzenie filmów w Windows XP. Projekty
Tworzenie filmów w Windows XP. ProjektyTworzenie filmów w Windows XP. Projekty
Tworzenie filmów w Windows XP. Projekty
 
Blog, więcej niż internetowy pamiętnik
Blog, więcej niż internetowy pamiętnikBlog, więcej niż internetowy pamiętnik
Blog, więcej niż internetowy pamiętnik
 
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczne
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktycznePozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczne
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczne
 
E-wizerunek. Internet jako narzędzie kreowania image&#39;u w biznesie
E-wizerunek. Internet jako narzędzie kreowania image&#39;u w biznesieE-wizerunek. Internet jako narzędzie kreowania image&#39;u w biznesie
E-wizerunek. Internet jako narzędzie kreowania image&#39;u w biznesie
 
Makrofotografia. Magia szczegółu
Makrofotografia. Magia szczegółuMakrofotografia. Magia szczegółu
Makrofotografia. Magia szczegółu
 
Windows PowerShell. Podstawy
Windows PowerShell. PodstawyWindows PowerShell. Podstawy
Windows PowerShell. Podstawy
 
Java. Efektywne programowanie. Wydanie II
Java. Efektywne programowanie. Wydanie IIJava. Efektywne programowanie. Wydanie II
Java. Efektywne programowanie. Wydanie II
 
Ajax, JavaScript i PHP. Intensywny trening
Ajax, JavaScript i PHP. Intensywny treningAjax, JavaScript i PHP. Intensywny trening
Ajax, JavaScript i PHP. Intensywny trening
 
PowerPoint 2007 PL. Seria praktyk
PowerPoint 2007 PL. Seria praktykPowerPoint 2007 PL. Seria praktyk
PowerPoint 2007 PL. Seria praktyk
 
Excel 2007 PL. Seria praktyk
Excel 2007 PL. Seria praktykExcel 2007 PL. Seria praktyk
Excel 2007 PL. Seria praktyk
 
Access 2007 PL. Seria praktyk
Access 2007 PL. Seria praktykAccess 2007 PL. Seria praktyk
Access 2007 PL. Seria praktyk
 
Word 2007 PL. Seria praktyk
Word 2007 PL. Seria praktykWord 2007 PL. Seria praktyk
Word 2007 PL. Seria praktyk
 
Serwisy społecznościowe. Budowa, administracja i moderacja
Serwisy społecznościowe. Budowa, administracja i moderacjaSerwisy społecznościowe. Budowa, administracja i moderacja
Serwisy społecznościowe. Budowa, administracja i moderacja
 
AutoCAD 2008 i 2008 PL
AutoCAD 2008 i 2008 PLAutoCAD 2008 i 2008 PL
AutoCAD 2008 i 2008 PL
 
Bazy danych. Pierwsze starcie
Bazy danych. Pierwsze starcieBazy danych. Pierwsze starcie
Bazy danych. Pierwsze starcie
 
USB. Praktyczne programowanie z Windows API w C++
USB. Praktyczne programowanie z Windows API w C++USB. Praktyczne programowanie z Windows API w C++
USB. Praktyczne programowanie z Windows API w C++
 
Rewizor GT. Prowadzenie ewidencji księgowej
Rewizor GT. Prowadzenie ewidencji księgowejRewizor GT. Prowadzenie ewidencji księgowej
Rewizor GT. Prowadzenie ewidencji księgowej
 
Windows Vista. Naprawa i optymalizacja. Ćwiczenia praktyczne
Windows Vista. Naprawa i optymalizacja. Ćwiczenia praktyczneWindows Vista. Naprawa i optymalizacja. Ćwiczenia praktyczne
Windows Vista. Naprawa i optymalizacja. Ćwiczenia praktyczne
 
JavaScript. Praktyczny kurs
JavaScript. Praktyczny kursJavaScript. Praktyczny kurs
JavaScript. Praktyczny kurs
 
FreeBSD 7. Instalacja i konfiguracja
FreeBSD 7. Instalacja i konfiguracjaFreeBSD 7. Instalacja i konfiguracja
FreeBSD 7. Instalacja i konfiguracja
 

Tworzenie aplikacji dla Windows. Od prostych programów do gier komputerowych

  • 1. Tworzenie aplikacji dla Windows. Od prostych programów do gier komputerowych Autor: Pawe³ Borkowski ISBN: 978-83-246-1881-1 Format: 158x235, stron: 456 Poznaj tajniki tworzenia aplikacji dla Windows • Jak okreœliæ po³o¿enie, rozmiar i styl okna? • Jak tworzyæ w¹tki aplikacji za pomoc¹ funkcji CreateThread? • Jak definiowaæ biblioteki? Dev-C++ to zintegrowane œrodowisko programistyczne, którego niew¹tpliwym atutem s¹ tzw. DevPaki, czyli rozszerzenia programu, pozwalaj¹ce korzystaæ z ró¿nych bibliotek, szablonów i narzêdzi. Œrodowisko Dev-C++ wspomaga tak¿e pracê nad nowym projektem Windows — gotowym kodem tworz¹cym okno z obs³ug¹ podstawowych komunikatów. Wszystko to sprawia, ¿e mamy do czynienia z wygodnym i funkcjonalnym œrodowiskiem, zarówno dla pocz¹tkuj¹cych, jak i zaawansowanych programistów. Z ksi¹¿ki „Tworzenie aplikacji dla Windows. Od prostych programów do gier komputerowych” mo¿e skorzystaæ ka¿dy, kto chce nauczyæ siê programowania: zarówno studenci kierunków informatycznych, jak i osoby, które nie maj¹ takiego przygotowania. Podrêcznik kolejno ods³ania poszczególne elementy wiedzy programistycznej — od najprostszych po najbardziej zaawansowane. Dowiesz siê wiêc, jak wprowadzaæ niewielkie zmiany w kodzie, jak projektowaæ aplikacje wielow¹tkowe i definiowaæ biblioteki, jak budowaæ du¿e, sk³adaj¹ce siê z kilku plików projekty, aby na koniec samodzielnie stworzyæ grê komputerow¹. • Instalacja œrodowiska Dev-C++ • Tworzenie narzêdzia pióro • Obs³uga map bitowych • Obs³uga komunikatów myszy i klawiatury • Obiekty steruj¹ce w oknie • Menu i plik zasobów • Projektowanie aplikacji wielow¹tkowych • Biblioteki statyczne i dynamiczne • Multimedia • Programowanie gier Naucz siê programowania i twórz w³asne gry!
  • 2. Spis treści Wstęp .............................................................................................. 7 Część I Dla początkujących ........................................................ 9 Rozdział 1. Instalacja środowiska Dev-C++ ....................................................... 11 Rozdział 2. Pierwszy program ........................................................................... 13 2.1. Przygotowanie edytora ....................................................................................... 13 2.2. Kod wygenerowany przez Dev-C++ .................................................................. 15 2.3. Określanie tytułu okna ....................................................................................... 19 2.4. Określanie położenia i rozmiaru okna ................................................................ 19 2.5. Określanie stylu okna ......................................................................................... 21 2.6. Ćwiczenia ........................................................................................................... 22 Rozdział 3. Rysowanie w oknie ........................................................................ 23 3.1. Obsługa komunikatu WM_PAINT .................................................................... 23 3.2. Zestawienie funkcji graficznych. Program z użyciem funkcji Ellipse i LineTo .................................................................... 25 3.3. Wyświetlanie tekstu w obszarze roboczym okna ............................................... 28 3.4. Pierwszy program z użyciem funkcji SetPixel — wykres funkcji sinus ............ 34 3.5. Tworzenie pióra ................................................................................................. 39 3.6. Drugi program z użyciem funkcji SetPixel — zbiór Mandelbrota ..................... 42 3.7. Trzeci program z użyciem funkcji SetPixel — prosta obsługa bitmap ............... 48 3.8. Ćwiczenia ........................................................................................................... 55 Rozdział 4. Obsługa komunikatów myszy .......................................................... 57 4.1. Program z obsługą komunikatu WM_MOUSEMOVE ...................................... 57 4.2. Obsługa komunikatów WM_LBUTTONDOWN i WM_RBUTTONDOWN — zbiór Mandelbrota po raz drugi .......................... 62 4.3. Obsługa komunikatów WM_MOUSEMOVE, WM_LBUTTONDOWN i WM_RBUTTONDOWN — zbiór Mandelbrota a zbiory Julii ........................ 66 4.4. Tajemnica przycisków okna ............................................................................... 75 4.5. Ćwiczenia ........................................................................................................... 86 Rozdział 5. Obsługa komunikatów klawiatury .................................................... 87 5.1. Komunikaty klawiatury. Obsługa komunikatu WM_CHAR .............................. 87 5.2. Obsługa komunikatu WM_KEYDOWN. Diagram Feigenbauma ...................... 90 5.3. Ćwiczenia ......................................................................................................... 101
  • 3. 4 Tworzenie aplikacji dla Windows. Od prostych programów do gier komputerowych Rozdział 6. Obiekty sterujące w oknie ............................................................ 103 6.1. Obiekt klasy BUTTON .................................................................................... 103 6.2. Obsługa grafiki za pomocą obiektów klasy BUTTON ..................................... 109 6.3. Obiekt klasy edycji. Automaty komórkowe ..................................................... 116 6.4. Ćwiczenia ......................................................................................................... 128 Rozdział 7. Menu i plik zasobów ..................................................................... 131 7.1. Dodanie menu do okna ..................................................................................... 131 7.2. Obsługa bitmapy z pliku zasobów .................................................................... 138 7.3. Odczytywanie danych z pliku. Edytor bitmap .................................................. 143 7.4. Kopiarka wielokrotnie redukująca ................................................................... 154 7.5. Ćwiczenia ......................................................................................................... 169 Podsumowanie części I ................................................................................................. 169 Część II Dla średniozaawansowanych ....................................... 171 Rozdział 8. Projektowanie aplikacji wielowątkowych ....................................... 173 8.1. Tworzenie wątków za pomocą funkcji CreateThread ...................................... 173 8.2. Czy praca z wątkami przyspiesza działanie aplikacji? Sekcja krytyczna i priorytety wątków .............................................................. 178 8.3. Wstrzymywanie pracy i usuwanie wątków ...................................................... 190 8.4. Ćwiczenia ......................................................................................................... 199 Rozdział 9. Definiowanie bibliotek .................................................................. 201 9.1. Biblioteki statyczne .......................................................................................... 201 9.2. Biblioteki dynamiczne — podejście strukturalne ............................................. 207 9.3. Biblioteki dynamiczne — podejście obiektowe ............................................... 220 9.4. Własny temat okna ........................................................................................... 225 9.5. Ćwiczenia ......................................................................................................... 254 Rozdział 10. Multimedia .................................................................................. 255 10.1. Odtwarzanie plików wav — funkcja sndPlaySound ........................................ 255 10.2. Odtwarzanie plików mp3 — biblioteka FMOD ............................................... 258 10.3. Ćwiczenia ......................................................................................................... 269 Podsumowanie części II ............................................................................................... 270 Część III Dla zaawansowanych .................................................. 273 Rozdział 11. Programowanie gier z użyciem biblioteki OpenGL .......................... 275 11.1. Podstawy obsługi biblioteki OpenGL .............................................................. 275 11.2. Prymitywy OpenGL ......................................................................................... 284 11.3. Bufor głębokości, perspektywa — wzorzec kodu do programowania gier (pierwsze starcie) ............................ 298 11.4. Animacja .......................................................................................................... 309 11.5. Poruszanie się po scenie, funkcja gluLookAt i wzorzec kodu do programowania gier (starcie drugie, decydujące) ............... 320 11.6. Tekstury i mipmapy ......................................................................................... 334 11.7. Listy wyświetlania i optymalizacja kodu ......................................................... 349 11.8. Detekcja kolizji ................................................................................................ 361 11.9. Światło, mgła, przezroczystość i inne efekty specjalne ....................................... 368 Uruchamianie gry w trybie pełnoekranowym .................................................. 368 Mgła ................................................................................................................. 371 Przezroczystość ................................................................................................ 374 Światło ............................................................................................................. 384
  • 4. Spis treści 5 11.10.Jak ustawić stałą prędkość działania programu? .............................................. 390 11.11.Gotowe obiekty OpenGL ................................................................................. 398 11.12.Fonty ................................................................................................................ 406 11.13.Dźwięk na scenie ............................................................................................. 416 11.14.Budujemy grę! ................................................................................................. 419 Wprowadzenie i charakter gry ......................................................................... 419 Dane gracza ...................................................................................................... 420 Strzał z broni .................................................................................................... 423 Pozostali bohaterowie gry ................................................................................ 425 Odnawianie zasobów gracza ............................................................................ 428 Zakończenie programu (gry) ............................................................................ 430 Podsumowanie części III .............................................................................................. 433 Dodatki ..................................................................................... 435 Dodatek A ................................................................................... 437 Dodatek B ................................................................................... 439 Skorowidz .................................................................................... 441
  • 5. Rozdziaä 8. i Projektowanie aplikacji wielowñtkowych 173 Rozdziaä 8. Projektowanie aplikacji wielowñtkowych 8.1. Tworzenie wñtków za pomocñ funkcji CreateThread Jeste my przyzwyczajeni do tego, e w systemie Windows mo emy pracowaü na wielu oknach jednocze nie. Jak du e jest to udogodnienie, nie trzeba nikogo przekonywaü. T cech systemu nazywamy wielozadaniowo ci . Jej najpo yteczniejszym zastosowa- niem jest mo liwo ü ukrycia przed pracodawc pod stosem otwartych okien jednego okienka z uruchomion ulubion gr . System Windows pozwala tak e na co wi cej — na wielow tkowo ü, czyli wykonywanie wielu zada równocze nie w ramach dziaáania jednego programu. Oczywi cie, poj cia pracy równoczesnej nie nale y traktowaü zbyt dosáownie. System dzieli czas pracy procesora i przyznaje po kolei pewn jego cz ü w celu obsáugi kolejnego w tku. Poniewa wspomniany proces wykonywany jest bardzo szybko, powstaje iluzja równolegáego dziaáania w tków. W tek tworzymy za pomoc funkcji CreateThread o nast puj cej skáadni: HANDLE CreateThread(LPSECURITY_ATTRIBUTES atrybuty_watku, DWORD rozmiar_stosu, LPTHREAD_START_ROUTINE adres_funkcji_watku, LPVOID parametr, DWORD flaga_watku, LPDWORD identyfikator ); Pierwszy argument atrybuty_watku miaá zastosowanie w systemie Windows NT. Od tego czasu nie wykorzystuje si go i mo emy w jego miejsce wpisaü NULL. Drugi argument okre la rozmiar stosu w bajtach. Je eli nie mamy pomysáu dotycz cego jego wielko ci, wpiszmy zero, co oznacza zadeklarowanie stosu standardowego rozmiaru. W parametrze
  • 6. 174 Czö è II i Dla redniozaawansowanych adres_funkcji_watku powinien znajdowaü si , zreszt zgodnie z pomysáowo nadan nazw , adres funkcji, która zawiera kod obsáugi w tku. Deklaracja funkcji musi mieü nast puj c postaü: DWORD NazwaFunkcji(LPVOID); Parametr, który mo emy przekazaü do funkcji w tku, przekazujemy jako czwarty argu- ment funkcji CreateThread. Argument flaga_watku okre la chwil uruchomienia w tku. Mo emy u yü jednej z dwóch warto ci:  0 — w tek uruchamiany jest w chwili utworzenia,  CREATE_SUSPENDED — uruchomienie w tku jest wstrzymane a do wywoáania funkcji ResumeThread. Ostatni parametr powinien zawieraü wska nik do zmiennej, w której zostanie umiesz- czony identyfikator w tku. Je eli uruchomienie w tku powiedzie si , funkcja Create ´Thread zwraca uchwyt utworzonego w tku, w przeciwnym przypadku zwracana jest warto ü NULL. Wszystko, co wáa nie przeczytali cie, jest niezwykle ciekawe, ale warto ju przyst piü do budowania programu. B dzie to aplikacja z dziedziny helmintologii, czyli nauki o robakach (niestety, paso ytniczych). Wyobra my sobie obszar roboczy naszego okna. Klikni cie lewego przycisku myszy powinno wywoáaü nowy w tek — robaka, którego pocz tek niszczycielskiej dziaáalno ci b dzie si znajdowaá w miejscu, w jakim aktualnie znajduje si kursor myszy. Tworzymy nowy projekt Windows o nazwie Program20.dev. Spójrzmy na prosty program realizuj cy wspomniane zadanie (plik Program20_main.cpp), a nast pnie omówi kluczowe punkty programu. #include <windows.h> /* Staáe rozmiaru obszaru roboczego okna */ const int MaxX = 640; const int MaxY = 480; /* Zmienne globalne dla obsáugi w tków */ int x, y; /* Funkcja w tku */ DWORD Robak(LPVOID param); LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM); char szClassName[ ] = "WindowsApp"; int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nFunsterStil) { HWND hwnd; MSG messages; WNDCLASSEX wincl;
  • 7. Rozdziaä 8. i Projektowanie aplikacji wielowñtkowych 175 wincl.hInstance = hThisInstance; wincl.lpszClassName = szClassName; wincl.lpfnWndProc = WindowProcedure; wincl.style = CS_DBLCLKS; wincl.cbSize = sizeof (WNDCLASSEX); wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION); wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION); wincl.hCursor = LoadCursor (NULL, IDC_ARROW); wincl.lpszMenuName = NULL; wincl.cbClsExtra = 0; wincl.cbWndExtra = 0; wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND; if (!RegisterClassEx (&wincl)) return 0; hwnd = CreateWindowEx ( 0, szClassName, "Program20 - aplikacja wielowætkowa", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, MaxX+8, MaxY+34, HWND_DESKTOP, NULL, hThisInstance, NULL ); ShowWindow (hwnd, nFunsterStil); while (GetMessage (&messages, NULL, 0, 0)) { TranslateMessage(&messages); DispatchMessage(&messages); } return messages.wParam; } LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, ´LPARAM lParam) { static HDC hdc; PAINTSTRUCT ps; DWORD pointer; switch (message) { case WM_PAINT: hdc = BeginPaint(hwnd, &ps); if(x>=5&&y>=5&&x<MaxX-5&&y<MaxY-5) Ellipse(hdc, x-5, y-5, x+5, y+5); EndPaint(hwnd, &ps); break; case WM_LBUTTONDOWN: x = LOWORD(lParam);
  • 8. 176 Czö è II i Dla redniozaawansowanych y = HIWORD(lParam); CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Robak, hwnd, 0, ´&pointer); break; case WM_DESTROY: PostQuitMessage (0); break; default: return DefWindowProc (hwnd, message, wParam, lParam); } return 0; } DWORD Robak(LPVOID param) { int wx = x, wy = y; //uruchomienie liczb losowych srand(GetTickCount()); //p tla niesko czona while(TRUE) { //wylosuj ruch robaka wx += (rand()%5) - 2; wy += (rand()%5) - 2; //sprawd , czy robak znajduje si w dozwolonym obszarze if(wx<5) wx = 5; if(wx>MaxX-5) wx = MaxX-5; if(wy<5) wy = 5; if(wy>MaxY-5) wy = MaxY-5; //zaáaduj nowe wspóárz dne do zmiennej globalnej x = wx; y = wy; //narysuj robaka w nowym poáo eniu InvalidateRect((HWND)param, NULL, FALSE); //zaczekaj 1/10 sekundy Sleep(100); } return 0; } Program po uruchomieniu czeka na naci ni cie lewego przycisku myszy. case WM_LBUTTONDOWN: x = LOWORD(lParam); y = HIWORD(lParam); CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Robak, hwnd, 0, &pointer); break; Je eli procedura okna otrzyma komunikat o zaj ciu tego zdarzenia, tworzy w tek, którego obsáug powierza funkcji Robak. Wspóárz dne kursora myszy s áadowane do zmien- nych globalnych x i y w celu przekazania ich do funkcji obsáugi w tku. Aplikacja kon- tynuuje prac , a równolegle z ni zaczyna dziaáaü nowy w tek. Spójrzmy na kod funkcji Robak.
  • 9. Rozdziaä 8. i Projektowanie aplikacji wielowñtkowych 177 DWORD Robak(LPVOID param) { int wx = x, wy = y; //uruchomienie liczb losowych srand(GetTickCount()); while(TRUE) { //wylosuj ruch robaka wx += (rand()%5) - 2; wy += (rand()%5) - 2; //sprawd , czy robak znajduje si w dozwolonym obszarze if(wx<5) wx = 5; if(wx>MaxX-5) wx = MaxX-5; if(wy<5) wy = 5; if(wy>MaxY-5) wy = MaxY-5; //zaáaduj nowe wspóárz dne do zmiennej globalnej x = wx; y = wy; //narysuj robaka w nowym poáo eniu InvalidateRect((HWND)param, NULL, FALSE); //zaczekaj 1/10 sekundy Sleep(100); } return 0; } Pocz tkowe wspóárz dne obiektu zostaáy przekazane przy u yciu zmiennych global- nych x i y. int wx = x, wy = y; Pozostaáa cz ü kodu umieszczona jest w p tli niesko czonej, co oznacza, e w tek zostanie zniszczony dopiero w chwili zamkni cia aplikacji. Bardzo wa n cech robaka jest jego losowy ruch realizowany za pomoc uaktualniania wspóárz dnych. wx += (rand()%5) - 2; wy += (rand()%5) - 2; Poniewa w tym zadaniu korzystamy z funkcji rand, która zwraca liczby pseudolosowe, wa ne jest, by warto ü inicjalizuj ca tej funkcji ró niáa si dla ka dego w tku. Liczb pocz tkow dla oblicze funkcji rand przekazujemy za pomoc srand, której argumen- tem jest u nas funkcja GetTickCount podaj ca liczb milisekund liczon od chwili uru- chomienia systemu Windows. srand(GetTickCount()); Po obliczeniu nowej wspóárz dnej poáo enia robaka i sprawdzeniu jej poprawno ci wy- muszamy odmalowanie obszaru roboczego okna. InvalidateRect((HWND)param, NULL, FALSE);
  • 10. 178 Czö è II i Dla redniozaawansowanych W ten sposób w tek komunikuje si z aplikacj gáówn i zmusza do zainteresowania si kodem obsáugi komunikatu WM_PAINT. case WM_PAINT: hdc = BeginPaint(hwnd, &ps); if(x>=5&&y>=5&&x<MaxX-5&&y<MaxY-5) Ellipse(hdc, x-5, y-5, x+5, y+5); EndPaint(hwnd, &ps); break; Wizualn cz ci dziaáania w tku jest narysowana w nowym poáo eniu elipsa. Przy- káadowy efekt dziaáania programu z uruchomionymi jednocze nie kilkudziesi cioma w tkami przedstawiam na rysunku 8.1. Rysunek 8.1. Okno dziaáaj cej aplikacji Program20 8.2. Czy praca z wñtkami przyspiesza dziaäanie aplikacji? Sekcja krytyczna i priorytety wñtków Odpowied na pytanie postawione w tytule podrozdziaáu nie jest prosta. Wszystko zale y od rodzaju czynno ci realizowanych przez w tek. Pami tajmy, e ka dy utwo- rzony w tek korzysta z cz ci czasu pracy procesora. Dlatego bá dna jest my l, e skomplikowane obliczenie rozáo one na wiele w tków wykona si szybciej ni to samo
  • 11. Rozdziaä 8. i Projektowanie aplikacji wielowñtkowych 179 obliczenie w jednow tkowej aplikacji. Natomiast istniej sytuacje, w których procesor „czeka bezczynnie” lub jest tylko „nieznacznie zaj ty”, wtedy — oczywi cie — stoso- wanie w tków jest zasadne. Operowanie w tkami ma przede wszystkim uáatwiü prac nam, czyli programistom. Ilustracj do postawionego pytania b dzie aplikacja, w której na dwóch cz ciach obszaru roboczego okna wy wietlimy zbiór Mandelbrota i jeden ze zbiorów Julii. Wykonanie ka dego z tych zada bardzo mocno obci a procesor i kart graficzn . Nasza aplika- cja w pierwszej kolejno ci b dzie rysowaáa oddzielnie zbiór Mandelbrota i zbiór Julii, a nast pnie obydwa zadania zostan wykonane równolegáe w dwóch w tkach. Poli- czymy czas wykonania zada w wersji bez u ycia w tków i z ich u yciem. Tworzymy nowy projekt Program21.dev. Poniewa przewidujemy du ilo ü operacji graficznych, odpowiedni kod umie cimy w pliku Program21.h. Wygenerowany przez Dev-C++ kod (plik Program21_main.cpp) modyfikujemy tylko w czterech miejscach. 1. Dodajemy plik nagáówkowy. #include "Program21.h" 2. Zmieniamy parametry funkcji CreateWindowEx. hwnd = CreateWindowEx ( 0, szClassName, "Program21", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 648, 340, HWND_DESKTOP, NULL, hThisInstance, NULL ); 3. Dodajemy kod obsáugi komunikatu WM_PAINT. case WM_PAINT: hdc = BeginPaint(hwnd, &ps); MojaProcedura(hdc); EndPaint(hwnd, &ps); break; 4. Dodajemy kod obsáugi komunikatu WM_LBUTTONDOWN. Dzi ki temu mo liwe b dzie áatwe od wie anie obszaru roboczego okna i tym samym wielokrotne powtórzenie do wiadczenia. case WM_LBUTTONDOWN: InvalidateRect(hwnd, NULL, TRUE); break; Plik Program21_main.cpp w caáo ci wygl da nast puj co (jak zwykle, pomini te zostaáy generowane przez Dev-C++ komentarze):
  • 12. 180 Czö è II i Dla redniozaawansowanych #include <windows.h> #include "Program21.h" LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM); char szClassName[ ] = "WindowsApp"; int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nFunsterStil) { HWND hwnd; MSG messages; WNDCLASSEX wincl; wincl.hInstance = hThisInstance; wincl.lpszClassName = szClassName; wincl.lpfnWndProc = WindowProcedure; wincl.style = CS_DBLCLKS; wincl.cbSize = sizeof (WNDCLASSEX); wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION); wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION); wincl.hCursor = LoadCursor (NULL, IDC_ARROW); wincl.lpszMenuName = NULL; wincl.cbClsExtra = 0; wincl.cbWndExtra = 0; wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND; if (!RegisterClassEx (&wincl)) return 0; hwnd = CreateWindowEx ( 0, szClassName, "Program21", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 648, 340, HWND_DESKTOP, NULL, hThisInstance, NULL ); ShowWindow (hwnd, nFunsterStil); while (GetMessage (&messages, NULL, 0, 0)) { TranslateMessage(&messages); DispatchMessage(&messages); } return messages.wParam; }
  • 13. Rozdziaä 8. i Projektowanie aplikacji wielowñtkowych 181 LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, ´LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; switch (message) { case WM_PAINT: hdc = BeginPaint(hwnd, &ps); MojaProcedura(hdc); EndPaint(hwnd, &ps); break; case WM_LBUTTONDOWN: InvalidateRect(hwnd, NULL, TRUE); break; case WM_DESTROY: PostQuitMessage (0); break; default: return DefWindowProc (hwnd, message, wParam, lParam); } return 0; } Kluczow cz ü programu, wraz z wywoáywan w kodzie obsáugi komunikatu WM_PAINT procedur MojaProcedura, umie cimy w pliku Program21.h. Zawarto ü procedury b d stanowiü: 1. Obliczenie czasu potrzebnego do narysowania zbioru Mandelbrota i Julii za pomoc funkcji wywoáywanych w sposób sekwencyjny. a) Pobranie liczby milisekund, które upáyn áy od chwili uruchomienia systemu Windows i umieszczenie tej wielko ci w zmiennej m1. b) Wywoáanie funkcji rysuj cej zbiór Mandelbrota. c) Wywoáanie funkcji rysuj cej zbiór Julii. d) Pobranie liczby milisekund, które upáyn áy od chwili uruchomienia systemu Windows i umieszczenie tej wielko ci w zmiennej m2. e) Obliczenie i wy wietlenie ró nicy m2-m1. Wynik oznacza czas wykonania zada opisanych w punktach b i c. 2. Obliczenie czasu potrzebnego do narysowania zbioru Mandelbrota i Julii za pomoc funkcji wywoáanych w równolegle pracuj cych w tkach. a) Pobranie liczby milisekund, które upáyn áy od chwili uruchomienia systemu Windows, i umieszczenie tej wielko ci w zmiennej m1. b) Utworzenie w tku wywoáuj cego funkcj rysuj c zbiór Mandelbrota. c) Utworzenie w tku wywoáuj cego funkcj rysuj c zbiór Julii. d) Oczekiwanie na zako czenie pracy obu w tków.
  • 14. 182 Czö è II i Dla redniozaawansowanych e) Pobranie liczby milisekund, które upáyn áy od chwili uruchomienia systemu Windows, i umieszczenie tej wielko ci w zmiennej m2. f) Obliczenie i wy wietlenie ró nicy m2-m1. Wynik oznacza czas wykonania zada opisanych w punktach b i c. Popatrzmy na pierwsz wersj procedury MojaProcedura. void MojaProcedura(HDC hdc) { char tab[32]; DWORD pointer; DWORD m, m1, m2; //pobierz ilo ü milisekund od chwili uruchomienia systemu Windows //(czas startu zadania) m1 = GetTickCount(); //wykonaj zadanie numer 1 Zbior_Mandelbrota(hdc); //wykonaj zadanie numer 2 Zbior_Julii(hdc); //pobierz ilo ü milisekund od chwili uruchomienia systemu Windows //(czas zako czenia zadania) m2 = GetTickCount(); //wy wietl okres czasu potrzebny do wykonania zadania m = m2 - m1; TextOut(hdc, 10, 250, "Czas sekwencyjnego wykonania zada :", 35); itoa(m, tab, 10); TextOut(hdc, 300, 250, tab, strlen(tab)); //wyczy ü fragment okna Rectangle(hdc, 0, 0, 640, 240); //wyzeruj zmienn globaln dla w tków zmienna_stop = 0; //pobierz ilo ü milisekund od chwili uruchomienia systemu Windows //(czas startu zadania) m1 = GetTickCount(); //wywoáaj w tek wykonuj cy zadanie numer 1 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Z_M, hdc, 0, &pointer); //wywoáaj w tek wykonuj cy zadanie numer 2 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Z_J, hdc, 0, &pointer); //czekaj na zako czenie pracy w tków do{}while(zmienna_stop<2); //pobierz ilo ü milisekund od chwili uruchomienia systemu Windows //(czas zako czenia zadania) m2 = GetTickCount(); //wy wietl okres czasu potrzebny do wykonania zadania m = m2 - m1; TextOut(hdc, 10, 270, "Czas równoleg ego wykonania zada :", 34); itoa(m, tab, 10); TextOut(hdc, 300, 270, tab, strlen(tab)); } Procedura realizuje kolejno przedstawione w punktach zadania. Do obliczenia czasu dziaáania cz ci programu u ywamy znanej ju funkcji GetTickCount. Taki sposób licze- nia przedziaáów czasu jest caákiem bezpieczny, gdy zwracana przez funkcj wielko ü
  • 15. Rozdziaä 8. i Projektowanie aplikacji wielowñtkowych 183 jest 32-bitowa, co oznacza, e mo emy spodziewaü si zrestartowania licznika dopiero po 49 dniach nieprzerwanej pracy systemu Windows. Funkcje tworzonych w procedurze w tków maj nast puj c postaü: DWORD Z_M(LPVOID param) { Zbior_Mandelbrota((HDC)param); //zwi ksz wska nik zako czenia pracy zmienna_stop++; return 0; } DWORD Z_J(LPVOID param) { Zbior_Julii((HDC)param); //zwi ksz wska nik zako czenia pracy zmienna_stop++; return 0; } Kody funkcji Zbior_Mandelbrota i Zbior_Julii na razie w naszych rozwa aniach nie s istotne. Nale y zwróciü uwag na sposób zako czenia funkcji w tków, polegaj cy na inkrementacji zmiennej globalnej. zmienna_stop++; Dzi ki temu mo liwe staje si sprawdzenie zako czenia dziaáania obu w tków za po- moc p tli: do{}while(zmienna_stop<2); Mo emy przyj ü, e mamy pierwsz podstawow wersj aplikacji. Nie jest to jeszcze wersja optymalna. Popatrzmy na rysunek 8.2, na którym przedstawiam rezultat dziaáania programu. Rysunek 8.2. Okno aplikacji Program21 w dziaáaniu (wersja pierwsza, niepoprawna) Na pocz tek nale y zauwa yü, e narysowanie zbiorów Mandelbrota i Julii za pomoc w tków wykonaáo si szybciej ni zadanie analogiczne, zrealizowane za pomoc sekwen- cyjnego wywoáania funkcji. Dzieje si tak dlatego, gdy okresy oblicze wykorzystu- j ce procesor s przerywane dáugimi okresami obci ania karty graficznej, podczas
  • 16. 184 Czö è II i Dla redniozaawansowanych których wy wietlany jest piksel o danej wspóárz dnej w odpowiednim kolorze. Istniej wi c krótkie przedziaáy czasowe maáego obci enia procesora, które mo e wykorzystaü dla wáasnych oblicze drugi w tek. Jednak niebezpiecze stwo pracy z w tkami polega na tym, e system mo e zarz dziü wstrzymanie pracy w tku i przekazanie sterowania drugiemu w najmniej spodziewanym momencie. Je eli obydwa w tki korzystaj w tym czasie ze wspólnych zasobów systemowych, a tak jest w przypadku operacji graficznych korzystaj cych z obiektów GDI, dane mog ulec zatraceniu, czego wyni- kiem s niezamalowane obszary, pokazane na rysunku 8.2. Na szcz cie, potrafimy przeciwdziaáaü przerwaniu pracy w tku w chwili dla nas niepo- danej (co za ulga!). Do tego celu sáu y sekcja krytyczna, a dokáadniej obiekty sekcji krytycznej. W celu przybli enia sensu istnienia tego rewelacyjnego rozwi zania pro- gramistycznego posáu si przykáadem. Wyobra my sobie bibliotek , w której znajduje si jeden egzemplarz starego manuskryptu. Wyobra my sobie tak e, e setka biblio- filów chce w danym momencie ów egzemplarz przeczytaü. Mo e to robiü na raz tylko jeden fanatyk starego pi miennictwa, natomiast reszta, obgryzaj c ze zdenerwowania palce, mo e tylko czekaü, a szcz liwy chwilowy posiadacz obiektu zako czy prac . Podobn rol w pracy w tków odgrywa obiekt sekcji krytycznej: w jego posiadanie mo e w danej chwili wej ü tylko jeden w tek, natomiast pozostaáe w tki zawieszaj prac do czasu przej cia obiektu sekcji krytycznej. Oczywi cie, czekaj tylko te w tki, w których zaznaczono konieczno ü wej cia w posiadanie obiektu sekcji krytycznej w celu wykonania fragmentu kodu. Praca z obiektami sekcji krytycznej jest niezwykle prosta i skáada si z kilku punktów. Oto one. 1. Deklaracja obiektu sekcji krytycznej. Nazwa obiektu jest dowolna, mo emy zadeklarowaü dowoln liczb obiektów. CRITICAL_SECTION critical_section; 2. Inicjalizacja obiektu sekcji krytycznej. InitializeCriticalSection(&critical_section); 3. Nast pne dwa podpunkty umieszczamy w funkcji w tków, s to: a) przej cie obiektu sekcji krytycznej: EnterCriticalSection(&critical_section); b) zwolnienie obiektu sekcji krytycznej: LeaveCriticalSection(&critical_section); 4. Zako czenie pracy z obiektem sekcji krytycznej powinno byü zwi zane z jego usuni ciem. DeleteCriticalSection(&critical_section); Sposób u ycia obiektów sekcji krytycznej zobaczymy na przykáadzie kodu poprawionej procedury MojaProcedura i jednej z funkcji w tków Z_M. Rezultat dziaáania tak popra- wionego programu przedstawiam na rysunku 8.3.
  • 17. Rozdziaä 8. i Projektowanie aplikacji wielowñtkowych 185 Rysunek 8.3. Okno aplikacji Program21 dziaáaj cej z wykorzystaniem obiektu sekcji krytycznej /* Obiekt sekcji krytycznej */ CRITICAL_SECTION critical_section; void MojaProcedura(HDC hdc) { char tab[32]; DWORD pointer, m, m1, m2; //pobierz ilo ü milisekund od chwili uruchomienia systemu Windows //(czas startu zadania) m1 = GetTickCount(); //wykonaj zadanie numer 1 Zbior_Mandelbrota(hdc); //wykonaj zadanie numer 2 Zbior_Julii(hdc); //pobierz ilo ü milisekund od chwili uruchomienia systemu Windows //(czas zako czenia zadania) m2 = GetTickCount(); //wy wietl okres czasu potrzebny do wykonania zadania m = m2 - m1; TextOut(hdc, 10, 250, "Czas sekwencyjnego wykonania zada :", 35); itoa(m, tab, 10); TextOut(hdc, 300, 250, tab, strlen(tab)); //wyczy ü fragment okna Rectangle(hdc, 0, 0, 640, 240); //wyzeruj zmienn globaln dla w tków zmienna_stop = 0; //zainicjalizuj obiekt sekcji krytycznej InitializeCriticalSection(&critical_section); //pobierz ilo ü milisekund od chwili uruchomienia systemu Windows //(czas startu zadania) m1 = GetTickCount(); //wywoáaj w tek wykonuj cy zadanie numer 1 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Z_M, hdc, 0, &pointer); //wywoáaj w tek wykonuj cy zadanie numer 2 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Z_J, hdc, 0, &pointer); //czekaj na zako czenie pracy w tków do{}while(zmienna_stop<2); //pobierz ilo ü milisekund od chwili uruchomienia systemu Windows //(czas zako czenia zadania) m2 = GetTickCount();
  • 18. 186 Czö è II i Dla redniozaawansowanych //usu obiekt sekcji krytycznej DeleteCriticalSection(&critical_section); //wy wietl okres czasu potrzebny do wykonania zadania m = m2 - m1; TextOut(hdc, 10, 270, "Czas równoleg ego wykonania zada :", 34); itoa(m, tab, 10); TextOut(hdc, 300, 270, tab, strlen(tab)); } DWORD Z_M(LPVOID param) { double a_lewy = -2.0, a_prawy = 2.0; double b_gora = 1.5, b_dol = -1.5; double krokX = (a_prawy - a_lewy)/320.0; double krokY = (b_gora - b_dol)/240.0; int kolor; for(int y=0; y<240; y++) for(int x=0; x<320; x++) { kolor = Kolor(a_lewy+double(x)*krokX, b_gora-double(y)*krokY); //wejd w sekcj krytyczn EnterCriticalSection(&critical_section); //ustaw piksel SetPixel((HDC)param, x, y, kolor); //opu ü sekcj krytyczn LeaveCriticalSection(&critical_section); } //zwi ksz wska nik zako czenia pracy zmienna_stop++; return 0; } Poniewa funkcje graficzne zostaáy w aplikacji zamkni te w sekcje krytyczne, nie ma na wykresie obszarów bá dnych. Wy wietlane przez program liczby mog si ró niü od zaprezentowanych na ilustracji, co jest wynikiem ró nej mocy obliczeniowej kom- putera, a nawet ilo ci procesów korzystaj cych w danej chwili z procesora. Ostatnie udoskonalenie programu b dzie zwi zane ze zmian priorytetu wykonywanych w tków. Uruchomione w aplikacji w tki musz wspóádzieliü czas pracy procesora nie tylko mi dzy siebie, ale te z wywoáuj c je aplikacj gáówn i innymi uruchomionymi w systemie w tkami. To wydáu a czas dziaáania w tków. Zmiana tej sytuacji jest mo liwa za pomoc zmiany priorytetu uruchomionych w tków. Do tego zadania sáu y funkcja SetThreadPriority o nast puj cej deklaracji: BOOL SetThreadPriority(HANDLE uchwyt_watku, int priorytet); Parametr uchwyt_watku powinien zawieraü uchwyt w tku, którego priorytet chcemy zmieniü, a argumentem priorytet okre lamy warto ü priorytetu w tku. Zestawienie mo liwych do wyboru warto ci priorytetu przedstawiam w tabeli 8.1. W naszej aplikacji u yjemy najwy szego priorytetu THREAD_PRIORITY_HIGHEST, czego wynikiem b dzie prawie dwukrotne przyspieszenie czasu rysowania wykresów zbioru Mandelbrota i Julii. Oto gotowy plik Program21.h.
  • 19. Rozdziaä 8. i Projektowanie aplikacji wielowñtkowych 187 Tabela 8.1. Priorytety uruchamianych w tków Staäa priorytetu Warto è priorytetu THREAD_PRIORITY_HIGHEST +2 THREAD_PRIORITY_ABOVE_NORMAL +1 THREAD_PRIORITY_NORMAL 0 THREAD_PRIORITY_BELOW_NORMAL -1 THREAD_PRIORITY_LOWEST -2 #include <math.h> //zmienna globalna do sprawdzenia stanu w tków int zmienna_stop; /* Deklaracja procedur */ void MojaProcedura(HDC); void Zbior_Mandelbrota(HDC); void Zbior_Julii(HDC); /* Funkcje w tków */ DWORD Z_M(LPVOID); DWORD Z_J(LPVOID); /* Obiekt sekcji krytycznej */ CRITICAL_SECTION critical_section; void MojaProcedura(HDC hdc) { char tab[32]; DWORD pointer, m, m1, m2; HANDLE h; //pobierz ilo ü milisekund od chwili uruchomienia systemu Windows //(czas startu zadania) m1 = GetTickCount(); //wykonaj zadanie numer 1 Zbior_Mandelbrota(hdc); //wykonaj zadanie numer 2 Zbior_Julii(hdc); //pobierz ilo ü milisekund od chwili uruchomienia systemu Windows //(czas zako czenia zadania) m2 = GetTickCount(); //wy wietl okres czasu potrzebny do wykonania zadania m = m2 - m1; TextOut(hdc, 10, 250, "Czas sekwencyjnego wykonania zada :", 35); itoa(m, tab, 10); TextOut(hdc, 300, 250, tab, strlen(tab)); //wyczy ü fragment okna Rectangle(hdc, 0, 0, 640, 240); //wyzeruj zmienn globaln dla w tków zmienna_stop = 0; //zainicjalizuj obiekt sekcji krytycznej InitializeCriticalSection(&critical_section);
  • 20. 188 Czö è II i Dla redniozaawansowanych //pobierz ilo ü milisekund od chwili uruchomienia systemu Windows //(czas startu zadania) m1 = GetTickCount(); //wywoáaj w tek wykonuj cy zadanie numer 1 h = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Z_M, hdc, 0, &pointer); SetThreadPriority(h, THREAD_PRIORITY_HIGHEST); //wywoáaj w tek wykonuj cy zadanie numer 2 h = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Z_J, hdc, 0, &pointer); SetThreadPriority(h, THREAD_PRIORITY_HIGHEST); //czekaj na zako czenie pracy w tków do{}while(zmienna_stop<2); //pobierz ilo ü milisekund od chwili uruchomienia systemu Windows //(czas zako czenia zadania) m2 = GetTickCount(); //usu obiekt sekcji krytycznej DeleteCriticalSection(&critical_section); //wy wietl okres czasu potrzebny do wykonania zadania m = m2 - m1; TextOut(hdc, 10, 270, "Czas równoleg ego wykonania zada :", 34); itoa(m, tab, 10); TextOut(hdc, 300, 270, tab, strlen(tab)); } int Kolor(double a0, double b0) { double an, a = a0, b = b0; int k = 0; while((sqrt(a*a+b*b)<2)&&(k<256)) { an = a*a - b*b + a0; b = 2.0*a*b + b0; a = an; k++; } return 0xF8*k; } void Zbior_Mandelbrota(HDC hdc) { double a_lewy = -2.0, a_prawy = 2.0; double b_gora = 1.5, b_dol = -1.5; double krokX = (a_prawy - a_lewy)/320.0; double krokY = (b_gora - b_dol)/240.0; for(int y=0; y<240; y++) for(int x=0; x<320; x++) SetPixel(hdc, x, y, Kolor(a_lewy+double(x)*krokX, b_gora-double(y)*krokY)); } int jKolor(double a0, double b0) { double an, a = a0, b = b0; int k = 0; while((sqrt(a*a+b*b)<2)&&(k<256)) { an = a*a - b*b + 0.373; b = 2.0*a*b + 0.133;
  • 21. Rozdziaä 8. i Projektowanie aplikacji wielowñtkowych 189 a = an; k++; } return 0xF8*k; } void Zbior_Julii(HDC hdc) { double a_lewy = -2.0, a_prawy = 2.0; double b_gora = 1.5, b_dol = -1.5; double krokX = (a_prawy - a_lewy)/320.0; double krokY = (b_gora - b_dol)/240.0; for(int y=0; y<240; y++) for(int x=0; x<320; x++) SetPixel(hdc, 320+x, y, jKolor(a_lewy+double(x)*krokX, b_gora-double(y)*krokY)); } DWORD Z_M(LPVOID param) { double a_lewy = -2.0, a_prawy = 2.0; double b_gora = 1.5, b_dol = -1.5; double krokX = (a_prawy - a_lewy)/320.0; double krokY = (b_gora - b_dol)/240.0; int kolor; for(int y=0; y<240; y++) for(int x=0; x<320; x++) { kolor = Kolor(a_lewy+double(x)*krokX, b_gora-double(y)*krokY); //wejd w sekcj krytyczn EnterCriticalSection(&critical_section); //zapal piksel SetPixel((HDC)param, x, y, kolor); //opu ü sekcj krytyczn LeaveCriticalSection(&critical_section); } //zwi ksz wska nik zako czenia pracy zmienna_stop++; return 0; } DWORD Z_J(LPVOID param) { double a_lewy = -2.0, a_prawy = 2.0; double b_gora = 1.5, b_dol = -1.5; double krokX = (a_prawy - a_lewy)/320.0; double krokY = (b_gora - b_dol)/240.0; int kolor; for(int y=0; y<240; y++) for(int x=0; x<320; x++)
  • 22. 190 Czö è II i Dla redniozaawansowanych { kolor = jKolor(a_lewy+double(x)*krokX, b_gora-double(y)*krokY); //wejd w sekcj krytyczn EnterCriticalSection(&critical_section); //ustaw piksel SetPixel((HDC)param, 320+x, y, kolor); //opu ü sekcj krytyczn LeaveCriticalSection(&critical_section); } //zwi ksz wska nik zako czenia pracy zmienna_stop++; return 0; } Rezultat dziaáania programu przedstawiam na rysunku 8.4. Rysunek 8.4. Okno aplikacji Program21 dziaáaj cej z wykorzystaniem obiektu sekcji krytycznej i ustawionym najwy szym priorytetem pracy w tków 8.3. Wstrzymywanie pracy i usuwanie wñtków Zapewne przynajmniej raz spotkali cie si z irytuj cym edytorem tekstowym, który — doskonale wiedz c, co chcemy napisaü — z zadziwiaj cym uporem poprawiaá postaü wpisywanego tekstu. Oto nadszedá czas zemsty i w niniejszym podrozdziale zajmiemy si konstruowaniem podobnego, tylko jeszcze bardziej záo liwego edytora. Niezwykle pomocna przy tym b dzie umiej tno ü tworzenia w tków, które niczym duch b d ledziáy wpisywany przez u ytkownika tekst, dokonuj c jego modyfikacji. Znamy ju trzy czynno ci zwi zane z w tkami. 1. Utworzenie w tku. Do tego zadania sáu y funkcja CreateThread. 2. Obsáuga obiektów sekcji krytycznej. Wykorzystywane do tego celu funkcje to: InitializeCriticalSection, EnterCriticalSection, LeaveCriticalSection i DeleteCriticalSection. 3. Zmiana priorytetu w tku. Do tego zadania sáu y funkcja SetThreadPriority.
  • 23. Rozdziaä 8. i Projektowanie aplikacji wielowñtkowych 191 Je eli chcemy chwilowo zawiesiü dziaáanie w tku, posáu ymy si funkcj Suspend ´Thread o nast puj cej skáadni: DWORD SuspendThread(HANDLE uchwyt_watku); Jedynym parametrem funkcji jest uchwyt wstrzymywanego w tku. Wznowienie pracy w tku jest mo liwe za pomoc funkcji ResumeThread: DWORD ResumeThread(HANDLE uchwyt_watku); Gdy dziaáalno ü w tku zupeánie nam zbrzydáa, mo emy go usun ü za pomoc funkcji TerminateThread: BOOL TerminateThread(HANDLE uchwyt_watku, DWORD kod_wyjscia); Argument uchwyt_watku to — oczywi cie — uchwyt usuwanego w tku. Posáuguj c si parametrem kod_wyjscia, mo emy wysáaü kod zako czenia pracy w tku. Ten pa- rametr najcz ciej nie b dzie nas interesowaá i w jego miejsce b dziemy wpisywaü liczb zero. Przyst pujemy do budowania aplikacji uwzgl dniaj cej nowo poznane funkcje: Sus ´pendThread i ResumeThread. Otwieramy nowy projekt o nazwie Program22.dev. Obszar roboczy okna podzielimy na dwie cz ci: w cz ci pierwszej umie cimy okno potomne klasy edycji, w cz ci drugiej — przyciski typu BS_AUTORADIOBUTTON. Okno potomne tworzymy za pomoc funkcji CreateWindow. Okno klasy edycji wykreujemy przy u y- ciu nast puj cego kodu: static HWND hwndEdytora = CreateWindowEx( 0, "EDIT", NULL, WS_VISIBLE | WS_CHILD | WS_BORDER | ES_MULTILINE | WS_VSCROLL | WS_HSCROLL, 0, 0, 400, 200, hwnd, NULL, hInst, NULL); Nazw klasy okna potomnego podajemy jako drugi parametr funkcji CreateWindow. Natomiast styl okna zdefiniowany za pomoc staáych: WS_VISIBLE | WS_CHILD | WS_BORDER | ES_MULTILINE | WS_VSCROLL | WS_HSCROLL utworzy edytor wielowierszowy o poziomym i pionowym pasku przewijania. Podsta- wowe wáasno ci okna klasy edycji to mo liwo ü edycji tekstu, jego pobierania i wstawia- nia tekstu nowego. Zaáó my, e chcemy pobraü wpisany w oknie tekst. T niezwyká ch ü mo emy zaspokoiü na dwa sposoby: wykorzystuj c funkcj GetWindowText lub wysyáaj c komunikat WM_GETTEXT. Kod programu, w którym zastosowali my funkcj GetWindowText, b dzie wygl daü nast puj co: const int MaxT = 0xFFFF; char tekst[MaxT]; GetWindowText(hwndEdytora, tekst, MaxT); Analogiczny efekt uzyskamy, wysyáaj c komunikat WM_GETTEXT: const int MaxT = 0xFFFF; char tekst[MaxT]; SendMessage(hwndEdytora, WM_GETTEXT, MaxT, (LPARAM)tekst);
  • 24. 192 Czö è II i Dla redniozaawansowanych Parametrem MaxT oznaczamy maksymaln liczb pobieranych znaków. Wysáanie tekstu do okna edycji równie mo emy zrealizowaü na dwa sposoby. Pierw- szym z nich jest u ycie funkcji SetWindowText: SetWindowText(hwndEdytora, tekst); Drugim sposobem jest wysáanie komunikatu WM_SETTEXT: SendMessage(hwndEdytora, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)tekst); Do ü káopotliw wáasno ci klasy edycji jest resetowanie pozycji karetki po ka dora- zowym wysáaniu tekstu do okna edycji. Do ustawienia pozycji karetki sáu y funkcja SetCaretPos, jednak — zgodnie z opisem Pomocy Microsoft Windows — funkcja dziaáa tylko dla karetek utworzonych przez okno, czyli nie dziaáa dla obiektów klasy edycji. Posáu ymy si wybiegiem, a dokáadniej wysáaniem komunikatu EM_SETSEL. SendMessage(hwndEdytora, EM_SETSEL, poczatek, koniec); Komunikat EM_SETSEL jest wysyáany w celu zaznaczenia bloku tekstu, pocz wszy od litery o indeksie poczatek i ko cu oznaczonym indeksem koniec. Po wykonaniu tego zadania karetka jest ustawiana w punkcie oznaczonym indeksem koniec. U ycie komu- nikatu w nast puj cy sposób: SendMessage(hwndEdytora, EM_SETSEL, x, x); jest áatwym sposobem przemieszczania pozycji karetki do pozycji x w oknie edycji. Przejd my do omawiania kluczowej cz ci programu, czyli do obsáugi w tków. W chwili uruchomienia aplikacji tworzone s dwa w tki, z których aktywny mo e byü tylko jeden lub aden. //uruchom pierwszy w tek sprawdzania pisowni watek1 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PisowniaPierwszaDuza, hwndEdytora, 0, &p); //uruchom drugi w tek sprawdzania pisowni watek2 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PisowniaWszystkieDuze, hwndEdytora, 0, &p); //wstrzymaj dziaáanie w tku drugiego SuspendThread(watek2); //ustaw wska nik uruchomionego w tku flaga = 1; Zmienna globalna flaga sáu y do zaznaczenia aktywno ci w tku. Przeá czanie aktyw- no ci w tków, zgodnie z konfiguracj przycisków klasy BS_AUTORADIOBUTTON, zostaáo zaimplementowane w kodzie obsáugi komunikatu WM_COMMAND. case WM_COMMAND: switch(LOWORD(wParam)) { case 1001: switch(flaga) { case 2: //wstrzymaj dziaáanie w tku drugiego SuspendThread(watek2);
  • 25. Rozdziaä 8. i Projektowanie aplikacji wielowñtkowych 193 case 3: //pocz tek nowego formatowania ustawiany jest //na ostatni wprowadzony znak GetWindowText(hwndEdytora, tekst, MaxT); pocz_format = strlen(tekst); //ponownie uruchom w tek pierwszy ResumeThread(watek1); break; } flaga = 1; break; case 1002: switch(flaga) { case 1: //wstrzymaj dziaáanie w tku pierwszego SuspendThread(watek1); case 3: //pocz tek nowego formatowania ustawiany jest na ostatni wprowadzony znak GetWindowText(hwndEdytora, tekst, MaxT); pocz_format = strlen(tekst); //ponownie uruchom w tek drugi ResumeThread(watek2); break; } flaga = 2; break; case 1003: switch(flaga) { case 1: //wstrzymaj dziaáanie w tku pierwszego SuspendThread(watek1); break; case 2: //wstrzymaj dziaáanie w tku drugiego SuspendThread(watek2); break; } flaga = 3; break; case 1010: SendMessage(hwnd, WM_DESTROY, 0, 0); break; } break; Dzi ki uwzgl dnieniu zmiennej pocz_poz modyfikacje tekstu nie wywoáuj zmian w tek cie wpisanym przed wybraniem kolejnego sposobu formatowania. Staáe parametru wParam odpowiadaj identyfikatorom okien potomnych klasy BS_AUTORADIOBUTTON. Aktywny w tek co sekund sprawdza wpisany tekst, generuj c zmiany zgodne z wybra- nym sposobem formatowania. Dzi ki zastosowanym w tkom kod pliku Program22_ main.cpp nie jest skomplikowany, w caáo ci wygl da nast puj co:
  • 26. 194 Czö è II i Dla redniozaawansowanych #include <windows.h> const int MaxT = 0xFFFF; char tekst[MaxT]; /* znacznik uruchomionego w tku*/ int flaga; /* Uchwyty w tków*/ HANDLE watek1, watek2; /* wska nik pocz tku formatowania tekstu */ int pocz_format; /* Deklaracja funkcji w tku */ DWORD PisowniaPierwszaDuza(LPVOID parametr); DWORD PisowniaWszystkieDuze(LPVOID parametr); LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM); char szClassName[ ] = "WindowsApp"; int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nFunsterStil) { HWND hwnd; MSG messages; WNDCLASSEX wincl; wincl.hInstance = hThisInstance; wincl.lpszClassName = szClassName; wincl.lpfnWndProc = WindowProcedure; wincl.style = CS_DBLCLKS; wincl.cbSize = sizeof (WNDCLASSEX); wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION); wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION); wincl.hCursor = LoadCursor (NULL, IDC_ARROW); wincl.lpszMenuName = NULL; wincl.cbClsExtra = 0; wincl.cbWndExtra = 0; wincl.hbrBackground = (HBRUSH) COLOR_BTNSHADOW; if (!RegisterClassEx (&wincl)) return 0; hwnd = CreateWindowEx ( 0, szClassName, "Program22", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 410, 375, HWND_DESKTOP, NULL, hThisInstance,
  • 27. Rozdziaä 8. i Projektowanie aplikacji wielowñtkowych 195 NULL ); ShowWindow (hwnd, nFunsterStil); while (GetMessage (&messages, NULL, 0, 0)) { TranslateMessage(&messages); DispatchMessage(&messages); } return messages.wParam; } LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, ´LPARAM lParam) { DWORD p; switch (message) { case WM_CREATE: static HINSTANCE hInst = (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE); //utwórz okno edycji static HWND hwndEdytora = CreateWindowEx( 0, "EDIT", NULL, WS_VISIBLE | WS_CHILD | WS_BORDER | ES_MULTILINE | WS_VSCROLL | ´WS_HSCROLL, 0, 0, 400, 200, hwnd, NULL, hInst, NULL); CreateWindowEx(0, "BUTTON", "Opcje formatowania tekstu", WS_VISIBLE | WS_CHILD | BS_GROUPBOX, 5, 210, 220, 110, hwnd, NULL, hInst, NULL); static HWND hwndRadio1 = CreateWindowEx( 0, "BUTTON", "Du e pierwsze litery", WS_VISIBLE | WS_CHILD | WS_GROUP | BS_AUTORADIOBUTTON, 10, 240, 170, 20, hwnd, (HMENU)1001, hInst, NULL); static HWND hwndRadio2 = CreateWindowEx( 0, "BUTTON", "Du e wszystkie litery", WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON, 10, 260, 170, 20, hwnd, (HMENU)1002, hInst, NULL); static HWND hwndRadio3 = CreateWindowEx( 0, "BUTTON", "Bez modyfikacji", WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON, 10, 280, 170, 20, hwnd, (HMENU)1003, hInst, NULL); CreateWindowEx(0, "BUTTON", "Koniec", WS_VISIBLE | WS_CHILD, 260, 230, 110, 80, hwnd, (HMENU)1010, hInst, NULL); //uruchom pierwszy w tek sprawdzania pisowni watek1 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PisowniaPierwszaDuza, hwndEdytora, 0, &p);
  • 28. 196 Czö è II i Dla redniozaawansowanych //uruchom drugi w tek sprawdzania pisowni watek2 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PisowniaWszystkieDuze, hwndEdytora, 0, &p); //wstrzymaj dziaáanie w tku drugiego SuspendThread(watek2); //ustaw wska nik uruchomionego w tku flaga = 1; //ustaw domy ln opcj SendMessage(hwndRadio1, BM_SETCHECK, 1001, 0); //ustaw zakres zmian tekstu pocz_format = 0; break; case WM_COMMAND: switch(LOWORD(wParam)) { case 1001: switch(flaga) { case 2: //wstrzymaj dziaáanie w tku drugiego SuspendThread(watek2); case 3: //pocz tek nowego formatowania ustawiany jest na ostatni //wprowadzony znak GetWindowText(hwndEdytora, tekst, MaxT); pocz_format = strlen(tekst); //ponownie uruchom w tek pierwszy ResumeThread(watek1); break; } flaga = 1; break; case 1002: switch(flaga) { case 1: //wstrzymaj dziaáanie w tku pierwszego SuspendThread(watek1); case 3: //pocz tek nowego formatowania ustawiany jest na ostatni //wprowadzony znak GetWindowText(hwndEdytora, tekst, MaxT); pocz_format = strlen(tekst); //ponownie uruchom w tek drugi ResumeThread(watek2); break; } flaga = 2; break; case 1003: switch(flaga) { case 1: //wstrzymaj dziaáanie w tku pierwszego SuspendThread(watek1); break;
  • 29. Rozdziaä 8. i Projektowanie aplikacji wielowñtkowych 197 case 2: //wstrzymaj dziaáanie w tku drugiego SuspendThread(watek2); break; } flaga = 3; break; case 1010: SendMessage(hwnd, WM_DESTROY, 0, 0); break; } break; case WM_DESTROY: PostQuitMessage (0); break; default: return DefWindowProc (hwnd, message, wParam, lParam); } return 0; } DWORD PisowniaPierwszaDuza(LPVOID parametr) { int i, pozycja; //dziaáaj a do odwoáania while(TRUE) { //pobierz tekst okna GetWindowText((HWND)parametr, tekst, MaxT); //popraw tekst i = pocz_format; while(tekst[i]) { //postaw du liter , gdy jest to pierwszy znak if((i==pocz_format)&&(tekst[i]>=97&&tekst[i]<=122)) tekst[i] -= 32; //lub jest to znak po spacji, lub znaku nowej linii if(tekst[i]==32||tekst[i]=='n') { if(tekst[i+1]>=97&&tekst[i+1]<=122) tekst[i+1] -= 32; //sprawd polskie znaki if(tekst[i+1]=='æ') tekst[i+1] = 'ä'; if(tekst[i+1]=='è') tekst[i+1] = 'ç'; if(tekst[i+1]=='ú') tekst[i+1] = 'ù'; if(tekst[i+1]==' ') tekst[i+1] = ' '; if(tekst[i+1]==' ') tekst[i+1] = ' '; if(tekst[i+1]=='ó') tekst[i+1] = 'Ó'; if(tekst[i+1]==' ') tekst[i+1] = ' '; if(tekst[i+1]==' ') tekst[i+1] = ' '; if(tekst[i+1]==' ') tekst[i+1] = ' '; } //zwi ksz licznik i++;
  • 30. 198 Czö è II i Dla redniozaawansowanych } //wy lij poprawiony tekst do okna edycji SetWindowText((HWND)parametr, tekst); //ustaw karetk na koniec tekstu SendMessage((HWND)parametr, EM_SETSEL, i, i); //zaczekaj Sleep(1000); } return 0; } DWORD PisowniaWszystkieDuze(LPVOID parametr) { int i, pozycja; //dziaáaj a do odwoáania while(TRUE) { //pobierz tekst okna GetWindowText((HWND)parametr, tekst, MaxT); //popraw tekst i = pocz_format; while(tekst[i]) { //postaw du liter w miejsce maáej if(tekst[i]>=97&&tekst[i]<=122) tekst[i] -= 32; //sprawd polskie znaki if(tekst[i]=='æ') tekst[i] = 'ä'; if(tekst[i]=='è') tekst[i] = 'ç'; if(tekst[i]=='ú') tekst[i] = 'ù'; if(tekst[i]==' ') tekst[i] = ' '; if(tekst[i]==' ') tekst[i] = ' '; if(tekst[i]=='ó') tekst[i] = 'Ó'; if(tekst[i]==' ') tekst[i] = ' '; if(tekst[i]==' ') tekst[i] = ' '; if(tekst[i]==' ') tekst[i] = ' '; //zwi ksz licznik i++; } //wy lij poprawiony tekst do okna edycji SetWindowText((HWND)parametr, tekst); //ustaw karetk na koniec tekstu SendMessage((HWND)parametr, EM_SETSEL, i, i); //zaczekaj Sleep(1000); } return 0; }
  • 31. Rozdziaä 8. i Projektowanie aplikacji wielowñtkowych 199 Okno gáówne dziaáaj cej aplikacji prezentuj na rysunku 8.5. W celu zilustrowania dzia- áania programu wykorzystaáem fragment wspaniaáej powie ci Arkadija i Borysa Stru- gackich Poniedziaáek zaczyna si w sobot 1. Rysunek 8.5. Okno gáówne aplikacji Program22 8.4. çwiczenia ûwiczenie 13. Zaprojektuj aplikacj , w której w obszarze roboczym okna wy wietlany b dzie czas systemowy. W lewej cz ci obszaru okna czas b dzie wy wietlany w postaci cyfrowej, praw cz ü okna zajmie tarcza zegara o klasycznej postaci (patrz rysunek 8.6). Do obsáugi zegarów u yj dwóch w tków. Rysunek 8.6. Okno gáówne aplikacji Cwiczenie13 ûwiczenie 14. Uruchomione w aplikacji Program22 w tki sáu yáy do automatycznego poprawiania pisowni w edytorze tekstowym. Zaprojektuj podobn aplikacj dziaáaj c w edytorze graficznym, w której uruchomiony w tek b dzie zamieniaá narysowane linie krzywe w linie proste (sposób dziaáania programu zilustrowano na rysunku 8.7). 1 Arkadij Strugacki, Borys Strugacki, Poniedziaáek zaczyna si w sobot , táum. Irena Piotrowska, Warszawa 1970, s. 17.
  • 32. 200 Czö è II i Dla redniozaawansowanych Rysunek 8.7. Ilustracja dziaáania programu Cwiczenie14