Creating Windows

Each window can be created as a child window, or not. Windows that aren't child windows are called top level (as opposed to topmost) windows. The two top level window types are overlapped and popup.
    Each window is divided into two areas, a client and a nonclient area. Child windows are drawn in the client area of its parent window. Mouse movements and clicks produce different messages depending on which window area the cursor is sitting on top of.

[ Back to Win95 ASM Page ]

Window classes revisited

As noted before in our minimal GUI program, we must first register a window class for each window we want to create. Because each registered window class can be used to create any number of windows, the window class effectively defines a common behavior.
    Win95 automatically registers several window classes before starting your program, saving you the work of registering them. They are the standard control classes: BUTTON, COMBOBOX, EDIT, LISTBOX, MDICLIENT, SCROLLBAR, and STATIC. Although these window classes can, indeed, be used to create top level windows, they are normally used to create child windows.
    Let's look at the not-so-obvious fields of the window class structure (WNDCLASSEX) passed to RegisterWindowEx.

wcxStyle
    This field specifies a number of options which are combined by ORing some CS_ constants together. The following are the important ones for beginning Windows programmers.

    CS_DBLCLKS: enable detection of double-clicks
    CS_NOCLOSE: Close option deleted from system menu, close button disabled
    CS_VREDRAW: client area redrawn when vertical size changes
    CS_HREDRAW: client area redrawn when horizontal size changes

    This style option is not necessary, but it is useful.
    CS_GLOBALCLASS: registers the class as a global class, see wcxInstance

wcxClsExtra
wcxWndExtra
    These two fields specifies how many bytes of class-specific or window-specific information you wish to add. The extra-window bytes are filled in after a window of this class is created. Curiously, the extra-class bytes must also be filled in after a window of this class is created.
    There are alternatives to extra-window bytes, which is important when dealing with dialog boxes.

wcxInstance
    The (module) instance handle in this field tells Windows which module (EXE or DLL) "owns" the window class. When creating windows, the instance handle argument in CreateWindowEx must match the instance handle in this field -- unless the class is registered as a global class with the class style option CS_GLOBALCLASS. Because the standard control classes are registered as global ones, any valid instance handle can be used in CreateWindowEx to create windows of these classes.

Creating windows

Windows are created with the CreateWindowEx function.

Window styles

A number of per-window options are collected together in two CreateWindowEx style arguments. The plain style argument has two parts: the standard part and the class-specific part. The second style argument is the extended style. The low 16-bits of the style argument is defined by the window class, and the control classes defined by Microsoft provide examples of this usage.
    The standard style options (WS_) are combined by ORing them together. (If you're careful, you can add them together.) The extended style options (WS_EX_) are combined together, separate from the standard style options. Here are some of the standard and extended style options to consider.

WS_OVERLAPPED, WS_POPUP, WS_CHILD
    These are the window types. Select one. Since WS_OVERLAPPED is 0, it's the default.
    Overlapped (WS_OVERLAPPED) and popup (WS_POPUP) windows are "top level" windows. They can have children, but they don't have parents. Child windows (WS_CHILD) have parent windows, and they can also be parent windows.
    Top level windows can have other top level windows as "owners". They always appear in front of their owners (if they have one). Only top level windows get activated (highlighted title bars)..
    Child windows do not have menus. Child windows always appear in front of their parents and are clipped to avoid going beyond parent boundaries. Although they can have title bars, they normally don't get "activated" (highlighted title bars). Instead, when selected, their top-level parent (or ancestor) gets activated.

WS_VISIBLE
    Forces the window to start out in the visible state. Otherwise the window starts out invisible, hidden, undisplayed. A child window may be in the visible state, but will not display if its parent is hidden.
    Win95 has a special rule for the first call to CreateWindowEx. If the created window is made "visible" with WS_VISIBLE, the startup information is queried to determine which visibility state to start in.

WS_BORDER, WS_DLGFRAME
    A popup or child window may be borderless or have one of these two border types. Cannot be combined with WS_CAPTION which forces a border.

WS_CAPTION, WS_SYSMENU, WS_MINIMIZEBOX, WS_MAXIMIZEBOX
    WS_CAPTION draws a caption, or title, bar and forces the drawing of a border. This is redundant for an overlapped window.

WS_THICKFRAME, WS_HSCROLL, WS_VSCROLL
    The thickframe is the sizing frame/border.
    These scroll bars look and act like scroll bar controls, but they don't have control handles or ID's.

WS_CLIPCHILDREN
    ??? Speeds up redrawing of windows by not erasing areas covered by child windows.

WS_EX_WINDOWEDGE, WS_EX_CLIENTEDGE
    These give you that Win95 3-D look to the window frames.

WS_EX_TOPMOST
    This divides windows into two groups: a set of topmost windows, and those that aren't. The topmost windows covers all windows which aren't.
    Cannot be used by child windows; they only cover portions of their parent windows.

Example program

The following program fragment (from wintypes.asm) illustrates how one window class can be used to make all three types of windows. The "main" overlapped window is made an owner of the popup, and minimize boxes are enabled so that some window "dependencies" can be demonstrated.
    When CreateWindowEx is called, Windows will send a WM_CREATE message. Our program creates "subsidiary" windows as a response to this message.
    We also ensure that the program is terminated only when the main window is closed.
    .data
wc WNDCLASSEX <size WNDCLASSEX,CS_HREDRAW+CS_VREDRAW,WndProc,0,0, 0, \
                0,0,COLOR_WINDOW+1, 0,wndclsname,0>
overlap CREATEARGS <0,wndclsname,caption,WS_OVERLAPPED+WS_CAPTION+WS_SYSMENU+\
                WS_THICKFRAME+WS_MINIMIZEBOX+WS_VISIBLE,100,100,200,200,0,0,0,0>
popup   CREATEARGS <0,wndclsname,caption,WS_POPUP+WS_CAPTION+WS_SYSMENU+\
                WS_THICKFRAME+WS_MINIMIZEBOX+WS_VISIBLE,150,150,200,200,0,0,0,0>
child   CREATEARGS <0,wndclsname,caption,WS_CHILD+WS_CAPTION+WS_SYSMENU+\
                WS_THICKFRAME+WS_MINIMIZEBOX+WS_VISIBLE,50,50,50,50,0,0,0,0>
wndclsname db 'generic',0
caption db 'Anywhere',0

    .code
InitApp:
    mov    edi,offset wc
    mov    esi,offset overlap

    push   large IDC_ARROW
    push   large 0
    call   LoadCursor
    mov    [wc].wcxCursor,eax
    ret

    .data
mainwnd dd 0

    .code
WndProc:
    mov    eax,[esp+4+4]    ; message
    cmp    eax,WM_CREATE
    je     finish_create
    cmp    eax,WM_DESTROY
    je     start_destroy
    jmp    DefWindowProc

    extrn  CreateWindowEx:near

finish_create:
    cmp    [mainwnd],0
    jne    create_nonmain

    mov    eax,[esp+4+0]  ; hwnd
    mov    [mainwnd],eax  ; set main window handle so we don't recurse indefinitely
    push   esi
    push   edi
    mov    esi,offset popup
    mov    [esi].cwargParent,eax    ; make "overlap" an owner of "popup"
    mov    eax,[wc].wcxInstance
    mov    [esi].cwargInstance,eax  ; set popup instance
    sub    esp,48    ; allocate args
    mov    edi,esp
    mov    ecx,12
    rep movsd
    call   CreateWindowEx

    mov    esi,offset child
    mov    [esi].cwargParent,eax    ; make "popup" a parent of "child"
    mov    eax,[wc].wcxInstance
    mov    [esi].cwargInstance,eax  ; set child instance
    sub    esp,48    ; allocate args
    mov    edi,esp
    mov    ecx,12
    rep movsd
    call   CreateWindowEx
    pop    edi
    pop    esi

create_nonmain:
    xor    eax,eax    ; signal a successful CREATE
    ret    16

start_destroy:
    mov    eax,[esp+4+0]    ; hwnd
    cmp    eax,[mainwnd]
    jne    no_special_destroy

    push   large 0
    call   PostQuitMessage

no_special_destroy:
    xor    eax,eax
    ret    16