【问题标题】:Delphi: positioning a form in a dllDelphi:在dll中定位表单
【发布时间】:2011-10-20 08:14:05
【问题描述】:

我正在 dll 中创建一个表单。没有包裹。使用导出的过程调用dll中的表单:

procedure ShowAbout(const AppHandle: THandle); stdcall;
  var
    aHandle: THandle;
    form:  TfrmAbout;  / my form in some other unit in the dll
  begin

    aHandle:= Application.Handle;
    Application.Handle:= AppHandle;

    form :=TfrmAbout.Create(Application);
    form.ShowModal;
    form.Free;
    Application.Handle:= aHandle;
  end;

表格显示良好,没有问题。现在,我唯一想做的就是将定位表现为 poMainFormCenter(我希望它始终显示在主窗体(调用 dll 的窗体)上。

我尝试过使用表单 :=TfrmAbout.Create(Application.MainForm);等等,但没有运气。

有什么技巧可以帮助到这里吗?

【问题讨论】:

  • 你应该传递Application指针而不是仅仅传递窗口句柄。它很粗糙,但不幸的是不能以其他方式工作
  • 绝对不要传递Application指针。您不能将对象从 VCL 的一个实例传递到另一个实例。您需要为此使用运行时包。

标签: forms delphi dll


【解决方案1】:

VCL Position 机制依赖于应用程序中的其他形式,所有这些形式都使用相同版本的 VCL。这显然不是这里的情况,您必须手动定位表单。

通过调用GetWindowRect() 传递主窗体句柄来找出主窗体的位置。然后,您需要确定您的表单需要位于该表单中心的位置。

procedure PositionForm(Form: TForm; MainWindow: HWND);
var
  MainBounds: TRect;
  MainWidth, MainHeight: Integer;
begin
  if GetWindowRect(MainWindow, MainBounds) then
  begin
    MainWidth := MainBounds.Right-MainBounds.Left;
    MainHeight := MainBounds.Bottom-MainBounds.Top;
    Form.Left := MainBounds.Left + (MainWidth - Form.Width) div 2;
    Form.Top := MainBounds.Top + (MainHeight - Form.Height) div 2
  end;

顺便说一句,您传递的句柄是HWND,而不是THandle。您应该相应地更改您的代码。它不会改变行为,但这样做在逻辑上是正确的。

【讨论】:

    【解决方案2】:

    由于你不使用 pacakges,你的 EXE 和你的 DLL 都有一个单独的 TApplication 实例。您的 EXE 中的 TApplication.MainForm 在您的 DLL 中看不到。更改 TApplication.Handle 不会更改 MainForm。找到其他方法来正确定位表单,但更好:使用包,如果不这样做,您会遇到更多问题。

    【讨论】:

    • 有时您需要使用 DLL。例如 Office 加载项。也就是说,如果包能满足你的需求,它们肯定会更干净。
    【解决方案3】:

    您是否尝试过将 form.ParentWindow 设置为父窗口的句柄?您应该将它作为参数传递给 ShowAbout,或者您可以从 Application 对象(类似于 Application.ActiveForm)中挖掘它,但我不确定它是否会起作用。

    调用TfrmAbout.Create(Application.MainForm) 只是指定 Application.MainForm 负责表单的销毁,它应该与窗口层次结构无关,而且我不确定如果您在单独的表单中创建表单,您是否应该使用自动销毁dll。

    【讨论】:

    • 是的,试过了。不幸的是,如果我添加 form.ParentWindow := parentHandle(作为参数传递),表单会挂起并且不显示。
    • 这很奇怪,它应该可以工作。您能否更新您的问题以显示 when 您是否设置了 ParentWindow 属性。另外,您的代码中的aHandle 是什么?你应该只有一个应用句柄。
    • ParentWindow 用于将一个窗体显示为另一个窗体的子窗体。听起来这个问题是关于顶级窗口的。
    • 是的,ParentWindow 似乎是关于别的东西。顺便说一句,aHandle 是在从调用应用程序分配句柄之前存储 dll 中使用的 Forms 单元的应用程序句柄,只是为了在 dll 即将关闭时恢复它。
    • 是的,这和我说的一样。 MSDN 说:“您不能使用 GWL_HWNDPARENT 索引调用 SetWindowLong 来更改子窗口的父级。而是使用 SetParent 函数。”
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-20
    • 2014-05-12
    • 1970-01-01
    相关资源
    最近更新 更多