📄 见招拆招windows程序设计(六) .txt
字号:
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
.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_LBUTTONDOWN
invoke GetWindowLong,hwnd,0
xor eax,1
invoke SetWindowLong ,hwnd, 0, eax
invoke InvalidateRect,hwnd, NULL, FALSE
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
invoke EndPaint,hwnd,addr ps
ret
.endif
invoke DefWindowProc,hwnd, message, wParam, lParam
ret
ChildWndProc endp
END START
CHECKER3有两个窗口消息处理程序WndProc和ChildWndProc。WndProc还是主(或父)窗口的窗口消息处理程序。ChildWndProc是针对25个子窗口的窗口消息处理程序。这两个窗口消息处理程序都必须定义为CALLBACK函数。
因为窗口消息处理程序与特定的窗口类别结构相关联,该窗口类别结构由Windows呼叫RegisterClass函数来注册,CHECKER3需要两个窗口类别。第一个窗口类别用于主窗口,名为「Checker3」。第二个窗口类别名为「Checker3_Child」。当然,您不必选择像这样有意义的名字。
CHECKER3在WinMain函数中注册了这两个窗口类别。注册完常规的窗口类别之后,CHECKER3只是简单地重新使用wndclass结构中的大多数的字段来注册Checker3_Child类别。无论如何,有四个字段根据子窗口类别而设定为不同的值:
pfnWndProc字段设定为ChildWndProc,子窗口类别的窗口消息处理程序。
cbWndExtra字段设定为4字节,或者更确切地用sizeof (long)。该字段告诉Windows在其为依据此窗口类别的窗口保留的内部结构中,预留了4字节额外的空间。您能使用此空间来保存每个窗口的可能有所不同的信息。
因为像CHECKER3中的子窗口不需要图标,所以hIcon字段设定为NULL 。
pszClassName字段设定为「Checker3_Child」,是类别的名称。
通常,在WinMain中,CreateWindow呼叫建立依据Checker3类别的主窗口。然而,当WndProc收到WM_CREATE消息后,它呼叫CreateWindow 25次以建立25个Checker3_Child类别的子窗口。表7-3是在WinMain中CreateWindow呼叫的参数,与在建立25个子窗口的WndProc中CreateWindow呼叫的参数间的比较。
表7-3
参数
主窗口
子窗口
窗口类别 「Checker3」 「Checker3_Child」
窗口标题 「Checker3...」 NULL
窗口样式 WS_OVERLAPPEDWINDOW WS_CHILDWINDOW | WS_VISIBLE
水平位置 CW_USEDEFAULT 0
垂直位置 CW_USEDEFAULT 0
宽度 CW_USEDEFAULT 0
高度 CW_USEDEFAULT 0
父窗口句柄 NULL hwnd
菜单句柄/子ID NULL (HMENU) (y << 8 | x)
执行实体句柄 hInstance (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE)
额外参数 NULL NULL
一般情况下,子窗口要求有关位置和大小的参数,但是在CHECKER3中的子窗口由WndProc确定位置和大小。对于主窗口,因为它本身就是父窗口,所以它的父窗口句柄是NULL。当使用CreateWindow呼叫来建立一个子窗口时,就需要父窗口句柄了。
主窗口没有菜单,因此参数是NULL。对于子窗口,相同位置的参数称为子ID(或子窗口ID)。这是唯一代表子窗口的数字。在处理对话框的子窗口控件时,子ID显得更为重要。对于CHECKER3来说,我只是简单地将子ID设定为一个数值,该数值是每个子窗口在5×5的主窗口中的x和y位置的组合。
CreateWindow函数需要一个执行实体句柄。在WinMain中,执行实体句柄可以很容易地取得,因为它是WinMain的一个参数。在建立子窗口时, CHECKER3必须用GetWindowLong来从Windows为窗口保留的结构中取得hInstance值(相对于GetWindowLong,我也能将hInstance的值保存到整体变量,并直接使用它)。
每一个子窗口都在hwndChild数组中保存了不同的窗口句柄。当WndProc接收到一个WM_SIZE消息后,它将为这25个子窗口呼叫MoveWindow。MoveWindow的参数表示子窗口左上角相对于父窗口显示区域的坐标、子窗口的宽度和高度以及子窗口是否需要重画。
现在让我们看一下ChildWndProc。此窗口消息处理程序为所有这25个子窗口处理消息。ChildWndProc的hwnd参数是子窗口接收消息的句柄。当ChildWndProc处理WM_CREATE消息时(因为有25个子窗口,所以要发生25次),它用SetWindowWord在窗口结构保留的额外区域中储存一个0值(通过在定义窗口类别时使用的cbWndExtra来保留的空间)。ChildWndProc用此值来恢复目前矩形的状态(有X或没有X)。在子窗口中单击时,WM_LBUTTONDOWN处理例程简单地修改这个整数值(从0到1,或从1到0),并使整个子窗口无效。此区域是被单击的矩形。WM_PAINT的处理很简单,因为它所绘制的矩形与显示区域一样大。
因为CHECKER3的C原始码文件和.EXE文件比CHECKER1的大(更不用说程序的说明了),我不会试着告诉你说CHECKER3比CHECKER1更简单。但请注意,我们没有做任何的鼠标命中测试!我们所要的,就是知道CHECKER3中是否有个子窗口得到了命中窗口的WM_LBUTTONDOWN消息。
子窗口和键盘
为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"), ;windo
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -