Fix for the RichTextBox Undo Information Lost When Retrieving Text

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

How to integrate NetSpell with FreeTextBox

The following code snippet show how integrate NetSpell with FreeTextBox.

Download the latest version of FreeTextBox and NetSpell.

Copy NetSpell.SpellChecker.dll to the bin folder and add the following files to the same folder as default.aspx for FreeTextBox.

  • spell.css
  • spell.js
  • SpellCheck.aspx 

Copy the dic folder to the FreeTextBox folder.  Then modify the web.config file so the path to the dic folder matches.

<configuration>
    <appSettings>
        <add key="DictionaryFolder" value="dic" />
    </appSettings>
</configuration>

Modify Default.aspx to look like this


How to create a custom dictionary

The following are some simple steps to create a custom dictionary.

Step 1

Create a text file with all the words you would like to use in the dictionary. The text file should have one word per line like so …

apple
banana
grape
orange
peach
pineapple

Step 2

Run the Dictionary Build tool. Create a new dictionary.

Step 3

Load the text file into the new dictionary by using the Dictionary > Add OpenOffice Word List.


The NetSpell project

Introduction

The NetSpell project is a spell checking engine written entirely in managed C# .net code. NetSpell’s suggestions for a misspelled word are generated using phonetic (sounds like) matching and ranked by a typographical (looks like) score. NetSpell supports multiple languages and the dictionaries are based on the OpenOffice Affix compression format. The library can be used in Windows or Web Form projects. The download includes an English dictionary with dictionaries for other languages available for download on the project web site. NetSpell also supports user added words and automatic creation of user dictionaries. It also includes a dictionary build tool to build custom dictionaries.