📄 chapter13.htm
字号:
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<HTML>
<HEAD>
<meta name="GENERATOR" content="Microsoft® HTML Help Workshop 4.1">
<Title>13.0 -Windows中的窗口</Title>
<LINK REL="stylesheet" HREF="css/basestyles.css" TYPE="text/css">
<LINK REL="stylesheet" HREF="css/tutorials.css" TYPE="text/css">
</HEAD>
<BODY>
<h1 align="center">Win32Asm 教程 </h1>
<TABLE ALIGN="CENTER">
<TR>
<TD CLASS="tutnav" VALIGN="MIDDLE" WIDTH="60" HEIGHT="20"><A HREF="chapter12.htm">前一章</A></TD>
<TD CLASS="tutnav" VALIGN="MIDDLE" WIDTH="60" HEIGHT="20">
<A HREF="contents.htm">目录</A></TD>
<TD CLASS="tutnav" VALIGN="MIDDLE" WIDTH="60" HEIGHT="20"><A HREF="#">下一章</A></TD>
</TR>
</TABLE>
<h2>13.0-Windows中的窗口</h2>
<p>
在本章中,我们将创建一个有窗口的程序
</p>
<h2>13.1-窗口</h2>
<p>
你可能已经猜到了Windows之所以称为Windows的原因了。在Windows中,有两种程序:GUI程序和控制台程序。控制台模式的程序看上去就像Dos程序,它们在一个似-dos的窗口中运行。你使用的大多数程序是GUI(图形用户界面)程序,它们有一个用于和用户交互的图形界面。这是由创建窗口来完成的。几乎你在Windows中看见的每一件东西都是窗口。首先,你创建一个父窗口,然后是像编辑框,静态控件(文本标签-译者注),按钮等的自窗口(控件)。
</p>
<h2>13.2-窗口类</h2>
<p>
每一个窗口都有名字。你为你的父窗口定义你自有的类。对于控件,你可以使用Windows的标准类名(例如,“Edit”,“Static”,“Button”)
</p>
<h2>13.3-结构</h2>
<p>
你程序中的窗口类是用“RegisterClassEx“函数注册的。(RegisterClassEx是RegisterClass的扩展版本,后者已经不太使用了)这个函数的声明是:
</p><p class="def1">
ATOM RegisterClassEx(<br/>
CONST WNDLCASSEX *lpwcx//有类数据的结构之地址<br/>
);
</p><p>
lpwcx:指向WNDCLASSEX结构。在把它传递给函数之前,你必须用适当的类属性填写结构。
</p><p>
唯一的参数是指向结构的指针。先来看看一些结构的基本知识:
</p><p>
一个结构是一些变量(数据)的集合。它用STRUCT定义:
</p><p class="def1">
SOMESTRUCTURE STRUCT<br/>
dword1 dd ?<br/>
dword2 dd ?<br/>
some_word dw ?<br/>
abyte db ?<br/>
anotherbyte db ?<br/>
SOMESTRUCTURE ENDS<br/>
(结构名不一定要大写)
</p><p>
你可以用问号把你的变量定义在未初始化data部分。现在你可以根据定义创建一个结构:
</p><p class="def2">
Initialized<br/>
Initializedstructure SOMESTRUCTURE <100,200,10,'A',90h><br/>
Uninitialized<br/>
UnInitializedstructure SOMESTRUCTURE <>
</p><p>
在第一个例子中,创建了一个新的结构(用初始化了的结构保存它的offset),而且结构的每一个元素用初始化数值填写了。第二个例子只是告诉masm为结构名分配内存,而且每个数据元素用0初始化。在创建了结构之后,你可以在代码中使用它:
</p><p class="def2">
mov eax, Initializedstructure.some_word<br/>
; eax现在是 10 <br/>
inc UnInitializedstructure.dword1<br/>
; 结构的dword1步增
</p><p>
结构是这样存在内存中的:
</p>
<table>
<tr>
<td class="general2">内存地址</td>
<td class="general2">内容</td>
</tr>
<tr>
<td class="general3">offset of Initializedstructure</td>
<td class="general3">100 (dword, 4 bytes)</td>
</tr>
<tr>
<td class="general3">offset of Initializedstructure + 4</td>
<td class="general3">200 (dword, 4 bytes)</td>
</tr>
<tr>
<td class="general3">offset of Initializedstructure + 8</td>
<td class="general3">10 (word, 2 bytes)</td>
</tr>
<tr>
<td class="general3">offset of Initializedstructure + 10</td>
<td class="general3">65 or 'A' (1 byte)</td>
</tr>
<tr>
<td class="general3">offset of Initializedstructure + 11</td>
<td class="general3">90h (1 byte)</td>
</tr>
</table>
<h2>12.3-WNDCLASSEX</h2>
<p>
现在已经了解了足够多的结构知识,让我们处理RegisterClassEx吧。在《win32程序员参考》中,你可以查找WNDCLASSEX结构的定义。
</p><p class="def1">
typedef struct _WNDCLASSEX { // <br/>
UINT cbSize; <br/>
UINT style; <br/>
WNDPROC lpfnWndProc; <br/>
int cbClsExtra; <br/>
int cbWndExtra; <br/>
HANDLE hInstance; <br/>
HICON hIcon; <br/>
HCURSOR hCursor; <br/>
HBRUSH hbrBackground; <br/>
LPCTSTR lpszMenuName; <br/>
LPCTSTR lpszClassName; <br/>
HICON hIconSm; <br/>
} WNDCLASSEX;
</p>
<p>
解释
</p><p>
<span class="def1">cbSize<br/></span>
WNDCLASSEX结构体的大小。用于Windows的认证。你可以用SIZEOF得到它的大小:
mov wc.cbsize, SIZEOF WNDCLASSEX
</p><p>
<span class="def1">style<br/></span>
为类指定一个样式(如果窗口要有滚动条,加上重画标志。等等)
</p><p>
<span class="def1">lpfnWndProc<br/></span>
指向Windows Procedure的指针(本章后面有更多内容)
</p><p>
<span class="def1">cbClsExtra<br/></span>
在Windows类结构后本配多少额外内存。对我们不重要
</p><p>
<span class="def1">cbWndExtra<br/></span>
在Windows实例后分配多少额外内存。对我们也不重要
</p><p>
<span class="def1">hInstance<br/></span>
你程序的实力句柄。你可以用GetMoudleHandle函数得到这个句柄
</p><p>
<span class="def1">hIcon<br/></span>
窗口图标资源的句柄
</p><p>
<span class="def1">hCursor<br/></span>
窗口光标资源的句柄
</p><p>
<span class="def1">hbrBackground<br/></span>
用于填充背景的画刷句柄,或是标准刷子类型中的一个,如 COLOR_WINDOW, COLOR_BTNFACE , COLOR_BACKGROUND.
</p><p>
<span class="def1">lpszMenuName<br/></span>
指向一个指定菜单类名的零结尾字符串
</p><p>
<span class="def1">lpszClassName<br/></span>
指向一个指定窗口类名的零结尾字符串
</p><p>
<span class="def1">hIconSm<br/></span>
一个和窗口类关联的小图标句柄
</p>
<p>
在你的Win32文件夹中创建一个名为firstWindow的文件夹并在这个文件夹中创建一个名为window.asm的新文件,输入一下内容:
</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/>
include \masm32\include\windows.inc<br/>
include \masm32\include\kernel32.inc<br/>
include \masm32\include\user32.inc<br/>
include \masm32\include\gdi32.inc
</p><p>
然后创建一个名为make.bat的.bat文件。把这些文本粘贴进去:
</p><p class="def1">
@echo off<br/>
ml /c /coff window.asm<br/>
link /subsystem:windows window.obj<br/>
pause>nul
</p><p>
从现在开始,为了节省空间,仅显示小段的代码。你可以通过点<view code>来显示教程此处的全部代码。完整的代码在新窗口中显示。
</p><p>
译者注:为了方便,我又把这些放回来了。
</p>
<h2>13.4-注册类</h2>
<p>
现在我们在名为WinMain的过程中注册类。该过程中完成窗口的初始化。
</p><p>
把这些加入你的汇编文件:
</p><p class="def2">
WinMain PROTO STDCALL :DWORD, :DWORD, :DWORD<br/>
<br/>
.data?<br/>
<br/>
hInstance dd ?<br/>
<br/>
.code<br/>
<br/>
invoke GetModuleHandle, NULL<br/>
mov hInstance, eax<br/>
invoke WinMain, hInstance, NULL, NULL, SW_SHOWNORMAL<br/>
<br/>
end start
</p><P>
这些代码通过GetModuleHandle得到模块句柄,并把模块句柄放入hInstance变量中。这个句柄在Windows API中频繁使用。然后它调用WinMain过程。这不是一个API函数,而是一个我们将要定义的过程。原型是:WinMain PROTO STDCALL :DWORD, :DWORD, :DWORD, :DWORD,因而是一个带4个参数的函数:
</p>
<p>
现在把这些代码放在end start:前
</p><p class="def2">
WinMain proc hInst:DWORD, hPrevInst:DWORD, CmdLine:DWORD, CmdShow:DWORD<br/>
<br/>
ret<br/>
WinMain endp
</p><p>
你根本就不需要用这个winmain过程,但这是一种十分普遍的处世化你的程序的方法。Visual C自动初始化这个函数的参数,但我们必须自己来做。现在不要管hPrevInst和CmdLine。集中注意在hInst和CmdShow上。Hinst是实例句柄(=模块句柄),CmdShow是定义窗口该如何显示的标志。(你可以在API参考关于ShowWindows部分发现更多)
</p><p>
在前面代码中的"invoke WinMain, hInstance, NULL, NULL, SW_SHOWNORMAL"用正确的实例句柄和显示标志调用这个函数。现在我们可以在WinMain中写我们的初始化代码了。
</p><p class="def2">
WinMain proc hInst:DWORD, hPrevInst:DWORD, CmdLine:DWORD, CmdShow:DWORD<br/>
LOCAL wc:WNDCLASSEX<br/>
LOCAL hwnd:DWORD <br/>
<br/>
ret<br/>
WinMain endp
</p><p>
这有我们将在过程中要用的两个局部变量
</p><p class="def2">
.data<br/>
<br/>
ClassName db "FirstWindowClass",0<br/>
<br/>
.code<br/>
<br/>
WinMain proc hInst:DWORD, hPrevInst:DWORD, CmdLine:DWORD, CmdShow:DWORD<br/>
LOCAL wc:WNDCLASSEX<br/>
LOCAL hwnd:DWORD<br/>
; now set all the structure members of the WNDCLASSEX structure wc:<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/>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -