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 <"¶m">
% 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
331

被折叠的 条评论
为什么被折叠?



