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

📄 chapter13.htm

📁 win32汇编资料 教程!
💻 HTM
📖 第 1 页 / 共 2 页
字号:
invoke RegisterClassEx, ADDR wc <br/>
<br/>
ret<br/>
WinMain endp
</p>
<p>
让我们来看看发生了什么:
</p>
<p class="def2">
mov  wc.cbSize,SIZEOF WNDCLASSEX<br/>
mov  wc.style, CS_HREDRAW or CS_VREDRAW<br/>
mov  wc.lpfnWndProc, OFFSET WndProc<br/>
mov  wc.cbClsExtra,NULL<br/>
mov  wc.cbWndExtra,NULL
</p><p>
初始化了结构的大小(这是RegisterClassEx要求的)。设置类的样式为”CS_HREDRAW or CS_VREDRAW”,然后设置了窗口过程的offset。你在后面会知道什么是窗口过程,现在你仅需要记住你需要WndProc过程的地址。该地址可以通过“offset WndProc”获得。Cb.ClsExtra和cb.WndExtra我们没有使用因而设它们为Null。
</p><p class="def2">
Push hInst<br/>
Pop wc.hInstance
</p><p>
Wc.hInstance设为WinMain的hInst参数。为什么我们不用:mov wc.hInstance, hInst?因为mov指令不允许从一个地址移到另一个地址。通过push/pop,值被压入栈,然后又弹入目标中。
</p><p class="def2">
mov  wc.hbrBackground, COLOR_WINDOW<br/>
mov  wc.lpszMenuName, NULL<br/>
mov  wc.lpszClassName, OFFSET ClassName
</p><p>
类的背景色被设为COLOR_WINDOW,没有定义菜单(null)而且lpszClassName设为一个指向零结尾的类名字符串:“FirstWindowClass”它应该是一个在你的程序中定义的唯一名字。
</p><p class="def2">
invoke LoadIcon, NULL, IDI_APPLICATION<br/>
mov  wc.hIcon, eax<br/>
mov  wc.hIconSm, eax
</p><p>
窗口需要一个图标。但又因为我们要一个指向图标的句柄,我们使用LoadIcon来载入图标并获得句柄。LoadIcon有两个参数:hInstance和lpIconName。HInstance是包含图标的可执行文件的模块句柄。LpIconName是一个指向图标资源和图标ID的字符串的指针。如果你用NULL为hInstance,你可以从一些标准图表中选这一个(这却是是因为我们在这里还没有图标资源)hIconSm是小图标,你可以对它使用相同的句柄。
</p><p class="def2">
invoke LoadCursor,NULL,IDC_ARROW<br/>
mov  wc.hCursor,eax
</p><p>
对光标也一样。NULL作hInstance,并用一个标准光标类型:IDC_ARROW,标准Windows箭头型光标。
</p><p class="def2">
invoke RegisterClassEx, ADDR wc
</p><p>
现在,最终用RegisterClassEx来注册类,通过一个指向WNDCLASSEX结构的指针作参数。
</p>

<h2>13.5-创建窗口</h2>
<p>
现在,你已经注册了一个类,你可以使用它创建一个窗口:
</p><p class="def1">
HWND CreateWindowEx(<br/>
DWORD dwExStyle, // extended window style<br/>
LPCTSTR lpClassName, // pointer to registered class name<br/>
LPCTSTR lpWindowName, // pointer to window name<br/>
DWORD dwStyle, // window style<br/>
int x, // horizontal position of window<br/>
int y, // vertical position of window<br/>
int nWidth, // window width<br/>
int nHeight, // window height<br/>
HWND hWndParent, // handle to parent or owner window<br/>
HMENU hMenu, // handle to menu, or child-window identifier<br/>
HINSTANCE hInstance, // handle to application instance<br/>
LPVOID lpParam // pointer to window-creation data<br/>
);
</p>
<p>
DwExstyle和dwStyle是两个决定窗口样式的参数。<br/>

LpClassName 是一个指向你注册了的类名的指针。<br/>

LpWindowName 是你窗口的名字(如果有的话,这将成为你窗口的标题)<br/>

X, Y, nWidth, nHeight 决定你窗口的位置和大小<br/>

HMenu 是菜单窗口的句柄(在后面讨论,现在为空)<br/>

