首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> Delphi

Delphi 純 Windows API 創建窗體:從註冊類到消息循環的完整實現

     編輯:Delphi

為什麼要學純 API 創建窗口?

VCL TForm 封裝了所有細節,但理解底層 RegisterClassEx、CreateWindowEx、GetMessage/DispatchMessage 消息循環,是掌握 Windows 程序本質、調試疑難雜癥、編寫高性能/無 VCL 依賴工具 (如引導程序、系統服務 UI) 的前提。

完整最小化窗口程序

program DelphiAPIWindow;

uses Windows, Messages;

const
  HelloStr = 'Hello World!';
  {$R *.res} // 包含圖標資源 MAINICON

// 窗口過程:處理所有發送給該類窗口的消息
function MyWinProc(hWnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
var
  hdc: HDC; ps: TPaintStruct; rect: TRect; hFont: HFONT;
begin
  Result := 0;
  case uMsg of
    WM_PAINT:
    begin
      hdc := BeginPaint(hWnd, ps);
      SetBkMode(hdc, TRANSPARENT);
      GetClientRect(hWnd, rect);
      // 繪製居中文本
      DrawText(hdc, PChar(HelloStr), -1, rect, DT_SINGLELINE or DT_CENTER or DT_VCENTER);
      EndPaint(hWnd, ps);
    end;
    WM_CREATE:
    begin
      // 創建自定義字體 (可選)
      hdc := GetDC(hWnd);
      hFont := CreateFont(45, 0, 0, 0, FW_NORMAL, 0, 0, 0,
        ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
        DEFAULT_QUALITY, VARIABLE_PITCH or FF_SWISS, 'Arial');
      SelectObject(hdc, hFont);
      ReleaseDC(hWnd, hdc);
      // 注意:此處創建的字體未保存句柄,WM_DESTROY 會泄漏。實際應存入窗口數據 (SetWindowLongPtr GWLP_USERDATA) 或類數據。
    end;
    WM_DESTROY:
      PostQuitMessage(0); // 發送 WM_QUIT 結束消息循環
  else
    Result := DefWindowProc(hWnd, uMsg, wParam, lParam); // 默認處理
  end;
end;

// 程序入口
var
  Msg: TMsg; hWnd, hInst: HINST; WndClass: TWndClassEx;
begin
  hInst := GetModuleHandle(nil); // 獲取模塊實例句柄

  // 1. 填充窗口類結構
  WndClass.cbSize := SizeOf(TWndClassEx);
  WndClass.lpszClassName := 'MyAPIWindowClass';
  WndClass.style := CS_HREDRAW or CS_VREDRAW or CS_OWNDC;
  WndClass.hInstance := hInst;
  WndClass.lpfnWndProc := @MyWinProc; // 關鍵:指定窗口過程
  WndClass.cbClsExtra := 0; WndClass.cbWndExtra := 0;
  WndClass.hIcon := LoadIcon(hInst, MakeIntResource('MAINICON')); // 從資源加載圖標
  WndClass.hIconSm := LoadIcon(hInst, MakeIntResource('MAINICON'));
  WndClass.hCursor := LoadCursor(0, IDC_ARROW);
  WndClass.hbrBackground := GetStockObject(WHITE_BRUSH); // 白色背景刷
  WndClass.lpszMenuName := nil;

  // 2. 註冊窗口類
  if RegisterClassEx(WndClass) = 0 then
  begin MessageBox(0, '窗口類註冊失敗!', 'Error', MB_OK); Exit; end;

  // 3. 創建窗口實例
  hWnd := CreateWindowEx(
    WS_EX_OVERLAPPEDWINDOW,      // 擴展風格
    WndClass.lpszClassName,      // 類名
    'Hello API Window',          // 窗口標題
    WS_OVERLAPPEDWINDOW,         // 風格
    CW_USEDEFAULT, 0,            // 位置 (x, y)
    CW_USEDEFAULT, 0,            // 尺寸 (寬, 高)
    0, 0,                        // 父窗口、菜單
    hInst,                       // 實例句柄
    nil                          // 創建參數
  );

  if hWnd = 0 then
  begin MessageBox(0, '窗口創建失敗!', 'Error', MB_OK); Exit; end;

  // 4. 顯示與更新
  ShowWindow(hWnd, SW_SHOWNORMAL);
  UpdateWindow(hWnd);
  SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE); // 置頂演示

  // 5. 消息循環:核心引擎
  while GetMessage(Msg, 0, 0, 0) do
  begin
    TranslateMessage(Msg); // 鍵盤虛擬鍵 -> 字符消息 (WM_CHAR)
    DispatchMessage(Msg);  // 分發到 MyWinProc
  end;
end.

關鍵環節解析

步驟API/結構核心作用
類定義TWndClassEx定義窗口「模板」:過程指釖、圖標、光標、背景刷、類名。
類註冊RegisterClassEx向系統登記類信息,返回原子標識。同一進程同類名只需註冊一次。
窗口創建CreateWindowEx實例化窗口,分配內核對象,關聯類,返回 HWND。
顯示更新ShowWindow/UpdateWindow使窗口可見,發送首個 WM_PAINT 觸發繪製。
消息循環GetMessage/TranslateMessage/DispatchMessage程序靈魂:從隊列取消息、鍵盤轉換、分發到窗口過程。GetMessage 遇 WM_QUIT 返回 0 退出循環。
窗口過程MyWinProc (回調)處理針對該窗口的所有消息。DefWindowProc 提供默認行為 (如標題欄拖動、系統菜單)。

VCL 做了什麼?(對照理解)

  • TForm 構造函數 → 隱式調用 RegisterClass (類名如 TForm1)、CreateWindowEx (風格 WS_POPUP 等)。
  • Application.Run → 封裝 GetMessage/DispatchMessage 循環,並處理 TApplication 級別消息 (如 OnIdle, OnMessage、異常捕獲)。
  • TControl.WndProc → 封裝 MyWinProc,將消息分發為 OnClick/OnPaint 等事件、屬性存取、子控件佈局。
  • 資源管理:字體、畫筆、刷句柄自動創建/釋放 (通過 TFont/TCanvas 封裝)。

常見坑與最佳實踐

  1. 字體/筆刷泄漏:WM_CREATE 創建 GDI 對象,必須在 WM_DESTROY 刪除 (DeleteObject) 或存入窗口實例數據 (SetWindowLongPtr(hWnd, GWLP_USERDATA, ...))。
  2. Unicode/ANSI:Delphi 2009+ 默認 Unicode,API 調用用 PChar (即 PWideChar),系統調用 RegisterClassExW/CreateWindowExW。資源字符串需一致。
  3. WM_PAINT 必須 BeginPaint/EndPaint 配對,否則會無限重繪導致 CPU 100%。
  4. DefWindowProc 必須調用處理未關心消息,否則窗口無法移動、關閉、響應系統命令。
  5. 控制台程序 ({$APPTYPE CONSOLE}) 也可創建 GUI 窗口,但需自行實現消息循環。

總結

純 API 窗口程序雖代碼量大、細節多,但它剝離了 VCL 厚重封裝,展現了 Windows 圖形子系統的核心架構:**類註冊 → 實例創建 → 消息泵 → 窗口過程**。每位 Delphi 開發者至少應手寫一次,方能真正理解「事件驅動」、「句柄」、「消息分發」等核心概念,並在需要時突破 VCL 限制實現極致控制。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved