前面几篇文章中都没有使用到菜单,对话框等资源,这次就演练如何在应用程序中加入这些资源。我们就以将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修改如下:
//Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define IDR_MAINFRAME 128
#define IDD_DEMO_DIALOG 102
#define IDD_ABOUTBOX 103
#define IDS_APP_TITLE 103
#define IDM_ABOUT 104
#define IDM_EXIT 105
#define IDS_HELLO 106
#define IDI_DEMO 107
#define IDI_SMALL 108
#define IDC_DEMO 109
#define IDC_MYICON 2
#define IDC_STATIC -1
/
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_DEMO ICON DISCARDABLE "demo.ICO"
IDI_SMALL ICON DISCARDABLE "SMALL.ICO"
/
//
// Menu
//
IDC_DEMO MENU DISCARDABLE
BEGIN
POPUP " &File "
BEGIN
MENUITEM "E &xit ", IDM_EXIT
END
POPUP " &Help "
BEGIN
MENUITEM " &About ", IDM_ABOUT
END
END
/
//
// Accelerator
//
IDC_DEMO ACCELERATORS MOVEABLE PURE
BEGIN
"?", IDM_ABOUT, ASCII, ALT
"/", IDM_ABOUT, ASCII, ALT
END
/
//
// Dialog
//
IDD_ABOUTBOX DIALOG DISCARDABLE 22, 17, 230, 75
STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
CAPTION "About"
FONT 8, "System"
BEGIN
ICON IDI_DEMO,IDC_MYICON,14,9,16,16
LTEXT "HelloApp 1.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
/
//
// String Table
//
STRINGTABLE DISCARDABLE
BEGIN
IDC_DEMO "DEMO"
IDS_APP_TITLE "demo"
IDS_HELLO "Hello World!"
END
/
//
#include "resource.h"
#define IDR_MAINFRAME 128
#define IDD_DEMO_DIALOG 102
#define IDD_ABOUTBOX 103
#define IDS_APP_TITLE 103
#define IDM_ABOUT 104
#define IDM_EXIT 105
#define IDS_HELLO 106
#define IDI_DEMO 107
#define IDI_SMALL 108
#define IDC_DEMO 109
#define IDC_MYICON 2
#define IDC_STATIC -1
/
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_DEMO ICON DISCARDABLE "demo.ICO"
IDI_SMALL ICON DISCARDABLE "SMALL.ICO"
/
//
// Menu
//
IDC_DEMO MENU DISCARDABLE
BEGIN
POPUP " &File "
BEGIN
MENUITEM "E &xit ", IDM_EXIT
END
POPUP " &Help "
BEGIN
MENUITEM " &About ", IDM_ABOUT
END
END
/
//
// Accelerator
//
IDC_DEMO ACCELERATORS MOVEABLE PURE
BEGIN
"?", IDM_ABOUT, ASCII, ALT
"/", IDM_ABOUT, ASCII, ALT
END
/
//
// Dialog
//
IDD_ABOUTBOX DIALOG DISCARDABLE 22, 17, 230, 75
STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
CAPTION "About"
FONT 8, "System"
BEGIN
ICON IDI_DEMO,IDC_MYICON,14,9,16,16
LTEXT "HelloApp 1.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
/
//
// String Table
//
STRINGTABLE DISCARDABLE
BEGIN
IDC_DEMO "DEMO"
IDS_APP_TITLE "demo"
IDS_HELLO "Hello World!"
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
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
.model flat,stdcall
option casemap: none
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> include windows.inc
include gdi32. inc
includelib gdi32.lib
include user32. inc
includelib user32.lib
include kernel32. inc
includelib kernel32.lib
IDR_MAINFRAME equ 128
IDD_DEMO_DIALOG equ 102
IDD_ABOUTBOX equ 103
IDS_APP_TITLE equ 103
IDM_ABOUT equ 104
IDM_EXIT equ 105
IDS_HELLO equ 106
IDI_DEMO equ 107
IDI_SMALL equ 108
IDC_DEMO equ 109
IDC_MYICON equ 2
IDC_STATIC equ - 1
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data?
hInstance dd ? ; 应用程序句柄
hWinMain dd ? ; 窗口句柄
szCaptionMain db 1024 dup (?)
szText db 1024 dup (?)
.const
szClassName db ' MyClass ' , 0 ; 窗口类名称
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; About对话框处理函数
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_About proc uses ebx edi esi,hDlg,uMsg,wParam,lParam
mov eax,uMsg
.if eax == WM_COMMAND
mov eax,wParam
movzx eax,ax
.if eax == IDOK
invoke EndDialog,hDlg,eax
; invoke MessageBox,NULL,addr szText,addr szCaptionMain,MB_OK
.endif
.elseif eax == WM_INITDIALOG
mov eax, 1
ret
.endif
xor eax,eax ; 这句非常重要,清零eax,相当于返回false
ret
_About endp
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 窗口过程
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcWinMain proc uses ebx edi esi hWnd,uMsg,wParam,lParam ; 让汇编器保持子程序中使用到的寄存器的正确性
local @stPs: PAINTSTRUCT
local @stRect: RECT
local @hDc
mov eax,uMsg
; *************************************************************
.if eax == WM_PAINT
invoke BeginPaint,hWnd,addr @stPs
mov @hDc,eax
invoke GetClientRect,hWnd,addr @stRect
invoke DrawText,@hDc,addr szText,- 1 ,\ ; 长度设置为-1,表示输出的字符串以'\0'结尾,且由函数自动计算出其长度
addr @stRect,\
DT_SINGLELINE or DT_CENTER or DT_VCENTER
invoke EndPaint,hWnd,addr @stPs
; *************************************************************
.elseif eax == WM_COMMAND
mov eax,wParam
movzx eax,ax
.if eax == IDM_EXIT
invoke DestroyWindow,hWinMain
invoke PostQuitMessage,NULL
.elseif eax == IDM_ABOUT
invoke DialogBoxParam,hInstance,IDD_ABOUTBOX,hWnd,_About,NULL
.endif
; *************************************************************
.elseif eax == WM_CLOSE
invoke DestroyWindow,hWinMain
invoke PostQuitMessage,NULL
; *************************************************************
.else
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
; *************************************************************
xor eax,eax ; eax寄存器清零
ret
_ProcWinMain endp
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; WinMain函数
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_WinMain proc
local @stWndClass: WNDCLASSEX
local @stMsg: MSG
invoke GetModuleHandle,NULL ; 获取应用程序句柄,这在VC里是通过操作系统传递进来的,但是汇编中需要自己去获取
mov hInstance,eax ; 获取到的应用程序句柄在eax中
invoke RtlZeroMemory,addr @stWndClass,sizeof @stWndClass ; 清零
; *************************************************************
; 注册窗口类
; *************************************************************
invoke LoadCursor, 0 ,IDC_ARROW ; 加载光标
mov @stWndClass.hCursor,eax
invoke LoadIcon,hInstance,offset IDI_DEMO
mov @stWndClass.hIcon,eax
invoke LoadString,hInstance,IDS_APP_TITLE,addr szCaptionMain,sizeof szCaptionMain
invoke LoadString,hInstance,IDS_HELLO,addr szText,sizeof szText
push hInstance
pop @stWndClass.hInstance
mov @stWndClass.cbSize,sizeof WNDCLASSEX
mov @stWndClass.style,CS_HREDRAW or CS_VREDRAW
mov @stWndClass.lpfnWndProc,offset _ProcWinMain ; 设置窗口处理函数
; invoke GetStockObject,WHITE_BRUSH
; mov @stWndClass.hbrBackground,eax
mov @stWndClass.hbrBackground,COLOR_WINDOW + 1
mov @stWndClass.lpszClassName,offset szClassName
mov @stWndClass.lpszMenuName,offset IDC_DEMO
invoke RegisterClassEx,addr @stWndClass ; 注册窗口类
; *************************************************************
; 建立并显示窗口
; *************************************************************
invoke CreateWindowEx,WS_EX_CLIENTEDGE,offset szClassName,addr szCaptionMain,\
WS_OVERLAPPEDWINDOW,\
100 , 100 , 600 , 400 ,\
NULL,NULL,hInstance,NULL ; 创建窗口,发出一个WM_CREATE消息
mov hWinMain,eax ; 保存窗口句柄
invoke ShowWindow,hWinMain,SW_SHOWNORMAL ; 显示窗口
invoke UpdateWindow,hWinMain ; 发出一个WM_PAINT消息
; *************************************************************
; 第一种消息循环,使用GetMessage,同步的
; *************************************************************
; .while TRUE
; invoke GetMessage,addr @stMsg,NULL,0,0
; .break .if eax == 0 ;stMsg为0,即收到WM_QUIT消息时退出
; invoke TranslateMessage,addr @stMsg
; invoke DispatchMessage,addr @stMsg
; .endw
; *************************************************************
; 另一种消息循环,使用PeekMessage,异步的
; *************************************************************
.while TRUE
invoke PeekMessage,addr @stMsg,NULL, 0 , 0 ,PM_REMOVE
.if eax != 0
.break .if @stMsg.message == WM_QUIT
invoke TranslateMessage,addr @stMsg
invoke DispatchMessage,addr @stMsg
.else
; 空闲时间,可以做其他处理工作
.endif
.endw
ret
_WinMain endp
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 程序入口点
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
call _WinMain
invoke ExitProcess,NULL
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
end start
.model flat,stdcall
option casemap: none
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> include windows.inc
include gdi32. inc
includelib gdi32.lib
include user32. inc
includelib user32.lib
include kernel32. inc
includelib kernel32.lib
IDR_MAINFRAME equ 128
IDD_DEMO_DIALOG equ 102
IDD_ABOUTBOX equ 103
IDS_APP_TITLE equ 103
IDM_ABOUT equ 104
IDM_EXIT equ 105
IDS_HELLO equ 106
IDI_DEMO equ 107
IDI_SMALL equ 108
IDC_DEMO equ 109
IDC_MYICON equ 2
IDC_STATIC equ - 1
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data?
hInstance dd ? ; 应用程序句柄
hWinMain dd ? ; 窗口句柄
szCaptionMain db 1024 dup (?)
szText db 1024 dup (?)
.const
szClassName db ' MyClass ' , 0 ; 窗口类名称
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; About对话框处理函数
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_About proc uses ebx edi esi,hDlg,uMsg,wParam,lParam
mov eax,uMsg
.if eax == WM_COMMAND
mov eax,wParam
movzx eax,ax
.if eax == IDOK
invoke EndDialog,hDlg,eax
; invoke MessageBox,NULL,addr szText,addr szCaptionMain,MB_OK
.endif
.elseif eax == WM_INITDIALOG
mov eax, 1
ret
.endif
xor eax,eax ; 这句非常重要,清零eax,相当于返回false
ret
_About endp
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 窗口过程
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcWinMain proc uses ebx edi esi hWnd,uMsg,wParam,lParam ; 让汇编器保持子程序中使用到的寄存器的正确性
local @stPs: PAINTSTRUCT
local @stRect: RECT
local @hDc
mov eax,uMsg
; *************************************************************
.if eax == WM_PAINT
invoke BeginPaint,hWnd,addr @stPs
mov @hDc,eax
invoke GetClientRect,hWnd,addr @stRect
invoke DrawText,@hDc,addr szText,- 1 ,\ ; 长度设置为-1,表示输出的字符串以'\0'结尾,且由函数自动计算出其长度
addr @stRect,\
DT_SINGLELINE or DT_CENTER or DT_VCENTER
invoke EndPaint,hWnd,addr @stPs
; *************************************************************
.elseif eax == WM_COMMAND
mov eax,wParam
movzx eax,ax
.if eax == IDM_EXIT
invoke DestroyWindow,hWinMain
invoke PostQuitMessage,NULL
.elseif eax == IDM_ABOUT
invoke DialogBoxParam,hInstance,IDD_ABOUTBOX,hWnd,_About,NULL
.endif
; *************************************************************
.elseif eax == WM_CLOSE
invoke DestroyWindow,hWinMain
invoke PostQuitMessage,NULL
; *************************************************************
.else
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
; *************************************************************
xor eax,eax ; eax寄存器清零
ret
_ProcWinMain endp
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; WinMain函数
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_WinMain proc
local @stWndClass: WNDCLASSEX
local @stMsg: MSG
invoke GetModuleHandle,NULL ; 获取应用程序句柄,这在VC里是通过操作系统传递进来的,但是汇编中需要自己去获取
mov hInstance,eax ; 获取到的应用程序句柄在eax中
invoke RtlZeroMemory,addr @stWndClass,sizeof @stWndClass ; 清零
; *************************************************************
; 注册窗口类
; *************************************************************
invoke LoadCursor, 0 ,IDC_ARROW ; 加载光标
mov @stWndClass.hCursor,eax
invoke LoadIcon,hInstance,offset IDI_DEMO
mov @stWndClass.hIcon,eax
invoke LoadString,hInstance,IDS_APP_TITLE,addr szCaptionMain,sizeof szCaptionMain
invoke LoadString,hInstance,IDS_HELLO,addr szText,sizeof szText
push hInstance
pop @stWndClass.hInstance
mov @stWndClass.cbSize,sizeof WNDCLASSEX
mov @stWndClass.style,CS_HREDRAW or CS_VREDRAW
mov @stWndClass.lpfnWndProc,offset _ProcWinMain ; 设置窗口处理函数
; invoke GetStockObject,WHITE_BRUSH
; mov @stWndClass.hbrBackground,eax
mov @stWndClass.hbrBackground,COLOR_WINDOW + 1
mov @stWndClass.lpszClassName,offset szClassName
mov @stWndClass.lpszMenuName,offset IDC_DEMO
invoke RegisterClassEx,addr @stWndClass ; 注册窗口类
; *************************************************************
; 建立并显示窗口
; *************************************************************
invoke CreateWindowEx,WS_EX_CLIENTEDGE,offset szClassName,addr szCaptionMain,\
WS_OVERLAPPEDWINDOW,\
100 , 100 , 600 , 400 ,\
NULL,NULL,hInstance,NULL ; 创建窗口,发出一个WM_CREATE消息
mov hWinMain,eax ; 保存窗口句柄
invoke ShowWindow,hWinMain,SW_SHOWNORMAL ; 显示窗口
invoke UpdateWindow,hWinMain ; 发出一个WM_PAINT消息
; *************************************************************
; 第一种消息循环,使用GetMessage,同步的
; *************************************************************
; .while TRUE
; invoke GetMessage,addr @stMsg,NULL,0,0
; .break .if eax == 0 ;stMsg为0,即收到WM_QUIT消息时退出
; invoke TranslateMessage,addr @stMsg
; invoke DispatchMessage,addr @stMsg
; .endw
; *************************************************************
; 另一种消息循环,使用PeekMessage,异步的
; *************************************************************
.while TRUE
invoke PeekMessage,addr @stMsg,NULL, 0 , 0 ,PM_REMOVE
.if eax != 0
.break .if @stMsg.message == WM_QUIT
invoke TranslateMessage,addr @stMsg
invoke DispatchMessage,addr @stMsg
.else
; 空闲时间,可以做其他处理工作
.endif
.endw
ret
_WinMain endp
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 程序入口点
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
call _WinMain
invoke ExitProcess,NULL
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
end start
nmake编译后运行如下图: