Imports MvpsOrg.Dotnet.InteropHelpers.WordConverter
Imports System.ComponentModel
Imports System.Runtime.InteropServices
Public Class ExtendedTextBox
Inherits TextBox
Private Declare Auto Function SendMessage Lib "user32.dll" ( _
ByVal hWnd As IntPtr, _
ByVal Msg As Int32, _
ByVal wParam As IntPtr, _
ByVal lParam As IntPtr _
) As IntPtr
Private Declare Auto Function GetCaretPos Lib "user32.dll" ( _
ByRef lpPoint As POINTAPI _
) As Boolean
Private Declare Auto Function SetCaretPos Lib "user32.dll" ( _
ByVal x As Int32, _
ByVal y As Int32 _
) As Boolean
Private Const EM_POSFROMCHAR As Int32 = &HD6
Private Const EM_CHARFROMPOS As Int32 = &HD7
<StructLayout(LayoutKind.Sequential)> _
Private Structure POINTAPI
Public x As Int32
Public y As Int32
End Structure
Private Declare Auto Function DrawText Lib "user32.dll" ( _
ByVal hDC As IntPtr, _
ByVal lpStr As String, _
ByVal nCount As Int32, _
ByRef lpRect As RECT, _
ByVal wFormat As Int32 _
) As Int32
Private Const DT_CALCRECT As Int32 = &H400
Private Structure RECT
Public Left As Int32
Public Top As Int32
Public Right As Int32
Public Bottom As Int32
End Structure
Private Declare Function SelectObject Lib "gdi32.dll" ( _
ByVal hdc As IntPtr, _
ByVal hObject As IntPtr _
) As IntPtr
< _
DesignerSerializationVisibility( _
DesignerSerializationVisibility.Hidden _
) _
> _
Public Property CaretPosition() As Integer
Get
Dim pt As POINTAPI
If Not GetCaretPos(pt) Then
Throw New Win32Exception()
Exit Property
End If
Return _
LoWord( _
SendMessage( _
Me.Handle, _
EM_CHARFROMPOS, _
IntPtr.Zero, _
New IntPtr(MakeLong(pt.x, pt.y)) _
).ToInt32() _
)
End Get
Set(ByVal Value As Integer)
Dim x As Integer
If Value >= Me.TextLength Then
Value = Me.TextLength - 1
Using g As Graphics = Me.CreateGraphics()
Dim hDC As IntPtr = g.GetHdc()
Dim hNewFont As IntPtr = Me.Font.ToHfont()
Dim hOldFont As IntPtr = SelectObject(hDC, hNewFont)
Dim rct As RECT
rct.Right = Int32.MaxValue
rct.Bottom = Int32.MaxValue
If _
DrawText( _
hDC, _
Strings.Right(Me.Text, 1), _
1, _
rct, _
DT_CALCRECT _
) = 0 _
Then
Throw New Win32Exception()
Exit Property
End If
x = rct.Right
SelectObject(hDC, hOldFont)
g.ReleaseHdc(hDC)
End Using
End If
Dim n As Int32 = _
SendMessage( _
Me.Handle, _
EM_POSFROMCHAR, _
New IntPtr(Value), _
IntPtr.Zero _
).ToInt32()
x += LoWord(n)
Dim y As Integer = HiWord(n)
' HACK: Is there any other way to get the Y-offset of the
' caret?
Select Case Me.BorderStyle
Case BorderStyle.Fixed3D
y += 1
Case BorderStyle.FixedSingle
y += 2
'Case BorderStyle.None
' y += 0
End Select
If Not SetCaretPos(x, y) Then
Throw New Win32Exception()
Exit Property
End If
End Set
End Property
End Class
Public Class WordConverter
<StructLayout(LayoutKind.Explicit)> _
Private Structure DWord
<FieldOffset(0)> Public LongValue As Integer
<FieldOffset(0)> Public LoWord As Short
<FieldOffset(2)> Public HiWord As Short
End Structure
Private Shared m_DWord As DWord
Public Shared Function MakeLong( _
ByVal LoWord As Short, _
ByVal HiWord As Short _
) As Integer
m_DWord.LoWord = LoWord
m_DWord.HiWord = HiWord
Return m_DWord.LongValue
End Function
Public Shared Function MakeLong( _
ByVal LoWord As Integer, _
ByVal HiWord As Integer _
) As Integer
Return MakeLong(CShort(LoWord), CShort(HiWord))
End Function
Public Shared Function LoWord(ByVal LongValue As Integer) As Short
m_DWord.LongValue = LongValue
Return m_DWord.LoWord
End Function
Public Shared Function HiWord(ByVal LongValue As Integer) As Short
m_DWord.LongValue = LongValue
Return m_DWord.HiWord
End Function
End Class