撰寫視窗程式

DispatchMessage 函式會呼叫訊息目標視窗的視窗程式。 窗口程式具有下列簽章。

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

有四個參數:

  • hwnd 是視窗的句柄。
  • uMsg 是訊息碼;例如, WM_SIZE 訊息表示視窗已重設大小。
  • wParamlParam 包含與訊息相關的其他數據。 確切的意義取決於訊息碼。

LRESULT 是程式傳回 Windows 的整數值。 其中包含程式對特定訊息的回應。 此值的意義取決於訊息碼。 CALLBACK 是函式的呼叫慣例。

典型的視窗程式只是切換訊息程序代碼的大型 switch 語句。 針對您想要處理的每個訊息新增案例。

switch (uMsg)
{
    case WM_SIZE: // Handle window resizing

    // etc
}

訊息的其他數據包含在 lParam 和 wParam 參數中。 這兩個參數都是指標寬度大小的整數值(32 位或64位)。 每個的意義取決於訊息碼 (uMsg)。 針對每個訊息,您必須查閱 MSDN 上的訊息程式代碼,並將參數轉換成正確的數據類型。 數據通常是數值或結構的指標。 有些訊息沒有任何數據。

例如,WM_SIZE訊息的檔指出:

  • wParam 是一個旗標,指出視窗已最小化、最大化或重設大小。
  • lParam 包含視窗的新寬度和高度,以 16 位值封裝成一個 32 位或 64 位數位。 您必須執行一些位移轉來取得這些值。 幸運的是,頭檔 WinDef.h 包含可執行這項操作的協助程序宏。

典型的視窗程序會處理數十則訊息,因此它可以成長相當長。 讓程式代碼更模組化的其中一種方法是將邏輯放在個別函式中處理每個訊息。 在視窗程式中,將 wParam 和 lParam 參數轉換成正確的數據類型,並將這些值傳遞至函式。 例如,若要處理 WM_SIZE 訊息,視窗程序看起來會像這樣:

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_SIZE:
        {
            int width = LOWORD(lParam);  // Macro to get the low-order word.
            int height = HIWORD(lParam); // Macro to get the high-order word.

            // Respond to the message:
            OnSize(hwnd, (UINT)wParam, width, height);
        }
        break;
    }
}

void OnSize(HWND hwnd, UINT flag, int width, int height)
{
    // Handle resizing
}

LOWORD 和 HIWORD 宏會從 lParam 取得 16 位寬度和高度值。 (您可以在 MSDN 檔中查閱每個訊息碼的這類詳細數據。視窗程式會擷取寬度和高度,然後將這些值傳遞至函 OnSize 式。

默認訊息處理

如果您未在視窗程序中處理特定訊息,請將訊息參數直接傳遞至 DefWindowProc 函式。 此函式會執行訊息的默認動作,依訊息類型而有所不同。

return DefWindowProc(hwnd, uMsg, wParam, lParam);

避免視窗程式中的瓶頸

當視窗程式執行時,它會封鎖在相同線程上建立之視窗的任何其他訊息。 因此,請避免在視窗程式內處理冗長。 例如,假設您的程序開啟 TCP 連線,並無限期等候伺服器回應。 如果您在視窗程式內這麼做,您的UI在要求完成之前將不會回應。 在此期間,視窗無法處理滑鼠或鍵盤輸入、重繪本身,甚至關閉。

相反地,您應該使用 Windows 內建的其中一個多任務功能,將工作移至另一個線程:

  • 建立新的線程。
  • 使用執行緒集區。
  • 使用異步 I/O 呼叫。
  • 使用異步過程調用。

下一步

小畫家 視窗