📄 clock.asm
字号:
;这里是用Win32汇编写的程序
;只是在十几天内看了一些书,
;对具体的API函数的细节还并
;不熟悉,所以后面的窗口程序部分
;就直接套用了一些模板,需要继
;续深入学习。之所以选择Win32Asm
;是因为它的用途,比起DOS下汇编
;要广得多,比如可以利用Windows
;本身提供的API函数等。
;对于本身学的信息安全专业,
;汇编起到很重要的作用,机器底层
;的东西需要汇编去做;病毒,加密
;解密之类的需要用汇编去做
;看了一些加密解密的书,首先提到的
;就是要有汇编基础。这学期汇编学习
;了基础的,要想深入还需要多看书多写
;程序并且和高级语言结合起来,所以我
;们要学习要实践的还有很多。老师常说
;要提出一些问题,解决一些问题,再留
;下一些可以继续研究讨论的余地。学习
;就是这样,老师教给了我们基础的,
;继续向深处的学习就要靠我们自己了,
;每门课都留给了我们继续学习的余地,
;学习无止境。
;这个程序是在窗口中用时钟显示系统时间
;查了很多资料才找到需要的API函数的
;具体用法,写了很多注释
NAME Clock
.386
.model flat,stdcall
option casemap:none
; INCLUDE 文件定义
include\masm32\include\windows.inc
include\masm32\include\user32.inc
includelib\masm32\lib\user32.lib
include\masm32\include\kernel32.inc
includelib\masm32\lib\kernel32.lib
include\masm32\include\Gdi32.inc
includelib\masm32\lib\Gdi32.lib
; 数据段
.data? ;未赋初值变量
CentX dd ? ;圆心X
CentY dd ? ;圆心Y
Radius dd ? ;半径
hInstance dd ? ;注册窗口类的应用程序实例句柄
hWinMain dd ?
.const ;常量数据
szClassName db 'Clock',0 ;窗口名
_180 dw 180 ;180代表角度
; 代码段
.code
;下面两个子程序用一些FPU指令计算某角度对应坐标
;子程序,已知半径
;计算圆周上某角度对应的X坐标,
;X = CentX + Sin(角度) *半径
_CalcX proc _X,_Degree,_Radius
local Retr ;局部变量,用来放弹出的坐标值
fild _X ;圆心X压栈
fild _Radius ;半径压栈
fild _Degree ;角度压栈
fldpi ;常量指令,圆周率压栈
fild _180 ;180度压栈
fdivp st(1),st ;Pi/180
fmul ;角度*Pi/180,结果压栈
fsin ;Sin(角度*Pi/180),结果压栈
fmul ;半径*Sin(角度*Pi/180),结果压栈
fadd ;CentX+半径*Sin(角度*Pi/180),结果压栈
fistp Retr ;把X坐标弹出到Retr中
mov eax,Retr
ret
_CalcX endp
;子程序,已知半径
;计算圆周上某角度对应的Y坐标,
;Y = _Y - Cos(角度) *半径
_CalcY proc _Y,_Degree,_Radius
local Retr ;局部变量,用来放弹出的坐标值
fild _Y ;圆心Y压栈
fild _Radius ;半径压栈
fild _Degree ;角度压栈
fldpi ;常量指令,圆周率压栈
fild _180 ;180度压栈
fdivp st(1),st ;Pi/180
fmul ;角度*Pi/180
fcos ;Cos(角度*Pi/180)
fmul ;半径*Cos(角度*Pi/180)
fsubp st(1),st ;CentY-半径*Cos(角度*Pi/180)
fistp Retr ;把Y坐标弹出到Retr中
mov eax,Retr
ret
_CalcY endp
;子程序,计算时钟的位置、大小等
_CalcClock proc
local Lrect:RECT ;局部结构变量
invoke GetClientRect,hWinMain,addr Lrect
;此函数返回指定窗口客户区矩形的大小到Lrect中
;取局部变量偏移地址要用addr
mov eax,Lrect.right
sub eax,Lrect.left ;eax = 宽度
mov ecx,Lrect.bottom
sub ecx,Lrect.top ;ecx = 高度
;比较宽度和高度,以小的值用做时钟的直径
.if ecx>eax
mov edx,eax ;高度>宽度就以宽度作直径
sub ecx,eax
shr ecx,1
mov CentX,0
mov CentY,ecx
.else
mov edx,ecx ;高度<宽度就以高度作直径
sub eax,ecx
shr eax,1
mov CentX,eax
mov CentY,0
.endif
shr edx,1
mov Radius,edx
add CentX,edx ;得到圆心X坐标CentX
add CentY,edx ;得到圆心Y坐标CentY
ret
_CalcClock endp
;画_Radius为半径的圆点
;本来想用画多边形的函数Polygon画五角形的点的
;但是调试了好多次都不行,
;只好改画椭圆形点(这里实际上就是圆点)
;注释掉的是开始写的五角形点
_DrawDot proc hDC,_DegreeInc,_Radius
;_DegreeInc为角度增量,_Radius为半径
local Dgr,R
;local iDgr,iDgrInc
local X,Y
;local Pt[5]:POINT ;用来放五角星五个角坐标
mov Dgr,0
;mov iDgr,0
;mov iDgrInc,72 ;内重循环角度增量
mov eax,Radius
sub eax,10
mov R,eax
.while Dgr<=360 ;循环,直到画了一圈
finit ;初始化FPU寄存器
invoke _CalcX,CentX,Dgr,R ;计算钟面圆周上小圆点的圆心X坐标
mov X,eax
invoke _CalcY,CentY,Dgr,R ;计算钟面圆周上小圆点的圆心X坐标
mov Y,eax
;mov edi,0
;.while edi<5
;invoke _CalcX,X,iDgr,_Radius
;mov Pt[edi].x,eax
;invoke _CalcY,Y,iDgr,_Radius
;mov Pt[edi].y,eax
;inc edi
;mov eax,iDgrInc
;add iDgr,eax
;.endw
;invoke Polygon,hDC,addr Pt,5
mov eax,X
mov ecx,X
mov ebx,Y
mov edx,Y
sub eax,_Radius
add ecx,_Radius
sub ebx,_Radius
add edx,_Radius
invoke Ellipse,hDC,eax,ebx,ecx,edx
mov eax,_DegreeInc
add Dgr,eax ;角度增加_DegreeInc
.endw
ret
_DrawDot endp
; 画线条,半径=时钟半径-参数_RAdj
_DrawLine proc hDC,_Degree,_RAdj
;_Degree用来指定画的线的偏移度数
;_RAdj用来调整画的线的长度,
;秒针、分针、时针长度应该一次减少
local R
local X1,Y1,X2,Y2
mov eax,Radius
sub eax,_RAdj
mov R,eax
; 计算线条两端的坐标
invoke _CalcX,CentX,_Degree,R ;调用子程序计算指针尖X坐标
mov X1,eax
invoke _CalcY,CentY,_Degree,R ;调用子程序计算针尖Y坐标
mov Y1,eax
add _Degree,180
invoke _CalcX,CentX,_Degree,10 ;调用子程序计算针尾X坐标
mov X2,eax
invoke _CalcY,CentY,_Degree,10 ;调用子程序计算针尾X坐标
mov Y2,eax
invoke MoveToEx,hDC,X1,Y1,NULL
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -