【发布时间】:2022-02-03 23:30:21
【问题描述】:
在项目源中,我检测到我的应用程序的前一个实例,打开它然后终止新实例。
请记住,我在项目源代码中执行此操作。
该应用程序有一个主窗体,可以打开第二个模态窗体。如果应用程序最小化(或用户切换到另一个应用程序)时第二个模态表单未打开,则它可以正常工作。
旧的主窗体打开,新的实例终止。但是,如果第二个模态窗体被最小化,它的父主窗体也被最小化。这是很好的 UI 行为。
尝试通过新实例恢复模态表单时存在问题。我似乎无法恢复模态表单。
我可以恢复主窗体,但是模态窗体仍然有焦点,但被隐藏了。
这可以防止用户对现在可见的主窗体进行任何操作。从用户的角度来看,应用程序已挂起。
模态表单的标题不会改变,因此很容易掌握它。
该应用程序有一个 DataModule,它是首先创建的。在创建 DM 之后,我在项目源中进行所有重复的应用程序测试,但在任何其他表单之前,并且在 Application.Run 之前。
这样可以确保我获取的句柄来自现有的应用程序。
我试过了:
PreviousHandle := FindWindow(nil, PAnsiChar('Form Editor'))
ShowWindow(PreviousHandle,SW_RESTORE);
ShowWindow(PreviousHandle,SW_NORMAL);
BringWindowToTop(PreviousHandle);
我从这个变体中得到的最好的结果是恢复主窗体。
当句柄用于模态表单时,它有时会在左下方显示为最小化表单。
我有时会这么说,因为我已经尝试了上面的很多变体,以至于我不记得这个代码示例的具体表现了。
我所知道的是,无论我从项目源中尝试过什么,都没有恢复模态表单,所以我尝试将自定义 Windows 消息发送到模态表单。
我知道消息到达并且消息处理程序捕获了它。示例:
if not PostMessage(PreviousHandle,WM_RESTORE_FORM,PreviousHandle,0) then
ShowMessage('Can''t automatically show the Form program. '+
'Please click the taskbar icon.');
这是消息处理程序的外观。它是模态形式。如您所见,我将表单的句柄作为 Message 参数传递。我已经确认它到货了。
这是 TApplicationEvents OnMessage 事件中的代码:
procedure TfrmDisplayForm.ApplicationEvents1Message(var Msg: tagMSG;
var Handled: Boolean);
var
oldHwnd : THandle;
begin
if Msg.message = WM_RESTORE_ACORD then
begin
oldHwnd := Msg.lParam;
if ForceForegroundWindow(OldHwnd) then ShowMessage('true') else ShowMessage('False');
Handled := True;
end;
end;
这是被调用的函数。但是,我尝试了各种 ShowWindows(...) 组合,但都没有成功。其实这个函数也没有用。
function TfrmDisplayForm.ForceForegroundWindow(hWnd: THandle): BOOL;
var
hCurWnd: THandle;
begin
{credit Peter Below}
hCurWnd := GetForegroundWindow;
AttachThreadInput(GetWindowThreadProcessId(hCurWnd, nil),
GetCurrentThreadId, True);
Result := SetForegroundWindow(hWnd);
AttachThreadInput(GetWindowThreadProcessId(hCurWnd, nil),
GetCurrentThreadId, False);
end;
我已经为此工作了几天,不知道我做错了什么。 问题:如何恢复模态形式?一定是可以的,因为点击任务栏图标后完美还原。
【问题讨论】: