代码之家  ›  专栏  ›  技术社区  ›  Nostromo

TextBox.SelStart/SelLength和长字符串

  •  1
  • Nostromo  · 技术社区  · 7 年前

    我在Access数据库中有一个表单(Access 2013)。在这张表格上是 TextBox 用户可以在其中输入文本。 点击一个按钮,我想对文本做点什么 SelStart SelLength 文本框 到 决定把我的新课文放在哪里。

    但不幸的是这两个属性( )是VBA吗 Integer 值,也就是说,只要我的文本长度 文本框 低于Integer.MaxValue(=32.767) 选择开始 选择开始 跳转Integer.MinValue(=-32.768)并从该数字开始计数。所以,如果我的文本长度是40000那么 选择开始 提供-25.535。

    有没有办法得到正确的数值 所选文本的长度 不管绳子的长度?可能是用API函数而不是错误的访问属性?

    2 回复  |  直到 7 年前
        1
  •  2
  •   Erik A    7 年前

    将此作为单独的答案发布,因为它完全不同

    你可以用 SendMessage 带有 EM_GETSEL

    声明:

    (由于我们不使用字符串,所以使用SendMessageA或SendMessageW并不重要,这些声明仅适用于VBA7)

    Public Declare Function SendMessage Lib "User32.dll" Alias "SendMessageW" (ByVal hWnd As LongPtr, ByVal Msg As Integer, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr
    Public Declare Function GetFocus Lib "User32.dll" () As LongPtr
    Public Const EM_SETSEL As Integer = &HB1
    Public Const EM_GETSEL As Integer = &HB0
    

    实施它:

    Public Sub GetSelection()
        Dim StartSel As Long
        Dim EndSel As Long
        Dim hWnd As LongPtr
        hWnd = GetFocus
        SendMessage hWnd, EM_GETSEL, VarPtr(StartSel), VarPtr(EndSel)
        Debug.Print StartSel
        Debug.Print EndSel
    End Sub
    

    这将打印当前活动控件的选择。

    我已经验证了对于选择超过32768个字符的文本框,结果与我的第一个解决方案相同( StartSel = UIntToLong(Control.SelStart) =正确,并且 EndSel = UIntToLong(Control.SelStart + Control.SelLength)

    我推荐另一个解决方案而不是WinAPI解决方案,因为这个解决方案使用当前的活动控件,如果是错误的控件,则不会给出错误,使用外部API调用,并且可能会有更多的开销。

    这个解决方案确实支持超过2^16个字符的文本框,但是如果出现这种情况,Access的行为会很挑剔,我建议不要对这样大的文本框使用内置的textbox控件。

        2
  •  2
  •   Erik A    7 年前

    听起来像是个无符号整数。

    VBA不支持无符号类型,因此当设置符号位时(对于2字节整数,一旦值超过(2^15)-1),它就会突然变为负数。但是,您可以使用底层函数来处理它们。

    我不久前编写了这些函数来处理无符号整数,您可以使用它将长整数转换为无符号整数并返回:

    Public Function LongToUInt(lIn As Long) As Integer
        If lIn >= 2 ^ 16 Then Exit Function 'Overflow, might want to raise an error
        If lIn < 0 Then Exit Function 'Unsigned type doesn't support negatives, might want to raise an error
        If lIn > (2 ^ 15) - 1 Then 'Set sign bit, then store remainder in an integer
            LongToUInt = (-2 ^ 16) + lIn
        Else
            LongToUInt = lIn
        End If
    End Function
    
    Public Function UIntToLong(iIn As Integer) As Long
        'No checks, an UINT always fits inside a long
        If iIn < 0 Then
            UIntToLong = iIn + 2 ^ 16
        Else
            UIntToLong = iIn
        End If
    End Function
    

    实施它们:

    Textbox.SelStart = LongToUInt(40000)
    
    Dim theStart As Long
    theStart = UIntToLong(Textbox.SelStart)
    

    正如Gustav所指出的,如果值大于(2^16)-1(无符号2字节整数的最大值),则仍然存在溢出问题