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

来源:互联网 发布:2003excel查找重复数据 编辑:程序博客网 时间:2024/06/04 18:58

windows是以消息为基础的。

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

Option Explicit'发送消息命令'hwnd接收消息的句柄,wMsg消息的编号(类型)'wParam消息的第一参数'IParam消息的第二参数,此参数是传址,为了传值,前须加byvalPrivate Declare Function SendMessage _                Lib "user32" _                Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As LongPrivate Const WM_SYSCOMMAND = &H112Private Const SC_MAXIMIZE = &HF030&Private Const WM_SETTEXT = &HCPrivate Const WM_GETTEXT = &HDPrivate Sub Command1_Click()    Dim s As String    SendMessage Me.hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, ByVal 0& '最大化    SendMessage Me.hwnd, WM_SETTEXT, 0, ByVal "新的标题"      '设置窗体标题    '为返回值做准备    s = String(80, Chr(0))    SendMessage Me.hwnd, WM_GETTEXT, Len(s), ByVal s  '返回窗体标题    s = Left$(s, InStr(s, Chr(0)) - 1)    Print sEnd Sub'可以看到第二参数情况:'传数据0           byval 0&'字符串常数        byval "新的标题"'字符串变量        byval  s           这是取回返回值时

上面可以看到消息种类有:WM_GETTEXT,WM_SETTEXT,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, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As LongPrivate Const EM_LINESCROLL = &HB6Private Sub Command1_Click() '注意卷动受“视察”限制,最后刚好满足视窗时,不再上卷,同理左右卷。同时加上滚动条,可看出效果。'    SendMessage Text1.hwnd, EM_LINESCROLL, 0, ByVal 9  '下卷3行'    SendMessage Text1.hwnd, EM_LINESCROLL, 0, ByVal -1 '上卷1行'    SendMessage Text1.hwnd, EM_LINESCROLL, 1, ByVal 0   '右卷1行'    SendMessage Text1.hwnd, EM_LINESCROLL, -1, ByVal 0  '左卷1行    SendMessage Text1.hwnd, EM_LINESCROLL, 1, ByVal 1   '同时向下向右卷一行End SubPrivate Sub Form_Load()    Text1.Text = "第一行.........................." & vbCrLf & _            "第二行.........................." & vbCrLf & _            "第三行.........................." & vbCrLf & _            "第四行.........................." & vbCrLf & _            "第五行.........................." & vbCrLf & _            "第六行.........................." & vbCrLf & _            "第七行.........................." & vbCrLf & _            "第八行.........................." & vbCrLf & _            "第九行.........................." & vbCrLf & _            "第十行.........................." & vbCrLfEnd SubInStr

           注意:第一参数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,0,byval 0&)     '后两参数无作用,用0

           


            读取某行字串:EM_GetLine

Option ExplicitPrivate 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, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As LongPrivate Const EM_LINESCROLL = &HB6Private Const EM_GETLINECOUNT = &HBAPrivate Const EM_LINEINDEX = &HBBPrivate Const EM_LINELENGTH = &HC1Private Const EM_GETLINE = &HC4    '取得某行串,返回值在最后一参数中Private Sub Command1_Click()    Dim a As Long    a = SendMessage(Text1.hwnd, EM_GETLINECOUNT, 0, ByVal 0&)    Print a '显示11行,为什么?因为最后有一个回车换行,将计算为第11行。注意行索引是从0开始的End SubPrivate 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, 3, ByVal s    Print s '显示第4行,因为行索引是从0开始的。    End SubPrivate Sub Form_Load()    Text1.Text = "第一行..........................1" & vbCrLf & _       "第二行..........................2" & vbCrLf & _       "第三行..........................3" & vbCrLf & _       "第四行..........................4" & vbCrLf & _       "第五行..........................5" & vbCrLf & _       "第六行..........................6" & vbCrLf & _       "第七行..........................7" & vbCrLf & _       "第八行..........................8" & vbCrLf & _       "第九行..........................9" & vbCrLf & _       "第十行..........................10" & vbCrLfEnd Sub

           

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

                           CharPos = SendMessage(txtText1.hwnd, EM_CharFromPos, 0, 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 LongPrivate 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, EM_CharFromPos, 0, 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, _                                      ByVal wMsg As Long, _                                      ByVal wParam As Long, _                                      lParam As Any) As LongPrivate 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 '传出位置    Dim i As Integer     '字符位置        pos = Y / Screen.TwipsPerPixelY * 65536 + X / Screen.TwipsPerPixelY    CharPos = SendMessage(txtText1.hwnd, EM_CharFromPos, 0, ByVal pos) '转入,获取行,位置        i = CharPos Mod 65536    Print GetWord(txtText1, i)End SubPrivate 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 IfEnd FunctionPrivate 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感到用处不大。略过。











    

原创粉丝点击