ITEEDU

用汇编编 Windows 程序

概述:

用汇编编制一般的 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