【问题标题】:Parent window freezes when child window freezes altough it's from another process当子窗口冻结时父窗口冻结,尽管它来自另一个进程
【发布时间】:2013-05-24 21:41:19
【问题描述】:

免责声明:我不熟悉 Win32 API,尤其是 windows 的工作原理。

我想让某个进程的窗口成为另一个进程的子窗口。这两个进程也是父进程和子进程。但我认为这并不重要。到目前为止,一切都像一个魅力 - 直到我冻结子窗口的主线程。

想象一个“托管”notepad.exe 和 someApplication.exe 的 container.exe

当我暂停 someApplication.exe 的主线程几秒钟时,它的窗口在这段时间内被冻结。这是完全可以理解的。但是container.exe的窗口会同时挂起。其他托管进程(如 notepad.exe)的子窗口将继续正常工作。

我正在使用SetParent 命令将常规非子窗口作为我的 container.exe 的子窗口:

SetParent(
    childProcess.HWND,
    myOwnHWND
);

之后,我使用setWindowPos

SetWindowPos(
    childProcess.HWND,
    HWND_TOP,
    someXPos,
    someYPos,
    0,
    0,
    SWP_FRAMECHANGED or SWP_NOSIZE or SWP_SHOWWINDOW
)

正如MSDN article on SetParent 建议的那样,我还清除了WS_POPUP 样式属性并添加了WS_CHILD 属性。由于这也没有帮助,我还添加了一个WS_EX_NOACTIVATE 扩展样式属性,两者都使用SetWindowLongPtr 命令。最后,我尝试向两个窗口发送 WM_UPDATEUISTATEWM_CHANGEUISTATE 消息,但这也没有改变。

让我感到困惑的是,父进程的窗口继续正常绘制,直到我触摸它。然后它完全冻结,直到子窗口解冻。我怀疑有一个叫做'输入队列'的东西。关于WM_ACTIVATE 消息的MSDN article 声明:

发送到正在激活的窗口和正在停用的窗口。如果窗口使用相同的输入队列,则消息同步发送,首先发送到被停用的顶层窗口的窗口过程,然后发送到顶层窗口的窗口过程顶层窗口被激活。如果窗口使用不同的输入队列,消息是异步发送的,所以窗口立即被激活。

因此,我对 WS_EX_NOACTIVATE 扩展样式属性寄予厚望。

总结一下:实际上是否可以托管另一个进程的窗口,并且在子窗口冻结时不冻结自己的窗口?

【问题讨论】:

标签: delphi winapi window


【解决方案1】:

您不能期望阻塞任何进程的 GUI 线程。在您的场景中,事情有点复杂,因为有两个 GUI 线程。每个进程一个。

但是,通过在这些进程的窗口之间建立父/子关系,您还引入了两个 GUI 线程都得到及时服务的要求。

处于父/子关系的 Windows 将相互发送消息。如果这些消息是同步的,即发送而不是发布,那么阻塞一个 GUI 线程将导致另一个被阻塞。

GUI 编程的黄金法则仍然有效:不要阻塞 GUI 线程。如果您有一个长时间运行的任务,请将其移至后台线程。

更新

好的,正如here 解释的那样,当您关联来自不同线程的窗口时,您将它们的消息队列彼此附加。因此,如果你阻塞了一个线程,就会阻塞所有附加的线程。

所以,不要阻塞 GUI 线程。

【讨论】:

  • 谢谢。当然,不应阻塞 GUI 线程。但是,我正在测试最坏的情况,例如 hosted 应用程序完全冻结。在这种情况下,主机应用程序可能不会冻结。另外,我仍然想知道父/子进程关系如何在这里发挥作用。如果子进程窗口不是父进程窗口的子进程,后者当然不会冻结。所以他们不能真正发送消息。
  • "如果子进程窗口不是父进程窗口的子进程,后者当然不会冻结。"您对 SetParent 的调用使一个窗口成为另一个窗口的子窗口。 “他们不可能真的在发送信息。”为什么不?整个 Windows GUI 是基于消息的。这绝对是窗户的作用。如果阻塞了一个 GUI 线程,那么你的 GUI 会失败。
  • 所以关键是两个窗口现在使用相同的输入队列。核心问题在于将WM_ACTIVATE 消息同步发送到冻结窗口。这是另一个涵盖完全相同主题的新闻组帖子:Link。由于我不希望能够使用AttachThreadInput 命令之类的东西分离子窗口输入队列,因此我接受这个作为答案并在没有父母/孩子的情况下过上幸福的生活窗口关系。非常感谢!
  • 即使没有队列依赖,发送消息也会害死你。从另一个进程托管窗口是危险的事情。
  • “当您关联来自不同线程的窗口时,您会将它们的消息队列彼此附加” - 这实际上是输入队列,正如您发布的 link 中所解释的那样。另外,同步发送消息并不是什么大问题。线程可以在等待出站发送消息返回时分派入站发送消息 (When can a thread receive window messages?)。
猜你喜欢
  • 2016-04-29
  • 1970-01-01
  • 2020-05-25
  • 2013-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-26
  • 2018-10-31
相关资源
最近更新 更多