Retrieve the Caret Position by Using an Extended TextBox Class

CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

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);
         }
      }
   }
}

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read