vbsendmessage详解1
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
vbsendmessage详解1
SendMessage函数的常⽤消息及其应⽤(有点长,希望能对⼤家有所帮助)
函数原型:
Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, _
ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
其中四个参数的含义和说明如下:
1.hWnd:
对象的句柄。
希望将消息传送给哪个对象,就把该对象的句柄作为实参传送,在 VB 中可以简单地
⽤“对象.hWnd”获得某个对象的句柄,如 Text1.hWnd和 Form1.hWnd分别可以得到 Text1和Form1的句
柄。
它是⼀个长整型数。
Windows给每个控件⼀个编号,这个编号就称为窗⼝句柄。
有了这个句柄,我们
就可告诉 Windows 我们要控制哪个控件,所以这个句柄在 API 调⽤中⾄关重要。
VB 的⼤多数控件都包
括hwnd属性,如下拉框、TreeView等,窗体也有这个属性。
但也有⼀些控件没有这个属性,如标签控件。
没有这个属性就⽆法利⽤Windows API函数,但可以节省系统资源。
2.wMsg:
被发送的消息。
根据具体需求和不同的对象,将不同的消息作为实参传送,以产⽣预期的动作。
使
SendMessage 传递消息,⼤多是为了完成以下⼏个⼯作:
①设置控件的⼀些选项,象我们要使⽤的CB_SETDROPPEDWIDTH的就属于这种情况。
尽管VB的每个控
件都提供了许多属性,但仍然有许多控件的选项没有包括在其中。
⽽这些选项中的⼤多数都可以利⽤该
函数进⾏设置。
②获得控件的⼀些设置。
同上⼀种情况相反,有时我们需要获得控件的⼀些设置,相当于读取属性。
例如,如果想知道⼀个下拉框的下拉部分的宽度是多少,就可以向控件发送CB_GETDROPPEDWIDTH消息。
对于这种情况,SendMessage函数的返回值就是结果。
③执⾏⼀定的操作。
例如,我们要在下拉框中寻找是否有“ABC”这个字符串,当然,我们可以编写
⼀个循环,逐条⽐较看是否存在这样的字符串。
如果使⽤API,我们只需要向下拉框发送CB_FINDSTRING
消息,这条消息就会⾃动进⾏查找⼯作并返回结果。
④模拟⽤户操作。
我们有时希望模拟⽤户的操作,⽐如关闭其他应⽤程序的窗⼝。
其实只要我们能知
道那个窗⼝的句柄,我们就可以发送WM_CLOSE消息给那个窗⼝,窗⼝接受到这条消息就会关闭,如同⽤户
关闭窗⼝⼀样。
3.wParam、
4.lParam:
附加的消息信息。
这两个是可选的参数,⽤来提供关于wMsg消息更多的信息,不同的wMsg可能使⽤这
两个参数中的0、1或2个,如果不需要哪个附加参数,则将实参赋为NULL(在VB中赋为0)。
lParam定义为Any类型。
指定 Any类型可禁⽌VB进⾏类型检查,从⽽允许将任意数据类型传递给该过
程。
由于每条消息对参数的类型和传递⽅式的要求都不同:有的可能要求为Long型,有的可能要求为⾃定
义类型;⼤多数要求按传值⽅式传递,但也有⼀些要求按传地址⽅式。
为了满⾜各种要求,我们将这个参
数定义为Any类型。
⽐如,我们要传递⼀个Long型变量lData。
如果消息要求传地址⽅式传递,可以使⽤:
SendMessage ……, lData
⽽如果要求传值⽅式传递,则使⽤
SendMessage ……, ByVal lData
如果传递常数,我们则需要使⽤类型后缀来指定常数的类型,⽐如"0&",表⽰Long型的常数0,如
SendMessage ……, ByVal 0&
我们也可以使⽤类型转换函数CLng将常数指定为Long型,如CLng(0)。
程序中,有时定义 lParam As Any,有时定义 ByVal lParam As String。
这是为什么呢?对于
SendMessage函数,lParam的使⽤是很灵活的,在⼀般情况下,lParam是⼀个指针,它指向的数据类型
有三种:长整形、⾃定义数据结构类型、字符串类型。
对于前两种类型,需要将 lParam定义为 lParam
As Any,从⽽将 lParam 数据的指针传递到 SendMessage 函数。
对于字符串类型,则需要定义 Byval
lParam As String,因为字符串类型数据不同,只有定义 ByVal,得到的才是字符串的指针,如果没有
ByVal,得到的将是指向字符串指针的指针。
另外对于少数的消息来说,SendMessage 函数需要的只是
lParam 本⾝的值,这时就需要将 lParam定义为 Byval lParam As Long,或者在程序调⽤时在 lParam
之前加 ByVal。
当⽤户在编辑控件上进⾏各种操作时,其⽗窗⼝将收到 WM_COMMAND 通知消息,lParam带控件句柄
(hWnd),同时 wParam 的低16位带控件的 ID,⾼16位带有如下表的消息代码:
常⽤编辑控件消息:
EC_LEFTMARGIN(&H1) EC_USEFONTINF 设置左边距时使⽤
EC_RIGHTMARGIN EC_USEFONTINF 设置右边距时使⽤
EC_USEFONTINF,O,边距设置编辑控件的左、右边距,当wParam含EC_LEFTMARGIN时在lParam的低16位指定左边距点数,当wParam 含EC_RIGHTMARGIN时在lParam的⾼16位指定右边距点数。
当指定wParam为EC_USEFONTINFO时,则⽤当前字体的字符"A"的宽度指定右边距和字符"C"的宽度指定左边距lParam被忽略。
EM_CHARFROMPOS(&HD7=215),0, 取得编辑控件中指定位置的字符相对于⽂本头部的偏移量。
使⽤本操作应先在第4个参数的⾼16位指定⾏号,低16位指定列号(或⼀个POINTAPI结构),⾏列是按编辑控件的客户区左上⾓为原点(0,0)计算的。
如果指定的位置超出控件客户区
EM_CANUNDO(&HC6=198),0,0 决定前⼀次编辑操作是否能够撤消:检测控件撤消缓冲区是否为空,通常控件把最后⼀次在控件的编辑操作保存在⼀个撤消缓冲区,如果缓冲区⾮空则返回TRUE表⽰上次操作可以撤消,否则返回FALSE,应⽤程序可以利⽤该返回值来禁⽌或允许菜单或⼯具条的"撤消"项。
EM_EMPTYUNDOBUFFER(&HCD=205 ),0,0 清除控件的撤消缓冲区,使其不能撤消前⼀次编辑操作
EM_FMTLINES(&HC8=200) 决定是否在取回的⽂本宇串中包含软回车字符
EM_GETFIRSTVISIBLEINE(&HCE=206),0,0 获得⽂本控件中处于可见位置的最顶部的⽂本所在的⾏号
EM_GETLINE(&HC4=196 ),⾏号,ByVal 变量获取编辑控件某⼀⾏的内容,变量须预先赋空格
EM_GETLINECOUNT(&HBA=186,0,0 获取编辑控件的总⾏数
EM_GETMODIFY(&HB8=184),0,0 判断编辑控件的内容是否已发⽣变化,返回TRUE则控件⽂本已被修改,返回FALSE则未变。
EM_GETPASSWORDCHAR( ),0,0 获取编辑控件的密码字符,返回NULL表⽰没有字符
EM_GETRECT(&HB2=178),0,结构 获取编辑控件的格式化矩形
EM_GETTHUMB(&HBE=190),0,0 取得多⾏⽂本编辑控件的滚动框的当前位置(注意:是象素值)
EM_GETSEL(&HB0=176),0,变量获取光标位置(以字节数表⽰),或:(缓冲区起点,缓冲区终点)取得编辑控件中选定内容的范围,返回值中低16位为起点,⾼16位为终点
EM_GETHANDLE(&HBD=189),0,0 取得⽂本缓冲区
EM_GETWORDBREAKPROC(&HD1=209),0,0 取得整字换⾏回调函数EditWordBreakProc指针
EM_GETLIMITTEXT(WM_USER+37=1061),0,0 获取⼀个编辑控件中⽂本的最⼤长度
EM_GETMARGINS( ),0,0 获取编辑控件的左、右边距,返回值低16位为左边距,⾼16位为右边距(不得⽤于NT3.51)
EM_LIMITTEXT(&HC5=197),最⼤值,0 设置编辑控件中的⽂本长度
EM_SCROLLCARET(&HB7=183),0,0 把可见范围移⾄光标处
EM_LINEFROMCHAR(&HC9=201),偏移值,0 获取指定位置(或:-1,0 表⽰光标位置)所在的⾏号
EM_LINEINDEX(&HBB=187),⾏号,0 获取指定⾏(或:-1,0 表⽰光标所在⾏)⾸字符在⽂本中的位置(以字节数表⽰)
EM_LINELENGTH(&hC1=193),偏移值,0 获取指定位置所在⾏(或:-1,0 表⽰光标所在⾏)的⽂本长度(以字节数表⽰)
EM_POSFROMCHARPOINT,结构地址,偏移值取得指定字符位置的⾏列号,偏移值是字符相对于⽂本头部的偏移。
EM_LINESCROLL(&HB6=182),列数,⾏数指定⾏数的⽂本⽔平滚动,每次滚动N列
EM_EXGETSEL(&H434=1076)
EM_EXSETSEL(&H437=1079),0,结构 RichEdit控件设置⽂本选定范围,参阅 EM_SETSEL 消息,结构是指 CHARRANGE 结构
EM_PASTESPECIAL(&H440=1088),2(1),1 RichEdit控件粘贴剪贴板中的位图(或⽂本)
EM_FINDTEXT(&H738=1080) RichEdit控件正⽂搜索操作
EM_FINDTEXTEX(&H44F=1103) 同上
EM_SETTEXTEX(&H461=1121) RichEdit控件正⽂替换/插⼊操作
EM_SETTARGETDEVICE, GetDC(RichText.hWnd), RichText.Width / 15)设置 RichTextBox ⾃动换⾏,后续代码是:
RichText.RightMargin = iif(RichText.RightMargin = 0,1,0)
EM_SETTARGETDEVICE, 0, 1 设置 RichTextBox 不⾃动换⾏
EM_POSFROMCHAR(&HD6或&H426) 判断指定字符在编辑控件的位置(⽤于NT3.51)
EM_SCROLL(&HB5=181),*,0 ⽂本垂直滚动。
第三个参数*控制滚动⽅向:SB_LINEDOWN(1)向下滚动⼀⾏,SB_LINEUP(0)向上滚动⼀⾏,SB_PAGEDOWN(3)向下滚动⼀页,SB_PAGEUP(2)向上滚动⼀页。
EM_REPLACESEL(&HC2=194),1(0),字符串⽤指定字符串替换编辑控件中的当前选定内容,如果第三个参数wParam为1,则本次操作允许撤消,0禁⽌撤消。
字符串可⽤传值⽅式,也可⽤传址⽅式(例:SendMessage Text1.hwnd, EM_REPLACESEL, 0, Text2.Text '这是传值⽅式)
EM_SETSEL(&HB1=177),起点,终点设置编辑控件中⽂本选定内容范围(或设置光标位置),该范围被反相显⽰,⽤于为复制、替换、粘贴、剪切、删除等编辑功能指定范围,光标将被移⾄指定的终点后⾯。
还可使⽤指定相同起点和终点来移动光标⽽不是选定范围。
当指定的起点等于0和终点等于-1时,⽂本全部被选中,此法常⽤在清空编辑控件。
当指定的起点等于-2和终点等于-1时,全⽂均不选,光标移⾄⽂本未端,此法常⽤在⽂本未端追加内容。
注意:当控件没有输⼊焦点时,本操作将会失败,⼀般在执⾏本操作前都应调⽤SetFocus先取得输⼊焦点。
EM_UNDO(&HC7=199),0,0 撤消前⼀次编辑操作,当重复发送本消息,控件将在撤消和恢复中来回切换
EM_SETCHARFORMAT(&H444) 改变选定⽂本的颜⾊
EM_SETHANDLE(&HBC=188),缓冲区指针,0 为编辑控件指定新的⽂本缓冲区。
此操作仅适⽤对话框创建带DS_LOCALEDIT风格的控件。
EM_SETLIMITTEXT,长度(字节),0 设置编辑控件中的⽂本最⼤长度(不得⽤于NT3.51)
EM_SETMARGINS(&HD3=211) 设置编辑控件的左、右边距(不得⽤于NT3.51)
EM_SETMODIFY(&HB9=185),1(0),0 设置或清除⼀个编辑控件的修改标志
EM_SETPASSWORDCHAR(&HCC=204),字符,0 指定控件⽤来显⽰密码的字符,缺省为"*"。
当第三个参数wParam为0时,本操作将清除控件的ES_PASSWORD风格,并按实际字符显⽰。
EM_SETREADONLY(&HCF=207),1(0),0 决定是否将编辑控件设为只读,同时决定控件的ES_READONLY风格
EM_SETRECT(&HB3=179),0(或RECT),结构地址为⼀个编辑控件设置格式化矩形
EM_SETRECTNP(&HB4=180),0(或RECT),结构地址为⼀个编辑控件设置格式化矩形,只是控件此时不会重画
EN_CHANGE(&H300=768) 编辑控件的内容发⽣改变。
与EN_UPDATE不同,该消息是在编辑框显⽰的正⽂被刷新后才发出的。
EN_ERRSPACE(&H500=1280) 任何时候只要由于内存不⾜以完成⼀项编辑操作
EN_HSCROLL(&H601=1537) ⽤户单击了编辑控件的⽔平滚动条。
注意:这条消息是在控件更新显⽰之前发送出去的。
EN_VSCROLL(&H602=1538) ⽤户单击了编辑控件的垂直滚动条。
注意:这条消息是在控件更新显⽰之前发送出去的。
EN_KILLFOCUS(&H200=512) 编辑控件失去了输⼊焦点
EN_SETFOCUS(&H100=256) 编辑控件获得了输⼊焦点
EN_UPDATE(&H400=1024) 控件准备显⽰改变了的正⽂时发送该消息。
它与EN_CHANGE通知消息相似,只是它发⽣于更新⽂本显⽰出
EN_MAXTEXT(&H501=1281) ⽤户输⼈的⽂字数超出由EM_LIMITTEXT消息规定的界限,或超出由VB Maxlength属性规定的界限,就会发送这条消息。
此外,倘若不允许⾃动进⾏⽔平滚动,同时插⼊点要超出控件的宽度;或者不允许⾃动垂直滚动,同时插⼊点要超出控件的⾼度,那么也会触发这条消息。
在没有ES_AUTOHSCROLL或ES_AUTOVSCROLL的编辑框中,当正⽂超出了编辑框的边框时也会发出该消息。
编辑风格消息:
ES_MULTILINE 指定编辑控件能否进⾏多⾏⽂本编辑,若多⾏编辑器不指定ES_AUTOHSCROLL风格,则会⾃动换⾏,⽤户每按⼀次Enter,在当前光标处输⼊⼀个回车换⾏符(0Dh,0Ah),⽂本增加⼀⾏。
若不指定ES_AUTOVSCROLL,则多⾏编辑器会在窗⼝中正⽂装满时发出警告声响。
ES_LEFT ⽂本显⽰居左。
ES_CENTER ⽂本显⽰居中。
ES_RIGHT ⽂本显⽰居右。
ES_LOWERCASE 把⽤户输⼊的字母统统转换成⼩写字母。
ES_UPPERCASE 把⽤户输⼊的字母统统转换成⼤写字母。
ES_OEMCONVERT 把输⼊的⽂本从ANSI码转换成OEM码,然后⼜转换成ANSI码,⽬的是保证函数AnsiToOem的正确调⽤。
这在编辑框中包含⽂件名时是很有⽤的。
ES_AUTOHSCROLL(⾃动增加⽔平滚动条?)当⽤户在⾏尾键⼊⼀个字符时,正⽂将⾃动向右滚动10个字符,当⽤户按回车键时,正⽂总是滚向左边。
ES_AUTOVSCROLL 当⽤户在最后⼀个可见⾏按回车键时,正⽂向上滚动⼀页。
ES_NUMBER 只接收数码输⼊,其它字符输⼊⼀律⽆效。
ES_NOHIDESEL(&H100=256) 当编辑框失去输⼊焦点时,选中的⽂本将隐藏,正⽂中的选择保持不变。
缺省时正⽂中的选择将失效,当获得输⼊焦点后才⼜显⽰出来。
ES_READONLY 将编辑框设置成只读的。
ES_PASSWORD(&H20=32) 使所有键⼊的字符都⽤"*"来显⽰。
ES_WANTRETURN 使多⾏编辑器接收回车键输⼊并换⾏。
如果不指定该风格,按回车键会选择缺省的命令按钮,这往往会导致对话框的关闭。
列表框操作:
LB_FINDSTRING(&H18F=399),-1,ByVal 字串查找列表项的字符串,返回值=字符串所在的列表项的索引。
-1表⽰从第0⾏开始查找,如果改为⼀个有效的列表项索引值,将从该⾏开始查找。
LB_ITEMFROMPOINT(&H1A9=425) 获取光标所在的列表项的索引
LB_SETHORIZONTALEXTENT(&H194=404),长度,0 设置列表框的横向滚动条以及滚动长度,长度为象素值
组合框操作:
CB_SHOWDROPDOWN(&H14F),1(0),0 打开(关闭)组合框的列表
TVM_SETBKCOLOR(&H1100+29=4381) 设置扩展树型列表控件的背景⾊(TVM开头的常数)
常⽤窗⼝消息:
WM_GETFONT(&H31=49) 得到当前控件绘制⽂本的字体(的句柄)
WM_GETTEXT(&HD=13),变量长度,变量取得窗体的标题,变量须预先赋空字串(chr(0)),变量长度=Len(变量)
WM_SETTEXT(&HC=12),0,ByVal "字串" 设置窗体的标题
WM_NCLBUTTONDOWN(&HA1=161),2,0 在⾮客户区,即边框及标题栏上(假如定义的是⼀个组件,则⾮客户区包括Form等)按下⿏标左键;
WM_LBUTTONDOWN(&H201=513),2,0 在客户区,也就是除边框及标题栏以外按下⿏标左键
WM_VSCROLL(&H115=277),&H10000*p+SB_THUMBPOSITION(&H4),0 同步滚动⽂本,p是位置改变量
WM_PAINT
WM_USER(&H400=1024)
WM_CUT(&H300=768),0,0 剪切
WM_COPY(&H301=769)),0,0 复制
WM_PASTE(&H302=770)),0,0 粘贴
WM_CLEAR(&H303=771)),0,0 删除
WM_UNDO(&H304=772)),0,0 撤消
按纽消息:
BM_SETSTYLE(&HF4) 设置按纽样式
BS_RADIOBUTTON(&H4) 收⾳机旋纽式的按纽,是 BM_SETSTYLE 使⽤的参数
SendMessage函数应⽤(⼀)
在Windows系统的很多消息中,有⼀些不仅仅是提供⼀个窗⼝消息那么简单。
它们可以控制窗⼝的
动作和属性。
下⾯向⼤家介绍SendMessage函数在扩充列表(ListBox)控件功能⽅⾯的应⽤。
在 Windows 中,有⼀系列的以 LB_ 开头的列表消息,这⾥介绍的就是利⽤LB消息控制的ListBox
的应⽤。
1、使列表中光标移动到不同的列表项上有不同的提⽰(ToolTip)
在列表框控件中有⼀个 ToolTipText 属性,该属性决定了当光标在列表框上移动时出现的提⽰⽂
字。
但是如何使得当光标在不同的列表项上移动时的提⽰⽂字也不同呢?问题的关键是要知道在光标移
动时光标所在的列表项的索引,使⽤SendMessage函数发送 LB_ITEMFROMPOINT 消息就可以获得。
在 Form1 中加⼊⼀个 ListBox 控件,运⾏程序,当光标在列表中移动时,可以看到根据光标所在
的不同的列表项,提⽰⽂字也不相同。
代码如下(我已试验成功):
Const LB_ITEMFROMPOINT = &H1A9
Private Sub Form_Load()
Dim ZXS As Long
Drive1.Drive = "G:": Dir1.Path = "G:\⼀江秋⽔的⽂档"
Combo1.Text = Combo1.List(0)
ZXS = SendMessage(Text1.hwnd, 186, 0, 0)
Label1.Caption = "共 " & ZXS & " ⾏," & Len(Text1.Text) & " 字"
For i = 1 To 200: List1.AddItem Str(i) + " 列表框试验项⽬": Next
End Sub
Private Sub List1_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim lXPoint As Long, lYPoint As Long, lIndex As Long
If Button = 0 Then '确定在移动⿏标的同时没有按下功能键或者⿏标键
lXPoint = CLng(X / Screen.TwipsPerPixelX) '获得光标的位置,以像素为单位
lYPoint = CLng(Y / Screen.TwipsPerPixelY)
With List1
lIndex = SendMessage(.hwnd, LB_ITEMFROMPOINT, 0, ByVal ((lYPoint * 65536) + lXPoint)) '获得光标所在的标题⾏的索引If lIndex < .ListCount Then .ToolTipText = .List(lIndex) Else .ToolTipText = ""
End With
End If
End Sub
2、向列表中加⼊横向滚动条使得可以浏览长列表项
当向列表中加⼊的列表项超出了列表的显⽰范围后,列表并不会出现横向滚动条让你可以通过滚动来浏览
项⽬的全部内容。
利⽤ LB_SETHORIZONTALEXTENT 消息可以设置列表框的横向滚动条以及滚动长度。
在 Form1 中加⼊⼀个 ListBox 控件,运⾏程序,可以看到列表中出现了横向滚动条,⽽且滚动范围正好
是列表项的长度。
代码如下(我已试验成功):
Option Explicit
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Declare Function DrawText Lib "user32" Alias "DrawTextA" (ByVal hdc As Long, _
ByVal lpStr As String, ByVal nCount As Long, lpRect As RECT, ByVal wFormat As Long) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, _
ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Const LB_SETHORIZONTALEXTENT = &H194
Const DT_CALCRECT = &H400
Public Function ListTextWidth(ByRef lstThis As ListBox) As Long '获取最长项⽬的象素长度值
Dim i As Long
Dim tR As RECT
Dim lW As Long
Dim lWidth As Long
Dim lHDC As Long
With lstThis.Parent.Font
.Name =
.Size = lstThis.Font.Size
.Bold = lstThis.Font.Bold
.Italic = lstThis.Font.Italic
End With
lHDC = lstThis.Parent.hdc
For i = 0 To lstThis.ListCount - 1 '遍历所有的列表项以找到最长的项
DrawText lHDC, lstThis.List(i), -1, tR, DT_CALCRECT
lW = tR.Right - tR.Left + 8
If lW > lWidth Then lWidth = lW
Next
ListTextWidth = lWidth '返回最长列表项的长度(像素)
End Function
Private Sub Form_Load()
Dim astr As String
Dim i
Dim l As Long
For i = 1 To 10: astr = Str(i) + "这是真正的长项⽬" + astr: List1.AddItem astr: Next '加⼊⼀个很⼤的列表项
L = ListTextWidth(List1)
SendMessage List1.hwnd, LB_SETHORIZONTALEXTENT, L, 0
End Sub
3、使列表框可以响应⽤户击键
有时我们需要列表根据⽤户的敲⼊字符串⾃动调整列表的ListIndex到最接近的列表项,就象VB中动态
响应⽤户输⼊控件属性的编辑器⼀样。
问题的关键是如何在列表中查找含有指定字符串的列表项,使⽤
LB_FINDSTRING消息可以在列表中查找指定字符串。
在 Form1 中加⼊⼀个 TextBox 控件和⼀个 ListBox 控件,并将 List1的 Sorted 属性设置为True。
运⾏程序,在⽂本框中敲⼊字符,例如"av" "gm",列表就会⾼亮显⽰相近的列表项。
代码如下(已成功):
Const LB_FINDSTRING = &H18F
Dim st As String
Private Sub Form_Load()
For i = 65 To 90: For j = 65 To 90: List1.AddItem Chr(i) + Chr(j): Next: Next '向List中加⼊列表项
End Sub
Private Sub Text1_KeyPress(KeyAscii As Integer)
If Len(st) > 1 Then st = ""
If ((KeyAscii > 64 And KeyAscii < 91) Or (KeyAscii > 96 Or KeyAscii < 123)) Then
Dim L As Long
st = st + Chr(KeyAscii)
L = SendMessage(List1.hwnd, LB_FINDSTRING, -1, ByVal st)'注意!当参数4传⼊的是字符串时,必须⽤ByVal传递If L Then List1.ListIndex = L
End If
End Sub
4.在列表框中查找匹配的项⽬
在Win95风格的帮助系统中⼀般都有⼀个“索引”页,索引页含有⼀个⽂本框和⼀个列表框,当⽤户
在⽂本框中输⼊⽂字时,下拉列表会动态地显⽰与⽂本框中⽂字最匹配的项⽬,为⽤户提供了最⼤的⽅
便。
这种效果在应⽤程序的帮助系统中很容易实现(只要按照 Win95帮助系统的正常制作过程制作就可
以实现),如果想在应⽤程序的其它地⽅实现这种特性就需费⼀番⼼思了。
⽽使⽤SendMessage函数实现上述特性则⾮常简单,甚⾄只需⼀条语句就⾜够了,那就是在⽂本框的
Change事件中给列表框发⼀条LB_FINDSTRING(&H18F)消息,该消息告诉列表框在列表中查找匹配的项
⽬。
在发LB_FINDSTRING消息时,wParam参数代表从列表框的哪⼀个项⽬后⾯开始查找,⼀般情况下该参
数可定为-1,表⽰从List1(0)即第⼀项开始向后循环查找,lParam则传进欲搜索的字符串(必须采⽤值
传递)。
具体的代码和运⾏画⾯与下⾯的 5. 合并在⼀起演⽰。
5.为ListBox添加⽔平滚动条
在VB中,列表框控件仅提供垂直滚动条,没有设置⽔平滚动条的能⼒,当某些项⽬的⽂本宽度较长
时,超出列表框宽度部分的⽂本就⽆法显⽰出来,因此,很有必要为ListBox添加⼀个⽔平滚动条来⽅
便操作。
为添加⽔平滚动条,只需发⼀条 LB_SETHORIZONTALEXTENT(&H194) 消息给列表框即可。
发送消息
时,wParam为滚动条的长度(以像素为单位,可通过计算得出准确的长度,上⾯例2 就是如此的,也可
随便给⼀个数字,如本例的 250),lParam⽆⽤。
代码如下(已试验成功):
Declare Function SendMessage Lib "user32" Alias "SendMessageA"(ByVal hwnd As Long, _
ByVal wMsg As Long,ByVal wParam As Long,lParam As Any) As Long
Public Const LB_FINDSTRING=&H18F
Public Const LB_SETHORIZONTALEXTENT=&H194
Private Sub Form_Load()
List1.AddItem "软件"
List1.AddItem "电脑游戏"
List1.AddItem "电视机"
List1.AddItem "电视台"
List1.AddItem "电脑"
List1.AddItem "电脑游戏软件"
SendMessage List1.hwnd,&H194,250,0 '为列表框添加⽔平滚动条
End Sub
Private Sub Text1_Change()
'注意!当lParam传⼊的是字符串时,必须⽤ByVal传递
List1.ListIndex = SendMessage(List1.hwnd,LB_FINDSTRING,-1,ByVal Text1.Text)
End Sub
6.在API⽂本浏览器⾥,当我们在搜索栏输⼊任意字母,“可⽤项”⾥以该字母开头的项⽬以⾼亮显
⽰以引起我们注意该项是不是我们所需的。
象这样的功能⼀切提供搜索选项的程序都应该具备。
以下例
⼦采⽤SendMessage函数实现这⼀技术。
Const LB_FINDSTRING = &H18F
Private Sub Form_Load()
Dim i As Integer
For i = Asc("A") To Asc("Z") '给列表框添加26个字母(⼤写)
List1.AddItem Chr$(i)
Next
Text1 = "" '令⽂本框为空
End Sub
Private Sub Text1_KeyPress(KeyAscii As Integer)
Text1 = "" '按下任意键则令原内容消失
Text1.SelLength = 1 '限制长度
Text1.SelText = Chr(KeyAscii) '显⽰键盘符号
KeyAscii = 0 '禁⽌响应
'ListBox中的项⽬⽂本若与⽂本框的⼀致则选中(⾼亮)
List1.ListIndex = SendMessage(List1.hwnd, LB_FINDSTRING, -1, ByVal CStr(Text1.Text))'经试,不需CStr函数End Sub
以上程序适⽤于单项⽬为多个字母的查询,但必须注意,在TextBox的KeyPress事件中要作相应的
改动
SendMessage函数应⽤(⼆)
介绍如何利⽤消息函数来扩展树型列表 TreeView 控件的功能。
相信对于树型列表控件⼤家⼗分的
熟悉,典型的应⽤就是 Windows 资源管理器中的⽬录列表。
⽽在VB中,树型列表控件包含在Microsoft Windows Common Control 6.0(也可能是5.0,视你的VB或者系统版本⽽定)中。
在Windows API 中,
有⼀系列的以 TVM_ 开头的消息值,这些消息就是扩展树型列表控件所特定的消息值,下⾯向⼤家介绍
其中的⼀些应⽤
1、设置树型列表控件的背景颜⾊
⾸先做如下的定义:
Const TV_FIRST = &H1100
Const TVM_SETBKCOLOR = TV_FIRST + 29(4381)
调⽤:
Call SendMessage(TreeView1.hwnd, 4381, 0,ByVal RGB(255, 0, 0))
上⾯的SendMessage调⽤将TreeView1的背景颜⾊设置为红⾊。
⼤家可能注意到了。
在上⾯的 Sendmessage 函数定义中,我们将 lParam 定义为 ByVal lParam
As Long,⽽不是象前⾯的那些范例那样定义为 Any 或者 String 类型,关于这个问题,我会在最后的
⼀章中做介绍。
2、设置树型列表控件标题⾏⾼度
TVM_SETITEMHEIGHT 消息设定控件的标题⾏的⾼度,该消息的定义及调⽤⽅法如下:
Const TV_FIRST = &H1100
Const TVM_SETITEMHEIGHT = TV_FIRST + 27
Call SendMessage(TreeView1.hwnd, TVM_SETITEMHEIGHT, 60, 0) '将TreeView1标题⾏⾼度设置到60像素⾼3、为树型列表控件中不同的标题⾏设置不同的提⽰
介绍如何为树型列表控件中的每⼀个标题设置不同的提⽰。
同 ListBox控件不通,树型列表控件中
并没有根据光标位置获得标题⾏索引的消息,我们需要另外想办法。
在TVM类消息中有⼀个TVM_HITTEST
消息,发送该消息可以检测控件表⾯上的某⼀点,如果该点位于⼀个标题上,则返回该标题的句柄。
⽽
利⽤ TVM_GETITEM消息,则可以根据标题句柄返回该标题⾏的⽂本。
所以结合利⽤这两个消息可以获取
光标所在标题⾏的标题⽂本。
具体的范例代码如下:
Option Explicit
Private Type TPoint
x As Long
y As Long
End Type
Private Type TVHITTESTINFO
pt As TPoint
flags As Long
hItem As Long
End Type
Private Type TVITEM
mask As Long
HTreeItem As Long
state As Long
stateMask As Long
pszText As Long
cchTextMax As Long
iImage As Long
iSelectedImage As Long
cChildren As Long
lParam As Long
End Type
Const TV_FIRST = &H1100
Const TVM_HITTEST = TV_FIRST + 17
Const TVM_GETITEM = TV_FIRST + 12
Const TVHT_ONITEMLABEL = &H4
Const TVIF_TEXT = &H1
Const GMEM_FIXED = &H0
Private Declare Function SendMessageRef Lib "user32" Alias "SendMessageA" (ByVal hwnd As _ Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Destination As _ String, ByVal Source As Long, ByVal Length As Long)
Private Declare Function GlobalAlloc Lib "kernel32" (ByVal wFlags As Long, ByVal dwBytes _
As Long) As Long
Private Declare Function GlobalFree Lib "kernel32" (ByVal hMem As Long) As Long
Dim hItemPrv As Long
Private Sub Form_Load()
Dim ndX As Node
'加⼊若⼲Item
Set ndX = TreeView1.Nodes.Add(, , "R", "Root")
Set ndX = TreeView1.Nodes.Add("R", tvwChild, "Key1", "Node1")
Set ndX = TreeView1.Nodes.Add("Key1", tvwChild, "SubKey1", "SubNode1")
Set ndX = TreeView1.Nodes.Add("SubKey1", tvwChild, "SubKeys1", "SubNode1")
Set ndX = TreeView1.Nodes.Add("Key1", tvwChild, "SubKey2", "SubNode2")
Set ndX = TreeView1.Nodes.Add("Key1", tvwChild, "SubKey3", "SubNode3")
Set ndX = TreeView1.Nodes.Add("Key1", tvwChild, "SubKey4", "SubNode4")
End Sub
Private Sub TreeView1_MouseMove(Button As Integer, Shift As Integer, x As Single, y As Single) Dim ptA As TPoint
Dim tf As TVHITTESTINFO
Dim tv As TVITEM
Dim hStr As Long
Dim hItem As Long
Dim astr As String * 1024
Dim bstr
On Error GoTo errLab
'获得当前光标所在的位置坐标
ptA.x = Int(x / Screen.TwipsPerPixelX)
ptA.y = Int(y / Screen.TwipsPerPixelY)
tf.pt = ptA
tf.flags = TVHT_ONITEMLABEL
'获得光标所在的Item的句柄
hItem = SendMessageRef(TreeView1.hwnd, TVM_HITTEST, 0, tf)
'如果未获得句柄或者同上⼀次是同⼀个Item的句柄则退出
If ((hItem <= 0) Or (hItem = hItemPrv)) Then Exit Sub
hItemPrv = hItem
'分配⼀定的内存空间⽤以存储Item的标题
hStr = GlobalAlloc(GMEM_FIXED, 1024)
If hStr > 0 Then
tv.mask = TVIF_TEXT '获取标题⽂本
tv.HTreeItem = hItem 'Item句柄
tv.pszText = hStr
hTextMax = 1023
'发送TVM_GETITEM获得标题⽂本
Call SendMessageRef(TreeView1.hwnd, TVM_GETITEM, 0, tv)
'将标题⽂本拷贝到字符串astr中
CopyMemory astr, hStr, 1024
bstr = Left$(astr, (InStr(astr, Chr(0)) - 1))
TreeView1.ToolTipText = bstr
'释放分配的内存空间
GlobalFree hStr
End If
Exit Sub
errLab:
Resume Next
End Sub
运⾏上⾯的程序,当光标在 TreeView1上⾯移动时,TreeView1的 ToolTips就会根据光标所在的不
同标题⾏⽽变动。
SendMessage函数应⽤(三)
介绍关于RichTextBox(简称RTF)控件的消息和ListView控件的消息控制。
1.在Windows消息中,以EM_开头的消息是专门控制TextBox类控件和RTF类控件的。
下⾯介绍的是如何利⽤ EM_ 消息实现向 RichTextBox 中粘贴⽂本和位图。
在 EM_消息中,有⼀个 EM_PASTESPECIAL 消息
可以从剪贴板中获取⽂本或者位图类数据并拷贝到 RTF 上。
运⾏程序,点击Command1,可以将剪贴板中的数据(位图或者⽂本)拷贝到RichTextBox1上。
在 EM_PASTESPECIAL 消息中,wParam 定义剪贴板数据类型,lParam 定义⼀个 repastespecial
类型的数据,其中的 dwAspect 说明数据以何种⽅式显⽰到 RTF 对象上,如果是 DVASPECT_CONTENT,则将整个数据显⽰在 RTF 上,如果是 DVASPECT_ICON ,则只在 RTF 上显⽰⼀个图标。
经试,repastespecial 格式没有作⽤,因此参数4设为0即可。
Private Type repastespecial
dwAspect As Long '显⽰⽅式
dwParam As Long
End Type
Const WM_USER = &H400
Const EM_PASTESPECIAL = 1088
Const CF_BITMAP = 2
Const CF_TEXT = 1
Const DVASPECT_CONTENT = 1
Const DVASPECT_ICON = 4
Private Sub Command1_Click()
Dim re As repastespecial
re.dwAspect = DVASPECT_CONTENT
If Clipboard.GetFormat(vbCFText) Then ''剪贴板中为⽂本信息
Call SendMessage(RichTextBox1.hwnd, EM_PASTESPECIAL, CF_TEXT, re)
ElseIf Clipboard.GetFormat(vbCFBitmap) Then ''剪贴板中为位图信息
Call SendMessage(RichTextBox1.hwnd, EM_PASTESPECIAL, CF_BITMAP, re)
End If
End Sub
2.ListView控件也是Windows界⾯开发中重要的控件,典型的应⽤就是Windows资源管理器中的⽂件列
表。
⽽在VB中,ListView控件包含在Microsoft Windows Common Control 6.0(也可能是5.0,视你的
VB或者系统版本⽽定)中。
在 Windows API 中,有⼀系列的以 LVM_开头的消息值,这些消息就是扩展ListView控件所特定的消息值,下⾯的范例介绍如何通过LVM_消息设置ListView控件中图标的间距。
范
例如下:
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Const LVM_FIRST = &H1000
Const LVM_SETWORKAREA = LVM_FIRST + 65
Const LVM_SETICONSPACING = LVM_FIRST + 53
Private Sub Form_Load()
Dim xn As ListItem
Me.Show
ListView1.Width = 4500
ListView1.Height = 3000
ListView1.Refresh
Set xn = ListView1.ListItems.Add
xn.Text = "List1"
Set xn = ListView1.ListItems.Add
xn.Text = "List2"
Set xn = ListView1.ListItems.Add
xn.Text = "List3"
Set xn = ListView1.ListItems.Add
xn.Text = "List4"
Set xn = ListView1.ListItems.Add
xn.Text = "List5"
Set xn = ListView1.ListItems.Add
xn.Text = "List6"
ListView1.Refresh
Call SendMessage(ListView1.hwnd, LVM_SETICONSPACING, 0, ByVal (60 * 65536 + 190&))
End Sub
要运⾏上⾯的程序,⾸先要确保ListView1的Arrange属性为1,View属性为0。
在上⾯的程序中,我
们利⽤了 VM_SETICONSPACING 消息来控制图标间距。
其中SendMessage中的参数lParam定义图标间距,⾼位为纵向间距,低位为横向间距,在上⾯的范例中,我们将图标的纵向间距定义为60像素,横向间距
定义为190像素。
SendMessage函数的应⽤(四)
1,获得光标位置和字符个数.
Cpos=SendMessage(text1.hwnd,187,-1,0) '光标所在⾏的⾸字符在⽂本中的位置
Lpos=SendMessage(text1.hwnd,201,Cpos,0) '光标所在的⾏号
Line=SendMessage(text1.hwnd,193,Cpos,0) '这⾏的字符数.
2.获取第N⾏的⽂本
Dim ST As String
ST = Space(110)'必须要事先赋空格
Line=SendMessage(text1.hwnd,196, N-1, ByVal ST 'ST返回获取到的⽂本,Line返回⽂本的长度字节数
'下⾯的未成功
Dim str(256) As Byte, K As Integer
str(1)=1 '最⼤允许存放256个字符
K = SendMessage (Text1.hwnd,196,2,str(0)) '获取第3⾏的数据放在str中
text1.text = StrConv(str,vbUnicode) '转换为字符串后显⽰
说明:在调⽤SendMessage获取第N⾏字符串时,lParam需要说明为字节数组,在调⽤完成后,再将
字节数组转换为字符串;另外,调⽤前必须在lParam的前两个字节指明允许存放的最⼤长度,其中第⼀
个字节为低位,第⼆个字节为⾼位,本例将⾼位(即str(1))置1.说明最⼤允许存放256个字符。
3.开关显⽰器.
SendMessage Handle, WM_SYSCOMMAND, SC_MONITORPOWER, 0 '关闭显⽰器.
SendMessage Handle, WM_SYSCOMMAND, SC_MONITORPOWER, -1 '打开显⽰器
4.程序控制拉下或收起组合框的下拉列表
⼀般情况下,为了拉下或收起组合框的下拉列表,需要⽤键盘或⿏标进⾏操作,⽽有时我们希望程
序运⾏的某个时刻⾃动拉出下拉列表(⽐如在⼀些演⽰程序中),为了实现这个⽬的,我们也只有借助
于SendMessage函数,⽅法是发⼀个CB_SHOWDROPDOWN(&H14F)消息给组合框。
在发CB_SHOWDROPDOWN消息时,wParam参数决定了是拉下列表(=True)还是收起表(=False),lParam⽆⽤(设为0)。
为说明具体的使⽤⽅法,下⾯提供简单的程序⽚段:。