常用的masm32宏 等等

common.inc

;--------------------------------------------------------------------

; common.inc

; 宏中不要使用@@, 因为它在展开后,会与程序中定义的@@冲突

; 引用文本宏的值时,注意不要为 文本宏名 加<>, 否则会出错
; 引用参数的值作为文本值使用时,注意一定要为 形参名 加<>,否则会出错。因为 形参名 只是占位符,
; 在宏展开时会被替换为 实参的值。

; 宏的调试:定义一个局部文本宏debugtext, 赋给它调试用的信息,再配合% echo debugtext来在汇编时输出
; 或是直接用echo输出一些调试信息

ifndef COMMON_INC
        COMMON_INC equ 1

;TRUE = 1    
;FALSE = 0  ; 以上两个在windows.inc中有定义

CR = 0dh
LF = 0ah
TAB = 9        ; 占8个空格的显示空间

StdOut textequ <_StdOut>  ; 与masm32库一致
StdErr textequ <_StdErr>
StdIn  textequ <_StdIn>

; 用来查看宏的传参情况
printargs macro vars:vararg
        local   debugtext
        debugtext textequ <>
        
        for param,<vars>
                debugtext textequ <"&param">
                % echo debugtext
        endm
endm

;----------------------------------------------------
; 以下3个宏是用来定义字符串指针表。如果能把指针表及字符串都定义在常量区是最完美的,但
; 如此会出现这个问题:strtable_cont宏展开时会在指针表中间定义字符串,破坏掉表的连续性

; 在常量段定义字符串并在数据段中引用其偏移地址
TXT   macro   text:vararg  ; 参数可为多个,格式同一般的在数据段的字符或字符串定义
    local   lblText

    .const
    lblText    db  text, 0
    
    .data
        exitm <offset lblText> ; 调用宏的文本被替换为此
endm

; 用来在数据区中调用,本宏展开后会在数据区中定义字符串指针表,并在常量区定义对应的字符串
; strtable tblSregsNames, TXT("cs"), TXT("ds"), TXT("ss"), TXT("es"), TXT("fs"), TXT("gs"), \
;          TXT("ldtr"), TXT("tr")
; strtable tblClasses, offset tblSystemClass, offset tblDataSegClass ; 二级表
strtable macro tablename:req, strs:vararg
        align 4
        tablename dd   strs
endm

; 因为宏调用语句有行长度的限制(用\续行的话,还是算同一行), 注意紧接着strtable后面用这个宏
; continue
strtable_cont macro strs:vararg
        dd      strs
endm
;----------------------------------------------------

; e.g.: jmptable name, lbl1, lbl2, lbl3, lbl4
; 引用标号时可以不用加offset
jmptable macro name:req, args:vararg
        .data
        align 4
        name dd args
        
        .code
endm
 
; 把一个数值(如数值型宏)转成文本值,方便输出调试信息
; e.g.: cnt = 1
;       % echo num2text(cnt)
num2text macro  num
        exitm %(num)
endm

; 返回参数的个数
getargc macro args:vararg
        local   cnt
        cnt = 0
        for param, <args>
                cnt = cnt + 1
        endm
        exitm <cnt>
endm
    
; 取参数序列args中的第idx个,idx从1开始
getarg  macro idx:req, args:vararg
        local   cnt, retarg
        cnt = 0
        retarg textequ <>
        
        for param, <args>
                cnt = cnt + 1
                if cnt eq idx
                        ;;% echo num2text(cnt) ;;测试num2text宏
                        ;;exitm <param> ;;只是退出for宏而已
                        retarg textequ <param>
                        exitm  ;;退出当前宏
                endif
        endm
        
        exitm retarg  ;; 没有取到的话,返回空
endm

; pushs与pops成对,方便保存与后续恢复多个变量,帮助消除push与pop的配对问题
; e.g.: pushs eax, edx, ecx, ebx, f
;       pops  eax, edx, ecx, ebx, f
pushs   macro   vars:vararg
        for param, <vars>  ;;vars若为空,则进不了这个for宏
                push    param
        endm
