|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
方式A的时钟.ASM
================================================================================
;程序运行结构
;01:程序建立消息循环
;02:窗口过程中创建窗口发送消息定时器
;03:设置客户区为无效矩形(每秒执行一次)
;04:然后在PAINT消息中开始绘画
; 05:执行_ShowTime子程序来
; 06:执行_CalcClockParam子程序计算时钟的位置、大小等参数
; 07:比较客户区宽度和高度,以小的值作为时钟的直径
; 08:画时钟圆周上的点
; 09:调用_DrawDot画12个大圆点
; 10:调用_CalcX子程序:计算时钟圆周上某个角度对应的 X 坐标
; 11:调用_CalcY子程序:计算时钟圆周上某个角度对应的 X 坐标
; 12:调用_DrawDot画60个小圆点
; 13:调用_CalcX子程序:计算时钟圆周上某个角度对应的 X 坐标
; 14:调用_CalcY子程序:计算时钟圆周上某个角度对应的 X 坐标
; 15:画时钟指针
; 16:调用_DrawLine绘画秒针、计算线条两端的坐标
; 17:调用_DrawLine绘画分针、计算线条两端的坐标
; 18:调用_DrawLine绘画时针、计算线条两端的坐标
; 19:结束_ShowTime子程序
;20:退出
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.386
.model flat, stdcall
option casemap :none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
include Gdi32.inc
includelib Gdi32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Equ 等值定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ICO_MAIN equ 1000h
ID_TIMER equ 1
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data?
hInstance dd ?
hWinMain dd ?
dwCenterX dd ? ;圆心X
dwCenterY dd ? ;圆心Y
dwRadius dd ? ;半径
.const
szClassName db '精简时钟',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 计算时钟的位置、大小等参数
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_CalcClockParam proc
local @stRect:RECT
invoke GetClientRect,hWinMain,addr @stRect ;获取客户区矩形左上角和右下角
;invoke GetWindowRect,hWinMain,addr @stRect
;获取的是程序的窗口坐标,不是按屏幕坐标
mov eax,@stRect.right ;将右下角X坐标放入eax
;sub eax,@stRect.left ;右下角X坐标减去左上角X坐标的值等于矩形宽度
mov ecx,@stRect.bottom ;将右下角Y坐标放入ecx
;sub ecx,@stRect.top ;右下角Y坐标减去左上角Y坐标的值等于矩形高度
;*****************************************************************************************************************
; 比较客户区宽度和高度,以小的值作为时钟的直径
;*****************************************************************************************************************
.if ecx > eax ;高度大于宽度
mov edx,eax ;将宽度放入edx寄存器
sub ecx,eax ;高度减去宽度的值放入ecx,便于改变大小时,还是在中间
shr ecx,1 ;将ecx的值除以2的1次方
mov dwCenterX,0 ;将圆心x置0
mov dwCenterY,ecx ;将exc(宽高相差值的一半)放入圆心y
.else ;高度小于或等于宽度
mov edx,ecx ;将高度放入edx寄存器
sub eax,ecx ;宽度减去高度然后把差值放入eax,便于改变大小时,还是在中间
shr eax,1 ;将eax的值除以2的1次方
mov dwCenterX,eax ;将差值放入圆心x
mov dwCenterY,0 ;将0放入放入圆心y
.endif
shr edx,1 ;将距离短的高度或者宽度除以2的1次方
mov dwRadius,edx ;半径
add dwCenterX,edx ;圆心x加上半径
add dwCenterY,edx ;圆心y加上半径
ret ;得到圆心坐标(x,y)返回
_CalcClockParam endp
_dwPara180 dw 180 ;类型:字
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 计算时钟圆周上某个角度对应的 X 坐标
; X = 圆心X + Sin(角度) * 半径
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_CalcX proc _dwDegree,_dwRadius ;角度,半径
local @dwReturn ;存储X坐标结果
fild dwCenterX ;将圆心x按整型放入st0(浮点栈顶)
fild _dwDegree ;将角度按整型放入st0(浮点栈顶),别的浮点数据栈+1
fldpi ;将圆周率压入浮点栈
fmulp st(1),st ;角度*圆周率(没有操作数的隐含规则:st(1),st(0)),清空参数1和参数2并将结果放入栈顶(st0)
;fistp @dwReturn
;操作完成后st(1)和st(0)会被清空,别的栈会上升,结果保存在st(0)
;如果fmul操作后带有参数,那么栈不会清空,并且把结果存放至参数1
;参数后面加上P代表弹出栈顶,fmulp st(1),st中的结果放在了参数1中,不是st(0)
fild _dwPara180 ;将类型为【字】的数据180按整型放入栈顶
fdivp st(1),st ;【角度*Pi】/180并把结果存放至st0
;参数1和参数2都会被清空,结果存在栈顶
fsin ;Sin(角度*圆周率/180)
fild _dwRadius ;将半径按整型放入st0
fmulp st(1),st(0) ;半径*Sin(角度*圆周率/180)【隐含操作数:st(1),st(0)】
faddp st(1),st(0) ;X+半径*Sin(角度*圆周率/180)
fistp @dwReturn ;将st(0)按整型存储至@dwReturn并将st(0)弹出
mov eax,@dwReturn ;将数据放入eax
ret
_CalcX endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 计算时钟圆周上某个角度对应的 Y 坐标
; Y = 圆心Y - Cos(角度) * 半径
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_CalcY proc _dwDegree,_dwRadius ;;角度,半径
local @dwReturn ;存储Y坐标结果
fild dwCenterY ;将圆心y按整型放入栈顶
fild _dwDegree ;将角度按整型放入栈顶
fldpi ;将圆周率放入栈顶
fmulp st(1),st(0) ;(角度*圆周率)st(0)和st(1)相乘后清空st(0)和st(1)并把结果放入栈顶
;参数后面加上P代表弹出栈顶,fmulp st(1),st中的结果放在了参赛1中,不是st(0)
fild _dwPara180 ;将180按整型存入栈顶
fdivp st(1),st ;参数1除以参数2后清空st(0)和st(1)并将结果放入栈顶
fcos ;Cos(角度*圆周率/180)
fild _dwRadius ;将半径存放至栈顶
fmulp st(1),st(0) ;半径*Cos(角度*圆周率/180)【隐含操作数:st(1),st(0)】
fsubp st(1),st ;参数1减去参数2,将结果存放至st(1),并且将st(0)弹出
fistp @dwReturn ;将st(0)按照整型存储至@dwReturn并弹出st(0)
mov eax,@dwReturn ;将数据放入eax
ret
_CalcY endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 按照 _dwDegreeInc 的步进角度,画 _dwRadius 为半径的小圆点
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_DrawDot proc _hDC,_dwDegreeInc,_dwRadius ;设备环境句柄,步进角度,小圆点半径
local @dwNowDegree,@dwR ;当前角度,局部半径
local @dwX1,@dwY1 ;X和Y坐标
mov @dwNowDegree,0 ;当前角度置0
mov eax,dwRadius ;将半径放入eax
sub eax,5 ;半径减去5
mov @dwR,eax ;将运算过的半径放入局部半径
.while @dwNowDegree <= 360
finit ;浮点堆栈清空
;*****************************************************************************************************************
; 计算小圆点的圆心坐标
;*****************************************************************************************************************
invoke _CalcX,@dwNowDegree,@dwR ;调用_CalcX子程序,参数:当前角度,局部半径
;计算时钟圆周上某个角度对应的 X 坐标
mov @dwX1,eax
invoke _CalcY,@dwNowDegree,@dwR ;调用_CalcY子程序,参数:当前角度,局部半径
;计算时钟圆周上某个角度对应的 Y 坐标
mov @dwY1,eax ;eax是Y坐标
mov esi,@dwX1
add esi,_dwRadius
push esi
pop @dwX1
sub esi,_dwRadius
sub esi,_dwRadius
mov edi,@dwY1
add edi,_dwRadius
push edi
pop @dwY1
sub edi,_dwRadius
sub edi,_dwRadius
invoke Ellipse,_hDC,esi,edi,@dwX1,@dwY1
mov eax,_dwDegreeInc ;步进角度放入eax
add @dwNowDegree,eax ;角度相加
.endw
ret
_DrawDot endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 秒针、分针、时针:画 _dwDegree 角度的线条,半径=时钟半径-参数_dwRadiusAdjust
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_DrawLine proc _hDC,_dwDegree,_dwRadiusAdjust ;参数:设备环境句柄,当前的角度,需要校正长度的值
local @dwR ;存储校正长度的秒针
local @dwX1,@dwY1,@dwX2,@dwY2 ;局部变量:从(x1,y1)画线到(x2,y2)
mov eax,dwRadius ;存储半径至eax
sub eax,_dwRadiusAdjust ;校正指针长度
mov @dwR,eax ;存储指针长度至局部变量@dwR
;*****************************************************************************************************************
; 计算线条两端的坐标
;*****************************************************************************************************************
invoke _CalcX,_dwDegree,@dwR ;计算时钟圆周上某个角度对应的 X1 坐标、参数:角度,半径
mov @dwX1,eax ;将x1放入局部变量@dwX1
invoke _CalcY,_dwDegree,@dwR ;计算时钟圆周上某个角度对应的 Y1 坐标、参数:角度,半径
mov @dwY1,eax ;将y1放入局部变量@dwY1
add _dwDegree,180 ;角度增加180度(半个圆)
invoke _CalcX,_dwDegree,8 ;计算时钟圆周上某个角度对应的 X2 坐标、参数:角度,半径:8
mov @dwX2,eax ;将x2放入局部变量@dwX2
invoke _CalcY,_dwDegree,8 ;计算时钟圆周上某个角度对应的 Y2 坐标、参数:角度,半径:8
mov @dwY2,eax ;将y2放入局部变量@dwY2
invoke MoveToEx,_hDC,@dwX1,@dwY1,NULL ;指定当前新的(x,y)坐标位置
invoke LineTo,_hDC,@dwX2,@dwY2 ;从当前位置画直线到(x,y),超过了圆心点
ret
_DrawLine endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ShowTime proc _hWnd,_hDC
local @stTime:SYSTEMTIME ;结构体包含系统时间相关
pushad
invoke GetLocalTime,addr @stTime ;将时间信息返回到@stTime结构体中
invoke _CalcClockParam ;该子程序计算时钟的位置、大小等参数
;*****************************************************************************************************************
; 画时钟圆周上的点
;*****************************************************************************************************************
invoke CreateSolidBrush,255 ;获取预定义库存中的画笔、刷子、字体、或调色板的句柄
invoke SelectObject,_hDC,eax ;设置在某个设备环境句柄中使用什么绘图工具
invoke _DrawDot,_hDC,360/12,3 ;该子程序画12个大圆点:设备环境句柄,步进角度,半径
invoke _DrawDot,_hDC,360/60,1 ;该子程序画60个小圆点:设备环境句柄,步进角度,半径
;*****************************************************************************************************************
; 画时钟指针
;*****************************************************************************************************************
invoke CreatePen,PS_SOLID,1,0 ;黑色画笔
;该函数创建一个逻辑画笔,它有指定的样式,宽度和颜色,能被任何DC选择为当前画笔
;nPenStyle :画笔工作的样式
;PS_SOLID :实心笔
;PS_DASH :短线式笔
;PS_DOT :点式笔
;PS_DASHDOT :点线笔
;PS_DASHDOTDOT :双点线笔
;PS_NULL :笔不可见
;PS_INSIDEFRAME :实线线条,和PS_SOLID相同,但是如果画笔宽度大于1像素时,宽度会像内部扩展
;nWidth :指定的宽度(逻辑单位)
;crColor :笔的基准颜色
invoke SelectObject,_hDC,eax ;设置设备环境使用实心笔来绘画
invoke DeleteObject,eax ;删除上一次使用的绘画工具
movzx eax,@stTime.wSecond ;将当前秒值扩展为双字放入eax
mov ecx,360/60 ;将每秒的度数6放入ecx
mul ecx ;秒针度数 = 秒 * 360/60
invoke _DrawLine,_hDC,eax,5 ;参数:设备环境句柄,当前的角度,需要校正长度的值
;*****************************************************************************************************************
invoke CreatePen,PS_SOLID,2,255 ;创建画笔参数:实心笔、宽度为2、颜色红色
invoke SelectObject,_hDC,eax ;设置画笔为这个设备环境服务
invoke DeleteObject,eax ;删除上次的绘画工具
movzx eax,@stTime.wMinute ;当前分钟值扩展为双字放入eax
mov ecx,360/60 ;将分钟度数为6放入ecx
mul ecx ;分针度数 = 分 * 360/60
invoke _DrawLine,_hDC,eax,20 ;参数:设备环境句柄,当前的角度,需要校正长度的值
;*****************************************************************************************************************
invoke CreatePen,PS_SOLID,3,250*10000h ;创建画笔参数:实心笔、宽度为3、颜色蓝色
invoke SelectObject,_hDC,eax ;设置画笔为这个设备环境服务
invoke DeleteObject,eax ;删除上次的绘画工具
movzx eax,@stTime.wHour ;当前时钟值扩展为双字放入eax
.if eax >= 12 ;如果大于12小时则减去12
sub eax,12
.endif
mov ecx,360/12 ;将每个时钟间隔度数放入ecx
mul ecx ;eax = 时钟间隔度数*几点钟(小于<12)
movzx ecx,@stTime.wMinute ;将当前分钟放入ecx
shr ecx,1 ;将ecx除以2的1次方
add eax,ecx ;eax = 当前时钟角度加上分钟角度的一半
invoke _DrawLine,_hDC,eax,40 ;参数:设备环境句柄,当前的角度,需要校正长度的值
;*****************************************************************************************************************
invoke GetStockObject,NULL_PEN ;取得空画笔的句柄
invoke SelectObject,_hDC,eax ;设置设备环境句柄为空画笔
invoke DeleteObject,eax ;删除上一次使用的绘画工具
popad
ret
_ShowTime endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcWinMain proc uses ebx edi esi hWnd,uMsg,wParam,lParam
local @stPS:PAINTSTRUCT
mov eax,uMsg
.if eax == WM_TIMER ;定时器消息
invoke InvalidateRect,hWnd,NULL,TRUE ;将客户区改变为无效区域,TRUE代表擦除背景
.elseif eax == WM_PAINT ;绘画窗口的消息
invoke BeginPaint,hWnd,addr @stPS ;开始绘画,将要绘画的信息放入@stPS结构体中,返回值为设备环境句柄
invoke _ShowTime,hWnd,eax ;执行子程序,参数1为窗口句柄,参数2为设备环境句柄
invoke EndPaint,hWnd,addr @stPS ;结束绘画
.elseif eax == WM_CREATE ;创建窗口的消息
invoke SetTimer,hWnd,ID_TIMER,1000,NULL ;创建1s执行一次的定时器
;*****************************************************************************************************************
.elseif eax == WM_RBUTTONUP ;单击右键,退出
invoke KillTimer,hWnd,ID_TIMER ;清理定时器
invoke DestroyWindow,hWinMain ;摧毁窗口
invoke PostQuitMessage,NULL ;退出消息循环
;*****************************************************************************************************************
.elseif eax == WM_CLOSE ;退出
invoke KillTimer,hWnd,ID_TIMER ;清理定时器
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
local @stMsg:MSG
invoke GetModuleHandle,NULL
mov hInstance,eax
;*****************************************************************************************************************
; 注册窗口类
;*****************************************************************************************************************
invoke RtlZeroMemory,addr @stWndClass,sizeof @stWndClass
invoke LoadIcon,hInstance,ICO_MAIN
mov @stWndClass.hIcon,eax
mov @stWndClass.hIconSm,eax
invoke LoadCursor,0,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 CreateHatchBrush,HS_DIAGCROSS,200*100h ;设置背景颜色
mov @stWndClass.hbrBackground,eax
mov @stWndClass.lpszClassName,offset szClassName
invoke RegisterClassEx,addr @stWndClass
;*****************************************************************************************************************
; 建立并显示窗口
;*****************************************************************************************************************
invoke CreateWindowEx,WS_EX_CLIENTEDGE or WS_EX_TOPMOST,offset szClassName,offset szClassName,WS_OVERLAPPEDWINDOW,550,200,240,250,\
NULL,NULL,hInstance,NULL
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
invoke DispatchMessage,addr @stMsg
.endw
ret
_WinMain endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
call _WinMain
invoke ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
end start
方式A的时钟.RC
=========================================================================================
#include <resource.h>
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//宏命令
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#define ICO_MAIN 0x1000 //图标
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ICO_MAIN ICON "Main.ico"
|
|