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

📄 用masmplus学习win32汇编(3) .txt

📁 会变语言实现的一些程序
💻 TXT
字号:
用MasmPlus学习Win32汇编(3) 
    作者:Zoologist 于2007-10-15上传   

--------------------------------------------------------------------------------
更改"开始"按钮




   ;#Mode=CON
   .386
   .model flat, stdcall
   option casemap :none

   include windows.inc
   include user32.inc
   include kernel32.inc
   include masm32.inc

   includelib user32.lib
   includelib kernel32.lib
   includelib masm32.lib
   include macro.asm

   .data?
      Handle1   dd   ?
      Handle2   dd ?
      buffer   db 100 dup(?)
   .CODE
   START: 
     ;get the handle of the taskbar
      invoke FindWindow,CTEXT('Shell_TrayWnd'),NULL         
      mov    Handle1,eax
     ;get the handle of the start button from the taskbar
      invoke FindWindowEx,Handle1,0,CTEXT('Button'),NULL   
      mov     Handle2,eax
     ;set the text
      invoke SetWindowText,Handle2,CTEXT('Z..T')
     ;used to refresh the caption of the start button
      invoke SendMessage,Handle2,WM_MOUSEMOVE,0,0    
   运行之后
      ;暂停显示,回车键关闭
      invoke StdIn,addr buffer,sizeof buffer
      invoke ExitProcess,0   
   end START


运行之后,就变为:




下面对程序进行简单的分析:

;查找任务栏的handle

   invoke FindWindow,CTEXT('Shell_TrayWnd'),NULL         
    mov    Handle1,eax


;开始键是任务栏上的button,取得它的handle

   invoke FindWindowEx,Handle1,0,CTEXT('Button'),NULL 
     mov     Handle2,eax


;替换掉原来的文字

   invoke SetWindowText,Handle2,CTEXT('Z..T')      


;这个地方,我们给button发一个消息,假装鼠标从上面经过,重新绘制新的文字
;就会显示出来

   invoke SendMessage,Handle2,WM_MOUSEMOVE,0,0    



从这个程序我们进行一下推广:
    1.如果去掉最后一句,我们用鼠标滑过 button 字迹也会出现,可以试试看哦~
    2.文字被改动之后,什么情况下会恢复为原来的呢?不妨自己手动试试看~
   3. invoke FindWindow,CTEXT('Shell_TrayWnd'),NULL
      其中的Shell_TrayWnd 是 Class name。不必关心这个是怎么来的,如果我告诉你xp中的"计算器"的 
      Class name是SciCalc,可否试验一下如何修改它的标题呢?

   

   4. invoke SendMessage,Handle2,WM_MOUSEMOVE,0,0 是发送"消息",我们可以
      试试看发送一个"点击"的消息,WM_LBUTTONDOWN。运行之后,开始
      菜单会自动弹出来的哦~


继续控制台

   上一次我们介绍了 Console 程序,不过我们仍然是沿用DOS下的编写方法,下面我们要开始学习Windows中的消息。如下代码是我从 Iczelion的win32汇编教程中"抄袭"过来的,原本是使用在GUI下面的。
   
   .WHILE TRUE
            invoke GetMessage, ADDR msg,NULL,0,0
            .BREAK .IF (!eax)
            invoke TranslateMessage, ADDR msg 
            invoke DispatchMessage, ADDR msg
   .ENDW 
   

   这时候我们的窗口已显示在屏幕上了。但是它还不能从外界接收消息。所以我们必须给它提供相关的消息。我们是通过一个消息循环来完成该项工作的。每一个模块仅有一个消息循环,我们不断地调用 GetMessage 从 Windows 中获得消息。GetMessage 传递一个 MSG 结构体给 Windows ,然后 Windows 在该函数中填充有关的消息,一直到 Windows 找到并填充好消息后 GetMessage 才会返回。在这段时间内系统控制权可能会转移给其他的应用程序。这样就构成了Win16 下的多任务结构。如果 GetMessage 接收到 WM_QUIT 消息后就会返回 FALSE,使循环结束并退出应用程序。TranslateMessage 函数是一个是实用函数,它从键盘接受原始按键消息,然后解释成 WM_CHAR,在把 WM_CHAR 放入消息队列,由于经过解释后的消息中含有按键的 ASCII 码,这比原始的扫描码好理解得多。如果您的应用程序不处理按键消息的话,可以不调用该函数。DispatchMessage 会把消息发送给负责该窗口过程的函数。

   形象一点的说法就是我们用GetMessage送msg这样一张小纸条给Windows,等他批阅之后我再拿回来看看。如果返回的是要退出,那我就主动的"自我了断"。


定时器

   很多时候,我们需要"每隔" XX秒来做一件事情,比如我通常每隔一天检查一次信箱,或者上班时每隔几个小时站起来找个mm聊天。在DOS下或者说面向过程的时候我们通常这样写:

   
   开始计时
   Repeat
      工作;
   Until (计时器到点了);
   计时结束
   

   不过这样的写法很明显是非常浪费的,我们不得不每隔一段时间检查一下计时器,老师们肯定会因为学生经常看表而大发雷霆,在约会时不断看表是赶走他人的最好方法。
   
   最好的方法是到了时间有人来叫你,就好比中午我趴着睡觉的时候有人叫我"上班都半个小时了,快点起来~"也或者是突然之间觉得自己肚子饿了,大脑收到肚子饿这个消息,转而执行"觅食"的动作。
   
   下面介绍的是Windows中的一种定时器
   
   UINT_PTR SetTimer(     //创建一个定时器
         HWND hWnd,  // 所在线程的handler,如果这个值为Null而下面nIDEvent
                    这个参数不为0,表示替换nIDEvent这个定时器
         UINT_PTR nIDEvent,// 定时器ID,多个定时器时,可以通过该ID判断是
                          哪个定时器
         UINT uElapse,      // 时间间隔,单位为毫秒
         TIMERPROC lpTimerFunc   // 回调函数
              );


   BOOL KillTimer(           //释放一个定时器
          HWND hWnd,            //释放handle线程的定时器
      UINT_PTR uIDEvent    //释放编号为 uIDEvent 的定时器
          );
   

   上面2个API通常要配对使用,有创建就要有释放。来也匆匆去也冲冲才是好同志。

   下面我们就要具体使用一下了,我们先实验一个简单的:

   在控制台下,每隔200毫秒输出一个字符"."。


   ;#Mode=CON

   .586P
   .MODEL Flat,StdCall
   OPTION CASEMAP:NONE

   INCLUDE     WINDOWS.INC
   INCLUDE     KERNEL32.INC
   INCLUDE     USER32.INC
   INCLUDELIB  KERNEL32.LIB
   INCLUDELIB  USER32.LIB
   include       macro.asm
   include       masm32.inc
   includelib    masm32.lib

   .DATA

   Counter     db  20
   lpMsg       MSG <>             
   TimerID     dd  ?              
   buffer   db 100 dup(?)
      
   .CODE

   TimerProc   proc 
      invoke wsprintf,offset buffer,CTXT("."),NULL
      invoke StdOut, offset buffer
        dec Counter                          ;计数减1
        jnz NoKill                           ;到0了没
        invoke  KillTimer, NULL, TimerID      ;释放定时器
        invoke  PostQuitMessage,NULL
   NoKill:   
         ret                
   TimerProc   endp

   Start:
   ;200ms一次,触发 TimerProc
     invoke  SetTimer, NULL, 0, 200, addr TimerProc   
     mov TimerID,eax                        ;存一下,释放的时候还要用
     
     .WHILE TRUE
         invoke GetMessage, ADDR lpMsg,NULL,0,0
         .BREAK .IF (!eax)
         invoke TranslateMessage, ADDR lpMsg 
         invoke DispatchMessage, ADDR lpMsg
      .ENDW         

      invoke  ExitProcess, NULL
   END     Start



给笔记本做一个自动存盘功能

   我们平时使用的word有自动存盘的功能(特别是一边调试程序一边用word写文章的时候千万要记得打开…否则不知道什么时候就欲哭无泪了) Windows自带的NotePad没有这个功能。下面就让我们做一个能让它自动存盘的程序。

   程序的基本思想是:使用FindWindow API取得NotePad的handle,然后使用sendmessage功能给它发 WM_COMMAND消息。


   ;#Mode=CON

   .586P
   .MODEL Flat,StdCall
   OPTION CASEMAP:NONE

   INCLUDE     WINDOWS.INC
   INCLUDE     KERNEL32.INC
   INCLUDE     USER32.INC
   INCLUDELIB  KERNEL32.LIB
   INCLUDELIB  USER32.LIB
   include       macro.asm
   include       masm32.inc
   includelib    masm32.lib

   .DATA

   lpMsg       MSG <>             
   TimerID     dd  ?              
   iCount      dd    0
   buffer      db 100 dup(?)
   .CODE

   TimerProc   proc
        invoke   FindWindow,CTEXT('Notepad'),NULL
        .if (EAX==0)
          invoke wsprintf,offset buffer,CTEXT("%d 没有找到笔记本程序",10,13),iCount      
             invoke StdOut, offset buffer
             inc   iCount
             ret
         .endif
         invoke SendMessage,EAX,WM_COMMAND,3,0
        invoke wsprintf,offset buffer,CTEXT("存盘一次",13,10),NULL
         invoke StdOut, offset buffer      
         ret                
   TimerProc   endp

   Start:
     invoke  SetTimer, NULL, 0, 1000, addr TimerProc   ;200ms一次,触发 TimerProc
     mov TimerID,eax   ;存一下,释放的时候还要用
     
     .WHILE TRUE
         invoke GetMessage, ADDR lpMsg,NULL,0,0
         .BREAK .IF (!eax)
         invoke TranslateMessage, ADDR lpMsg 
         invoke DispatchMessage, ADDR lpMsg
      .ENDW         
      
      invoke  KillTimer, NULL, TimerID      ;释放定时器
      
      ;暂停显示,回车键关闭
      invoke StdIn,addr buffer,sizeof buffer
      invoke ExitProcess,0
      
   END     Start


   

   上面的程序很简单,我就不做更多的解释了,至于为什么我们知道发送

   WM_COMMAND消息,且听下回分解。在下一期中,我们会介绍一些工具的使用。

参考:

   中文SetTimer这个API函数 

   1.   http://blog.csdn.net/junhua198310/archive/2007/07/22/1702173.aspx

   2. 英文 MSDN 上关于Timer的专题介绍
      http://msdn2.microsoft.com/en-us/library/ms632592.aspx

   3.软件网络 2005年6月28日 《记事本也会自动存盘》 吉林 空乐

   

--------------------------------------------------------------------------------
<<<上一篇  欢迎访问AoGo汇编小站:http://www.aogosoft.com 下一篇>>>  

⌨️ 快捷键说明

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