将非VCL窗口添加到VCL对齐队列中

一些背景(继续 TLabel和TGroupbox Captions Flicker on Resize 的):

  • 所以,我有一个应用程序加载不同的插件并创建一个 每个TPageControl上的新选项卡。
  • 每个DLL都有一个与之关联的TForm。
  • 使用父hWnd创建表单作为新的TTabSheet。 因为就VCL而言,TTabSheets不是表单的父级 有关(不想使用动态RTL和插件制作 其他语言)我必须手动处理调整大小。

对于这种“插件”类型的应用程序,我似乎遇到了很多新问题(但很棒的学习经历)。

因此,我目前的努力是尝试使用一个插件,该插件不会插入到TTabSheet中,但会在表单上直接调整大小并对齐。

因为用图片更容易解释: 现在我可以手动进行对齐和调整大小,但我更愿意为我做VCL对齐程序( alClient,alTop等)。这样我就不必考虑在其表单上设置插件对齐。

在查看VCL源代码后,我开始逐步调整对齐代码及其调用方式。基本上,当TControl获得WM_RESIZE时,它将:

  1. 调用调用AlignControl()
  2. 的Realign()
  3. AlignControl()将获取客户端rect并调用AlignControls()
  4. AlignControls()将按以下顺序为每个TAlignment类型调用DoAlign():alTop,alBottom,alLeft,alRight,alClient,alCustom,alNone
  5. DoAlign()将遍历FControls和FWinControls(是TLists )并将它们正确对齐

所以我的思维过程是,如果我创建一个新的TWinControl,设置它的插件形式(窗口)句柄的句柄,并将其插入FControls列表与正确对齐它应该为我做我的工作。

我当然在这里,所以它失败了。我甚至在退出应用程序时获得了一个关于无效窗口句柄的AV。我的猜测是我创建的TWinControl试图释放不再存在的插件形式( window )的句柄。

我尝试过的:

procedure AddHandleToControlList(AHandle: DWORD; Align: TAlign);
var
  NewWinControl : TWinControl;
begin
  NewWinControl := TWinControl.Create(frmMain);
  NewWinControl.WindowHandle := AHandle;
  NewWinControl.Align := Align;
  NewWinControl.Width := frmMain.ClientWidth;
  NewWinControl.Height := 30;
  NewWinControl.Parent := frmMain;
end;

procedure AddHandleToControlList(AHandle: DWORD; Align: TAlign);
var
  NewWinControl : TWinControl;
begin
  NewWinControl := TWinControl.Create(frmMain);
  NewWinControl.WindowHandle := AHandle;
  NewWinControl.Align := Align;
  NewWinControl.Width := frmMain.ClientWidth;
  NewWinControl.Height := 30;
  TWinControl(frmMain).Insert(NewWinControl);
end;

Soooo,想法?

编辑1:

好吧,所以这正确地将控件添加到列表并符合TAlign设置(为什么我花了8个小时试图解决问题,我在这里发布,然后答案就出现了......哦,有人可能会发现这个问题和我的ramblings有用):

procedure AddHandleToControlList(AHandle: DWORD; AName: PChar; ATop, ALeft, AWidth, AHeight: Integer; AAlign: TAlign);
var
  NewWinControl : TWinControl;
begin
  NewWinControl := TWinControl.Create(frmMain);
  With NewWinControl Do
    begin
    Name := AName;
    Top := ATop;
    Left := ALeft;
    Width := AWidth;
    Height := AHeight;
    Align := AAlign;
    WindowHandle := AHandle;
    Visible := True;
  end;
  TWinControl(frmMain).InsertControl(NewWinControl);
end;

现在的问题是,当应用程序关闭时,我收到无效错误AV ...我会继续!

EDIT 2: Ok, so it is TWinControl.DestroyWindowHandle that raises the AV because the window handle doesn't exist any more. I'm trying to think of a clean solution.

9
额外 编辑
意见: 2

1 答案

TWinControl 派生一个新类,并覆盖其虚拟 DestroyWindowHandle()方法,以免释放您提供的 HWNDTWinControl.DestroyWindowHandle()的默认实现调用Win32 API DestroyWnd()函数。

9
额外
这不是一个黑客。 TWinControl的 CreateWindowHandle()DestroyWindowHandle()方法是故意虚拟的,以允许自定义窗口管理。
额外 作者 Remy Lebeau,
可以+1甜
额外 作者 David Heffernan,
+1哇。我怀疑是否称这是一个黑客或技巧,但地狱,给一个随机窗口控制VCL特性肯定是有用的!谢谢。你们两个!
额外 作者 NGLN,
+1。同意大卫 - 很好!
额外 作者 Ken White,
+1非常好,鲜为人知的事实。
额外 作者 Gregor Brandt,
这是一个比我正在做的更优雅的解决方案!完美,谢谢!
额外 作者 ThievingSix,