I devised this algorithm to facilitate runtime modification of event handlers in windows procedure. It also illuminates the busyness of excessive conditionals and jumps. ScanMap also deals with sub/super classed windows and post default processing.
MMap dd 0 ; Pointer to subclass procedure
dd (MainWnd - MMap - 8) / 8 ; Number of handlers in map
dd WM_COMMAND, CWndCmd ; Event # & Procedure pointer combos
dd WM_DESTROY, MDest
Entry point to window procedure
MainWndProc:
mov esi, MMap
jmp ScanMap
Code to handle qualifying events
ScanMap:
lodsd ; Load pointer to subclass procedure if applicable
xchg ebx, eax ; Move it into EBX
lodsd ; Load number of handlers in map
xchg ecx, eax ; Move it into ECX
@@: lodsd ; Load corresponding handlers message number
cmp ax, [esp + 8] ; Is it same as kernel message
lodsd ; Load pointer to procedure
jz @Hd1 ; If it's the same, then handle message
loopnz @B ; Keep going until end of map
@@: or ebx, ebx ; Is there a subclass procedure
jnz @Sub
jmp [DefWindowProc] ; Do default processing
@Sub: pop eax
push ebx
push eax
jmp [CallWindowProc]
@Hd1: lea esi, [esp + 4] ; ESI points to hwnd, msg, wParam, lParam
mov edx, eax ; So EAX is NULL at the beginning of all handlers
xor eax, eax
call edx ; Execute handler
jnc @B ; Branch if default handling required.
xor eax, eax ; Handled messages return zero
ret 16 ; Waste parameters
This may look a bit bizarre, but it does work, primarily because kernel code looks after cleaning up stack.
The handler simply looks like this and the only thing ScanMap needs is CF cleared if post default processing is required.
MDest:
push 0
call [PostQuitMessage]
stc ; Don't require default processing
ret