创建窗口
.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 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; 数据段 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> .data? hInstance dd ? hWinMain dd ? .const szClassName db ‘MyClass‘,0 szCaptionMain db ‘My first Window !‘,0 szText db ‘Win32 Assembly, Simple and powerful !‘,0 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; 代码段 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> .code ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; 窗口过程 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> _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, addr @stRect, DT_SINGLELINE or DT_CENTER or DT_VCENTER invoke EndPaint,hWnd,addr @stPs ;******************************************************************** .elseif eax == WM_CLOSE invoke DestroyWindow,hWinMain invoke PostQuitMessage,NULL ;******************************************************************** .else invoke DefWindowProc,hWnd,uMsg,wParam,lParam ret .endif ;******************************************************************** xor eax,eax ret _ProcWinMain endp ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> _WinMain proc local @stWndClass:WNDCLASSEX local @stMsg:MSG invoke GetModuleHandle,NULL mov hInstance,eax invoke RtlZeroMemory,addr @stWndClass,sizeof @stWndClass ;******************************************************************** ; 注册窗口类 ;******************************************************************** invoke LoadCursor,0,IDC_ARROW mov @stWndClass.hCursor,eax push hInstance pop @stWndClass.hInstance mov @stWndClass.cbSize,sizeof WNDCLASSEX mov @stWndClass.style,CS_HREDRAW or CS_VREDRAW mov @stWndClass.lpfnWndProc,offset _ProcWinMain mov @stWndClass.hbrBackground,COLOR_WINDOW + 1 mov @stWndClass.lpszClassName,offset szClassName invoke RegisterClassEx,addr @stWndClass ;******************************************************************** ; 建立并显示窗口 ;******************************************************************** invoke CreateWindowEx,WS_EX_CLIENTEDGE, offset szClassName,offset szCaptionMain, WS_OVERLAPPEDWINDOW, 100,100,600,400, NULL,NULL,hInstance,NULL mov hWinMain,eax invoke ShowWindow,hWinMain,SW_SHOWNORMAL invoke UpdateWindow,hWinMain ;******************************************************************** ; 消息循环 ;******************************************************************** .while TRUE invoke GetMessage,addr @stMsg,NULL,0,0 .break .if eax == 0 invoke TranslateMessage,addr @stMsg invoke DispatchMessage,addr @stMsg .endw ret _WinMain endp ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> start: call _WinMain invoke ExitProcess,NULL ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> end start
前面是顺序下来的几个API:
GetModuleHandle → RtlZeroMemory → LoadCursor → RegisterClassEx
→ CreateWindowEx → ShowWindow → UpdateWindow
调用模块
如果使用参数NULL调用GetModuleHandle,那么得到的是调用者本模块的句柄
invoke GetModuleHandle,NULL
mov hInstance,eax
ChildWindowFromPoint来获得编辑子窗口的句柄。
锁定了最后的目标即记事本中的编辑子窗口后,程序用PostMessage向它发送消息,根据字符串的长度,用一个循环每次发送一个WM_CHAR消息,WM_CHAR消息的wParam和lParam的含义是:
wParam = chCharCode // wParam是键值
lParam = lKeyData // lParam是键数据(重复次数)
程序中用mov eax,al将键值扩展到参数所需的32位,当做wParam参数发送,lParam为1,表示键的重复次数为1次,
模态对话框
.386 .model flat, stdcall option casemap :none ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; Include 文件定义 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> include windows.inc include user32.inc includelib user32.lib include kernel32.inc includelib kernel32.lib ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; Equ 等值定义 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ICO_MAIN equ 1000h ;图标 DLG_MAIN equ 1 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; 数据段 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> .data? hInstance dd ? ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; 代码段 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> .code _ProcDlgMain proc uses ebx edi esi hWnd,wMsg,wParam,lParam mov eax,wMsg .if eax == WM_CLOSE invoke EndDialog,hWnd,NULL .elseif eax == WM_INITDIALOG invoke LoadIcon,hInstance,ICO_MAIN invoke SendMessage,hWnd,WM_SETICON,ICON_BIG,eax .elseif eax == WM_COMMAND mov eax,wParam .if ax == IDOK invoke EndDialog,hWnd,NULL .endif .else mov eax,FALSE ret .endif mov eax,TRUE ret _ProcDlgMain endp ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> start: invoke GetModuleHandle,NULL mov hInstance,eax invoke DialogBoxParam,hInstance,DLG_MAIN, NULL,offset _ProcDlgMain,NULL invoke ExitProcess,NULL ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> end start
创建模态对话框的函数是DialogBoxParam,它的使用方法是:
invoke DialogBoxParam,hInstance,lpTemplateName,hWndParent,\
lpDialogFunc,dwInitParam
要结束模态对话框,必须在对话框过程的WM_CLOSE消息中使用EndDialog函数:
invoke EndDialog,hDlg,dwResult
非模态对话框
创建非模态对话框的函数是CreateDialogParam,它的参数定义和DialogBoxParam一模一样:
invoke CreateDialogParam,hInstance,lpTemplateName,hWndParent,\
lpDialogFunc,dwInitParam
mov hDlg,eax
区别
非模态对话框模板的风格是否定义WS_VISIBLE决定了是否显示对话框窗口。如果定义了则显示,没有的话,则程序需要在以后自行调用ShowWindow来显示它;而DialogBoxParam函数不管是否定义了WS_VISIBLE风格都会显示对话框。
● CreateDialogParam在建立对话框窗口后直接返回,返回值是对话框窗口的句柄;而DialogBoxParam要在对话框关闭后才返回,返回值是EndDialog中的dwResult参数。
● 在CreateDialogParam返回后,应用程序在自己的消息循环中获取对话框消息,所以如果要用非模态对话框做程序的主窗口,消息循环的代码还是要写的;而DialogBoxParam是使用Windows为它内建的消息循环。
● 关闭非模态对话框使用DestroyWindow函数,注意在这里不要用EndDialog函数。
对话框过程和窗口过程的输入参数是一样的,也是:
DialogProc proc hwndDlg,uMsg,wParam,lParam
_ProcDlgMain proc uses ebx edi esi hWnd,wMsg,wParam,lParam mov eax,wMsg .if eax == WM_CLOSE ;模态对话框用EndDialog关闭 ;非模态对话框用DestroyWindow关闭 .elseif eax == WM_INITDIALOG ;初始化代码 .elseif eax == WM_COMMAND ;子窗口控件发送的消息 ;wParam的低16位为子窗口控件ID .elseif eax == WM_XXXX ;处理其他需要处理的消息 .else mov eax,FALSE ret .endif mov eax,TRUE ret _ProcDlgMain endp
对话框过程和普通的窗口过程在使用上有以下区别:
窗口过程对应于不同的消息有各种不同含义的返回值,而对话框过程返回BOOL类型的值,返回TRUE表示已经处理了某条消息,返回FALSE表示没有处理。“对话框管理器”代码会根据返回值决定是否继续处理某一条消息(惟一的例外是WM_INITDIALOG消息)。
● 对于不处理的消息,不需要调用DefWindowProc来处理,这事情由“对话框管理器”来做。
“对话框管理器”不会把WM_CREATE消息转发给对话框过程,取而代之,它会以WM_INITDIALOG消息来调用对话框过程,程序可以在这里进行一些初始化的操作,WM_INITDIALOG消息的返回值有点特殊,如果程序想自行设置输入焦点,那么可以用SetFocus函数把输入焦点设置到需要的子窗口控件上,然后返回FALSE;如果返回TRUE的话,那么Windows会自动将输入焦点设置到第一个有WS_TABSTOP的子窗口控件上。
对话框过程在WM_COMMAND消息中处理子窗口控件发送的命令,当用户在对话框中按下了按钮,输入文字或选择复选框等操作时,子窗口控件会向对话框过程发送WM_COMMAND消息,wParam是子窗口控件的ID,如例子程序中处理“退出”按钮的消息,在里面用EndDialog函数关闭对话框。
对话框窗口的标题栏上默认没有定义图标,如果要像普通窗口一样显示一个图标,那么可以像例子程序中那样,在WM_INITDIALOG中用WM_SETICON消息来设置。
子窗口句柄
有一个函数可以从ID中获取子窗口句柄:
invoke GetDlgItem,hDlg,dwIDDlgItem
mov hDlgItem,eax
函数的输入参数是对话框句柄和ID值,返回值是子窗口句柄;反过来,有两种方法可以从子窗口句柄获取ID:
(1) invoke GetDlgCtrlID,hWndCtrl ;输入子窗口句柄,返回值是控件ID
(2) invoke GetWindowLong,hWndCtrl,GWL_ID
当需要向控件发送消息的时候,当然可以先用GetDlgItem获取子窗口句柄再用SendMessage函数,但有一个函数更为简便:
invoke SendDlgItemMessage,hDlg,dwIDDlgItem,Msg,wParam,lParam
这个函数可以直接向控件发送消息,只需要在参数中指定对话框句柄和子窗口ID(注意:并没有PostDlgItemMessage这样的函数!)。
下一焦点位置
如果要想知道在一个控件上按下了Tab键或Shift+Tab键会跳到哪一个控件上去,也就是说下一个或上一个Tab停留位在哪里,可以使用GetNextDlgTabItem函数:
invoke GetNextDlgTabItem,hDlg,hCtl,bPrevious
.if eax
mov hWinNext,eax
.endif
其中的bPrevious参数指定了搜索的方向;与之相似,使用GetNextDlgGroupItem 函数可以返回下一个分组的位置:
invoke GetNextDlgGroupItem,hDlg,hCtl,bPrevious
.if eax
mov hWinNext,eax
.endif
查看一个单选钮或复选框是否被选中可以用下面的函数来检测:
invoke IsDlgButtonChecked,hDlg,nIDButton
函数的返回值可能是BST_CHECKED(选中状态),BST_INDETERMINATE(3态复选框的灰化状态)或BST_UNCHECKED(未选中状态)。也可以用向子窗口控件发送BM_GETCHECK消息的方法来检测,返回值和上面的函数是一样的。
如果想设置单选钮或复选框的状态,可以使用下面的语句:
invoke CheckDlgButton,hDlg,nIDButton,uCheck
参数uCheck用BST_CHECKED,BST_INDETERMINATE或BST_UNCHECKED来表示需要设置的状态,含义同上。向控件发送BM_SETCHECK消息也可以取得同样的效果,这时消息的wParam中放置需要设置的状态。
针对单选钮有一个专用函数:
invoke CheckRadioButton,hDlg,\
nIDFirstButton,nIDLastButton,nIDCheckButton
这个函数把ID在nIDFirstButton和nIDLastButton之间的单选钮全部设置为非选中状态,只有nIDCheckButton是选中状态,当然在使用中要注意将这一批ID定义为连续的数值。
如果还嫌CheckRadioButton有点麻烦,还有一种最简单的办法——使用自动单选钮,同组的AUTORADIOBUTTON会随着用户选中一个而自动清除其他单选钮的状态,所以在程序中只需要在初始化的时候预设一次,其他时间就可以不必关心设置问题了,以后惟一用到的就是调用IsDlgButtonChecked检查状态了。
对于文本框,文本长度超过边界的时候默认是自动换行的,但如果同时指定SS_SIMPLE风格的话,就不会自动换行。读者可以在程序中用SetWindowText或发送WM_SETTEXT消息来动态改变显示的文本,同样,也可以用GetWindowText或发送WM_GETTEXT消息来获取其中的文本。
要获取编辑框中的文本有多种方法,可以用GetWindowText,也可以用发送WM_GETTEXT消息的办法,要设置文本,同样可以用SetWindowText或发送WM_SETTEXT,但最简便的办法还是使用下面的函数:
invoke GetDlgItemText,hDlg,nIDDlgItem,lpString,nMaxCount ;取文本
invoke SetDlgItemText,hDlg,nIDDlgItem,lpString ;设置文本
在实际使用中,经常要在文本编辑控件中输入输出数值型参数,将文本转换为数值比较麻烦,把数值转换为文本也要经过一个wsprintf调用,为了简化操作,Windows提供了两个函数来处理这个问题:
invoke SetDlgItemInt,hDlg,nIDDlgItem,uValue,bSigned ;取控件中的数值
invoke GetDlgItemInt,hDlg,nIDDlgItem,lpTranslated,bSigned ;设置控件中的数值
使用文本编辑控件的时候,文本的长度也是个需要注意的问题。如果控件的宽度定义得过窄,当字符填充到最右边的时候,编辑框就不允许继续输入了,为了继续输入并让文本自动卷动,可以指定WS_HSCROLL风格;反之,定义WS_HSCROLL风格后输入文本的长度不受限制又不好,那么可以用向控件发送EM_LIMITTEXT消息的方法来设定最大长度。下面的例子将IDC_EDIT的输入最大长度定为10个字符:
invoke SendDlgItemMessage,hDlg,IDC_EDIT,EM_LIMITTEXT,10,NULL
另外,有时候可能需要把编辑框设置为只读的(和灰化不同,灰化的编辑框中文本无法进行任何操作,包括卷动操作,而只读的仅仅是不能修改),要把初始状态定义为只读的,只需在定义语句中加上ES_READONLY风格,在程序中需要动态改变只读状态可以发送EM_SETREADONLY消息,下面的第一句把编辑框设为只读,第二句把编辑框改回到可写状态:
invoke SendDlgItemMessage,hDlg,IDC_EDIT,EM_SETREADONLY,TRUE,NULL ;只读
invoke SendDlgItemMessage,hDlg,IDC_EDIT,EM_SETREADONLY,FALSE,NULL ;可写
文本编辑框在默认状态下是单行的,也可以通过加上ES_MULTILINE风格变成多行的,这时可以同时加上WS_VSCROLL风格显示一个垂直方向的滚动条。
滚动条有水平和垂直两种,默认的SCROLLBAR语句定义的是水平的滚动条,它的默认风格是SBS_HORZ,例子程序中用下面的语句定义了一个水平滚动条:
SCROLLBAR IDC_SCROLL, 6, 118, 125, 10
如果要定义垂直的滚动条,那么要指明SBS_VERT风格:
SCROLLBAR IDC_SCROLL, x, y, 宽度, 高度,SBS_VERT
和其他子窗口控件发送WM_COMMAND消息不同,水平滚动条向对话框窗口发送WM_HSCROLL消息,而垂直滚动条则发送WM_VSCROLL消息,所以针对两种方式的滚动条要分别处理不同的消息。
WM_xSCROLL消息的参数如下所示:
wParam的低16位= nScrollCode ;动作码
wParam的高16位= nPos ;滚动条当前位置
lParam = hwndScrollBar ;滚动条控件的窗口句柄
其中nScrollCode代表了滚动条的当前动作,定义值及其含义如下:
● SB_BOTTOM 滚动条移到了最下/右边。
● SB_ENDSCROLL 用户停止了滚动动作。
● SB_THUMBPOSITION 滚动条被拖动到某处。
● SB_THUMBTRACK 滚动条在拖动中。
● SB_TOP 滚动条移到了最上/左边。
● SB_LINELEFT 滚动条左移了一格(对于水平滚动条)。
● SB_LINERIGHT 滚动条右移了一格(对于水平滚动条)。
● SB_PAGELEFT 滚动条左移了一页(对于水平滚动条)。
● SB_PAGERIGHT 滚动条右移了一页(对于水平滚动条)。
● SB_LINEDOWN 滚动条下移了一格(对于垂直滚动条)。
● SB_LINEUP 滚动条上移了一格(对于垂直滚动条)。
● SB_PAGEDOWN 滚动条下移了一页(对于垂直滚动条)。
● SB_PAGEUP 滚动条上移了一页(对于垂直滚动条)。
nPos的值只有当动作码是SB_THUMBPOSITION或SB_THUMBTRACK时才有效,其他的时候为0,图5.7示出了鼠标点击滚动条各处时对应的nScrollCode。
当计算好新位置的时候要将位置设置回去,用户才会看到滚动条移动了,方法是向滚动条发送SBM_SETPOS消息:
invoke SendDlgItemMessage,hWnd,IDC_SCROLL,SBM_SETPOS,dwPos,TRUE
最后一个参数为TRUE表示设置后重新绘画滚动条。
在初始化的时候,要给滚动条发送SBM_SETRANGE消息来设定滚动范围:
invoke SendDlgItemMessage,hWnd,IDC_SCROLL,SBM_SETRANGE,最小值,最大值
如果需要获取滚动条的信息,可以尝试发送下面两个消息:SBM_GETPOS可以获取滚动条的当前位置,也就是上一次用SBM_SETPOS设置的值;SBM_GETRANGE可以获取滚动的范围,也就是用SBM_SETRANGE设置的值。
使用组合框
顾名思义,组合框是一个“组合”起来的东西,它由一个可供选择的列表和一个可供输入的edit类组合而成。组合框让用户既可以自己输入文本,也可以选择列表中的某一项当做输入。用不同的风格定义可以产生3种类型的组合框,如图5.8所示。左边的是CBS_SIMPLE风格的组合框,它的上面可以输入文本,下面的列表可供选择预设文本;中间的是CBS_DROPDOWN风格的组合框,上面同样可以输入文本,但下面的列表是下拉式的,平时处于收起状态,点击编辑框右边的三角形才会拉下来;右边的是CBS_DROPDOWNLIST风格的组合框,它仅是一个下拉的选择框,上面的框中不允许输入文字。
组合框中还有几种常用的、可以附加的风格:
● CBS_AUTOHSCROLL 输入过长的文本时输入框自动卷动。
● CBS_LOWERCASE 自动将所有的文本转换成小写。
● CBS_SORT 自动将插入的文本项排序。
● CBS_UPPERCASE 自动将所有的文本转换成大写。
组合框中列表框部分的文字添加、项目的选择等操作都是通过发送消息来完成的,主要的消息如表5.5所示。
表5.5 组合框的消息
消 息 |
Wparam |
lParam |
说 明 |
CB_ADDSTRING |
0 |
字符串地址 |
把一个字符串添加到列表中 |
CB_INSERTSTRING |
位置索引 |
字符串地址 |
把一个字符串插入到列表中 |
CB_FINDSTRING |
开始查找的位置索引 |
查找的字符串 |
在列表中查找以lParam字符串开头的项,找到则返回位置索引,未找到则返回CB_ERR |
CB_FINDSTRINGEXACT |
位置索引 |
查找的字符串 |
精确查找字符串 |
CB_DELETESTRING |
位置索引 |
0 |
删除一个列表项 |
CB_RESETCONTENT |
0 |
0 |
删除所有的列表项 |
消 息 |
Wparam |
lParam |
说 明 |
CB_GETLBTEXT |
位置索引 |
缓冲区地址 |
获取指定列表项的字符串,缓冲区必须足够大 |
CB_GETLBTEXTLEN |
位置索引 |
0 |
获取指定列表项的字符串长度 |
CB_GETCOUNT |
0 |
0 |
获取列表项的总项数 |
CB_SETCURSEL |
位置索引 |
0 |
选中一个列表项,并将列表项中的文字拷贝到编辑控件中 |
CB_SELECTSTRING |
开始查找的位置索引 |
字符串地址 |
查找以lParam指定的字符串开始的列表项,如果找到则选中它并将字符串拷贝到编辑控件中 |
CB_GETCURSEL |
0 |
0 |
获取当前选中的位置索引,没有选中的项目则返回CB_ERR |
CB_SHOWDROPDOWN |
状态 |
0 |
打开(状态为TRUE)或收起(状态为FALSE)下拉列表 |
CB_GETDROPPEDSTATE |
0 |
0 |
检测列表的当前下拉状态,返回TRUE表示拉下,FALSE表示收起 |
当用户在组合框中进行选择操作时,Windows向对话框过程发送WM_COMMAND消息,消息中wParam参数的低16位是组合框ID,高16位是通知码,用来表示用户的操作,通知码的定义如表
表5.6 用户操作组合框后的通知码
通 知 码 |
说 明 |
CBN_SELCHANGE |
用户将要选择一个项目(鼠标移动到了这个项目上) |
CBN_CLOSEUP |
下拉列表关闭(可能是选择完成也可能是取消选择) |
CBN_SELENDOK |
用户完成选择项目 |
CBN_SELENDCANCEL |
用户取消选择(鼠标移动到了某个项目上,但并没有按下而是点击了其他控件,或按动了Esc键) |
CBN_DBLCLK |
在CBS_SIMPLE的组合框中双击了一个列表项 |
CBN_DROPDOWN |
用户打开了下拉框(按动了编辑框边的下拉按钮) |
如果想在用户选择了一个项目后做相应的动作,最好的办法就是处理CBN_SELENDOK通知码,因为这才意味着用户真正完成了一个选择动作
以上的操作都是针对下拉列表部分的,另外也有很多消息是针对组合框中的编辑控件的,对组合框的窗口句柄发送WM_GETTEXT和WM_SETTEXT,操作的对象就是组合框的编辑控件;如果要限制编辑控件中文本的最大输入长度,可以发送CB_LIMITTEXT消息,这时候wParam参数指定最大数量;当用户在编辑框中编辑文本的时候,Windows在用户输入之后、字符显示之前会发送CBN_EDITUPDATE通知码;当字符在编辑框中显示以后,又会发送CBN_EDITCHANGE通知码。所以在处理WM_COMMAND消息时通过处理这两个通知码可以检测到用户的输入操作。
组合框是子窗口控件中比较复杂的一种,这里介绍的是常用的消息和通知码,另外还有少量不常用的内容,读者可以自行查看相关的资料。
8. 使用列表框
表5.7 列表框可以使用的风格
风 格 |
说 明 |
LBS_DISABLENOSCROLL |
在不需滚动的时候也显示垂直滚动条 |
LBS_EXTENDEDSEL |
在多选列表框中允许按住Shift键同时选中一个范围 |
LBS_MULTIPLESEL |
允许多选,如果不定义的话则是单选列表框 |
LBS_NOSEL |
列表框项目只能查看不能选择 |
LBS_NOTIFY |
用户点击或双击项目时向父窗口发送WM_COMMAND消息 |
LBS_SORT |
自动按字母顺序排序插入的项目 |
LBS_USETABSTOPS |
列表框项目的文本中允许将Tab字符的位置展开 |
LBS_STANDARD |
组合LBS_NOTIFY,LBS_SORT,WS_VSCROLL和WS_BORDER |
一般单选列表框只需定义LBS_STANDARD就可以了。