⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 见招拆招《windows程序设计》(七) .txt

📁 会变语言实现的一些程序
💻 TXT
📖 第 1 页 / 共 4 页
字号:
                   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 + -