概述:
用汇编编制一般的 Windows 程序需要的不是汇编编程的资料,而是 Windows 函数调用的资料,你分析一下下面的源程序就会发现,程序的结构跟用 BC++ 编 Windows 程序几乎一模一样,原来用 C++ 函数的地方,变成了一个 Call 外部子程序,而函数的参数是由 PUSH 指令先压入堆栈,先由最后一个参数压起。同样,用汇编编 Windows 程序也需要 .DEF 文件和 .RES 文件,这是由 Windows 程序的结构决定的。本文是一个最简单的 Windows 程序,仅仅开了一个窗口,说一句话:"Hello, Windows 95!",这个声音文件是我从别的地方拷来的,你可以把它换成其他声音文件。
用于编译的工具请到软件下载中找,本文要用到的是 Tasm.exe,Tlink.exe,Make.exe 和库文件 Import32.lib。这儿是源程序和编译好的可执行文件的压缩档:Hellowin.zip
源程序:
文件 Makefile 的内容,这个文件是给 Make.exe 用的,告诉它用什么库文件,什么 .RES 文件等等:
NAME = hellowin
OBJS = $(NAME).obj
DEF = $(NAME).def
RES = $(NAME).res
IMPORT=IMPORT32
$(NAME).EXE: $(OBJS) $(DEF)
tlink32 /Tpe /aa /c $(LINKDEBUG) $(OBJS),,, $(IMPORT), $(DEF),
.asm.obj:
tasm32 /ml /m2 $&.asm,,,
文件 Hellowin.def 的内容,同编 C++ 程序一样,定义了数据段,代码段的属性等内容:
NAME HELLOWIN
DESCRIPTION '(C) Copyright by Lyb'
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE MULTIPLE
EXETYPE WINDOWS
HEAPSIZE 8192
STACKSIZE 8192
EXPORTS WndProc
HelloWin 的源程序:
.486p
.model flat,STDCALL
include windows.inc ;外部子程序,常量的定义等
;**************************************************
.data
msg MSGSTRUCT <?> ;消息
wndclass WNDCLASS <?> ;Windows 类
ptstr PAINTSTRUCT <?> ;用于屏幕刷新的句柄
rect RECT <?> ;
h_dc dd ? ;DC 句柄,用于屏幕刷新的句柄
h_inst dd ? ;handle of module
h_win dd ? ;handle of window
d_class db "hello win",0
t_title db "Hello, windows 95 !",0
t_copy db 'A copy of program is already running, continue ? ',0
paint_x dd ?
paint_y dd ?
wav_filename db 'hellowin.wav',0
;**************************************************
.code
start:
push 0
call GetModuleHandle ;取模块句柄
mov h_inst,eax
find_class:
push 0
push offset d_class
call FindWindow ;查找有无程序副本在运行
or eax,eax
jz register_class
push MB_YESNO or MB_ICONQUESTION
push offset t_title
push offset t_copy
push 0
call MessageBox ;显示一个对话框
cmp eax,IDNO
jz end_loop
register_class:
push IDC_ARROW
push 0
call LoadCursor ;装入光标
mov wndclass.clsHCursor,eax
mov wndclass.clsStyle,CS_HREDRAW or CS_VREDRAW
mov wndclass.clsLpfnWndProc,offset WndProc
mov wndclass.clsCbClsExtra,0
mov wndclass.clsCbWndExtra,0
mov eax,h_inst
mov wndclass.clsHInstance,eax
mov wndclass.clsHIcon,0
mov wndclass.clsHbrBackground,COLOR_WINDOW+1
mov wndclass.clsLpszMenuName,0
mov wndclass.clsLpszClassName,offset d_class
push offset wndclass
call RegisterClass ;注册窗口类
; create new window
push 0
push h_inst
push 0
push 0
push CW_USEDEFAULT
push CW_USEDEFAULT
push CW_USEDEFAULT
push CW_USEDEFAULT
mov eax,WS_OVERLAPPEDWINDOW or WS_MINIMIZE
push eax
push offset t_title
push offset d_class
push 0
call CreateWindowEx ;创建一个窗口
mov h_win,eax
; show new window
push SW_SHOWNORMAL
; push SW_SHOWMINNOACTIVE ;show in task bar
push h_win
call ShowWindow ;显示窗口
push h_win
call UpdateWindow ;刷新窗口
msg_loop:
push 0
push 0
push 0
push offset msg
call GetMessage ;取消息循环
cmp ax,0
jz end_loop
push offset msg
call TranslateMessage ;把消息传给 WndProc 子程序
push offset msg
call DispatchMessage
jmp msg_loop
end_loop:
push msg.msWPARAM
call ExitProcess
;********************************************************************
; WndProc
;消息处理程序
;********************************************************************
WndProc proc uses ebx edi esi,hwnd:DWORD,wmsg:DWORD,wparam:DWORD,lparam:DWORD
LOCAL theDC:DWORD
;注意,以上的结构是固定的,因为 Windows 自己回先把 EBX,EDI,ESI 压入 STACK
mov eax,wmsg
cmp eax,WM_CREATE ;判断消息类型并执行响应程序
jz wm_create
cmp eax,WM_DESTROY
jz wm_destroy
cmp eax,WM_PAINT
jz wm_paint
push lparam ;return with default windows proc
push wparam
push wmsg
push hwnd
call DefWindowProc
ret
wm_create:
push 20000h or 1 ;snd_filename | snd_async
push 0
push offset wav_filename
call PlaySound
xor eax,eax
ret
wm_paint:
push offset ptstr
push hwnd
call BeginPaint
mov h_dc,eax
push offset rect
push hwnd
call GetClientRect
push 20h or 1 or 4 ;dt_singleline | dt_enter | DT_VCENTEr
push offset rect
push -1
push offset t_title
push h_dc
call DrawText
push offset ptstr
push hwnd
call EndPaint
xor eax,eax
ret
wm_destroy:
push 0
call PostQuitMessage
xor eax,eax
ret
WndProc endp
public WndProc
ends
end start