建立 Win32 應用程式 (C++)
更新:2007 年 11 月
Win32 API (又稱為 Windows API) 是建立 Windows 應用程式的 C 架構,而且從 Windows 1.0 開始就已經存在。在 Windows API 中可以找到此 API 的大量文件。
在本程序中,我們會建立在視窗顯示 "Hello, World!" 的簡單 Win32 應用程式。對於所有的 Win32 應用程式,程序步驟都是相同的。在完成本程序之後,即可使用在此處建立的程式碼,做為建立其他 Win32 應用程式的基本架構。
必要條件
本主題假設您已了解 C++ 語言的基礎。如果您才剛開始學習 C++,建議您參考 Herb Schildt 所著的《C++ Beginner's Guide》。您可以在 https://www.microsoft.com/taiwan/vstudio/ 找到這份文件的線上版本。
如需觀看示範影片,請參閱影片 HOW TO:建立 Win32 應用程式 (C++) (英文)。
若要建立新的 Win32 專案
在 [檔案] 功能表上,按一下 [新增],然後再按一下 [專案]。
在 [專案類型] 窗格中,選取 [Visual C++] 節點中的 [Win32],然後選取 [樣板] 窗格中的 [Win32 專案]。
輸入專案名稱,例如 win32app。您可以接受預設位置、輸入某個位置,或瀏覽至您要儲存此專案的目錄。
在 [Win32 應用程式精靈] 上,選取 [下一步]。
在 [Win32 應用程式精靈] 的 [應用程式類型] 之下,選取 [Windows 應用程式]。在 [其他選項] 之下,選取 [空專案]。讓剩餘的選項維持不變。按一下 [完成] 以建立專案。
從 [專案] 功能表選取 [加入新項目],將 C++ 檔案加入專案。在 [加入新項目] 對話方塊中,選取 [C++ 檔 (.cpp)]。輸入檔案的名稱,例如 GT_HelloWorldWin32.cpp,並按一下 [加入]。
若要啟動 Win32 應用程式
如您所知道的,每個 C 與 C++ 應用程式都必須有一個 main 函式。這個函式是應用程式的起點。同樣地,在 Win32 應用程式中,每個應用程式都必須有一個 WinMain 函式。WinMain 的語法如下:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
如需此函式之參數與傳回值的說明,請參閱 WinMain 函式。
除了 WinMain 以外,每個 Win32 應用程式也都必須有第二個函式,此函式通常稱為 WndProc,代表視窗程序。WndProc 的語法如下:
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
此函式的目的,是要處理您的應用程式從作業系統所接收的所有訊息。您的應用程式何時會從作業系統接收訊息?任何時刻!例如,假設我們已經建立了具有 [確定] 按鈕的對話方塊。當使用者按一下該按鈕時,作業系統就會將訊息傳送到應用程式,讓我們知道使用者按了這個按鈕。WndProc 函式會負責回應該事件。在我們的範例中,適當的回應可能會是關閉對話方塊。
如需詳細資訊,請參閱視窗程序。
將功能加入 WinMain
首先,在 WinMain 函式內部建立 WNDCLASSEX 型別的視窗類別結構。這個結構會包含與視窗有關的資訊,例如應用程式的圖示、視窗的背景色彩、在標題列中顯示的名稱、視窗程序函式的名稱等等。一般的 WNDCLASSEX 結構會具有下列格式:
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(hInstance, MAKEINTRESOURCE(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, MAKEINTRESOURCE(IDI_APPLICATION));
如需此結構之欄位的說明,請參閱 WNDCLASSEX。
現在您已經建立自己的視窗類別,所以必須予以註冊。請使用 RegisterClassEx 函式,並將視窗類別結構當做引數傳遞。
if (!RegisterClassEx(&wcex)) { MessageBox(NULL, _T("Call to RegisterClassEx failed!"), _T("Win32 Guided Tour"), NULL); return 1; }
現在,您已註冊了自己的類別,可以開始建立視窗。請依照下列方式使用 CreateWindow 函式:
static TCHAR szWindowClass[] = _T("win32app"); static TCHAR szTitle[] = _T("Win32 Guided Tour Application"); // The parameters to CreateWindow explained: // 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 = CreateWindow( szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 100, NULL, NULL, hInstance, NULL ); if (!hWnd) { MessageBox(NULL, _T("Call to CreateWindow failed!"), _T("Win32 Guided Tour"), NULL); return 1; }
這個函式會傳回 HWND,也就是視窗的控制代碼。如需詳細資訊,請參閱 Windows 資料型別。
現在我們已經建立了視窗,可以使用下列程式碼在畫面上予以顯示:
// The parameters to ShowWindow explained: // hWnd: the value returned from CreateWindow // nCmdShow: the fourth parameter from WinMain ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd);
直到目前為止,這個視窗都還不會顯示多少內容,因為我們還沒有實作 WndProc 函式。
WinMain 的最終步驟就是訊息迴圈。這個迴圈的目的,是要接聽作業系統所傳送的訊息。當應用程式收到訊息時,該訊息就會分派到 WndProc 函式以進行處理。訊息迴圈會與下列相似:
MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int) msg.wParam;
如需在訊息迴圈中使用之結構與函式的詳細資訊,請參閱 MSG、GetMessage、TranslateMessage 及 DispatchMessage。
您剛才所完成的步驟可以通用於多數的 Win32 應用程式。此時,您的 WinMain 函式應該會與以下相似:
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(hInstance, MAKEINTRESOURCE(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, MAKEINTRESOURCE(IDI_APPLICATION)); if (!RegisterClassEx(&wcex)) { MessageBox(NULL, _T("Call to RegisterClassEx failed!"), _T("Win32 Guided Tour"), NULL); return 1; } hInst = hInstance; // Store instance handle in our global variable // The parameters to CreateWindow explained: // 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 = CreateWindow( szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 100, NULL, NULL, hInstance, NULL ); if (!hWnd) { MessageBox(NULL, _T("Call to CreateWindow failed!"), _T("Win32 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; }
將功能加入 WndProc
WndProc 函式的目的,是要處理您的應用程式所接收到的訊息。您通常會使用切換函式來實作這項工作。
我們將會處理的第一個訊息是 WM_PAINT 訊息。當應用程式視窗的部分必須更新時,您的應用程式就會收到這個訊息。當第一次建立視窗時,整個視窗都必須更新,因此會傳遞這個訊息表示這一點。
當您處理 WM_PAINT 訊息時,所應該做的第一件事就是呼叫 BeginPaint,而最後一件應該做的事則是呼叫 EndPaint。在這兩個函式呼叫之間,您會處理所有的邏輯以安排視窗的文字、按鈕及其他控制項。在此應用程式中,我們會在視窗內顯示 "Hello, World!" 字串。若要顯示文字,請使用 TextOut 函式,如下所示:
PAINTSTRUCT ps; HDC hdc; TCHAR greeting[] = _T("Hello, World!"); switch (message) { case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // Here your application is laid out. // For this introduction, we just print out "Hello, World!" // in the top left corner. TextOut(hdc, 5, 5, greeting, _tcslen(greeting)); // End application-specific layout section. EndPaint(hWnd, &ps); break; }
您的應用程式一般都會處理許多其他訊息,例如 WM_CREATE 和 WM_DESTROY。以下是簡單而完整的 WndProc 函式:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HDC hdc; TCHAR greeting[] = _T("Hello, World!"); switch (message) { case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // Here your application is laid out. // For this introduction, we just print out "Hello, World!" // 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; }
範例
說明
在完成所有步驟之後,您的程式碼應該會與以下相似。若要建置應用程式,請從 [建置] 功能表選取 [建置方案]。如果您的應用程式順利編譯而未發生錯誤,您就可以按 F5 執行該應用程式。具有 "Hello, World!" 文字的簡單視窗將會出現在畫面上靠近左上角的地方。
程式碼
// GT_HelloWorldWin32.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("win32app");
// The string that appears in the application's title bar.
static TCHAR szTitle[] = _T("Win32 Guided Tour Application");
HINSTANCE hInst;
// Forward declarations of functions included in this code module:
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
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(hInstance, MAKEINTRESOURCE(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, MAKEINTRESOURCE(IDI_APPLICATION));
if (!RegisterClassEx(&wcex))
{
MessageBox(NULL,
_T("Call to RegisterClassEx failed!"),
_T("Win32 Guided Tour"),
NULL);
return 1;
}
hInst = hInstance; // Store instance handle in our global variable
// The parameters to CreateWindow explained:
// 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 = CreateWindow(
szWindowClass,
szTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
500, 100,
NULL,
NULL,
hInstance,
NULL
);
if (!hWnd)
{
MessageBox(NULL,
_T("Call to CreateWindow failed!"),
_T("Win32 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, World!");
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// Here your application is laid out.
// For this introduction, we just print out "Hello, World!"
// 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;
}
後續步驟
上一個主題:建立 Windows 應用程式 (C++) | 下一個主題:使用 .NET Framework 建立 Windows Form 應用程式 (C++)