使用視窗程式

本節說明如何執行與視窗程式相關聯的下列工作。

設計視窗程式

下列範例顯示一般視窗程式的結構。 視窗程式會使用 switch 語句中的 message 引數,以及個別 案例 語句所處理的個別訊息。 請注意,每個案例都會傳回每個訊息的特定值。 對於未處理的訊息,視窗過程會呼叫 DefWindowProc 函式。

LRESULT CALLBACK MainWndProc(
    HWND hwnd,        // handle to window
    UINT uMsg,        // message identifier
    WPARAM wParam,    // first message parameter
    LPARAM lParam)    // second message parameter
{ 
 
    switch (uMsg) 
    { 
        case WM_CREATE: 
            // Initialize the window. 
            return 0; 
 
        case WM_PAINT: 
            // Paint the window's client area. 
            return 0; 
 
        case WM_SIZE: 
            // Set the size and position of the window. 
            return 0; 
 
        case WM_DESTROY: 
            // Clean up window-specific data objects. 
            return 0; 
 
        // 
        // Process other messages. 
        // 
 
        default: 
            return DefWindowProc(hwnd, uMsg, wParam, lParam); 
    } 
    return 0; 
} 

WM_NCCREATE訊息會在建立視窗之後傳送,但如果應用程式傳回FALSE來回應此訊息,CreateWindowEx函式就會失敗。 建立視窗之後,就會傳送 WM_CREATE 訊息。

當視窗即將終結時,就會傳送 WM_DESTROY 訊息。 DestroyWindow函式會負責終結視窗的任何子視窗。 WM_NCDESTROY訊息會在視窗終結之前傳送。

至少,視窗程式應該處理 WM_PAINT 訊息以繪製本身。 一般而言,它也應該處理滑鼠和鍵盤訊息。 請參閱個別訊息的描述,以判斷您的視窗程式是否應該處理這些訊息。

您的應用程式可以在處理訊息時呼叫 DefWindowProc 函式。 在這種情況下,應用程式可以在將訊息傳遞至 DefWindowProc之前修改訊息參數,也可以在執行自己的作業之後繼續進行預設處理。

對話方塊程式會接收 WM_INITDIALOG 訊息,而不是 WM_CREATE 訊息,而且不會將未處理的訊息傳遞至 DefDlgProc 函式。 否則,對話方塊程式與視窗程式完全相同。

將視窗程式與視窗類別產生關聯

註冊類別時,您會將視窗程式與視窗類別產生關聯。 您必須使用 類別的相關資訊填入 WNDCLASS 結構, 而 lpfnWndProc 成員必須指定視窗程式的位址。 若要註冊 類別,請將 WNDCLASS 結構的位址傳遞至 RegisterClass 函式。 註冊視窗類別之後,視窗程式會自動與使用該類別建立的每個新視窗相關聯。

下列範例示範如何將上一個範例中的視窗程式與視窗類別產生關聯。

int APIENTRY WinMain( 
    HINSTANCE hinstance,  // handle to current instance 
    HINSTANCE hinstPrev,  // handle to previous instance 
    LPSTR lpCmdLine,      // address of command-line string 
    int nCmdShow)         // show-window type 
{ 
    WNDCLASS wc; 
 
    // Register the main window class. 
    wc.style = CS_HREDRAW | CS_VREDRAW; 
    wc.lpfnWndProc = (WNDPROC) MainWndProc; 
    wc.cbClsExtra = 0; 
    wc.cbWndExtra = 0; 
    wc.hInstance = hinstance; 
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); 
    wc.hCursor = LoadCursor(NULL, IDC_ARROW); 
    wc.hbrBackground = GetStockObject(WHITE_BRUSH); 
    wc.lpszMenuName =  "MainMenu"; 
    wc.lpszClassName = "MainWindowClass"; 
 
    if (!RegisterClass(&wc)) 
       return FALSE; 
 
    // 
    // Process other messages. 
    // 
 
} 

子類別化視窗

若要子類別視窗的實例,請呼叫 SetWindowLong 函式,並指定視窗的控制碼,以子類別化GWL_WNDPROC旗標和子類別程式的指標。 SetWindowLong 會傳回原始視窗程式的指標;使用此指標將訊息傳遞至原始程式。 子類別視窗程式必須使用 CallWindowProc 函式來呼叫原始視窗程式。

注意

若要撰寫與 32 位和 64 位版本的 Windows 相容的程式碼,請使用 SetWindowLongPtr 函式。

 

下列範例示範如何在對話方塊中將編輯控制項的實例子類別化。 每當控制項具有輸入焦點時,子類別視窗程式可讓編輯控制項接收所有鍵盤輸入,包括 ENTER 鍵和 TAB 鍵。

WNDPROC wpOrigEditProc; 
 
LRESULT APIENTRY EditBoxProc(
    HWND hwndDlg, 
    UINT uMsg, 
    WPARAM wParam, 
    LPARAM lParam) 
{ 
    HWND hwndEdit; 
 
    switch(uMsg) 
    { 
        case WM_INITDIALOG: 
            // Retrieve the handle to the edit control. 
            hwndEdit = GetDlgItem(hwndDlg, ID_EDIT); 
 
            // Subclass the edit control. 
            wpOrigEditProc = (WNDPROC) SetWindowLong(hwndEdit, 
                GWL_WNDPROC, (LONG) EditSubclassProc); 
            // 
            // Continue the initialization procedure. 
            // 
            return TRUE; 
 
        case WM_DESTROY: 
            // Remove the subclass from the edit control. 
            SetWindowLong(hwndEdit, GWL_WNDPROC, 
                (LONG) wpOrigEditProc); 
            // 
            // Continue the cleanup procedure. 
            // 
            break; 
    } 
    return FALSE; 
        UNREFERENCED_PARAMETER(lParam); 
} 
 
// Subclass procedure 
LRESULT APIENTRY EditSubclassProc(
    HWND hwnd, 
    UINT uMsg, 
    WPARAM wParam, 
    LPARAM lParam) 
{ 
    if (uMsg == WM_GETDLGCODE) 
        return DLGC_WANTALLKEYS; 
 
    return CallWindowProc(wpOrigEditProc, hwnd, uMsg, 
        wParam, lParam); 
}