共用方式為


建立 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 專案

  1. 在 [檔案] 功能表上,按一下 [新增],然後再按一下 [專案]。

  2. 在 [專案類型] 窗格中,選取 [Visual C++] 節點中的 [Win32],然後選取 [樣板] 窗格中的 [Win32 專案]。

    輸入專案名稱,例如 win32app。您可以接受預設位置、輸入某個位置,或瀏覽至您要儲存此專案的目錄。

  3. 在 [Win32 應用程式精靈] 上,選取 [下一步]。

  4. 在 [Win32 應用程式精靈] 的 [應用程式類型] 之下,選取 [Windows 應用程式]。在 [其他選項] 之下,選取 [空專案]。讓剩餘的選項維持不變。按一下 [完成] 以建立專案。

  5. 從 [專案] 功能表選取 [加入新項目],將 C++ 檔案加入專案。在 [加入新項目] 對話方塊中,選取 [C++ 檔 (.cpp)]。輸入檔案的名稱,例如 GT_HelloWorldWin32.cpp,並按一下 [加入]。

若要啟動 Win32 應用程式

  1. 如您所知道的,每個 C 與 C++ 應用程式都必須有一個 main 函式。這個函式是應用程式的起點。同樣地,在 Win32 應用程式中,每個應用程式都必須有一個 WinMain 函式。WinMain 的語法如下:

    int WINAPI WinMain(HINSTANCE hInstance,
                       HINSTANCE hPrevInstance,
                       LPSTR lpCmdLine,
                       int nCmdShow);
    

    如需此函式之參數與傳回值的說明,請參閱 WinMain 函式

  2. 除了 WinMain 以外,每個 Win32 應用程式也都必須有第二個函式,此函式通常稱為 WndProc,代表視窗程序。WndProc 的語法如下:

    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    

    此函式的目的,是要處理您的應用程式從作業系統所接收的所有訊息。您的應用程式何時會從作業系統接收訊息?任何時刻!例如,假設我們已經建立了具有 [確定] 按鈕的對話方塊。當使用者按一下該按鈕時,作業系統就會將訊息傳送到應用程式,讓我們知道使用者按了這個按鈕。WndProc 函式會負責回應該事件。在我們的範例中,適當的回應可能會是關閉對話方塊。

    如需詳細資訊,請參閱視窗程序

將功能加入 WinMain

  1. 首先,在 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

  2. 現在您已經建立自己的視窗類別,所以必須予以註冊。請使用 RegisterClassEx 函式,並將視窗類別結構當做引數傳遞。

        if (!RegisterClassEx(&wcex))
        {
            MessageBox(NULL,
                _T("Call to RegisterClassEx failed!"),
                _T("Win32 Guided Tour"),
                NULL);
    
            return 1;
        }
    
  3. 現在,您已註冊了自己的類別,可以開始建立視窗。請依照下列方式使用 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 資料型別

  4. 現在我們已經建立了視窗,可以使用下列程式碼在畫面上予以顯示:

    // The parameters to ShowWindow explained:
    // hWnd: the value returned from CreateWindow
    // nCmdShow: the fourth parameter from WinMain
    ShowWindow(hWnd,
        nCmdShow);
    UpdateWindow(hWnd);
    

    直到目前為止,這個視窗都還不會顯示多少內容,因為我們還沒有實作 WndProc 函式。

  5. WinMain 的最終步驟就是訊息迴圈。這個迴圈的目的,是要接聽作業系統所傳送的訊息。當應用程式收到訊息時,該訊息就會分派到 WndProc 函式以進行處理。訊息迴圈會與下列相似:

        MSG msg;
        while (GetMessage(&msg, NULL, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    
        return (int) msg.wParam;
    

    如需在訊息迴圈中使用之結構與函式的詳細資訊,請參閱 MSGGetMessageTranslateMessageDispatchMessage

  6. 您剛才所完成的步驟可以通用於多數的 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

  1. 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;
    }
    
  2. 您的應用程式一般都會處理許多其他訊息,例如 WM_CREATEWM_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++)

請參閱

工作

建立 Windows 應用程式 (C++)