如果自己用CreateWindow来创建窗口的话, 虽然也可以, 但是搞起来太麻烦, 其实在汇编里面, 一样可以像VC一样使用资源, 今天, 我们就使用资源来创建一个对话框。
先不说那么多, 照旧先上代码:
; FileName: Dialog.asm
; Function: A Division Example That Uses Dialog And Resource
; Author : thinker
; Compile & Link :
; ml /c /coff Dialog.asm
; rc Dialog.rc
; link /subsystem:windows Dialog.obj Dialog.res
.386
.model flat, stdcall
option casemap:none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
IDD_MAIN EQU 101
IDC_EDIT_DIVIDEND EQU 1000
IDC_EDIT_DIVISOR EQU 1001
IDC_EDIT_QUOTIENT EQU 1002
IDC_EDIT_REMAINDER EQU 1003
.data?
hInstance dd ?
.code
_ProcDlgMain proc hWnd, uMsg, wParam, lParam
mov eax, uMsg
.if eax == WM_COMMAND
mov eax, wParam
.if ax == IDOK
invoke GetDlgItemInt, hWnd, IDC_EDIT_DIVIDEND, NULL, FALSE
push eax
invoke GetDlgItemInt, hWnd, IDC_EDIT_DIVISOR, NULL, FALSE
mov ecx, eax
xor edx, edx
pop eax
.if ecx
div ecx
push eax
invoke SetDlgItemInt, hWnd, IDC_EDIT_REMAINDER, edx, FALSE
pop eax
invoke SetDlgItemInt, hWnd, IDC_EDIT_QUOTIENT, eax, FALSE
.endif
.elseif ax == IDCANCEL
invoke EndDialog, hWnd, NULL
.endif
.elseif eax == WM_INITDIALOG
invoke GetDlgItem, hWnd, IDC_EDIT_DIVIDEND
invoke SetFocus, eax
mov eax, FALSE
ret
.elseif eax == WM_CLOSE
invoke EndDialog, hWnd, NULL
.else
mov eax, FALSE
ret
.endif
mov eax, TRUE
ret
_ProcDlgMain endp
start:
invoke GetModuleHandle, NULL
mov hInstance, eax
invoke DialogBoxParam, hInstance, IDD_MAIN, NULL, offset _ProcDlgMain, NULL
invoke ExitProcess, 0
end start
资源文件:
// Dialog.rc
// rc Dialog.rc
#include <resource.h>
#define IDD_MAIN 101
#define IDC_EDIT_DIVIDEND 1000
#define IDC_EDIT_DIVISOR 1001
#define IDC_EDIT_QUOTIENT 1002
#define IDC_EDIT_REMAINDER 1003
IDD_MAIN DIALOG DISCARDABLE 0, 0, 207, 55
STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Division Example"
FONT 8, "Verdana"
BEGIN
DEFPUSHBUTTON "Compute",IDOK,33,34,50,14
PUSHBUTTON "Quit",IDCANCEL,126,34,50,14
EDITTEXT IDC_EDIT_DIVIDEND,9,15,40,14,ES_AUTOHSCROLL
EDITTEXT IDC_EDIT_DIVISOR,60,15,40,14,ES_AUTOHSCROLL
EDITTEXT IDC_EDIT_QUOTIENT,112,15,40,14,ES_AUTOHSCROLL | ES_READONLY
EDITTEXT IDC_EDIT_REMAINDER,159,15,40,14,ES_AUTOHSCROLL | ES_READONLY
CTEXT "/",IDC_STATIC,50,18,9,8
CTEXT "=",IDC_STATIC,102,18,8,8
LTEXT "dividend",IDC_STATIC,7,2,38,8
LTEXT "divisor",IDC_STATIC,59,2,38,8
LTEXT "quotient",IDC_STATIC,112,2,38,8
LTEXT "remainder",IDC_STATIC,159,2,38,8
END
程序运行效果如下:
这是一个简单除法计算程序, 将2个32位无符号整数相除, 得到商和余数。
为了简单起见,程序没有对输入做检查。
对于资源文件, 直接用VC编辑器编辑就可以了, 然后去掉VC添加的多余的一些语句
做成如上的形式。 想了解资源文件的详细信息, 可以查看相关的文档。
资源文件的编译方式是:
rc Dialog.rc
如果没有语法错误, 将生成Dialog.res文件
具体编译方式, 可以参考程序上面的注释。
使用了资源之后, 你会发现程序设计变得简单起来:
start: 标签开始出仍然是程序的入口点
invoke GetModuleHandle, NULL
mov hInstance, eax
invoke DialogBoxParam, hInstance, IDD_MAIN, NULL, offset _ProcDlgMain, NULL
invoke ExitProcess, 0
程序首先调用GetModuleHandle传入NULL参数获取当前模块句柄, 并且保存在全局变量hInstance中
接着调用DialogBoxParam显示一个对话框, 这个对话框内部有消息循环, 不需要我们来写消息循环
只需要通过回调函数处理我们感兴趣的消息就可以了, 该函数的原型如下:
INT_PTR DialogBoxParam(
HINSTANCE hInstance, // handle to module
LPCTSTR lpTemplateName, // dialog box template
HWND hWndParent, // handle to owner window
DLGPROC lpDialogFunc, // dialog box procedure
LPARAM dwInitParam // initialization value
);
hInstance 就是模块句柄
lpTemplateName 就是对话框模板, 这里填入对话框资源ID就可以了
hWndParent 父窗口, 这里没有,填NULL
lpDialogFunc 窗口过程, 这个是我们特别要处理的
dwInitParam 窗口过程的 lParam 参数
在窗口过程中, 主要处理三个消息:WM_COMMAND, WM_INITDIALOG, WM_CLOSE
对于WM_INITDIALOG:
invoke GetDlgItem, hWnd, IDC_EDIT_DIVIDEND
invoke SetFocus, eax
mov eax, FALSE
ret
首先通过GetDlgItem获取被除数文本框的句柄
然后用SetFocus函数设置焦点, 让程序运行起来之后, 焦点自动放在被除数文本框中
程序必须用mov eax, FLASE 以及ret返回, 否则设置焦点无效
对于WM_CLOSE:
很简单, 调用EndDialog结束对话框
对于WM_COMMAND:
该消息的消息参数 wParam 的高16位是通知码, 低16位是控件ID
lParam是控件的句柄
这里, 我们对wParam低16位进行判断
如果是IDCANCEL则结束对话框
如果是IDOK, 则获取除法的参数, 进行计算:
invoke GetDlgItemInt, hWnd, IDC_EDIT_DIVIDEND, NULL, FALSE
获取被除数
push eax
保存被除数
invoke GetDlgItemInt, hWnd, IDC_EDIT_DIVISOR, NULL, FALSE
获取除数
mov ecx, eax
除数送入ecx
xor edx, edx
被除数的高32位清0
pop eax
得到被除数低32位
.if ecx // 如果除数不为0
div ecx // 进行除法运算
push eax // 保存商
invoke SetDlgItemInt, hWnd, IDC_EDIT_REMAINDER, edx, FALSE
显示得到的余数
pop eax
invoke SetDlgItemInt, hWnd, IDC_EDIT_QUOTIENT, eax, FALSE
显示商
.endif
对于32位无符号除法运算, 被除数保存在 edx:eax中, 是64位的, 高32为保存在edx中, 低32位保存eax中
得到的结果: 商保存在eax中, 余数保存在edx中
需要特别注意的是, SetDlgItemInt函数会在内部改变ecx, edx, eax的值, 所以, 必须先把得到的商或者余数
保存起来, 否则后面显示结果就不对了。
整个程序比较简单, 对于反汇编的分析, 将在下篇文章 中进行。
<script type="text/javascript"> </script> <script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script>