Windows Event Handler in MASM

Tight_Coder_Ex 0 Tallied Votes 747 Views Share

This procedure dispatches application defined event handlers and alternately executes default process for both standard or sub/super classed windows.

Map is defined as follows. In most cases I define this table in .data, but in can be in .const also. I choose writeable memory as application can redefine characteristics.

MWMap	            dd	0					; Address of sub or super class default proc
		dw	(MWEnd - MWMap - 6) / 6		; Determine number of messages in map
		dw	WM_DESTROY
		dd	QuitApp
		dw	WM_CREATE
		dd	CMainWnd
  MWEnd	equ	$

Entry point of windows procedure requires only two instructions

MWndProc		proc

	  		mov	esi, offset MWMap			; Point to message map for this window
	  		jmp	ScanMap
	    
  MWndProc		endp

By whatever means you choose to intialize WNDCLASSEX then entry point need only be specified as the 3 parameter

Wc		WNDCLASSEX	< 30h, CS_HREDRAW or CS_VREDRAW, MWndProc, 0, 0,\
				 0, 0, 0, COLOR_APPWORKSPACE + 1, NULL, AppName, 0>

Here is an example of the actual handler

CMainWnd		proc	uses	ebx edi
  
  		LOCAL	Rc:RECT
  		
  			lea	ebx, Rc
  			mov	edi, [esi]
  			
  			invoke	GetClientRect, dword ptr [esi], ebx	; Get client windows metrics
  			invoke	InflateRect, ebx, -32, -32		; Adjust for border
 			mov	eax, [ebx + 8]
 			sub	eax, [ebx]
 			  			
			invoke	CreateWindowEx,
				WS_EX_STATICEDGE or WS_EX_CLIENTEDGE,  ADDR EditClass, NULL, \
				WS_VISIBLE or WS_BORDER or WS_CHILD or ES_AUTOHSCROLL, \
				32, 32, eax, 22, edi, 64, Wc.hInstance, NULL
			
			mov	EditWnd, eax
			mov	edi, eax				; Save copy of window
			and	eax, eax
			jnz	@f
			
			int	3
			
		@@:	invoke	SetWindowLong, eax, GWL_WNDPROC, ADDR EditProc
			mov	EditMap, eax
			
			invoke	GetStockObject, ANSI_VAR_FONT
			invoke	SendMessage, edi, WM_SETFONT, eax, 0
			invoke	SendMessage, edi, EM_SETMARGINS, EC_LEFTMARGIN or EC_RIGHTMARGIN, 0180018H
			invoke	SetFocus, edi
			
   			stc					; Inhibit default processing by setting carry
  			ret
ScanMap	proc

	; EBX = Pointer to default procedure if window has been sub/super classed.
	; ECX = Number of handlers in map (can be NULL, although not usual).

		lodsd				; Get address of default window procedure.
		mov	ebx, eax		; Save in case window has been sub/super classed
		lodsw				; Number of messages in map
		cwde				; Sign extend to 32 bits, can be NULL but not usually the case
		
		.if	eax				; Does map have defninitions
			mov	ecx, eax		; Move into counter register
		
		; Cycle through each of the application defined handlers until a match is found,
		; otherwise just automatically drop into default message processing.

		@@:	lodsw				; Get message number from map
			mov	edx, eax		; Copy it so next instruction doesn't destroy
			lodsd				; Pointer to application defined handler
			
			.if	dx == [esp + 8]		; When match if found, execute handler
				lea	esi, [esp + 4]		; ESI points to API parameters
				call	eax			; Call handler
				jnc	@F			; Do default processing if no carry
		
				xor	eax, eax		; Set default return condition
				ret	16			; Clean-up stack and return.
			.endif

			loopnz	@B			; Keep comparing until ECX = Zero.
		.endif
	
	@@:	; Either there wasn't a need to handle this event or the handler requires default processing
	
		.if 	!ebx
			jmp	DefWindowProc	; Do default processing for this window
		.endif
	
	; Processing of a subclassed window requires address of default code so it will
	; be placed on stack at this point.
		
		xchg	[esp], ebx		; Exchange default processing address
		push	ebx			; with return and push on stack again
		jmp	CallWindowProc	; Do default processing for this window