Win32汇编学习(9):窗口控件
这次我们将探讨控件,这些控件是我们程序主要的输入输出设备。
理论:
WINDOWS 提供了几个预定义的窗口类以方便我们的使用。大多数时间内,我们把它们用在对话框中,所以我们一般就它们叫做子窗口控件。子窗口控件会自己处理消息,并在自己状态发生改变时通知父窗口。这样就大大地减轻了我们的编程工作,所以我们应尽可能地利用它们。本课中我们把这些控件放在窗口中以简化程序,但是大多数时间内子窗口控件都是放在对话框中的。我们示例中演示的子窗口控件包括:按钮、下拉菜单、检查框、单选按钮、编辑框等。使用子窗口控件时,先调用CreateWindow 或 CreateWindowEx。在这里由于WINDOWS 已经注册了这些子控件,所以无须我们再注册。当然我们不能改变它们的类名称。譬如:如果您想产生一个按钮,在调用上述两个函数时就必须指定类名为"button"。其他必须指定的参数还有父窗口的句柄和将要产生的子控件的ID号。子控件的ID号是用来标识子控件的,故也必须是唯一 的。子控件产生后,当其状态改变时将会向父窗口发送消息。一般我们应在父窗口的WM_CREATE消息中产生子控件。子控件向父窗口发送的消息是WM_COMMAND,并在传递的参数wPara的低位中包括控件的ID号,消息号在wParam的高位,lParam中则包括了子控件的窗口的句柄。各类控件有不同的消息代码集,详情请参见WIN32 API参考手册。父窗口也可以通过调用函数SendMessage向子控件发送消息,其中第一个参数是子控件的窗口句柄,第二个参数是要发送的消息号,附加的参数可以在wParam和lParam中传递,其实只要知道了某个窗口的句柄就可以用该函数向其发送相关消息。所以产生了子窗口后必须处理WM_COMMAND消息以便可以接收到子控件的消息。
例子:
我们将写一个窗口,在该窗口中有一个编辑框和一个按钮。当您按下按钮时 ,会弹出一个对话框其中显示了您在编辑框中输入的内容。另外,该应用程序还有一个菜单,其中有四个菜单项:
Say Hello-- 把一个字符串输入编辑控件;Clear Edit Box-- 清除编辑控件中的字符串;Get Text-- 弹出对话框显示编辑控件中的字符串;Exit-- 退出应用程序。
.386
.model flat,stdcall
option casemap:none
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
.data
ClassName db "SimpleWinClass",0
AppName db "Our First Window",0
MenuName db "FirstMenu",0
ButtonClassName db "button",0
ButtonText db "My First Button",0
EditClassName db "edit",0
TestString db "Wow! I'm in an edit box now",0
.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hwndButton HWND ?
hwndEdit HWND ?
buffer db 512 dup(?) ; buffer to store the text retrieved from the edit box
.const
ButtonID equ 1 ; The control ID of the button control
EditID equ 2 ; The control ID of the edit control
IDM_HELLO equ 1
IDM_CLEAR equ 2
IDM_GETTEXT equ 3
IDM_EXIT equ 4
.code
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke GetCommandLine
mov CommandLine,eax
invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
invoke ExitProcess,eax
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
LOCAL hwnd:HWND
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInst
pop wc.hInstance
mov wc.hbrBackground,COLOR_BTNFACE+1
mov wc.lpszMenuName,OFFSET MenuName
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc
invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName, \
ADDR AppName, WS_OVERLAPPEDWINDOW,\
CW_USEDEFAULT, CW_USEDEFAULT,\
300,200,NULL,NULL, hInst,NULL
mov hwnd,eax
invoke ShowWindow, hwnd,SW_SHOWNORMAL
invoke UpdateWindow, hwnd
.WHILE TRUE
invoke GetMessage, ADDR msg,NULL,0,0
.BREAK .IF (!eax)
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
.ENDW
mov eax,msg.wParam
ret
WinMain endp
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
.IF uMsg==WM_DESTROY
invoke PostQuitMessage,NULL
.ELSEIF uMsg==WM_CREATE
invoke CreateWindowEx,WS_EX_CLIENTEDGE, ADDR EditClassName,NULL,\
WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or\
ES_AUTOHSCROLL,\
50,35,200,25,hWnd,8,hInstance,NULL
mov hwndEdit,eax
invoke SetFocus, hwndEdit
invoke CreateWindowEx,NULL, ADDR ButtonClassName,ADDR ButtonText,\
WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON,\
75,70,140,25,hWnd,ButtonID,hInstance,NULL
mov hwndButton,eax
.ELSEIF uMsg==WM_COMMAND
mov eax,wParam
.IF lParam==0
.IF ax==IDM_HELLO
invoke SetWindowText,hwndEdit,ADDR TestString
.ELSEIF ax==IDM_CLEAR
invoke SetWindowText,hwndEdit,NULL
.ELSEIF ax==IDM_GETTEXT
invoke GetWindowText,hwndEdit,ADDR buffer,512
invoke MessageBox,NULL,ADDR buffer,ADDR AppName,MB_OK
.ELSE
invoke DestroyWindow,hWnd
.ENDIF
.ELSE
.IF ax==ButtonID
shr eax,16
.IF ax==BN_CLICKED
invoke SendMessage,hWnd,WM_COMMAND,IDM_GETTEXT,0
.ENDIF
.ENDIF
.ENDIF
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret
WndProc endp
end start
menu.rc
#define IDM_HELLO 1
#define IDM_CLEAR 2
#define IDM_GETTEXT 3
#define IDM_EXIT 4
SecondMenu MENU
{
POPUP "&PopUp"
{
MENUITEM "&Say Hello",IDM_HELLO
MENUITEM "&Clear", IDM_CLEAR
MENUITEM SEPARATOR
MENUITEM "E&xit",IDM_EXIT
}
MENUITEM "&Text",IDM_GETTEXT
}
分析:
我们现在开始分析,
.ELSEIF uMsg==WM_CREATE
invoke CreateWindowEx,WS_EX_CLIENTEDGE, \
ADDR EditClassName,NULL,\
WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT\
or ES_AUTOHSCROLL,\
50,35,200,25,hWnd,EditID,hInstance,NULL
mov hwndEdit,eax
invoke SetFocus, hwndEdit
invoke CreateWindowEx,NULL, ADDR ButtonClassName,\
ADDR ButtonText,\
WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON,\
75,70,140,25,hWnd,ButtonID,hInstance,NULL
mov hwndButton,eax
我们在WM_CREATE中产生子控件,其中在函数CreateWindowEx中给子控件窗口一个WS_EX_CLIENTEDGE风格,它使得子控件窗口看上去边界下凹,具有立体感。每一个子控件的类名都是预定义的,譬如:按钮的预定义类名是"button",编辑框是"edit"。接下来的参数是窗口风格,除了通常的窗口风格外,每一个控件都有自己的扩展风格,譬如:按钮类的扩展风格前面加有BS_,编辑框类则是:ES_,WIN32 API 参考中有所有的扩展风格的描述。注意:您在CreateWindowsEx函数中本来要传递菜单句柄的地方传入子窗口空间的ID号不会有什么副作用,因为子窗口控件本身不能有菜单。产生控件后,我们保存它们的句柄,然后调用SetFocus把焦点设到编辑控件上以便用户立即可以输入。接下来的是如何处理控件发送的通知消息WM_COMMAND:
.ELSEIF uMsg==WM_COMMAND
mov eax,wParam
.IF lParam==0
我们以前讲过选择菜单项也会发送WM_COMMAND消息,那我们应如何区分呢?看了下表您就会一目了然:
/---------+--------------------+--------------------+---------------------\
| | Low word of wParam |High word of wParam | lParam |
+---------+--------------------+--------------------+---------------------+
| Menu | Menu ID | 0 | 0 |
+---------+ -------------------+--------------------+---------------------+
| Control | Control ID | Notification code | Child Window Handle |
\---------+--------------------+--------------------+---------------------/
其中我们可以看到不能用wParam来区分,因为菜单和控件的ID号可能相同,而且子窗口空间的消息号也有可能为0。
.IF ax==IDM_HELLO
invoke SetWindowText,hwndEdit,ADDR TestString
.ELSEIF ax==IDM_CLEAR
invoke SetWindowText,hwndEdit,NULL
.ELSEIF ax==IDM_GETTEXT
invoke GetWindowText,hwndEdit,ADDR buffer,512
invoke MessageBox,NULL,ADDR buffer,ADDR AppName,MB_OK
您可以调用SetWindowText函数把一字符串复制到编辑控件中去,为了清空,传入NULL值。SetWindowText是一个通用函数,即可以用它来设定一个窗口的标题,也可以用它来改变一个按钮上的文字。如果是要得到按钮上的文字,则调用GetWindowText。
.IF ax==ButtonID
shr eax,16
.IF ax==BN_CLICKED
invoke SendMessage,hWnd,WM_COMMAND,IDM_GETTEXT,0
.ENDIF
.ENDIF
上面的片段是处理用户按钮事件的。他首先检查wParam的高字节看是否是按钮的ID 号,若是则检查低字节看发送的消息号是否BN_CLICKED,该消息是在按钮按下时发送的,如果一切都对,则转入处理该消息,我们可以从处理消息IDM_GETTEXT处复制全部的代码,但是更专业的办法是在发送一条IDM_GETTEXT消息让主窗口过程处理,这只要把传送的消息设置为WM_COMMAND,再把wParam的低字节中设置为IDM_GETTEXT即可。这样一来您的代码就简洁了许多,所以尽可能利用该技巧。最后,当然不是或有或无,必须在消息循环中调用函数TranslateMessage,因为您的应用程序需要在编辑框中输入可读的文字。如果省略了该函数,就不能在编辑框中输入任何东西。
Win32汇编学习(9):窗口控件的更多相关文章
- PyQt5学习--基本窗口控件--QMainWindow
QMainWindow主窗口为用户提供一个应用程序框架,它有自己的布局,可以在布局中添加控件.比如将工具栏.菜单栏和状态栏等添加到布局管理器中. 窗口类型介绍 QMainWindow.QWidget和 ...
- Win32汇编学习(10):对话框(1)
现在我们开始学习一些有关GUI编程的有趣的部分:以对话框为主要界面的应用程序. 理论: 如果您仔细关注过前一个程序就会发现:您无法按TAB键从一个子窗口控件跳到另一个子窗口控件,要想转移的话只有 用鼠 ...
- Win32汇编学习(4):绘制文本
这次,我们将学习如何在窗口的客户区"绘制"字符串.我们还将学习关于"设备环境"的概念. 理论: "绘制"字符串 Windows 中的文本是一 ...
- Swift学习之熟悉控件
最近是比较清闲一些的,对于一个开发者来说,这也是一个很好的充电机会.以前做项目都是使用Objective-C去开发,但我们都知道,Swift语言从2014年的出现到现在,一步一步变的完善,渐渐变的受欢 ...
- Delphi 查找标题已知的窗口句柄,遍历窗口控件句柄(转)
用我的方法来控制其他程序窗体上的窗口控件,必须先了解什么是 回调函数.我的理解是这样的: 回 调函数写出来不是自己的程序去调用的,反而是让其他的东西去调用,比如windows操作系统,比如其他的程序等 ...
- asp.net学习之Repeater控件
asp.net学习之Repeater控件 文章摘自:http://www.cnblogs.com/shipfi/archive/2009/10/19/1585703.html Repeater控件和D ...
- [转载]ExtJs4 笔记(9) Ext.Panel 面板控件、 Ext.window.Window 窗口控件、 Ext.container.Viewport 布局控件
作者:李盼(Lipan)出处:[Lipan] (http://www.cnblogs.com/lipan/)版权声明:本文的版权归作者与博客园共有.转载时须注明本文的详细链接,否则作者将保留追究其法律 ...
- 使用DataGridView数据窗口控件,构建用户快速输入体验
在"随风飘散" 博客里面,介绍了一个不错的DataGridView数据窗口控件<DataGridView数据窗口控件开发方法及其源码提供下载>,这种控件在有些场合下,还 ...
- Win32 SDK程序创建一些控件(简单调用InitCommonControlsEx,并指定ICC_LISTVIEW_CLASSES控件就可以了)
在Win32 SDK中创建一些控件的时候需要注意一下(具体是哪些控件请参看MSDN文档中列出来的) /* MSDN:Carries information used to load common co ...
随机推荐
- mybatis07--关联查询一对多
案例 查询国家的同时,查询出国家下的省会信息! 01.使用单表的连接查询 创建对应的实体类 和数据库表 /** * *国家的实体类 */ public class Country { privat ...
- HTML <script> 标签的 defer 和 async 属性
HTMKL <script>标签中有defer和async属性,简单介绍一下两者的区别吧. 普通的script标签会让浏览器立即下载并执行完毕,执行也是按照先后顺序,再进行后面的解析. ...
- windows环境下Oracle数据库冷备份和恢复
1.点击开始菜单的“运行”,输入sqlplus/nolog 2.在弹出的命令行窗口以sysdba身份登陆,要输入:系统用户名/登陆密码@数据库实例名,如sys/testora@orcl 3.输入 al ...
- ubuntu下安装php扩展
参考原文地址:http://www.php.cn/php-weizijiaocheng-341528.html 发现在mac上好像不太行,然后按照下面的可以,写下来与大家分享 利用ubuntu的软件包 ...
- Python学习之旅(二十)
Python基础知识(19):面向对象高级编程(Ⅱ) 定制类 形如“__xx__”的变量或函数在Python中是有特殊用途的 1.__str__ 让打印出来的结果更好看 __str__:面向用户:__ ...
- 个人小爱好:Operating System:three easy pieces---第6章第4节_担心并发问题?
担心并发问题? 微妙,上下文切换大约6微妙.而,现在的系统有着级数级别的提升,在2-3GHz的处理起中消耗只有亚微妙级. 但应该注意到,不是所有的系统性能都跟着CPU性能的提升而提升,根据Ouster ...
- linux --mariadb/redis数据库篇
mariadb ---磁盘型数据库 基础安装 配置好yum源后,软件就可以通过配置的yum源进行安装,按理来讲安装mysql直接通过 yum install mariadb -y 便可安装,但 ...
- MySql查看与修改auto_increment方法(转)
add by zhj: 在创建表时,如果没有显式的指定AUTO_INCREMENT的值,那它默认是1 原文:https://blog.csdn.net/fdipzone/article/detail ...
- JDK 1.8 JVM的变化
前言: 1.什么是JVM JVM的全称是 Java Virtual Machine(Java虚拟机),它通过模拟一个计算机来达到一个计算机所具有的功能. Java和实体计算机一样也必须有一套合适的指令 ...
- WIN7无法访问共享打印机及文件的解决办法
故障: 在网上邻居上能看到对方的电脑名字,双击进入的时候弹出问题.出现“用户账户限制”或“未授予用户在计算机上的请求登陆类型”的问题,这说明我们的局域网和网络是畅通的,问题的根源就在电脑的安全设置上. ...