delphi - TWinControl - 当 WinControl 具有有效句柄时,析构函数之前的最后一个阶段是什么?

标签 delphi delphi-7

就在我的 TCustomWinControl 被永久销毁之前,我需要对其句柄执行一些操作。

如果我尝试在析构函数中访问其句柄,则会收到错误:

"Control "xxx" has no parent window".

那么 TWinControl 析构函数之前的最后一个阶段是什么?其句柄 (HandleAllocation) 仍然有效?

type
  TPanel = class(ExtCtrls.TPanel)
  protected
    procedure DestroyWindowHandle; override;
  public
    procedure BeforeDestruction; override;
  end;

procedure TPanel.DestroyWindowHandle;
begin
  Beep;
  if csDestroying in ComponentState then Beep;      
  inherited;
end;

procedure TPanel.BeforeDestruction;
begin
  if HandleAllocated then Beep;
  inherited;
end;

没有蜂鸣声。

最佳答案

更新

这比我最初想象的要复杂。你的控件存在于一个窗体上,控件的死亡是由该窗体的死亡引起的。当窗体被销毁时,子窗口也会被销毁。因此,Win32 API 负责销毁您的窗口。 VCL 通过响应 WM_NCDESTROY 消息来跟踪这一点:

procedure TWinControl.WMNCDestroy(var Message: TWMNCDestroy);
begin
  inherited;
  FHandle := 0;
  FShowing := False;
end;

所以,我想你可以自己处理WM_NCDESTROY。在 ControlState 中查找 csRecreating,根据窗口销毁是否与 VCL 窗口重新创建相关来切换行为。

这里需要注意的一个有趣的点是,没有理由必须调用控件的析构函数。如果它不属于表单,那么您的控件将不会被破坏。然后您可以将其重新设置为另一个表单的父级。所以 WM_NCDESTROY 确实是正确的钩子(Hook)。


原始答案

析构函数的源代码如下所示:

destructor TWinControl.Destroy;
var
  I: Integer;
  Instance: TControl;
begin
  Destroying;
  if FDockSite then
  begin
    FDockSite := False;
    RegisterDockSite(Self, False);
  end;
  FDockManager := nil;
  FDockClients.Free;
  if Parent <> nil then RemoveFocus(True);
  if FHandle <> 0 then DestroyWindowHandle;
  I := ControlCount;
  while I <> 0 do
  begin
    Instance := Controls[I - 1];
    Remove(Instance);
    Instance.Destroy;
    I := ControlCount;
  end;
  FBrush.Free;
{$IFDEF LINUX}
  if FObjectInstance <> nil then WinUtils.FreeObjectInstance(FObjectInstance);
{$ENDIF}
{$IFDEF MSWINDOWS}
  if FObjectInstance <> nil then Classes.FreeObjectInstance(FObjectInstance);
{$ENDIF}
  inherited Destroy;
end;

对 Win32 API DestroyWindow 的调用是在这一行中进行的:

if FHandle <> 0 then DestroyWindowHandle;

所以你需要在此之前运行你的代码。

您可以重写DestroyWindowHandle并在那里完成您的工作。只要您需要处理的事件是窗口的破坏,那么这种方法就可以很好地工作。但请记住,重新创建窗口时将调用 DestroyWindowHandle

如果您需要执行与 VCL 控件销毁相关的操作,那么您最好重写 BeforeDestruction。或者作为替代方案,您可以重写 DestroyWindowHandle 并在 ComponentState 中测试 csDestroying

关于delphi - TWinControl - 当 WinControl 具有有效句柄时,析构函数之前的最后一个阶段是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27038925/

相关文章:

delphi - 'set of integer' 是什么 Delphi 类型?

delphi - 文件 MD5 校验和

delphi - 是否可以读取未嵌入应用程序的外部资源文件?

performance - 当我关闭 {$IMPORTEDDATA} 时,性能是否有真正的提升?

Delphi 7 - 使用 TIdDecoderMIME 解码 Base64

delphi - 如何绘制 Unicode 文本?

delphi - 使用Delphi + Jedi,设备发送USB数据时丢失 "too fast"

delphi - Delphi中的 "customizable VCL designer guideline"是什么?

excel - Delphi - 更改 Excel 中的图表标题会导致 AV - 使用完整示例进行更新

delphi - Delphi 有没有办法显示垂直缩进线?