如何跨流程管理前台窗口



我有两个项目,它们作为单独的进程运行,但属于同一个应用程序:

  • Master(包含TMasterMainFormTMasterModalForm
  • 从(包含TSlaveForm

使用此应用程序的典型方式如下:

  1. Master启动并显示TMasterMainForm
  2. 用户可以通过点击TMasterMainForm中的一个按钮来运行从机
  3. Master启动Slave进程
  4. Slave显示TSlaveForm
  5. Master向Slave发送TMasterMainFormTForm.Handle。(通过IPC=WM_COPYDATA)

完成步骤5,使得当Slave关闭时,它可以将前景窗口设置回TMasterMainForm。这样做是为了改善用户体验。

在我们引入TMasterModalForm之前,这一直很有效。

可以使用CCD_ 12中的另一个按钮来启动CCD_。它是一个单独的窗口,但显示为模态,并将TMasterMainForm作为其显式弹出父窗口。

现在,当TSlaveForm关闭时,从应用程序在TMasterMainForm的句柄上调用SetForegroundWindow,但这不再正确,因为它上面有一个模态形式(TMasterModalForm)。

所以问题是:

在这种不重要的情况下,我该如何设置前台窗口?

附言:这是一个简化的描述,真正的应用程序也在以另一种方式做前台窗口的事情。

不能将前台窗口设置为主窗体,因为它已被禁用。它被禁用,因为您正在显示一个所有者是主窗体的模态窗体。

显而易见的解决方案是将前台窗口设置为模式窗口,而不是主窗口。由于您的从属应用程序可能无法轻易知道哪个窗口是活动的,因此您应该重新使用IPC,允许从属应用程序询问主应用程序哪个窗口是活动的,然后将其设置为前台窗口。

一个更优雅的解决方案是让主应用程序调用SetForegroundWindow。事实上,只从主进程调用Application.BringToFront可能会更简单。当然,从进程仍然需要向主进程发送一条消息才能调用它。难题的最后一块是处理焦点窃取限制,但您可以使用AllowSetForegroundWindow来做到这一点。您需要您的从属进程通过主进程的ID来调用它。

为了解决您的问题,我不会从从属应用程序调用SetForegroundWindow,而是向主应用程序发送自定义激活消息。在该消息中,您可以在WParam或LParam中传递所需的句柄。主应用程序本身可以确定它是否可以激活该句柄,或者是否需要激活模态形式。您将激活正确窗口的责任放在了应用程序本身。

PS:您不需要WM_COPYDATA来发送句柄。你可以在WParam或LParam中传递你编造的任何消息。正如我上面解释的那样,这将用于发送回句柄,但也适用于首先发送到从属对象的句柄。

最新更新