endm

; 与pushs成对
; 写本宏时尝试了用echo来输出调试信息
pops    macro   vars:vararg
        local   cnt;;, debugtext

        cnt = getargc(vars)
        while cnt
                ;;debugtext textequ <<getarg(cnt,vars)>>
                ;;% echo debugtext
                pop     getarg(cnt, vars)
                cnt = cnt - 1
        endm
endm

; bHigh与bLow得为常数,也即立即数
MAKEWORD macro bHigh, bLow
        exitm <( ((bHigh) shl 8) or (bLow) )>   ; 用实参替代掉<>中的形参,然后用替换后的<>中的文本替换掉调用宏的指令
endm
makeword equ MAKEWORD

; wHigh与wLow得为常数,也即立即数,与Win32 API文档中的MAKELPARAM宏类似,只是参数顺序相反
MAKEDWORD macro wHigh, wLow
        exitm <( ((wHigh) shl 16) or (wLow) )>   ; 用实参替代掉<>中的形参,然后用替换后的<>中的文本替换掉调用宏的指令
endm
makedword equ MAKEDWORD

; 三个参数得是常数
RGB     macro red, green, blue ; R在最低字节
        exitm <( ((blue) shl 16) or ((green) shl 8) or (red) )>
endm
rgb equ RGB

BLACK = RGB(0,0,0) ;windows.inc中有对应的如Black这样的仅首字母大写形式的宏
BLUE  = RGB(0,0,255)
GREEN = RGB(0,255,0)
CYAN = RGB(0,255,255) ;青色、蓝绿
RED = RGB(255,0,0)
MAGENTA = RGB(255,0,255) ;洋红、红紫
YELLOW = RGB(255,255,0)
WHITE = RGB(255,255,255)
GRAY = RGB(8,8,8)

; 在常量段定义字符串并在代码段中引用其偏移地址
CTEXT   macro   text:vararg  ; 参数可为多个,格式同一般的在数据段的字符或字符串定义
    local   lblText

    .const
    lblText    db     text, 0

    .code
        exitm <offset lblText> ; 调用宏的文本被替换为此
endm
ctext equ CTEXT

CTXT equ CTEXT ; 与masm32一致
ctxt equ CTXT

; 定义函数的静态局部变量
; 定义结构体变量,赋值时要用双层<>, 如static  hitpointL, POINT, <<0, 0>>。<>是用来包含特殊字符,如空格和<>
static  macro  varName, varType, varValue:vararg ;值域可为多个,否则如'1','2'就只能取前一个
        .data        
        align 4 ;
        varName varType varValue    
        .code   ; 切换回代码段,否则会报错
endm

;---------------------------- c风格 ----------------------------------
float equ <real4>  ; 不能为float = <real4>
double equ <real8> ; = 后面只能是数值表达式;equ后面可以是数值表达式,也可以是文本

; retVal只能是常数值,为空,或是不计较大小写的eax
return  macro   retVal  
        ;;local   debugtext

        ;;debugtext textequ <"&retVal">
        ;;% echo debugtext
comment /*
        return FALSE
        return TRUE ; 1
        return INVALID_HANDLE_VALUE ;-1
        return edx
        return eax
        return EAX
        return 6+7
% echo debugtext分别输出
        "FALSE"
        "TRUE"
        "INVALID_HANDLE_VALUE"
        "edx"
        "eax"
        "EAX"
        "6+7"
*/        

        ;;retVal是形参,只是个占位符,在宏展开时会被实参的值替换,
        ;;所以一定要加<>, 不加的话,在retVal为空的时候,会出现问题
        ifb <retVal>  
                ret
                exitm
        endif
        
        ifidni <retVal>,<eax> ;;不区分大小写
                ret
                exitm
        endif
              
        if retVal eq 0 ;;用eq的话,如果retVal是如edx等其他的文本值,展开时会出错
                xor     eax, eax
        elseif retVal eq 1
                xor     eax, eax
                inc     eax
        elseif retVal eq -1
                xor     eax, eax
                dec     eax
        else
                mov     eax, retVal
        endif
        ret
endm

exit    macro   exitCode:=<0> ; 默认值为0,用<>包起来,因为默认值表示为文本值
        invoke  ExitProcess, exitCode
endm

fclose  macro   hFile:req       ;req表示参数是必需的
        invoke  CloseHandle, hFile
endm

malloc  macro   cbSize
        invoke  GlobalAlloc, GMEM_FIXED or GMEM_ZEROINIT, cbSize
        exitm <eax>
endm

free    macro   pMem
        invoke  GlobalFree, pMem
endm    
;--------------------------------------------------------------------

;---------------------------- DOS命令风格 -----------------------------
chdir   macro   pathName
        local   char, lblPathName
        
        char    substr <pathName>,1,1
        
        ifidn char,<">
                .const
                lblPathName db pathName, 0
                .code
                invoke  SetCurrentDirectory, offset lblPathName
        else
                ifidn char, <'>
                        .const
                        lblPathName db pathName, 0
                        .code
                        invoke  SetCurrentDirectory, offset lblPathName   
                else
                ;; pathName为路径字符串的地址
                        invoke  SetCurrentDirectory, pathName
                endif
        endif
endm  
cd equ chdir
;---------------------------------------------------------------------

;---------------------------------------------------------------------
; fld/fild的操作数不支持常数, 本宏模拟fld/fild加载常数。注意fpVal/intVal得为常数
; e.g.: fld8    1234.56789
;       fild4   1234
fld4    macro   fpVal
        local   name
        
        .data
        align 4
        name    real4   fpVal
        
        .code
        fld     name
endm


fld8    macro   fpVal
        local   name
        
        .data
        align 4
        name    real8   fpVal
          
        .code
        fld     name
endm


fld10   macro   fpVal
        local   name
        
        .data
        align 4
        name    real10  fpVal
 
        .code
        fld     name
endm

; 16位整数
fild2   macro   intVal
        local   name
        
        .data
        align 2
        name    dw intVal
        
        .code
        fild    name
endm

fild4   macro   intVal
        local   name
        
        .data
        align 4
        name    dd intVal
        
        .code
        fild    name
endm

fild8  macro   intVal
        local   name
        
        .data
        align 4
        name    dq intVal
        
        .code
        fild    name
endm
;---------------------------------------------------------------------
; "aaa.bbb.ccc.ddd"
MAKEIP  macro   aaa, bbb, ccc, ddd
        exitm <( ((aaa) shl 24) or ((bbb) shl 16) or ((ccc) shl 8) or (ddd) )>
endm  
makeip equ MAKEIP

; e.g.: mov hInstance, FUNC(GetModuleHandle,NULL)
FUNC    macro   args:vararg
        invoke  args
        exitm <eax>
endm
func equ FUNC
rv equ FUNC   ; 与masm32一致: return value

; title默认为NULL, 显示为“错误”或"error"
msgbox  macro   owner:=<NULL>, text:req, title:=<NULL>, style:=<MB_OK>
        invoke  MessageBox, owner, text, title, style
endm

GetLastErrMsg macro
        ifndef @@errmsg@@
                .data?
                @@errmsg@@ db 1024 dup (?)
        endif

        .code
        invoke  GetLastError
        invoke  FormatMessage, FORMAT_MESSAGE_FROM_SYSTEM, NULL, \
                        eax, 0, offset @@errmsg@@, sizeof @@errmsg@@, NULL
        exitm   <offset @@errmsg@@>
endm

m2m     macro   m1, m2
        push    m2
        pop     m1
endm

; 用于控制台
write    macro  text:vararg
        invoke  StdOut, CTXT(text)
endm
print equ write

; 在代码节区插入字符串
inlineText  macro   textName, text:vararg
        local   lblNext
        ;; 宏中不要使用@@, 因为它在展开后,会与程序中定义的@@冲突
        jmp     lblNext   ;;@f
        textName db text, 0   
        
lblNext:   ;;@@:
endm
inlinetext equ inlineText
;-------------------- oop之c++风格 ----------------------------------            
class   macro   className
        className struct
                VirtFuncTAble dd 32 dup (?)
                szClassName   db "className", 0
        className ends
endm

new     macro   className
        invoke  GetProcessHeap
        invoke  HeapAlloc, eax, 0, sizeof className
        mov     [eax], offset className&VirtFuncTable
        exitm <eax>
endm

delete  macro   pObj
        mov     eax, pObj
        mov     eax, [eax] ; 得到类的虚函数表的地址
        call    [eax] ; 调用虚函数表的第一个函数,即销毁自身
        invoke  GetProcessHeap
        invoke  HeapFree, eax, 0, pObj        
endm

method  macro   
endm
;--------------------------------------------------------------------
; 定义纯英文的Unicode字符串
; 其实用dw定义,更方便,生成的汇编文本也越少
wstr macro text:vararg
        local   lblText, textline, strvalue, ch, idx, cnt ;; 局部标号与局部宏名的定义
        ;; 若上面的宏名不用local定义,在宏外可以访问到
        
        ;;得再这样定义一次,否则在无名宏中不可见
        textline textequ <lblText db >
        strvalue textequ <>
        ch textequ <>
        idx = 0
        cnt sizestr textline ;; 若宏生成的汇编代码文本行太长,汇编器不会接受
 
        for arg, <text>
                ch substr <arg>, 1, 1
                
                ifidn ch,<">
                ;; 两头以"包住字符串,字符串中不会有", 因为masm不允许
                        idx = 2
                        while 1
                                ch substr <arg>, idx, 1
                                ifidn ch, <">
                                        exitm
                                endif
                                
                                ifb strvalue
                                        strvalue catstr <">, ch, <",0>
                                        cnt = cnt + 5
                                else
                                        strvalue catstr strvalue, <,">, ch, <",0>
                                        cnt = cnt + 6
                                endif

                                if cnt ge 80 ;; 换一行输出
                                        textline catstr textline, strvalue
                                        
                                        .const
                                        textline
                                        
                                        textline textequ <db >
                                        cnt = 3
                                        strvalue textequ <>
                                endif
                                
                                idx = idx + 1
                        endm
                else
                        ifidn ch,<'>
                        ;; 两头以'包住字符串,字符串中不会有', 因为masm不允许
                                idx = 2
                                while 1
                                        ch substr <arg>, idx, 1
                                        ifidn ch, <'>
                                                exitm
                                        endif
                                        
                                        ifb strvalue
                                                strvalue catstr <'>, ch, <',0>
                                                cnt = cnt + 5
                                        else
                                                strvalue catstr strvalue, <,'>, ch, <',0>
                                                cnt = cnt + 6
                                        endif

                                        if cnt ge 80 ;; 换一行输出
                                                textline catstr textline, strvalue
                                                
                                                .const
                                                textline
                                        
                                                textline textequ <db >
                                                cnt = 3
                                                strvalue textequ <>
                                        endif                            
                                        
                                        idx = idx + 1
                                endm
                        else
                        ;; 不知道arg的长度。为保险,输出后换一行
                                ifb strvalue
                                        strvalue catstr <arg>, <,0>
                                else
                                        strvalue catstr strvalue, <arg>, <,0>
                                endif

                                textline catstr textline, strvalue
                                .const
                                textline   
              
                                textline textequ <db >
                                cnt = 3
                                strvalue textequ <>
                        endif
                endif
        endm
        
        ifb strvalue
                strvalue textequ <0,0>
        else
                strvalue catstr strvalue, <,0,0>
        endif
        
        textline catstr textline, strvalue        
        .const
        textline
        
        .code
        exitm <offset lblText>
endm

; 在代码节区嵌入纯英文的Unicode字符串
; 其实用dw定义,更方便,生成的汇编文本也越少
inlineWText macro name:req, text:vararg
        local   lblNext, textline, strvalue, ch, idx, cnt ;; 局部标号与局部宏名的定义
        ;; 若上面的宏名不用local定义,在宏外可以访问到
        
        ;;得再这样定义一次,否则在无名宏中不可见
        textline catstr <name>, < db >
        strvalue textequ <>
        ch textequ <>
        idx = 0
        cnt sizestr textline ;; 若宏生成的汇编代码文本行太长,汇编器不会接受
 
        .code
        jmp     lblNext
        
        for arg, <text>
                ch substr <arg>, 1, 1
                
                ifidn ch,<">
                ;; 两头以"包住字符串,字符串中不会有", 因为masm不允许
                        idx = 2
                        while 1
                                ch substr <arg>, idx, 1
                                ifidn ch, <">
                                        exitm
                                endif
                                
                                ifb strvalue
                                        strvalue catstr <">, ch, <",0>
                                        cnt = cnt + 5
                                else
                                        strvalue catstr strvalue, <,">, ch, <",0>
                                        cnt = cnt + 6
                                endif

                                if cnt ge 80 ;; 换一行输出
                                        textline catstr textline, strvalue
                                        
                                        .code
                                        textline
                                        
                                        textline textequ <db >
                                        cnt = 3
                                        strvalue textequ <>
                                endif
                                
                                idx = idx + 1
                        endm
                else
                        ifidn ch,<'>
                        ;; 两头以'包住字符串,字符串中不会有', 因为masm不允许
                                idx = 2
                                while 1
                                        ch substr <arg>, idx, 1
                                        ifidn ch, <'>
                                                exitm
                                        endif
                                        
                                        ifb strvalue
                                                strvalue catstr <'>, ch, <',0>
                                                cnt = cnt + 5
                                        else
                                                strvalue catstr strvalue, <,'>, ch, <',0>
                                                cnt = cnt + 6
                                        endif

                                        if cnt ge 80 ;; 换一行输出
                                                textline catstr textline, strvalue
                                                
                                                .code
                                                textline
                                        
                                                textline textequ <db >
                                                cnt = 3
                                                strvalue textequ <>
                                        endif                            
                                        
                                        idx = idx + 1
                                endm
                        else
                        ;; 不知道arg的长度。为保险,输出后换一行
                                ifb strvalue
                                        strvalue catstr <arg>, <,0>
                                else
                                        strvalue catstr strvalue, <arg>, <,0>
                                endif

                                textline catstr textline, strvalue
                                .code
                                textline   
              
                                textline textequ <db >
                                cnt = 3
                                strvalue textequ <>
                        endif
                endif
        endm
        
        ifb strvalue
                strvalue textequ <0,0>
        else
                strvalue catstr strvalue, <,0,0>
        endif
        
        textline catstr textline, strvalue    
        .code
        textline
        
lblNext:
endm
inlinewtext equ inlineWText

else
        echo -----------------------------------------
        echo WARNING Duplicate include file common.inc
        echo -----------------------------------------
        
endif


;----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

; common.asm


.686p
.model  stdcall, flat
option  casemap: none

include common.inc
include file.inc
includelib file.lib ; 静态库
include console.inc
includelib console.lib ; 静态库

include windows.inc
include kernel32.inc
includelib kernel32.lib
include user32.inc
includelib user32.lib
include gdi32.inc
includelib gdi32.lib
include comctl32.inc
includelib comctl32.lib
include shell32.inc
includelib shell32.lib
include comdlg32.inc
includelib comdlg32.lib




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值