iczelion tut3[3]

[入库:2005年8月19日] [更新:2007年3月24日]

本文简介:选择自 jimgreen 的 blog

        invoke defwindowproc,hwnd,umsg,wparam,lparam     ; default message processing
        ret
    .endif
    xor eax,eax
    ret
wndproc endp

end start

分析:

看到一个简单的 windows 程序有这么多行,您是不是有点想撤? 但是您必须要知道的是上面的大多数代码都是模板而已,模板的意思即是指这些代码对差不多所有标准 windows 程序来说都是相同的。在写 windows 程序时您可以把这些代码拷来拷去,当然把这些重复的代码写到一个库中也挺好。其实真正要写的代码集中在 winmain 中。这和一些 c 编译器一样,无须要关心其它杂务,集中精力于 winmain 函数。唯一不同的是 c 编译器要求您的源代码有必须有一个函数叫 winmain。否则 c 无法知道将哪个函数和有关的前后代码链接。相对c,汇编语言提供了较大的灵活性,它不强行要求一个叫 winmain 的函数。

下面我们开始分析,您可得做好思想准备,这可不是一件太轻松的活。

.386
.model flat,stdcall
option casemap:none

winmain proto :dword,:dword,:dword,:dword

include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

您可以把前三行看成是"必须"的.

.386告诉masn我们要用80386指令集。
. model flat,stdcall告诉masm 我们用的内存寻址模式,此处也可以加入stdcall告诉masm我们所用的参数传递约定。

接下来是函数 winmain 的原型申明,因为我们稍后要用到该函数,故必须先声明。我们必须包含 window.inc 文件,因为其中包含大量要用到的常量和结构的定义,该文件是一个文本文件,您可以用任何文本编辑器打开它, window.inc还没有包含所有的常量和结构定义,不过 hutch 和我一直在不断加入新的内容。如果暂时在 window.inc 找不到,您也可以自行加入。

我们的程序调用驻扎在 user32.dll (譬如:createwindowex, registerwindowclassex) 和 kernel32.dll (exitprocess)中的函数,所以必须链接这两个库。接下来我如果问:您需要把什么库链入您的程序呢 ? 答案是:先查到您要调用的函数在什么库中,然后包含进来。譬如:若您要调用的函数在 gdi32.dll 中,您就要包含gdi32.inc头文件。和 masm 相比,tasm 则要简单得多,您只要引入一个库,即:import32.lib。<译者注:但 tasm5 麻烦的是 windows.inc 非常的不全面,而且如果在 windows.inc 中包含全部的 api 定义会内存不够,所以每次你得把用到的 api 定义拷贝出来>

.data

classname db "simplewinclass",0
appname db "our first window",0

.data?

hinstance hinstance ?
commandline lpstr ?

接下来是data"分段"。 在 .data 中我们定义了两个以 null 结尾的字符串 (asciiz):其中 classname 是 windows 类名,appname 是我们窗口的名字。这两个变量都是初始化了的。未进行初始化的两个边量放在 .data? "分段"中,其中 hinstance 代表应用程序的句柄,commandline 保存从命令行传入的参数。hinstace 和 lpstr 是两个数据类型名,它们在头文件中定义,可以看做是 dword 的别名,之所以要这么重新定仅是为了易记。您可以查看 windows.inc 文件,在 .data? 中的变量都是未经初始化的,这也就是说在程序刚启动时它们的值是什么无关紧要,只不过占有了一块内存,以后可以再利用而已。

.code
start:
invoke getmodulehandle, null
mov hinstance,eax
invoke getcommandline
mov commandline,eax
invoke winmain, hinstance,null,commandline, sw_showdefault
invoke exitprocess,eax
.....
end start

.data "分段"包含了您应用程序的所有代码,这些代码必须都在 .code 和 end 之间。至于 label 的命名只要遵从 windows 规范而且保证唯一则具体叫什么倒是无所谓。我们程序的第一条语句是调用 getmodulehandle 去查找我们应用程序的句柄。在win32下,应用程序的句柄和模块的句柄是一样的。您可以把实例句柄看成是您的应用程序的 id 号。我们在调用几个函数是都把它作为参数来进行传递,所以在一开始便得到并保存它就可以省许多的事。

特别注意:win32下的实例句柄实际上是您应用程序在内存中的线性地址。

win32 中函数的函数如果有返回值,那它是通过 eax 寄存器来传递的。其他的值可以通过传递进来的参数地址进行返回。一个 win32 函数被调用时总会保存好段寄存器和 ebx,edi,esi和ebp 寄存器,而 ecx和edx 中的值总是不定的,不能在返回是应用。特别注意:从 windows api 函数中返回后,eax,ecx,edx 中的值和调用前不一定相同。当函数返回时,返回值放在eax中。如果您应用程序中的函数提供给 windows 调用时,也必须尊守这一点,即在函数入口处保存段寄存器和 ebx,esp,esi,edi 的值并在函数返回时恢复。如果不这样一来的话,您的应用程序很快会崩溃。从您的程序中提供给 windows 调用的函数大体上有两种:windows 窗口过程和 callback 函数。

如果您的应用程序不处理命令行那么就无须调用 getcommandline,这里只是告诉您如果要调用应该怎么做。

下面则是调用winmain了。该函数共有4个参数:应用程序的实例句柄,该应用程序的前一实例句柄,命令行参数串指针和窗口如何显示。win32 没有前一实例句柄的概念,所以第二个参数总为0。之所以保留它是为了和 win16 兼容的考虑,在 win16下,如果 hprevinst 是 null,则该函数是第一次运行。特别注意:您不用必须申明一个名为 winmain 函数,事实上在这方面您可以完全作主,您甚至无须有一个和 winmain 等同的函数。您只要把 winmain 中的代码拷到getcommandline 之后,其所实现的功能完全相同。在 winmain 返回时,把返回码放到 eax 中。然后在应用程序结束时通过 exitprocess 函数把该返回码传递给 windows 。

winmain proc inst:hinstance,hprevinst:hinstance,cmdline:lpstr,cmdshow:dword

上面是winmain的定义。注意跟在 proc 指令后的parameter:type形式的参数,它们是由调用者传给 winmain 的,我们引用是直接用参数名即可。至于压栈和退栈时的平衡堆栈工作由 masm 在编译时加入相关的前序和后序汇编指令来进行。 local wc:wndclassex local msg:msg local hwnd:hwnd local 伪指令为局部变量在栈中分配内存空间,所有的 local 指令必须紧跟在 proc 之后。local 后跟声明的变量,其形式是 变量名:变量类型。譬如 local wc:wndclassex 即是告诉 masm 为名字叫 wc 的局部边量在栈中分配长度为 wndclassex 结构体长度的内存空间,然后我们在用该局部变量是无须考虑堆栈的问题,考虑到 dos 下的汇编,这不能不说是一种恩赐。不过这就要求这样申明的局部变量在函数结束时释放栈空间,(也即不能在函数体外被引用),另一个缺点是您因不能初始化您的局部变量,不得不在稍后另外再对其赋值。

mov wc.cbsize,sizeof wndclassex
mov wc.style, cs_hredraw or cs_vredraw
mov wc.lpfnwndproc, offset wndproc
mov wc.cbclsextra,null
mov wc.cbwndextra,null
push hinstance
pop wc.hinstance
mov wc.hbrbackground,color_window+1
mov wc.lpszmenuname,null
mov wc.lpszclassname,offset classname
invoke loadicon,null,idi_application
mov wc.hicon,eax
mov wc.hiconsm,eax
invoke loadcursor,null,idc_arrow
mov wc.hcursor,eax invoke
registerclassex, addr w

本文关键:iczelion asm
  相关方案
Google
 

本站最佳浏览方式为 分辨率 1024x768 IE 6.0(或更高版本的 IE浏览器)

go top