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