Is it legal to have a cross-process parent/child or owner/owned window relationship?


A customer liaison asked whether it was legal to use Set­Parent to create a parent/child relationship between windows which belong to different processes. "If I remember correctly, the documentation for Set­Parent used to contain a stern warning that it is not supported, but that remark does not appear to be present any more. I have a customer who is reparenting windows between processes, and their application is experiencing intermittent instability."

Is it technically legal to have a parent/child or owner/owned relationship between windows from different processes?

Yes, it is technically legal.

It is also technically legal to juggle chainsaws.

Creating a cross-thread parent/child or owner/owned window relationship implicitly attaches the input queues of the threads which those windows belong to, and this attachment is transitive: If one of those queues is attached to a third queue, then all three queues are attached to each other. More generally, queues of all windows related by a chain of parent/child or owner/owned or shared-thread relationships are attached to each other.

Exercise: What are the equivalence classes generated by taking the transitive closure of parent/child windows, and what would be a natural choice of class representative? What about the equivalence classes generated by the transitive closure of parent/child and owner/owned windows?

This gets even more complicated when the parent/child or owner/owned relationship crosses processes, because cross-process coordination is even harder than cross-thread coordination. Sharing variables within a process is much easier than sharing variables across processes. On top of that, some window messages are blocked between processes.

So yes, it is technically legal, but if you create a cross-process parent/child or owner/owned relationship, the consequences can be very difficult to manage. And they become near-impossible to manage if one or both of the windows involved is unaware that it is participating in a cross-process window tree. (I often see this question in the context of somebody who wants to grab a window belonging to another process and forcibly graft it into their own process. That other process was totally unprepared for its window being manipulated in this way, and things may stop working. Indeed, things will definitely stop working if you change that other window from a top-level window to a child window.)

The existing text was probably removed when somebody pointed out that the action is technically legal (though not recommended for beginners), and instead of trying to come up with new text that describes the situation, merely removed the text that was incorrect. The problem with coming up with new text that describes the situation is that it only leads to more questions from people who want to do it in spite of the warnings. (It's one of those "if you don't already know what the consequences are, then you are not smart enough to do it correctly" things. You must first become the master of the rules before you can start breaking them.)

Comments (14)
  1. Anonymous says:

    I used a similar rule when I told a colleague to always write "new T()" instead of "new T" in C++.

    Unless you know what you're doing, the former is the correct in the cases there's a difference at all.

  2. Anonymous says:

    It's funny you should mention this, because I was able to close a monitoring software's window by setting its parent to an explorer window and closing that. I sent it in along with the more severe ones that were found. The CEO was really nice.

  3. The review panel of twelve-year-old boys should have taken a look at this title.

  4. Anonymous says:

    Can you explain what it means for input queues from two different threads to be "attached"?

  5. Dan Bugglin says:

    @Chris Sounds like they've likely chosen to ignore Windows' built in user account security (eg run the software as a service where a limited user can't stop it) and install their own screendoor on the submarine.  Good luck to them patching that up.

  6. Anonymous says:

    OLE in-place activation relies on cross-process parent-child relationship (embed an Excel spreadsheet into a Word document, double-click it to activate, inspect the window hierarchy with Spy++). Of course in this case both parties are aware of what's going on.

  7. Anonymous says:

    I'm guessing that the way web browsers implement tabs with different processes is an example of cross-process relationships.

  8. Anonymous says:

    Oh, this reminds me on a Windows bug I've encountered…

    I've had a following situation:

    1. Parent process creates a main window.
    2. Child process creates a child window that gets SetParented into the main window.

    3. In the 'parent' process, PrintWindow is called on a main window.

    4. 'Child' process in child window's WM_PAINT does UpdateWindow on a parent window (that is, it goes back to the 'parent' process).

    Win7 blue screen on this.

    Note that I do not work on this project any more and mine part was only point 3; I didn't have sources for other points, but I've figured out eventually how it works and what causes the blue screen. I've managed to do some workaround for this (don't remember any more what), but Windows shouldn't really crash.

    Neat.

  9. Anonymous says:

    I agree with Goran Mitrovic on one point. Any bluescreen except MANUALLY_INITIATED_CRASH (or one along the lines of I can't boot) is a kernel bug or hardware problem, and almost all of them are at least trivial DOS level security bugs.

  10. Anonymous says:

    @AC: No, it is new T that would be correct in places where new T() would be wrong. (I seem to remember that VC6 had a compiler bug where it would incorrectly compile new T() as new T in certain circumstances but that particular code got rewritten anyway.)

  11. Anonymous says:

    Agree with Neil, every C++ book I've read clearly says, for default constructors, use: new T. Reason is, new T() can be sometimes ambiguous as to whether it's a constructor call or function declaration.

  12. Anonymous says:

    @APZ & @AC – (OT) I suspect the reason AC wants to use 'new T()' always, is that is guarantees initialization even for POD, which 'new T' does not, leading to fewer 'surprises'.

  13. Anonymous says:

    Another case where a child window belongs to a different process than the parent is the screensaver preview.

  14. I always wondered how exactly it works… For example when SetParent(hWnd, NULL) is called then desktop windows is the new parent. But the input queues should not be attached (at least I see it as big technical problem if they were). But desktop window is special, right?

Comments are closed.