见招拆招Windows程序设计(六) 第二部分
相关的例子:下载>>> 作者:Zoologist 于2008-3-16上传 

紧接上一部分
子窗口和键盘

为CHECKER3添加键盘接口就像CHECKER系列构想中的最后一步。但在这样做的时候,可能有更适当的做法。在CHECKER2中,鼠标光标的位置决定按下Spacebar键时哪个区域将获得标记符号。当我们处理子窗口时,我们能从对话框功能中获得提示。在对话框中,带有闪烁的插入符号或点划的矩形的子窗口表示它有输入焦点(当然也可以用键盘进行定位)。

我们不需要把Windows内部已有的对话框处理方式重新写过,我只是要告诉您大致上应该如何在应用程序中仿真对话框。研究过程中,您会发现这样一件事:父窗口和子窗口可能要共享同键盘消息处理。按下Spacebar键和Enter键时,子窗口将锁定复选标记。按下方向键时,父窗口将在子窗口之间移动输入焦点。实际上,当您在子窗口上单击时,情况会有些复杂,这时是父窗口而不是子窗口获得输入焦点。

CHECKER4.C如程序7-5所示。

程序7-5 CHECKER4

        
CHECKER4.ASM
;MASMPlus 代码模板 - 普通的 Windows 程序代码

.386
.Model Flat, StdCall
Option Casemap :None

Include windows.inc
Include user32.inc
Include kernel32.inc
Include gdi32.inc
Include libc.inc

includelib gdi32.lib
IncludeLib user32.lib
IncludeLib kernel32.lib
IncludeLib msvcrt.lib
include macro.asm
	
	WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD
	WndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD
	
DIVISIONS equ	5

.DATA
	szAppName	DB		"Checker4",0
	szChildClass DB	"Checker4_Child",0
	idFocus 		DD		0
.DATA?
	hInstance	DD		?
	hwndChild	DD		DIVISIONS*DIVISIONS dup (?)
	

	szBuffer		db		100 dup (?)

.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

   mov wndclass.lpfnWndProc,offset ChildWndProc    
   mov wndclass.cbWndExtra,sizeof (LONG) 
   mov wndclass.hIcon,NULL
	mov wndclass.lpszClassName,offset szChildClass
	invoke RegisterClassEx, ADDR wndclass

	invoke CreateWindowEx,
					NULL,
					ADDR szAppName, 	;window class name
					CTXT("Checker3 Mouse Hit-Test Demo"), ;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

WndProc proc hwnd:DWORD,message:DWORD,wParam :DWORD,lParam :DWORD
		
	LOCAL hdc 				:HDC
   LOCAL x,y,cxBlock,cyBlock :DWORD
	LOCAL xcx,ycy:DWORD   
	.if	  message == WM_CREATE

     	 lea		esi,hwndChild
       xor		eax,eax
       mov		x,eax
     loop1x:
     	 xor		eax,eax
     	 mov		y,eax
     	loop1y:
     	 invoke	GetWindowLong,hwnd,GWL_HINSTANCE
     	 mov		ecx,eax
	;invoke	wsprintf,addr szBuffer,CTXT("%d"),sizeof (LONG) 
	;invoke	MessageBox,hwnd,addr szBuffer,NULL,NULL	     	 
     	 mov		ebx,y
     	 shl		ebx,8
     	 or		ebx,x
		 invoke	CreateWindowEx,NULL,offset szChildClass,NULL,
		 				WS_CHILDWINDOW or WS_VISIBLE,
		 				0, 0, 0, 0,
		 				hwnd,ebx,ecx,NULL
		 mov		[esi],eax
		 add		esi,4
	 
     	 inc		y
     	 mov		eax,y
     	 cmp		eax,DIVISIONS
     	 jb		loop1y
     	 
     	 inc		x
     	 mov		eax,x
     	 cmp		eax,DIVISIONS
     	 jb		loop1x
		     	 
		 ret
	.elseif message == WM_SIZE
		 mov		eax,lParam	;cxBlock = LOWORD (lParam) / DIVISIONS 
		 shl		eax,16
		 shr		eax,16
		 mov		ecx,DIVISIONS
		 xor		edx,edx
		 div		ecx
		 mov		cxBlock,eax
		
		 mov		eax,lParam	 ;cyBlock = HIWORD (lParam) / DIVISIONS
		 shr		eax,16
 	 	 mov		ecx,DIVISIONS
 	 	 xor		edx,edx
		 div		ecx
		 mov		cyBlock,eax

		 lea		esi,hwndChild                                                   
       xor		eax,eax
       mov		x,eax
     loop2x:
     	 xor		eax,eax
     	 mov		y,eax
     	loop2y:
		 mov		eax,x
		 mov		ecx,cxBlock
		 mul		ecx
		 mov		xcx,eax
		 
		 mov		eax,y
		 mov		ecx,cyBlock
		 mul		ecx
		 mov		ycy,eax
;MoveWindow (  hwndChild[x][y],x * cxBlock, y * cyBlock,cxBlock, cyBlock, TRUE)		 
		 invoke	MoveWindow,[esi],xcx,ycy,cxBlock,cyBlock,TRUE

		 ;mov		[esi],eax
		 add		esi,4
		 
     	 inc		y
     	 mov		eax,y
     	 cmp		eax,DIVISIONS
     	 jb		loop2y
     	 
     	 
     	 inc		x
     	 mov		eax,x
     	 cmp		eax,DIVISIONS
     	 jb		loop2x
     	 
       ret

   .elseif message == WM_LBUTTONDOWN
       invoke	MessageBeep,0 
      ret
    ;On set-focus message, set focus to child window
	.elseif message == WM_SETFOCUS
		 invoke	GetDlgItem,hwnd, idFocus
       invoke	SetFocus ,eax
       ret
    ;On key-down message, possibly change the focus window
	.elseif message == WM_KEYDOWN
       mov		eax,idFocus
       and		eax,0FFh
       mov		x,eax
  
  		 mov		eax,idFocus
  		 shr		eax,8
  		 mov		y,eax
		.if	wParam == VK_UP
				dec	y
		.elseif wParam == VK_DOWN
				inc	y
		.elseif wParam == VK_LEFT
				dec	x
		.elseif wParam == VK_RIGHT
				inc	x
		.elseif wParam == VK_HOME
				xor	eax,eax
				mov	x,eax
				mov	y,eax
		.elseif wParam == VK_END
				mov	eax,DIVISIONS-1
				mov	x,eax
				mov	y,eax
		.else
				ret
		.endif		
		 mov		eax,x
		 add		eax,DIVISIONS
		 xor		edx,edx
		 mov		ecx,DIVISIONS
		 div		ecx
		 mov		x,edx

		 mov		eax,y
		 add		eax,DIVISIONS
		 xor		edx,edx
		 mov		ecx,DIVISIONS
		 div		ecx
		 mov		y,edx		

       mov	   eax,y
       shl		eax,8
       or		eax,x
       mov		idFocus,eax

		 invoke	GetDlgItem,hwnd, idFocus
       invoke	SetFocus ,eax

		 ret
		 
	.elseif message == WM_DESTROY
		invoke PostQuitMessage,NULL		
		ret
	.endif

	invoke DefWindowProc,hwnd, message, wParam, lParam
	ret
WndProc endp

