前面几篇文章中都没有使用到菜单,对话框等资源,这次就演练如何在应用程序中加入这些资源。我们就以将VC6.0默认生成的Win32程序移植为32位汇编为例。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
首先用VC6.0生成一个默认Win32版的Hello,World程序,将Hello.rc,demo.ico,small.ico都拷贝到项目目录下,去掉VC6.0相关的部分,最后Hello.rc修改如下:
//MicrosoftVisualC++generatedresourcescript.
//
#include"resource.h"

#defineIDR_MAINFRAME128
#defineIDD_DEMO_DIALOG102
#defineIDD_ABOUTBOX103
#defineIDS_APP_TITLE103

#defineIDM_ABOUT104
#defineIDM_EXIT105
#defineIDS_HELLO106
#defineIDI_DEMO107
#defineIDI_SMALL108
#defineIDC_DEMO109

#defineIDC_MYICON2
#defineIDC_STATIC-1

/
//
//Icon
//
//IconwithlowestIDvalueplacedfirsttoensureapplicationicon
//remainsconsistentonallsystems.

IDI_DEMOICONDISCARDABLE"demo.ICO"
IDI_SMALLICONDISCARDABLE"SMALL.ICO"
/
//
//Menu
//
IDC_DEMOMENUDISCARDABLE
BEGIN
POPUP"
&File
"
BEGIN
MENUITEM"E
&xit
",IDM_EXIT
END
POPUP"
&Help
"
BEGIN
MENUITEM"
&About
",IDM_ABOUT
END
END
/
//
//Accelerator
//
IDC_DEMOACCELERATORSMOVEABLEPURE
BEGIN
"?",IDM_ABOUT,ASCII,ALT
"/",IDM_ABOUT,ASCII,ALT
END
/
//
//Dialog
//
IDD_ABOUTBOXDIALOGDISCARDABLE22,17,230,75
STYLEDS_MODALFRAME|WS_CAPTION|WS_SYSMENU
CAPTION"About"
FONT8,"System"
BEGIN
ICONIDI_DEMO,IDC_MYICON,14,9,16,16
LTEXT"HelloApp1.0",IDC_STATIC,49,10,119,8,SS_NOPREFIX
LTEXT"Copyright(C)2008",IDC_STATIC,49,20,119,8
DEFPUSHBUTTON"OK",IDOK,195,6,30,11,WS_GROUP
END

/
//
//StringTable
//

STRINGTABLEDISCARDABLE
BEGIN
IDC_DEMO"DEMO"
IDS_APP_TITLE"demo"
IDS_HELLO"HelloWorld!"
END
/
然后创建一个MakFile文件,内容如下:
NAME
=
Hello
OBJS
=
$(
NAME
).
obj
RES
=
$(
NAME
).
res

$(
NAME
).
exe:
$(
OBJS
)
$(
RES
)
Link
/
SUBSYSTEM
:WINDOWS
$(
OBJS
)
$(
RES
)
$(
RES
)
:
$(
NAME
).
rc
rc
$(
NAME
).
rc
.
asm
.
obj:
ml
/
c
/
coff
$(
NAME
).
asm
最后仿照VC++代码编写汇编代码如下:
.
386
.modelflat,stdcall
option
casemap:
none
;
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;
Include文件定义
;
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>includewindows.inc
includegdi32.
inc
includelibgdi32.lib
includeuser32.
inc
includelibuser32.lib
includekernel32.
inc
includelibkernel32.lib


IDR_MAINFRAMEequ
128
IDD_DEMO_DIALOGequ
102
IDD_ABOUTBOXequ
103
IDS_APP_TITLEequ
103
IDM_ABOUTequ
104
IDM_EXITequ
105
IDS_HELLOequ
106
IDI_DEMOequ
107
IDI_SMALLequ
108
IDC_DEMOequ
109
IDC_MYICONequ
2
IDC_STATICequ-
1

;
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;
数据段
;
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data?
hInstancedd?
;
应用程序句柄
hWinMaindd?
;
窗口句柄
szCaptionMaindb
1024
dup(?)
szTextdb
1024
dup(?)

.const
szClassNamedb
'
MyClass
'
,
0
;
窗口类名称
;
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;
代码段
;
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
;
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;
About对话框处理函数
;
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_Aboutprocusesebxediesi,hDlg,uMsg,wParam,lParam
mov
eax,uMsg
.ifeax==WM_COMMAND
mov
eax,wParam
movzx
eax,ax
.ifeax==IDOK
invokeEndDialog,hDlg,eax
;
invokeMessageBox,NULL,addrszText,addrszCaptionMain,MB_OK
.endif
.elseifeax==WM_INITDIALOG
mov
eax,
1
ret
.endif
xor
eax,eax
;
这句非常重要,清零eax,相当于返回false
ret
_Aboutendp
;
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;
窗口过程
;
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcWinMainprocusesebxediesihWnd,uMsg,wParam,lParam
;
让汇编器保持子程序中使用到的寄存器的正确性
local
@stPs:
PAINTSTRUCT
local
@stRect:
RECT
local@hDc

mov
eax,uMsg
;
*************************************************************
.ifeax==WM_PAINT
invokeBeginPaint,hWnd,addr@stPs
mov
@hDc,eax

invokeGetClientRect,hWnd,addr@stRect
invokeDrawText,@hDc,addrszText,-
1
,/
;
长度设置为-1,表示输出的字符串以'/0'结尾,且由函数自动计算出其长度
addr@stRect,/
DT_SINGLELINE
or
DT_CENTER
or
DT_VCENTER
invokeEndPaint,hWnd,addr@stPs
;
*************************************************************
.elseifeax==WM_COMMAND
mov
eax,wParam
movzx
eax,ax
.ifeax==IDM_EXIT
invokeDestroyWindow,hWinMain
invokePostQuitMessage,NULL
.elseifeax==IDM_ABOUT
invokeDialogBoxParam,hInstance,IDD_ABOUTBOX,hWnd,_About,NULL
.endif

;
*************************************************************
.elseifeax==WM_CLOSE
invokeDestroyWindow,hWinMain
invokePostQuitMessage,NULL
;
*************************************************************
.else
invokeDefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
;
*************************************************************
xor
eax,eax
;
eax寄存器清零
ret

_ProcWinMainendp
;
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;
WinMain函数
;
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_WinMainproc
local
@stWndClass:
WNDCLASSEX
local
@stMsg:
MSG

invokeGetModuleHandle,NULL
;
获取应用程序句柄,这在VC里是通过操作系统传递进来的,但是汇编中需要自己去获取
mov
hInstance,eax
;
获取到的应用程序句柄在eax中
invokeRtlZeroMemory,addr@stWndClass,sizeof@stWndClass
;
清零
;
*************************************************************
;
注册窗口类
;
*************************************************************
invokeLoadCursor,
0
,IDC_ARROW
;
加载光标
mov
@stWndClass.hCursor,eax
invokeLoadIcon,hInstance,offsetIDI_DEMO
mov
@stWndClass.hIcon,eax
invokeLoadString,hInstance,IDS_APP_TITLE,addrszCaptionMain,sizeofszCaptionMain
invokeLoadString,hInstance,IDS_HELLO,addrszText,sizeofszText
push
hInstance
pop
@stWndClass.hInstance
mov
@stWndClass.cbSize,sizeofWNDCLASSEX
mov
@stWndClass.style,CS_HREDRAW
or
CS_VREDRAW

mov
@stWndClass.lpfnWndProc,offset_ProcWinMain
;
设置窗口处理函数
;
invokeGetStockObject,WHITE_BRUSH
;
mov@stWndClass.hbrBackground,eax
mov
@stWndClass.hbrBackground,COLOR_WINDOW+
1
mov
@stWndClass.lpszClassName,offsetszClassName
mov
@stWndClass.lpszMenuName,offsetIDC_DEMO
invokeRegisterClassEx,addr@stWndClass
;
注册窗口类
;
*************************************************************
;
建立并显示窗口
;
*************************************************************
invokeCreateWindowEx,WS_EX_CLIENTEDGE,offsetszClassName,addrszCaptionMain,/
WS_OVERLAPPEDWINDOW,/
100
,
100
,
600
,
400
,/
NULL,NULL,hInstance,NULL
;
创建窗口,发出一个WM_CREATE消息
mov
hWinMain,eax
;
保存窗口句柄
invokeShowWindow,hWinMain,SW_SHOWNORMAL
;
显示窗口
invokeUpdateWindow,hWinMain
;
发出一个WM_PAINT消息
;
*************************************************************
;
第一种消息循环,使用GetMessage,同步的
;
*************************************************************
;
.whileTRUE
;
invokeGetMessage,addr@stMsg,NULL,0,0
;
.break.ifeax==0;stMsg为0,即收到WM_QUIT消息时退出
;
invokeTranslateMessage,addr@stMsg
;
invokeDispatchMessage,addr@stMsg
;
.endw
;
*************************************************************
;
另一种消息循环,使用PeekMessage,异步的
;
*************************************************************
.whileTRUE
invokePeekMessage,addr@stMsg,NULL,
0
,
0
,PM_REMOVE
.ifeax!=
0
.break.if@stMsg.message==WM_QUIT
invokeTranslateMessage,addr@stMsg
invokeDispatchMessage,addr@stMsg
.else
;
空闲时间,可以做其他处理工作
.endif
.endw
ret
_WinMainendp
;
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;
程序入口点
;
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
call
_WinMain
invokeExitProcess,NULL
;
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
endstart
nmake编译后运行如下图:
