"Use of GoBug" demonstrations
WndProc recursion

This demonstrates shows how GoBug displays the depth of recursion in a window procedure. It is also a useful demonstration of the single-step message break (which must be "on" for this test). Start Testbug as the debuggee and set a breakpoint at WNDPROC_RECURSION by using the GoBug menu item "action, run to .. procedure" menu item.

Recursion is when a window procedure is dealing with a call, but is called again before it returns from the call. In fact in this test the calls go 4 deep. This happens because the same window procedure is used to deal with 3 windows. But even if your windows don't share window procedures recursion often happens. Always use the stack to keep local data and only use data symbols if you are confident their value cannot be overwritten.

To try out this test make sure "single-step message break" is switched on ("action" menu).

When the breakpoint is reached single-step down the code using F6. When you F6 past MAKE_WINDOWX the 3 windows will be made. Each one is made on the WM_CREATE message coming into the window procedure.
The single-step message break will ensure that GoBug breaks at each message. If you look at the status line at the bottom of GoBug's window it will tell you the degree of recursion for each message.
When the message break occurs you can press F6 to jump over the message or F5 to see execution of the code.
Here is the coding involved:-

MAKE_WINDOWX:
INC B[WINDOW_COUNT]
MOV ESI,ADDR RECURSIONMESS
MOV AL,[WINDOW_COUNT]
ADD AL,'0'
MOV B[ESI+28D],AL
PUSH 0,[hInst],0,[EBP+8]    ;owner=calling window
PUSH 200,320                ;height, width
XOR EAX,EAX
MOV AL,[WINDOW_COUNT]
SHL EAX,5
ADD EAX,50D
PUSH EAX,EAX                ;position y then x
PUSH 90000000h +0C00000h+40000h +80000h +20000h     +10000h
;(POPUP+VISIBLE)+CAPTION+SIZEBOX+SYSMENU+MINIMIZEBOX+MAXIMIZEBOX
PUSH ESI,ADDR RECURSION_CLASSNAME      ;class
PUSH 0                      ;extended window style
CALL CreateWindowExA        ;make window, returning handle in EAX
RET
;
RecursionWndProc:
PUSH EBP
MOV EBP,ESP
PUSH EBX,EDI,ESI        ;save registers as required by Windows
;now [EBP+8]=hWnd, [EBP+0Ch]=uMsg, [EBP+10h]=wParam, [EBP+14h]=lParam,
MOV EAX,[EBP+0Ch]       ;uMsg
CMP EAX,01h             ;see if WM_CREATE
JZ >L9                  ;yes so make another window and return zero
PUSH [EBP+14h],[EBP+10h],[EBP+0Ch],[EBP+8h]
CALL DefWindowProcA
JMP >L13
L9:
CMP B[WINDOW_COUNT],3   ;see if 3 windows already made
JZ >L11                 ;do no more
CALL MAKE_WINDOWX
L11:
XOR EAX,EAX
L13:
POP ESI,EDI,EBX
MOV ESP,EBP
POP EBP
RET 10h
;
WNDPROC_RECURSION:
CALL INITIALISE_WNDCLASS    ;get ready for all windows
MOV D[EBX],01h+02h+40h      ;CS_VREDRAW+CS_HREDRAW+CS_CLASSDC
MOV D[EBX+4],ADDR RecursionWndProc
MOV D[EBX+24h],ADDR RECURSION_CLASSNAME
PUSH EBX                ;address of structure with window class data
CALL RegisterClassA     ;register a window class for subsequent use
MOV B[WINDOW_COUNT],0
CALL MAKE_WINDOWX
RET