Win32 API
Radzenie sobie z oknami
Szukaj…
Tworzenie okna
#define UNICODE
#define _UNICODE
#include <windows.h>
#include <tchar.h>
const TCHAR CLSNAME[] = TEXT("helloworldWClass");
LRESULT CALLBACK winproc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp);
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, PTSTR cmdline,
int cmdshow)
{
WNDCLASSEX wc = { };
MSG msg;
HWND hwnd;
wc.cbSize = sizeof (wc);
wc.style = 0;
wc.lpfnWndProc = winproc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = CLSNAME;
wc.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wc)) {
MessageBox(NULL, TEXT("Could not register window class"),
NULL, MB_ICONERROR);
return 0;
}
hwnd = CreateWindowEx(WS_EX_LEFT,
CLSNAME,
NULL,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInst,
NULL);
if (!hwnd) {
MessageBox(NULL, TEXT("Could not create window"), NULL, MB_ICONERROR);
return 0;
}
ShowWindow(hwnd, cmdshow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK winproc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp)
{
return DefWindowProc(hwnd, wm, wp, lp);
}
Pierwszą rzeczą, jaką _UNICODE
są dwie definicje makr, UNICODE
i _UNICODE
. Te makra powodują, że nasz program rozumie szerokie ciągi znaków ( wchar_t[n]
), a nie zwykłe wąskie ciągi znaków ( char[n]
). W rezultacie wszystkie literały ciągów muszą być zawinięte w TEXT(
makro. Ogólnym typem znaków dla ciągów Win32 jest TCHAR
, którego definicja zależy od tego, czy zdefiniowano UNICODE
. Dołączono nowy nagłówek: <tchar.h>
zawiera deklaracja TCHAR
.
Okno składa się z tak zwanej klasy okna . Opisuje informacje o oknie, które ma być udostępniane między jego instancjami, takimi jak ikona, kursor i inne. Klasa okna jest identyfikowana przez nazwę klasy okna, która jest podana w zmiennej globalnej CLSNAME
w tym przykładzie. Pierwszym aktem WinMain
jest wypełnienie struktury klasy okna WNDCLASSEX wc
. Członkami są:
- cbSize: rozmiar struktury w bajtach
- styl: style klas okien. Na razie jest to 0.
- lpfnWndProc: To jedno z ważniejszych pól. Przechowuje adres procedury okna . Procedura okna jest funkcją, która obsługuje zdarzenia dla wszystkich okien, które są instancjami tej klasy okna.
- cbClsExtra: Liczba dodatkowych bajtów do przydzielenia dla klasy okna. W większości sytuacji tym członkiem jest 0.
- cbWndExtra: Liczba dodatkowych bajtów do przydzielenia dla każdego okna. Nie należy mylić tego z
cbClsExtra
, który jest wspólny dla wszystkich instancji. Często jest to 0. - hInstance: uchwyt instancji. Po prostu przypisz argument
hInst
wWinMain
do tego pola. - hIcon: Uchwyt ikony dla klasy okna.
LoadIcon(NULL, IDI_APPLICATION)
ładuje domyślną ikonę aplikacji. - hCursor: uchwyt kursora dla klasy okna.
LoadCursor(NULL, IDC_ARROW)
ładuje domyślny kursor. - hbrBackground: Uchwyt pędzla w tle.
GetStockObject (WHITE_BRUSH)
daje uchwyt białego pędzla.GetStockObject
wartość musi być rzutowana, ponieważGetStockObject
zwraca obiekt ogólny. - lpszMenuName: nazwa zasobu używanego paska menu. Jeśli pasek menu nie jest potrzebny, to pole może mieć wartość NULL.
- lpszClassName: nazwa klasy, która identyfikuje tę strukturę klas okna. W tym przykładzie zmienna globalna
CLSNAME
przechowuje nazwę klasy okna. - HIconSm: Uchwyt do ikony małej klasy.
Po zainicjowaniu tej struktury wywoływana jest funkcja RegisterClassEx
. To powoduje, że klasa okna jest rejestrowana w systemie Windows, dzięki czemu jest znana aplikacji. W przypadku niepowodzenia zwraca 0.
Teraz, gdy klasa okna została zarejestrowana, możemy wyświetlić okno za pomocą CreateWindowEx
. Argumenty są następujące:
- stylesex: Rozszerzone style okien. Wartość domyślna to WS_EX_LEFT.
- clsname: nazwa klasy
- cap: tytuł okna lub podpis. W tym przypadku jest to podpis wyświetlany na pasku tytułu okna.
- styles: style okna. Jeśli chcesz utworzyć okno najwyższego poziomu (nadrzędne), takie jak to, flagą do przekazania jest WS_OVERLAPPEDWINDOW.
- x: Współrzędna x lewego górnego rogu okna.
- y: współrzędna y lewego górnego rogu okna
- cx: szerokość okna
- cy: Wysokość okna
- hwndParent: uchwyt do okna nadrzędnego. Ponieważ to okno samo w sobie jest oknem nadrzędnym, argument ten ma wartość NULL.
- hMenuOrID: Jeśli tworzone okno jest oknem nadrzędnym, ten argument jest uchwytem menu okna. Nie myl tego z menu klasy, którym jest
WNDCLASSEX::lpszClassName
. Menu klasy jest wspólne dla wszystkich instancji systemu Windows o tej samej nazwie klasy. Ten argument jest jednak specyficzny tylko dla tej instancji. Jeśli tworzone okno jest oknem potomnym, to jest to identyfikator okna potomnego. W tym przypadku tworzymy okno nadrzędne bez menu, więc wartość NULL jest przekazywana. - hInst: uchwyt do instancji aplikacji.
- itp .: Dodatkowe informacje przekazywane do procedury okna. Jeśli nie ma być przesyłana żadna dodatkowa informacja, należy podać NULL.
Jeśli x
lub y
cx
lub cy
to CW_USEDEFAULT
, wartość tego argumentu zostanie określona przez system Windows. Tak właśnie zrobiono w tym przykładzie.
CreateWindowEx
zwraca uchwyt do nowo utworzonego okna. Jeśli tworzenie okna nie powiodło się, zwróciło NULL
.
Następnie wyświetlamy okno, wywołując ShowWindow
. Pierwszym argumentem tej funkcji jest uchwyt okna. Drugi argument to styl pokazu, który wskazuje sposób wyświetlania okna. Większość aplikacji po prostu przekazuje argument cmdshow
przekazany w WinMain
. Po wyświetleniu okna należy je zaktualizować przez wywołanie UpdateWindow
. Powoduje wysłanie komunikatu aktualizacji do okna. Dowiemy się, co to znaczy w innym samouczku.
Teraz jest sedno aplikacji: pompa wiadomości. Pompuje wiadomości wysłane do tej aplikacji przez system operacyjny i wysyła je do procedury okna. Wywołanie GetMessage
zwraca wartość niezerową, dopóki aplikacja nie odbierze komunikatów, które powodują jej zamknięcie, w którym to przypadku zwraca 0. Jedyny argument, który nas dotyczy, to wskaźnik do struktury MSG
, która zostanie wypełniona informacjami o wiadomości. Pozostałe argumenty to 0.
Wewnątrz pętli komunikatów TranslateMessage
tłumaczy wiadomości z kluczem wirtualnym na wiadomości znakowe. Znaczenie tego ponownie nie jest dla nas ważne. Pobiera wskaźnik do struktury MSG
. Wywołanie bezpośrednio po nim, DispatchMessage
, wysyła komunikat wskazany przez jego argument do procedury okna. Ostatnią rzeczą, którą WinMain
musi zrobić, jest zwrócenie kodu statusu. Element wParam
struktury MSG
zawiera tę zwracaną wartość, więc jest zwracana.
Ale to tylko dla funkcji WinMain
. Inną funkcją jest winproc
, procedura okna. Będzie obsługiwał wiadomości dla okna wysyłane do niego przez system Windows. Podpis dla winproc
to:
- hwnd: uchwyt do okna, którego wiadomości są przetwarzane.
- wm: identyfikator komunikatu okna
- wp: Jeden z argumentów informacji o wiadomości. To zależy od argumentu
wm
- lp: Jeden z argumentów informacji o wiadomości. To zależy od argumentu
wm
. Ten argument jest zwykle używany do przesyłania wskaźników lub uchwytów
W tym prostym programie sami nie obsługujemy żadnych wiadomości. Ale to nie znaczy, że Windows też nie. Dlatego należy wywołać DefWindowProc
, który zawiera domyślny kod obsługi okna. Ta funkcja musi zostać wywołana na końcu każdej procedury okna.
Co to jest uchwyt?
Uchwyt to typ danych reprezentujący unikalny obiekt. Są to wskaźniki, ale tajne struktury danych utrzymywane przez system operacyjny. Szczegóły tych struktur nie muszą nas dotyczyć. Wszystko, co użytkownik musi zrobić, to po prostu utworzyć / pobrać uchwyt za pomocą wywołania API i przekazać go innym wywołaniom API przyjmującym ten typ uchwytu. Jedynym rodzajem używanego przez nas uchwytu byłHWND
zwrócony przez CreateWindowEx
. Stałe
W tym przykładzie napotkamy garść stałych, które są wielkimi literami i zaczynają się od 2 lub 3 literowego prefiksu. (Typy Windows są również pisane wielkimi literami)- IDI_APPLICATION: Nazwa zasobu zawierająca domyślną ikonę aplikacji. Jest on używany zarówno z
LoadIcon
lubLoadImage
(LoadIcon w tym przykładzie). - IDC_ARROW: Nazwa zasobu obejmująca domyślny kursor aplikacji. Jest on używany zarówno z
LoadIcon
lubLoadImage
(LoadIcon w tym przykładzie). - WHITE_BRUSH: nazwa obiektu podstawowego. Ten obiekt podstawowy to biały pędzel.
- MB_ICONERROR: Flaga używana z
MessageBox
do wyświetlania ikony błędu. - WS_EX_LEFT: Domyślny styl rozszerzonego okna. Powoduje to, że okno ma właściwości wyrównane do lewej.
- WS_OVERLAPPEDWINDOW: Styl okna wskazujący, że okno powinno być oknem nadrzędnym z paskiem tytułu, polem rozmiaru i innymi elementami typowymi dla okien najwyższego poziomu.
- CW_USEDEFAULT: Używany z argumentami
x
,y
,cx
lubcy
CreateWindowEx
. Powoduje, że system Windows wybiera prawidłową wartość argumentu, dla którego przekazanoCW_USEDEFAULT
.
Typy Windows
Podczas programowania w systemie Windows będziesz musiał przyzwyczaić się do typów Win32, które są aliasami dla typów wbudowanych. Te typy są wielkimi literami. Typy aliasów używane w tym programie to:- TCHAR: Ogólny typ znaków. Jeśli zdefiniowano
UNICODE
, jest towchar_t
. Otheriwse, tochar
. - UINT: Liczba całkowita bez znaku. Służy do reprezentowania identyfikatora wiadomości w procedurach okna i innych celach.
- WPARAM: W Win16 był to argument WORD (stąd przedrostek
W
). Jednak wraz z wprowadzeniem Win32 jest to terazUINT_PTR
. To ilustruje sens tych aliasów systemu Windows; służą ochronie programów przed zmianami. - LPARAM: To jest
LONG
argument (LONG_PTR
w Win64). - PTSTR:
P
oznacza wskaźnik.T
oznacza ogólny znak, aSTR
oznacza ciąg. Jest to zatem wskaźnik do ciąguTCHAR
. Inne typy ciągów obejmują:- LPTSTR: Taki sam jak
PTSTR
- LPCTSTR: Oznacza
const TCHAR *
- PCTSTR: Taki sam jak
LPCTSTR
- LPWSTR: Szeroki ciąg (
wchar_t *
) - LPCWSTR: Oznacza
const wchar_t *
- PWSTR: Taki sam jak
LPWSTR
- i wiele więcej Jak widać, typy Win32 mogą być trudne do zrozumienia, szczególnie w przypadku tak wielu typów synonimicznych, które są artefaktem Win16.
- LPTSTR: Taki sam jak
- LRESULT: Ten typ służy do reprezentowania wartości zwracanej przez procedury okna. Zwykle jest DŁUGI (stąd
L
).