用汇编编制一般的 Windows 程序需要的不是汇编编程的资料,而是 Windows 函数调用的资料,你分析一下下面的源程序就会发现,程序的结构跟用
BC++ 编 Windows 程序几乎一模一样,原来用 C++ 函数的地方,变成了一个 Call 外部子程序,而函数的参数是由 PUSH 指令先压入堆栈,先由最后一个参数压起。同样,用汇编编
Windows 程序也需要 .DEF 文件和 .RES 文件,这是由 Windows 程序的结构决定的。本文是一个最简单的 Windows 程序,仅仅开了一个窗口,说一句话:"Hello,
Windows 95!",这个声音文件是我从别的地方拷来的,你可以把它换成其他声音文件。
用于编译的工具请到软件下载中找,本文要用到的是 Tasm.exe,Tlink.exe,Make.exe 和库文件
Import32.lib。
源程序:
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