1. 程式人生 > >GDI 設備環境句柄(2)

GDI 設備環境句柄(2)

BE round 背景 狀態 信息 lld style 景區 def

WM_PAINT 消息的觸發

Windows 程序在以下情況會觸發WM_PAINT消息:

  • 窗口被移動導致被遮蓋部分暴露出來
  • 用戶調整窗口的大小(當窗口類的 style 字段被設置為 CS_HREDRAW 和 CS_VREDRAW)
  • 調用 ScrollWindow 或 ScrollDC 函數滾動客戶區
  • 調用 InvalidateRect 或 InvalidateRgn 函數生成 WM_PAINT

獲取設備環境句柄

需要在屏幕上繪圖的時候,需要先獲取到設備環境句柄,這裏有兩種方式:

1、調用 BeginPaint 函數(用於響應 WM_PAINT 消息)

第一個參數是當前的窗口句柄,第二個參數是 PAINTSTRUCT 結構的地址,它將返回一個設備環境句柄。BeginPaint 函數的原型如下:

HDC BeginPaint(
  HWND hwnd,            // 當前的窗口句柄
  LPPAINTSTRUCT lpPaint // PAINTSTRUCT 結構的地址
)

Windows 為每個窗口維護一個“繪制信息結構”,即 PAINTSTRUCT,這裏給出了它的定義:

typedef struct tagPAINTSTRUCT { 
  HDC  hdc;             // 設備環境句柄,即 BeginPaint 函數的返回值
  BOOL fErase;          // 背景刷狀態,如果為 TRUE,表示無效背景區域需要進行擦除,為 FALSE,表示已經擦除了無效區域的背景
RECT rcPaint; // 無效矩形邊界,是一個 RECT 結構,包含 left、top、right、bottom 四個參數 BOOL fRestore; BOOL fIncUpdate; BYTE rgbReserved[32]; } PAINTSTRUCT;

調用 BeginPaint 函數時,PAINTSTRUCT 結構中的字段將被自動填充。

當調用 BeginPaint 函數獲得設備環境句柄,並處理 WM_PAINT 消息後,必須使用 EndPaint 函數釋放獲取到的設備環境句柄,該函數原型如下:

BOOL EndPaint(
  HWND hWnd,                  
// 當前的窗口句柄 CONST PAINTSTRUCT *lpPaint // PAINTSTRUCT 結構的地址 );

源碼片段示例:

// ......
case WM_PAINT:
    hdc = BeginPaint(hwnd, &ps);
    // 其他GDI代碼
    EndPaint(hwnd, &ps);
    return 0;
// ......

2、調用 GetDC 函數(用於響應非 WM_PAINT 消息)

GetDC 函數只有一個參數,即當前的窗口句柄,它將設備環境句柄作為返回值返回。在使用完設備環境句柄後,必須調用 ReleaseDC 函數將其釋放,它有兩個參數,第一個是當前的窗口句柄,第二個是要釋放的設備環境句柄。

源碼片段示例:

// ......
    hdc = GetDC(hwnd);
    // 其他GDI代碼
    ReleaseDC(hwnd, hdc);
    return 0;
// ......

GetDC / ReleaseDC 組合通常用於處理鍵盤消息或(與)鼠標消息。

需要註意的地方(小結)

  • WM_PAINT 消息的產生,表示窗口客戶區需要重繪。
  • BeginPaint 函數返回的是無效矩形客戶區(PAINTSTRUCT 結構中的 rcPaint 字段)的設備環境句柄,而 GetDC 函數返回的是整個客戶區的設備環境句柄。
  • BeginPaint 函數調用後,無效矩形區域將變得有效化;而 GetDC 函數本身不會使客戶區無效區域有效化,需要自行調用 ValidateRect 函數使客戶區無效區域有效化。

GDI 設備環境句柄(2)