Retrieve the Caret Position by Using an Extended TextBox Class
CodeGuru Editor's Comment: This article uses the Win32 API from C#. Generally, you should avoid calling such unmanaged code from a managed (.NET) application. This is, however, an interesting example of calling the API from .NET.
Sometimes, we need to know the caret position in a TextBox control; for example, in editor programs. The following ExtTextBox class extends the TextBox class with two read-only properties. The GetCaretXYPosition returns a Point struct with the (X,L) coordinates of the current position of the caret. The GetCaretLCPosition returns a CharPoint custom struct with the (L, C) coordinates of the position of the caret, where L is the one-based line number and C is the one-based column number.
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing;
namespace TextBoxUtils
{
/// <summary>
/// struct to handle the caret (L, C) co-ordinates
/// L = one-based line number of the line containing the caret
/// C = one-based column number in the line containing the caret
/// </summary>
public struct CharPoint
{
private int l, c;
public static readonly CharPoint Empty;
static CharPoint()
{
CharPoint.Empty = new CharPoint();
}
public CharPoint(int l, int c)
{
this.l = l;
this.c = c;
}
public override string ToString()
{
return(String.Format("{{L={0}, C={1}}}", this.l, this.c));
}
}
public class ExtTextBox: TextBox
{
[DllImport("user32")] private static extern IntPtr
SendMessage(HandleRef hWnd, int msg,
int wParam, int lParam);
[DllImport("user32")] private static extern int
GetCaretPos(ref Point lpPoint);
private int EM_LINEINDEX = 0xbb;
private int EM_LINEFROMCHAR = 0xc9;
private int EM_GETSEL = 0xb0;
/// <summary>
/// Gets the caret current (X, Y) position.
/// </summary>
/// <value>
/// Point struct
/// </value>
public Point GetCaretXYPosition
{
get
{
Point pt = Point.Empty;
// get a Point struct with the caret current (X, Y)
// position
GetCaretPos(ref pt);
// return the Point struct with the caret current
// (X, Y) position
return pt;
}
}
/// <summary>
/// Gets the caret current (L, C) position.
/// </summary>
/// <value>
/// CharPoint struct
/// </value>
public CharPoint GetCaretLCPosition
{
get
{
CharPoint cpt = CharPoint.Empty;
// save the handle reference for the ExtToolBox
HandleRef hr = new HandleRef(this, base.Handle );
// Send the EM_LINEFROMCHAR message with the value of
// -1 in wParam.
// The return value is the zero-based line number
// of the line containing the caret.
int l = (int)SendMessage(hr,EM_LINEFROMCHAR, -1, 0);
// Send the EM_GETSEL message to the ToolBox control.
// The low-order word of the return value is the
// character position of the caret relative to the
// first character in the ToolBox control,
// i.e. the absolute character index.
int sel = (int)SendMessage(hr, EM_GETSEL,0, 0);
// get the low-order word from sel
int ai = sel & 0xffff;
// Send the EM_LINEINDEX message with the value of -1
// in wParam.
// The return value is the number of characters that
// precede the first character in the line containing
// the caret.
int li = (int)SendMessage(hr,EM_LINEINDEX, -1, 0);
// Subtract the li (line index) from the ai
// (absolute character index),
// The result is the column number of the caret position
// in the line containing the caret.
int c = ai - li;
cpt = new CharPoint(l+1,c+1);
// Add 1 to the l and c since these are zero-based.
// Return a CharPoint with the caret current (L,C)
// position
return new CharPoint(l+1,c+1);
}
}
}
}

Comments
There are no comments yet. Be the first to comment!