Application startup & Message Pump

Tight_Coder_Ex 0 Tallied Votes 234 Views Share

The next few posts will be what's required to get a window to display on the monitor. The code between Main & Pump will probably change as time goes on, but for now this is all that is required. I choose this method or placement because only 28 bytes of stack are used at this point. Nesting pump deeper in application might unnecessarily retain unused stack space.

; 				*** APPLICATION ENTRY POINT ***

; This is where application begins after OS has done its thing.  I use the space before
; ShowMainWnd for anything that is not particularly related to displaying main window or is
; coded into a message handler such as WM_CREATE.
; ____________________________________________________________________________________________

  Main		enter	28, 0			; MSG structure in proceedure frame.
		call	InitFrame		; Set elements of MSG to zero's

	; In the event there is a failure creating main window, MSG.wParam has already been
	; established.  If a different value is required, set it where ever required.

		lea	ebx, [ebp - 28]		; EBX points to MSG
		dec	dword [ebx + 8]		; Msg.wParam = -1, default error condition.

		call	ShowMainWnd		; Execute main body of application
		jc	.Exit			; NC = 1, Proeedure failed.  

		xor	eax, eax		; EAX = NULL

  	; Applications message pump, continually scan for messages until WM_QUIT is returned.
		
  .Pump		push	eax			; Save zero value in EAX
		push	eax			; wMsgFilterMax
		push	eax			; wMsgFilterMin
		push	eax			; hWnd = 0, Desktop
		push	ebx			; Pointer to MSG
		call	_GetMessageA@16
		and	eax, eax		; Evaluate returned value
		jz	.Exit	
 
	; If main window is a dialog box, IsDialog would be evaluated here.

		push	ebx
		call	_TranslateMessage@4
		push	ebx
		call	_DispatchMessageA@4

		pop	eax			; Restore NULL
		jmp	short .Pump
	
	; Application has terminated, either because ShowMainWnd failed or message que
	; encountered WM_QUIT.  Other fatal errors usually kill app at the point they
	; were encountered as ExitProcess will do appropriate cleanup anywhere.

  .Exit		leave
		push	dword [ebx + 8]		; MSG.wParam
		call	_ExitProcess@4		; Cleanup

Dani AI

Generated

Good start, — the minimal pump and tiny stack footprint make sense for a compact Win32 app. A few practical clarifications and hardening tips follow.

On 32-bit Windows the MSG structure is 28 bytes (HWND, UINT, WPARAM, LPARAM, DWORD time and POINT), which explains the 28-byte frame used. That exact size is valid only for Win32; on x64 the structure and pointer sizes grow. Avoid hard-coded sizes in portable code — prefer a symbolic sizeof(MSG) or an assembler equate rather than a literal 28.

The GetMessage return needs a slightly more robust check. GetMessage returns >0 for a message, 0 for WM_QUIT, and -1 on error. The posted and eax,eax / jz .Exit handles WM_QUIT but does not detect the -1 error case. A safer pattern is:

call    _GetMessageA@16
cmp     eax, -1
js      .GetMessageError
test    eax, eax
jz      .Exit

On error, call GetLastError and return an appropriate exit code instead of relying on a magic -1 in MSG.wParam.

Also, avoid testing the carry flag after ShowMainWnd unless that routine explicitly sets CF. Standard Win32 results are returned in EAX (e.g., CreateWindowEx returns NULL on failure), so prefer test eax,eax / jz .Exit. For dialog-based windows, check IsDialogMessage(hDlg, &msg) before TranslateMessage/DispatchMessage so dialog keyboard handling works; if accelerators are in use, call TranslateAccelerator before TranslateMessage and skip dispatch when it returns nonzero.

When porting to x64 remember calling conventions and data sizes change (register arguments, no stdcall name decoration). These small checks make the pump more deterministic, easier to debug, and more portable across 32/64-bit builds.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.