Parent window freezes when child window freezes altough it's from another process
Asked Answered
D

1

26

Disclaimer: I'm not familiar with the Win32 API, especially how windows work.

I'd like to make the window of some process a child window of another process. The two processes are also parent and child. But I don't think that matters. So far, everything works like a charm - Until I freeze the main thread of the child window.

Imagine a container.exe that 'hosts' notepad.exe and someApplication.exe

When I suspend the main thread of someApplication.exe for a few seconds, its window is frozen for that amount of time. That's perfectly understandable. But the window of container.exe will also hang for the same time. The child windows of other hosted processes (like notepad.exe) will continue to work fine.

I am using the SetParent command to make a regular non-child window a child of my container.exe:

SetParent(
    childProcess.HWND,
    myOwnHWND
);

After that, I'm using setWindowPos:

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

As the MSDN article on SetParent suggests, I also clear the WS_POPUP style attribute and add a WS_CHILD attribute. Since that didn't help either, I also added a WS_EX_NOACTIVATE extended style attribute, both by using the SetWindowLongPtr command. Finally, I tried sending both windows a WM_UPDATEUISTATE and then a WM_CHANGEUISTATE message but that also didn't change a thing.

The thing that confuses me is that the window of the parent process continues to be drawn normally, until I touch it. Then it freezes completely until the child window unfreezes. I suspect something called an 'input queue'. The MSDN article about a WM_ACTIVATE message states:

Sent to both the window being activated and the window being deactivated. If the windows use the same input queue, the message is sent synchronously, first to the window procedure of the top-level window being deactivated, then to the window procedure of the top-level window being activated. If the windows use different input queues, the message is sent asynchronously, so the window is activated immediately.

Because of that, I had high hopes for the WS_EX_NOACTIVATE extended style attribute.

To sum it up: Is actually possible to host the window of another process and to not freeze your own window when the child window freezes?

Domela answered 29/5, 2013 at 14:49 Comment(5)
+1 This question is incredibly thorough.Yoghurt
Related reading: Is it legal to call have a cross-process parent/child or owner/owned window relationship?Therein
Why do you need to do this? I'm sure there are better and easier way to achieve your actual purpose. Don't fall into the XY problem trap.Hysterics
@GSerg: exactly the link I wanted to post. By binding Windows from two or more processes in a parent/child fashion, you bind the input queues of them. If you then block any of the input queues, all of the Windows get blocked.Yuu
See #40526384Arratoon
W
18

You cannot expect to block the GUI thread of any process. In your scenario things are a little more complex because there are two GUI threads. One for each process.

However, by establishing a parent/child relationship between windows of these processes you are also introducing a requirement that both GUI threads are serviced in good time.

Windows that are in a parent/child relationship will send each other messages. And if those messages are synchronous, that is sent rather than posted, then blocking one GUI thread will lead to the other being blocked.

The golden rule of GUI programming remains in force: do not block a GUI thread. If you have a long running task, then move it onto a background thread.

Update

OK, as explained here when you relate windows from different threads you attach their message queues to each other. And so if you block one thread, you block all of the attached threads.

So, don't block a GUI thread.

Winton answered 29/5, 2013 at 15:22 Comment(5)
Thank you. Of course a GUI thread should not be blocked. I am however testing a worst case scenario, like the hosted application totally freezing. In this case, the host application simply MAY NOT freeze. Also, I still wonder how parent/child process relationship comes into play here. If the child process window is not a child of the parent process window, the latter of course won't freeze. So they can't be really sending messages.Logger
"If the child process window is not a child of the parent process window, the latter of course won't freeze." Your call to SetParent makes one window be a child of the other. "They can't really be sending messages." Why not? The entire Windows GUI is message based. It's absolutely what windows do. If block a GUI thread, expect your GUI to fail.Winton
So the key point is that both windows now use the same input queue. The core problem lies within the synchronous sending of a WM_ACTIVATE message to the frozen window. Here is another newsgroup post that covers the exact same subject: Link. Since I don't expect to be able to detach the child windows input queue with something like the AttachThreadInput command, I am accepting this as an answer and going to live a happy life without parent/child window relationships. Many thanks!Logger
Even without queue dependencies, sending messages kills you. Hosting windows from another process is dangerous stuff.Winton
"when you relate windows from different threads you attach their message queues to each other" - it's really the input queues, as explained in the link you posted. Plus, sending messages synchronously isn't much of an issue. A thread can dispatch inbound sent messages while it is waiting for an outbound sent message to return (When can a thread receive window messages?).Hollander

© 2022 - 2024 — McMap. All rights reserved.