如何跨进程管理前台窗口?

时间:2012-02-22 11:36:21

标签: delphi window ipc delphi-2007 foreground

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

  • 主人(包含TMasterMainFormTMasterModalForm
  • 奴隶(包含TSlaveForm

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

  1. Master已启动并显示TMasterMainForm
  2. 用户可以通过点击TMasterMainForm中的按钮来运行从属设备。
  3. Master启动Slave进程。
  4. Slave显示TSlaveForm
  5. Master将TForm.Handle TMasterMainForm发送给Slave。 (通过IPC = WM_COPYDATA)
  6. 完成步骤5,以便当Slave关闭时,它可以将前景窗口设置回TMasterMainForm。这样做是为了改善用户体验。

    在我们介绍TMasterModalForm之前,这很好。

    TMasterModalForm可以使用TMasterMainForm中的其他按钮启动。它是一个单独的窗口,但是以模态显示,并且TMasterMainForm作为其显式弹出父级。

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

    所以问题是:

    如何管理在这种非常重要的情况下设置前景窗口?

    PS:这是一个简化的描述,真正的应用程序也在做这个前台窗口的东西。

2 个答案:

答案 0 :(得分:5)

您无法将前景窗口设置为主主窗体,因为它已被禁用。它被禁用,因为您正在显示一个模式表单,其所有者是主表单。

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

更优雅的解决方案是让主应用程序调用{​​{1}}。事实上,从主进程调用SetForegroundWindow可能更简单。当然,从属进程仍然需要向主服务器发送消息以便调用它。拼图中的最后一部分是处理焦点窃取限制,但你可以使用AllowSetForegroundWindow来做到这一点。您需要从属进程调用此方法来传递主进程的ID。

答案 1 :(得分:3)

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

PS:您不需要WM_COPYDATA来发送句柄。你可以直接传入你组成的任何消息的WParam或LParam。这就像我上面解释的那样发送回句柄,但也适用于首先发送给从站的句柄。