menu

darmowe eBooki

Efekt Motyla

okładka

Książka, która wywróci Twoje życie do góry nogami

Sprawdź sam, czytając darmowy fragment eBooka Efekt Motyla.

Czy ta wiedza okazała się dla Ciebie przydatna? Chcesz wiedzieć więcej? Zobacz tutaj.

Google Adsense

migawka z forum

Dowcipy o programistach/informatykach

Witam, grunt to potrafić śmiać sie z samego siebie  ;DPrzychodzi informatyk do domu po pra...

Rysiek z "Klanu"

W związku z ogromnym poruszeniem we wszystkich mediach w naszym kraju, dotyczącym tak kultowej postaci jak Rysiek z &quo...

Propozycje zmian w serwisie Guide C++

Witam, ze względu na to że nie znalazłem podobnego tematu na forum, a mam kilka sugestii   ;) postanowiłem je ...

buttony

SDJ
vortal programistów
Vademecum sieci komputerowych
Soldiers'04 - fan klub Legii Warszawa
www.katalog.bajery.pl
katalog stron
katalog najlepszych stron
jestem w katalogu
Wszystko o C++
[zamknij]

Korzystamy z plików cookies i umożliwiamy zamieszczanie ich osobom trzecim. Pliki cookie pozwalają na poznanie twoich preferencji na podstawie zachowań w serwisie.
Uznajemy, że jeżeli kontynuujesz korzystanie z serwisu, wyrażasz na to zgodę.

jesteś w: Kurs WinAPI / Pierwsze okno
Szkoła Hakerów - Kurs Hackingu Bez Cenzury

Pierwsze okno

Ta lekcja będzie chyba najtrudniejsza z całego kursu WinAPI :o Spoko, spoko, chciałem powiedzieć najdłuższa :) Tak naprawdę jeżeli dobrze zrozumiesz to, co tutaj powiem, to reszta będzie tylko jakby rozwinięciem. Tak więc bez zbędnego gadania przejdźmy do sedna sprawy. Stwórzmy sobie pierwsze okienko! Oczywiście za pomocą WinAPI, a jakżeby inaczej ;-) Jak już wiesz z lekcji poprzedniej każda aplikacja okienkowa musi posiadać funkcję główną o nazwie WinMain. Tak więc zacznijmy właśnie od niej. Zatem utwórz nowy projekt. Pamiętaj tylko, że tworzysz program 32-bitowy, a nie konsolowy! Jeżeli nie wiesz, jak to zrobić, a korzystasz ze środowiska Dev-C++ to odsyłam do opisu W przypadku innych środowisk programistycznych zerknij do dokumentacji. Jeżeli wszystko poszło dobrze to nowy projekt został utworzony. Dev-C++ jest tak wspaniałomyślny, że sam tworzy dla nas z szablonu okienko główne. My jednak dla celów edukacyjnych stworzymy sobie wszystko ręcznie od nowa. Wyrzuć zatem całą zawartość pliku main.cpp [standardowa nazwa]. Na początek trzeba dołączyć wszelkie niezbędne pliki nagłówkowe. Mamy szczęście, bo w Windows'ie wystarczy dodać tylko jeden plik! Nosi on nazwę windows.h i zawiera wszystko, co niezbędne [na początku ;-)] Pamiętasz jeszcze, jak dołączało się pliki? Jeżeli nawet zapomniałeś to przypomnę. Służy do tego dyrektywa #include <nazwa_pliku>. Tak więc w naszym przypadku będzie to wyglądało następująco: #include <windows.h>. To wystarczy, aby móc korzystać z dobrodziejstw API! Co prawda w profesjonalnych aplikacjach pojawia się jeszcze inny plik, ale o tym powiem nieco później. Na razie ten plik jest wystarczający. Dobra mamy już przygotowane narzędzia. Teraz trzeba sobie napisać definicję funkcji głównej. Zatem piszemy:

  1. int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nMode)
  2. {
  3. return 0;
  4. }

Jak widać funkcja przyjmuje cztery argumenty. Pierwszy argument hInstance to uchwyt instancji, czyli po prostu uchwyt naszego programu. Pojęcie uchwyt oznacza praktycznie to samo, co wskaźnik. Wprawdzie są drobne różnice między tymi elementami, ale nie warto sobie zaprzątać nimi głowy. Drugim argumentem tej funkcji, czyli hPrevInstance jest także uchwyt. Odnosi się on do poprzedniej instancji. Jest on jednak nieistotny, gdyż w systemie 32-bitowym nie jest używany. Kolejny argument o nazwie lpszCmdLine to wskaźnik do łańcucha znakowego. Ten łańcuch to nic innego, jak wskaźnik do ścieżki poleceń. Gdy program zostanie uruchomiony z argumentami, to można się do nich dobrać właśnie za pomocą tego wskaźnika. Został nam jeszcze ostatni argument - nMode. Określa on sposób wyświetlania okna. Konkretnie chodzi o to, czy okno po utworzeniu ma być zminimalizowane czy zmaksymalizowane etc. - zazwyczaj stawiamy tam 0. Obecnie funkcja jest pusta. Widnieje tam jedynie instrukcja zwracająca wartość 0. Tak, aby kompilator się nie buntował. To już znamy od dawna. Teraz zajmiemy się czymś, czego ja osobiście nie lubię :-/ Mianowicie musimy zdefiniować sobie trzy obiekty. Pierwszy to obiekt typu HWND będący uchwytem okna, drugi to struktura komunikatów typu MSG, a trzeci to struktura reprezentująca klasę okna, czyli typ WNDCLASS. Aby nie trzymać Cię w niepewności pokażę jak to wszystko wygląda składniowo:

  1. HWND hOkno;
  2. MSG message;
  3. WNDCLASS okno;
  4.  
  5. okno.hInstance = hInstance;
  6. okno.lpszClassName = "klasa główna";
  7. okno.lpfnWndProc = DefWindowProc;
  8. okno.lpszMenuName = NULL;
  9. okno.style = 0;
  10. okno.hIcon = LoadIcon (NULL,IDI_WINLOGO);
  11. okno.hCursor = LoadCursor (NULL,IDC_ARROW);
  12. okno.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH);
  13. okno.cbClsExtra = 0;
  14. okno.cbWndExtra = 0;

Pierwsze trzy linijki chyba są zrozumiałe. Zwykłe definicja obiektów poszczególnych typów. Pozostałe linie to właśnie ta cała babranina o której nadmieniłem przed chwilą ;-) Ale po kolei. Pierwsza instrukcja to: okno.hInstance = hInstance. W tej instrukcji określamy, do jakiej instancji będzie należało nasze okno. My podaliśmy nazwę hInstance, czyli to, co jest pierwszym argumentem funkcji głównej WinMain. Następna linijka to: okno.lpszClassName = "klasa główna";, czyli po prostu nazwa naszej klasy. Możesz tutaj napisać praktycznie co tylko chcesz. To nie ma znaczenia. Nazwa klasy posłuży nam później do utworzenia okienka. Kolejny wers okno.lpfnWndProc = DefWindowProc; to wskaźnik do procedury obsługi okna. Procedura obsługi to bardzo istotny element. Jest to praktycznie zwykła funkcja, w której określamy sposób zachowywania się okna. Konkretnie jak ma reagować na rozmaite zdarzenia, jak kliknięcie mychą, przesuwanie, rozciąganie i wiele innych. Znów panowie z Microsoftu poszli nam na rękę i napisali taką standardową procedurę o nazwie DefWindowProc. Obsługuje ona wszystkie zdarzenia i komunikaty. Problem w tym, że robi to w sposób tradycyjny, co nie zawsze akceptujemy. Jeżeli chcemy, aby okienko w danej sytuacji reagowało inaczej to należy napisać własną procedurę i podczepić ją pod konkretne okno. O budowie procedury okna i jej zamianie powiemy sobie dopiero, gdy utworzymy okienko. Tak więc już za niedługo. Kolejnym elementem struktury WNDCLASS jest pole lpszMenuName. Chyba wyczuwasz o co chodzi? Tak, tak tutaj określamy czy okno będzie posiadać menu. Na razie rezygnujemy z menu, więc podstawiamy wartość NULL. Dokładniej o tworzeniu menu powiemy sobie w następnej lekcji. Kolejnym ważnym elementem jest styl okna. Styl określa wygląd okienka. Wartość zero oznacza, że chcemy utworzyć standardowe okienko posiadające pasek tytułowy oraz trzy przyciski: minimalizacja, maxymalizacja i zamknięcie okna. Więcej o stylach możesz poczytać na tej stronie Dwie następne instrukcje to okno.hIcon = LoadIcon(NULL, IDI_WINLOGO); i okno.hCursor = LoadCursor(NULL, IDC_ARROW);. Pierwsza określa, jaka ikona będzie widoczna na pasku tytułowym okna. W drugiej określamy jaki wygląd będzie miał kursor. Funkcja LoadIcon służy do odczytania ikony. Pierwszym argumentem tej funkcji jest NULL, co oznacza, że wybieramy ikonę z zasobów Windows'a. Jej nazwa jest podana w drugim argumencie. Analogicznie wygląda sprawa z kursorem. Ostatnią rzeczą, którą należy zrobić przy inicjalizacji struktury reprezentującej klasę okna jest ustawienie koloru okienka. Musimy zatem ustawić wskaźnik hbrBackground na odpowiedni pędzel. Pędzel to obiekt klasy HBRUSH. W Windowsie do takich 'kolorowanek' używa się właśnie pędzli lub innych 'przyborów kreślarskich' ;-) Tylko skąd wziąć taki pędzel? Otóż mamy dwa wyjścia. Możemy sobie sami stworzyć nowy pędzel lub skorzystać z już istniejących. Bowiem Windows idzie nam na rękę i automatycznie tworzy kilka pędzli! Chcąc wykorzystać istniejący już pędzel trzeba skorzystać z funkcji GetStockObject. Przyjmuje ona tylko jeden argument. Jest to liczba określająca obiekt, do którego chcemy się odwołać. No tak, tylko jaki numer ma pędzel w kolorze czarnym? Ja nie wiedziałem, ale poszperałem trochę w plikach nagłówkowych i znalazłem taką oto makrodefinicję: #define BLACK_BRUSH 4. To jest właśnie to, o co nam chodziło. Pędzel w kolorze czarnym posiada numer identyfikacyjny 4. Tak więc wystarczy wywołać funkcję GetStockObject z argumentem równym 4 lub BLACK_BRUSH, a ona zwróci uchwyt do czarnego pędzla. Tak BTW to warto czasami popatrzeć po plikach z rozszerzeniem *.h Można tam znaleźć mnóstwo przydatnych informacji. Dobra, mamy już uchwyt do pędzla. Teraz wystarczy podpiąć go do składnika struktury WNDCLASS o nazwie hbrBackground. Linijka okno.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); załatwia sprawę. Zapamiętaj tylko, że funkcja GetStockObject zwraca uchwyt do bliżej nieokreślonego obiektu. My sami musimy wiedzieć jakiego typu jest obiekt i poinformować o tym kompilator poprzez rzutowanie. Stąd zapis (HBRUSH) przed wywołaniem funkcji GetStockObject. Zostały nam jeszcze dwa składniki struktury WNDCLASS. Są to cbClsExtra i cbWndExtra. Określają one ile dodatkowej pamięci należy przydzielić dla klasy okna oraz samego okna. Zazwyczaj nie ma potrzeby rezerwowania dodatkowej pamięci. Tak więc najlepiej ustawić je na zero. Praktycznie już możemy sobie utworzyć nowe okno. Jednak zanim to zrobimy musimy jeszcze zarejestrować naszą klasę. Rejestracją zajmuje się funkcja RegisterClass. Jako argument przyjmuje adres struktury reprezentującej klasę okna. Zerknij sobie:

  1. if (!RegisterClass (& okno)) return 0;

Gdy wszystko pójdzie dobrze funkcja RegisterClass zwraca wartość nie-zerową. W przeciwnym wypadku [np. gdy braknie pamięci] klasa nie zostanie zarejestrowana i funkcja zwróci wartość 0. Wtedy trzeba jakoś zareagować. My po prostu zwracamy wartość 0 do funkcji WinMain co jest równoznaczne z zakończeniem programu. Jednak gdy wszystko będzie dobrze i klasa zostanie zarejestrowana możemy wreszcie utworzyć pierwsze okno :) Robi się to funkcją CreateWindow. Jej deklaracja wygląda tak:

  1. HWND WINAPI CreateWindow (LPCSTR, LPCSTR, DWORD, int, int, int, int, HWND, HMENU, HINSTANCE, LPVOID);

Pierwszym argumentem jest nazwa klasy okna. Pamiętasz jeszcze, jak my nazwaliśmy naszą klasę? Drugi argument to tytuł okna, czyli text wyświetlany na pasku tytułowym. Dalej podajemy styl okna oraz koordynaty lewego-górnego narożnika okna. Dwa kolejne argumenty to wysokość i szerokość. Następnie jest uchwyt rodzica, czyli okna nadrzędnego, uchwyt menu i uchwyt instancji. Ostatni argument to dodatkowe informacje. Ja zawsze stawiam tutaj wartość NULL. Jeżeli tworzenie okna powiedzie się funkcja CreateWindow zwróci uchwyt do nowo utworzonego okna. Popatrz na kod, a wszystko stanie się zrozumiałe.

  1. hOkno = CreateWindow (
  2. "klasa główna", //nazwa klasy okna
  3. "pierwsze okno :)", //tytuł okna
  4. WS_OVERLAPPEDWINDOW, //styl - WS_OVERLAPPEDWINDOW to standardowe okienko
  5. 300, 400, //współrzędne i..
  6. 200, 100, //..wymiary okna
  7. NULL, //brak okna nadrzędnego, właścicielem jest pulpit
  8. NULL, //brak menu
  9. hInstance, //uchwyt instancji
  10. NULL //brak dodatkowych danych
  11. );

To już prawie koniec. Okienko już istnieje, ale trzeba jeszcze poinformować nasz program, że chcemy je ujrzeć na ekranie. Nic prostszego! Wystarczy wywołać funkcję ShowWindow. Funkcja ta przyjmuje tylko dwa argumenty. Pierwszy to uchwyt okienka [u nas jest to hOkno], a drugi to tryb wyświetlania okna [my podamy SW_SHOW, czyli po prostu wyświetlenie okna w normalnej postaci]. Zatem wywołajmy tę funkcję!

  1. ShowWindow (hOkno, SW_SHOW);

Ostatnią rzeczą, którą należy zrobić jest utworzenie pętli, w której umieścimy instrukcje obsługujące nasze okno.

  1. while (GetMessage (&message, NULL, 0, 0))
  2. {
  3. DispatchMessage (&message);
  4. }

Wpierw pojawia się nam funkcja GetMessage. Jej zadanie polega na pobieraniu komunikatów od systemu. Gdy takowe się pojawią zostaje wywołana kolejna funkcja - DispatchMessage, która posyła komunikat do procedury okna, gdzie następuje odpowiednia reakcja. I tak w kółko dopóki nie zamkniemy naszego okna :) Mniej więcej tak to wszystko wygląda. Jakbyś się pogubił to poniżej znajduje się całościowy kod tworzenia okna

  1. #include <windows.h>
  2.  
  3. int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpsCmdLine, int nMode)
  4. {
  5. //uchwyt okna
  6. HWND hOkno;
  7. //struktura komunikatów
  8. MSG message;
  9. //klasa okna
  10. WNDCLASS okno;
  11.  
  12. //uchwyt instancji
  13. okno.hInstance = hInstance;
  14. //nazwa klasy okna
  15. okno.lpszClassName = "klasa główna";
  16. //standardowa procedura okna
  17. okno.lpfnWndProc = DefWindowProc;
  18. //brak menu
  19. okno.lpszMenuName = NULL;
  20. //standardowe okno
  21. okno.style = 0;
  22. //standardowa ikona
  23. okno.hIcon = LoadIcon (NULL, IDI_WINLOGO);
  24. //standardowy kursor
  25. okno.hCursor = LoadCursor (NULL, IDC_ARROW);
  26. //czarny kolor
  27. okno.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH);
  28. //brak przydziału dodatkowej pamieci dla klasy okna
  29. okno.cbClsExtra = 0;
  30. //brak przydziału dodatkowej pamieci okna
  31. okno.cbWndExtra = 0;
  32. //rejestracja klasy okna
  33. if(!RegisterClass (&okno)) return 0;
  34. //utworzenie okna
  35. hOkno = CreateWindow ("klasa główna", "łokno :p",
  36. WS_OVERLAPPEDWINDOW, 100,100,200,100,
  37. NULL, NULL, hInstance, NULL);
  38. //wyświetlenie okna na ekranie
  39. ShowWindow (hOkno, SW_SHOW);
  40.  
  41. while (GetMessage (&message, NULL, 0, 0))
  42. {
  43. DispatchMessage (&message);
  44. }
  45. }