win32汇编-窗口 对话框 (三)

创建窗口

                .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
View Code

前面是顺序下来的几个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
View Code

创建模态对话框的函数是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
View Code

 对话框过程和普通的窗口过程在使用上有以下区别:

   窗口过程对应于不同的消息有各种不同含义的返回值,而对话框过程返回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消息来设置。
View Code

 子窗口句柄

有一个函数可以从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就可以了。

 

 

 

 

 

 

 

 

 

 

 

原文地址:https://www.cnblogs.com/xuankuwa/p/3659356.html