In my work with the RichTextBox control, I’ve often run into this bug in the RichEdit control. You can read more about this bug by looking at Microsoft’s knowledge base article - 812943. If you are unable to get the latest Riched20.dll then you can get around the problem using the following code …

using System;  
using System.Runtime.InteropServices;  
using System.Text;  
using System.Windows.Forms;  
  
namespace TextUndoBuffer  
{  
    /// <summary>    
    /// Work around for KB 812943, The RichEdit Control Undo    
    /// Information May Be Lost When the Control Retrieves Text.   
    /// </summary>    
    public class RichTextBoxEx : RichTextBox  
    {  
        // RichEdit messages (Richedit.h)   
        private const int EM_GETTEXTEX = (WM_USER + 94);  
        private const int EM_GETTEXTLENGTHEX = (WM_USER + 95);  
        // Flags for the GETEXTEX data structure   
        private const int GT_DEFAULT = 0;  
        // Flags for the GETTEXTLENGTHEX data structure   
        // Fast computation of a "close" answer   
        private const int GTL_CLOSE = 4;  
        // Do default (return # of chars)   
        private const int GTL_DEFAULT = 0;   
        private const int WM_USER = 0x0400;  
  
        public override string Text  
        {  
            get  
            {  
                GETTEXTLENGTHEX getLength = new GETTEXTLENGTHEX();  
                getLength.flags = GTL_CLOSE; //get buffer size   
                getLength.codepage = 1200; //Unicode   
                  
                int textLength = SendMessage(  
                    base.Handle, EM_GETTEXTLENGTHEX,   
                    ref getLength, 0);  
  
                GETTEXTEX getText = new GETTEXTEX();  
                //add space for null terminator   
                getText.cb = textLength + 2;   
                getText.flags = GT_DEFAULT;  
                getText.codepage = 1200; //Unicode   
                  
                StringBuilder sb = new StringBuilder(getText.cb);  
                  
                SendMessage(base.Handle, EM_GETTEXTEX, ref getText, sb);  
                  
                return sb.ToString();  
            }  
            set  
            {  
                base.Text = value;  
            }  
        }  
  
        public override int TextLength  
        {  
            get  
            {  
                GETTEXTLENGTHEX getLength = new GETTEXTLENGTHEX();  
                //Returns the number of characters   
                getLength.flags = GTL_DEFAULT;   
                getLength.codepage = 1200; //Unicode   
                return SendMessage(base.Handle, EM_GETTEXTLENGTHEX, ref getLength, 0);  
            }  
        }  
  
        [DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]  
        private static extern int SendMessage(IntPtr hWnd, int msg,  
                                              ref GETTEXTEX wParam, StringBuilder lParam);  
  
        [DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]  
        private static extern int SendMessage(IntPtr hWnd, int msg,  
                                              ref GETTEXTLENGTHEX wParam, int lParam);  
 
        #region Nested type: GETTEXTEX  
  
        [StructLayout(LayoutKind.Sequential)]  
        private struct GETTEXTEX  
        {  
            public Int32 cb;  
            public Int32 flags;  
            public Int32 codepage;  
            public IntPtr lpDefaultChar;  
            public IntPtr lpUsedDefChar;  
        }  
 
        #endregion  
 
        #region Nested type: GETTEXTLENGTHEX  
  
        [StructLayout(LayoutKind.Sequential)]  
        private struct GETTEXTLENGTHEX  
        {  
            public Int32 flags;  
            public Int32 codepage;  
        }  
 
        #endregion  
    }  
}