32
Tags:
c++
Skrevet af
Bruger #7461
@ 23.10.2006
Jeg vil i denne artikel fortælle om Windows api'et som bruges til at lave Windows programmer med. Så kan du noget grundlæggende c/c++ programmering og har du lyst til at lave ”rigtige” programmer i stedet for konsol programmer, så er denne artikel noget for dig. Jeg vil prøve at forklare alt ting så godt jeg kan, skulle der være noget du ikke forstår er du meget velkommen til at spørge.
Hvad er windows api'etWindows api’et er udviklet af Microsoft og gør det muligt at lave windows programmer, api’et er lavet så du ved hjælp af c/c++ kan kode dine egne windows programmer. I api’et er der en masse funktioner du kan kalde som kan udføre forskellige ting, såsom tilføje knapper til dit vindue, vise grafik og meget mere. Windows api’et kaldes også win32 api.
Lad os komme i gang med at lære noget om det at lave windows programmer. Det første vi vil lave er et meget simpelt program som faktisk blot er et popup vindue. For at lave windows programmer skal du have en compiler der understøtter win api’et, det gør det fleste c/c++ compiler i dag. Nå men lad os komme i gang.
Eksempel 1
#include "windows.h"
int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nShow)
{
MessageBox(NULL, "Velkommen til windows api'et", "Windows api", NULL);
}
Okay dette er koden der laver en simpel popup, lad os gå koden igennem fra en ende af for at forstå den.
#include ”windows.h” Det er i denne fil alle windows apiet’s funktioner er defineret, så vi skal include denne fil for at få mulighed for at bruge api’et.
Int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nShow)
Dette er vores main funktion ligesom int main(int argc, char ** argv) er det i et konsol program. Man behøves ikke at koncentrer sig så meget om hvad de forskellige ting i denne main funktion betyder, men her kommer det alligevel.
hInst er handleren til vores program som er læst ind i hukomelsen. hPrev bruges ikke i win32 programmer og vi skal derfor ikke tænke på den. lpCmd indeholder komando lines argumenter, hvis der er nogen. nShow bruges til at beskrive på hvilken måde vi vil vise vores program, så den kommer vi til senere når vi skal til at lave et vindue.
MessageBox(NULL, "Velkommen til windows api'et", "Windows api", NULL);
MessageBox() er en forud defineret funktion i Windows api’et og bruges til at lave en popup med.
Funktionen er defineret sådan her
int MessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);
hWnd er handleren til vores vindue hvor vi vil lave popup’en, den er sat til NULL her da vi ikke har lavet noget vindue endnu. lpText er teksten der skal stå i popup’en. lpCaption er overskriften på popup’en. uType bruges til af beskrive hvordan popup’en skal se ud, det her man bestemmer hvilke knapper man vil have og sådan noget, nedenfor ses en samling af typer man kan bruge. Man kan sammen sætte flere ved at bruge | eks. MB_OK | MB_ICONSTOP.
Liste over knapper
MB_OK - Der bliver vist en ok knap, dette er den der bliver brugt som standart.
MB_OKCANCEL - Der bliver vist en ok og en annuller knap.
MB_RETRYCANCEL - Der bliver vist en forsøg igen og en anuller knap.
MB_YESNO - Der bliver vist en ja og en nej knap.
MB_YESNOCANCEL - Der bliver vist en ja, nej og en annuller knap
MB_ABORTRETRYIGNORE - Der bliver vist en afbryd, forsøg igen og en ignorer knap.
Liste over ikoner
MB_ICONWARNING - Der bliver vist et ikon med udråbstegn.
MB_ICONINFORMATION - Der bliver vist et ikon med et informationstegn.
MB_ICONQUESTION - Der bliver vist et ikon med et spørgsmålstegn.
MB_ICONSTOP - Der bliver vist et ikon med et stoptegn.
Det var en masse forklaring, jeg håber du forstod det meste af det. Du har nu prøvet at lave dit første Windows program. Det vil være en god ide hvis du prøver at lege lidt med det inden du går videre så du har forstået det hele. Du kan lege lidt med at udskifte teksten, tilføje forskellige knapper og ikoner.
Nu vil vi gå videre og lære hvordan vi laver et rigtigt vindue, det er meget svært at komme i gang med da det kræver mange liners kode bare for at lave et vindue. Jeg vil først vise jer hele koden til at lave et vindue og vil derefter beskrive koden. Jeg har også lavet nogle kommentarer i koden du kan læse mens du læser koden igennem, så du har lettere ved at forstå koden. Det vil nok være en god ide at læse koden igennem et par gange så du bedre forstår hvad det er vi gør.
#include <windows.h>
LRESULT CALLBACK MainWndProc (HWND hwnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
switch (nMsg)
{
case WM_CREATE:
{
/* vores vindue er blevet lavet, det er her vi skal have alt det der skal ske når vores vindue
er oprettet*/
}
break;
case WM_DESTROY:
/* vinduet bliver lukket, de andre ting forsvinder automatisk*/
PostQuitMessage (0);
break;
}
return DefWindowProc (hwnd, nMsg, wParam, lParam);
}
int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nShow)
{
WNDCLASSEX wndclass;
/* Vores vindues class, vi skal bruge sådan en for at lave et vindue */
char*szMainWndClass = "winapi2";
/* Dette er navnet på vores class */
/* For at lave et vindue skal vi først lave vores vindues class. */
/* Vi nulstiller classen */
memset (&wndclass, 0, sizeof(WNDCLASSEX));
/* Vi giver classen det navn som vi har bestemt */
wndclass.lpszClassName = szMainWndClass;
/* Vi indstiller støreslsen på classen */
wndclass.cbSize = sizeof(WNDCLASSEX);
/* Vi fortæller classen at vinduet skal opdateres, hvis vi ændre størelsen på det */
wndclass.style = CS_HREDRAW | CS_VREDRAW;
/* Vi fortæller den hvilken funktion alt skal sendes til. */
wndclass.lpfnWndProc = MainWndProc;
/* Dette er "handleren" til vores program */
wndclass.hInstance = hInst;
/* Her bestemmer vi om der skal være noget icon til vores program, og hvilken cursor vi vil bruge. */
wndclass.hIcon = LoadIcon(NULL, NULL);
wndclass.hIconSm = LoadIcon(NULL, NULL);
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
/* Vi bestemmer baggruden skal være hvid*/
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
/* Vi registre classen så vi kan bruge den til at lave et vindue med */
RegisterClassEx (&wndclass);
MSG msg;/* Vores msg variable kommer til at indeholder alle beskeder der bliver sendt til vinduet. */
HWND hwndMain; /* Dette er handleren vil vores vindue */
hwndMain = CreateWindow (
szMainWndClass,/* classens navn */
"Windows api",/* titlen på vinduet */
WS_OVERLAPPEDWINDOW,/* Stylen på vinduet */
0,/* Vinduet's start position (x) */
0,/* Vinduet's start position (y) */
500,/* Bredden på vinduet */
600,/* højden på vinduet */
NULL,/* Ikke nogen ejer til vindue */
NULL,/* ingen menu */
hInst,/* Handleren til programmet. */
NULL/* oprettelses parameter */
);
ShowWindow (hwndMain, nShow); /* vi fortæller programmet det skal vise vinduet (vi bruger nShow) */
UpdateWindow (hwndMain); /* fortæller programmet det skal opdatere vinduet */
/* det der sker her er at alle beskeder der bliver sendt til programmet, bliver sendt videre så vi kan se hvad der sker i programmet */
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
return msg.wParam;
}
Det var en masse kode på en gang, men der kræves så meget kode for at lave et vindue. Jeg håber du forstod lidt af koden, og hvad det var vi gjorde. Vi skal nu kigge lidt på koden så vi er helt med på hvad det er der sker.
LRESULT CALLBACK MainWndProc (HWND hwnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
Er vores “tilbage kalds funktion” det er er alle informationer om hvad der sker I programmet og hvad folk gør I programmet bliver sendt til. Det er i denne funktion vi skal have det meste af vores kode, når vi skal til at lave noget i vores vindue. Hwnd er handleren til vinduet, nMsg indeholder beskederne som bliver sendt til programmet, wParam og lParam kan indeholde forskellige information alt efter hvilken besked der bliver sendt.
switch (nMsg)
{
case WM_CREATE:
{
/* vores vindue er blevet lavet, det er her vi skal have alt det der skal ske når vores vindue
er oprettet*/
}
break;
case WM_DESTROY:
/* vinduet bliver lukket, de andre ting forsvinder automatisk*/
PostQuitMessage (0);
break;
}
Det næste der kommer er en switch som bruges til at ”skifte” mellem de forskellige beskeder. Der er forskellige cases. WM_CREATE bliver sendt når vores vindue er blevet oprettet, så her kan vi gøre alle de ting vi vil have gjord når vores vindue er oprettet. WM_DESTROY bliver sendt når programmet bliver lukket, så det er her man gør de ting der skal ske når programmet skal lukkes ned.
int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nShow)
Nu kommer vores main funktion igen som er beskrevet i første eksempel.
/* Vores vindues class, vi skal bruge sådan en for at lave et vindue */
WNDCLASSEX wndclass;
/* Dette er navnet på vores class */
char*szMainWndClass = "winapi2";
/* For at lave et vindue skal vi først lave vores vindues class. */
/* Vi nulstiller classen */
memset (&wndclass, 0, sizeof(WNDCLASSEX));
/* Vi giver classen det navn som vi har bestemt */
wndclass.lpszClassName = szMainWndClass;
/* Vi indstiller støreslsen på classen */
wndclass.cbSize = sizeof(WNDCLASSEX);
/* Vi fortæller classen at vinduet skal opdateres, hvis vi ændre størelsen på det */
wndclass.style = CS_HREDRAW | CS_VREDRAW;
/* Vi fortæller den hvilken funktion alt skal sendes til. */
wndclass.lpfnWndProc = MainWndProc;
/* Dette er "handleren" til vores program */
wndclass.hInstance = hInst;
/* Her bestemmer vi om der skal være noget icon til vores program, og hvilken cursor vi vil bruge. */
wndclass.hIcon = LoadIcon(NULL, NULL);
wndclass.hIconSm = LoadIcon(NULL, NULL);
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
/* Vi bestemmer baggruden skal være hvid*/
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
/* Vi registre classen så vi kan bruge den til at lave et vindue med */
RegisterClassEx (&wndclass);
Det næste vi gør er at vi lave en vindues class som skal bruges til at indeholde information om hvordan vi vil have vores vindue til at se ud. Kommentarerne i koden fortæller hvad de forskellige ting er.
hwndMain = CreateWindow (
szMainWndClass,/* classens navn */
"Windows api",/* titlen på vinduet */
WS_OVERLAPPEDWINDOW,/* Stylen på vinduet */
0,/* Vinduet's start position (x) */
0,/* Vinduet's start position (y) */
500,/* Bredden på vinduet */
600,/* højden på vinduet */
NULL,/* Ikke nogen ejer til vindue */
NULL,/* ingen menu */
hInst,/* Handleren til programmet. */
NULL/* oprettelses parameter */
);
ShowWindow (hwndMain, nShow); /* vi fortæller programmet det skal vise vinduet (vi bruger nShow) */
UpdateWindow (hwndMain); /* fortæller programmet det skal opdatere vinduet */
Det der sker her er at vi laver vores vindue, med funktion CreateWindow(). Læg mærke til at vi bruger vores vindues class som vi lige har lavet. Det er også her vi bestemmer hvad vinduet skal hedde, og hvordan det skal se ud ved hjælp af styles. Stylen WS_OVERLAPPEDWINDOW laver et et normalt vindue med en luk, minimer og maksimer knap. Der ud over bestemmer vi hvor vores vindue skal være på skærmen og hvor stort det skal være. Positionen og størrelsen på vinduet er angivet i pixel, og bliver angivet ud fra et koordinat system som har 0,0 i toppen af højre hjørne.
Det sidste vi gør af at fortælle den skal vise vinduet og opdatere det.
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
return msg.wParam;
Det allersidste vi har i vores program er en while funktion som modtager alle meddelser som bliver sendt til programmet, ”oversætter” dem og sender dem videre til vores tilbagekalds funktion.
Tillykke du har nu lært at lave et windoes program, hvis du har fået koden til at virke skulle du gerne have et vindue uden noget i
Hvis koden ikke virker så check at du har skrevet alt rigtigt, du kunne måske prøve at kopiere hele koden over og se om det virker. Gør det ikke er det måske fordi din kompiler ikke ved at at du laver et windows program, hvis din kompiler spørger dig om hvilken slags projekt du vil lave skal du vælge et win 32 projekt.
Jeg håber du har lært noget af denne artikel, jeg ved godt at vi ikke fik lært noget om hvad man kan gøre når man har lavet vinduet, men da det er meget besværligt at komme i gang med har jeg valgt bare at beskrive hvordan man laver vinudet. Jeg vil i næste artikel beskrive noget om hvordan man kan komme i gang med at lave nogle ting. Jeg håber du nød at læse artiklen og lærte noget har du nogle spørgsmål er du meget velkommen til at stille dem som en kommentar og jeg skal gøre mit bedste for at svare.
Så har jeg ikke så meget andet at sige end vi ses i artikel nummer 2
Hvad synes du om denne artikel? Giv din mening til kende ved at stemme via pilene til venstre og/eller lægge en kommentar herunder.
Del også gerne artiklen med dine Facebook venner:
Kommentarer (31)
Glæder mig til næste nummer.
god artikel men får fejl når jeg compiler:
C:\\DOCUME~1\\sope08\\LOKALE~1\\Temp\\ccyqaaaa.o(.text+0xe8) In function `WinMain':
[Linker error] undefined reference to `GetStockObject@4'
C:\\DOCUME~1\\sope08\\LOKALE~1\\Temp\\ccyqaaaa.o(.text+0xe8) ld returned 1 exit status
kan ikke rigtig finde ud af hvad det er der er galt.? bruger dev-c++ med den originale compiler og har kopieret koden.
Hey Jørn
Jeg arbejder på den men får ikke lavet så meget fordi jeg har lidt travlt for tiden, men jeg lover den kommer engang inden nytår
Hey Smurf
Det er fordi når du laver et ny projekt skal du vælge at du vil lave en windows application og ikke en Console application. Hvis du gør det skulle det virke.
Mvh.
Søren
Jeg kiggede hurtigt på siste side, gad ikke lige kigge på dem alle, men jeg har endelig fået en brændende lyst for at gå i gang med at programmere C++!
Hold kæft jeg er dum, så skriver jeg til den forkerte artikel... Men det er bare dit held du så fik et 5-tal af mig
Generelt en god artikel.. men;
"hPrev bruges ikke i win32 programmer og vi skal derfor ikke tænke på den." - Lidt overfladisk skrevet, da du dog har inkluderet det i koden?
Kan nogen fortælle mig hvorfor, at jeg bilder mig selv ind, at have læst, at koordinaterne IKKE er angivet efter pixels, men efter skiftstørrelse osv.? - Hvilket passer?
"et koordinat system som har 0,0 i toppen af højre hjørne." - Ikke venstre (som ville være mest logisk)?
Jeg vil nu mene, at lidt indrykning i koden, samt kommentarer i selve koden, efter koden (ikke over eller under) ville give et bedre overblik over kodeeksemplerne.
Tak.
Pixel-spørgsmålet fandt jeg selv svar på.
Jeg havde læst en sektion om dialogs og dialog-units. - Fik blandet det hele grundigt sammen
Kender jeg alt for godt, Steffen
God artikel, giver en lyst til hoppe stille videre fra Consol
hvorhenne på computeren finder man filen win32 api???
Jeg synes du mangler at forklare en masse ting. Hvorfor skal nogle funktioner være af typen LRESULT, og hvor skal de kunne bruges som CALLBACK? Og hvad med MB_ICONEXCLAMATIN - den mangler du?
/* Vi nulstiller classen */
memset (&wndclass, 0, sizeof(WNDCLASSEX));
Jeg vil gerne vide hvorfor.
/* Vi registre classen så vi kan bruge den til at lave et vindue med */
RegisterClassEx (&wndclass);
Hvorfor _SKAL_ et vindue registreres?
Og jeg kunne blive ved
Jeg mente:
og hvorfor skal de kunne bruges som CALLBACK?
...og...
Jeg mente: MB_ICONEXCLAMATION
AWESOME!!! denne kode virker og er god til C++ nybegynder (Som mig)
5 POINT TIL DIG
AWESOME!!! denne kode virker og er god til C++ nybegynder (Som mig)
5 POINT TIL DIG
Haha jeg ved ikke om den kommentar var tiltænkt mig, men jeg synes nu den er meget sjovt. Jeg synes det er meget fedt Lorita er blevet intresseret i mig, ved at kigge i min profil(hun kan nok ikke læse den, da den er dansk) og jeg har ikke rigtigt nogle billeder af mig der
Det er nu lidt sjovt med lidt spam engang imellem
Anyways thanks Lorita
Din Lorita er dig vist utro, jeg har set hende andre steder på sitet med samme kommentar
Super artikel, lige hvad jeg manglede.
Er der evt. en der har kildekoden til et program der indeholde diverse funktioner så jeg har noget jeg kan leget med indtil næste artikel kommer?
UINT ikke UNIT ...
Tak for fire herlige timers debugging
Men bortset fra
min lille fejl, var artiklen meget tæt på perfekt!
Simon Larsen > Hvad tænker du præcis på? For jeg kan muligvis lave noget til dig.
Til alle jer der synes koden ser uoverskuelig ud:
Lær den udenad i bidder!!!
det har jeg gjordt og jeg kan nu!
det tog mig kun 2 timer... (Kun og kun..
)
anyways 5 herfra for en fantastisk artikel (hvornår kommer 2'eren???)
Godt lavet
er det bare mig eller er der aldrig kommet en nr. 2? please
for en fejl her:
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
bruger den compiler der kommer med codeblocks, tror den heder noget med gnu.
den skriver:
undefined reference to ´_GetStockObject@4'
har prøvet at slette linien, så fungere det bortset fra at windows vist ikke er så glad for gennemsigtige bagrunde.
eller heder den mingw... ved ikk
sry for dobbelt post
kørte det i dev c++, der virkede det...
Hej. Jeg har lige et spørgsmål hvor jeg er gået i stå.
uType bruges til af beskrive hvordan popup’en skal se ud, det her man bestemmer hvilke knapper man vil have og sådan noget, nedenfor ses en samling af typer man kan bruge. Man kan sammen sætte flere ved at bruge | eks. MB_OK | MB_ICONSTOP.
Min kode ser sådan her ud indtil nu:
#include "windows.h"
int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nShow)
{
MessageBox(NULL, "Velkommen til windows api'et", "Windows api", NULL);
int MessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);
}
Hvor skal jeg sætte MB_OKCANCEL eller nogen af de andre koder henne? Jeg har prøvet mig frem ved at slette uType, ved at sætte MB_OKCANCEL efter uType osv. osv. men jeg kan ikke finde ud af hvor jeg skal sætte det. Nogen der kan hjælpe mig?
Jeg er nybegynder så håber I kan bære over med mig stupidhed
- Cosinus.
Hej Cosinus
De skal indsættes på uType's plads. Der hvor jeg i eksemplet har skrevet NULL. Sådan her:
MessageBox(NULL, "Velkommen til windows api'et", "Windows api", MB_OKCANCEL);
Og hvis du ønsker at sætte flere ind så skal der en | imellem dem, sådan her:
MessageBox(NULL, "Velkommen til windows api'et", "Windows api", MB_OKCANCEL | MB_ICONSTOP);
Så den rigtige kode ser sådan her ud:
#include "windows.h"
int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nShow)
{
MessageBox(NULL, "Velkommen til windows api'et", "Windows api", MB_OKCANCEL);
}
- Sieg
Når jeg compiler din kode i visual c++ får jeg fejlen:
1>------ Build started: Project: Popup vindue, Configuration: Debug Win32 ------
1>Compiling...
1>Popup vindue.cpp
1>f:\c++ programmer\c++\popup vindue\popup vindue\popup vindue.cpp(5) : error C2664: 'MessageBoxW' : cannot convert parameter 2 from 'const char [29]' to 'LPCWSTR'
1> Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
1>Build log was saved at "file://f:\c++ programmer\c++\Popup vindue\Popup vindue\Debug\BuildLog.htm"
1>Popup vindue - 1 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Hvordan kan det være?
Ej nej nej, og han skriver ikke engang, hvor man kan downloade API'et, hvis det ikke følger med ens compiler. Jesus.
Du skal linke med gdi32.lib for at benytte GetStockObject
Super god artikel! Det vigtigste er forklaret, og koden er forståelig!
God forklaring over det hele. Godt at du har tilføjet kommentarer i koden.
øv dig i at lave indryk.
Jeg glæder mig meget til, at du kommer med 2. del af den her artikel!
svar til Christian:
visual c++ er et edit- og compilerprogram, der er udviklet af windows, og har en masse forskellige funktioner, der tjekker koden på forhånd. Desværre har denne compiler også et indbygget register over hvordan tingene skal stå, uafhængigt af compilerens forståen af c++sproget! Så selvom du vælger at du vil lave en win32-applikation, er der mange ting, som dette program ikke forstår.
tag i stedet at downloade CodeBlocks! opret nyt projekt og vælg at lave et "win32 GUI projekt". Compileren i CodeBlocks er meget hurtigere og editoren er nøjagtig lige så go'!
hent den her:
http://www.codeblocks.org/downloads
Steffen: det skyldes altså at han befinder sig på et UNICODE-system. Smid alle dine strenge i TEXT-makroen, så bliver problemet løst. Altså
MessageBox(hwnd, TEXT("besked"), TEXT("overskrift"), MB_OK);
Du skal være
logget ind for at skrive en kommentar.