1. 程式人生 > >Windows視窗程式從建立到關閉產生的訊息

Windows視窗程式從建立到關閉產生的訊息

Windows是訊息驅動的,理解訊息機制及訊息迴圈是特別重要。知道在什麼情況下產生什麼訊息會讓我們對程式有更好的控制。Windows給應用程式發訊息,有些會加入應用程式的訊息佇列,也是就是佇列訊息。有些直接呼叫視窗訊息處理程式,不會加入到訊息佇列,這部分為非佇列訊息。

下面分析一下一個應用程式從建立到結束產生的訊息。

先給出測試用的程式,當然是一個非常經典的結構:

#include <windows.h>
#include <tchar.h>


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

int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine,
                   int nShowCmd)
{
    MSG msg;
    TCHAR szClassName[] = _T("MainWClass");
    WNDCLASSEX wndclass;

    wndclass.cbClsExtra = 0;
    wndclass.cbSize = sizeof(wndclass);
    wndclass.cbWndExtra = 0;
    wndclass.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH);
    wndclass.hCursor = ::LoadCursor(NULL, IDI_APPLICATION);
    wndclass.hIcon = ::LoadIcon(NULL, IDC_ARROW);
    wndclass.hIconSm = NULL;
    wndclass.hInstance = hInstance;
    wndclass.lpfnWndProc = WndProc;
    wndclass.lpszClassName = szClassName;
    wndclass.lpszMenuName = NULL;
    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    
    if (::RegisterClassEx(&wndclass) == 0)
    {
        ::MessageBox(NULL, _T("RegisterClassEx Failed"), _T("Error"), MB_OK | MB_ICONHAND);
        return 0;
    }

    HWND hwnd = ::CreateWindow(
        szClassName,            // lpClassName
        _T("My Window"),        // lpWindowName
        WS_OVERLAPPEDWINDOW,    // dwStyle
        CW_USEDEFAULT,          // X
        CW_USEDEFAULT,          // Y
        CW_USEDEFAULT,          // nWidth
        CW_USEDEFAULT,          // nHeight
        NULL,                   // hWndParent,
        NULL,                   // hMenu
        hInstance,              // hInstance
        NULL                    // lpParam
        );                  

    ::ShowWindow(hwnd, nShowCmd);
    ::UpdateWindow(hwnd);

    while (::GetMessage(&msg, NULL, 0, 0))
    {
        ::TranslateMessage(&msg);
        ::DispatchMessage(&msg);
    }

    return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    TCHAR szText[] = _T("Simple Window!");
    switch (message)
    {
    case WM_PAINT:
        {
            HDC hdc;
            PAINTSTRUCT ps;
            hdc = ::BeginPaint(hwnd, &ps);
            ::TextOut(hdc, 10, 10, szText, _tcslen(szText));
            ::EndPaint(hwnd, &ps);
        }
        return 0;
    case WM_DESTROY:
        ::PostQuitMessage(0);
        return 0;
    }
    return ::DefWindowProc(hwnd, message, wParam, lParam);
}
啟動這個程式到關閉他都會產生什麼訊息呢?
// 呼叫CreateWindow後產生第一條訊息:
CreateWindow()
0X0024 WM_GETMINMAXINFO     "當視窗將要改變大小或位置時,由系統傳送本訊息給視窗,使用者拖動一個可重置大小的視窗時便會發出本訊息"
0X0081 WM_NCCREATE          "當某視窗首次被建立時,本訊息在WM_CREATE訊息傳送前傳送"
0X0083 WM_NCCALCSIZE        "當某視窗的客戶區的大小和位置須被計算時傳送本訊息"
0X0001 WM_CREATE            "新建一個視窗"
CreateWindow() 返回

ShowWindow()
0X0018 WM_SHOWWINDOW        "傳送本訊息給一個視窗,以便隱藏或顯示該視窗"
0X0046 WM_WINDOWPOSCHANGING "本訊息會發送給那些大小和位置(Z_Order)將被改變的視窗,以呼叫SetWindowPos函式或其它視窗管理函式"
0X001C WM_ACTIVATEAPP       "視窗程序啟用狀態改動,正被啟用的視窗屬於不同的應用程式 "
0X0086 WM_NCACTIVATE        "本訊息傳送給某視窗,在視窗的非客戶區被啟用時重繪視窗"
0X007F WM_GETICON           "本訊息傳送給某個視窗,用於返回與某視窗有關聯的大圖示或小圖示的控制代碼(一般收到多個,用於獲取不同大小的圖示)"
0X0006 WM_ACTIVATE          "一個視窗被啟用或失去啟用狀態"
0X0281 WM_IME_SETCONTEXT    "應用程式的視窗啟用時,系統將嚮應用程式傳送WM_IME_SETCONTEXT訊息,輸入焦點轉移到了某個視窗上,注:輸入法相關"
0X0282 WM_IME_NOTIFY        "可使用WM_IME_NOTIFY訊息來通知關於IME視窗狀態的常規改變,注:輸入法相關,IME視窗發生了改變" 
0X0007 WM_SETFOCUS          "將焦點轉向一個視窗"
0X0085 WM_NCPAINT           "當視窗框架(非客戶區)必須被被重繪時,應用程式傳送本訊息給該視窗"
0X0014 WM_ERASEBKGND        "當一個視窗的背景必須被擦除時本訊息會被觸發(如:視窗大小改變時)"
0X0047 WM_WINDOWPOSCHANGED  "本訊息會發送給那些大小和位置(Z_Order)已被改變的視窗,以呼叫SetWindowPos函式或其它視窗管理函式"
0X0005 WM_SIZE              "改變一個視窗的大小"
0X0003 WM_MOVE              "移動一個視窗"
ShowWindow() 返回

UpdateWindow()
0X000F WM_PAINT             "視窗重繪"
UpdateWindow() 返回
0X007F WM_GETICON           "本訊息傳送給某個視窗,用於返回與某視窗有關聯的大圖示或小圖示的控制代碼(一般收到多個,用於獲取不同大小的圖示)"

// 進入訊息迴圈
0X0113 WM_TIMER             "發生了定時器事件"
0X0101 WM_KEYUP             "當一個非系統按鍵被釋放彈起時(<ALT>鍵沒有被按下),會發送本訊息給擁有鍵盤焦點的視窗"
0X0113 WM_TIMER             "發生了定時器事件"
0X0104 WM_SYSKEYDOWN        "當用戶按住<ALT>鍵的同時又按下其它鍵時,傳送本訊息給擁有焦點的視窗",
0X0112 WM_SYSCOMMAND        "當用戶選擇一條系統選單命令、使用者最大化或最小化或還原或關閉時,視窗會收到本訊息"
0X0010 WM_CLOSE             "使用者關閉視窗時會發送本訊息,緊接著會發送WM_DESTROY訊息"
0X0046 WM_WINDOWPOSCHANGING "本訊息會發送給那些大小和位置(Z_Order)將被改變的視窗,以呼叫SetWindowPos函式或其它視窗管理函式"
0X0047 WM_WINDOWPOSCHANGED  "本訊息會發送給那些大小和位置(Z_Order)已被改變的視窗,以呼叫SetWindowPos函式或其它視窗管理函式"
0X0086 WM_NCACTIVATE        "本訊息傳送給某視窗,在視窗的非客戶區被啟用時重繪視窗"
0X0006 WM_ACTIVATE          "一個視窗被啟用或失去啟用狀態"
0X001C WM_ACTIVATEAPP       "視窗程序啟用狀態改動,正被啟用的視窗屬於不同的應用程式 "
0X0008 WM_KILLFOCUS         "使一個視窗失去焦點"
0X0281 WM_IME_SETCONTEXT    "應用程式的視窗啟用時,系統將嚮應用程式傳送WM_IME_SETCONTEXT訊息,輸入焦點轉移到了某個視窗上,注:輸入法相關"
0X0282 WM_IME_NOTIFY        "可使用WM_IME_NOTIFY訊息來通知關於IME視窗狀態的常規改變,注:輸入法相關,IME視窗發生了改變" 
0X0002 WM_DESTROY           "銷燬一個視窗"
0X0082 WM_NCDESTROY         "本訊息通知某視窗,非客戶區正在銷燬"

就是以上這些,可以看出上面的訊息是使用系統快捷鍵來關閉的程式。