Zoeken…


Een venster maken

#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);
}

Het eerste wat je ziet zijn de twee _UNICODE , UNICODE en _UNICODE . Deze macro's zorgen ervoor dat ons programma brede tekenreeksen ( wchar_t[n] ) begrijpt, geen gewone smalle tekenreeksen ( char[n] ). Als gevolg hiervan moeten alle tekenreeksliteralen worden ingepakt in een TEXT( macro. Het generieke TCHAR voor Win32-tekenreeksen is TCHAR , waarvan de definitie afhangt of UNICODE is gedefinieerd. Een nieuwe koptekst is opgenomen: <tchar.h> bevat de verklaring van TCHAR .

Een venster bestaat uit een zogenaamde vensterklasse . Dit beschrijft informatie over een venster dat moet worden gedeeld tussen instanties ervan, zoals het pictogram, de cursor en andere. Een vensterklasse wordt geïdentificeerd door een vensterklasse naam, die in dit voorbeeld wordt gegeven in de algemene variabele CLSNAME . De eerste handeling van WinMain is het invullen van de vensterklasse-structuur, WNDCLASSEX wc . De leden zijn:

  • cbSize: de grootte, in bytes, van de structuur
  • stijl: de stijlen van de vensterklasse. Dit is nu 0.
  • lpfnWndProc: Dit is een van de belangrijkste velden. Het slaat het adres van de vensterprocedure op . De vensterprocedure is een functie die gebeurtenissen afhandelt voor alle vensters die instanties zijn van deze vensterklasse.
  • cbClsExtra: het aantal extra bytes dat moet worden toegewezen voor de vensterklasse. Voor de meeste situaties is dit lid 0.
  • cbWndExtra: het aantal extra bytes dat moet worden toegewezen voor elk afzonderlijk venster. Verwar dit niet met cbClsExtra , wat in alle instanties gebruikelijk is. Dit is vaak 0.
  • hInstance: de exemplaarhandle. Wijs hInst argument WinMain in WinMain aan dit veld.
  • hIcon: de pictogramgreep voor de vensterklasse. LoadIcon(NULL, IDI_APPLICATION) laadt het standaard toepassingspictogram.
  • hCursor: de cursorhandgreep voor de vensterklasse. LoadCursor(NULL, IDC_ARROW) laadt de standaardcursor.
  • hbrBackground: een handvat voor het achtergrondpenseel. GetStockObject (WHITE_BRUSH) geeft een handvat aan een witte borstel. De retourwaarde moet worden gecast omdat GetStockObject een generiek object retourneert.
  • lpszMenuName: de bronnaam van de te gebruiken menubalk. Als er geen menubalk nodig is, kan dit veld NULL zijn.
  • lpszClassName: de klassenaam die deze structuur van de vensterklasse identificeert. In dit voorbeeld slaat de algemene variabele CLSNAME de naam van de vensterklasse op.
  • hIconSm: een handvat voor het pictogram van de kleine klasse.

Nadat deze structuur is geïnitialiseerd, wordt de functie RegisterClassEx aangeroepen. Hierdoor wordt de vensterklasse geregistreerd bij Windows, waardoor deze bekend wordt bij de toepassing. Het geeft 0 terug bij mislukking.

Nu de vensterklasse is geregistreerd, kunnen we het venster weergeven met CreateWindowEx . De argumenten zijn:

  • stylesex: de uitgebreide vensterstijlen. De standaardwaarde is WS_EX_LEFT.
  • clsname: de klassenaam
  • cap: de venstertitel of het bijschrift. In dit geval is het het bijschrift dat wordt weergegeven in de titelbalk van een venster.
  • stijlen: de vensterstijlen. Als u een hoofdvenster (bovenliggend) zoals deze wilt maken, is de vlag die moet worden doorgegeven WS_OVERLAPPEDWINDOW.
  • x: de x-coördinaat van de linkerbovenhoek van het venster.
  • y: de y-coördinaat van de linkerbovenhoek van het venster
  • cx: de breedte van het venster
  • cy: de hoogte van het venster
  • hwndParent: de greep naar het bovenliggende venster. Aangezien dit venster op zichzelf een bovenliggend venster is, is dit argument NULL.
  • hMenuOrID: Als het venster dat wordt gemaakt een bovenliggend venster is, is dit argument een handvat voor het venstermenu. Verwar dit niet met het klassenmenu, namelijk WNDCLASSEX::lpszClassName . Het klassenmenu is gemeenschappelijk voor alle exemplaren van vensters met dezelfde klassenaam. Dit argument is echter specifiek voor alleen deze instantie. Als het venster dat wordt gemaakt een onderliggend venster is, is dit de ID van het onderliggende venster. In dit geval maken we een bovenliggend venster zonder menu, dus wordt NULL doorgegeven.
  • hInst: de ingang van het exemplaar van de toepassing.
  • enz.: De extra informatie die wordt doorgegeven aan de vensterprocedure van het venster. Als u geen extra informatie wilt verzenden, geeft u NULL door.

Als x of y of cx of cy CW_USEDEFAULT , wordt de waarde van dat argument bepaald door Windows. Dat is wat er in dit voorbeeld wordt gedaan.

CreateWindowEx retourneert de handle naar het nieuw gemaakte venster. Als het maken van vensters is mislukt, is NULL geretourneerd.

We tonen het venster vervolgens door ShowWindow bellen. Het eerste argument voor deze functie is de greep naar het venster. Het tweede argument is de showstijl, die aangeeft hoe het venster moet worden weergegeven. De meeste toepassingen passeren gewoon het cmdshow argument dat is doorgegeven in WinMain . Nadat het venster is weergegeven, moet het worden bijgewerkt door een aanroep van UpdateWindow . Hierdoor wordt een updatebericht naar het venster verzonden. We zullen leren wat dit betekent in een andere zelfstudie.

Nu komt het hart van de applicatie: de berichtenpomp. Het pompt berichten verzonden naar deze toepassing door het besturingssysteem en verzendt de berichten naar de vensterprocedure. De GetMessage retourneert niet-nul totdat de toepassing berichten GetMessage waardoor deze wordt afgesloten, in welk geval deze 0 retourneert. Het enige argument dat ons bezighoudt, is de aanwijzer naar een MSG structuur die wordt ingevuld met informatie over het bericht. De andere argumenten zijn allemaal 0.

Binnen de berichtenlus vertaalt TranslateMessage berichten met virtuele sleutels naar berichten met tekens. De betekenis hiervan is wederom onbelangrijk voor ons. Het neemt een pointer naar een MSG structuur. De aanroep die er direct op volgt, DispatchMessage , verzendt het bericht waarnaar het argument verwijst, naar de vensterprocedure van het venster. Het laatste wat WinMain moet doen, is een statuscode retourneren. Het wParam lid van de MSG structuur bevat deze retourwaarde, dus wordt deze geretourneerd.

Maar dat is alleen voor de WinMain functie. De andere functie is winproc , de vensterprocedure. Het zal berichten voor het venster afhandelen die het door Windows worden verzonden. De handtekening voor winproc is:

  • hwnd: een ingang naar het venster waarvan de berichten worden verwerkt.
  • wm: de identificatie van het vensterbericht
  • wp: een van de berichtinformatieargumenten. Dit hangt af van het wm argument
  • lp: een van de berichtinformatieargumenten. Dit hangt af van het wm argument. Dit argument wordt meestal gebruikt om pointers of handvatten te verzenden

In dit eenvoudige programma verwerken we zelf geen berichten. Maar dat betekent niet dat Windows dat ook niet is. Dit is de reden waarom men DefWindowProc moet aanroepen, die de standaard afhandelingscode voor vensters bevat. Deze functie moet worden opgeroepen aan het einde van elke vensterprocedure.

Wat is een handvat?

Een handle is een gegevenstype dat een uniek object vertegenwoordigt. Het zijn verwijzingen, maar dan naar geheime datastructuren die door het besturingssysteem worden onderhouden. De details van deze structuren hoeven ons geen zorgen te maken. Het enige dat een gebruiker hoeft te doen, is eenvoudig een handle maken / terughalen met behulp van een API-aanroep en deze doorgeven aan andere API-aanroepen met dat type handle. Het enige type handvat we gebruikten was de HWND geretourneerd door CreateWindowEx .

constanten

In dit voorbeeld komen we een handvol constanten tegen, die allemaal in hoofdletters staan en beginnen met een voorvoegsel van 2 of 3 letters. (De Windows-typen staan ook in hoofdletters)

  • IDI_APPLICATION: de bronnaam die het standaardtoepassingspictogram bevat. Dit wordt gebruikt met LoadIcon of LoadImage (LoadIcon in dit voorbeeld).
  • IDC_ARROW: de bronnaam die de standaardcursor van de toepassing bevat. Dit wordt gebruikt met LoadIcon of LoadImage (LoadIcon in dit voorbeeld).
  • WHITE_BRUSH: de naam van een stockobject. Dit stockobject is de witte borstel.
  • MB_ICONERROR: een vlag die wordt gebruikt met MessageBox om een foutpictogram weer te geven.
  • WS_EX_LEFT: De standaard uitgebreide vensterstijl. Hierdoor heeft het venster links uitgelijnde eigenschappen.
  • WS_OVERLAPPEDWINDOW: Een vensterstijl die aangeeft dat het venster een bovenliggend venster moet zijn met een titelbalk, groottevak en andere elementen die typisch zijn voor vensters op het hoogste niveau.
  • CW_USEDEFAULT: Gebruikt met CreateWindowEx 's x , y , cx , of cy argumenten. CW_USEDEFAULT ervoor dat Windows een geldige waarde kiest voor het argument waarvoor CW_USEDEFAULT is doorgegeven.

Windows-typen

Bij het programmeren voor Windows moet je wennen aan de Win32-typen, aliassen voor ingebouwde typen. Deze types hebben allemaal hoofdletters. De alias-typen die in dit programma worden gebruikt, zijn:

  • TCHAR: het generieke karaktertype. Als UNICODE is gedefinieerd, is dit een wchar_t . Anders is het een char .
  • UINT: een geheel getal zonder teken. Wordt gebruikt om de berichtidentificatie weer te geven in vensterprocedures en andere doeleinden.
  • WPARAM: In Win16 was dit een WORD-argument (vandaar het W voorvoegsel). Met de introductie van Win32 is dit nu een UINT_PTR . Dit illustreert het punt van deze Windows-aliassen; ze zijn er om programma's tegen verandering te beschermen.
  • LPARAM: Dit is een LONG argument ( LONG_PTR in Win64).
  • PTSTR: De P betekent aanwijzer. De T betekent generiek teken en de STR betekent tekenreeks. Dit is dus een verwijzing naar een TCHAR tekenreeks. Andere stringtypen zijn onder meer:
    • LPTSTR: Hetzelfde als PTSTR
    • LPCTSTR: Betekent const TCHAR *
    • PCTSTR: Hetzelfde als LPCTSTR
    • LPWSTR: brede string ( wchar_t * )
    • LPCWSTR: betekent const wchar_t *
    • PWSTR: Hetzelfde als LPWSTR
    • en veel meer Zoals je kunt zien, kunnen de Win32-typen een probleem zijn om te begrijpen, vooral met zoveel synonieme typen, wat een artefact is van Win16.
  • LRESULT: Dit type wordt gebruikt om de retourwaarde van vensterprocedures weer te geven. Het is meestal een LANG (vandaar de L ).


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow