📄 clock.asm
字号:
;MoveToEx函数用来设置当前点的位置
;X1和Y1指出当前点的坐标
invoke LineTo,hDC,X2,Y2
;LineTo函数和MoveToEx函数配合起来使用
;用来绘制一条从点(X1,Y1)到(X2,Y2)的线段
ret
_DrawLine endp
;显示时钟
_ShowTime proc _hWnd,hDC
local stTime:SYSTEMTIME ;SYSTEMTIME是一个结构,
;包括年月日时分秒等信息
;stTime是一个结构变量
pushad
invoke GetLocalTime,addr stTime ;获取系统时间,返回到stTime中
invoke _CalcClock ;调用子程序计算时钟在窗口中的位置和大小
;画时钟圆周上的点
invoke GetStockObject,WHITE_PEN
;此函数得到画笔颜色,这里用白色画笔
;对象句柄,返回值放在eax中
invoke SelectObject,hDC,eax
;SelectObject函数用来将GetStockObject函数
;得到的对象句柄放到hDC中
;画时钟圆心
mov eax,CentX
mov ecx,CentX
mov ebx,CentY
mov edx,CentY
sub eax,6 ;圆心半径为6
add ecx,6
sub ebx,6
add edx,6
invoke Ellipse,hDC,eax,ebx,ecx,edx
invoke _DrawDot,hDC,90,4 ;90=360/4 ,画 4个大圆点,半径为4
invoke _DrawDot,hDC,30,3 ;30=360/12,画12个中圆点,半径为3
invoke _DrawDot,hDC,6,1 ;6=360/60 ,画60个小圆点,半径为1
;画时钟指针
;画秒针
;CreatePen函数可以自定义画笔
invoke CreatePen,PS_SOLID,1,00000ffh
;1代表画笔粗度,00000ffh代表画笔颜色为红色
invoke SelectObject,hDC,eax
invoke DeleteObject,eax
movzx eax,stTime.wSecond ;eax中放系统时间的秒值
mov ecx,6 ;6=360/60
mul ecx ;秒针度数=秒*360/60
invoke _DrawLine,hDC,eax,12
;调用子程序画秒针,12用来调整秒针长度
;画分针
invoke CreatePen,PS_SOLID,2,000ff00h
;2代表画笔粗度,000ff00h代表画笔颜色为绿色
invoke SelectObject,hDC,eax
invoke DeleteObject,eax
movzx eax,stTime.wMinute ;eax中放系统时间的分值
mov ecx,6 ;6=360/60
mul ecx ;分针度数 = 分*360/60
invoke _DrawLine,hDC,eax,20
;调用子程序画分针,20用来调整分针长度
;画时针
invoke CreatePen,PS_SOLID,3,0ff0080h
;3代表画笔粗度,0ff0080h代表画笔颜色为紫色
invoke SelectObject,hDC,eax
invoke DeleteObject,eax
movzx eax,stTime.wHour ;eax中放系统时间的小时值
.if eax>=12
sub eax,12
;系统时间为24小时制,若超过12小时就减去12
;使小时保持在0到12之间能被时钟显示
.endif
mov ecx,30 ;30=360/12
mul ecx
movzx ecx,stTime.wMinute
shr ecx,1
add eax,ecx
invoke _DrawLine,hDC,eax,32
;调用子程序画时针,32用来调整时针长度
popad
ret
_ShowTime endp
;处理消息的子程序,
;窗口过程,用来给Windows回调
;这一部分直接套用了一般的模板;
;然后在里面加入了自己的注释,
;因为对这些API函数还没有时间熟悉
;以后要继续熟悉
_ProcWinMain proc uses ebx edi esi hWnd,uMsg,wParam,lParam
local stPS:PAINTSTRUCT ;局部结构变量
mov eax,uMsg
.if eax==WM_TIMER
;WM_TIMER消息一般在计时器超时时发送
;用来执行计时回调函数
;(在一些资料上看到说这个消息存在
;安全问题,攻击者可以利用这个漏洞
;造成权限提升,具体的我还没有搞明白
;这里又留下一个问题)
invoke InvalidateRect,hWnd,NULL,TRUE
;此函数屏蔽窗口客户区的区域
;导致窗口客户区被重画
.elseif eax==WM_PAINT
;绘制自己的客户区的代码放在这里
invoke BeginPaint,hWnd,addr stPS
;WM_PAINT消息呼叫此函数,
;使区域变成有效
;它和EndPaint成对被呼叫
invoke _ShowTime,hWnd,eax
;区域有效后调用子程序显示时钟
invoke EndPaint,hWnd,addr stPS
.elseif eax==WM_CREATE
;WM_CREATE是窗口建立收到的消息,
;放置窗口初始化代码
invoke SetTimer,hWnd,1,1000,NULL
.elseif eax==WM_CLOSE
;WM_CLOSE是退出窗口时发送的消息
invoke KillTimer,hWnd,1
;此函数用来取消定时器
invoke DestroyWindow,hWinMain
;此函数摧毁窗口
invoke PostQuitMessage,NULL
;此函数结束消息循环
.else
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
;此函数是默认的窗口回调函数
;默认处理窗口的最大化最小化关闭等
ret
.endif
xor eax,eax
ret
_ProcWinMain endp
_WinMain proc
local stWndClass:WNDCLASSEX
;结构变量,WNDCLASSEX是一个有12个成员变量的结构体
;定义了窗口的属性等信息如图标光标
local stMsg:MSG
;结构变量,为了从消息队列中获取消息信息而使用MSG结构
invoke GetModuleHandle,NULL ;得到应用程序的句柄
mov hInstance,eax
;注册窗口类
;这里查了一些资料,了解了这里用到的API函数,
;直接套用了一般窗口程序(包括上面处理消息的子程序)
;的模板,在里面添加了自己的一些数据,注释是自己写的。
invoke RtlZeroMemory,addr stWndClass,sizeof stWndClass
;此函数用来清除缓冲区,是为了下一次能正确显示
invoke LoadCursor,0,IDC_ARROW
;此函数用来装入光标,IDC_ARROW代表标准的箭头形状
mov stWndClass.hCursor,eax ;光标
push hInstance
pop stWndClass.hInstance
;窗口所属的应用程序实例句柄
mov stWndClass.cbSize,sizeof WNDCLASSEX
;本结构体所占字节数
mov stWndClass.style,CS_HREDRAW or CS_VREDRAW
;窗口类型风格
mov stWndClass.lpfnWndProc,offset _ProcWinMain
;回调函数指针,指向前面那个回调函数
invoke CreateSolidBrush,0002540h
;此函数得到画刷颜色,这里用棕色画刷
;对象句柄,返回值放在eax中
mov stWndClass.hbrBackground,eax
;刷窗口颜色的画刷句柄,背景色为棕色
mov stWndClass.lpszClassName,offset szClassName
;指向窗口类名字的字符串指针
invoke RegisterClassEx,addr stWndClass
;注册窗口类的函数
invoke CreateWindowEx,WS_EX_CLIENTEDGE,\ ;建立窗口的函数
offset szClassName,offset szClassName,\
WS_OVERLAPPEDWINDOW,\
800,1,200,210,\ ;设置窗口位置(800和1为窗口左上角顶点的坐标位置)
NULL,NULL,hInstance,NULL ;和大小(200和210分别为窗口的宽和高)
mov hWinMain,eax
invoke ShowWindow,hWinMain,SW_SHOWNORMAL
;显示窗口的函数
invoke UpdateWindow,hWinMain
;刷新窗口客户区的函数,
;这个画时钟的程序每次显示都刷新窗口客户区
; 消息循环
.while TRUE
invoke GetMessage,addr stMsg,NULL,0,0 ;获取消息
.break .if eax == 0
invoke TranslateMessage,addr stMsg
;把基于键盘扫描码的按键消息转换成基于ASCII码的键盘消息
invoke DispatchMessage,addr stMsg
;回调函数,使系统将消息发送到窗口过程来处理
.endw
ret
_WinMain endp
;程序入口
start:
call _WinMain
invoke ExitProcess,NULL
end start
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -