上面几行从概念上说确实是非常地简单。只要几行指令就可以实现。其中的主要概念就是窗口类(window class),一个窗口类就是一个有关窗口的规范,这个规范定义了几个主要的窗口的元素,如:图标、光标、背景色、和负责处理该窗口的函数。您产生一个窗口时就必须要有这样的一个窗口类。如果您要产生不止一个同种类型的窗口时,最好的方法就是把这个窗口类存储起来,这种方法可以节约许多的内存空间。也许今天您不会太感觉到,可是想想以前 pc 大多数只有 1m 内存时,这么做是非常有必要的。如果您要定义自己的创建窗口类就必须:在一个 windclass 或 windowclassexe 结构体中指明您窗口的组成元素,然后调用 registerclass 或 registerclassex ,再根据该窗口类产生窗口。对不同特色的窗口必须定义不同的窗口类。 windows有几个预定义的窗口类,譬如:按钮、编辑框等。要产生该种风格的窗口无须预先再定义窗口类了,只要包预定义类的类名作为参数调用 createwindowex 即可。
wndclassex 中最重要的成员莫过于lpfnwndproc了。前缀 lpfn 表示该成员是一个指向函数的长指针。在 win32中由于内存模式是 flat 型,所以没有 near 或 far 的区别。每一个窗口类必须有一个窗口过程,当 windows 把属于特定窗口的消息发送给该窗口时,该窗口的窗口类负责处理所有的消息,如键盘消息或鼠标消息。由于窗口过程差不多智能地处理了所有的窗口消息循环,所以您只要在其中加入消息处理过程即可。下面我将要讲解 wndclassex 的每一个成员
wndclassex struct dword
cbsize dword ?
style dword ?
lpfnwndproc dword ?
cbclsextra dword ?
cbwndextra dword ?
hinstance dword ?
hicon dword ?
hcursor dword ?
hbrbackground dword ?
lpszmenuname dword ?
lpszclassname dword ?
hiconsm dword ?
wndclassex ends
- cbsize:wndclassex 的大小。我们可以用sizeof(wndclassex)来获得准确的值。
- style:从这个窗口类派生的窗口具有的风格。您可以用“or”操作符来把几个风格或到一起。
- lpfnwndproc:窗口处理函数的指针。
- cbclsextra:指定紧跟在窗口类结构后的附加字节数。
- cbwndextra:指定紧跟在窗口事例后的附加字节数。如果一个应用程序在资源中用class伪指令注册一个对话框类时,则必须把这个成员设成dlgwindowextra。
- hinstance:本模块的事例句柄。
- hicon:图标的句柄。
- hcursor:光标的句柄。
- hbrbackground:背景画刷的句柄。
- lpszmenuname:指向菜单的指针。
- lpszclassname:指向类名称的指针。
- hiconsm:和窗口类关联的小图标。如果该值为null。则把hcursor中的图标转换成大小合适的小图标。
invoke createwindowex, null,\
addr classname,\
addr appname,\
ws_overlappedwindow,\
cw_usedefault,\
cw_usedefault,\
cw_usedefault,\
cw_usedefault,\
null,\
null,\
hinst,\
null
注册窗口类后,我们将调用createwindowex来产生实际的窗口。请注意该函数有12个参数。
createwindowexa proto dwexstyle:dword,\
lpclassname:dword,\
lpwindowname:dword,\
dwstyle:dword,\
x:dword,\
y:dword,\
nwidth:dword,\
nheight:dword,\
hwndparent:dword ,\
hmenu:dword,\
hinstance:dword,\
lpparam:dword
我们来仔细看一看这些的参数:
- dwexstyle:附加的窗口风格。相对于旧的createwindow这是一个新的参数。在9x/nt中您可以使用新的窗口风格。您可以在style中指定一般的窗口风格,但是一些特殊的窗口风格,如顶层窗口则必须在此参数中指定。如果您不想指定任何特别的风格,则把此参数设为null。
- lpclassname:(必须)。asciiz形式的窗口类名称的地址。可以是您自定义的类,也可以是预定义的类名。像上面所说,每一个应用程序必须有一个窗口类。
- lpwindowname:asciiz形式的窗口名称的地址。该名称会显示在标题条上。如果该参数空白,则标题条上什么都没有。
- dwstyle:窗口的风格。在此您可以指定窗口的外观。可以指定该参数为零,但那样该窗口就没有系统菜单,也没有最大化和最小化按钮,也没有关闭按钮,那样您不得不按alt+f4 来关闭它。最为普遍的窗口类风格是 ws_overlappedwindow。 一种窗口风格是一种按位的掩码,这样您可以用“or”把您希望的窗口风格或起来。像 ws_overlappedwindow 就是由几种最为不便普遍的风格或起来的。
- x,y: 指定窗口左上角的以像素为单位的屏幕坐标位置。缺省地可指定为 cw_usedefault,这样 windows 会自动为窗口指定最合适的位置。
- nwidth, nheight: 以像素为单位的窗口大小。缺省地可指定为 cw_usedefault,这样 windows 会自动为窗口指定最合适的大小。
- hwndparent: 父窗口的句柄(如果有的话)。这个参数告诉 windows 这是一个子窗口和他的父窗口是谁。这和 mdi(多文档结构)不同,此处的子窗口并不会局限在父窗口的客户区内。他只是用来告诉 windows 各个窗口之间的父子关系,以便在父窗口销毁是一同把其子窗口销毁。在我们的例子程序中因为只有一个窗口,故把该参数设为 null。
- hmenu: windows菜单的句柄。如果只用系统菜单则指定该参数为null。回头看一看wndclassex 结构中的 lpszmenuname 参数,它也指定一个菜单,这是一个缺省菜单,任何从该窗口类派生的窗口若想用其他的菜单需在该参数中重新指定。其实该参数有双重意义:一方面若这是一个自定义窗口时该参数代表菜单句柄,另一方面,若这是一个预定义窗口时,该参数代表是该窗口的 id 号。windows 是根据lpclassname 参数来区分是自定义窗口还是预定义窗口的。
- hinstance: 产生该窗口的应用程序的实例句柄。
- lpparam: (可选)指向欲传给窗口的结构体数据类型参数的指针。如在mdi中在产生窗口时传递 clientcreatestruct 结构的参数。一般情况下,该值总为零,这表示没有参数传递给窗口。可以通过getwindowlong 函数检索该值。
mov hwnd,eax
invoke showwindow, hwnd,cmdshow
invoke updatewindow, hwnd
调用createwindowex成功后,窗口句柄在eax中。我们必须保存该值以备后用。我们刚刚产生的窗口不会自动显示,所以必须调用 showwindow 来按照我们希望的方式来显示该窗口。接下来调用 updatewindow 来更新客户区。
.while true
invoke getmessage, addr msg,null,0,0
.break .if (!eax)
invoke translatemessage, addr msg
invoke dispatchmessage, addr msg