Okay, before I even begin, I will offer a warning: You might regard the code you are about to read crazy. In it, I use ESP to reference params and locals, I SUBtract from ESP and MOVe params, rather than PUSHing and POPping, and you won't find a PROC...ENDP, STRUCT, or WM_* anywhere.

It is this way because I was trying to learn what all those luxuries do for me, and then binrapt on #win32asm said I might as well use ESP for speed or write it in C. Naturally, being a n00b not to be outdone, I did just that. And, for the most part, it works. I even figured out how to shortcircuit DefWindowProc to return to WndProc's caller. However, I have goofed something where I handle the WM_PAINT message, and after WM_PAINT is handled, WndProc RETurns and then crashes. But, only on that message do thing go wrong...

It is commented, however, it is probably painful to look at. I have also attached the file, which retains my indentation, making it slightly easier to read than what is below.


; Assemble with "GoAsm <file.asm>"

; Link with "GoLink <file.asm> kernel32.dll user32.dll"
; Append "-debug coff" to GoLine command to link with symbols

data section

szClsNm db "FastererWin", 0x0
szAppNm db "Attempt at a ", 0x22, "Fasterer", 0x22, " Window Implementation", 0x0
szText db "This is my attempt at a ", 0x22, "fasterer", 0x22, " window ", \
   "implementation. Rather than managing a ", \
   "static stack frame manually through EBP, ", \
   "I manage a dynamic stack frame through ESP.", \
   0xA, 0xA, \
   "To alleviate the headache that ensues from ", \
   "trying to keep track of params and locals ", \
   "on the stack, especially between intervening ", \
   "PUSHes and POPs, I did away with them all ", \
   "together. Instead, I SUBtract from ESP the ", \
   "number of bytes I need for passing params. ", \
   "This allows me to deal with a fixed number ", \
   "of intervening bytes throughout the entire ", \
   "process of putting params on the stack, as ", \
   "opposed to the number changing with each ", \
   "PUSH. An ideal side effect of using this ", \
   "method is that now I can place params on the ", \
   "stack in left-to-right order, at increasing ", \
   "offsets from ESP, instead of right-to-left, ", \
   "at decreasing offsets from EBP.", \
   0xA, 0xA, \
   "Well, any speed advantage will surely not be ", \
   "human-perceptible, but at least I have the ", \
   "satisfaction of know that this implementation ", \
   "is ", 0x22, "fasterer", 0x22, " than my last one. Also, I have ", \
   "discovered an opportunity for additional speed ", \
   "gain. About 99.999% of windows messages, at ", \
   "least in this program, are sent to DefWindowProc. ", \
   "Instead of WndProc coping its params on the stack ", \
   "before calling DefWindowProc, it just discards ", \
   "its local storage and JuMPs to it instead. ", \
   "This eliminates two copies of the same data ", \
   "on the stack and one whole procedure RETurn."
   0x0

hInst dd 0x0

code section

Start:

; Get hInst

sub esp, 0x4 ; Prep 1 Arg
mov d, 0x0 ; Calling App hInst
call GetModuleHandleA ; Get hInst
mov , eax ; Save hInst

; Call FastererWin

sub esp, 0x10 ; Prep 4 Args
mov , eax ; hInst
mov d, 0x0 ; No Prev Inst
mov d, 0x0 ; No Cmd Ln
mov d, 0xA ; Show Def
call WinMain ; FastererWin

; Exit to Win

ret ; Ret Val in EAX

WinMain:

; Reserve Auto Store

sub esp, 0x4C ; 0x30+0x18+0x4

; No Crit Regs on Stack

; Auto Store on Stack

; WndClsEx: esp ; 0x0
; cbSize +0x0
; style +0x4
; lpfnWndProc +0x8
; cbClsEx +0xC
; cbWndEx +0x10
; hInst +0x14
; hIcon +0x18
; hCurs +0x1C
; hbrBckGrnd +0x20
; lpszMnuNm +0x24
; lpszClsNm +0x28
; hIconSm +0x2C

; Msg: esp+0x30 ; 0x0+0x30
        ; hWnd +0x0
; msg +0x4
; wParam +0x8
; lParam +0xC
; time +0x10
; pt +0x14

        ; hWnd: esp+0x48 ; 0x30+0x18

; Ret Addr on Stack

; Ret EIP: esp+0x4C ; 0x48+0x4

; Params on Stack

        ; hInst esp+0x50 ; 0x4C+0x4
        ; hPrevInst esp+0x54 ; 0x50+0x4
; lpCmdLn esp+0x58 ; 0x54+0x4
; nCmdShow esp+0x5C ; 0x58+0x4

; Do Not Preserve Crit Regs

; Fill WinClsEx

mov d, 0x30 ; WinClsEx Size
mov d, 0x1|0x2 ; Horiz and Vert Redraw
mov d, addr WndProc ; FastererWin Wndproc
mov d, 0x0 ; No Extra Cls Bytes
mov d, 0x0 ; No Extra Wnd Bytes
mov , eax ; EAX Still hInst
mov d, 0x5 ; Window Color
mov d, 0x0 ; No Menu
mov d, addr szClsNm ; FastererWin Cls Nm

; Get WinClsEx hIcon and hIconSm

sub esp, 0x8 ; Prep 2 Args
mov d, 0x0 ; Sys hIcon
mov d, 0x7F00 ; Std App hIcon
call LoadIconA ; Get hIcon
mov , eax ; Save WinClsEx hIcon
mov , eax ; Save WinClsEx hIconSm

; Get WinClsEx hCurs

sub esp, 0x8 ; Prep 2 Args
; WOW! ---> ; Correct Args Still on Stack
call LoadCursorA ; Get hCurs
mov , eax ; Save WinClsEx hCurs

; Register FastererWin WinCls

lea eax, ; Load WinClsEx Addr
sub esp, 0x4 ; Prep 1 Arg
mov , eax ; WinClsEx Addr
call RegisterClassExA ; Register FastererWin WinCls

; Create FastererWin Win

sub esp, 0x30 ; Prep 12 Args
mov d, 0x0 ; No Ex Style
mov , addr szClsNm ; FastererWin
mov , addr szAppNm
mov d, 0x0|0x40000|0x80000|0xC00000
; Overlapped|ThickFrame|SysMnu|Caption
mov d, 0x80000000 ; Def X Coord
mov d, 0x80000000 ; Def Y Coord
mov d, 0x80000000 ; Def Width
mov d, 0x80000000 ; Def Height
mov d, 0x0 ; DeskTop Parent Win
mov d, 0x0 ; No Mnu
mov eax, ; Get hInst Param
mov , eax ; hInst Param
mov d, 0x0 ; No Ex Info
call CreateWindowExA ; Create FastererWin Win
mov , eax ; Save FastererWin hWnd

; Show FastererWin Win

sub esp, 0x8 ; Prep 2 Args
mov , eax ; FastererWin hWnd
mov eax, ; Get nCmdShow
mov , eax ; nCmdShow
call ShowWindow ; Show FastererWin Win

; Update FastererWin Win

sub esp, 0x4 ; Prep 1 Arg
mov eax, ; Get FastererWin hWnd
mov , eax ; FastererWin hWnd
call UpdateWindow ; Update FastererWin Win

MsgLp:

; Get Msg

lea eax, ; Get Msg Addr
sub esp, 0x10 ; Prep 4 Args
mov , eax ; Msg Addr
mov d, 0x0 ; No hWnd for All Msgs
mov d, 0x0 ; No Min Msg Filter
mov d, 0x0 ; No Max Msg Filter
call GetMessageA ; Get Msg

; Exit Msg Lp on Null Msg

or eax, eax ; Check Null Msg
jz >EndMsgLp ; Exit Msg Lp on Null Msg

; Do Not Trans Msg

; Dispatch Msg

lea eax, ; Get Msg Addr
sub esp, 0x4 ; Prep 1 Arg
mov , eax ; Msg Addr
call DispatchMessageA ; Dispatch Msg

jmp <MsgLp ; Keep Pumping Msgs

EndMsgLp:

mov eax, ; Ret Msg wParam

; Do Not Restore Crit Regs

; Discard Auto Store

add esp, 0x4C ; 0x30+0x18+0x4

; Exit to Start

ret 0x10 ; Discard 4 Params

WndProc:

; Reserve Auto Store

sub esp, 0x48 ; 0x34+0x10+0x4

; No Crit Regs on Stack

; Auto Store on Stack

; PaintStruct: esp ; 0x0
; hdc +0x0
; fErase +0x4
; rcPaint +0x8
; fRestore +0xC
; fIncUpdate +0x10
; rgbReserved +0x14

; Rect: esp+0x34 ; 0x0+0x34
; left +0x0
; top +0x4
; right +0x8
; bottom +0xC

; hdc: esp+0x44 ; 0x34+0x10

; Ret Addr on Stack

; Ret EIP: esp+0x48 ; 0x44+0x4

; Params on Stack

        ; hWnd esp+0x4C ; 0x48+0x4
        ; uMsg esp+0x50 ; 0x4C+0x4
; wParam esp+0x54 ; 0x50+0x4
; lParam esp+0x58 ; 0x54+0x4

; Do Not Preserve Crit Regs

ProcMsgs:

; Check for Msgs of Interest

mov eax, ; Get Msg Num

; Something buggy with OnPaint...

;cmp eax, 0xF ; Paint Msg?
;jz >OnPaint ; Paint FastererWin Win

cmp eax, 0x2 ; Destroy Msg?
jz >OnDestroy ; Destroy FastererWin Win

; Discard Auto Store...

add esp, 0x48 ; 0x34+0x10+0x4

; Fwd Msg to Windows

jmp DefWindowProcA ; DefWindowProcA Will
; Ret to WndProc's Caller

OnPaint:

; Paint FastererWin Win

lea eax, ; Get PaintStruct Addr
sub esp, 0x8 ; Prep 2 Args
mov , eax ; PaintStruct Addr
mov eax, ; Get hWnd
mov , eax ; hWnd
call BeginPaint ; Begin Painting
mov , eax ; Save hdc

; Get FastererWin Win Rect

lea eax, ; Get Rect Addr
sub esp, 0x8 ; Prep 2 Args
mov , eax ; Rect Addr
mov eax, ; Get hWnd
mov , eax ; hWnd
call GetClientRect ; Get FastererWin Win Rect

; Draw Text to FastererWin Win

mov eax, ; Get hdc
sub esp, 0x14 ; Prep 5 Args
mov , eax ; hdc
mov , addr szText ; szText Addr
mov d, -1 ; Assume szText Zero Terminated
lea eax, ; Get Rect Addr
mov , eax ; Rect Addr
mov d, 0x10|0x40000 ; Word Break and Ellipsis
call DrawTextA ; Draw Text

; End Paint FastererWin Win

lea eax, ; Get PaintStruct Addr
sub esp, 0x8 ; Prep 2 Args
mov , eax ; PaintStruct Addr
mov eax, ; Get hWnd
mov , eax ; hWnd
call EndPaint ; End Painting

; Set Ret Val

xor eax, eax ; ???

; Exit ProcMsgs

jmp >EndProcMsgs

OnDestroy:

; Destroy FastererWin Win

sub esp, 0x4 ; Prep 1 Arg
mov d, 0x0
call PostQuitMessage ; Destroy FastererWin Win

; Set Ret Val

xor eax, eax ; ???

EndProcMsgs:

; Do Not Restore Crit Regs

; Discard Auto Store

add esp, 0x48 ; 0x34+0x10+0x4

; Exit to Dispatch/SendMessage

ret 0x10 ; Discard 4 Params


If you uncomment this section, listed below for convenience, it crashes after WM_PAINT.


; Something buggy with OnPaint...

;cmp eax, 0xF ; Paint Msg?
;jz >OnPaint ; Paint FastererWin Win


Any masochists out there that can tell me where I goofed, other than the obvious "Why the hell are you coding like that?"?

Thanks to anyone interested in helping.
Attachments:
Posted on 2007-08-31 18:50:56 by TheAbysmal

typedef struct tagPAINTSTRUCT {
  HDC  hdc;
  BOOL fErase;
  RECT rcPaint;
  BOOL fRestore;
  BOOL fIncUpdate;
  BYTE rgbReserved[32];
} PAINTSTRUCT, *PPAINTSTRUCT;

Notice that rcPaint is a RECT and not a DWORD?

; PaintStruct: esp ; 0x0
; hdc +0x0
; fErase             +0x4
; rcPaint             +0x8
; fRestore +0xC                  ;everything from here on is out by 12 bytes <<<<<<<<<<<<<<
; fIncUpdate +0x10
; rgbReserved +0x14

; Rect: esp+0x34 ; 0x0+0x34
Posted on 2007-08-31 19:59:58 by sinsi
Sinsi,

Thanks a million!  You sure made quick work of that.
Posted on 2007-08-31 20:20:13 by TheAbysmal
TheAbysmal,

Okay, before I even begin, I will offer a warning: You might regard the code you are about to read crazy. In it, I use ESP to reference params and locals, I SUBtract from ESP and MOVe params, rather than PUSHing and POPping, and you won't find a PROC...ENDP, STRUCT, or WM_* anywhere.


    I have been doing PROCless programming for years now.  I suggest you read reply #12 of http://www.asmcommunity.net/board/index.php?topic=28695.0 and reply #1 of http://www.asmcommunity.net/board/index.php?topic=24957.0 .  Be careful of not calling DefWindowProc when you should, because that cleans up a lot of things that could come back and bite you unexpectedly.  Ask if you have any questions.  Be warned that MASM is the only assembler I work with.  Ratch
Posted on 2007-09-01 00:43:10 by Ratch
There's one mouse trap with the WM_PAINT message which you must be aware of. That message is sent during the creation of the window. If your procedure is such that it uses data (specially memory addresses) which will be defined only AFTER the creation of the window, it's bound to try accessing illegal memory areas and crash your program right from the start.

To circumvent such a problem, have some kind of a flag in your global data which you have initialized to 0 (or -1 or whatever) and you check it BEFORE running the paint code; you then skip that paint code as long as that flag remains set to its initial value. You modify that flag when you define the required data which would then allow the paint code to be executed as intended.

Raymond
Posted on 2007-09-01 19:17:57 by Raymond