ChildWndProc proc hwnd:DWORD,message:DWORD,wParam :DWORD,lParam :DWORD
	LOCAL hdc 				:HDC
	LOCAL ps  				:PAINTSTRUCT 
	LOCAL	rect				:RECT	
	.if	  message == WM_CREATE
      invoke	SetWindowLong,hwnd, 0, 0      ; on/off flag
      ret
   .elseif message == WM_KEYDOWN
	;Send most key presses to the parent window
		.if (wParam != VK_RETURN) && (wParam != VK_SPACE)
			invoke	GetParent,hwnd
         invoke	SendMessage,eax, message, wParam, lParam
			ret
		.endif	
        ; For Return and Space, fall through to toggle the square
       jmp	@f  
   .elseif message == WM_LBUTTONDOWN
     @@:
   	invoke	GetWindowLong,hwnd,0
   	xor		eax,1
      invoke	SetWindowLong ,hwnd, 0, eax
      invoke	SetFocus,hwnd
      invoke   InvalidateRect,hwnd, NULL, FALSE
		ret
	;For focus messages, invalidate the window for repaint
	.elseif	message == WM_SETFOCUS
		invoke	GetWindowLong,hwnd, GWL_ID
		mov		idFocus,eax
		jmp	@f	
	;Fall through
	.elseif	message == WM_KILLFOCUS
		@@:
      invoke	InvalidateRect,hwnd, NULL, TRUE
		ret
		.elseif message == WM_PAINT
			
		invoke	BeginPaint,hwnd,addr ps
		mov		hdc,eax
      invoke    GetClientRect,hwnd, addr rect
      lea		esi,rect
      mov		eax,[esi+8]
      mov		ebx,[esi+12]
      invoke 	 Rectangle,hdc, 0, 0, eax,ebx
		
		invoke	GetWindowLong,hwnd,0
		.if	eax != 0
      	lea		esi,rect			                                      
			invoke	MoveToEx,hdc,0,0,NULL
			mov		ebx,[esi+8]	;Right
			mov		ecx,[esi+12];Buttom
			invoke	LineTo,hdc,ebx,ecx
			mov		ecx,[esi+12];Buttom			
			invoke	MoveToEx,hdc,0,ecx,NULL
			invoke	LineTo,hdc,ebx,0
		.endif	
             ;Draw the "focus" rectangle
                                  
          invoke	GetFocus        
			.if	eax == hwnd
					lea	esi,rect
            ;rect.left   += rect.right / 10 
					mov	eax,[esi+8]
					mov	ecx,10
					xor	edx,edx
					div	ecx
					add	[esi],eax
				
	;rect.right  -= rect.left
					mov	eax,[esi+8]
					sub	eax,[esi]
					mov	[esi+8],eax

	;rect.top    += rect.bottom / 10
					mov	eax,[esi+12]
					mov	ecx,10
					xor	edx,edx
					div	ecx
					add	[esi+4],eax					
	;rect.bottom -= rect.top					
					mov	eax,[esi+12]
					sub	eax,[esi]
					mov	[esi+12],eax				
					invoke 	GetStockObject,NULL_BRUSH
					invoke 	SelectObject,hdc,eax
					
					invoke	CreatePen,PS_DASH,0,0
					invoke	SelectObject,hdc,eax
					
					lea		esi,rect
					push		[esi+12]
					push		[esi+8]
					push		[esi+4]
					push		[esi]
					push		hdc
					call		Rectangle

					invoke	GetStockObject,BLACK_PEN
					invoke	SelectObject,hdc,eax
					invoke	DeleteObject,eax

			.endif	
		invoke	  EndPaint,hwnd,addr ps
		ret
	.endif
	invoke	DefWindowProc,hwnd, message, wParam, lParam
	ret
ChildWndProc endp
END START

        

ss5.JPG (27468 字节)

                             运行结果

您应该能回忆起每一个子窗口有唯一的子窗口ID,该ID在呼叫CreateWindow建立窗口时定义。在CHECKER3中,此ID是矩形的x和y位置的组合。一个程序可以通过下面的呼叫来获得一个特定子窗口的子窗口ID:

idChild = GetWindowLong (hwndChild, GWL_ID) ;
        

下面的函数也有同样的功能:

idChild = GetDlgCtrlID (hwndChild) ;
        

正如函数名称所表示的,它主要用于对话框和控制窗口。如果您知道父窗口的句柄和子窗口ID,此函数也可以获得子窗口的句柄:

hwndChild = GetDlgItem (hwndParent, idChild) ;
        

在CHECKER4中,整体变量idFocus用于保存目前输入焦点窗口的子窗口ID。我在前面说过,当您在子窗口上面单击鼠标时,它们不会自动获得输入焦点。因此,CHECKER4中的父窗口将通过呼叫下面的函数来处理WM_SETFOCUS消息:

SetFocus (GetDlgItem (hwnd, idFocus)) ;
        

这样设定一个子窗口为输入焦点。

ChildWndProc处理WM_SETFOCUS和WM_KILLFOCUS消息。对于WM_SETFOCUS,它将保存在整体变量idFocus中接收输入焦点的子窗口ID。对于这两种消息,窗口是无效的,并产生一个WM_PAINT消息。如果WM_PAINT消息画出了有输入焦点的子窗口,则它将用PS_DASH画笔的风格画一个矩形以表示此窗口有输入焦点。

ChildWndProc也处理WM_KEYDOWN消息。对于除了Spacebar和Enter键以外的其它消息,WM_KEYDOWN都将给父窗口发送消息。另外,窗口消息处理程序也处理类似WM_LBUTTONDOWN消息的消息。

处理方向移动键是父窗口的事情。在风格相似的CHECKER2中,此程序可获得有输入焦点的子窗口的x和y坐标,并根据按下的特定方向键来改变它们。然后通过呼叫SetFocus将输入焦点设定给新的子窗口。

拦截鼠标

一个窗口消息处理程序通常只在鼠标光标位于窗口的显示区域,或非显示区域上时才接收鼠标消息。一个程序也可能需要在鼠标位于窗口外时接收鼠标消息。如果是这样,程序可以自行「拦截」鼠标。别害怕,这么做没什么大不了的。

设计矩形

为了说明拦截鼠标的必要性,请让我们看一下BLOKOUT1程序(如程序7-6所示)。此程序看起来达到了一定的功能,但它却有十分严重的缺陷。

程序7-6 BLOKOUT1

        
BLOKOUT1.ASM
        

此程序展示了一些,它可以实作在Windows的「画图」程序中的东西。由按下鼠标左键开始确定矩形的一角,然后拖动鼠标。程序将画一个矩形的轮廓,其相对位置是鼠标目前的位置。当您释放鼠标后,程序将填入这个矩形。图7-4显示了一个已经画完的矩形和另一个正在画的矩形。


 

ss6.JPG (17529 字节)

图7-4 BLOKOUT1的屏幕显示

那么,问题在哪里呢?

请试一试下面的操作:在BLOKOUT1的显示区域按下鼠标的左键,然后将光标移出窗口。程序将停止接收WM_MOUSEMOVE消息。现在释放按钮,BLOKOUT1将不再获得WM_BUTTONUP消息,因为光标在显示区域以外。然后将光标移回BLOKOUT1的显示区域,窗口消息处理程序仍然认为按钮处于按下状态。

这样做并不好,因为程序不知道发生了什么事情。