HInstance 是程序实例的句柄<br/>

LpPararm 是你能在你的程序中使用的扩展值
</p>
<p class="def2">
.data<br/>
<br/>
AppName "FirstWindow",0<br/>
<br/>
.code<br/>
<br/>
INVOKE CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\<br/>
WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\<br/>
CW_USEDEFAULT,400,300,NULL,NULL,\<br/>
hInst,NULL<br/>
mov hwnd, eax<br/>
invoke ShowWindow, hwnd, SW_SHOWNORMAL<br/>
invoke UpdateWindow, hwnd<br/>
<br/>
(注意\使汇编器读下一行的时候好像还在同一行)
</p><p>
我们的代码将用我们刚刚注册的类名创建一个新的窗口。标题是“FirstWindow”(程序名,AppName),样式是WS_OVERLAPPEDWINDOW,这是一个创建有标题,系统菜单,可缩放边框和最大化/最小化按钮的窗口样式。CW_USERDEFAULT作为x和y的位置会使Windows为新窗口使用缺省位置。窗口的(初始)大小是400×300象素。
</p><p>
函数的返回值是窗口句柄,HWND。它储存在局部变量hwnd中。然后窗口用ShowWindow显示。UpdateWindow确保窗口被画出。
</p>
<h2>13.6-消息循环</h2>
<p>
窗口可以通过消息和你的程序以及其他窗口通讯。无论何时,一条消息被发送给指定的窗口。它的窗口过程都要被调用。每个窗口都有一个消息循环或消息泵(pump)。这是一个无止尽的检查是否给有你的窗口的消息的循环。而且如果有,把消息传递给dispatchMessage函数。这个函数会调用你的窗口过程。消息循环和窗口过程是两个完全不同的东西!!!
</p>
<p class="def2">
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD<br/>
LOCAL wc:WNDCLASSEX<br/>
LOCAL hwnd:DWORD<br/>
LOCAL msg:MSG ;<<<NEW<br/>
<br/>
........<br/>
<br/>
.WHILE TRUE<br/>
invoke GetMessage, ADDR msg,NULL,0,0<br/>
.BREAK .IF (!eax)<br/>
invoke TranslateMessage, ADDR msg<br/>
invoke DispatchMessage, ADDR msg<br/>
.ENDW
</p><p>
这是消息循环看上去的样子。.WHILE TRUE, .ENDW循环到eax为0之前都会继续。如果它接到了WM_QUIT消息,GetMessage返回0,这将关闭窗口因而程序应该在不论GetMessage返回0时退出。如果不是这样(0),消息被传递给TranslateMessage(这个函数把按键翻译为消息)而且消息被Windows用DispatchMessage函数解包。消息本身在一个消息循环的组成部分MSG结构中(LOCAL msg: MSG被加入过程,增加了一个称为msg的局部消息结构)你可以在你的所有程序中用这个消息循环。
</p>
<h2>13.7-窗口过程</h2>
<p>
消息会被发送往窗口过程。一个窗口过程看上去总是这样:
</p><p class="def2">
WndProc PROTO STDCALL :DWORD, :DWORD, :DWORD, :DWORD<br/>
<br/>
.code<br/>
<br/>
WndProc proc hWnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD<br/>
mov eax, uMsg<br/>
.IF eax==XXXX<br/>
.ELSEIF eax==XXXX<br/>
.ELSE<br/>
    invoke DefWindowProc, hWnd, uMsg, wParam, lParam<br/>
.ENDIF<br/>
ret<br/>
WndProc endp
</p>
<p>
窗口过程总是有4个参数
</p><p class="def1">
hWnd 包含窗口句柄<br/>

uMsg 消息<br/>

wParam 消息的第一个参数(由消息定义)<br/>

lParam 消息的第二个参数(由消息定义)<br/>
</p>
<p>
窗口不处理的消息应该传递给DefWindowProc,它会处理这些。一个窗口过程的例子:
</p><p class="def2">
WndProc proc hWnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD<br/>
mov eax, uMsg<br/>
.IF eax==WM_CREATE<br/>
    invoke MessageBox, NULL, ADDR AppName, ADDR AppName, NULL<br/>
.ELSEIF eax==WM_DESTROY<br/>
    invoke PostQuitMessage, NULL<br/>
