首页
社区
课程
招聘
[study-note]Windows环境下32位汇编语言程序设计--第4章 第一个窗口程序4.1 开始了解窗口(2)
发表于: 2008-4-14 21:26 7527

[study-note]Windows环境下32位汇编语言程序设计--第4章 第一个窗口程序4.1 开始了解窗口(2)

2008-4-14 21:26
7527
;=============================================
;=>使用386指令集
;=>内存模式为平坦模式
;=>函数调用为标准调用方式,即参数从右到左压栈,由被调用者恢复堆栈
;============================================

.386
.model  flat,stdcall
option  casemap:none

;=========
;=>文件定义
;=========
include  windows.inc
include  gdi32.inc
includelib  gdi32.lib
include  user32.inc
includelib  user32.lib
include  kernel32.inc
includelib  kernel32.lib

;==============
;=>数据段
;==============
.data?
hInstance    dd  ?
hWinMain    dd  ?

.const
szClassName  db  'MyClass',0
szCaptionMain  db  'My first Window!',0
szText    db  'Win32 Assembly,Simple and powerful!',0

;==========
;=>代码段
;==========
.code

;==========================================
;=>窗口过程
;=>告诉编译器在函数中使用ebx edi esi寄存器,参数缺省时为dword类型
;==========================================
_ProcWinMain  proc  uses ebx edi esi,hWnd,uMsg,wParam,lParam

    ;定义一个绘制结构体变量和一个矩形结构体变量
    ;绘制结构体变量存储一些关于在屏幕上绘制图形的信息
    ;矩形结构体存储窗口的大小

    local  @stPs:PAINTSTRUCT
    local  @stRect:RECT
    local  @hDc
    
    ;将接受到的消息传送到eax中去,以作进一步的处理
    ;为什么要传送到eax中去呢?不喜欢也可以换ebx的
    ;重要的是里面的消息,而不是存储这个消息的寄存器
    mov  eax,uMsg

    .if  eax==WM_PAINT  ;绘制消息,当屏幕变动时触发该消息事件

      ;调用开始绘制API取得窗口DC并将其传送到DC句柄
      invoke  BeginPaint,hWnd,addr @stPs
      mov  @hDc,eax

      ;取得窗口的坐标并将其传送到结构体变量
      invoke  GetClientRect,hWnd,addr @stRect

      ;完成上面工作后,在客户区中以水平垂直居中形式输出一行文字
      invoke  DrawText,@hDc,addr szText,-1,addr @stRect,DT_SINGLELINE or DT_CENTER or \
                  DT_VCENTER

      ;结束绘制图形并进行扫尾工作
      invoke  EndPaint,hWnd,addr @stPs

    .elseif  eax==WM_CLOSE  ;如果接收到关闭窗口的消息

      ;调用销毁窗口API销毁创建的窗口
      invoke  DestroyWindow,hWinMain
    .else
      ;如果不是自己感兴趣的消息,就交给缺省消息处理函数去处理吧
      invoke  DefWindowProc,hWnd,uMsg,wParam,lParam
      
      ret
    .endif

    xor  eax,eax

    ret
_ProcWinMain  endp

;========================================
;=>主函数,用于创建窗口及接受消息和分发消息到相应窗口中去
;========================================
_WinMain    proc

    ;定义一个窗口类结构体变量,这里的类不是C++里说的类,而是一个结构体,仅是名字叫类而已
    ;这个类限制了将要创建的窗口的风格,利用这个类可以创建N个窗口,一般只要一个就可以了
    local  @stWndClass:WNDCLASSEX
    
    ;定义一个消息结构体变量,同样是一个结构体,这说明了结构体类型是多么的重要
    local  @stMsg:MSG

    ;调用取模块句柄API,参数是NULL,并将结果传送到实例句柄变量
    invoke  GetModuleHandle,NULL
    mov  hInstance,eax

    ;将窗口类结构体变量清空为0,这是为了防止不必要的意外发生
    invoke  RtlZeroMemory,addr @stWndClass,sizeof @stWndClass

;==========
;=>注册窗口类
;==========  
    ;加载光标资源到内存,并将其句柄传送到窗口类变量,这里加载的是系统的光标
    ;其实我们可以轻松将其替换成我们自己的光标,但这超出了第一个窗口程序的要求了
    invoke  LoadCursor,0,IDC_ARROW
    mov  @stWndClass.hCursor,eax

    ;将模块实例句柄传送到窗口类中去
    ;这里不是直接用mov指令传送,而是通过堆栈间接传送的
    push  hInstance
    pop  @stWndClass.hInstance

    ;将窗口类结构体类型大小传送到窗口类结构体变量的cbsize成员中
    mov  @stWndClass.cbSize,sizeof WNDCLASSEX

    ;设置窗口风格为当窗口水平或垂直方向大小发生改变时要重新刷新窗口
    ;CS_HREDRAW 表示 窗口类风格(CS) 为 水平方向(H)发生改变时重绘窗口(REDRAW)
    ;CS_VREDRAW 表示 窗口类风格(CS) 为 垂直方向(V)发生改变时重绘窗口(REDRAW)
    ;更多风格请参照微软MSDN,其实这两个风格一般情况下已经足够了
    mov  @stWndClass.style,CS_HREDRAW or CS_VREDRAW

    ;将所谓的窗口消息处理函数的地址传送到窗口类成员lpfnWndProc中去
    ;lpfnWndProc 要分四个部分看:lp 表示 long point 即变量类型为 长指针(指针就指针还长指针,不可理解)
    ;      Wnd 表示 window(s) 即窗口
    ;      Proc 表示 process 即处理
    ;四个部分合起来就是类型为指向窗口处理函数的指针,即存储函数的地址的变量
    ;恐怖的术语常常成为我们学习的阻碍,现在开始要透过现象看本质,指针不过是一个变量而已,只是它里面存储的是另一个
    ;内存单元的地址
    mov  @stWndClass.lpfnWndProc,offset _ProcWinMain

    ;设置窗口背景颜色为窗口缺省颜色再加1
    ;这里COLOR_WINDOW是一个常量,是已经设置好的颜色值
    mov  @stWndClass.hbrBackground,COLOR_WINDOW+1
    
    ;设置窗口类名为 szClassName
    ;窗口类变量名和窗口类名有什么关系呢?  简单点说一个是结构体变量,一个是字符串
    ;关于其作用可百度一下
    ;lpszClassName 这个名字好长啊=-=|| @#$%(&*^
    ;我们可以这样理解:lp 为变量类型,即long point长指针
    ;    sz 为变量类型,即字符串。和上面的合起来就是字符串指针
    ;    ClassName 为类名,即变量的名字,这样命名易于理解很多
    ;上面几个意思合起来就是:指向一个类名字符串的指针
    mov  @stWndClass.lpszClassName,offset szClassName

    invoke  RegisterClassEx,addr @stWndClass
;============
;=>建立并显示窗口
;============
    invoke  CreateWindowEx,WS_EX_CLIENTEDGE,\
      offset szClassName,offset szCaptionMain,\  ;参数为窗口类名和窗口标题,窗口标题才会显示
      WS_OVERLAPPEDWINDOW,\  
      100,100,600,400,\        ;窗口大小
      NULL,NULL,hInstance,NULL      ;其中有一个参数是本模块句柄

    ;将创建的窗口的句柄传送到主窗口句柄变量,其实它这个变量不过是一个双字变量而已
    ;没什么好怕的,见多用多就熟悉了
    mov  hWinMain,eax

    ;显示创建好的窗口
    invoke  ShowWindow,hWinMain,SW_SHOWNORMAL

    ;刷新窗口的客户区
    invoke  UpdateWindow,hWinMain
;===========
;=>消息循环
;===========
    .while  TRUE      ;死循环,一般都有这么一个循环在消息处理程序中的
    
      ;获取系统发送到这个程序对应的消息队列里的消息
      invoke  GetMessage,addr @stMsg,NULL,0,0
      
      
      .break  .if  eax==0

      ;对获取的消息进行"解密",即如果有键盘键按下,则将两个键盘消息合并为一个字符消息处理
      invoke  TranslateMessage,addr @stMsg

      ;将消息发送到各自的处理函数中去处理,即什么窗口的消息,就发送到什么窗口的
      ;消息处理函数去处理,一个窗口可以有一个处理函数,二个则可能有两个处理函数
      invoke  DispatchMessage,addr @stMsg

    .endw

    ret
_WinMain    endp

;=======================================
start:  
    call  _WinMain
    invoke  ExitProcess,NULL
;=======================================
end  start

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 7
支持
分享
最新回复 (7)
雪    币: 486
活跃值: (13)
能力值: ( LV9,RANK:430 )
在线值:
发帖
回帖
粉丝
2
如果觉得看上面的代码繁杂,可以看"原版"的清晰版的代码

.386
                 .model flat,stdcall
                 option casemap:none

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include          windows.inc
include          gdi32.inc
includelib       gdi32.lib
include          user32.inc
includelib       user32.lib
include          kernel32.inc
includelib       kernel32.lib

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                 .data?

hInstance        dd         ?

hWinMain         dd         ?

                 .const

szClassName      db    'MyClass',0

szCaptionMain    db    'My first Window !',0

szText           db    'Win32 Assembly, Simple and powerful !',0

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                 .code

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 窗口过程
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcWinMain     proc  uses ebx edi esi,hWnd,uMsg,wParam,lParam

                 local @stPs:PAINTSTRUCT

                 local @stRect:RECT

                 local @hDc

                 mov   eax,uMsg

;********************************************************************
                 .if      eax ==    WM_PAINT

                          invoke    BeginPaint,hWnd,addr @stPs

                          mov       @hDc,eax

                          invoke    GetClientRect,hWnd,addr @stRect

                          invoke    DrawText,@hDc,addr szText,-1,\

                                   addr @stRect,\

                                   DT_SINGLELINE or DT_CENTER or DT_VCENTER

                          invoke    EndPaint,hWnd,addr @stPs

;********************************************************************
                 .elseif  eax ==    WM_CLOSE

                          invoke    DestroyWindow,hWinMain

                          invoke    PostQuitMessage,NULL

;********************************************************************
                 .else
                          invoke    DefWindowProc,hWnd,uMsg,wParam,lParam

                                   ret

                          .endif
;********************************************************************
                 xor      eax,eax

                 ret
_ProcWinMain     endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_WinMain         proc
                 local    @stWndClass:WNDCLASSEX

                 local    @stMsg:MSG

                 invoke   GetModuleHandle,NULL

                 mov                hInstance,eax

                 invoke   RtlZeroMemory,addr @stWndClass,sizeof @stWndClass

;********************************************************************
; 注册窗口类
;********************************************************************
                 invoke   LoadCursor,0,IDC_ARROW

                 mov      @stWndClass.hCursor,eax

                 push     hInstance

                 pop      @stWndClass.hInstance

                 mov      @stWndClass.cbSize,sizeof WNDCLASSEX

                 mov      @stWndClass.style,CS_HREDRAW or CS_VREDRAW

                 mov      @stWndClass.lpfnWndProc,offset _ProcWinMain

                 mov      @stWndClass.hbrBackground,COLOR_WINDOW + 1

                 mov      @stWndClass.lpszClassName,offset szClassName

                 invoke   RegisterClassEx,addr @stWndClass

;********************************************************************
; 建立并显示窗口
;********************************************************************
                 invoke   CreateWindowEx,WS_EX_CLIENTEDGE,\

                          offset szClassName,offset szCaptionMain,\

                          WS_OVERLAPPEDWINDOW,\

                          100,100,600,400,\

                          NULL,NULL,hInstance,NULL

                 mov      hWinMain,eax

                 invoke   ShowWindow,hWinMain,SW_SHOWNORMAL

                 invoke   UpdateWindow,hWinMain

;********************************************************************
; 消息循环
;********************************************************************
                 .while   TRUE

                          invoke    GetMessage,addr @stMsg,NULL,0,0

                          .break    .if eax  == 0

                          invoke    TranslateMessage,addr @stMsg

                          invoke    DispatchMessage,addr @stMsg

                 .endw

                 ret
_WinMain         endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
                 call     _WinMain

                 invoke   ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                 end      start
2008-4-14 21:27
0
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3

整个架子出来鸟。。
Copy了去添砖添瓦~~
无风。顶死你。。霸王绝顶!!
2008-4-14 21:45
0
雪    币: 205
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
感觉没什么意义啊。如果单纯的只是写注释,我觉的没任何意义。网络上的文章也很多或者老罗的书上已经很详细。。
我觉得你应该把自己的见解表达的多一些,并不是一味的去摘抄,加个注释。。。。
2008-4-15 01:59
0
雪    币: 1852
活跃值: (504)
能力值: (RANK:1010 )
在线值:
发帖
回帖
粉丝
5
可能你觉得没意义,但对楼主来说却非常有益,学习别人的代码真正掌握原理,这才是最重要的。
楼主在学习之后能够与大家分享经验自然就该得到尊重。
至于所写的内容到底如何,我们管理团队自然会给出相应评价。
2008-4-15 09:49
0
雪    币: 212
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
6
不错啊,顶!如果每章每个例子都有人做出注释那就好了!
2008-4-15 13:05
0
雪    币: 290
活跃值: (11)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
7
uses  ebx edi esi

是 在过程中

push ebx
push edi
push esi

....

pop ebx  
pop edi  
pop esi

是嘛??
2008-4-15 13:39
0
雪    币: 271
活跃值: (18)
能力值: ( LV12,RANK:370 )
在线值:
发帖
回帖
粉丝
8
楼上。保存寄存器,防止被破坏...。感觉写的蛮好的。...
2008-4-15 15:19
0
游客
登录 | 注册 方可回帖
返回
//