TextBox.SelStart / SelLength和长字符串

时间:2018-10-05 07:47:58

标签: vba ms-access winapi

我在Access数据库中有一个表单(Access 2013)。在此表单上是TextBox,用户可以在其中输入文本。 通过单击按钮,我想对TextBox中的文本(例如插入文本)进行一些处理。为此,我使用属性 SelStart中的SelLengthTextBox 确定将新文本放在何处。

但是不幸的是,两个属性(SelStartSelLength)都是VBA Integer值,这意味着只要我的TextBox中的文本长度小于Integer .MaxValue(= 32.767)SelStart是正确的,但是一旦我超过Integer。MaxValueSelStart就会跳转zu Integer.MinValue(= -32.768)并从该数字开始计数。因此,如果我的文本长度为40.000,则SelStart给出-25.535。

是否有任何方法可以获取SelStartSelLength的正确值,而不管字符串的长度如何?也许使用API​​函数而不是错误的Access属性?

2 个答案:

答案 0 :(得分:2)

听起来像是无符号整数。

VBA不支持无符号类型,因此当符号位被置位(对于2字节整数,一旦值超过(2 ^ 15)-1),它突然变为负数。但是,您可以使用基础功能来使用它们。

前一段时间,我已经编写了这些函数以使用无符号整数,您可以使用它将long转换为无符号整数并返回:

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字节整数的最大值),则仍然存在溢出问题

答案 1 :(得分:2)

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

您可以将SendMessage WinAPI函数与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) = True,EndSel = UIntToLong(Control.SelStart + Control.SelLength)也是如此。

我建议使用该WinAPI解决方案之外的另一种解决方案,因为该解决方案使用当前处于活动状态的控件,并且如果使用了错误的控件,使用外部API调用且没有错误,则不会出现任何错误。

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