0

I'm trying to write a helper class to let me set the parent of a specific window, and then release the parent at a specific point or when the class is disposed.

My problem is that after I call SetParent function, GetParent always returns null. This is a problem because for this reason I can't do a safety check to determine whether the window is parented before trying to release it from its current parent and set the window (window style and position) back to its normal state.

I also tried IsChild function and it also returns null.

I'm using a custom SafeWindowHandle class that inherits from SafeHandleZeroOrMinusOneIsInvalid class to ensure that the parented window handle does not turn zero. Also my P/Invoke definitions for SetParent / GetParent / Ischild functions takes a SafeHandle object.

What could be the problem with GetParent and IsChild?.

This is a sample code that in my case reproduces the problem:

Dim pr As Process = Process.GetProcessesByName("name").Single()
Dim hwnd As New SafeWindowHandle(pr.MainWindowHandle)

NativeMethods.SetParent(hwnd, Me.Panel1.Handle)

Dim hasParent As Boolean = NativeMethods.GetParent(hwnd)
Console.WriteLine(hasParent.ToString())
ElektroStudios
  • 19,105
  • 33
  • 200
  • 417
  • 1
    try use `GetWindowLongPtr(hwnd, GWLP_HWNDPARENT)` instead `GetParent(hwnd)` – RbMm May 10 '22 at 20:40
  • @RbMm Thank you, it worked!. However I would like to know if someone can explain us why GetParent and Ischild does not work as expected in this scenario, and if I can do something to make them work as expected instead of calling GetWindowLongPtr. Thanks again!. – ElektroStudios May 10 '22 at 20:48
  • 2
    Your use of `SetParent()` is actually setting the window's *Owner* not its *Parent*, because the window does not initially have the `WS_CHILD` style enabled, and the `SetParent()` documentation says: "*For compatibility reasons, SetParent does not modify the WS_CHILD or WS_POPUP window styles of the window whose parent is being changed.*" Per the `GetParent()` documentation: "*To obtain a window's owner window, instead of using GetParent, use GetWindow with the GW_OWNER flag. To obtain the parent window and not the owner, instead of using GetParent, use GetAncestor with the GA_PARENT flag.*" – Remy Lebeau May 10 '22 at 20:59
  • 1
    Also see: [GetParent, just as confusing as EnumClaw, but it's an actual function!](https://devblogs.microsoft.com/oldnewthing/20111207-00/?p=8953), and: [Is it legal to have a cross-process parent/child or owner/owned window relationship?](https://devblogs.microsoft.com/oldnewthing/20130412-00/?p=4683) – Remy Lebeau May 10 '22 at 20:59
  • @Remy Lebeau Very useful, so firstly I should check whether the window has the the WS_CHILD style to be aware whether I'm really setting a parent, or a owner window. Or just add the WS_CHILD style after setting the owner window to convert it to a parent window If I understand good. – ElektroStudios May 10 '22 at 21:05
  • 1
    @ElektroStudios `Process.MainWindowHandle` will never return an `HWND` that has the `WS_CHILD` style applied, or a `GW_OWNER` window assigned. That property only supports top-level unowned windows. If you want to set a new *parent* window, you have to add the `WS_CHILD` style before calling `SetParent()`, not after. This is clearly stated in `SetParent`'s documentation. – Remy Lebeau May 10 '22 at 21:10
  • Oh, but I'm noticing that GetWindow with GW_OWNER flag returns null after I call SetParent. I'm calling SetParent to set the owner window for "sublime_text" process window to a panel control of my form. – ElektroStudios May 10 '22 at 21:11
  • 1
    @ElektroStudios your panel is itself a child window of your Form UI. So, it can be set as a parent of child windows, but cannot be set as an owner of other windows. Only an overlapped or popup window can be an owner. – Remy Lebeau May 10 '22 at 21:14
  • 1
    @ElektroStudios I suggest you read [Parent or Owner Window Handle](https://learn.microsoft.com/en-us/windows/win32/winmsg/about-windows#parent-or-owner-window-handle), [Child Windows](https://learn.microsoft.com/en-us/windows/win32/winmsg/window-features#child-windows), [Relationship to Parent Window](https://learn.microsoft.com/en-us/windows/win32/winmsg/window-features#relationship-to-parent-window), and [Owned Windows](https://learn.microsoft.com/en-us/windows/win32/winmsg/window-features#owned-windows). – Remy Lebeau May 10 '22 at 21:17
  • Ok, but if it is not a owner window, and it is not a parent window, what it is and what function I must call?. I noticed that GetAncestor with GA_PARENT flag returns the hwnd of the panel, but you said calling SetParent I'm not really setting the panel as a parent for sublime_text main window?, and GetParent function returns null for this. it's a little confusing these two function behaviors. – ElektroStudios May 10 '22 at 21:18
  • 1
    @ElektroStudios please [edit] your question to provide code snippets demonstrating your observations. – Remy Lebeau May 10 '22 at 21:21
  • Don't worry, I don't pretend to bother but it's just a little bit confusing because you said *use of SetParent() is actually setting the window's Owner not its Parent* and then that my panel control's window cannot be used as a owner window, but I'm getting a parent window handle with GetAncestor while I get null handle for owner window, so I think I'm setting the parent window, not a owner window. I will do some experiments while I use GetAncestor with other different windows. Thanks for your help. – ElektroStudios May 10 '22 at 21:26
  • 1
    In your [previous question](https://stackoverflow.com/q/72153907/7444103), the linked code is storing the Handle of the previous *Parent* (ancestor) or the parented Window (Top-Level, it's assumed). When that stored handle is not `(IntPtr)(-1)`, you know that the Window has been *reparented* -- If you call `GetAncestor([Window Handle], GA_PARENT)`, you'll find out that the ancestor of the Window is the Panel used as container. – Jimi May 10 '22 at 22:03
  • Everybody feel free to publish an answer mentioning GetAncestor or GetWindowLongPtr to mark it as the accepted answer if you like. Thanks everybody. – ElektroStudios May 11 '22 at 00:20

0 Answers0