娃娃鸭深入核心VCL架构剖析(李维)笔记

 

35TApplication创建的主窗体

Application.CreateForm(TForm1, Form1);

procedure TApplication.CreateForm(InstanceClass: TComponentClass; var Reference);

var

  Instance: TComponent;

begin

  Instance := TComponent(InstanceClass.NewInstance);

  TComponent(Reference) := Instance;

  try

    Instance.Create(Self);

  except

    TComponent(Reference) := nil;

    raise;

  end;

  if (FMainForm = nil) and (Instance is TForm) then

  begin

    TForm(Instance).HandleNeeded;

    FMainForm := TForm(Instance);

  end;

end;

 

constructor TWinControl.Create(AOwner: TComponent);

begin

  inherited Create(AOwner);

{$IFDEF LINUX}

  FObjectInstance := WinUtils.MakeObjectInstance(MainWndProc);

{$ENDIF}

{$IFDEF MSWINDOWS}

  FObjectInstance := Classes.MakeObjectInstance(MainWndProc);

  //设置回调函数

{$ENDIF}

  FBrush := TBrush.Create;

  FBrush.Color := FColor;

  FParentCtl3D := True;

  FTabOrder := -1;

  FImeMode := imDontCare;

  if SysLocale.PriLangID = LANG_JAPANESE then

    FImeName := ''

  else

    FImeName := Screen.DefaultIme;

  FUseDockManager := False;

  FBevelEdges := [beLeft, beTop, beRight, beBottom];

  FBevelInner := bvRaised;

  FBevelOuter := bvLowered;

  FBevelWidth := 1;

  FHelpType := htContext;

end;

 

constructor TControl.Create(AOwner: TComponent);

begin

  inherited Create(AOwner);

  FWindowProc := WndProc;

end;

 

TControl = class(TComponent)

  private

    FParent: TWinControl;

FWindowProc: TWndMethod;

end;

 

procedure TWinControl.MainWndProc(var Message: TMessage);

begin

  try

    try

      WindowProc(Message);

    finally

      FreeDeviceContexts;

      FreeMemoryContexts;

    end;

  except

    Application.HandleException(Self);

  end;

end;

 

申明:

procedure MainWndProc(var Message: TMessage);

不希望程序员覆盖,但是可以覆盖WindowProc方法。

TWinCtrol=class(TControl)

procedure WndProc(var Message: TMessage); override;

end;

TForm(Instance).HandleNeeded;

其实调用的是TWinControl.HandleNeeded;

procedure TWinControl.HandleNeeded;

begin

  if FHandle = 0 then

  begin

    if Parent <> nil then Parent.HandleNeeded;

    CreateHandle;

  end;

end;

 

procedure TWinControl.CreateHandle;

var

  I: Integer;

begin

  if FHandle = 0 then

  begin

    CreateWnd;

    SetProp(FHandle, MakeIntAtom(ControlAtom), THandle(Self));

    SetProp(FHandle, MakeIntAtom(WindowAtom), THandle(Self));

    if Parent <> nil then

      SetWindowPos(FHandle, Parent.PrecedingWindow(Self), 0, 0, 0, 0,

        SWP_NOMOVE + SWP_NOSIZE + SWP_NOACTIVATE);

    for I := 0 to ControlCount - 1 do

      Controls[I].UpdateAnchorRules;

  end;

end;

procedure TCustomForm.CreateWnd;

var

  ClientCreateStruct: TClientCreateStruct;

begin

  inherited CreateWnd;

  if NewStyleControls then

    if BorderStyle <> bsDialog then

      SendMessage(Handle, WM_SETICON, 1, GetIconHandle) else

      SendMessage(Handle, WM_SETICON, 1, 0);

  if not (csDesigning in ComponentState) then

    case FormStyle of

      fsMDIForm:

        begin

          with ClientCreateStruct do

          begin

            idFirstChild := $FF00;

            hWindowMenu := 0;

            if FWindowMenu <> nil then hWindowMenu := FWindowMenu.Handle;

          end;

          FClientHandle := Windows.CreateWindowEx(WS_EX_CLIENTEDGE, 'MDICLIENT',

            nil, WS_CHILD or WS_VISIBLE or WS_GROUP or WS_TABSTOP or

            WS_CLIPCHILDREN or WS_HSCROLL or WS_VSCROLL or WS_CLIPSIBLINGS or

            MDIS_ALLCHILDSTYLES, 0, 0, ClientWidth, ClientHeight, Handle, 0,

            HInstance, @ClientCreateStruct);

{$IFDEF LINUX}

          FClientInstance := WinUtils.MakeObjectInstance(ClientWndProc);

{$ENDIF}

{$IFDEF MSWINDOWS}

          FClientInstance := Classes.MakeObjectInstance(ClientWndProc);//设置回调函数

{$ENDIF}

          FDefClientProc := Pointer(GetWindowLong(FClientHandle, GWL_WNDPROC));

          SetWindowLong(FClientHandle, GWL_WNDPROC, Longint(FClientInstance));

        end;

      fsStayOnTop:

        SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or

          SWP_NOSIZE or SWP_NOACTIVATE);

    end;

end;

 

TWincontrol=class(TControl)

    procedure CreateWnd; virtual;

end;

 

procedure TWinControl.CreateWnd;

var

  Params: TCreateParams;

  TempClass: TWndClass;

  ClassRegistered: Boolean;

begin

  CreateParams(Params);//设定窗口注册属性,虚拟方法

  with Params do

  begin

    if (WndParent = 0) and (Style and WS_CHILD <> 0) then

      if (Owner <> nil) and (csReading in Owner.ComponentState) and

        (Owner is TWinControl) then

        WndParent := TWinControl(Owner).Handle

      else

        raise EInvalidOperation.CreateFmt(SParentRequired, [Name]);

    FDefWndProc := WindowClass.lpfnWndProc;

    ClassRegistered := GetClassInfo(WindowClass.hInstance, WinClassName, TempClass);

    if not ClassRegistered or (TempClass.lpfnWndProc <> @InitWndProc) then

    begin

      if ClassRegistered then Windows.UnregisterClass(WinClassName,

        WindowClass.hInstance);

      WindowClass.lpfnWndProc := @InitWndProc;

      WindowClass.lpszClassName := WinClassName;

      if Windows.RegisterClass(WindowClass) = 0 then RaiseLastOSError;

    end;

    CreationControl := Self;

    CreateWindowHandle(Params);

    if FHandle = 0 then

      RaiseLastOSError;

    if (GetWindowLong(FHandle, GWL_STYLE) and WS_CHILD <> 0) and

      (GetWindowLong(FHandle, GWL_ID) = 0) then

      SetWindowLong(FHandle, GWL_ID, FHandle);

  end;

  StrDispose(FText);

  FText := nil;

  UpdateBounds;

  Perform(WM_SETFONT, FFont.Handle, 1);

  if AutoSize then AdjustSize;

end;

 

procedure TWinControl.CreateWindowHandle(const Params: TCreateParams);

begin

  with Params do

    FHandle := CreateWindowEx(ExStyle, WinClassName, Caption, Style,

      X, Y, Width, Height, WndParent, 0, WindowClass.hInstance, Param);

end;

 

TWinControl = class(TControl)

  procedure CreateParams(var Params: TCreateParams); virtual;

end;

 

 

36InitWndProc函数

InitWndProc被设定为主窗体创建的窗口控件的回调函数,最终窗口消息处理函数却是VCL类方法,所以InitWndProc一定需要进行转换的工作,让窗口的回调函数能够正确到达主窗体的窗口消息处理函数MainWndProc

function InitWndProc(HWindow: HWnd; Message, WParam,

  LParam: Longint): Longint;

{$IFDEF LINUX}

type

  TThunkProc = function (HWindow: HWnd; Message, WParam, LParam: Longint): Longint stdcall;

var

  WinControl: TWinControl;

{$ENDIF}

begin

  CreationControl.FHandle := HWindow;

  SetWindowLong(HWindow, GWL_WNDPROC,

    Longint(CreationControl.FObjectInstance));//改变主窗体的回调函数

  if (GetWindowLong(HWindow, GWL_STYLE) and WS_CHILD <> 0) and

    (GetWindowLong(HWindow, GWL_ID) = 0) then

    SetWindowLong(HWindow, GWL_ID, HWindow);

  SetProp(HWindow, MakeIntAtom(ControlAtom), THandle(CreationControl));

  SetProp(HWindow, MakeIntAtom(WindowAtom), THandle(CreationControl));

{$IFDEF LINUX}

  WinControl := CreationControl;

  CreationControl := nil;

  Result := TThunkProc(WinControl.FObjectInstance)(HWindow, Message, WParam, LParam);

{$ENDIF}

 

  asm

        PUSH    LParam

        PUSH    WParam

        PUSH    Message

        PUSH    HWindow //开始窗口的Pascal调用惯例转换成调用类方法的stdcall调用惯例

        MOV     EAX,CreationControl

        MOV     CreationControl,0

        CALL    [EAX].TWinControl.FObjectInstance //调用

        MOV     Result,EAX

  end;

 

end;

 

37CreateWindowHandle方法

procedure TCustomForm.CreateWindowHandle(const Params: TCreateParams);

var

  CreateStruct: TMDICreateStruct;

  NewParams: TCreateParams;

begin

  if (FormStyle = fsMDIChild) and not (csDesigning in ComponentState) then

  begin

    if (Application.MainForm = nil) or

      (Application.MainForm.ClientHandle = 0) then

      raise EInvalidOperation.Create(SNoMDIForm);

    with CreateStruct do

    begin

      szClass := Params.WinClassName;

      szTitle := Params.Caption;

      hOwner := HInstance;

      X := Params.X;

      Y := Params.Y;

      cX := Params.Width;

      cY := Params.Height;

      style := Params.Style;

      lParam := Longint(Params.Param);

    end;

    WindowHandle := SendMessage(Application.MainForm.ClientHandle,

      WM_MDICREATE, 0, Longint(@CreateStruct));

    Include(FFormState, fsCreatedMDIChild);

  end else

  begin

    NewParams := Params;

    NewParams.ExStyle := NewParams.ExStyle and not WS_EX_LAYERED;

    inherited CreateWindowHandle(NewParams);

    Exclude(FFormState, fsCreatedMDIChild);

  end;

  SetLayeredAttribs;

end;

 

procedure TWinControl.CreateWindowHandle(const Params: TCreateParams);

begin

  with Params do

    FHandle := CreateWindowEx(ExStyle, WinClassName, Caption, Style,

      X, Y, Width, Height, WndParent, 0, WindowClass.hInstance, Param);

end;

 

38、小结

方法名称

说明

InitWndProc

VCL Framework中转换窗体窗口回调函数的轴心程序。InitWndProc会重新设定窗体封装的窗口控件的回调函数为MakeObjectInstance封装的类方法。

MainWndProc

窗体对象的窗口消息处理函数,但是实际上会调用虚拟方法WndProc来处理窗口消息

WndProc

虚拟方法,真正处理窗口消息的处理函数

CreateParams

虚拟方法,设定窗口类属性信息

CreateWindowHandle

虚拟方法,调Windows API CreateWindowEx创建封装性的原生窗口控件。

 

VCL(Visual Component Library)是Delphi编程语言中的一个重要特性,它是一个层次化的组件库,用于构建用户界面和应用程序的交互逻辑。VCL架构核心是一系列基础组件,这些组件包括窗体、按钮、标签等常用控件,以及数据访问、图形绘制等功能模块。 VCL架构设计十分灵活,能够满足各种应用程序开发的需求。其核心思想是面向对象编程(OOP),通过组合和继承来构建复杂的控件和功能模块。 VCL框架可以分为两个主要层次:可视化层和非可视化层。可视化层负责处理用户界面的显示和交互,而非可视化层则处理底层的逻辑和数据操作。 在可视化层中,VCL使用窗体作为最基础的容器,并提供了一系列的控件用于用户界面的构建和展示。这些控件通过事件机制实现与用户的交互,并通过属性设置来调整外观和行为。 在非可视化层中,VCL提供了许多功能模块,例如数据访问模块(如数据库连接和查询),图形绘制模块(如图表和图像处理),以及网络通信模块等。这些模块通过封装底层API和算法,为开发者提供了便利的功能接口。 在VCL架构中,还有一个重要的特性是可视化设计器(IDE),它提供了开发者友好的图形界面,用于快速创建和编辑界面和逻辑。开发者可以通过拖放和属性设置等方式来构建复杂的界面和控制流程,从而快速实现应用程序的开发和调试。 总的来说,VCL架构是一种灵活而强大的开发框架,能够帮助开发者快速构建高效、易用的应用程序。通过深入核心vcl架构剖析,开发者可以更好地理解和应用VCL框架,提高开发效率和程序质量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值