.ELSE<br/>
    invoke DefWindowProc, hWnd, uMsg, wParam, lParam<br/>
.ENDIF<br/>
ret<br/>
WndProc endp
</p><p>
这段代码在窗口初始化时显示程序名称。也要注意我加入了WM_DESTROY消息的处理。这条消息在窗口将要关闭的时候发送。程序要用PostQuitMessage作出反应。
</p><p>
现在看看最终的代码:
<p><p class="def2">
.486<br/>
.model flat, stdcall<br/>
option casemap:none<br/>
 <br/>
includelib \masm32\lib\kernel32.lib<br/>
includelib \masm32\lib\user32.lib<br/>
includelib \masm32\lib\gdi32.lib<br/>
 <br/>
include \masm32\include\windows.inc<br/>
include \masm32\include\kernel32.inc<br/>
include \masm32\include\user32.inc<br/>
include \masm32\include\gdi32.inc<br/>
WinMain PROTO STDCALL   :DWORD, :DWORD, :DWORD, :DWORD<br/>
WndProc PROTO STDCALL   :DWORD, :DWORD, :DWORD, :DWORD<br/>
.data?<br/>
hInstance       dd      ?<br/>
 <br/>
.data<br/>
ClassName       db      "FirstWindowClass",0<br/>
AppName         db      "FirstWindow",0<br/>
 <br/>
.code<br/>
start:<br/>
 <br/>
    invoke  GetModuleHandle, NULL<br/>
    mov     hInstance, eax<br/>
    invoke  WinMain, hInstance, NULL, NULL, SW_SHOWNORMAL<br/>
    invoke  ExitProcess, NULL<br/>
 <br/>
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD<br/>
    LOCAL wc:WNDCLASSEX<br/>
    LOCAL hwnd:DWORD<br/>
    LOCAL msg:MSG<br/>
    mov     wc.cbSize,SIZEOF WNDCLASSEX<br/>
    mov     wc.style,   CS_HREDRAW or CS_VREDRAW<br/>
    mov     wc.lpfnWndProc, OFFSET WndProc<br/>
    mov     wc.cbClsExtra,NULL<br/>
    mov     wc.cbWndExtra,NULL<br/>
    push    hInst<br/>
    pop     wc.hInstance<br/>
    mov     wc.hbrBackground,COLOR_WINDOW<br/>
    mov     wc.lpszMenuName,NULL<br/>
    mov     wc.lpszClassName,OFFSET ClassName<br/>
    invoke  LoadIcon,NULL,IDI_APPLICATION<br/>
    mov     wc.hIcon,   eax<br/>
    mov     wc.hIconSm, eax<br/>
    invoke  LoadCursor,NULL,IDC_ARROW<br/>
    mov     wc.hCursor,eax<br/>
    invoke  RegisterClassEx,    addr wc<br/>
    <br/>
    INVOKE CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\<br/>
           WS_OVERLAPPEDWINDOW-WS_SIZEBOX-WS_MAXIMIZEBOX,CW_USEDEFAULT,\<br/>
           CW_USEDEFAULT,400,300,NULL,NULL,\<br/>
           hInst,NULL<br/>
    mov   hwnd,eax<br/>
    invoke ShowWindow, hwnd,SW_SHOWNORMAL<br/>
    invoke UpdateWindow, hwnd<br/>
    .WHILE TRUE<br/>
        invoke GetMessage, ADDR msg,NULL,0,0<br/>
        .BREAK .IF (!eax)<br/>
                invoke TranslateMessage, ADDR msg<br/>
                invoke DispatchMessage, ADDR msg<br/>
    .ENDW<br/>
    mov     eax,msg.wParam<br/>
    ret<br/>
WinMain endp<br/>
 <br/>
WndProc proc hWnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD<br/>
mov eax, uMsg<br/>
.IF eax==WM_CREATE<br/>
    invoke  MessageBox, NULL, ADDR AppName, ADDR AppName, NULL<br/>
.ELSEIF eax==WM_DESTROY<br/>
    invoke PostQuitMessage, NULL<br/>
.ELSE<br/>
    invoke DefWindowProc, hWnd, uMsg, wParam, lParam<br/>
.ENDIF<br/>
ret<br/>
WndProc endp<br/>
end start
</p>

</BODY>
</HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -