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.
If you uncomment this section, listed below for convenience, it crashes after WM_PAINT.
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.
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.
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
Sinsi,
Thanks a million! You sure made quick work of that.
Thanks a million! You sure made quick work of that.
TheAbysmal,
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
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
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
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