VB与API学习笔记(4)消息传递

前端之家收集整理的这篇文章主要介绍了VB与API学习笔记(4)消息传递前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

windows是以消息为基础的。

学一个SendMessage传送消息(命令)的API

Option Explicit
'发送消息命令
'hwnd接收消息的句柄,wMsg消息的编号(类型)
'wParam消息的第一参数
'IParam消息的第二参数,此参数是传址,为了传值,前须加byval

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 Const WM_SYSCOMMAND = &H112
Private Const SC_MAXIMIZE = &HF030&
Private Const WM_SETTEXT = &HC
Private Const WM_GETTEXT = &HD

Private Sub Command1_Click()
    Dim s As String
    SendMessage Me.hwnd,WM_SYSCOMMAND,SC_MAXIMIZE,ByVal 0& '最大化
    SendMessage Me.hwnd,WM_SETTEXT,ByVal "新的标题"      '设置窗体标题
    '为返回值做准备
    s = String(80,Chr(0))
    SendMessage Me.hwnd,WM_GETTEXT,Len(s),ByVal s  '返回窗体标题
    s = Left$(s,InStr(s,Chr(0)) - 1)
    Print s
End Sub
'可以看到第二参数情况:
'传数据0           byval 0&
'字符串常数        byval "新的标题"
'字符串变量        byval  s           这是取回返回值时

上面可以看到消息种类有:WM_GETTEXT,WM_SYSCOMMAND

最后一种还有几个参数:SC_MINIMIZE,SC_RESTORE,SC_CLOSE和窗体的几个状态命令等同

注: WM即:windows message

SC即:system command


一、TEXTBox

对应VB有的:

事件:

En_Change change

En_KillFocus LostFocus

EN_SetFocus GotFocus

属性

EM_GetPasswordChar PasswordChar

EM_GetSel SelText,SelStart,SelLength

EM_LimitText MaxLength

EM_ReplaceSel SelText

EM_SetLimitText MaxLength

EM_SetPasswordChar PasswordChar

EM_SetReadOnly Locked

VB中没有的类型:

EM_LineScroll 以行为单位,卷动TextBox

EM_Scroll 以行或页为单位卷动

EM_GetLineCount 计算总行数

EM_GetLine 读取某一行的字符串

EM_LineIndex 读取某一行第一个字母在TextBox中的索引

EM_LineLength 读取某一字母所在行次的“行字符数” (即这一行的字符数)

EM_CharFromPos 读取鼠标所在位置的字符索引

EM_SetSel 设置选择区域


视觉上的滚动如下:

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

Private Const EM_LINESCROLL = &HB6

Private Sub Command1_Click() '注意卷动受“视察”限制,最后刚好满足视窗时,不再上卷,同理左右卷。同时加上滚动条,可看出效果。
'    SendMessage Text1.hwnd,EM_LINESCROLL,ByVal 9  '下卷3行
'    SendMessage Text1.hwnd,ByVal -1 '上卷1行
'    SendMessage Text1.hwnd,1,ByVal 0   '右卷1行
'    SendMessage Text1.hwnd,-1,ByVal 0  '左卷1行
    SendMessage Text1.hwnd,ByVal 1   '同时向下向右卷一行
End Sub

Private Sub Form_Load()
    Text1.Text = "第一行.........................." & vbCrLf & _
            "第二行.........................." & vbCrLf & _
            "第三行.........................." & vbCrLf & _
            "第四行.........................." & vbCrLf & _
            "第五行.........................." & vbCrLf & _
            "第六行.........................." & vbCrLf & _
            "第七行.........................." & vbCrLf & _
            "第八行.........................." & vbCrLf & _
            "第九行.........................." & vbCrLf & _
            "第十行.........................." & vbCrLf
End Sub
InStr

注意:第一参数wParam是水平卷动,向下为正,向上为负

第二参数IParam是垂直卷动,向右为正,向左为负。 这两个受视窗限制。到“底”后不会再卷动

另一个卷动类型:EM_Scroll 是以行或页,由wParam具体指出:

wParam: SB_LineUp 向上一行

SB_LineDown 向下。。

SB_PageUp 向上一页

SB_PageDown 向下一页

SB:傻B,傻瓜式的:)

此时IParam无作用,用byval 0&

SentMessage Text1.hwnd,EM_Scroll,SB_PageDown,byval 0& '向下翻一页




获取总行数:EM_GetLineCount

LineCount=SendMessage(text1.hwnd,em_getlineCount,byval 0&) '后两参数无作用,用0


读取某行字串:EM_GetLine

Option Explicit
Private Declare Sub RtlMoveMemory _
                Lib "kernel32" (Dest As Any,_
                                Src As Any,_
                                ByVal Length As Long)
Private Declare Function SendMessage _
                Lib "user32" _
                Alias "SendMessageA" (ByVal hwnd As Long,lParam As Any) As Long

Private Const EM_LINESCROLL = &HB6
Private Const EM_GETLINECOUNT = &HBA
Private Const EM_LINEINDEX = &HBB
Private Const EM_LINELENGTH = &HC1
Private Const EM_GETLINE = &HC4    '取得某行串,返回值在最后一参数中

Private Sub Command1_Click()
    Dim a As Long
    a = SendMessage(Text1.hwnd,EM_GETLINECOUNT,ByVal 0&)
    Print a '显示11行,为什么?因为最后有一个回车换行,将计算为第11行。注意行索引是从0开始的
End Sub

Private Sub Command2_Click()
    Dim s As String
    Dim pos As Long
    Dim Length As Integer
    '先取出该行的长度
    pos = SendMessage(Text1.hwnd,EM_LINEINDEX,3,ByVal 0&) '3行首字母索引
    Length = SendMessage(Text1.hwnd,EM_LINELENGTH,pos,ByVal 0&) '该索引所在行的长度
    '初始化返回字串
    s = String$(Length,Chr(0))  '行串长度初始化
    RtlMoveMemory ByVal s,Length,2  '前两字节指定字串总长,不指定取不出字串
    SendMessage Text1.hwnd,EM_GETLINE,ByVal s
    Print s '显示第4行,因为行索引是从0开始的。
    
End Sub

Private Sub Form_Load()
    Text1.Text = "第一行..........................1" & vbCrLf & _
       "第二行..........................2" & vbCrLf & _
       "第三行..........................3" & vbCrLf & _
       "第四行..........................4" & vbCrLf & _
       "第五行..........................5" & vbCrLf & _
       "第六行..........................6" & vbCrLf & _
       "第七行..........................7" & vbCrLf & _
       "第八行..........................8" & vbCrLf & _
       "第九行..........................9" & vbCrLf & _
       "第十行..........................10" & vbCrLf

End Sub

读取字符串位置:EM_CharFromPos=&HD7& '在win32api.txt中没有,手动添加

CharPos = SendMessage(txtText1.hwnd,EM_CharFromPos,ByVal pos)

wParam:无用,用0

IParam: Long, 传入相对于TextBox左上角的像素位置,&H11223344,高位两字节是Y坐标,低两字节是X坐标。

即:Y*65536+X. 注意是像素,若为Twip要转换

返回值: Long,&H11223344,高两字节是行数,低两字节是字符位置。CharPos\65536即行,CharPos mod 65536即字符位置。

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 Const EM_CharFromPos As Long = &HD7&

Private Sub txtText1_MouseDown(Button As Integer,_
                               Shift As Integer,_
                               X As Single,_
                               Y As Single)

    Dim pos     As Long '传入位置

    Dim CharPos As Long '传出位置
    
    pos = Y / Screen.TwipsPerPixelY * 65536 + X / Screen.TwipsPerPixelY
    CharPos = SendMessage(txtText1.hwnd,ByVal pos) '转入,获取行,位置
    Print "第" & CharPos \ 65536 & "行"     '提取高两字节
    Print "第" & CharPos Mod 65536 & "个字符"  '提取低两字节
    
End Sub


再次可以看到,行索引是从0开始,字符位置是从最开始算起的(注意上面因为回车与换行算两个字符,所以位置是9)



获取鼠标所在位置的单词:

思路:

1、取得鼠标的位置

2、从鼠标位置分别向前和向后循环检查分隔符的位置,以确定整个单词的起点和终点。

3、根据起点和终点提取单词。


Private Declare Function SendMessage _
                Lib "user32" _
                Alias "SendMessageA" (ByVal hwnd As Long,_
                               Y As Single)

    Dim pos     As Long '传入位置

    Dim CharPos As Long '传出位置
    Dim i As Integer     '字符位置
    
    pos = Y / Screen.TwipsPerPixelY * 65536 + X / Screen.TwipsPerPixelY
    CharPos = SendMessage(txtText1.hwnd,ByVal pos) '转入,获取行,位置
    
    i = CharPos Mod 65536
    Print GetWord(txtText1,i)
End Sub

Private Function IsDelimiter(ByVal char As Byte) As Boolean '判断是否是分隔号

    Dim s As String

    s = Chr(char)
    IsDelimiter = False

    If s = " " Or s = "." Or s = "?" Or s = vbCr Or s = vbLf Then '分隔符自定
        IsDelimiter = True

    End If

End Function

Private Function GetWord(txtBox As TextBox,pos As Integer) As String  '取得鼠标所在单词

    Dim pos1 As Integer,pos2 As Integer

    Dim b()  As Byte,i As Integer

    b = StrConv(txtBox,vbFromUnicode)
    pos1 = 0
    pos2 = UBound(b)

    '分别取得鼠标位置的前后分隔符位置,为下一步取单词作准备
    For i = pos To 0 Step -1  '鼠标位置的前一个分隔符位置

        If IsDelimiter(b(i)) Then
            pos1 = i + 1
            Exit For

        End If

    Next

    For i = pos To pos2    '鼠标位置的后一个分隔符位置

        If IsDelimiter(b(i)) Then
            pos2 = i - 1
            Exit For

        End If

    Next

    If pos2 > pos1 Then

        ReDim b2(pos2 - pos1) As Byte '变量上下限定义时,用ReDim

        For i = pos1 To pos2
            b2(i - pos1) = b(i)
        Next
        GetWord = StrConv(b2,vbUnicode)
    Else
        GetWord = ""

    End If
    
End Function

看到这个程序不由得再次感叹,为啥要用vbformunicode,因为API是外国用的,不适用中国的双字节字符。为了适合中文(比如上面是

中英文混合字符),就得全转到字节方式,取得单词后,再回到unicode状态。所以上面的pos1,pos2是字节状态的位置,和字符的位置

是不同的。

因此若根据pos1,pos2来用:

text1.selstart=pos1

text1.sellength=pos2-pos1+1

来选择这个单词将会出错。



若要选择这个单词,再次用API: EM_SetSel

sendMessage txt.hwnd,Em_SetSel,pos1,byval cLng(pos2+1)

wParam: 起始位置

Iparam: 终点位置+1



二、listBox,Combo 这个两个的API感到用处不大。略过。

猜你在找的VB相关文章