Popup Windows and Ownership

The first window we created was an overlapped window. A second type of window is the popup window or popup for short. There doesn't appear to be any real difference between overlapped windows and popups except for initialization. The overlapped window is always created with a border and a caption (title bar) but a popup window can be created without either. You can let Windows figure out where and how big to make your overlapped window by using CW_USEDEFAULT as the x y cx and cy arguments of CreateWindowEx but a popup window requires explicit location and size arguments.
    To make one window always appear in front of another window we can make the "background" window the owner of the other. When the owner is minimized the owned window will disappear. Restoring the minimized window will cause the owned window to reappear. Only overlapped and popup windows can be owners or be owned. The popup is often a dialog or a message window so it's sensible to make a main window the owner of popups.
    The program winowner.asm shows key features of the owner/owned relationship. The program creates four popup windows three of which are owned directly by the main window. The fourth window is indirectly owned by the main window.
    None of the owned windows will appear on the taskbar.
    Because Popup1 Popup2 and Popup3 are owned at the same level any one of them can appear "between" the other two. Because Popup1 owns Popup4 the other popups (Popup2 and Popup3) cannot be placed between them. And none of the popups can appear behind the "top owner" the main window.
    If any of the windows are partially covered clicking on any of the program windows will bring them all to the front. Minimize an owner window (main window or Popup1) and the popups it owns will disappear. After minimizing an owner restoring or maximizing it will cause its owned popups to reappear and be restored. [ Back to Win32 ASM Page ]
 

The window classes

We register two window classes one for the main parent window and one for the popup windows. To prevent the owned popup windows from totally disappearing (we don't yet have a way of recreating them) we add CS_NOCLOSE to the popup class style. Otherwise we aren't doing anything special with the popup windows so we make their window procedures the default DefWindowProc.
.386
.model  flat

; If using TLINK32
don't include vclib.inc
include vclib.inc    ; Microsoft VC++ .lib link names

include win32hst.inc ; constants
structures
and entry names

.data
align   4
wcx     dd      size WNDCLASSEX           ; cbSize
dd      CS_VREDRAW or CS_HREDRAW  ; style
dd      WndProc                   ; lpfnWndProc
dd      0
0                       ; cbClsExtra
cbWndExtra
dd      0                         ; hInstance
dd      0                         ; hIcon
dd      0                         ; hCursor
dd      COLOR_WINDOW+1            ; hbrBackground
dd      0                         ; lpszMenuName
dd      wndclsname                ; lpszClassName
dd      0                         ; hIconSm

wndclsname db 'winmain'
0

align 4
popup_class     dd      size WNDCLASSEX           ; cbSize
dd      CS_VREDRAW or CS_HREDRAW or CS_NOCLOSE ; style
dd      DefWindowProc             ; lpfnWndProc
dd      0
0                       ; cbClsExtra
cbWndExtra
dd      0                         ; hInstance
dd      0                         ; hIcon
dd      0                         ; hCursor
dd      COLOR_WINDOW+1            ; hbrBackground
dd      0                         ; lpszMenuName
dd      popup_class_name          ; lpszClassName
dd      0                         ; hIconSm

popup_class_name db 'popupclass'
0

.code

public _start
extrn   GetModuleHandle:near
extrn   LoadIcon:near
LoadCursor:near
extrn   RegisterClassEx:near

_start:
push    large 0         ; NULL string pointer means
call    GetModuleHandle ; get HINSTANCE/HMODULE of EXE file
mov     [wcx.wcx_hInstance]
eax
mov     [popup_class.wcx_hInstance]
eax

push    large IDI_WINLOGO
push    large 0         ; hInstance
0 = stock icon
call    LoadIcon
mov     [wcx.wcx_hIcon]
eax
mov     [popup_class.wcx_hIcon]
eax

push    large IDC_ARROW
push    large 0         ; hInstance
0 = stock cursor
call    LoadCursor
mov     [wcx.wcx_hCursor]
eax
mov     [popup_class.wcx_hCursor]
eax

push    offset wcx
call    RegisterClassEx

push    offset popup_class
call    RegisterClassEx

Creating the main window

Here we create a main window. After it is created we save its handle and call a subroutine to create the popup windows.
.data
align   4

hMainWnd dd   0                  ; handle of main window

cwargs   dd   0                  ; dwExStyle
dd   wndclsname         ; lpszClass
dd   wnd_title          ; lpszName
dd   WS_VISIBLE or WS_OVERLAPPED or WS_SYSMENU or WS_THICKFRAME \
or WS_MINIMIZEBOX or WS_MAXIMIZEBOX  ; style
dd   100                ; x
dd   100                ; y
dd   400                ; cx (width)
dd   200                ; cy (height)
dd   0                  ; hwndParent
dd   0                  ; hMenu
dd   0                  ; hInstance
dd   0                  ; lpCreateParams

msgbuf MSG      <>

wnd_title db 'Owner of popup windows'
0

.code

extrn   CreateWindowEx:near
extrn   GetMessage:near
DispatchMessage:near
extrn   ExitProcess:near

sub     esp
48            ; allocate argument list
mov     esi
offset cwargs ; set block move source
mov     edi
esp           ; set block move destination
mov     ecx
12            ; number of arguments
rep movsd
mov     eax
[wcx.wcx_hInstance]
mov     [esp+40]
eax      ; set hInstance argument in stack
call    CreateWindowEx
mov     [hMainWnd]
eax

call    create_popups     ; call our special procedure

The message loop and program termination

Here is the minimal message loop and program termination code.
msg_loop:
push    large 0         ; uMsgFilterMax
push    large 0         ; uMsgFilterMin
push    large 0         ; hWnd (filter)
0 = all windows
push    offset msgbuf   ; lpMsg
call    GetMessage      ; returns FALSE if WM_QUIT
or      eax
eax
jz      end_loop

push    offset msgbuf
call    DispatchMessage

jmp     msg_loop

end_loop:
push    large 0 ; (error) return code
call    ExitProcess

Main window procedure

Here is the minimal window procedure used by the main window.
.code

extrn   DefWindowProc:near
PostQuitMessage:near

WndProc:
mov     eax
[esp+4+4]           ; message ID
cmp     eax
WM_DESTROY          ; about to start window destruction
je      on_destroy
jmp     DefWindowProc           ; delegate other message processing

on_destroy:
push    large 0
call    PostQuitMessage

xor     eax
eax
ret     16

Creating the popup windows

Popups are created by calling CreateWindowEx with WS_POPUP included in the style argument.
    The hwndParent argument is used in this case as the owner argument. When the window type (set in the style argument) is set to WS_OVERLAPPED or WS_POPUP this argument is treated as an owner.
    Notice that WS_POPUP replaces WS_OVERLAPPED. Also we have added WS_CAPTION because popups do not automatically have a caption (title bar).
    The following code creates the large CreateWindowEx argument list by building it in a directly addressable area and then copying it onto the stack.
.data
align   4
cwp_args      dd   0                  ; dwExStyle
dd   popup_class_name   ; lpszClass
popup_caption dd   0                  ; lpszName
dd   WS_VISIBLE or WS_POPUP or WS_SYSMENU or WS_THICKFRAME \
or WS_MINIMIZEBOX or WS_MAXIMIZEBOX or WS_CAPTION  ; style
popup_x       dd   0                  ; x
popup_y       dd   0                  ; y
dd   200                ; cx (width)
dd   145                ; cy (height)
hOwner        dd   0                  ; hwndParent
dd   0                  ; hMenu (control ID)
hInstance     dd   0                  ; hInstance
dd   0                  ; lpCreateParams

popup_title1 db   'Popup1'
0
popup_title2 db   'Popup2'
0
popup_title3 db   'Popup3'
0
popup_title4 db   'Popup4'
0

.code

create_popups:
mov     eax
[wcx.wcx_hInstance]
mov     [hInstance]
eax   ; set hInstance argument

mov     eax
[hMainWnd]
mov     [hOwner]
eax      ; set owner to main window
mov     [popup_x]
150
mov     [popup_y]
150
mov     [popup_caption]
offset popup_title1
call    create_one_popup

mov     [hOwner]
eax      ; set owner to previous window
mov     [popup_x]
200
mov     [popup_y]
200
mov     [popup_caption]
offset popup_title2
call    create_one_popup

mov     eax
[hMainWnd]
mov     [hOwner]
eax      ; set owner to main window
mov     [popup_x]
450
mov     [popup_y]
150
mov     [popup_caption]
offset popup_title3
call    create_one_popup

mov     eax
[hMainWnd]
mov     [hOwner]
eax      ; set owner to main window
mov     [popup_x]
750
mov     [popup_y]
150
mov     [popup_caption]
offset popup_title4
call    create_one_popup

ret

create_one_popup:
sub     esp
48            ; allocate argument list
mov     esi
offset cwp_args ; set block move source
mov     edi
esp           ; set block move destination
mov     ecx
12            ; number of arguments
rep movsd
call    CreateWindowEx
ret

end     _start