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 w WinMain 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 lub LoadImage (LoadIcon w tym przykładzie).
  • IDC_ARROW: Nazwa zasobu obejmująca domyślny kursor aplikacji. Jest on używany zarówno z LoadIcon lub LoadImage (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 lub cy CreateWindowEx . Powoduje, że system Windows wybiera prawidłową wartość argumentu, dla którego przekazano CW_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 to wchar_t . Otheriwse, to char .
  • 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 teraz UINT_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, a STR oznacza ciąg. Jest to zatem wskaźnik do ciągu TCHAR . 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.
  • LRESULT: Ten typ służy do reprezentowania wartości zwracanej przez procedury okna. Zwykle jest DŁUGI (stąd L ).


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow