窗口的创建过程中用到了CreateHandle CreateParams CreateWnd,具体过程如下:
1、TCustomForm.Create
在 TCustomForm.Create 中调用 TCustomForm.CreateNew;
2、TCustomForm.CreateNew;
调用 FCanvas := TControlCanvas.Create;
触发 TControlCanvas.Create;
触发 TControlCanvas.CreateHandle;
3、TControlCanvas.CreateHandle;
调用 FControl.GetDeviceContext(FWindowHandle);
即 TWinControl.GetDeviceContext(FWindowHandle);
4、TWinControl.GetDeviceContext(FWindowHandle);
调用 TWinControl.GetDC(Handle);
此处说明一下:
对 TWinControl 的 Handle 属性的读取会触发 TWinControl.GetHandle;
可以察看 Property Handle; 的声明。
5、第四步中对 Handle 进行读取,触发下述序列:(TWinControl)
Handle->GetHandle->HandleNeeded
6、TWinControl.HandleNeeded 检查 FHandle 的值:
if FHandle = 0 then
begin
if Parent <> nil then Parent.HandleNeeded;
CreateHandle; // 调用 CreateHandle;
end;
7、TWinControl.CreateHandle
调用 CreateWnd;
if FHandle = 0 then // 此时 FHandle 仍然为零
begin
CreateWnd;
...
end;
8、TWinControl.CreateWnd
调用 CreateParams(Params);
// 让用户有机会加入新的特征参数
CreateParams(Params);
with Params do
begin
...
// 标准的 API 使用,注册窗口类,CreateWindowEx ...
if Windows.RegisterClass(WindowClass) = 0 then RaiseLastWin32Error;
...
CreateWindowHandle(Params);
...
end;
9、CreateWindowHandle(Params);
FHandle := CreateWindowEx(ExStyle, WinClassName, Caption, Style,
X, Y, Width, Height, WndParent, 0, WindowClass.hInstance, Param);
完成真正的窗口创建,并赋予 FHandle 窗口句柄。
10、回到第一步
CreateNew 之后调用 DoCreate
try
CreateNew(AOwner);
...
if OldCreateOrder then DoCreate;
finally
...
end;
11、DoCreate
调用用户的 OnCreate 事件:
if Assigned(FOnCreate) then
try
FOnCreate(Self); // 调用 OnCreate;
except
Application.HandleException(Self);
end;
if fsVisible in FFormState then Visible := True;
补充一点:
其他的控件比如 TEdit 等都是 TWinControl 的子孙,构造的顺序都差不多,
关键的一点是:
对 TWinControl.Handle 属性的第一次访问会触发对窗口句柄的真正创建。
即:Handle->GetHandle->HandleNeeded
关于这一点,可以察看 Delphi Help->HandleAllocated 方法的注解。
上文只是剖析了 TForm 的构造过程,其它类似控件可能有所差别,其它控件并不
一定是在构造 TControlCanvas 时才第一次访问 TWinControl.Handle 的,也许
是在其他地方,不过没有必要都写出来。
From: BaKuBaKu大侠