BCB 程式啟動流程:
WinMain → Application->Initialize() → Application->CreateForm() → Application->Run()
Application->Run() 進入訊息迴圈,核心邏輯在 TApplication.ProcessMessage:
// 簡化自 VCL 原始碼 (forms.pas)
function TApplication.ProcessMessage(var Msg: TMsg): Boolean;
begin
Result := False;
if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then begin
Result := True;
if Msg.Message <> WM_QUIT then begin
Handled := False;
// 1. OnMessage 事件 (最早攔截點,僅限佇列訊息)
if Assigned(FOnMessage) then FOnMessage(Msg, Handled);
// 2. 內部處理 (Hint, MDI, 鍵盤, 對話框)
if not Handled and not IsHintMsg(Msg) and not IsMDIMsg(Msg)
and not IsKeyMsg(Msg) and not IsDlgMsg(Msg) then begin
TranslateMessage(Msg);
DispatchMessage(Msg); // 分派至視窗程序
end;
end else
FTerminate := True;
end;
end;
| 攔截點 | 方法 | 可攔截 SendMessage | 時機 | 備註 |
|---|---|---|---|---|
| 1. Application.OnMessage | 指派事件處理器 | 否 (僅 PeekMessage 取得的佇列訊息) | 最早 (訊息迴圈中) | 簡單、安全 |
| 2. Form/Control.WndProc | 覆寫虛擬函數 | 是 | 中等 (視窗程序中) | 標準做法 |
| 3. Application.HookMainWindow | 掛鉤自訂函數 | 是 | 最早 (TApplication.WndProc 開頭) | 功能最強、需手動移除 |
void __fastcall TForm1::MyOnMessage(tagMSG &Msg, bool &Handled) {
if (Msg.message == WM_KEYDOWN) {
MessageDlg("You Pressed Key!", mtWarning, TMsgDlgButtons() << mbOK, 0);
Handled = true; // 標記已處理,不再分派
}
}
void __fastcall TForm1::FormCreate(TObject *Sender) {
Application->OnMessage = MyOnMessage;
}
TApplication.WndProc 開頭遍歷 FWindowHooks 清單呼叫掛鉤函數:
for I := 0 to FWindowHooks.Count - 1 do
if TWindowHook(FWindowHooks[I])(Message) then Exit; // 返回 true 表示已處理
bool __fastcall TForm1::AppHookFunc(TMessage &Message) {
bool Handled = false;
if (Message.Msg == WM_CLOSE) {
if (MessageDlg("Really Close??", mtWarning,
TMsgDlgButtons() << mbYes << mbNo, 0) == mrNo) {
Handled = true; // 取消關閉
}
}
return Handled;
}
void __fastcall TForm1::FormCreate(TObject *Sender) {
Application->HookMainWindow(AppHookFunc);
}
void __fastcall TForm1::FormDestroy(TObject *Sender) {
Application->UnhookMainWindow(AppHookFunc); // 必須配對移除!
}
void __fastcall TForm1::Button1Click(TObject *Sender) {
// 測試:直接發送 WM_CLOSE 給 Application 視窗
SendMessage(Application->Handle, WM_CLOSE, 0, 0);
}
[硬體/系統] → 系統訊息佇列
↓ PeekMessage (ProcessMessage)
[Application.OnMessage] → 內部處理 (Hint/MDI/Key/Dialog)
↓ DispatchMessage
[TApplication.WndProc] → [HookMainWindow 掛鉤函數] → 預設處理
↓ DispatchMessage 找到目標視窗
[目標視窗 MainWndProc] → [WndProc] → [Dispatch] → [DefaultHandler]
HookMainWindow,並在 FormDestroy 呼叫 UnhookMainWindowWndProc 或使用訊息對應巨集bool __fastcall (TMessage&)BCB 訊息處理提供從應用層到控制項層的完整攔截能力,開發者可根據需求選擇最適合的切入點。