windows消息的結構
TMsg = packed record
hwnd: HWND;//窗口句柄
message: UINT;//消息標識
wParam: WPARAM;//
lParam: LPARAM;//
time: DWORD;//消息創建的時間
pt: TPoint;//消息創建時鼠標所在位置
end;
WM_KEYDOWN,WM_KEYUP, WM_KEYPRESS: KEYPress消息不同之處在於只有對應有ascii碼的按鍵纔會產生這個消息
windows消息流程
1.系統中產生事件
2.windows把這個事件翻譯成消息,並放入消息隊列
3.應用程序從消息隊列中接收到這個消息,把它放到TMsg記錄中
4.應用程序把消息傳遞給一個適當的窗口的窗口過程
5.窗口過程響應這個消息並處理
步驟3,4就構成了應用程序的消息循環。
delphi把windows的TMsg記錄中的信息映射爲TMessage記錄:
TMessage = record
Msg: Cardinal;
case Integer of
0:( WParam: LongInt;
LParam: LongInt;
Result: LongInt);
1:( WParamLo: Word;
WParamHi: Word;
LParamLo: Word;
LParamHi: Word;
ResultLo: Word;
ReslutHi: Word);
end;
除此之外,delphi爲每個windows消息定義了一個特殊的消息記錄,方便使用,例如一個鼠標消息:
TWMMoust = record
Msg: Cardinal;
Keys: LongInt;
case: Integer of
0:(XPos, YPos: SamllInt);
1:(Pos: TSmallPoint; Result: LongInt);
end;
MessageBeep(): 窮人的調試器
對消息中的Result賦值:
典型的例子是WM_CTLCOLOR,處理這個消息時,windows期望返回一個畫刷的句柄,
所以需要在消息處理之後對result賦值
procedure TFrom1.WMCtlColor(var Msg: TWMCtlColor);
var
BrushHand: hBrush;
begin
inherited;
// todo: 創建一個畫刷,放入BrushHand
Msg.Result := BrushHand;
end;
Application.OnMessage
OnMessage相應的是從消息隊列中檢索到的消息,所以SendMessage發送的消息會繞過消息隊列,就不會觸發OnMessage事件
子類化
用自己的窗口過程代替Application的窗口過程,當在自己的窗口過程處理完成呢過後,把消息再傳遞給原窗口。這個過程就叫 子類化
1.使用SetWindowLong()來指定與i個新的窗口過程:
聲明:
function NewWndProc(Handle: hWnd; Msg, WParam, LParam: LongInt): Longint; stdcall;
使用OldWndProc := Pointer(SetWindowLong(Application.Handle, gwl_WndProc, Integer(@NewWndProc)));
來設置。
2.也可以使用Delphi方法來代替上面的NewWndProc
需要使用MakeObjectInstance()來處理一下這個delphi的方法
NewProc := MakeObjectInstance(self.NewWndProc);
OldWProc := Pointer(SetWindowLong(Application.Handle, GWL_WNDPROC, Integer(NewProc)));
3.HookMainWindow()
這個函數能把一個自定義的消息處理過程插入到TApplication的WndProc方法之前