11 October 2012

An owned Form

Until of the older set of chm MSDN Library files (<= October 2001) were replaced by the newer MSHELP, the MSDN contained an article called "Win32 Window Hierarchy and Styles" by Kyle Marsh, September 29, 1993. This article explains how top-level windows (aka Forms) relate to each other.

Form is a top-level window
A Form window, whether is is created using OpenW, Dialog, or Form, is a top-level window by default. A top-level window is any window that is not a child window. Top-level windows do not have the WS_CHILD style. All top-level windows are also connected to the desktop window through the parent window handle, GetParent(). Top-level windows are connected to the desktop window as if they were child windows of the desktop, and can be considered children of the desktop in that parent/child navigation techniques can be used to move between a top-level window and the desktop window. All top-level windows are displayed in the client area of the desktop window and thus behave as if they were children of the desktop for display purposes.

The parent window
Each window, being a top-level or a child window, has a parent window. The desktop window occupies the first level of the windows hierarchy and top-level windows occupy the second level. Child windows, which are windows created with the WS_CHILD style, occupy all other levels. Child windows connect to their parent window in the same way top-level windows connect to the desktop window.

The owned window
Top-level windows can own or be owned by other top-level windows. One Form can own another Form. An owned window is always displayed above its owner in the Z order and is hidden when its owner is minimized. Try this and see what happens, you cannot display Form Win_1 on top of Form Win_2:

OpenW 1
Me.Caption = Me.Name
OpenW Owner Win_1 , 2
Me.Caption = Me.Name
Do
  Sleep
Until Me Is Nothing

Win_2 is owned by Win_1. Owned windows are not hidden when their owner is hidden. Thus, if window #1 is minimized, window #2 is hidden as well.
BTW you can set the owner using the designer in the Properties window. A Form has a an Owned property that can be set to True. After loading the Form using LoadForm the current active Form as referenced by Me will be set as the owner.

On the API level an owned window relationship is created by passing the window handle to the owner window in the hwndParent parameter of the CreateWindow() function. GB32 passes the window handle of the Form object specified in the Owner clause in the OpenW statement. To top-level window #2, window #1 is the owner, but not its parent window. The parent window for both Forms is the desktop window.
The GetParent() API function is not used to obtain the owner of a top-level window, that would return the desktop window handle. Insert the following lines before the start of the message loop. Both will return Null (0).

Print GetParent(Win_1.hWnd)
Print GetParent(Win_2.hWnd)

To obtain the owner GetWindow(hWnd, GW_OWNER) API function should be used. Insert these lines as well, and see how their results differ.

Print GetWindow(Win_1.hWnd, GW_OWNER)
Print GetWindow(Win_2.hWnd, GW_OWNER)

Finally, closing the owned top-level Win_2 won't automatically close Win_1. After Win_2 has been destroyed the current Form Me is set to Win_1. The global message loop will not end until Me == Nothing, which will not happen until Win_1 has been closed.