拦截的解决方案

BLOKOUT1显示了一些常见的程序功能,但它的程序代码显然有缺陷。这种问题就是要使用鼠标拦截来对付。如果使用者正在拖曳鼠标,那么当鼠标短时间内被拖出窗口时应该没有什么大问题,程序应该仍然控制着鼠标。

拦截鼠标要比放置一个老鼠夹子容易一些,您只要呼叫:

SetCapture (hwnd) ;
        

在这个函数呼叫之后,Windows将所有鼠标消息发给窗口句柄为hwnd的窗口消息处理程序。之后收到鼠标消息都是以显示区域消息的型态出现,即使鼠标正在窗口的非显示区域。lParam参数将指示鼠标在显示区域坐标中的位置。不过,当鼠标位于显示区域的左边或者上方时,这些x和y坐标可以是负的。当您想释放鼠标时,呼叫:

ReleaseCapture () ;
        

从而使处理恢复正常。

在32位的Windows中,鼠标拦截要比在以前的Windows版本中有多一些限制。特别是,如果鼠标被拦截,而鼠标按键目前并未被按下,并且鼠标光标移到了另一个窗口上,那么将不是由拦截鼠标的那个窗口,而是由光标下面的窗口来接收鼠标消息。对于防止一个程序在拦截鼠标之后不释放它而引起整个系统的混乱,这是必要的。

换句话说,只有当鼠标按键在您的显示区域中被按下时才拦截鼠标;当鼠标按键被释放时,才释放鼠标拦截。

BLOKOUT2程序

展示鼠标拦截的BLOKOUT2程序如程序7-7所示。

程序7-7 BLOKOUT2

        
BLOKOUT2.ASM
        
;MASMPlus 代码模板 - 普通的 Windows 程序代码

.386
.Model Flat, StdCall
Option Casemap :None

Include windows.inc
Include user32.inc
Include kernel32.inc
Include gdi32.inc
Include libc.inc

includelib gdi32.lib
IncludeLib user32.lib
IncludeLib kernel32.lib
IncludeLib msvcrt.lib
include macro.asm
	
	WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD
	WndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD
	
.DATA
	szAppName	DB		"BlokOut2",0
.DATA?
	hInstance	DD		?
   fBlocking		BOOL	?
   fValidBox 	BOOL	?
   ptBeg			POINT  		
   ptEnd			POINT  		
   ptBoxBeg		POINT  		
   ptBoxEnd 	POINT  		

	szBuffer		db		100 dup (?)

.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("Mouse Button & Capture Demo"), ;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

DrawBoxOutline proc hwnd:DWORD,ptBeg2:DWORD,ptEnd2:DWORD
   LOCAL		hdc:HDC
   invoke 	GetDC,hwnd
   mov		hdc,eax
   
   invoke   SetROP2,hdc, R2_NOT
   invoke	GetStockObject,NULL_BRUSH
   invoke   SelectObject,hdc, eax
   
   mov    	esi,ptEnd2	;这个地方传递过来的参数是地址
   push		[esi+4]
   push		[esi]
   
   mov		esi,ptBeg2	;这个地方传递过来的参数是地址
   push		[esi+4]
   push		[esi]
   
   push		hdc
   call		Rectangle
        
   invoke	ReleaseDC,hwnd, hdc
   
	ret
DrawBoxOutline endp

WndProc proc hwnd:DWORD,message:DWORD,wParam :DWORD,lParam :DWORD
		
	LOCAL hdc 				:HDC
	LOCAL ps  				:PAINTSTRUCT 

	.if message == WM_LBUTTONDOWN

		lea		esi,ptBeg
		lea		edi,ptEnd
		
		mov		eax,lParam
		shl		eax,16
		shr		eax,16
		
		mov		[esi],eax
		mov		[edi],eax
		
		mov		eax,lParam
		shr		eax,16
		
		mov		[esi+4],eax
		mov		[edi+4],eax
		
		invoke	DrawBoxOutline,hwnd,addr ptBeg,addr ptEnd
		invoke	SetCapture,hwnd
		invoke	LoadCursor,NULL,IDC_CROSS
		invoke	SetCursor,eax
      mov		fBlocking,TRUE            
		ret	 
		.elseif message == WM_MOUSEMOVE 
      .if		fBlocking == TRUE  
   
		invoke	LoadCursor,NULL,IDC_CROSS
		invoke	SetCursor,eax
      invoke	DrawBoxOutline,hwnd, addr ptBeg, addr ptEnd
      lea		esi,ptEnd
      mov		eax,lParam
      shl		eax,16
      shr		eax,16
      mov		[esi],eax

      mov		eax,lParam
      shr		eax,16
		mov		[esi+4],eax        
        
      invoke	DrawBoxOutline,hwnd, addr ptBeg, addr ptEnd
      .endif
        
       ret
       
		.elseif message == WM_LBUTTONUP  
      .if		fBlocking == TRUE  
		invoke	DrawBoxOutline ,hwnd, addr ptBeg, addr ptEnd
		lea		esi,ptBeg
		lea		edi,ptBoxBeg
		mov		eax,[esi]
		mov		[edi],eax
		mov		eax,[esi+4]
		mov		[edi+4],eax

		lea		esi,ptBoxEnd
		mov		eax,lParam
		shl		eax,16
		shr		eax,16
		mov		[esi],eax
		
		mov		eax,lParam
		shr		eax,16
		mov		[esi+4],eax
		invoke	ReleaseCapture

		invoke	LoadCursor,NULL,IDC_ARROW
		invoke	SetCursor,eax

		mov		fBlocking,FALSE
		mov		fValidBox,TRUE
      invoke	InvalidateRect,hwnd, NULL, TRUE

      .endif
        
       ret			
     .elseif 	message == WM_CHAR
       .if		(wParam == 1Bh) && (fBlocking == TRUE)     ; i.e., Escape
        invoke DrawBoxOutline,hwnd, addr ptBeg,addr ptEnd
        invoke ReleaseCapture
        invoke	LoadCursor,NULL,IDC_ARROW
        invoke	SetCursor,eax
        mov		fBlocking,FALSE
		 .endif        
		ret       
		.elseif message == WM_PAINT
		invoke	BeginPaint,hwnd,addr ps
		mov		hdc,eax
      
      .if 		fValidBox == TRUE
      
  
      invoke	GetStockObject,BLACK_BRUSH
      invoke	SelectObject,hdc, eax
      lea		esi,ptBoxEnd
      push		[esi+4]
      push		[esi]
      
      lea		esi,ptBoxBeg
      push		[esi+4]
      push		[esi]
      
      push		hdc
      
      call		Rectangle
		.endif
		.if (fBlocking==TRUE)
      ;invoke	wsprintf,addr szBuffer,CTXT("ss")
	;invoke	MessageBox,hwnd,addr szBuffer,NULL,NULL  			
      invoke	SetROP2 ,hdc, R2_NOT
      invoke	GetStockObject,NULL_BRUSH
      invoke	SelectObject,hdc,eax

		lea		esi,ptEnd
		push		[esi+4]
		push		[esi]
		
		lea		esi,ptBeg
		push		[esi+4]
		push		[esi]
		push		hdc
		
		call		Rectangle
        
      .endif
		
      invoke	EndPaint,hwnd, addr ps
        
      ret
	.elseif message == WM_DESTROY
		invoke PostQuitMessage,NULL		
		ret
	.endif
UseDefWindowProc:
	invoke DefWindowProc,hwnd, message, wParam, lParam
	ret
WndProc endp

END START

        

BLOKOUT2程序和BLOKOUT1程序一样,只是多了三行新程序代码:在WM_LBUTTONDOWN消息处理期间呼叫SetCapture,而在WM_LBUTTONDOWN和WM_CHAR消息处理期间呼叫ReleaseCapture。检查画出窗口:使窗口小于屏幕大小,开始在显示区域画出一块矩形,然后将鼠标光标移出显示区域的右边或下边,最后释放鼠标按键。程序将获得整个矩形的坐标。但是需要扩大窗口才能看清楚它。

拦截鼠标并非只适用于那些古怪的应用程序。如果您需要鼠标按键在显示区域按下时都能够追踪WM_MOUSEMOVE消息,并直到鼠标按键被释放为止,那么您就应该拦截鼠标。这样将简化您的程序,同时又符合使用者的期望。

鼠标滑轮

与传统的鼠标相比,Microsoft IntelliMouse的特点是在两个键之间多了一个小滑轮。您可以按下这个滑轮,这时它的功能相当于鼠标按键的中键;或者您也可以用食指来转动它,这会产生一条特殊的消息,叫做WM_MOUSEWHEEL。使用鼠标滑轮的程序通过滚动或放大文件来响应此消息。它最初听起来像一个不必要的隐藏机关,但我必须承认,我很快就习惯于使用鼠标滑轮来滚动Microsoft Word和Microsoft Internet Explorer了。

我不想讨论鼠标滑轮的所有使用方法。实际上,我只是想告诉您如何在现有的程序(例如程序SYSMETS4)中添加鼠标滑轮处理程序,以便在显示区域中卷动数据。最终的SYSMETS程序如程序7-8所示。

程序7-8 SYSMETS4

        
SYSMETS.ASM
;MASMPlus 代码模板 - 普通的 Windows 程序代码

.386
.Model Flat, StdCall
Option Casemap :None

Include windows.inc
Include user32.inc
Include kernel32.inc
Include gdi32.inc
Include winmm.inc

includelib gdi32.lib
IncludeLib user32.lib
IncludeLib kernel32.lib
IncludeLib winmm.lib
include macro.asm
	
	WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD
	WndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD
	
	NUMLINES		equ	(sysmetricsEnd - sysmetrics) / 4 /3

.DATA
	szAppName   db "SysMets4",0
	
	szShow01		db	"SM_CXSCREEN",0
	szShow02		db	"Screen width in pixels",0	
	
	szShow03		db	"SM_CYSCREEN",0	
	szShow04		db	"Screen height in pixels",0	
	
	szShow05		db	"SM_CXVSCROLL",0	
	szShow06		db	"Vertical scroll width",0	

	szShow07		db	"SM_CYHSCROLL",0	
	szShow08		db	"Horizontal scroll height",0	
	
	szShow09		db	"SM_CYCAPTION",0		
	szShow10		db	"Caption bar height",0	

	szShow11		db	"SM_CXBORDER",0		
	szShow12		db	"Window border width",0	   
	
	szShow13		db	"SM_CYBORDER",0		
	szShow14		db	"Window border height",0	

	szShow15		db	"SM_CXFIXEDFRAME",0		
	szShow16		db	"Dialog window frame width",0	
	
	szShow17		db	"SM_CYFIXEDFRAME",0		
	szShow18		db	"Dialog window frame height",0	
	
	szShow19		db	"SM_CYVTHUMB",0		
	szShow20		db	"Vertical scroll thumb height",0	
	
	szShow21		db	"SM_CXHTHUMB",0		
	szShow22		db	"Horizontal scroll thumb width",0	
	szShow23		db	"SM_CXICON",0		
	szShow24		db	"Icon width",0	
	szShow25		db	"SM_CYICON",0		
	szShow26		db	"Icon height",0	

	szShow27		db	"SM_CXCURSOR",0		
	szShow28		db	"Cursor width",0		

	szShow29		db	"SM_CYCURSOR",0		
	szShow30		db	"Cursor height",0		
	
	szShow31		db	"SM_CYMENU",0		
	szShow32		db	"Menu bar height",0		
	
	szShow33		db	"SM_CXFULLSCREEN",0		
	szShow34		db	"Full screen client area width",0		
	
	szShow35		db	"SM_CYFULLSCREEN",0		
	szShow36		db	"Full screen client area height",0		
	
	szShow37		db	"SM_CYKANJIWINDOW",0		
	szShow38		db	"Kanji window height",0		
	
	szShow39		db	"SM_MOUSEPRESENT",0		
	szShow40		db	"Mouse present flag",0		
	
	szShow41		db	"SM_CYVSCROLL",0		
	szShow42		db	"Vertical scroll arrow height",0		

	szShow43		db	"SM_CXHSCROLL",0		
	szShow44		db	"Horizontal scroll arrow width",0		
	
	szShow45		db	"SM_DEBUG",0		
	szShow46		db	"Debug version flag",0		
	
	szShow47		db	"SM_SWAPBUTTON",0		
	szShow48		db	"Mouse buttons swapped flag",0		
	
	szShow49		db	"SM_CXMIN",0		
	szShow50		db	"Minimum window width",0		
	
	szShow51		db	"SM_CYMIN",0		
	szShow52		db	"Minimum window height",0		
	
	szShow53		db	"SM_CXSIZE",0		
	szShow54		db	"Min/Max/Close button width",0		
	
	szShow55		db	"SM_CYSIZE",0		
	szShow56		db	"Min/Max/Close button height",0	                           
	
	szShow57		db	"SM_CXSIZEFRAME",0		
	szShow58		db	"Window sizing frame width",0	                           
	
	szShow59		db	"SM_CYSIZEFRAME",0		
	szShow60		db	"Window sizing frame height",0	                           
	
	szShow61		db	"SM_CXMINTRACK",0		
	szShow62		db	"Minimum window tracking width",0	                           
	
	szShow63		db	"SM_CYMINTRACK",0		
	szShow64		db	"Minimum window tracking height",0	                           
	
	szShow65		db	"SM_CXDOUBLECLK",0		
	szShow66		db	"Double click x tolerance",0	                           
	
	szShow67		db	"SM_CYDOUBLECLK",0		
	szShow68		db	"Double click y tolerance",0	                           

	szShow69		db	"SM_CXICONSPACING",0		
	szShow70		db	"Horizontal icon spacing",0	                           
	
	szShow71		db	"SM_CYICONSPACING",0		
	szShow72		db	"Vertical icon spacing",0	                           
	
	szShow73		db	"SM_MENUDROPALIGNMENT",0		
	szShow74		db	"Left or right menu drop",0	                           
	
	szShow75		db	"SM_PENWINDOWS",0		
	szShow76		db	"Pen extensions installed",0	                           
	
	szShow77		db	"SM_DBCSENABLED",0		
	szShow78		db	"Double-Byte Char Set enabled",0	                           
                                  
	szShow79		db	"SM_CMOUSEBUTTONS",0		
	szShow80		db	"Number of mouse buttons",0	                           
	
	szShow81		db	"SM_SECURE",0		
	szShow82		db	"Security present flag",0	                           
	
	szShow83		db	"SM_CXEDGE",0		
	szShow84		db	"3-D border width",0	                           
	
	szShow85		db	"SM_CYEDGE",0		
	szShow86		db	"3-D border height",0	                           
	
	szShow87		db	"SM_CXMINSPACING",0		
	szShow88		db	"Minimized window spacing width",0	
	
	szShow89		db	"SM_CYMINSPACING",0		
	szShow90		db	"Minimized window spacing height",0	                           
	
	szShow91		db	"SM_CXSMICON",0		
	szShow92		db	"Small icon width",0	                           
	
	szShow93		db	"SM_CYSMICON",0		
	szShow94		db	"Small icon height",0	                           
	
	szShow95		db	"SM_CYSMCAPTION",0		
	szShow96		db	"Small caption height",0	                           

	szShow97		db	"SM_CXSMSIZE",0		
	szShow98		db	"Small caption button width",0	
	
	szShow99		db	"SM_CYSMSIZE",0		
	szShow100	db	"Small caption button height",0	                           

	szShow101	db	"SM_CXMENUSIZE",0		
	szShow102	db	"Menu bar button width",0	                           
	
	szShow103	db	"SM_CYMENUSIZE",0		
	szShow104	db	"Menu bar button height",0	                           
	
	szShow105		db	"SM_ARRANGE",0		
	szShow106	db	"How minimized windows arranged",0	                           
	
	szShow107	db	"SM_CXMINIMIZED",0		
	szShow108	db	"Minimized window width",0		

	szShow109	db	"SM_CYMINIMIZED",0		
	szShow110	db	"Minimized window height",0	                           
	
	szShow111	db	"SM_CXMAXTRACK",0		
	szShow112		db	"Maximum draggable width",0	                           
	
	szShow113		db	"SM_CYMAXTRACK",0		
	szShow114		db	"Maximum draggable height",0	

	szShow115	db	"SM_CXMAXIMIZED",0		
	szShow116		db	"Width of maximized window",0	                           
	
	szShow117	db	"SM_CYMAXIMIZED",0		
	szShow118	db	"Height of maximized window",0	                           
	
	szShow119	db	"SM_NETWORK",0		
	szShow120	db	"Network present flag",0	

	szShow121	db	"SM_CLEANBOOT",0		
	szShow122	db	"How system was booted",0	                           
	
	szShow123	db	"SM_CXDRAG",0		
	szShow124	db	"Avoid drag x tolerance",0	                           
	
	szShow125	db	"SM_CYDRAG",0		
	szShow126	db	"Avoid drag y tolerance",0		
	
	szShow127	db	"SM_SHOWSOUNDS",0		
	szShow128	db	"Present sounds visually",0	                           
	
	szShow129	db	"SM_CXMENUCHECK",0		
	szShow130	db	"Menu check-mark width",0	                           
	
	szShow131	db	"SM_CYMENUCHECK",0		
	szShow132	db	"Menu check-mark height",0	
	
	szShow133	db	"SM_SLOWMACHINE",0		
	szShow134	db	"Slow processor flag",0	                           

	szShow135	db	"SM_MIDEASTENABLED",0		
	szShow136	db	"Hebrew and Arabic enabled flag",0	                           
	
	szShow137	db	"SM_MOUSEWHEELPRESENT",0		
	szShow138	db	"Mouse wheel present flag",0		
	
	szShow139	db	"SM_XVIRTUALSCREEN",0		
	szShow140	db	"Virtual screen x origin",0	                           
	
	szShow141	db	"SM_YVIRTUALSCREEN",0		
	szShow142	db	"Virtual screen y origin",0	
	
	szShow143		db	"SM_CXVIRTUALSCREEN",0		
	szShow144	db	"Virtual screen width",0	                           
	
	szShow145	db	"SM_CYVIRTUALSCREEN",0		
	szShow146	db	"Virtual screen height",0		
	
	szShow147	db	"SM_CMONITORS",0		
	szShow148	db	"Number of monitors",0	                           
	
	szShow149	db	"SM_SAMEDISPLAYFORMAT",0		
	szShow150	db	"Same color format flag",0	

sysmetrics	dd		SM_CXSCREEN, offset szShow01, offset szShow02
				dd		SM_CYSCREEN, szShow03,offset szShow04
				dd		SM_CXVSCROLL,offset szShow05,offset szShow06
				dd		SM_CYHSCROLL,offset szShow07,offset szShow08		
				dd		SM_CYCAPTION,offset szShow09,offset szShow10				
				dd		SM_CXBORDER,offset szShow11,offset szShow12				
				dd		SM_CYBORDER,offset szShow13,offset szShow14				
        		dd		SM_CXFIXEDFRAME,offset szShow15,offset szShow16				
				dd		SM_CYVTHUMB,offset szShow17,offset szShow18				
				dd		SM_CYFIXEDFRAME,offset szShow19,offset szShow20	        
        		dd		SM_CXHTHUMB,offset szShow21,offset szShow22	
        		dd		SM_CXICON,offset szShow23,offset szShow24
        		dd		SM_CYICON,offset szShow25,offset szShow26        		
        		dd		SM_CXCURSOR,offset szShow27,offset szShow28	
        		dd		SM_CYCURSOR,offset szShow29,offset szShow30
        		dd		SM_CYMENU,offset szShow31,offset szShow32        		
        		dd		SM_CXFULLSCREEN,offset szShow33,offset szShow34 
       		dd		SM_CYFULLSCREEN,offset szShow35,offset szShow36 
        		dd		SM_CYKANJIWINDOW,offset szShow37,offset szShow38 
       		dd		SM_MOUSEPRESENT,offset szShow39,offset szShow40 
        		dd		SM_CYVSCROLL,offset szShow41,offset szShow42 
       		dd		SM_CXHSCROLL,offset szShow43,offset szShow44 
        		dd		SM_DEBUG,offset szShow45,offset szShow46 
       		dd		SM_SWAPBUTTON,offset szShow47,offset szShow48 
        		dd		SM_CXMIN,offset szShow49,offset szShow50 
       		dd		SM_CYMIN,offset szShow51,offset szShow52 
        		dd		SM_CXSIZE,offset szShow53,offset szShow54 
       		dd		SM_CYSIZE,offset szShow55,offset szShow56        		
       		dd		SM_CXSIZEFRAME,offset szShow57,offset szShow58 
       		dd		SM_CYSIZEFRAME,offset szShow59,offset szShow60        		
       		dd		SM_CXMINTRACK,offset szShow61,offset szShow62        		
       		dd		SM_CYMINTRACK,offset szShow63,offset szShow64 
       		dd		SM_CXDOUBLECLK,offset szShow65,offset szShow66        		
        		dd		SM_CYDOUBLECLK,offset szShow67,offset szShow68        		
       		dd		SM_CXICONSPACING,offset szShow69,offset szShow70 
       		dd		SM_CYICONSPACING,offset szShow71,offset szShow72        		
        		dd		SM_MENUDROPALIGNMENT,offset szShow73,offset szShow74        		
       		dd		SM_PENWINDOWS,offset szShow75,offset szShow76 
       		dd		SM_DBCSENABLED,offset szShow77,offset szShow78        		
        		dd		SM_CMOUSEBUTTONS,offset szShow79,offset szShow80        		
       		dd		SM_SECURE,offset szShow81,offset szShow82 
       		dd		SM_CXEDGE,offset szShow83,offset szShow84        		
        		dd		SM_CYEDGE,offset szShow85,offset szShow86        		
       		dd		SM_CXMINSPACING,offset szShow87,offset szShow88 
       		dd		SM_CYMINSPACING,offset szShow89,offset szShow90        		
       		dd		SM_CXSMICON,offset szShow91,offset szShow92 
       		dd		SM_CYSMICON,offset szShow93,offset szShow94  
       		dd		SM_CYSMCAPTION,offset szShow95,offset szShow96 
       		dd		SM_CXSMSIZE,offset szShow97,offset szShow98        		
       		dd		SM_CYSMSIZE,offset szShow99,offset szShow100 
       		dd		SM_CXMENUSIZE,offset szShow101,offset szShow102  
       		dd		SM_CYMENUSIZE,offset szShow103,offset szShow104 
       		dd		SM_ARRANGE,offset szShow105,offset szShow106        		
       		dd		SM_CXMINIMIZED,offset szShow107,offset szShow108 
       		dd		SM_CYMINIMIZED,offset szShow109,offset szShow110  
       		dd		SM_CXMAXTRACK,offset szShow111,offset szShow112 
       		dd		SM_CYMAXTRACK,offset szShow113,offset szShow114        		
       		dd		SM_CXMAXIMIZED,offset szShow115,offset szShow116 
       		dd		SM_CYMAXIMIZED,offset szShow117,offset szShow118  
       		dd		SM_NETWORK,offset szShow119,offset szShow120 
       		dd		SM_CLEANBOOT,offset szShow121,offset szShow122  
       		dd		SM_CXDRAG,offset szShow123,offset szShow124 
       		dd		SM_CYDRAG,offset szShow125,offset szShow126  
       		dd		SM_SHOWSOUNDS,offset szShow127,offset szShow18 
       		dd		SM_CXMENUCHECK,offset szShow129,offset szShow130  
       		dd		SM_CYMENUCHECK,offset szShow131,offset szShow132 
       		dd		SM_SLOWMACHINE,offset szShow133,offset szShow134         		
       		dd		SM_MIDEASTENABLED,offset szShow135,offset szShow136 
       		dd		SM_MOUSEWHEELPRESENT,offset szShow137,offset szShow138 
       		dd		SM_XVIRTUALSCREEN,offset szShow139,offset szShow140 
       		dd		SM_YVIRTUALSCREEN,offset szShow141,offset szShow142 
       		dd		SM_CXVIRTUALSCREEN,offset szShow143,offset szShow144 
       		dd		SM_CYVIRTUALSCREEN,offset szShow145,offset szShow146 
       		dd		SM_CMONITORS,offset szShow147,offset szShow148 
       		dd		SM_SAMEDISPLAYFORMAT,offset szShow149,offset szShow150        		
sysmetricsEnd	label	DWORD

.DATA?
	hInstance	dd ?
	cxChar		dd	?
	cxCaps		dd	?
	cyChar		dd	?
	cxClient		dd ?
	cyClient		dd	?
	iMaxWidth	dd	?
   iDeltaPerLine	dd	?			 ; for mouse wheel logic
   iAccumDelta 	dd	?         ; for mouse wheel logic
	
.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("Get System Metrics"), 	;window caption
					WS_OVERLAPPEDWINDOW or WS_VSCROLL or WS_HSCROLL,
					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

WndProc proc hwnd:DWORD,message:DWORD,wParam :DWORD,lParam :DWORD

	LOCAL hdc 				:HDC
	LOCAL i,x,y,iVertPos,iHorzPos, iPaintBeg, iPaintEnd :DWORD
	LOCAL ps  				:PAINTSTRUCT 
	LOCAL ssi 				:SCROLLINFO
	LOCAL szBuffer[10]	:BYTE
	LOCAL tm					:TEXTMETRIC
	LOCAL y_Pos,x_Caps 	:DWORD
	LOCAL	ulScrollLines	:ULONG	; for mouse wheel logic

	.if message==WM_CREATE
		
		invoke	GetDC,hwnd
		mov		hdc,eax
		
		invoke	GetTextMetrics,hdc,addr	tm
		mov		eax,tm.tmAveCharWidth		
		mov		cxChar,eax	;cxChar = tm.tmAveCharWidth 
		mov		eax,2	;cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2
		test		DWORD ptr tm.tmPitchAndFamily,1
		jz		@f
		inc		eax
		@@:
		push		eax
		mov		eax,cxChar
		pop		ebx
		mul		ebx
		shr		eax,1
		mov		cxCaps,eax
 
				
		mov		eax,tm.tmHeight	;cyChar = tm.tmHeight + tm.tmExternalLeading 
		add		eax,DWORD ptr tm.tmExternalLeading
		mov		cyChar,eax

      invoke   ReleaseDC,hwnd, hdc
      
      ;Save the width of the three columns
    	mov		eax,cxChar	;iMaxWidth = 40 * cxChar + 22 * cxCaps
    	mov		ecx,40
    	mul		ecx
    	mov		ebx,eax
    	mov		eax,cxCaps
    	mov		ecx,22
    	mul		ecx
    	add		eax,ebx
    	mov		iMaxWidth,eax
      jmp		@f                 ; Fall through for mouse wheel information
        
	.elseif	message == WM_SETTINGCHANGE
		@@:
      invoke   SystemParametersInfo,SPI_GETWHEELSCROLLLINES, 0,addr ulScrollLines, 0
            ; ulScrollLines usually equals 3 or 0 (for no scrolling)
          	; WHEEL_DELTA equals 120, so iDeltaPerLine will be 40
      .if (ulScrollLines != 0)
            ;iDeltaPerLine = WHEEL_DELTA / ulScrollLines ;
            mov	eax,WHEEL_DELTA
            mov	ecx,ulScrollLines
            xor	edx,edx
            div	ecx
            mov	iDeltaPerLine,eax
		.else
	      	mov	iDeltaPerLine,0 
		.endif        
		ret

		.elseif message == WM_SIZE
      		mov		eax,lParam	;cxClient = LOWORD (lParam)
      		and		eax,0FFFFh
      		mov		cxClient,eax
      		
      		mov		eax,lParam
      		shr		eax,16
      		mov		cyClient,eax	;cyClient = HIWORD (lParam)
      		
      		mov		eax,sizeof ssi
      		mov		ssi.cbSize,eax
      		mov		DWORD ptr [ssi.fMask],SIF_RANGE or SIF_PAGE
      		mov		DWORD ptr [ssi.nMin],0
      		mov		DWORD ptr [ssi.nMax],NUMLINES - 1
      		xor		edx,edx	;si.nPage = cyClient / cyChar
      		mov		eax,cyClient
      		mov		ecx,cyChar
      		div		ecx
      		mov		DWORD ptr [ssi.nPage],eax       
      	;Set horizontal scroll bar range and page size
      		invoke	SetScrollInfo,hwnd,SB_VERT,addr ssi,TRUE      		
	  
      		mov		eax,sizeof ssi
      		mov		ssi.cbSize,eax
      		mov		DWORD ptr [ssi.fMask],SIF_RANGE or SIF_PAGE
      		mov		DWORD ptr [ssi.nMin],0
      		xor		edx,edx	;    si.nMax       = 2 + iMaxWidth / cxChar
      		mov		eax,iMaxWidth
      		mov		ecx,cxChar
      		div		ecx      
      		add		eax,2
      		mov		DWORD ptr [ssi.nMax],eax
      		
      		xor		edx,edx
      		mov		eax,cxClient
      		mov		ecx,cxChar
      		div		ecx
      		mov		DWORD ptr [ssi.nPage],eax    		
      		
      	;Set horizontal scroll bar range and page size
      		invoke	SetScrollInfo,hwnd,SB_HORZ,addr ssi,TRUE
  		ret
      .elseif message == WM_VSCROLL
      	;Get all the vertical scroll bar information
      		mov		eax,sizeof ssi
      		mov		ssi.cbSize,eax
      		mov		DWORD ptr [ssi.fMask],SIF_ALL
      		invoke	GetScrollInfo,hwnd,SB_VERT,addr ssi
      	;Save the position for comparison later on
      		mov		eax,ssi.nPos
      		mov		DWORD ptr iVertPos,eax
      
      			mov	eax,wParam		
      			and	eax,0FFFFh	;LOWORD (wParam)
      		.if	eax ==SB_TOP
      			mov	eax,ssi.nMin
      			mov	ssi.nPos,eax
      		.elseif	eax==SB_BOTTOM
      			mov	eax,ssi.nMax
      			mov	ssi.nPos,eax      		
      		.elseif	eax==SB_LINEUP
      			mov	eax,ssi.nPos
      			dec	eax
      			mov	ssi.nPos,eax
     			
     			.elseif eax==SB_LINEDOWN
     			
      			mov	eax,ssi.nPos
      			inc	eax
      			mov	ssi.nPos,eax
 			 
    			
				.elseif eax==SB_PAGEUP		
      			mov	eax,ssi.nPos
      			sub	eax,ssi.nPage
      			mov	ssi.nPos,eax
      			
      		.elseif eax==SB_PAGEDOWN            
      			mov	eax,ssi.nPos
      			add	eax,ssi.nPage
      			mov	ssi.nPos,eax
      			
      		.elseif eax==SB_THUMBTRACK
      			mov	eax,ssi.nTrackPos
      			mov	ssi.nPos,eax
 		      .endif 
	   	;Set the position and then retrieve it.  Due to adjustments
            ;by Windows it may not be the same as the value set.

				mov		DWORD ptr [ssi.fMask],SIF_POS
				invoke	SetScrollInfo,hwnd,SB_VERT,Addr ssi,TRUE
				invoke	GetScrollInfo,hwnd,SB_VERT,Addr ssi
				

	;If the position has changed, scroll the window and update 
				mov		eax,ssi.nPos
				.if		eax!=iVertPos
				mov		eax,iVertPos
				sub		eax,ssi.nPos
				mov		ecx,cyChar
				mul		ecx
				invoke	ScrollWindow,hwnd,0,eax,NULL,NULL
				invoke	UpdateWindow,hwnd
				.endif
		ret      
      .elseif message == WM_HSCROLL
      		mov		eax,sizeof ssi
      		mov		ssi.cbSize,eax
      		mov		DWORD ptr [ssi.fMask],SIF_ALL
      		invoke	GetScrollInfo,hwnd,SB_HORZ,addr ssi
      
      		mov		eax,ssi.nPos
				mov  DWORD ptr iHorzPos,eax ; 此处原为 iVertPos 
      
      
      
      			mov	eax,wParam		
      			and	eax,0FFFFh	;LOWORD (wParam)
      		.if	eax ==SB_LINELEFT
      			mov	eax,ssi.nPos
      			dec	eax
      			mov	ssi.nPos,eax
      		.elseif	eax==SB_LINERIGHT
      			mov	eax,ssi.nPos
      			inc	eax
      			mov	ssi.nPos,eax
      		.elseif	eax==SB_PAGELEFT
      			mov	eax,ssi.nPos
      			sub	eax,DWORD ptr ssi.nPage
      			mov	ssi.nPos,eax
    		.elseif eax==SB_PAGERIGHT
      			mov	eax,ssi.nPos
      			add	eax,DWORD ptr ssi.nPage
      			mov	ssi.nPos,eax
     		.elseif ax==SB_THUMBTRACK
      			mov	eax,ssi.nTrackPos
      			mov	ssi.nPos,eax
 		      .endif 
		   
				mov		DWORD ptr [ssi.fMask],SIF_POS
				invoke	SetScrollInfo,hwnd,SB_HORZ,Addr ssi,TRUE
				invoke	GetScrollInfo,hwnd,SB_HORZ,Addr ssi
				
			  mov eax,DWORD ptr [ssi.nPos]
		  .if eax != iHorzPos
				   mov  eax,iHorzPos
				   sub  eax,DWORD ptr [ ssi.nPos]
				   mov  ecx,cxChar
				   mul  ecx
				   invoke ScrollWindow,hwnd,eax,0,NULL,NULL
				   invoke UpdateWindow,hwnd
		  .endif
	  ret   		

     .elseif message == WM_KEYDOWN
      			mov	eax,wParam		
      			and	eax,0FFFFh	;LOWORD (wParam)
      		.if		eax == VK_HOME
      			invoke	SendMessage,hwnd,WM_VSCROLL,SB_TOP,0
      		.elseif	eax == VK_END
      			invoke	SendMessage,hwnd,WM_VSCROLL,SB_BOTTOM,0      		
      		.elseif	eax == VK_PRIOR
      			invoke	SendMessage,hwnd,WM_VSCROLL,SB_PAGEUP,0       
      		.elseif	eax == VK_NEXT
      			invoke	SendMessage,hwnd,WM_VSCROLL,SB_PAGEDOWN,0         			
      		.elseif	eax == VK_UP
      			invoke	SendMessage,hwnd,WM_VSCROLL,SB_LINEUP,0  
      		.elseif	eax == VK_DOWN
      			invoke	SendMessage,hwnd,WM_VSCROLL,SB_LINEDOWN,0        			
      		.elseif	eax == VK_LEFT
      			invoke	SendMessage,hwnd,WM_VSCROLL,SB_PAGEUP,0  
      		.elseif	eax == VK_RIGHT
      			invoke	SendMessage,hwnd,WM_VSCROLL,SB_PAGEDOWN,0         			
				.endif
      ret
					
    	     .elseif message == WM_MOUSEWHEEL
         
            .if (iDeltaPerLine == 0)
               ret	;Break 将会跳出这个过程
				.endif     
			
				mov	edx,wParam
				shr	edx,16
	;and	edx,0FFFFh
				movsx	eax,dx
				mov	ecx,iAccumDelta
				add	eax,ecx
				mov	iAccumDelta,eax	;iAccumDelta += (short) HIWORD (wParam) // 120 or -120
		
	         mov	eax,iAccumDelta
	         @@:
            cmp	eax,iDeltaPerLine	;.while (eax >= iDeltaPerLine)
 				jl		@f
               invoke	SendMessage,hwnd, WM_VSCROLL, SB_LINEUP, 0
               mov		eax,iAccumDelta
               sub		eax,iDeltaPerLine
               mov		iAccumDelta,eax
               jmp		@b
 				@@:

	;invoke	wsprintf,addr szBuffer,CTXT("%d %d %d"),iAccumDelta,wParam,iDeltaPerLine
	;invoke	MessageBox,hwnd,addr szBuffer,NULL,NULL	

            
            @@:
				mov		eax,iDeltaPerLine
				neg		eax
            cmp		eax,iAccumDelta	; .while (eax >= iAccumDelta)
            jl			@F
               invoke	SendMessage,hwnd, WM_VSCROLL, SB_LINEDOWN, 0
               mov		eax,iAccumDelta	;iAccumDelta += iDeltaPerLine
               add		eax,iDeltaPerLine
               mov		iAccumDelta,eax
               jmp	@b
				@@:
		
      ret
      
			.elseif message == WM_PAINT
		invoke	BeginPaint,hwnd,addr ps
		mov		hdc,eax
		
	;Get vertical scroll bar position
		mov		eax,sizeof ssi
      mov		ssi.cbSize,eax
      mov		DWORD ptr [ssi.fMask],SIF_POS
      invoke	GetScrollInfo,hwnd,SB_VERT,addr ssi
      mov		eax,ssi.nPos
      mov		iVertPos,eax
      
 	;Get horizontal scroll bar position
 		invoke	GetScrollInfo,hwnd,SB_HORZ,addr ssi
      mov		eax,ssi.nPos
      mov		iHorzPos ,eax
      
     	;Find painting limits
		xor		edx,edx	;iPaintEnd=min(NUMLINES - 1,iVertPos + ps.rcPaint.bottom / cyChar)
      mov		eax,ps.rcPaint.bottom
      mov		ecx,cyChar
      div		ecx
      add		eax,iVertPos
      mov		ecx,(NUMLINES-1)
      .if		eax>ecx
      mov		eax,NUMLINES-1
      .endif
      mov		iPaintEnd,eax      
      
		xor		edx,edx	;iPaintBeg = max (0, iVertPos + ps.rcPaint.top / cyChar)
      mov		eax,ps.rcPaint.top
      mov		ecx,cyChar
      div		ecx
      add		eax,iVertPos
		cmp		eax,0	;iVscrollPos = max (0, min (iVscrollPos, NUMLINES - 1))
		jg			@f
		xor		eax,eax	
	@@:      
      mov		iPaintBeg,eax
      mov		i,eax	;i=iPaintBeg
		mov		eax,iPaintBeg	;ESI point to sysmetrics[i]
		shl		eax,2
		lea		esi,sysmetrics
		add		esi,4
		add		esi,eax
		add		esi,eax
		add		esi,eax
		
	;invoke	wsprintf,addr szBuffer,CTXT("%d %d"),iPaintBeg,iPaintEnd
	;invoke	MessageBox,hwnd,addr szBuffer,NULL,NULL 
@@:
		
		mov		eax,1	; x = cxChar * (1 - iHorzPos)
		sub		eax,iHorzPos
		mov		ecx,cxChar
		mul		ecx
		mov		x,eax

		mov		eax,i	; y = cyChar * (i - iVertPos)
		sub		eax,iVertPos
		mov		ecx,cyChar
		mul		ecx
		mov		y,eax
		

   	mov		edi,[esi]	;esi指向字符串的地址
   	;edi指向字符串
   	invoke	lstrlen,edi	;取字符串长度
   	mov		ebx,eax

;TextOut (hdc, 0, cyChar * i,sysmetrics[i].szLabel,lstrlen (sysmetrics[i].szLabel))
		invoke	TextOut,hdc,x,y,edi,ebx

		add		esi,4
		mov		edi,[esi]	;指向一个字符串地址
		
		mov		eax,cxCaps
		mov		ecx,22
		mul		ecx
		mov		ecx,DWORD ptr x
		add		ecx,eax
		
		
		push		ecx
		invoke	lstrlen,edi
   	mov		ebx,eax
   	pop		ecx

		invoke	TextOut,hdc,ecx,y,edi,ebx
		invoke	SetTextAlign,hdc,TA_RIGHT or TA_TOP	

		sub		esi,8					
		
		mov		edi,[esi]	;edi=sysmetrics[i].iIndex
		
		mov		eax,cxCaps	;x_Caps=22 * cxCaps + 40 * cxChar
		mov		ecx,22
		mul		ecx
		mov		ebx,eax
		mov		eax,cxChar
		mov		ecx,40
		mul		ecx
		add		eax,ebx
		add		eax,DWORD ptr	x
		mov		x_Caps,eax
		
		invoke	GetSystemMetrics,edi
		invoke	wsprintf,addr szBuffer,CTXT("%5d"),eax	;wsprintf格式化后的长度会作为返回值放在EAX中
		mov		ebx,eax
		
		invoke	TextOut,hdc,x_Caps,y,addr	szBuffer,ebx
		invoke	SetTextAlign,hdc,TA_LEFT or TA_TOP
   	
   	inc		i
   	add		esi,16
   	mov		eax,iPaintEnd
   	cmp		DWORD ptr i,eax
		jbe		@b		
		invoke	EndPaint,hwnd,addr ps

		ret	  		
	.elseif message == WM_DESTROY
		
		invoke PostQuitMessage,NULL		
		
	.endif
	
	invoke DefWindowProc,hwnd, message, wParam, lParam

	ret
WndProc endp
END START    

        

    ss7.JPG (76532 字节)

和以前的程序外观完全一样,新增支持鼠标滚轮功能。

    转动滑轮会导致Windows在有输入焦点的窗口(不是鼠标光标下面的窗口)产生WM_MOUSEWHEEL消息。与平常一样,lParam将获得鼠标的位置,当然坐标是相对于屏幕左上角的,而不是显示区域的。另外,wParam的低字组包含一系列的旗标,用于表示鼠标按键、Shift与Ctrl键的状态。

新的信息保存在wParam的高字组。其中有一个「delta」值,该值目前可以是120或-120,这取决于滑轮的向前转动(也就是说,向鼠标的前面,即带有按钮与电缆的一端)还是向后转动。值120或-120表示文件将分别向上或向下卷动三行。这里的构想是,以后版本的鼠标滑轮能有比现在的鼠标产生更精确的移动速度信息,并且用delta值,例如40和-40,来产生WM_MOUSEWHEEL消息。这些值能使文件只向上或向下卷动一行。

为使程序能在一般化环境执行,SYSMETS将在WM_CREATE和WM_SETTINGCHANGE消息处理时,以SPI_GETWHEELSCROLLLINES作为参数来呼叫SystemParametersInfo。此值说明WHEEL_DELTA的delta值将滚动多少行,WHEEL_DELTA在WINUSER.H中定义。WHEEL_DELTA等于120,并且,在内定情况下SystemParametersInfo传回3,因此与卷动一行相联系的delta值就是40。SYSMETS将此值保存在iDeltaPerLine。

在WM_MOUSEWHEEL消息处理期间,SYSMETS将delta值给静态变量iAccumDelta。然后,如果iAccumDelta大于或等于iDeltaPerLine(或者是小于或等于-iDeltaPerLin),SYSMETS用SB_LINEUP或SB_LINEDOWN值产生WM_VSCROLL消息。对于每一个WM_VSCROLL消息,iAccumDelta由iDeltaPerLine增加(或减少)。此代码允许delta值大于、小于或等于滚动一行所需要的delta值。



<<<上一篇
欢迎访问AoGo汇编小站:http://www.aogosoft.com