Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
I den här genomgången beskrivs hur du skapar ett traditionellt Windows-skrivbordsprogram i Visual Studio. Programmet du skapar använder Windows-API:et för att visa Hello, Windows Desktop! i ett fönster. Du kan använda koden som du utvecklar i den här genomgången som ett mönster för att skapa Windows-skrivbordsprogram.
Windows API (även kallat Win32 API, Windows Desktop API och Klassiskt Windows-API) är ett C-språkbaserat ramverk för att skapa Windows-program. Det har använts för att skapa Windows-program i årtionden. Mer avancerade och enklare programramverk har byggts ovanpå Windows-API:et, till exempel ramverken MFC, ATL och .NET. Även den modernaste Windows Runtime-koden för UWP- och Store-appar som skrivits i C++/WinRT använder Windows-API:et under. Mer information om Windows API finns i Windows API Index.
Viktigt!
Avsnittet Skapa koden i slutet av den här artikeln visar den fullständiga koden. Den här genomgången beskriver de olika koddelarna som går in i en Windows-app, men vissa detaljer utelämnas i kodfragmenten för att fokusera på de viktigaste delarna. Du kan kopiera den fullständiga koden och klistra in den i projektet i slutet.
Förutsättningar
Microsoft Windows 7 eller senare versioner. Vi rekommenderar Windows 11 eller senare för bästa möjliga utveckling.
Visual Studio. Information om hur du laddar ned och installerar Visual Studio finns i Installera Visual Studio. När du kör installationsprogrammet kontrollerar du att skrivbordsutvecklingen med C++ -arbetsbelastningen är markerad. Oroa dig inte om du inte installerade den här arbetsbelastningen när du installerade Visual Studio. Du kan köra installationsprogrammet igen och installera det nu.
En grundläggande förståelse för hur du använder Visual Studio IDE. Om du har använt Windows-skrivbordsappar tidigare kan du förmodligen hänga med. En introduktion finns i Visual Studio IDE-funktionsvisning.
Viss kunskap om C++-språket. Oroa dig inte, vi gör inget för komplicerat.
Skapa ett Windows-skrivbordsprojekt
Följ de här stegen för att skapa ditt första Windows-skrivbordsprojekt. Som vi noterade i början av den här artikeln är den färdiga koden tillgänglig i avsnittet Skapa koden i slutet av genomgången. Gå vidare och följ stegen för att skapa projektet, men vänta med att klistra in följande kodavsnitt till slutet, när den fullständiga programkoden visas. Vissa detaljer utelämnas i kodfragmenten för att fokusera på de viktigaste delarna. Du kan kopiera den fullständiga koden och klistra in den i projektet i slutet.
Om du vill se stegen för den önskade versionen av Visual Studio använder du versionsväljaren längst upp i innehållsförteckningen på den här sidan.
Skapa ett Windows-skrivbordsprojekt i Visual Studio
På huvudmenyn väljer du Arkiv>Nytt>projekt för att öppna dialogrutan Skapa ett nytt projekt .
Överst i dialogrutan anger du Språk till C++, anger Plattform till Windows och anger Projekttyp till Skrivbord.
I den filtrerade listan över projekttyper väljer du Guiden Windows Desktop och väljer sedan Nästa. På nästa sida anger du ett namn för projektet, till exempel DesktopApp.
Välj knappen Skapa för att skapa projektet.
Dialogrutan Windows Desktop-projekt visas nu. I listrutan Programtyp kontrollerar du att du väljer Skrivbordsprogram (.exe). Eftersom vi skapar ett Windows-program resulterar valet av konsolprogram i ett projekt som inte skapas med tanke på den kod som vi ska använda. Under Ytterligare alternativ väljer du Sedan Tomt projekt. Välj OK för att skapa projektet.
Högerklicka på Projektet DesktopApp i Solution Explorer, välj Lägg till och välj sedan Nytt objekt.
Animeringen visar hur du högerklickar på projektnamnet i Solution Explorer, väljer Lägg till i menyn som visas och väljer sedan Nytt objekt.
I dialogrutan Lägg till nytt objekt väljer du C++-fil (.cpp). I rutan Namn skriver du ett namn för filen,
HelloWindowsDesktop.cpp
till exempel . Välj Lägg till.
Projektet har nu skapats och källfilen öppnas i redigeraren.
Skapa ett Windows-skrivbordsprojekt i Visual Studio 2017
På Arkiv-menyn väljer du Nytt och sedan Projekt.
I dialogrutan Nytt projekt i den vänstra rutan expanderar du Installerat>visuellt C++-objekt och väljer sedan Windows Desktop. I den mellersta rutan väljer du Guiden Windows Desktop.
I rutan Namn skriver du ett namn för projektet, till exempel DesktopApp. Välj OK.
I dialogrutan Windows Desktop Project under Programtyp väljer du Windows-program (.exe). Under Ytterligare alternativ väljer du Tomt projekt. Kontrollera att förkompilerat huvud inte är markerat. Välj OK för att skapa projektet.
Högerklicka på Projektet DesktopApp i Solution Explorer, välj Lägg till och välj sedan Nytt objekt.
Animeringen visar hur du högerklickar på projektnamnet i Solution Explorer, väljer Lägg till i menyn som visades och väljer sedan Nytt objekt.
I dialogrutan Lägg till nytt objekt väljer du C++-fil (.cpp). I rutan Namn skriver du ett namn för filen,
HelloWindowsDesktop.cpp
till exempel . Välj Lägg till.
Projektet har nu skapats och källfilen öppnas i redigeraren.
Skapa ett Windows-skrivbordsprojekt i Visual Studio 2015
På Arkiv-menyn väljer du Nytt och sedan Projekt.
I dialogrutan Nytt projekt i den vänstra rutan expanderar du Installerade>mallar>Visual C++och väljer sedan Win32. I den mellersta rutan väljer du Win32-projekt.
I rutan Namn skriver du ett namn för projektet, till exempel DesktopApp. Välj OK.
På sidan Översikt i win32-programguiden väljer du Nästa.
På sidan Programinställningar går du till Programtyp och väljer Windows-program. Under Ytterligare alternativ avmarkerar du Förkompilerat huvud och väljer sedan Tomt projekt. Välj Slutför för att skapa projektet.
Högerklicka på Projektet DesktopApp i Solution Explorer, välj Lägg till och välj sedan Nytt objekt.
Animeringen visar hur du högerklickar på projektnamnet i Solution Explorer, väljer Lägg till i menyn som visas och väljer sedan Nytt objekt.
I dialogrutan Lägg till nytt objekt väljer du C++-fil (.cpp). I rutan Namn skriver du ett namn för filen,
HelloWindowsDesktop.cpp
till exempel . Välj Lägg till.
Projektet har nu skapats och källfilen öppnas i redigeraren.
Koden
Lär dig sedan hur du skapar koden för ett Windows-skrivbordsprogram i Visual Studio.
Där koden börjar köras i ett Windows-skrivbordsprogram
Precis som varje C-program och C++-program måste ha en
main
funktion som utgångspunkt måste varje Windows-skrivbordsprogram ha enWinMain
funktion.WinMain
har följande syntax.int WINAPI WinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow );
Information om parametrarna och returvärdet för den här funktionen finns i Startpunkt för WinMain.
Anmärkning
Vad är alla dessa extra ord, till exempel
WINAPI
, ellerCALLBACK
, ellerHINSTANCE
_In_
? Det traditionella Windows-API:et använder typedefs och makron för förprocessorer i stor utsträckning för att sammanfatta en del av informationen om typer och plattformsspecifik kod, till exempel anropa konventioner,__declspec
deklarationer och kompilator pragmas. I Visual Studio kan du använda funktionen IntelliSense Snabbinformation för att se vad dessa typedefs och makron definierar. Hovra musen över ordet av intresse, eller välj det och tryck på Ctrl+K, Ctrl+I för ett litet popup-fönster som innehåller definitionen. Mer information finns i Använda IntelliSense. Parametrar och returtyper använder ofta SAL-anteckningar för att fånga upp programmeringsfel. Mer information finns i Använda SAL-anteckningar för att minska C/C++-kodfel.Windows-skrivbordsprogram kräver
<windows.h>
. Du ser också ofta#include <tchar.h>
. Det gör det enklare att skriva en app som kan fungera med antingenchar
ellerwchar_t
. Så här fungerar det är att du istället använder makronTCHAR
i din kod, vilket i slutändan översätts tillwchar_t
om symbolenUNICODE
är definierad i ditt projekt, annars översätts det tillchar
. Om du alltid skapar med UNICODE aktiverat behöverTCHAR
du inte och kan bara användawchar_t
direkt. Mer information finns i Använda generiska textmappningar. Följande kod visar dessa två#include
instruktioner överst i filen.#include <windows.h> #include <tchar.h>
Tillsammans med
WinMain
funktionen måste alla Windows-skrivbordsprogram också ha en funktion för fönsterprocedurer. Den här funktionen kallas för ,WndProc
men du kan ge den vilket namn du vill i koden.WndProc
har följande syntax.LRESULT CALLBACK WndProc( _In_ HWND hWnd, _In_ UINT message, _In_ WPARAM wParam, _In_ LPARAM lParam );
I den här funktionen skriver du kod för att hantera meddelanden som programmet tar emot från Windows när händelser inträffar. Om en användare till exempel väljer en OK-knapp i ditt program skickar Windows ett meddelande till dig. Du skriver kod i en
WndProc
funktion som utför det arbete som är lämpligt. Det kallas att hantera en händelse. Du hanterar bara de händelser som är relevanta för ditt program.Mer information finns i Fönsterprocedurer.
Lägga till funktioner i WinMain
funktionen
WinMain
I funktionen måste du samla in grundläggande information om huvudfönstret. Det gör du genom att fylla i en struktur av typenWNDCLASSEX
. Strukturen innehåller information om fönstret, till exempel programikonen, fönstrets bakgrundsfärg, namnet som ska visas i namnlisten, bland annat. Det är viktigt att den innehåller en funktionspekare till fönsterproceduren som hanterar de meddelanden som Windows skickar till din app. I följande exempel visas en typiskWNDCLASSEX
struktur:WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(wcex.hInstance, IDI_APPLICATION); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = NULL; wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION);
Information om fälten i den här strukturen finns i
WNDCLASSEX
.När du har fyllt i
WNDCLASSEX
strukturen registrerar du den med Windows så att den vet om ditt fönster och hur du skickar meddelanden till den.RegisterClassEx
Använd funktionen och skicka fönstrets klassstruktur som argument. Makrot_T
används eftersom vi använderTCHAR
typen enligt föregående diskussion om Unicode. Följande kod visar hur du registrerar fönsterklassen.if (!RegisterClassEx(&wcex)) { MessageBox(NULL, _T("Call to RegisterClassEx failed!"), _T("Windows Desktop Guided Tour"), NULL); return 1; }
Skapa ett fönster med hjälp av
CreateWindowEx
funktionen .static TCHAR szWindowClass[] = _T("DesktopApp"); static TCHAR szTitle[] = _T("Windows Desktop Guided Tour Application"); // The parameters to CreateWindowEx explained: // WS_EX_OVERLAPPEDWINDOW : An optional extended window style. // szWindowClass: the name of the application // szTitle: the text that appears in the title bar // WS_OVERLAPPEDWINDOW: the type of window to create // CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y) // 500, 100: initial size (width, length) // NULL: the parent of this window // NULL: this application does not have a menu bar // hInstance: the first parameter from WinMain // NULL: not used in this application HWND hWnd = CreateWindowEx( WS_EX_OVERLAPPEDWINDOW, szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 100, NULL, NULL, hInstance, NULL ); if (!hWnd) { MessageBox(NULL, _T("Call to CreateWindowEx failed!"), _T("Windows Desktop Guided Tour"), NULL); return 1; }
Den här funktionen returnerar en
HWND
, som är ett handtag till ett fönster. Ett handtag liknar en pekare. Windows använder den för att hålla reda på de fönster som du skapar. Mer information finns i Windows-datatyper.Nu har fönstret skapats, men vi måste ändå be Windows att göra det synligt. Det är vad den här koden gör:
// The parameters to ShowWindow explained: // hWnd: the value returned from CreateWindow // nCmdShow: the fourth parameter from WinMain ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd);
Det visade fönstret är bara en tom rektangel eftersom du ännu inte har implementerat
WndProc
funktionen. Programmet hanterar ännu inte de meddelanden som Windows nu skickar till det.För att hantera meddelandena lägger vi först till det som kallas en meddelandeloop för att lyssna efter de meddelanden som Windows skickar. När programmet tar emot ett meddelande skickar den här loopen den till din
WndProc
funktion som ska hanteras. Meddelandeloopen liknar följande kod:MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int) msg.wParam;
Mer information om strukturerna och funktionerna i meddelandeloopen
MSG
finns i , ,GetMessage
TranslateMessage ochDispatchMessage
.En grundläggande
WinMain
funktion som skapar programmets huvudfönster och lyssnar efter meddelanden som Windows skickar din app skulle likna följande kod:int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(wcex.hInstance, IDI_APPLICATION); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = NULL; wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION); if (!RegisterClassEx(&wcex)) { MessageBox(NULL, _T("Call to RegisterClassEx failed!"), _T("Windows Desktop Guided Tour"), NULL); return 1; } // Store instance handle in our global variable hInst = hInstance; // The parameters to CreateWindowEx explained: // WS_EX_OVERLAPPEDWINDOW : An optional extended window style. // szWindowClass: the name of the application // szTitle: the text that appears in the title bar // WS_OVERLAPPEDWINDOW: the type of window to create // CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y) // 500, 100: initial size (width, length) // NULL: the parent of this window // NULL: this application dows not have a menu bar // hInstance: the first parameter from WinMain // NULL: not used in this application HWND hWnd = CreateWindowEx( WS_EX_OVERLAPPEDWINDOW, szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 100, NULL, NULL, hInstance, NULL ); if (!hWnd) { MessageBox(NULL, _T("Call to CreateWindow failed!"), _T("Windows Desktop Guided Tour"), NULL); return 1; } // The parameters to ShowWindow explained: // hWnd: the value returned from CreateWindow // nCmdShow: the fourth parameter from WinMain ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); // Main message loop: MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int) msg.wParam; }
Hantera meddelanden i WndProc
funktionen
Om du vill hantera meddelanden som programmet tar emot implementerar du en
switch
instruktion i dinWndProc
funktion.Ett viktigt meddelande att hantera är
WM_PAINT
. Programmet får ettWM_PAINT
meddelande när en del av det visade fönstret måste uppdateras. Händelsen kan inträffa när en användare flyttar ett fönster framför fönstret och flyttar bort det igen. Det tar emot det här meddelandet första gången ditt fönster visas, vilket ger dig en chans att visa ditt programgränssnitt. Ditt program får reda på dessa händelser när Windows skickar dem. När fönstret först visas måste allt uppdateras.Om du vill hantera ett
WM_PAINT
meddelande anroparBeginPaint
du först och hanterar sedan all logik för att lägga ut text, knappar och andra kontroller i fönstret. Anropa sedanEndPaint
. För den här applikationen visar koden mellanBeginPaint()
ochEndPaint()
Hello, Windows desktop!
i fönstret som du skapade iWinMain()
. I följande kodTextOut
visar funktionen texten på den angivna platsen i fönstret.PAINTSTRUCT ps; HDC hdc; TCHAR greeting[] = _T("Hello, Windows desktop!"); switch (message) { case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // Here your application is laid out. // For this introduction, we just print out "Hello, Windows desktop!" // in the top left corner. TextOut(hdc, 5, 5, greeting, _tcslen(greeting)); // End application-specific layout section. EndPaint(hWnd, &ps); break; }
I föregående kod
HDC
är en referens till en enhetskontext som är associerad med fönstrets klientområde. Du använder den när du ritar i fönstret för att referera till dess klientområde. AnvändBeginPaint
ochEndPaint
funktionerna för att förbereda och slutföra ritningen i klientområdet.BeginPaint
returnerar ett handtag till visningsenhetens kontext som används för ritning i klientområdet.EndPaint
avslutar färgbegäran och släpper enhetskontexten.Ett program hanterar vanligtvis många andra meddelanden. Till exempel
WM_CREATE
skickas när ett fönster först skapas ochWM_DESTROY
när fönstret stängs. Följande kod visar en grundläggande men fullständigWndProc
funktion:LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HDC hdc; TCHAR greeting[] = _T("Hello, Windows desktop!"); switch (message) { case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // Here your application is laid out. // For this introduction, we just print out "Hello, Windows desktop!" // in the top left corner. TextOut(hdc, 5, 5, greeting, _tcslen(greeting)); // End application specific layout section. EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); break; } return 0; }
Skapa koden
Som utlovat följer den fullständiga koden för arbetsprogrammet.
Skapa det här exemplet
Ta bort all kod i
HelloWindowsDesktop.cpp
redigeraren. Kopiera den här exempelkoden och klistra in den iHelloWindowsDesktop.cpp
:// HelloWindowsDesktop.cpp // compile with: /D_UNICODE /DUNICODE /DWIN32 /D_WINDOWS /c #include <windows.h> #include <stdlib.h> #include <string.h> #include <tchar.h> // Global variables // The main window class name. static TCHAR szWindowClass[] = _T("DesktopApp"); // The string that appears in the application's title bar. static TCHAR szTitle[] = _T("Windows Desktop Guided Tour Application"); // Stored instance handle for use in Win32 API calls such as FindResource HINSTANCE hInst; // Forward declarations of functions included in this code module: LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow ) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(wcex.hInstance, IDI_APPLICATION); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = NULL; wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION); if (!RegisterClassEx(&wcex)) { MessageBox(NULL, _T("Call to RegisterClassEx failed!"), _T("Windows Desktop Guided Tour"), NULL); return 1; } // Store instance handle in our global variable hInst = hInstance; // The parameters to CreateWindowEx explained: // WS_EX_OVERLAPPEDWINDOW : An optional extended window style. // szWindowClass: the name of the application // szTitle: the text that appears in the title bar // WS_OVERLAPPEDWINDOW: the type of window to create // CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y) // 500, 100: initial size (width, length) // NULL: the parent of this window // NULL: this application does not have a menu bar // hInstance: the first parameter from WinMain // NULL: not used in this application HWND hWnd = CreateWindowEx( WS_EX_OVERLAPPEDWINDOW, szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 100, NULL, NULL, hInstance, NULL ); if (!hWnd) { MessageBox(NULL, _T("Call to CreateWindow failed!"), _T("Windows Desktop Guided Tour"), NULL); return 1; } // The parameters to ShowWindow explained: // hWnd: the value returned from CreateWindow // nCmdShow: the fourth parameter from WinMain ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); // Main message loop: MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int) msg.wParam; } // FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM) // // PURPOSE: Processes messages for the main window. // // WM_PAINT - Paint the main window // WM_DESTROY - post a quit message and return LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HDC hdc; TCHAR greeting[] = _T("Hello, Windows desktop!"); switch (message) { case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // Here your application is laid out. // For this introduction, we just print out "Hello, Windows desktop!" // in the top left corner. TextOut(hdc, 5, 5, greeting, _tcslen(greeting)); // End application-specific layout section. EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); break; } return 0; }
På menyn Skapa väljer du Skapa lösning. Resultatet av kompilering visas i utdatafönstret i Visual Studio.
Animeringen visar hur du klickar på knappen Spara alla och sedan väljer Skapa > Bygg lösning på Huvudmenyn.
Tryck på F5 för att köra programmet. Ett fönster med texten
Hello, Windows desktop!
ska visas.
Grattis! Du har skapat ett traditionellt Windows-skrivbordsprogram.