📄 用masmplus学习win32汇编(3) .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 + -