📄 见招拆招windows程序设计(六) .txt
字号:
WndProc proc hwnd:DWORD,message:DWORD,wParam :DWORD,lParam :DWORD
LOCAL hdc :HDC
LOCAL x,y :DWORD
LOCAL ps :PAINTSTRUCT
LOCAL point :POINT
LOCAL rect :RECT
LOCAL xcx,ycy,x1cx,y1cy:DWORD
.if message == WM_SIZE
mov eax,lParam ;cxBlock = LOWORD (lParam) / DIVISIONS
shl eax,16
shr eax,16
mov ecx,DIVISIONS
div ecx
mov cxBlock,eax
xor edx,edx
mov eax,lParam ;cyBlock = HIWORD (lParam) / DIVISIONS
shr eax,16
mov ecx,DIVISIONS
div ecx
mov cyBlock,eax
mov ebx,eax
ret
.elseif message == WM_SETFOCUS
invoke ShowCursor,TRUE
ret
.elseif message == WM_KILLFOCUS
invoke ShowCursor,FALSE
ret
.elseif message == WM_KEYDOWN
invoke GetCursorPos,addr point
invoke ScreenToClient,hwnd, addr point
;x = max (0, min (DIVISIONS - 1, point.x / cxBlock))
;y = max (0, min (DIVISIONS - 1, point.y / cyBlock))
lea esi,point
mov eax,[esi]
mov ecx,cxBlock
xor edx,edx
div ecx
cmp eax,DIVISIONS - 1
jl @f
mov eax,DIVISIONS - 1
@@:
cmp eax,0
jg @f
xor eax,eax
@@:
mov x,eax
mov eax,[esi+4]
mov ecx,cyBlock
xor edx,edx
div ecx
cmp eax,DIVISIONS - 1
jl @f
mov eax,DIVISIONS - 1
@@:
cmp eax,0
jg @f
xor eax,eax
@@:
mov y,eax
mov eax,wParam
.if eax == VK_UP
dec y
.elseif eax == VK_DOWN
inc y
.elseif eax == VK_LEFT
dec x
.elseif eax == VK_RIGHT
inc x
.elseif eax == VK_HOME
xor eax,eax
mov x,eax
mov y,eax
.elseif eax == VK_END
mov eax,DIVISIONS - 1
mov x,eax
mov y,eax
.elseif (eax == VK_RETURN) || (eax == VK_SPACE)
;MAKELONG宏可以将两个16位的无符号数组合成一个32位的无符号数
mov eax,xcx
shl eax,16
add eax,ycy
invoke SendMessage,hwnd, WM_LBUTTONDOWN, MK_LBUTTON,eax
.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
;point.x = x * cxBlock + cxBlock / 2
;point.y = y * cyBlock + cyBlock / 2
mov eax,x
mov ecx,cxBlock
mul ecx
mov xcx,eax
mov eax,y
mov ecx,cyBlock
mul ecx
mov ycy,eax
lea esi,point
mov eax,cxBlock
shr eax,1
add eax,xcx
mov [esi],eax
mov eax,cyBlock
shr eax,1
add eax,ycy
mov [esi+4],eax
; invoke wsprintf,addr szBuffer,CTEXT("[%d] [%d]"),xcx,ycy
;invoke MessageBox,hwnd, addr szBuffer, NULL, NULL
;ClientToScreen (hwnd, &point)
;SetCursorPos (point.x, point.y)
invoke ClientToScreen,hwnd,addr point
lea esi,point
mov eax,[esi]
mov ebx,[esi+4]
invoke SetCursorPos,eax,ebx
.elseif message == WM_LBUTTONDOWN
xor edx,edx
mov eax,lParam
shl eax,16
shr eax,16
mov ecx,cxBlock
div ecx
mov x,eax
xor edx,edx
mov eax,lParam
shr eax,16
mov ecx,cyBlock
div ecx
mov y,eax
mov eax,x
mov ebx,y
lea esi,fState
.if (eax<DIVISIONS)&&(ebx<DIVISIONS)
mov eax,y
mov ecx,DIVISIONS
mul ecx
add esi,eax
add esi,x
xor BYTE ptr [esi],1
;RECT STRUCT
; left dd ?
; top dd ?
; right dd ?
; bottom dd ?
;RECT ENDS
lea esi,rect
mov eax,x
mov ecx,cxBlock
mul ecx
mov [esi],eax
mov eax,y
mov ecx,cyBlock
mul ecx
mov [esi+4],eax
mov eax,x
inc eax
mov ecx,cxBlock
mul ecx
mov [esi+8],eax
mov eax,y
inc eax
mov ecx,cyBlock
mul ecx
mov [esi+12],eax
invoke InvalidateRect,hwnd,addr rect,FALSE
.elseif
invoke MessageBeep,0
.endif
ret
.elseif message == WM_PAINT
invoke BeginPaint,hwnd,addr ps
mov hdc,eax
xor eax,eax
mov x,eax
Loopx:
xor eax,eax
mov y,eax
Loopy:
mov eax,y
inc eax
mov ecx,cyBlock
mul ecx
mov y1cy,eax
push eax
mov eax,x
inc eax
mov ecx,cxBlock
mul ecx
mov x1cx,eax
push eax
mov eax,y
mov ecx,cyBlock
mul ecx
mov ycy,eax
push eax
mov eax,x
mov ecx,cxBlock
mul ecx
mov xcx,eax
push eax
push hdc
call Rectangle
lea esi,fState
mov eax,y
mov ecx,DIVISIONS
mul ecx
add esi,eax
add esi,x
mov al,[esi]
.if (al!=0)
;invoke wsprintf,addr szBuffer,CTEXT("[%d][%d][%d][%d]") ,x,y,ecx,ebx
;invoke MessageBox,hwnd,addr szBuffer,NULL,NULL
invoke MoveToEx,hdc,xcx,ycy,NULL
invoke LineTo,hdc,x1cx,y1cy
invoke MoveToEx,hdc,xcx,y1cy,NULL
invoke LineTo,hdc,x1cx,ycy
.endif
inc y
mov eax,y
cmp eax,DIVISIONS
jb Loopy
inc x
mov eax,x
cmp eax,DIVISIONS
jb Loopx
invoke EndPaint,hwnd, addr ps
ret
.elseif message == WM_DESTROY
invoke PostQuitMessage,NULL
.endif
UseDefWindowProc:
invoke DefWindowProc,hwnd, message, wParam, lParam
ret
WndProc endp
END START
CHECKER2中的WM_KEYDOWN的处理方式决定光标的位置(用GetCursorPos),把屏幕坐标转换为显示区域坐标(用ScreenToClient),并用矩形方块的宽度和高度来除这个坐标。这会产生指示矩形位置的x和y值(5×5数组)。当按下一个键时,鼠标光标可能在或不在显示区域中,所以x和y必须经过min和max宏处理以保证它们的范围是0到4之间。
对方向键,CHECKER2近似地增加或减少x和y。如果是Enter键或Spacebar键,那么CHECKER2使用SendMessage把WM_LBUTTONDOWN消息发送给它自身。这种技术类似于前面一章中把键盘接口加到窗口滚动条时所使用的方法。WM_KEYDOWN的处理方式是通过计算指向矩形中心的显示区域坐标,再用ClientToScreen转换成屏幕坐标,然后用SetCursorPos设定光标位置来实作的。
将子窗口用于命中测试
有些程序(例如,Windows的「画图」程序),把显示区域划分为几个小的逻辑区域。「画图」程序在其左边有一个由图示组成的工具菜单区,在底部有颜色菜单区。在这两个区做命中测试的时候,「画图」必须在使用者选中菜单项之前记住菜单的位置。
不过,也可能不需要这么做。实际上,画风经由使用子窗口简化了菜单的绘制和命中测试。子窗口把整个矩形区域划分为几个更小的矩形区,每个子窗口有自己的窗口句柄、窗口消息处理程序和显示区域,每个窗口消息处理程序接收只适用于它的子窗口的鼠标消息。鼠标消息中的lParam参数含有相当于该子窗口显示区域左上角的坐标,而不是其父窗口(那是「画图」的主应用程序窗口)显示区域左上角的坐标。
以这种方式使用子窗口有助于程序的结构化和模块化。如果子窗口使用不同的窗口类别,那么每个子窗口都有它自己的窗口消息处理程序。不同的窗口也可以定义不同的背景颜色和不同的内定光标。在第九章中,我将看到「子窗口控件」-滚动条、按钮和编辑方块等预先定义的子窗口。现在,我们说明在CHECKER程序中是如何使用子窗口的。
CHECKER中的子窗口
程序7-4所示的CHECKER3程序,这一版本建立了25个处理鼠标单击的子窗口。它没有键盘接口,但是可以按本章后面的范例的方法添加。
程序7-4 CHECKER3
CHECKER3.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 "Checker3",0
szChildClass DB "Checker3_Child",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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -