我的应用程序可以加载基本上包含另一个窗口应用程序的DLL。
它只能随时打开一个DLL窗口。
我遇到DLL窗口显示消息框和/或我的主应用程序显示消息框或模态窗体的情况,并通过停用应用程序(切换到另一个)然后激活它,移动所有窗口随机(?)z顺序,从而使DLL形式与它的消息框在主窗体后面。主表单消息框位于主表单后面。
这导致无响应的应用程序。不能点击任何东西,不能关闭,不能最小化。必须通过任务管理器杀死。
在Delphi中,我看到有Screen
个对象,它有一个列表Forms
。我检查了它,看到它包含我的应用程序当前打开的所有表单(即使是消息框,这是ShowMessage()
的结果,它没有名称,但我可以看到ClassName
)。
到目前为止它很好,我可以遍历表单并使用SetWindowPos
告诉他们正确的z顺序,但是,我不能为DLL应用程序执行此操作。 Screen
在列表中没有此表单。
如何控制DLL表单的z顺序?
这些DLL是使用Delphi,C ++,WPF构建的。
答案 0 :(得分:4)
您必须按照OS的方式订购窗口(使用句柄)。 DLL的应用程序句柄默认为零,因此您需要在显示模式对话框时定义它。
根据文件Vcl.Forms.TApplication.Handle
:
注意:编写使用VCL表单的DLL时,请将主机EXE主窗口的窗口句柄指定给DLL的全局Application变量的Handle属性。这使得DLL的形式成为宿主应用程序的一部分。永远不要在EXE中分配Handle属性。
要保持dll模态形式的Z顺序,请按下面suggests
下面的Peter:
// In the dll
var
oldWnd: HWND;
begin
oldWnd := Application.Handle;
Application.Handle := HandleOfHostform; // <-- Pass the exe host form handle
try
.... create and show the DLL form
finally
Application.Handle := oldWnd;
end;
end;
应该在没有所有者TMyDllForm.Create(nil)
的情况下创建模态表单。
我不是100%确定Delphi-7正确地以这种方式解析DLL中的句柄。
另一种方法是覆盖表单对象的CreateParams
,如建议here
。
procedure TMyDLLForm.CreateParams(var Params: TCreateParams);
begin
inherited;
Params.WndParent := HandleOfHostForm;
end;