chinanetboy 11/05/2007
我们用什么工具才能知道windows内核是如何工作,消息是如何处理的呢?
windows的汇编工具MASM32可以让我们非常容易彻底明了WIN32底层工作
窗口程序的核心工作就是3大点,A资源文件的编辑+B窗口的处理主程序+C消息处理程序
MASM32官方下载站点: http://www.masm32.com
在没有使用C++和MFC开发window程序以前,都是用C语言与WIN32的API函数进行编程
在使用C++和MFC开发window之后,由于MFC类库不能完全封装完所有的API函数,以及MFC的类库的复杂性以及MFC大量内置宏,加大了程序员写程序的工作量
一种比C语言更加简洁的汇编语言MASM32+API函数+各种数据结构的开发环境诞生啦
MASM32是微软专门为WINDOWS量身订做的一种高效方便的汇编开发工具
配置和安装MASM32的开发环境
1.从网站下载开发工具,安装到C:或者D:下面的MASM32文件夹中,建议不要改文件夹的名字
2.设置编译环境到windows,用下面的代码建立一个批处理文件为VAR.bat,其中set Masm32Dir=D:/Masm32是指定安装的实际文件夹路径
@echo off
rem 请根据 Masm32 软件包的安装目录修改下面的 Masm32Dir 环境变量!
set Masm32Dir=D:/Masm32
set include=%Masm32Dir%/Include;%include%
set lib=%Masm32Dir%/lib;%lib%
set path=%Masm32Dir%/Bin;%Masm32Dir%;%PATH%
set Masm32Dir=
echo on
3.用编辑器写源文件另存为*.asm,可以从源代码样例中找出测试的代码源文件,也可以用本代码的源代码进行编译和链接
4.编译源文件为*.OBJ ,命令行是ml /c /coff *.asm
5.连接目标*.OBJ文件为*.EXE程序 ,命令行是Link /subsystem:windows *.obj
6.输入得到的*.EXE文件名,可以看到程序的窗口界面
******************************************************************************************************************
下面通过一个完整的代演示一个windows窗口程序的实现过程和工作方式,请把代码另存为win32.asm
实现一个窗口主要由2个程序过程组成
窗口程序的核心工作就是3大点,A资源文件的编辑+B窗口的处理主程序+C消息处理程序
1._Proc()拦截此程序的各种消息,在本代码中只实现窗口重绘消息WM_PAINT和关闭窗口消息WM_CLOSE的处理,其它消息没有处理代码
而GetMessage,sendmessage两个函数都要截到这个窗口的句柄ID,这就是黑客编程最常用的技术
我们在_proc过程对各种消息进行检查,然后指定它们按照作者想要的工作方式进行各种操作,
这就是windows消息处理的核心点
2._WinMain()实现装载资源,填充窗口结构,注册,建立,显示,更新窗口,并进行消息循环
;操作流程是
;1.装载各种资源,如鼠标,图标,菜单,对话框,图片等,本例只装光标资源LoadCursor,0,IDC_ARROW
;2.填充窗口结构数据,各部数据依次填入,指定消息处理的函数为上面_Proc过程,见API的结构WNDCLASSEX
; 见代码mov @stWndClass.lpfnWndProc,offset _Proc
;3.注册窗口结构:把上面定制好的窗口结构在WINDOW注册,见API函数RegisterClassEx
;4.创建窗口:在注册窗口后就应该创建,见API函数CreateWindowEx
;5.显示窗口:在创建成功后显示窗口,见API函数ShowWindow
;6.更新窗口:用WM_PAINT消息不断刷新窗口,见API函数UpdateWindow
; 如消息处函数_Proc没有实现WM_PAINT的处理,则按windows缺省处理,如有处理WM_PAINT的代码,
; 本例已经实现窗口刷新的代码,见.if eax == WM_PAINT,代码段,
; 它在实现在窗口中间的客户区显示文字Win32 Assembly, Simple and powerful!
;7.进入窗口的消息循环
;7.1GetMessage()首先从windows消息对列中取有没有自己的消息,如没有就退出
; 其它程序和窗口也可以用API函数postmessage()发要这个窗口处理的消息到windows消息对列
; 也就是说GetMessage()也可以取得由其它程序用postmessage发给自己的消息
;7.2TranslateMessage()如果有消息则把消息标识进行简化转换,它通常负责键盘和鼠标消息的简化
;7.3DispatchMessage()对消息进行分派处理,把消息处理权转给_Proc这个专用的消息处理函数
;此程序又开始进行下一轮的消息循环
;其它程序可以直接用API函数sendmessage()发消息给这个窗口指定的消息处理函数_proc
以下源代码用EDITPLUS编辑OK,用MASM32工具编译OK,win32.exe在windows XP运行正常
每次重载编译,都得删除以前的*.OBJ文件和*.EXE文件,否则编译和连接不过去
*********************************************************************************************
;source code filename is win32.asm
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Sample code for < Win32ASM Programming >
; win32.asm
; 窗口程序的模板代码
; 使用 nmake 或下列命令进行编译和链接:
; ml /c /coff win32.asm
; Link /subsystem:windows win32.obj
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.386 ;使用CPU386的指指令集
.model flat,stdcall ;函数的参数传递为标准调用,左-右
option casemap:none ;源代码勿略大小写区分
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义,它通常把*.LIB和*.INC包含到此程序中来
; *.inc功能C++的*.H头文件,*.LIB如同C++的DLL,LIB是以C语言实现的API函数做成的静态链接库文件
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include windows.inc ;它包含了大量的windows的宏定义和windows常用的数据结构
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 'win32 Assembly!',0
szText db 'Win32 Assembly, Simple and powerful !',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 窗口过程_Proc(主要实现对消息的处理,在此程序中只处理了WM_PAINT和WM_CLOSE消息,让它在程序的客户区显示文字)
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_Proc proc uses ebx edi esi,hWnd,uMsg,wParam,lParam
local @stPs:PAINTSTRUCT
local @stRect:RECT
local @hDc
mov eax,uMsg
;通过uMsg移入EAX来判断常用消息,uMsg通常包含windows常用消息,wParam,lParam通常包含键盘和鼠标的消息
;********************************************************************
;对WM_PAINT消息进行处理的消息代码段,负责把文件显示在程序的客户区的中央位置
;显示文字是Win32 Assembly, Simple and powerful !
.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
_Proc 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 _Proc
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