用Nasm编写Windows窗口

     要用Nasm来创建Windows窗口的话必须要用到Nasm和一个辅助工具Nasmx,该工具提供了对Windows API的支持,Nasmx可以从 http://sourceforge.net/projects/nasmx/ 下载,Nasm从http://www.nasm.us 上下载,其实Nasmx已经包含了Nasm,所以Nasm可以不下载.

 

     在编写基于Windows的窗口之前首先要了解的是Windows的消息机制, 即Windows操作系统是如何处理接收到的消息的:

比如当你按下键盘上或者鼠标的某一个键的时候, 操作系统将捕获这个按键信息, 然后放到应用程序的消息队列中(操作系统会为每个应用程序创建消息队列), 这时应用程序(消息循环 )从消息队列中取出消息, 翻译消息并将消息传递给操作系统, 由操作系统去调用窗口过程(窗口过程是一个回调函数,由操作系统调用) , 由窗口过程进行对消息进行处理.

以下代码创建一个带有按钮,文本框,静态文本和列表框的窗口:

%include "nasmx.inc"
%include "win32/user32.inc"
%include "win32/kernel32.inc"
%include "win32/windows.inc"
%include "win32/gdi32.inc"

%define IDC_BUTTON1    500
%define IDC_EDIT1         501
%define IDC_LIST1          502

entry EntryPoint

[section .bss]
hWnd:         resd 1
hInstance:     resd 1
hButton1:    resd 1
hList1:        resd 1
hEdit1:        resd 1

[section .data]
szButton:           db     "BUTTON",0
szEdit:               db    "EDIT",0
szListBox:          db  "LISTBOX",0
szStatic:            db    "STATIC",0
szClass:             db     "WClass",0
szWndName:     db     "Window",0
szBtnStr:            db    "OK",0
szBtnText1:       db    "Hello...",0
szText1:             db    "File",0

wc:
    istruc WNDCLASSEX
        at WNDCLASSEX.cbSize,                 dd    WNDCLASSEX_size
        at WNDCLASSEX.style,                   dd    CS_VREDRAW + CS_HREDRAW
        at WNDCLASSEX.lpfnWndProc,       dd    NULL
        at WNDCLASSEX.cbClsExtra,          dd    NULL
        at WNDCLASSEX.cbWndExtra,        dd    NULL
        at WNDCLASSEX.hInstance,           dd    NULL
        at WNDCLASSEX.hIcon,                  dd    NULL
        at WNDCLASSEX.hCursor,               dd    NULL
        at WNDCLASSEX.hbrBackground,    dd    COLOR_BTNFACE + 1
        at WNDCLASSEX.lpszMenuName,    dd    NULL
        at WNDCLASSEX.lpszClassName,    dd    NULL
        at WNDCLASSEX.hIconSm,              dd    NULL
    iend
   
message:
    istruc MSG
        at MSG.hwnd,                  dd     NULL
        at MSG.message,               dd     NULL
        at MSG.wParam,                dd     NULL
        at MSG.lParam,                dd     NULL
        at MSG.time,                  dd     NULL
        at MSG.pt,                    dd     NULL
    iend

[section .code]
    proc EntryPoint
        invoke GetModuleHandleA,dword NULL
        mov [hInstance],eax
        invoke WinMain,dword hInstance,dword NULL,dword NULL,dword SW_SHOWNORMAL
        invoke ExitProcess,dword NULL
        ret
    endproc

    proc WinMain
    hInst argd
    hPrevInstance argd
    lpCmdLine argd
    nCmdShow argd
        invoke LoadIconA,dword NULL,dword IDI_APPLICATION
        mov [wc+WNDCLASSEX.hIcon],eax
        mov [wc+WNDCLASSEX.hIconSm],eax
        mov eax,dword szClass
        mov [wc+WNDCLASSEX.lpszClassName],eax
        mov eax,dword WinProc
        mov [wc+WNDCLASSEX.lpfnWndProc],eax
        mov eax,dword argv(hInst)
        mov [wc+WNDCLASSEX.hInstance],eax
        invoke LoadCursorA,dword NULL,dword IDC_ARROW
        mov [wc+WNDCLASSEX.hCursor],eax
        invoke GetStockObject,dword WHITE_BRUSH
        mov [wc+WNDCLASSEX.hbrBackground],eax
       
        invoke RegisterClassExA,dword wc
   
        invoke CreateWindowExA,dword NULL,dword szClass,dword szWndName,dword WS_CAPTION|WS_SYSMENU|WS_VISIBLE,dword 300,dword 100,dword 600,dword 600,dword NULL,dword NULL,dword argv(hInst),dword NULL
        mov [hWnd],eax
        invoke ShowWindow,dword hWnd,dword argv(nCmdShow)
        invoke UpdateWindow,dword hWnd
        ;消息循环
        .msgloop:
            invoke GetMessageA,dword message,dword NULL,dword NULL,dword NULL
            cmp eax,dword 0
            je .exit
            invoke TranslateMessage,dword message
            invoke DispatchMessageA,dword message
            jmp .msgloop
        .exit:
            mov eax,dword [message+MSG.wParam]
            ret
    endproc
    ;窗口过程
    proc WinProc
    hwnd argd  
    uMsg argd
    wParam argd
    lParam argd
    .wm_create:
        cmp argv(uMsg),dword WM_CREATE
        jnz .wm_command
        ;创建按钮
        invoke CreateWindowExA,dword NULL,dword szButton,dword szBtnStr,dword BS_DEFPUSHBUTTON|WS_CHILD|WS_VISIBLE,dword 250,dword 10,dword 100,dword 20,dword argv(hwnd),dword IDC_BUTTON1,dword hInstance,dword NULL
        mov [hButton1],eax
        ;创建文本框
        invoke CreateWindowExA,dword NULL,dword szEdit,dword NULL,dword ES_LEFT|WS_CHILD|WS_BORDER|WS_VISIBLE,dword 10,dword 10,dword 200,dword 20,dword argv(hwnd),dword IDC_EDIT1,dword hInstance,dword NULL
        mov [hEdit1],eax
        ;创建列表框
        invoke CreateWindowExA,dword NULL,dword szListBox,dword NULL,dword WS_CHILD|WS_BORDER|WS_VISIBLE,dword 300,dword 50,dword 200,dword 200,dword argv(hwnd),dword IDC_LIST1,dword hInstance,dword NULL
        mov [hList1],eax
        ;创建静态文本
        invoke CreateWindowExA,dword NULL,dword szStatic,dword szText1,dword SS_CENTER|WS_CHILD|WS_VISIBLE,dword 10,dword 50,dword 100,dword 20,dword argv(hwnd),dword 600,dword hInstance,dword NULL
        jmp .default

        ;处理单击按钮消息
    .wm_command:
        cmp argv(uMsg),dword WM_COMMAND
        jnz .wm_destroy
        mov edx,dword argv(lParam)    ;等价于(HWND)lParam==hButton
        cmp edx,dword [hButton1]
        jnz .wm_destroy
        mov ebx,dword wParam
        shr ebx,16
        and ebx,0000ffffh
        cmp ebx,dword BN_CLICKED    ;等价于HIWORD(wParam)==BN_CLICKED
        jnz .wm_destroy
        invoke MessageBoxA,dword NULL,dword szBtnText1,dword szBtnText1,dword MB_OK
       
        jmp .default
    .wm_destroy:
        cmp argv(uMsg),dword WM_DESTROY
        jnz .default
        invoke PostQuitMessage,dword 0
    .default:
        invoke DefWindowProcA,dword argv(hwnd),dword argv(uMsg),dword argv(wParam),dword argv(lParam)
    .exit:
        ret
    endproc

编译方法:

到X:/Nasm安装目录 /inc/下将win32文件夹和nasmx.inc拷贝到nasm的目录下(即nasm.exe,ndisasm.exe所在目录),将X:/Nasm安装目录 /bin/下的GoLink.exe也拷贝到nasm的目录下,GoLink.exe是链接器. 如果nasm的路径已配置到环境变量Path中,假定上述代码的文件名为window.asm,路径为X:/window.asm,则在cmd中运行命令:

nasm -f win32 window.asm     @rem 该命令产生一个目标对象window.obj

golink /entry _main window.obj user32.dll kernel32.dll gdi32.dll  @rem 该命令产生一个win32程序 /entry指明了程序的入口点,不过这里的入口点为_main而不是WinMain是因为编译程序对符号进行了处理,将WinMain的导出名编程了_main,这个和dll类似.加上user32.dll是因为使用了MessageBox函数,后面kernel32.dll和gdi32.dll一样,有些函数后面要加上A是因为那些函数是用ANSI编码来实现的,还有一个W的版本,W的版本是基于Unicode实现的,可以在MSDN中查看所用到的函数是否有ANSI和Unicode版本.(PS:以上代码在nasm2.09能编译成功,nasm2.10下有所区别:istruc处为NASMX_ISTRUC,而且声明的proc在使用前必须进行函数原型声明或者放到调用过程之前,argv必须包含在[]中,总之觉得2.10的变化挺多的.)


代码解释 : %define处定义了按钮,文本框和列表框的ID. entry处表示程序入口点为名为EntryPoint的过程,该过程调用过程WinMain,其实此处可以直接写WinMain也一样. 下面来看[section],Nasm中可以用section来指明一个段(数据区是何种类型的段(数据区),.bss是为初始化数据区,里面的数据都是没有经过初始化的;.data为初始化数据区;.code为代码段,写成.text作用和.code一样..data段中的istruc定义了一个 WNDCLASSEX的实例, WNDCLASSEX已在Nasmx自带的windows.inc中用struc声明,所以我们只要创建一个实例就可以(注意: WNDCLASSEX中 每个属性的顺序必须和用struc声明的 WNDCLASSEX 中的顺序一致,不然编译出错...),紧接着的MSG和 WNDCLASSEX一样. 下面进入代码段:过程WinMain首先创建了窗口,窗口的创建过程分为四个步骤:定义窗口类->创建窗口->注册窗口->显示窗口,最后其实还有一步就是更新窗口,这个过程和C++创建窗口一样,这里不再敖述. 接下来看.msgloop,这就是消息循环,负责总应用程序的消息队列中取消息并转发给操作系统,由操作系统去调用窗口过程进行处理. 在这里WinProc为窗口过程,带有四个参数,argd前面的为参数名,而argd本身说明了参数类型为dword类型,要在过程中使用参数,必须用argv(param),param为argd之前的参数名.

 

其实我比较喜欢Nasm,感觉比较干净, 语法也比较简洁,而且能编译出纯机器码,尤其适合写操作系统代码 ,相比之下MASM32比较臃肿,不过Nasmx对Windows API的支持没有MASM32全面,比如 和ListView相关函数没有提供支持,后来看了一下nasmx中的inc文件,自己加了import也没用,不足之处还是有的. 呵呵,闲着无聊,写着玩的...

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值