下面我们来看看GetText源码: function TControl.GetText: TCaption; var Len: Integer; begin Len := GetTextLen;//得到文本长度 SetString(Result, PChar(nil), Len);// 设置Result返回以Len指定的长度 if Len <> 0 then GetTextBuf(Pointer(Result), Len + 1);//长度不为空,Result得到文本数据 end;
回到GetText函数,其中GetTextLen的作用是得到文本长度,GetTextBuf得到文本数据。 SetText就更简单了,定义如下: procedure TControl.SetText(const Value: TCaption); begin if GetText <> Value then SetTextBuf(PChar(Value)); end; 意思是如果设定的Value与原来的不同,则重新设置缓存文本。
为了更深入VCL底部,我们再看看GetTextLen如何实现的(其实SetTextBuf和GetTextLen的实现过程相似): function TControl.GetTextLen: Integer; begin Result := Perform(WM_GETTEXTLENGTH, 0, 0);//WM_派发的是WINDOWS标准消息 end; 看到这里想必大家都明白了,如果还不明白(没用过Perform),我看再看看Perform,它到底做了什么: function TControl.Perform(Msg: Cardinal; WParam, LParam: Longint): Longint; var Message: TMessage; Begin {你的消息赋予TMessage } Message.Msg := Msg; ; Message.WParam := WParam; Message.LParam := LParam; Message.Result := 0;//0表示返回不处理 if Self <> nil then WindowProc(Message);//不为空,将消息交给TControl的窗口过程WindowProc处理 Result := Message.Result;//返回结果 end; 这里主要再看看WindowProc做了什么,TControl里面WindowProc是这样定义的: property WindowProc: TWndMethod read FWindowProc write FWindowProc; 在TControl的Create函数中: constructor TControl.Create(AOwner: TComponent); begin inherited Create(AOwner); FWindowProc := WndProc; 。。。。。。 可见我们还要找到TControl 的WndProc过程才能明白究竟, WndProc过程定义如下: procedure WndProc(var Message: TMessage); override; 实现: procedure TControl.WndProc(var Message: TMessage); var Form: TCustomForm; KeyState: TKeyboardState; WheelMsg: TCMMouseWheel; begin if (csDesigning in ComponentState) then begin Form := GetParentForm(Self); if (Form <> nil) and (Form.Designer <> nil) and Form.Designer.IsDesignMsg(Self, Message) then Exit end; if (Message.Msg >= WM_KEYFIRST) and (Message.Msg <= WM_KEYLAST) then begin Form := GetParentForm(Self); if (Form <> nil) and Form.WantChildKey(Self, Message) then Exit; end else if (Message.Msg >= WM_MOUSEFIRST) and (Message.Msg <= WM_MOUSELAST) then begin if not (csDoubleClicks in ControlStyle) then case Message.Msg of WM_LBUTTONDBLCLK, WM_RBUTTONDBLCLK, WM_MBUTTONDBLCLK: Dec(Message.Msg, WM_LBUTTONDBLCLK - WM_LBUTTONDOWN); end; case Message.Msg of WM_MOUSEMOVE: application.HintMouseMessage(Self, Message); WM_LBUTTONDOWN, WM_LBUTTONDBLCLK: begin if FDragMode = dmAutomatic then begin BeginAutoDrag; Exit; end; Include(FControlState, csLButtonDown); end; WM_LBUTTONUP: Exclude(FControlState, csLButtonDown); else with Mouse do if WheelPresent and (RegWheelMessage <> 0) and (Message.Msg = RegWheelMessage) then begin GetKeyboardState(KeyState); with WheelMsg do begin Msg := Message.Msg; ShiftState := KeyboardStateToShiftState(KeyState); WheelDelta := Message.WParam; Pos := TSmallPoint(Message.LParam); end; MouseWheelHandler(TMessage(WheelMsg)); Exit; end; end; end else if Message.Msg = CM_VISIBLECHANGED then with Message do SendDockNotification(Msg, WParam, LParam); Dispatch(Message);//派发消息 end; 这里主要讲讲Dispatch方法,它根据传入的消息调用消息的句柄方法,如果在组件类和它的父类都没有找到消息的处理句柄,Dispatch方法便会调用Defaulthandler(默认的消息处理方法),如下: procedure TObject.Dispatch(var Message); asm PUSH ESI MOV SI,[EDX] OR SI,SI JE @@default CMP SI,0C000H JAE @@default PUSH EAX MOV EAX,[EAX] CALL GetDynaMethod POP EAX JE @@default MOV ECX,ESI POP ESI JMP ECX
@@default: POP ESI MOV ECX,[EAX] JMP DWord PTR [ECX] + VMTOFFSET TObject.DefaultHandler//调用默认的消息处理方法 end; 而默认的消息处理如下,在SYSTEM.PAS单元里: procedure TObject.DefaultHandler(var Message); begin end; 由以上代码看好像是没有任何处理过程,跟踪Object.DefaultHandler的汇编执行动作call dword ptr[ecx-$10],即调用Object.DefaultHandle,看看做何处理: {Object.DefaultHandle} Ret Lea eax,[eax+$00] 即一个返回处理!