[32位汇编系列]004 - 对话框资源的使用(1)

来源:互联网 发布:手机管理路由器软件 编辑:程序博客网 时间:2024/04/28 09:51

如果自己用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"><!-- google_ad_client = "pub-8062742131839416";/* 728x90, created 7/12/09 */google_ad_slot = "4877331128";google_ad_width = 728;google_ad_height = 90;// --></script><script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script>

原创粉丝点击