vB SendMessage API 简单用法

vB SendMessage API 简单用法
1、

在Windows编程中,向文本框控件、列表控件、按钮控件等是我们最常接触的控件了。但是在VB中这些控件有时无法实现我们的需要。在这时,我们只要简单的利用Windows API函数就可以扩充这些控件的功能了。
顾名思义,SendMessage函数就是向窗口(这里的窗口指的是向按钮、列表框、编辑框等具有hWnd属性的控件)发送消息的函数,该函数的定义如下:
Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hwnd As Long, _
ByVal wMsg As Long, _
ByVal wParam As Long, _
lParam As Any) As Long

其中hwnd指定接受消息的窗口,参数wMsg指定消息值,参数wParam lParam分别定义传递到窗口的附加参数。而在Windows系统的很多消息中,有一些不仅仅是提供一个窗口消息那么简单。它们可以控制窗口的动作和属性。下面我将分次向向大家介绍SendMessage函数在扩充基本控件功能方面的应用。
一、列表(ListBox)控件
在Windows中,有一系列的以LB_开头的列表消息,这里介绍的就是利用LB消息控制的ListBox的应用
1、使列表中光标移动到不同的列表项上有不同的提示(ToolTip)
在列表框控件中有一个ToolTipText属性,该属性决定了当光标在列表框上移动时出现的提示文字。但是如何使得当光标在不同的列表项上移动时的提示文字也不同呢?问题的关键是要知道在光标移动时光标所在的列表项的索引,使用SendMessage函数发送LB_ITEMFROMPOINT消息就可以获得。下面是程序范例:

Option Explicit

Const LB_ITEMFROMPOINT = &H1A9

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

Private Sub Form_Load()
Dim i

For i = 1 To 200
List1.AddItem Str(i) + " Samples in this list is " + Str(i)
Next i
End Sub

Private Sub List1_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim lXPoint As Long
Dim lYPoint As Long
Dim 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))
‘将ListBox的Tooltip设置为该标题行的文本
If (lIndex >= 0) And (lIndex <= .ListCount) Then
.ToolTipText = .List(lIndex) ‘Return the text = .list(lIndex)
Else
.ToolTipText = ""
End If
End With
End If
End Sub

首先在Form1中加入一个ListBox控件,然后再将上面的代码加入到Form1的代码窗口中。运行程序,当光标在列表中移动时,可以看到根据光标所在的不同的列表项,提示文字也不相同。

2、向列表中加入横向滚动条使得可以浏览长列表项
当向列表中加入的列表项超出了列表的显示范围后,列表并不会出现横向滚动条让你可以通过滚动来浏览项目的全部内容。利用LB_SETHORIZONTALEXTENT消息可以设置列表的横向滚动条以及滚动长度。下面是范例程序:
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 = lstThis.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
End If
Next i

‘返回最长列表项的长度(像素)
ListTextWidth = lWidth
End Function

Private Sub Form_Load()
Dim astr As String
Dim i
Dim l As Long

l = List1.FontSize * 20 / Screen.TwipsPerPixelX
For i = 1 To 10
astr = astr + "我们This is a very long item " + Str(i)
Next i
List1.AddItem astr + "aaa"
‘加入一个很长的列表项
l = ListTextWidth(List1)

SendMessage List1.hwnd, LB_SETHORIZONTALEXTENT, l, 0
End Sub

首先在Form1中加入一个ListBox控件,然后再将上面的代码加入到Form1的代码窗口中。运行程序,可以看到列表中出现了横向滚动条,而且滚动范围正好是列表项的长度。

3、使列表可以响应用户击键
有时我们需要列表根据用户的敲入字符串自动调整列表的ListIndex到最接近的列表项,就象VB中动态感应用户输入控件属性的编辑器一样。问题的关键是如何在列表中查找含有指定字符串的列表项,使用LB_FINDSTRING消息可以在列表中查找指定字符串。下面是范例:

Private Declare Function SendMessageStr Lib "user32" Alias "SendMessageA" _
(ByVal hwnd As Long, _
ByVal wMsg As Long, _
ByVal wParam As Long, _
ByVal lParam As String) As Long

Const LB_FINDSTRING = &H18F
Dim astr As String

Private Sub Form_KeyPress(KeyAscii As Integer)
Dim l As Long

astr = astr + Chr(KeyAscii)

l = SendMessageStr(List1.hwnd, LB_FINDSTRING, -1, astr)

If l Then
List1.ListIndex = l
End If
End Sub

Private Sub Form_Load()
‘向List中加入列表项
For i = 65 To 85
For j = 65 To 85
List1.AddItem Chr(i) + Chr(j)
Next j
Next i
End Sub

Private Sub List1_DblClick()
‘清除原来的查找字符串
astr = ""
End Sub

Private Sub List1_KeyPress(KeyAscii As Integer)
‘如果按下的是字母键就将击键消息传递到Form1
If ((KeyAscii >= 65 And KeyAscii <= 90) Or (KeyAscii >= 97 _
Or KeyAscii <= 122)) Then
KeyAscii = 0
End If
End Sub

首先在Form1中加入一个ListBox控件,然后再将上面的代码加入到Form1的代码窗口中。并将List1的Sorted属性设置为True。运行程序,在列表中敲入字符,例如"av" "gm",列表就会高亮显示相近的列表项,双击列表就可以清除原来的输入。

在上一篇文章中我向大家介绍了关于ListBox类控件消息的应用,在这一章我将向大家介绍如何利用消息操控TextBox类控件。

1、获得光标所在的行和列
一般的比较完善的文本编辑器一般都有在状态栏中显示当前光标所在行和列的功能。利用SendMessage向TextBox控件发送编辑控件类型消息。也可以实现这样的功能。下面首先来看程序,然后再分析。
首先在VB中建立一个新工程,并在Form1中加入一个TextBox控件和两个Label控件。将TextBox控件的MultiLine属性设置为True。然后在Form1的代码窗口中加入如下代码:

Option Explicit

Private Declare Function SendMessage Lib "user32" Alias "SendMessageW" _
(ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, _
lParam As Any) As Long

Private Declare Function SendMessageByRef Lib "user32" Alias "SendMessageA" _
(ByVal hwnd As Long, ByVal wMsg As Long, wParam As Long, _
lParam As Long) As Long

Const EM_LINEFROMCHAR = &HC9
Const EM_LINEINDEX = &HBB
Const EM_GETLINE = &HC4
Const EM_GETSEL = &HB0

Dim iLineX, iLineY As Long

Sub GetCurPos(txtA As TextBox)
Dim l, l1, l2 As Long
Dim astr As String * 256

l = SendMessage(txtA.hwnd, EM_LINEINDEX, -1, 0)
iLineY = SendMessage(txtA.hwnd, EM_LINEFROMCHAR, l, 0)

SendMessageByRef txtA.hwnd, EM_GETSEL, l1, l2
iLineX = l1 - l
Label1.Caption = "列:" + Str(iLineX)
Label2.Caption = "行:" + Str(iLineY)
End Sub

Private Sub Form_Load()
Dim iFile
Dim astr As String

Label1.Height = 300: Label2.Height = 300
Text1.Left = 0: Text1.Top = 0
Text1.Text = ""
Label1.Caption = ""
Label2.Caption = ""

iFile = FreeFile
Open "C:\windows\readme.txt" For Input As #iFile
Do
Line Input #iFile, astr
Text1.Text = Text1.Text + astr + vbCrLf
Loop Until EOF(iFile)
Close iFile
End Sub

Private Sub Form_Resize()
Label1.Top = Me.ScaleHeight - 300
Label2.Top = Me.ScaleHeight - 300

Label1.Left = 0: Label2.Left = 1200
Label1.Width = 1200
Label2.Width = 1200

Text1.Width = Me.ScaleWidth
Text1.Height = Me.ScaleHeight - Label1.Height
End Sub

Private Sub Text1_Click()
GetCurPos Text1
End Sub

Private Sub Text1_KeyUp(KeyCode As Integer, Shift As Integer)
GetCurPos Text1
End Sub

在运行程序前,确保在你的硬盘上有 c:\windows\readme.txt 这个文件。否则程序会出错。然后运行程序。当在编辑文本时,可以看到在窗口底部可以显示当前光标所在的行、列值。在上面的程序中。我们首先发送EM_LINEINDEX消息,发送该消息可以返回某一行的第一个字符在整个文本控件中的位置,如果wParam参数设置为-1,则返回当前行的字符位置。然后发送EM_LINEFROMCHAR,发送该消息可以根据参数wParam指定的字符位置返回该字符所在的行号,文本第一行的位置为0。这样使用这两个消息就获得当前光标所在的行号。要取得列号,首先发送EM_GETSEL消息,发送该消息返回当前被选中文本的起始位置,如果没有文本被选中,则返回当前光标所在字符在文本中的位置。由于上面的EM_LINEINDEX消息返回的是当前行的第一个字符在文本中的位置。所以将两值相减,就是光标所在字符的列位置。在上面的程序中,如果你的文本中有中文字符的话,当你的光标在中文字符中移动一个位置,你会看到标签中的列位置增加了2,这是由于SendMessage发送的消息所得到的结果是不支持中文的,它将一个中文字算做两个字符。这也算是程序中的一个Bug吧(这也就是为什么我要使用EM_GETSEL消息而不直接使用TextBox控件的SelStart属性来获取光标所在字符位置了,因为如果使用SelStart返回的值将一个中文算一个字符,同EM_LINEINDEX返回值相减有可能得到负值).

2、声明API

Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long   ‘声明的 API

‘API常量申明

Public Const WM_SETHOTKEY = &H32
Public Const HOTKEYF_SHIFT = &H1
Public Const HOTKEYF_CONTROL = &H2
Public Const HOTKEYF_ALT = &H4

例子:    用sendmessage 给窗体发送个消息! 让他显示出来

Private Sub Form_Load()
   Dim l As Long
   Dim wHotkey As Long
   wHotkey = (HOTKEYF_ALT Or HOTKEYF_CONTROL) * (2 ^ 8) + 66  ‘设置热键
   l = SendMessage(Me.hwnd, WM_SETHOTKEY, wHotkey, 0) ‘WM_SETHOTKEY设置热键消息
   MsgBox "只需按Ctl+Alt+B 即可调出窗体"
   Me.WindowState = 1  ‘窗体最小化
End Sub

时间: 2024-08-02 07:01:55

vB SendMessage API 简单用法的相关文章

[转载]C#中MessageBox.Show用法以及VB.NET中MsgBox用法

一.C#中MessageBox.Show用法 MessageBox.Show (String) 显示具有指定文本的消息框. 由 .NET Compact Framework 支持. MessageBox.Show (IWin32Window, String) 在指定对象的前面显示具有指定文本的消息框. MessageBox.Show (String, String) 显示具有指定文本和标题的消息框.由 .NET Compact Framework 支持. MessageBox.Show (IWi

第12章 剪贴板_12.1 剪贴板的简单用法

12.1 剪贴板的简单用法 12.1.1 剪贴板的标准格式 分类 标准格式 说明 文本格式 CF_TEXT 以NULL结尾的ANSI字符集,每行结尾含有回车换行符,最后的NULL表示整个数据的结束. CF_OEMTEXT 以NULL结尾的OEM字符集,供MS-DOS下的剪贴板使用 CF_UNICODETEXT 类似CF_TEXT,每行以回车换行结束,字符两个NULL标志着整个数据的结束. CF_SYLK 含有微软件符号链接(Symbolic Link)格式数据的内存块.用与Excel程序交换,是

Notification(通知) 简单用法

Notification(通知) 是应用程序提醒用户某件事情已经发生了的一种方式,可以在“状态栏”和“通知托盘”中看到它.如我们更新程序的时候,可以通过Notification来实现下载进度. Notification 可以有以下动作来增强用户提醒: 1.在状态栏中显示图标. 2.灯光:手机LED呼吸灯闪烁 3.发出声音提醒. 4.手机震动. 5.在通知托盘中显示更多的信息 一,创建Notification Notification需要使用NotificationManager来管理.Notif

CATransition(os开发之画面切换) 的简单用法

CATransition 的简单用法 //引进CATransition 时要添加包“QuartzCore.framework”,然后引进“#import <QuartzCore/QuartzCore.h>” CATransition  *animation = [CATransition animation]; animation.duration = 0.6 ; //动画的切换时间速度 animation.timingFunction = [CAMediaTimingFunction fun

IOS 中block结构的简单用法

自从block出现之后,很多API都开始采用这样的结构,由此可见,block确实有许多优势存在,这里将一些简单用法总结如下: 一.如何声明一个block变量 我们通过^符号来声明block类型,形式如下: void (^myBlock)(); 其中第一个void是返回值,可以是任意类型,中间括号中^后面的是这个block变量的名字,我把它命名为myBlock,最后一个括号中是参数,如果多参数,可以写成如下样式: int (^myBlock)(int,int); 同样,你也可以给参数起名字: in

slf4j的简单用法以及与log4j的区别

之前在项目中用的日志记录器都是log4j的日志记录器,可是到了新公司发现都是slf4j,于是想着研究一下slf4j的用法. 1 基本介绍 SLF4J不同于其他日志类库,与其它日志类库有很大的不同.SLF4J(Simple logging Facade for Java)不是一个真正的日志实现,而是一个抽象层( abstraction layer),它允许你在后台使用任意一个日志类库.如果是在编写供内外部都可以使用的API或者通用类库,那么你真不会希望使用你类库的客户端必须使用你选择的日志类库.

iOS block-base 动画简单用法+关键帧动画设置线性变化速度的问题

本文转载至 http://www.tuicool.com/articles/aANBF3m 时间 2014-12-07 20:13:37  segmentfault-博客原文  http://segmentfault.com/blog/alan/1190000002411296 iOS的各种动画相漂亮,相信这是吸引很多人买iPhone的原因之一.不仅如此,这还是吸引我做iOS开发的一大原因,因为在iOS上给界面实现一些像样的动画实在是太轻松了! 这里就介绍一下iOS的block-based an

Vb.net/VB 声明API函数实现父窗体功能

回顾第一次敲机房收费,自己调用了api函数实现了父窗体及其子窗体最小化的功能,如今再次遇到,自己就在思考,能不能继续使用API函数呢?答案当然是Of Course! 其实仔细看两者并没有多大的区别,先看看在vb.net中如何调用: 首先添加一个类模块,来封装此API函数: <span style="font-size:14px;"> Public Declare Function SetParent Lib "<span style="color:

Android WIFI 简单用法

随着Wifi的普及,在开发App的时候对wifi的考虑越来越多了.例如程序的升级在wifi下可以省很多流量,在通信软件中的视频通话.可以实现高画质的传输等等,Android提供了WifiManager类来帮助开发者们管理Wifi.下面就简单来说一下WifiManager的简单用法把. 权限: 为了使用WfiManager 我们需要在Androidmanifest.xml 加入权限: //本例中使用了前两个.具体请按照需要添加权限. <uses-permission android:name=&quo