📄 见招拆招《windows程序设计》(七) .txt
字号:
1, 1, 0, 1, 0, 1, 1
dummy0 BYTE 1, 1, 0, 1, 1, 1, 1,\
1, 0, 1, 0, 0, 1, 0,\
1, 1, 1, 1, 1, 1, 1,\
1, 1, 1, 1, 0, 1, 1
ptSegment POINT {7, 6}, {11, 2}, {31, 2}, {35, 6}, {31, 10}, {11, 10},\
{ 6, 7}, {10, 11}, {10, 31}, {6, 35}, {2, 31}, {2, 11},\
{ 36, 7}, {40, 11}, {40, 31}, {36, 35}, {32, 31}, {32, 11},\
{ 7 , 36}, {11, 32}, {31, 32}, {35, 36}, {31, 40}, {11, 40},\
{ 6 , 37}, {10, 41}, {10, 61}, {6, 65}, {2, 61}, {2, 41},\
{ 36, 37}, {40, 41}, {40, 61}, {36, 65}, {32, 61}, {32, 41}
dummy1 POINT { 7 , 66}, {11, 62}, {31, 62}, {35, 66}, {31, 70}, {11, 70}
ptColon POINT {2,21},{6,17},{10,21},{6,25},{2,51},{6,47},{10,51},{6,55 }
.DATA?
hInstance dd ?
cxClient dd ?
cyClient dd ?
f24Hour BOOL ?
fSuppress BOOL ?
hBrushRed HBRUSH ?
.CODE
START: ;从这里开始执行
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke WinMain,hInstance,NULL,NULL,SW_SHOWDEFAULT
invoke ExitProcess,0
WinMain proc hInst:DWORD,hPrevInst:DWORD,CmdLine:DWORD,iCmdShow:DWORD
LOCAL wndclass :WNDCLASSEX
LOCAL msg :MSG
LOCAL hWnd :HWND
mov wndclass.cbSize,sizeof WNDCLASSEX
mov wndclass.style,CS_HREDRAW or CS_VREDRAW
mov wndclass.lpfnWndProc,offset WndProc
mov wndclass.cbClsExtra,0
mov wndclass.cbWndExtra,0
push hInst
pop wndclass.hInstance
invoke LoadIcon,NULL,IDI_APPLICATION
mov wndclass.hIcon,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wndclass.hCursor,eax
invoke GetStockObject,WHITE_BRUSH
mov wndclass.hbrBackground,EAX
mov wndclass.lpszMenuName,NULL
mov wndclass.lpszClassName,offset szAppName
mov wndclass.hIconSm,0
invoke RegisterClassEx, ADDR wndclass
.if (EAX==0)
invoke MessageBox,NULL,CTXT("This program requires Windows NT!"),addr szAppName,MB_ICONERROR
ret
.endif
invoke CreateWindowEx,
NULL,
ADDR szAppName, ;window class name
CTXT("Digital Clock"), ;window caption
WS_OVERLAPPEDWINDOW, ;window style
CW_USEDEFAULT, ;initial x position
CW_USEDEFAULT, ;initial y position
CW_USEDEFAULT, ;initial x size
CW_USEDEFAULT,;initial y size
NULL,;parent window handle
NULL,;window menu handle
hInstance,;program instance handle
NULL;creation parameters
mov hWnd,eax
invoke ShowWindow,hWnd,iCmdShow
invoke UpdateWindow,hWnd
StartLoop:
invoke GetMessage,ADDR msg,NULL,0,0
cmp eax, 0
je ExitLoop
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
jmp StartLoop
ExitLoop:
mov eax,msg.wParam
ret
WinMain endp
DisplayDigit proc hdc:HDC,iNumber:DWORD ;显示一个数字
LOCAL iSeg:DWORD
mov eax,iNumber
shl eax,3
sub eax,iNumber ;iNumber*8-iNumber
lea edi,fSevenSegment
add edi,eax
lea esi,ptSegment;取数字对应的数码管是否显示
mov iSeg,0
.while (iSeg<7)
mov al,[edi]
.if (al!=0)
invoke Polygon,hdc,esi,6
.endif
inc iSeg
add esi,48
add edi,1
.endw
ret
DisplayDigit Endp
DisplayTwoDigits proc hdc:HDC,iNumber:DWORD,fSuppressDT:BOOL ;显示2位数字
xor edx,edx
mov eax,iNumber
mov ecx,10
div ecx
push edx
.if (fSuppressDT==0)||(edx!=0)
invoke DisplayDigit,hdc,eax
.endif
invoke OffsetWindowOrgEx,hdc,-42,0,NULL
pop edx
invoke DisplayDigit,hdc,edx
invoke OffsetWindowOrgEx,hdc,-42,0,NULL
ret
DisplayTwoDigits Endp
DisplayColon proc hdc:HDC ;显示冒号
lea esi,ptColon
invoke Polygon,hdc,esi,4
add esi,32
invoke Polygon,hdc,esi,4
invoke OffsetWindowOrgEx,hdc,-12,0,NULL
ret
DisplayColon Endp
DisplayTime proc hdc:HDC,f24HourDispT:BOOL,fSuppressDispT:BOOL
LOCAL stCurrent:SYSTEMTIME
invoke GetLocalTime,addr stCurrent
.if (f24HourDispT)
invoke DisplayTwoDigits,hdc,stCurrent.wHour,fSuppressDispT
.else
xor edx,edx
xor eax,eax
mov ax,stCurrent.wHour
mov ecx,12
div ecx
.if (edx==0)
mov eax,12
.else
xor eax,eax
mov ax,stCurrent.wHour
.endif
invoke DisplayTwoDigits,hdc,eax,fSuppressDispT
.endif
invoke DisplayColon,hdc
invoke DisplayTwoDigits,hdc,stCurrent.wMinute,FALSE
invoke DisplayColon,hdc
invoke DisplayTwoDigits,hdc,stCurrent.wSecond,FALSE
ret
DisplayTime Endp
WndProc proc uses ebx esi edi ,hwnd:DWORD,message:DWORD,wParam :DWORD,lParam :DWORD
LOCAL hdc:HDC
LOCAL ps :PAINTSTRUCT
LOCAL szBuffer[2] :TCHAR
.if message == WM_CREATE
RGB 255,0,0
invoke CreateSolidBrush,eax
mov hBrushRed,eax
invoke SetTimer,hwnd,ID_TIMER,500,NULL
jmp @f
.elseif message == WM_SETTINGCHANGE
@@:
invoke GetLocaleInfo,LOCALE_USER_DEFAULT,LOCALE_ITIME,addr szBuffer,2
.if (szBuffer[0]=='1')
mov f24Hour,TRUE
.else
mov f24Hour,FALSE
.endif
invoke GetLocaleInfo,LOCALE_USER_DEFAULT,LOCALE_ITLZERO,addr szBuffer,2
.if (szBuffer[0]=='0')
mov f24Hour,TRUE
.else
mov f24Hour,FALSE
.endif
invoke InvalidateRect,hwnd,NULL,TRUE
xor eax,eax
ret
.elseif message == WM_SIZE
LOWORD lParam
mov cxClient,eax
HIWORD lParam
mov cyClient,ebx
xor eax,eax
ret
.elseif message == WM_TIMER
invoke InvalidateRect,hwnd,NULL,TRUE
xor eax,eax
ret
.elseif message == WM_PAINT
invoke BeginPaint, hwnd, ADDR ps
mov hdc,eax ; Get handle to device context
invoke SetMapMode,hdc,MM_ISOTROPIC
invoke SetWindowExtEx,hdc,276,72,NULL
invoke SetViewportExtEx,hdc,cxClient,cyClient,NULL
invoke SetWindowOrgEx,hdc,138,36,NULL
push NULL
mov eax,cyClient
shr eax,1
push eax
mov eax,cxClient
shr eax,1
push eax
push hdc
call SetViewportOrgEx
invoke GetStockObject,NULL_PEN
invoke SelectObject,hdc,eax
invoke SelectObject,hdc,hBrushRed
invoke DisplayTime,hdc,f24Hour,fSuppress
invoke EndPaint, hwnd, ADDR ps
xor eax,eax
ret
.elseif message == WM_DESTROY
invoke KillTimer,hwnd,ID_TIMER
invoke DeleteObject,hBrushRed
invoke PostQuitMessage,NULL
ret
.endif
invoke DefWindowProc,hwnd, message, wParam, lParam
ret
WndProc endp
END START
DIGCLOCK窗口如图8-1所示。
图8-1 DIGCLOCK的屏幕显示
虽然,在图8-1中您看不到时钟的数字是红色的。DIGCLOCK的窗口消息处理程序在处理WM_CREATE消息处理期间建立了一个红色的画刷并在处理WM_DESTROY消息处理期间清除它。WM_CREATE消息也为DIGCLOCK设定了一个一秒的定时器,该定时器在处理WM_DESTROY消息处理期间被终止(待会将讨论对GetLocaleInfo的呼叫)。
在收到WM_TIMER消息后,DIGCLOCK的窗口过程调用InvalidateRect简单地使整个窗口无效。这不是最佳方法,因为每秒整个窗口都要被擦除和重画,有时会引起显示器的闪烁。依据目前的时间使窗口需要更新的部分无效是最好的解决方法。然而,在逻辑上这样做的确很复杂。
在处理WM_TIMER消息处理期间使窗口无效会迫使所有程序的真正活动转入WM_PAINT。DIGCLOCK在WM_PAINT消息一开始将映像方式设定为MM_ISOTROPIC。这样,DIGCLOCK将使用水平方向和垂直方向相等的轴。这些轴(由SetWindowExtEx呼叫设定)是水平276个单位,垂直72个单位。当然,这些轴定得有点太随意了,但它们是按照时钟数字元的大小和间距安排的。
DIGCLOCK将窗口原点设定为(138,36),这是窗口范围的中心;将视埠原点设定为(cxClient / 2,cyClient / 2)。这意味着时钟的显示位于DIGCLOCK显示区域的中心,但是该DIGCLOCK也可以使用在显示屏左上角的原点(0, 0)的轴。
然后WM_PAINT将目前画刷设定为之前建立的红画刷,将目前画笔设定为NULL_PEN,并呼叫DIGCLOCK中的函数DisplayTime。
思考:
仔细阅读程序,
1.如何修改程序使得能够显示24小时制时间或者12小时制时间?
2.如何修改程序,能够完成自动省略0。比如,12:08,显示为12: 8?
3.如果有兴趣的话,不妨修改一个属于你自己的十六进制的电子表。比如: 12:10,显示出来就是C:0A。
取得目前时间
DisplayTime函数开始呼叫Windows函数GetLocalTime,它带有一个的SYSTEMTIME结构的参数,在WINDOWS.INC中定义为:
SYSTEMTIME STRUCT
wYear WORD ?
wMonth WORD ?
wDayOfWeek WORD ?
wDay WORD ?
wHour WORD ?
wMinute WORD ?
wSecond WORD ?
wMilliseconds WORD ?
SYSTEMTIME ENDS
很明显,SYSTEMTIME结构包含日期和时间。月份由1开始递增(也就是说,一月是1),星期由0开始递增(星期天是0)。wDay成员是本月目前的日子,也是由1开始递增的。
SYSTEMTIME主要用于GetLocalTime和GetSystemTime函数。GetSystemTime函数传回目前的世界时间(Coordinated Universal Time,UTC),大概与英国格林威治时间相同。GetLocalTime函数传回当地时间,依据计算机所在的时区。这些值的精确度完全决定于使用者所调整的时间精确度以及是否指定了正确的时区。可以双击工作栏的时间显示来检查计算机上的时区设定。
Windows还有SetLocalTime和SetSystemTime函数,可以在MSDN上查找到详细介绍。
显示数字和冒号
如果DIGCLOCK使用一种仿真7段显示的字体将会简单一些。否则,它就得使用Polygon函数做所有的工作。
DIGCLOCK中的DisplayDigit函数定义了两个数组。fSevenSegment数组有7个BOOL值,用于从0到9的每个十进制数。这些值指出了哪一段需要显示(为1),哪一段不需要显示(为0)。在这个数组中,7段由上到下、由左到右排序。7段中的每个段都是一个6边的多边形。ptSegment数组是一个POINT结构的数组,指出了7个段中每个点的图形坐标。每个数字由下列程序代码画出:
mov eax,iNumber
shl eax,3
sub eax,iNumber ;iNumber*8-iNumber
lea edi,fSevenSegment
add edi,eax
lea esi,ptSegment;取数字对应的数码管是否显示
mov iSeg,0
.while (iSeg<7)
mov al,[edi]
.if (al!=0)
invoke Polygon,hdc,esi,6
.endif
inc iSeg
add esi,48 ;需要注意的是汇编语言处理结构体的时候需要自己计算
add edi,1
.endw
类似地(但更简单),DisplayColon函数在小时与分钟、分钟与秒之间画一个冒号。数字是42个单位宽,冒号是12个单位宽,因此6个数字与2个冒号,总宽度是276个单位,SetWindowExtEx呼叫中使用了这个大小。
回到DisplayTime函数,原点位于最左数字位置的左上角。DisplayTime呼叫DisplayTwoDigits,DisplayTwoDigits呼叫DisplayDigit两次,并且在每次呼叫OffsetWindowOrgEx后,将窗口原点向右移动42个单位。类似地,DisplayColon函数在画完冒号后,将窗口原点向右移动12个单位。用这种方法,不管对象出现在窗口内的哪个地方,函数对数字和冒号都使用同样的坐标。
这个程序的其它技巧是以12小时或24小时的格式显示时间以及当最左边的小时数字为0时不显示它。
建立模拟时钟
模拟时为了正确的显示时钟,您需要知道一些三角函数。CLOCK如程序8-4所示。
程序8-4 CLOCK
CLOCK.Asm 本程序使用的是网上流传的一份程序
;MASMPlus 代码模板 - 普通的 Windows 程序代码
.386
.Model Flat, StdCall
Option Casemap :None
Include windows.inc
Include user32.inc
Include kernel32.inc
Include gdi32.inc
includelib gdi32.lib
IncludeLib user32.lib
IncludeLib kernel32.lib
include macro.asm
LOWORD MACRO bigword;; Retrieves the low word from double word argument
mov eax,bigword
and eax,0FFFFh ;; Get low word
ENDM
HIWORD MACRO bigword ;; Retrieves the high word from double word
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -