_CASE MACRO regmem:REQ,tag:REQ,msgs:VARARG ;; inspired by Sashka Yackubtchick

FOR msg,<&msgs>
cmp regmem,msg
je tag&_&msg
WndProc PROC hWnd:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD

mov eax,uMsg
_CASE eax,<_>, \
invoke DefWindowProc,hWnd,uMsg,wParam,lParam

mov eax,wParam
return 0

iMOVr4 kh,0.025
return 0
iMOVr4 kh,-0.025
return 0
iMOVr4 ka,0.025
return 0
iMOVr4 ka,-0.025
return 0
invoke SendMessage,hWnd,WM_CLOSE,0,0
return 0

mov eax,wParam
return 0

iMOVr4 kh,0.0
return 0
iMOVr4 ka,0.0
return 0

return HTCLIENT;

mov eax,wParam
jmp Default

return 1

mov eax,wParam
mov active,TRUE
jmp Default

mov active,FALSE
jmp Default

mov eax,active
cmp eax,ready
jne Default
cmp eax,TRUE
jne Default
invoke SetCursor,NULL
jmp Default

invoke DestroyWindow,hWnd
invoke PostQuitMessage,0
return 0
WndProc ENDP
Hey, maybe it's just me, but I think it looks better than all those .if/.else/.endif.
It isn't to shabby speedwise either.
Posted on 2002-06-15 22:57:04 by bitRAKE
Certainly an interesting idea.


Posted on 2002-06-15 23:00:16 by hutch--
This macro is truly creative but -
why bother using assembly if you want to code this way? C could be a better choice if your in favour of macros.

Just my thought.:rolleyes:

Posted on 2002-06-15 23:08:33 by C.Z.
bomb01, please show us one of your more complex message loops - so that we may all learn how it should be done in ASM. All I have seen around here is very unreadable code - to me the above is very self documenting, and I'm too lazy to document most code. :)
Posted on 2002-06-15 23:22:10 by bitRAKE
bitRAKE, my msg loops are done in C.
As of doing in assembly, your macro is quite a fabulous choice; but in my humble opinion coding interface in assembly isn't worth it.
Just too much effort with little gain.
Maybe it's just because...because I am still an asm newbie.:grin:
Posted on 2002-06-15 23:36:47 by C.Z.

bitRAKE, my msg loops are done in C. As of doing in assembly, your macro is quite a fabulous choice; but in my humble opinion coding interface in assembly isn't worth it.
The above message loop is a direct translation from the C, and it is less code that the C version. So, when you say, "isn't worth it", is that not because your C programming is faster than your ASM programming? ...or is it because your C compiler optimizes your message loops better than the code above? I think well in ASM and code faster in ASM, but that is just me. The code above can easily be optimized, imo. Also, the code is very cut-n-paste type material.

I see you have answered above. :)
Really, it is the same lines as the C code, not less. ;)
Posted on 2002-06-15 23:44:11 by bitRAKE
Here is my implementation of swith/case. I have attatched it in a file since it is quite complex. It uses C syntax (switch/case/default) but has the functionality of the Pascal "Select Case". In other words it allows for multiple items for each case. And any item can be a "range" (case lowval .. hival).

for example:

case !, 2, 7 .. 11

I have included an example in the attachment.
Posted on 2002-06-16 02:25:20 by gfalen
Hmmm the attachment did'nt takeso here is the code

; Switch/Case emulation
; ---------------------
$casflg equ <>
$casvar equ <>
$casstk equ <>

switch macro _var:req, _reg:=<eax>
mov _reg, _var
$casstk catstr <_reg>, <#>, $casflg, <#>, $casstk
$casvar equ _reg
$casflg equ <0> ;; 0 = emit an .if, 1 an .elseif

case macro _args:vararg ;; like Pascal: case id1. id4 .. id8, lparam, ...
;; does an or (case1 || case2 || case3...)
$cas textequ <>
irp $v, <_args> ;; for each case
t@ instr <$v>, <..> ;; range ?
if t@ ;; yes
$LB substr <$v>, 1, t@-1 ;; lbound = left portion
$LB catstr <(>, $casvar, <!>=>, $LB, <)> ;; ($casvar >= lbound)
$UB substr <$v>, t@+2 ;; ubound = right portion
$UB catstr <(>, $casvar, <!<=>, $UB, <)> ;; ($casvar <= ubound)
$t catstr <(>, $LB, <&&> , $UB,<)> ;; (($casvar >= $lb) && ($casvar <= $ub))
else ;; no, it's a value (var/const)
$t catstr <(>, $casvar, <==>, <$v>, <)> ;; ($casvar == value)
$cas catstr <|| >, $t, $cas ;; or this case w/ others
$cas substr $cas, 3 ;; lose the extra "|| " in front
ifidn $casflg, <0> ;; 0 = 1'st case
% .if $cas ;; emit ".if"
else ;; all others
% .elseif $cas ;; emit ".elseif"
$casflg equ <1> ;; NOT 1'st

default macro _default:vararg

endsw macro _cmd:vararg
ifidn $casstk, <>
.err <Endsw w/o Switch>
t@ instr $casstk, <#>
$casvar substr $casstk, 1, t@-1
$casstk substr $casstk, t@+1
t@ instr $casstk, <#>
$casflg substr $casstk, 1, t@-1
ifidn $casstk, <#>
$casstk equ <>
$casstk substr $casstk, t@+1

... and an example of usage:

; In window proc

switch uMsg

case WM_SIZE

case WM_COMMAND ; menu/toolbar commands
movzx eax, word ptr wParam
switch eax
case id_close
case id_help
case id_new .. id_print


invoke DefWindowProc, hWin, uMsg, wParam, lParam
Posted on 2002-06-16 02:43:01 by gfalen
gfalen, very impressive, very flexible!
I'll be keeping a copy in my macro toolbox.
Thank you for sharing.
Posted on 2002-06-16 03:01:23 by bitRAKE
I always wondered why people use conditional jumps to implementing switch (or the equivalent in a HLL other than C). Of course, if there are small number of cases, Jcc is the way to go. But, the code presented by bitRAKE may utilize indirect jump to implement it. Since WndProc is the busiest routine under Win32, too many Jcc would not help speeding up the application. I personally prefer indirect jump when the number of cases is more than 10, and use Jcc otherwise. And, for the same reason, I _hate_ and _avoid_ those high level directives, which usually generate horrible code.

What do you guys think about it?
Posted on 2002-06-16 03:16:33 by Starless
This thread is a good read and outlines the reason for using different methods, iirc. My experience is that there are many messages coming through the WndProc that I don't process and all those JE instructions are correctly predicted (not taken) as well as very little instruction cache polution - all the way around this method is the best one until your processing a large percentage of the messages. Caleb and Svin help bring this to my attention.
Posted on 2002-06-16 03:40:22 by bitRAKE
Here's my complete macro file. Lot of good stuff
Posted on 2002-06-16 09:00:23 by gfalen

Your switch macro looks very good, its the first effective one I have seen done for MASM in macros. Compliments on a nice piece of code.



PS : I have just rewritten one of my templates using this macro and the switch/case macro works perfectly with the normal nesting of switch/case statements.


I just wrote some equates for case variation with the macro names.

; ------------------------------------------
; equates for case variation in macro names
; ------------------------------------------
Case equ <case>
CASE equ <case>
Switch equ <switch>
SWITCH equ <switch>
Endsw equ <endsw>
EndSw equ <endsw>
ENDSW equ <endsw>
Posted on 2002-06-16 09:04:04 by hutch--
Thanx for the compliments guys. I have posted a zip file (above) which contains two files:

Masm.inc - Non-model specific macros used in 16 or 32 segments. Macro primitives (helper macros used by other macros), pseudo-ops (like incx, decx which allow mulltiple arguments) and HLL implementations.

Macs32.inc - wrappers for Win32 API functions. Note: many of these "wrappers" link to library functions some of which are my own design & not part of the MASN32 package. I will be happy to provide the source(s) to these lib functions to any interested parties.

Feel free to use and or publish any part of these files as you see fit. I'll be happy to answer any questions (usage, limitations discussion etc.) to the best of my ability.

My gift to the community. Enjoy!
Posted on 2002-06-16 09:34:58 by gfalen
Hutch, Bitrake:

I was'nt sure how this macro would be recieved. I'm glad to see you guys liked it! The macro (as I posted it) is different from the one I use (see post above with attachment). Mine uses a "let" macro (let eax = _var - instead of mov eax, _var). The "Let" macro automatically promotes a byte or word to dword using the movzx instruction (no provision for "signed" values yet).

The file Masm.inc included in the attachment has many similarly complex macros. The "Static" macro is not working yet so don't use it!
I was thinking about asking bitrake for some ideas on this one.

Some other macros I use frequently are:

dim & data - let you save lines by putting declarations on one line
enum - id1[=val][:step], id2, id3[=val2] ...
for init, limit, step
iff expression, action - uses 1 line instead of three
let var1=val1, var2=val2 ... - auto promote byte/word to dword & m2m
locals v1[=val], v2[=val] ... - auto-initializes locals

I provided these files for everyone's use so feel free. And Hutch you may of course make any or all of this available for MASM32.

Feedback welcome. Enjoy.
Posted on 2002-06-16 10:08:12 by gfalen
I have attached a prostart template that has been modified to use Greg's "switch" set of macros.

In conjunction with a few other macros, the format is starting be be as fast and convenient as coding a high level language but with the obvious exception, it is still assembler and its size shows it.

The mentality I have here is that API code is hack operating system code that needs to be got working in the most painless method possible so that the performance aspects of a program can be worked on within a reasonable time frame.

I am still in beta with two code wizards and this macro set of Gregs is a natural for the design I want for the templates that they create.


Posted on 2002-06-16 10:44:28 by hutch--