RichTextBox.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / fx / src / WinForms / Managed / System / WinForms / RichTextBox.cs / 5 / RichTextBox.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Windows.Forms { 
    using Microsoft.Win32; 
    using System;
    using System.Collections.Specialized; 
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;
    using System.Drawing; 
    using System.Drawing.Design;
    using System.Globalization; 
    using System.IO; 
    using System.Runtime.InteropServices;
    using System.Runtime.Remoting; 
    using System.Runtime.Serialization.Formatters;
    using System.Security;
    using System.Security.Permissions;
    using System.Text; 
    using System.Windows.Forms.ComponentModel;
    using System.Windows.Forms.Design; 
    using System.Windows.Forms.Layout; 

    using IComDataObject = System.Runtime.InteropServices.ComTypes.IDataObject; 
    using Util = NativeMethods.Util;

    //
 

 
 

 
    /// 
    /// 
    ///     Rich Text control. The RichTextBox is a control that contains formatted text.
    ///     It supports font selection, boldface, and other type attributes. 
    /// 
 
    [ClassInterface(ClassInterfaceType.AutoDispatch), 
     ComVisible(true),
     Docking(DockingBehavior.Ask), 
     Designer("System.Windows.Forms.Design.RichTextBoxDesigner, " + AssemblyRef.SystemDesign),
     SRDescription(SR.DescriptionRichTextBox)
   ]
    public class RichTextBox : TextBoxBase { 
        static TraceSwitch richTextDbg;
        static TraceSwitch RichTextDbg { 
            get { 
                if (richTextDbg == null) {
                    richTextDbg = new TraceSwitch("RichTextDbg", "Debug info about RichTextBox"); 
                }
                return richTextDbg;
            }
        } 

        ///  
        ///  
        ///     Paste special flags.
        ///  
        private const int DV_E_DVASPECT      = unchecked((int)0x8004006B);
        private const int DVASPECT_CONTENT   = 1;
        private const int DVASPECT_THUMBNAIL = 2;
        private const int DVASPECT_ICON      = 4; 
        private const int DVASPECT_DOCPRINT  = 8;
 
        internal const int INPUT             = 0x0001; 
        internal const int OUTPUT            = 0x0002;
        internal const int DIRECTIONMASK     = INPUT | OUTPUT; 
        internal const int ANSI              = 0x0004;
        internal const int UNICODE           = 0x0008;
        internal const int FORMATMASK        = ANSI | UNICODE;
        internal const int TEXTLF            = 0x0010; 
        internal const int TEXTCRLF          = 0x0020;
        internal const int RTF               = 0x0040; 
        internal const int KINDMASK          = TEXTLF | TEXTCRLF | RTF; 

        // This is where we store the reched library. 
        private static IntPtr moduleHandle;

        private static readonly string SZ_RTF_TAG      = "{\\rtf";
        private const int CHAR_BUFFER_LEN    = 512; 

        // Event objects 
        // 
        private static readonly object EVENT_HSCROLL          = new object();
        private static readonly object EVENT_LINKACTIVATE     = new object(); 
        private static readonly object EVENT_IMECHANGE        = new object();
        private static readonly object EVENT_PROTECTED        = new object();
        private static readonly object EVENT_REQUESTRESIZE    = new object();
        private static readonly object EVENT_SELCHANGE        = new object(); 
        private static readonly object EVENT_VSCROLL          = new object();
 
 
        // Persistent state
        // 
        private int         bulletIndent;
        private int         rightMargin;
        private string      textRtf; // If not null, takes precedence over cached Text value
        private string      textPlain; 
        private Color selectionBackColorToSetOnHandleCreated;
        RichTextBoxLanguageOptions languageOption = RichTextBoxLanguageOptions.AutoFont | RichTextBoxLanguageOptions.DualFont; 
 
        // Non-persistent state
        // 
        static int logPixelsX;
        static int logPixelsY;
        Stream editStream = null;
        float zoomMultiplier = 1.0f; 

        // used to decide when to fire the selectionChange event. 
        private int curSelStart; 
        private int curSelEnd;
        private short curSelType; 
        object oleCallback;

        private static int[] shortcutsToDisable;
        private static int richEditMajorVersion = 3; //Assume version 3: it'll only be version 2 on Win98, and we don't yet load version 4. 

        private BitVector32 richTextBoxFlags = new BitVector32(); 
        private static readonly BitVector32.Section autoWordSelectionSection = BitVector32.CreateSection(1); 
        private static readonly BitVector32.Section showSelBarSection = BitVector32.CreateSection(1, autoWordSelectionSection);
        private static readonly BitVector32.Section autoUrlDetectSection = BitVector32.CreateSection(1, showSelBarSection); 
        private static readonly BitVector32.Section fInCtorSection = BitVector32.CreateSection(1, autoUrlDetectSection);
        private static readonly BitVector32.Section protectedErrorSection = BitVector32.CreateSection(1, fInCtorSection);
        private static readonly BitVector32.Section linkcursorSection = BitVector32.CreateSection(1, protectedErrorSection);
        private static readonly BitVector32.Section allowOleDropSection = BitVector32.CreateSection(1, linkcursorSection); 
        private static readonly BitVector32.Section suppressTextChangedEventSection = BitVector32.CreateSection(1, allowOleDropSection);
        private static readonly BitVector32.Section callOnContentsResizedSection = BitVector32.CreateSection(1, suppressTextChangedEventSection); 
        private static readonly BitVector32.Section richTextShortcutsEnabledSection = BitVector32.CreateSection(1, callOnContentsResizedSection); 
        private static readonly BitVector32.Section allowOleObjectsSection = BitVector32.CreateSection(1, richTextShortcutsEnabledSection);
        private static readonly BitVector32.Section scrollBarsSection = BitVector32.CreateSection((short) RichTextBoxScrollBars.ForcedBoth, allowOleObjectsSection); 
        private static readonly BitVector32.Section enableAutoDragDropSection = BitVector32.CreateSection(1, scrollBarsSection);

        /// 
        ///  
        ///     Constructs a new RichTextBox.
        ///  
        public RichTextBox() { 
            InConstructor = true;
            richTextBoxFlags[autoWordSelectionSection] = 0;// This is false by default 
            DetectUrls = true;
            ScrollBars = RichTextBoxScrollBars.Both;
            RichTextShortcutsEnabled = true;
            MaxLength = int.MaxValue; 
            Multiline = true;
            AutoSize = false; 
            curSelStart = curSelEnd = curSelType = -1; 
            InConstructor = false;
        } 

        /// 
        /// 
        ///     RichTextBox controls have built-in drag and drop support, but AllowDrop, DragEnter, DragDrop 
        ///     may still be used: this should be hidden in the property grid, but not in code
        ///  
        [Browsable(false)] 
        public override bool AllowDrop {
            get { 
                return richTextBoxFlags[allowOleDropSection] != 0;
            }
            set {
                if (value) { 
                    try
                    { 
                        IntSecurity.ClipboardRead.Demand(); 
                    }
                    catch (Exception e) 
                    {
                        throw new InvalidOperationException(SR.GetString(SR.DragDropRegFailed), e);
                    }
                } 
                richTextBoxFlags[allowOleDropSection] = value ? 1 : 0;
                UpdateOleCallback(); 
            } 
        }
 
        internal bool AllowOleObjects {
            get {
                return richTextBoxFlags[allowOleObjectsSection] != 0;
            } 
            set {
                richTextBoxFlags[allowOleObjectsSection] = value ? 1 : 0; 
            } 
        }
 
        /// 
        /// 
        ///    
        ///       Gets or sets a value indicating whether the size 
        ///       of the control automatically adjusts when the font assigned to the control
        ///       is changed. 
        /// 
        ///       Note: this works differently than other Controls' AutoSize, so we're hiding
        ///       it to avoid confusion. 
        ///    
        /// 
        [
        DefaultValue(false), 
        RefreshProperties(RefreshProperties.Repaint),
        Browsable(false), EditorBrowsable(EditorBrowsableState.Never), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible) 
        ]
        public override bool AutoSize { 
            get {
                return base.AutoSize;
            }
            set { 
                base.AutoSize = value;
            } 
        } 

        ///  
        /// 
        ///     Controls whether whether mouse selection snaps to whole words.
        /// 
        [ 
        SRCategory(SR.CatBehavior),
        DefaultValue(false), 
        SRDescription(SR.RichTextBoxAutoWordSelection) 
        ]
        public bool AutoWordSelection { 
            get { return richTextBoxFlags[autoWordSelectionSection] != 0; }
            set {
                richTextBoxFlags[autoWordSelectionSection] = value ? 1 : 0;
                if (IsHandleCreated) { 
                    SendMessage(RichTextBoxConstants.EM_SETOPTIONS,
                                value ? RichTextBoxConstants.ECOOP_OR : RichTextBoxConstants.ECOOP_XOR, 
                                RichTextBoxConstants.ECO_AUTOWORDSELECTION); 
                }
            } 
        }

        /// 
        ///  
        ///    [To be supplied.]
        ///  
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 
        public override Image BackgroundImage {
            get { 
                return base.BackgroundImage;
            }
            set {
                base.BackgroundImage = value; 
            }
        } 
 
        /// 
        ///  
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler BackgroundImageChanged {
            add {
                base.BackgroundImageChanged += value; 
            }
            remove { 
                base.BackgroundImageChanged -= value; 
            }
        } 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 
        public override ImageLayout BackgroundImageLayout { 
            get {
                return base.BackgroundImageLayout; 
            }
            set {
                base.BackgroundImageLayout = value;
            } 
        }
 
        ///  
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 
        new public event EventHandler BackgroundImageLayoutChanged {
            add {
                base.BackgroundImageLayoutChanged += value;
            } 
            remove {
                base.BackgroundImageLayoutChanged -= value; 
            } 
        }
 
        /// 
        /// 
        ///     Returns the amount of indent used in a RichTextBox control when
        ///     SelectionBullet is set to true. 
        /// 
        [ 
        SRCategory(SR.CatBehavior), 
        DefaultValue(0),
        Localizable(true), 
        SRDescription(SR.RichTextBoxBulletIndent)
        ]
        public int BulletIndent {
            get { 
                return bulletIndent;
            } 
 
            set {
 
                if (value < 0) {
                    throw new ArgumentOutOfRangeException("BulletIndent", SR.GetString(SR.InvalidArgument, "BulletIndent", (value).ToString(CultureInfo.CurrentCulture)));
                }
 
                this.bulletIndent = value;
 
                // Call to update the control only if the bullet is set. 
                if (IsHandleCreated && SelectionBullet)
                    SelectionBullet = true; 
            }
        }

        private bool CallOnContentsResized { 
            get { return richTextBoxFlags[callOnContentsResizedSection] != 0; }
            set { richTextBoxFlags[callOnContentsResizedSection] = value ? 1 : 0; } 
        } 

        internal override bool CanRaiseTextChangedEvent { 
            get {
                return !SuppressTextChangedEvent;
            }
        } 

        ///  
        ///  
        ///      Whether or not there are actions that can be Redone on the RichTextBox control.
        ///  
        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.RichTextBoxCanRedoDescr) 
        ]
        public bool CanRedo { 
            get { 
                if (IsHandleCreated) {
                    bool b; 
                    b = (int)SendMessage(RichTextBoxConstants.EM_CANREDO, 0, 0) != 0;

                    return b;
                } 
                return false;
            } 
        } 

        ///  
        /// 
        ///    [To be supplied.]
        /// 
        protected override CreateParams CreateParams { 
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
            get { 
                // Check for library 
                if (moduleHandle == IntPtr.Zero) {
                    moduleHandle = UnsafeNativeMethods.LoadLibrary(RichTextBoxConstants.DLL_RICHEDIT); 

                    int lastWin32Error = Marshal.GetLastWin32Error();
                    if ((long)moduleHandle < (long)32) {
                        throw new Win32Exception(lastWin32Error, SR.GetString(SR.LoadDLLError,RichTextBoxConstants.DLL_RICHEDIT)); 
                    }
 
                    //Determine whether we're Rich Edit 2.0 or 3.0: see 
                    //http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/richedit/richeditcontrols/aboutricheditcontrols.asp
                    StringBuilder pathBuilder = new StringBuilder(NativeMethods.MAX_PATH); 
                    UnsafeNativeMethods.GetModuleFileName(new HandleRef(null, moduleHandle), pathBuilder, pathBuilder.Capacity);
                    string path = pathBuilder.ToString();
                    new FileIOPermission(FileIOPermissionAccess.Read, path).Assert();
                    FileVersionInfo versionInfo; 
                    try {
                        versionInfo = FileVersionInfo.GetVersionInfo(path); 
                    } 
                    finally {
                        CodeAccessPermission.RevertAssert(); 
                    }
                    Debug.Assert(versionInfo != null && !string.IsNullOrEmpty(versionInfo.ProductVersion), "Couldn't get the version info for the richedit dll");
                    if (versionInfo != null && !string.IsNullOrEmpty(versionInfo.ProductVersion)) {
                        //Note: this only allows for one digit version 
                        int parsedValue;
                        if (int.TryParse(versionInfo.ProductVersion[0].ToString(), out parsedValue)) { 
                            richEditMajorVersion = parsedValue; 
                        }
                    } 
                }

                CreateParams cp = base.CreateParams;
                if (Marshal.SystemDefaultCharSize == 1) { 
                    cp.ClassName = RichTextBoxConstants.WC_RICHEDITA;
                } 
                else { 
                    cp.ClassName = RichTextBoxConstants.WC_RICHEDITW;
                } 

                if (Multiline) {
                    if (((int)ScrollBars & RichTextBoxConstants.RTB_HORIZ) != 0 && !WordWrap) {
                        // RichEd infers word wrap from the absence of horizontal scroll bars 
                        cp.Style |= NativeMethods.WS_HSCROLL;
                        if (((int)ScrollBars & RichTextBoxConstants.RTB_FORCE) != 0) 
                            cp.Style |= RichTextBoxConstants.ES_DISABLENOSCROLL; 
                    }
 
                    if (((int)ScrollBars & RichTextBoxConstants.RTB_VERT) != 0) {
                        cp.Style |= NativeMethods.WS_VSCROLL;
                        if (((int)ScrollBars & RichTextBoxConstants.RTB_FORCE) != 0)
                            cp.Style |= RichTextBoxConstants.ES_DISABLENOSCROLL; 
                    }
                } 
 
                // VSWhidbey 94843: Remove the WS_BORDER style from the control, if we're trying to set it,
                // to prevent the control from displaying the single point rectangle around the 3D border 
                if (BorderStyle.FixedSingle == BorderStyle && ((cp.Style & NativeMethods.WS_BORDER) != 0)) {
                    cp.Style &= (~NativeMethods.WS_BORDER);
                    cp.ExStyle |= NativeMethods.WS_EX_CLIENTEDGE;
                } 

                return cp; 
            } 
        }
 
        // public bool CanUndo {}; <-- inherited from TextBoxBase

        /// 
        ///  
        ///     Controls whether or not the rich edit control will automatically highlight URLs.
        ///     By default, this is true. Note that changing this property will not update text that is 
        ///     already present in the RichTextBox control; it only affects text which is entered after the 
        ///     property is changed.
        ///  
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(true),
        SRDescription(SR.RichTextBoxDetectURLs) 
        ]
        public bool DetectUrls { 
            get { 
                return richTextBoxFlags[autoUrlDetectSection] != 0;
            } 
            set {
                if (value != DetectUrls) {
                    richTextBoxFlags[autoUrlDetectSection] = value ? 1 : 0;
                    if (IsHandleCreated) { 
                        this.SendMessage(RichTextBoxConstants.EM_AUTOURLDETECT, value ? 1 : 0, 0);
                        RecreateHandle(); 
                    } 
                }
            } 
        }

        /// 
        protected override Size DefaultSize { 
            get {
                return new Size(100, 96); 
            } 
        }
 
        /// 
        /// 
        ///     We can't just enable drag/drop of text by default: it's a breaking change (VSWhidbey
        ///     375177).  Should be false by default. 
        /// 
        [ 
        SRCategory(SR.CatBehavior), 
        DefaultValue(false),
        SRDescription(SR.RichTextBoxEnableAutoDragDrop) 
        ]
        public bool EnableAutoDragDrop
        {
            get 
            {
                return richTextBoxFlags[enableAutoDragDropSection] != 0; 
            } 
            set
            { 
                if (value)
                {
                    try
                    { 
                        IntSecurity.ClipboardRead.Demand();
                    } 
                    catch (Exception e) 
                    {
                        throw new InvalidOperationException(SR.GetString(SR.DragDropRegFailed), e); 
                    }
                }
                richTextBoxFlags[enableAutoDragDropSection] = value ? 1 : 0;
                UpdateOleCallback(); 
            }
        } 
 
        /// 
        public override Color ForeColor { 
            get {
                return base.ForeColor;
            }
            set { 
                if (IsHandleCreated) {
                    if (InternalSetForeColor(value)) { 
                        base.ForeColor = value; 
                    }
                } 
                else {
                    base.ForeColor = value;
                }
            } 
        }
 
        ///  
        public override Font Font {
            get { 
                return base.Font;
            }
            set {
                if (IsHandleCreated) 
                {
                    if (SafeNativeMethods.GetWindowTextLength(new HandleRef(this, Handle)) > 0) { 
                        if (value == null) { 
                            base.Font = null;
                            SetCharFormatFont(false, Font); 
                        }
                        else {
                            try{
                                Font f = GetCharFormatFont(false); 
                                if (f == null || !f.Equals (value)) {
                                    SetCharFormatFont(false, value); 
                                    // update controlfont from "resolved" font from the attempt 
                                    // to set the document font...
                                    // 
                                    CallOnContentsResized = true;
                                    base.Font = GetCharFormatFont(false);
                                }
                            } 
                            finally{
                                CallOnContentsResized = false; 
                            } 
                        }
                    } 
                    else {
                        base.Font = value;
                    }
                } 
                else {
                    base.Font = value; 
                } 
            }
        } 

        internal override Size GetPreferredSizeCore(Size proposedConstraints) {
            Size scrollBarPadding = Size.Empty;
 
            //If the RTB is multiline, we won't have a horizontal scrollbar.
            if (!WordWrap && Multiline && (ScrollBars & RichTextBoxScrollBars.Horizontal) != 0) { 
                scrollBarPadding.Height += SystemInformation.HorizontalScrollBarHeight; 
            }
            if (Multiline && (ScrollBars & RichTextBoxScrollBars.Vertical) != 0) { 
                scrollBarPadding.Width += SystemInformation.VerticalScrollBarWidth;
            }

            // Subtract the scroll bar padding before measuring 
            proposedConstraints -= scrollBarPadding;
 
            Size prefSize = base.GetPreferredSizeCore(proposedConstraints); 

            return prefSize + scrollBarPadding; 
        }

        private bool InConstructor {
            get { return richTextBoxFlags[fInCtorSection] != 0; } 
            set { richTextBoxFlags[fInCtorSection] = value ? 1 : 0; }
        } 
 
        /// 
        ///     Sets or gets the rich text box control' language option. 
        ///     The IMF_AUTOFONT flag is set by default.
        ///     The IMF_AUTOKEYBOARD and IMF_IMECANCELCOMPLETE flags are cleared by default.
        /// 
        [ 
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) 
        ] 
        public RichTextBoxLanguageOptions LanguageOption
        { 
            get
            {
                RichTextBoxLanguageOptions opt;
                if (IsHandleCreated) { 
                    opt = (RichTextBoxLanguageOptions)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETLANGOPTIONS, 0, 0);
                } 
                else { 
                    opt = languageOption;
                } 
                return opt;
            }
            set
            { 
                if (this.LanguageOption != value)
                { 
                    this.languageOption = value; 
                    if (IsHandleCreated) {
                        UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETLANGOPTIONS, 0, (int) value); 
                    }
                }
            }
        } 

        private bool LinkCursor { 
            get { return richTextBoxFlags[linkcursorSection] != 0; } 
            set { richTextBoxFlags[linkcursorSection] = value ? 1 : 0; }
        } 

        /// 
        [
        DefaultValue(int.MaxValue), 
        ]
        public override int MaxLength { 
            get { 
                return base.MaxLength;
            } 
            set {
                base.MaxLength = value;
            }
        } 
        /// 
        ///  
        ///    [To be supplied.] 
        /// 
        [DefaultValue(true)] 
        public override bool Multiline {
            get {
                return base.Multiline;
            } 
            set {
                base.Multiline = value; 
            } 
        }
 
        private bool ProtectedError {
            get { return richTextBoxFlags[protectedErrorSection] != 0; }
            set { richTextBoxFlags[protectedErrorSection] = value ? 1 : 0; }
        } 

        ///  
        ///  
        ///     Returns the name of the action that will be performed if the user
        ///     Redo's their last Undone operation. If no operation can be redone, 
        ///     an empty string ("") is returned.
        /// 
        //NOTE: This is overridable, because we want people to be able to
        //      mess with the names if necessary...? 
        [
        SRCategory(SR.CatBehavior), 
        Browsable(false), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.RichTextBoxRedoActionNameDescr) 
        ]
        public string RedoActionName {
            get {
                if (!CanRedo) return ""; 
                int n;
                n = (int)SendMessage(RichTextBoxConstants.EM_GETREDONAME, 0, 0); 
                return GetEditorActionName(n); 
            }
        } 

        /// 
        //Description: Specifies whether rich text formatting keyboard shortcuts are enabled.
        [ 
        DefaultValue(true),
        Browsable(false), 
        EditorBrowsable(EditorBrowsableState.Never) 
        ]
        public bool RichTextShortcutsEnabled { 
            get { return richTextBoxFlags[richTextShortcutsEnabledSection] != 0; }
            set {
                if (shortcutsToDisable == null) {
                    shortcutsToDisable = new int[] {(int)Shortcut.CtrlL, (int)Shortcut.CtrlR, (int)Shortcut.CtrlE, (int)Shortcut.CtrlJ}; 
                }
                richTextBoxFlags[richTextShortcutsEnabledSection] = value ? 1 : 0; 
            } 
        }
 
        /// 
        /// 
        ///     The right margin of a RichTextBox control.  A nonzero margin implies WordWrap.
        ///  
        [
        SRCategory(SR.CatBehavior), 
        DefaultValue(0), 
        Localizable(true),
        SRDescription(SR.RichTextBoxRightMargin) 
        ]
        public int RightMargin {
            get {
                return rightMargin; 
            }
            set { 
                if (this.rightMargin != value) { 
                    if (value < 0)
                        throw new ArgumentOutOfRangeException("RightMargin", SR.GetString(SR.InvalidLowBoundArgumentEx, "RightMargin", value.ToString(CultureInfo.CurrentCulture), (0).ToString(CultureInfo.CurrentCulture))); 
                    this.rightMargin = value;

                    if (value == 0) {
                        // Once you set EM_SETTARGETDEVICE to something nonzero, RichEd will assume 
                        // word wrap forever and ever.
                        RecreateHandle(); 
                    } 
                    else if (IsHandleCreated) {
                        IntPtr hDC = UnsafeNativeMethods.CreateIC("DISPLAY", null, null, new HandleRef(null, IntPtr.Zero)); 
                        try {
                            SendMessage(RichTextBoxConstants.EM_SETTARGETDEVICE, hDC, (IntPtr)Pixel2Twip(hDC, value, true));
                        }
                        finally { 
                            if (hDC != IntPtr.Zero) {
                                UnsafeNativeMethods.DeleteDC(new HandleRef(null, hDC)); 
                            } 
                        }
                    } 
                }
            }
        }
 
        /// 
        ///  
        ///     The text of a RichTextBox control, including all Rtf codes. 
        /// 
        [ 
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.RichTextBoxRTF),
        RefreshProperties(RefreshProperties.All) 
        ]
        public string Rtf { 
            get { 
                if (IsHandleCreated)
                { 
                    return StreamOut(RichTextBoxConstants.SF_RTF);
                }
                else if (textPlain != null)
                { 
                    ForceHandleCreate();
                    return StreamOut(RichTextBoxConstants.SF_RTF); 
                } 
                else
                { 
                    return textRtf;
                }
            }
            set { 
                if (value == null) value = "";
 
                if (value.Equals(Rtf)) 
                    return;
 
                ForceHandleCreate();
                textRtf = value;
                StreamIn(value, RichTextBoxConstants.SF_RTF);
                if (CanRaiseTextChangedEvent) { 
                    OnTextChanged(EventArgs.Empty);
                } 
            } 
        }
 
        /// 
        /// 
        ///     The current scrollbar settings for a multi-line rich edit control.
        ///     Possible return values are given by the RichTextBoxScrollBars enumeration. 
        /// 
        [ 
        SRCategory(SR.CatAppearance), 
        DefaultValue(RichTextBoxScrollBars.Both),
        Localizable(true), 
        SRDescription(SR.RichTextBoxScrollBars)
        ]
        public RichTextBoxScrollBars ScrollBars {
            get { 
                return (RichTextBoxScrollBars) richTextBoxFlags[scrollBarsSection];
            } 
            set { 
                // we could be more clever here, but it doesnt seem like this would get set enough
                // to warrant a clever bitmask. 
                if (!ClientUtils.IsEnumValid_NotSequential(value,
                    (int)value,
                    (int)RichTextBoxScrollBars.Both,
                    (int)RichTextBoxScrollBars.None, 
                    (int)RichTextBoxScrollBars.Horizontal,
                    (int)RichTextBoxScrollBars.Vertical, 
                    (int)RichTextBoxScrollBars.ForcedHorizontal, 
                    (int)RichTextBoxScrollBars.ForcedVertical,
                    (int)RichTextBoxScrollBars.ForcedBoth)) { 

                    throw new InvalidEnumArgumentException("value", (int)value, typeof(RichTextBoxScrollBars));
                }
 
                if (value != ScrollBars) {
                    using (LayoutTransaction.CreateTransactionIf(AutoSize, ParentInternal, this, PropertyNames.ScrollBars)) { 
                        richTextBoxFlags[scrollBarsSection] = (int) value; 
                        RecreateHandle();
                    } 
                }
            }
        }
 
        /// 
        ///  
        ///     The alignment of the paragraphs in a RichTextBox control. 
        /// 
        [ 
        DefaultValue(HorizontalAlignment.Left),
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.RichTextBoxSelAlignment) 
        ]
        public HorizontalAlignment SelectionAlignment { 
            get { 
                HorizontalAlignment selectionAlignment = HorizontalAlignment.Left;
 
                ForceHandleCreate();
                NativeMethods.PARAFORMAT pf = new NativeMethods.PARAFORMAT();
                pf.rgxTabs = new int[RichTextBoxConstants.MAX_TAB_STOPS];
 
                // get the format for our currently selected paragraph
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETPARAFORMAT, 0, pf); 
 
                // check if alignment has been set yet
                if ((RichTextBoxConstants.PFM_ALIGNMENT & pf.dwMask) != 0) { 
                    switch (pf.wAlignment) {
                        case RichTextBoxConstants.PFA_LEFT:
                            selectionAlignment = HorizontalAlignment.Left;
                            break; 

                        case RichTextBoxConstants.PFA_RIGHT: 
                            selectionAlignment = HorizontalAlignment.Right; 
                            break;
 
                        case RichTextBoxConstants.PFA_CENTER:
                            selectionAlignment = HorizontalAlignment.Center;
                            break;
                    } 
                }
 
                return selectionAlignment; 
            }
            set { 
                //valid values are 0x0 to 0x2
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)HorizontalAlignment.Left, (int)HorizontalAlignment.Center))
                {
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(HorizontalAlignment)); 
                }
 
                ForceHandleCreate(); 
                NativeMethods.PARAFORMAT pf = new NativeMethods.PARAFORMAT();
                pf.dwMask = RichTextBoxConstants.PFM_ALIGNMENT; 
                switch (value) {

                    case HorizontalAlignment.Left:
                        pf.wAlignment = RichTextBoxConstants.PFA_LEFT; 
                        break;
 
                    case HorizontalAlignment.Right: 
                        pf.wAlignment = RichTextBoxConstants.PFA_RIGHT;
                        break; 

                    case HorizontalAlignment.Center:
                        pf.wAlignment = RichTextBoxConstants.PFA_CENTER;
                        break; 
                }
 
                // set the format for our current paragraph or selection 
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETPARAFORMAT, 0, pf);
            } 
        }

        /// 
        ///  
        ///     Determines if a paragraph in the RichTextBox control
        ///     contains the current selection or insertion point has the bullet style. 
        ///  
        [
        DefaultValue(false), 
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.RichTextBoxSelBullet)
        ] 
        public bool SelectionBullet {
            get { 
                RichTextBoxSelectionAttribute selectionBullet = RichTextBoxSelectionAttribute.None; 

                ForceHandleCreate(); 
                NativeMethods.PARAFORMAT pf = new NativeMethods.PARAFORMAT();
                pf.rgxTabs = new int[RichTextBoxConstants.MAX_TAB_STOPS];

                // get the format for our currently selected paragraph 
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETPARAFORMAT, 0, pf);
 
                // check if alignment has been set yet 
                if ((RichTextBoxConstants.PFM_NUMBERING & pf.dwMask) != 0) {
                    if (RichTextBoxConstants.PFN_BULLET == pf.wNumbering) { 
                        selectionBullet = RichTextBoxSelectionAttribute.All;
                    }
                }
                else { 
                    // For paragraphs with mixed SelectionBullets, we just return false
                    return false; 
                } 

                return selectionBullet == RichTextBoxSelectionAttribute.All; 
            }
            set {
                ForceHandleCreate();
 
                NativeMethods.PARAFORMAT pf = new NativeMethods.PARAFORMAT();
                pf.dwMask = RichTextBoxConstants.PFM_NUMBERING | RichTextBoxConstants.PFM_OFFSET; 
 
                if (!value) {
                    pf.wNumbering = 0; 
                    pf.dxOffset = 0;
                }
                else {
                    pf.wNumbering = RichTextBoxConstants.PFN_BULLET; 
                    pf.dxOffset = Pixel2Twip(IntPtr.Zero, bulletIndent, true);
                } 
                // set the format for our current paragraph or selection 
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETPARAFORMAT, 0, pf);
            } 
        }

        /// 
        ///  
        ///     Determines whether text in the RichTextBox control
        ///     appears on the baseline (normal), as a superscript above the baseline, 
        ///     or as a subscript below the baseline. 
        /// 
        [ 
        DefaultValue(0),
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.RichTextBoxSelCharOffset) 
        ]
        public int SelectionCharOffset { 
            get { 
                int selCharOffset = 0;
 
                ForceHandleCreate();
                NativeMethods.CHARFORMATA cf = GetCharFormat(true);
                // if the effects member contains valid info
                if ((cf.dwMask & RichTextBoxConstants.CFM_OFFSET) != 0) { 
                    selCharOffset = cf.yOffset;
                } 
                else { 
                    // The selection contains characters of different offsets,
                    // so we just return the offset of the first character. 
                    selCharOffset = cf.yOffset;
                }

                return Twip2Pixel(IntPtr.Zero,selCharOffset,false); 
            }
            set { 
                if (value > 2000 || value < -2000) 
                    throw new ArgumentOutOfRangeException("SelectionCharOffset", SR.GetString(SR.InvalidBoundArgument, "SelectionCharOffset", value, -2000, 2000));
 
                ForceHandleCreate();
                NativeMethods.CHARFORMATA cf = new NativeMethods.CHARFORMATA();
                cf.dwMask = RichTextBoxConstants.CFM_OFFSET;
                cf.yOffset = Pixel2Twip(IntPtr.Zero, value, false); 

                // Set the format information 
                // SendMessage will force the handle to be created if it hasn't already. Normally, 
                // we would cache property values until the handle is created - but for this property,
                // it's far more simple to just create the handle. 
                //
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETCHARFORMAT, RichTextBoxConstants.SCF_SELECTION, cf);
            }
        } 

        ///  
        ///  
        ///     The color of the currently selected text in the
        ///     RichTextBox control. 
        ///     Returns Color.Empty if the selection has more than one color.
        /// 
        [
        Browsable(false), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.RichTextBoxSelColor) 
        ] 
        public Color SelectionColor {
            get { 
                Color selColor = Color.Empty;

                ForceHandleCreate();
                NativeMethods.CHARFORMATA cf = GetCharFormat(true); 
                // if the effects member contains valid info
                if ((cf.dwMask & RichTextBoxConstants.CFM_COLOR) != 0) 
                    selColor = ColorTranslator.FromOle(cf.crTextColor); 

                return selColor; 
            }
            set {
                ForceHandleCreate();
                NativeMethods.CHARFORMATA cf = GetCharFormat(true); 
                cf.dwMask = RichTextBoxConstants.CFM_COLOR;
                cf.dwEffects = 0; 
                cf.crTextColor = ColorTranslator.ToWin32(value); 

                // set the format information 
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETCHARFORMAT, RichTextBoxConstants.SCF_SELECTION, cf);
            }
        }
 
        /// 
        ///  
        ///     The background color of the currently selected text in the RichTextBox control. 
        ///     Returns Color.Empty if the selection has more than one color.
        ///  
        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.RichTextBoxSelBackColor) 
        ]
        public Color SelectionBackColor { 
            get { 
                Color selColor = Color.Empty;
 
                if (IsHandleCreated) {
                    NativeMethods.CHARFORMAT2A cf2 = GetCharFormat2(true);
                    // If the effects member contains valid info
                    if ((cf2.dwEffects & RichTextBoxConstants.CFE_AUTOBACKCOLOR) != 0) { 
                        selColor = this.BackColor;
                    } 
                    else if ((cf2.dwMask & RichTextBoxConstants.CFM_BACKCOLOR) != 0) { 
                        selColor = ColorTranslator.FromOle(cf2.crBackColor);
                    } 
                }
                else {
                    selColor = selectionBackColorToSetOnHandleCreated;
                } 
                return selColor;
            } 
            set 
            {
                //Note: don't compare the value to the old value here: it's possible that 
                //you have a different range selected.
                selectionBackColorToSetOnHandleCreated = value;
                if (IsHandleCreated)
                { 
                    NativeMethods.CHARFORMAT2A cf2 = new NativeMethods.CHARFORMAT2A();
                    if (value == Color.Empty) 
                    { 
                        cf2.dwEffects = RichTextBoxConstants.CFE_AUTOBACKCOLOR;
                    } 
                    else
                    {
                        cf2.dwMask = RichTextBoxConstants.CFM_BACKCOLOR;
                        cf2.crBackColor = ColorTranslator.ToWin32(value); 
                    }
 
                    UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETCHARFORMAT, RichTextBoxConstants.SCF_SELECTION, cf2); 
                }
            } 
        }

        /// 
        ///  
        ///     The font used to display the currently selected text
        ///     or the characters(s) immediately following the insertion point in the 
        ///     RichTextBox control.  Null if the selection has more than one font. 
        /// 
        [ 
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.RichTextBoxSelFont)
        ] 
        public Font SelectionFont {
            get { 
                return GetCharFormatFont(true); 
            }
            set { 
                SetCharFormatFont(true, value);
            }
        }
 

        ///  
        ///  
        ///     The distance (in pixels) between the left edge of the first line of text
        ///     in the selected paragraph(s) (as specified by the SelectionIndent property) 
        ///     and the left edge of subsequent lines of text in the same paragraph(s).
        /// 
        [
        DefaultValue(0), 
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 
        SRDescription(SR.RichTextBoxSelHangingIndent) 
        ]
        public int SelectionHangingIndent { 
            get {
                int selHangingIndent = 0;

                ForceHandleCreate(); 
                NativeMethods.PARAFORMAT pf = new NativeMethods.PARAFORMAT();
                pf.rgxTabs = new int[RichTextBoxConstants.MAX_TAB_STOPS]; 
 
                // get the format for our currently selected paragraph
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETPARAFORMAT, 0, pf); 

                // check if alignment has been set yet
                if ((RichTextBoxConstants.PFM_OFFSET & pf.dwMask) != 0)
                    selHangingIndent = pf.dxOffset; 

                return Twip2Pixel(IntPtr.Zero, selHangingIndent, true); 
            } 
            set {
                ForceHandleCreate(); 

                NativeMethods.PARAFORMAT pf = new NativeMethods.PARAFORMAT();
                pf.dwMask = RichTextBoxConstants.PFM_OFFSET;
                pf.dxOffset = Pixel2Twip(IntPtr.Zero, value, true); 

                // set the format for our current paragraph or selection 
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETPARAFORMAT, 0, pf); 
            }
        } 

        /// 
        /// 
        ///     The distance (in pixels) between the left edge of the RichTextBox control and 
        ///     the left edge of the text that is selected or added at the current
        ///     insertion point. 
        ///  
        [
        DefaultValue(0), 
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.RichTextBoxSelIndent)
        ] 
        public int SelectionIndent {
            get { 
                int selIndent = 0; 

                ForceHandleCreate(); 
                NativeMethods.PARAFORMAT pf = new NativeMethods.PARAFORMAT();
                pf.rgxTabs = new int[RichTextBoxConstants.MAX_TAB_STOPS];

                // get the format for our currently selected paragraph 
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETPARAFORMAT, 0, pf);
 
                // check if alignment has been set yet 
                if ((RichTextBoxConstants.PFM_STARTINDENT & pf.dwMask) != 0)
                    selIndent = pf.dxStartIndent; 

                return Twip2Pixel(IntPtr.Zero, selIndent, true);
            }
            set { 
                ForceHandleCreate();
 
                NativeMethods.PARAFORMAT pf = new NativeMethods.PARAFORMAT(); 
                pf.dwMask = RichTextBoxConstants.PFM_STARTINDENT;
                pf.dxStartIndent = Pixel2Twip(IntPtr.Zero, value, true); 

                // set the format for our current paragraph or selection
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETPARAFORMAT, 0, pf);
            } 
        }
 
        ///  
        /// 
        ///     
        ///       Gets or sets the number of characters selected in the text
        ///       box.
        ///    
        ///  
        [
        SRCategory(SR.CatAppearance), 
        Browsable(false), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.TextBoxSelectionLengthDescr) 
        ]
        public override int SelectionLength {
            get {
 
                if (!IsHandleCreated) {
                    return base.SelectionLength; 
                } 

                // RichTextBox allows the user to select the EOF character, 
                // but we don't want to include this in the SelectionLength.
                // So instead of sending EM_GETSEL, we just obtain the SelectedText and return
                // the length of it.
                // 
                return SelectedText.Length;
            } 
 
            set {
                base.SelectionLength = value; 
            }
        }

        ///  
        /// 
        ///     true if the current selection prevents any changes to its contents. 
        ///  
        [
        DefaultValue(false), 
        SRDescription(SR.RichTextBoxSelProtected),
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ] 
        public bool SelectionProtected {
            get { 
                ForceHandleCreate(); 
                return GetCharFormat(RichTextBoxConstants.CFM_PROTECTED, RichTextBoxConstants.CFM_PROTECTED) == RichTextBoxSelectionAttribute.All;
            } 
            set {
                ForceHandleCreate();
                SetCharFormat(RichTextBoxConstants.CFM_PROTECTED, value ? RichTextBoxConstants.CFE_PROTECTED : 0, RichTextBoxSelectionAttribute.All);
            } 
        }
 
        ///  
        ///     Specifies whether the control uses unicode to set/get text selection information (WM_GESEL/WM_SETSEL)
        ///     in Win9x. 
        /// 
        internal override bool SelectionUsesDbcsOffsetsInWin9x {
            get {
                return false; // false for RichEdit, true for Edit. 
            }
        } 
 
        /// 
        ///  
        ///     The currently selected text of a RichTextBox control, including
        ///     all Rtf codes.
        /// 
        [ 
        DefaultValue(""),
        Browsable(false), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 
        SRDescription(SR.RichTextBoxSelRTF)
        ] 
        public string SelectedRtf {
            get {
                ForceHandleCreate();
                return StreamOut(RichTextBoxConstants.SFF_SELECTION | RichTextBoxConstants.SF_RTF); 
            }
            set { 
                ForceHandleCreate(); 
                if (value == null) value = "";
                StreamIn(value, RichTextBoxConstants.SFF_SELECTION | RichTextBoxConstants.SF_RTF); 
            }
        }

        ///  
        /// 
        ///     The distance (in pixels) between the right edge of the RichTextBox control and 
        ///     the right edge of the text that is selected or added at the current 
        ///     insertion point.
        ///  
        [
        DefaultValue(0),
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 
        SRDescription(SR.RichTextBoxSelRightIndent)
        ] 
        public int SelectionRightIndent { 
            get {
                int selRightIndent = 0; 

                ForceHandleCreate();

                NativeMethods.PARAFORMAT pf = new NativeMethods.PARAFORMAT(); 
                pf.rgxTabs = new int[RichTextBoxConstants.MAX_TAB_STOPS];
 
                // get the format for our currently selected paragraph 
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETPARAFORMAT, 0, pf);
 
                // check if alignment has been set yet
                if ((RichTextBoxConstants.PFM_RIGHTINDENT & pf.dwMask) != 0)
                    selRightIndent = pf.dxRightIndent;
 
                return Twip2Pixel(IntPtr.Zero, selRightIndent, true);
            } 
            set { 
                if (value < 0)
                    throw new ArgumentOutOfRangeException("SelectionRightIndent", SR.GetString(SR.InvalidLowBoundArgumentEx, "SelectionRightIndent", value, 0)); 

                ForceHandleCreate();
                NativeMethods.PARAFORMAT pf = new NativeMethods.PARAFORMAT();
                pf.dwMask = RichTextBoxConstants.PFM_RIGHTINDENT; 
                pf.dxRightIndent = Pixel2Twip(IntPtr.Zero, value, true);
 
                // set the format for our current paragraph or selection 
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETPARAFORMAT, 0, pf);
            } 
        }

        /// 
        ///  
        ///     The absolute tab positions (in pixels) of text in a RichTextBox control.
        ///  
        [ 
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 
        SRDescription(SR.RichTextBoxSelTabs)
        ]
        public int[] SelectionTabs {
            get { 
                int[] selTabs = new int[0];
 
                ForceHandleCreate(); 
                NativeMethods.PARAFORMAT pf = new NativeMethods.PARAFORMAT();
                pf.rgxTabs = new int[RichTextBoxConstants.MAX_TAB_STOPS]; 

                // get the format for our currently selected paragraph
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETPARAFORMAT, 0, pf);
 
                // check if alignment has been set yet
                if ((RichTextBoxConstants.PFM_TABSTOPS & pf.dwMask) != 0) { 
                    selTabs = new int[pf.cTabCount]; 
                    for (int x = 0; x < pf.cTabCount; x++)
                        selTabs[x] = Twip2Pixel(IntPtr.Zero, pf.rgxTabs[x], true); 
                }

                return selTabs;
            } 
            set {
                // Verify the argument, and throw an error if is bad 
                if (value != null && value.Length > RichTextBoxConstants.MAX_TAB_STOPS) 
                    throw new ArgumentOutOfRangeException("SelectionTabs", SR.GetString(SR.SelTabCountRange));
 
                ForceHandleCreate();
                NativeMethods.PARAFORMAT pf = new NativeMethods.PARAFORMAT();
                pf.rgxTabs = new int[RichTextBoxConstants.MAX_TAB_STOPS];
 
                // get the format for our currently selected paragraph because
                // we need to get the number of tabstops to copy 
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETPARAFORMAT, 0, pf); 

                pf.cTabCount = (short)((value == null) ? 0 : value.Length); 
                pf.dwMask = RichTextBoxConstants.PFM_TABSTOPS;
                for (int x = 0; x < pf.cTabCount; x++)
                    pf.rgxTabs[x] = Pixel2Twip(IntPtr.Zero, value[x], true);
 
                // set the format for our current paragraph or selection
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETPARAFORMAT, 0, pf); 
            } 
        }
 
        /// 
        /// 
        ///     The currently selected text of a RichTextBox control; consists of a
        ///     zero length string if no characters are selected. 
        /// 
        [ 
        DefaultValue(""), 
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 
        SRDescription(SR.RichTextBoxSelText)
        ]
        public override string SelectedText {
            get { 
                ForceHandleCreate();
 
                String text = StreamOut(RichTextBoxConstants.SFF_SELECTION | RichTextBoxConstants.SF_TEXT | RichTextBoxConstants.SF_UNICODE); 
                return text;
            } 
            set {
                ForceHandleCreate();
                StreamIn(value, RichTextBoxConstants.SFF_SELECTION | RichTextBoxConstants.SF_TEXT | RichTextBoxConstants.SF_UNICODE);
            } 
        }
 
        ///  
        /// 
        ///     The type of the current selection. The returned value is one 
        ///     of the values enumerated in RichTextBoxSelectionType.
        /// 
        [
        SRCategory(SR.CatBehavior), 
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 
        SRDescription(SR.RichTextBoxSelTypeDescr) 
        ]
        public RichTextBoxSelectionTypes SelectionType { 
            get {
                ForceHandleCreate();
                if (SelectionLength > 0) {
                    int n; 
                    n =  (int)SendMessage(RichTextBoxConstants.EM_SELECTIONTYPE, 0, 0);
                    return (RichTextBoxSelectionTypes)n; 
                } 
                else {
                    return RichTextBoxSelectionTypes.Empty; 
                }
            }
        }
 
        /// 
        ///  
        ///     Whether or not the left edge of the control will have a "selection margin" which 
        ///     can be used to select entire lines
        ///  
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(false),
        SRDescription(SR.RichTextBoxSelMargin) 
        ]
        public bool ShowSelectionMargin { 
            get { return richTextBoxFlags[showSelBarSection] != 0; } 
            set {
                if (value != ShowSelectionMargin) { 
                    richTextBoxFlags[showSelBarSection] = value ? 1 : 0;
                    if (IsHandleCreated) {
                        SendMessage(RichTextBoxConstants.EM_SETOPTIONS,
                            value ? RichTextBoxConstants.ECOOP_OR : 
                            RichTextBoxConstants.ECOOP_XOR,
                            RichTextBoxConstants.ECO_SELECTIONBAR); 
                    } 
                }
            } 
        }

        /// 
        ///  
        ///    [To be supplied.]
        ///  
        [ 
        Localizable(true),
        RefreshProperties(RefreshProperties.All) 
        ]
        public override string Text {
            get {
                if (IsDisposed) { 
                    return base.Text;
                } 
 
                if (RecreatingHandle || GetAnyDisposingInHierarchy()) {
                    // We can return any old garbage if we're in the process of recreating the handle 
                    return "";
                }

                if (!IsHandleCreated && textRtf == null) { 
                    if (textPlain != null) {
                        return textPlain; 
                    } 
                    else {
                        return base.Text; 
                    }
                }
                else {
                    // if the handle is created, we are golden, however 
                    // if the handle isn't created, but textRtf was
                    // specified, we need the RichEdit to translate 
                    // for us, so we must create the handle; 
                    //
                    ForceHandleCreate(); 

                    return StreamOut(RichTextBoxConstants.SF_TEXT | RichTextBoxConstants.SF_UNICODE);
                }
            } 
            set {
                using(LayoutTransaction.CreateTransactionIf(AutoSize, ParentInternal, this, PropertyNames.Text)) { 
                    textRtf = null; 
                    if (!IsHandleCreated) {
                        textPlain = value; 
                    }
                    else {
                        textPlain = null;
                        if (value == null) { 
                            value = "";
                        } 
                        StreamIn(value, RichTextBoxConstants.SF_TEXT | RichTextBoxConstants.SF_UNICODE); 
                        // reset Modified
                        SendMessage(NativeMethods.EM_SETMODIFY, 0, 0); 
                    }
                }
            }
        } 

        private bool SuppressTextChangedEvent { 
            get { return richTextBoxFlags[suppressTextChangedEventSection] != 0; } 
            set {
                bool oldValue = SuppressTextChangedEvent; 
                if (value != oldValue) {
                    richTextBoxFlags[suppressTextChangedEventSection] = value ? 1 : 0;
                    CommonProperties.xClearPreferredSizeCache(this);
                } 
            }
        } 
 
        /// 
        [Browsable(false)] 
        public override int TextLength {
            get
            {
                NativeMethods.GETTEXTLENGTHEX gtl = new NativeMethods.GETTEXTLENGTHEX(); 

                gtl.flags = RichTextBoxConstants.GTL_NUMCHARS; 
 
                if (Marshal.SystemDefaultCharSize == 1 /*ANSI*/)
                { 
                    gtl.codepage = 0;  /* CP_ANSI */;
                }
                else
                { 
                    gtl.codepage = 1200; /* CP_UNICODE */
                } 
 
                return (int) UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETTEXTLENGTHEX, gtl, 0 /*ignored*/);
            } 
        }

        /// 
        ///  
        ///     Returns the name of the action that will be undone if the user
        ///     Undo's their last operation. If no operation can be undone, it will 
        ///     return an empty string (""). 
        /// 
        //NOTE: This is overridable, because we want people to be able to 
        //      mess with the names if necessary...?
        [
        SRCategory(SR.CatBehavior),
        Browsable(false), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.RichTextBoxUndoActionNameDescr) 
        ] 
        public string UndoActionName {
            get { 
                if (!CanUndo) return "";
                int n;
                n = (int)SendMessage(RichTextBoxConstants.EM_GETUNDONAME, 0, 0);
                return GetEditorActionName(n); 
            }
        } 
 
        private string GetEditorActionName(int actionID) {
            switch (actionID) { 
                case 0:
                    return SR.GetString(SR.RichTextBox_IDUnknown);
                case 1:
                    return SR.GetString(SR.RichTextBox_IDTyping); 
                case 2:
                    return SR.GetString(SR.RichTextBox_IDDelete); 
                case 3: 
                    return SR.GetString(SR.RichTextBox_IDDragDrop);
                case 4: 
                    return SR.GetString(SR.RichTextBox_IDCut);
                case 5:
                    return SR.GetString(SR.RichTextBox_IDPaste);
                default: 
                    goto
                case 0; 
            } 
        }
 
        /// 
        /// 
        ///     The current zoom level for the RichTextBox control. This may be between 1/64 and 64. 1.0 indicates
        ///     no zoom (i.e. normal viewing).  Zoom works best with TrueType fonts; 
        ///     for non-TrueType fonts, ZoomFactor will be treated as the nearest whole number.
        ///  
        [ 
        SRCategory(SR.CatBehavior),
        DefaultValue(1.0f), 
        Localizable(true),
        SRDescription(SR.RichTextBoxZoomFactor)
        ]
        public float ZoomFactor { 
            get {
                if (IsHandleCreated) { 
                    int numerator = 0; 
                    int denominator = 0;
                    SendMessage(RichTextBoxConstants.EM_GETZOOM, ref numerator, ref denominator); 
                    if ( (numerator != 0) && (denominator != 0) ) {
                        zoomMultiplier = ((float)numerator)/((float)denominator);
                    }
                    else { 
                        zoomMultiplier = 1.0f;
                    } 
                    return zoomMultiplier; 
                }
                else return zoomMultiplier; 
            }

            set {
                if (zoomMultiplier == value) return; 

                if (value <= 0.015625f || value >= 64.0f) 
                    throw new ArgumentOutOfRangeException("ZoomFactor", SR.GetString(SR.InvalidExBoundArgument, "ZoomFactor", (value).ToString(CultureInfo.CurrentCulture), (0.015625f).ToString(CultureInfo.CurrentCulture), (64.0f).ToString(CultureInfo.CurrentCulture))); 
                SendZoomFactor(value);
            } 
        }


        ///  
        /// 
        ///    [To be supplied.] 
        ///  
        [SRCategory(SR.CatBehavior), SRDescription(SR.RichTextBoxContentsResized)]
        public event ContentsResizedEventHandler ContentsResized { 
            add {
                Events.AddHandler(EVENT_REQUESTRESIZE, value);
            }
            remove { 
                Events.RemoveHandler(EVENT_REQUESTRESIZE, value);
            } 
        } 

 
        /// 
        /// 
        ///     RichTextBox controls have built-in drag and drop support, but AllowDrop, DragEnter, DragDrop
        ///     may still be used: this should be hidden in the property grid, but not in code 
        /// 
        [Browsable(false)] 
        public new event DragEventHandler DragDrop { 
            add {
                base.DragDrop += value; 
            }
            remove {
                base.DragDrop -= value;
            } 
        }
 
        ///  
        /// 
        ///     RichTextBox controls have built-in drag and drop support, but AllowDrop, DragEnter, DragDrop 
        ///     may still be used: this should be hidden in the property grid, but not in code
        /// 
        [Browsable(false)]
        public new event DragEventHandler DragEnter { 
            add {
                base.DragEnter += value; 
            } 
            remove {
                base.DragEnter -= value; 
            }
        }

        ///  
        /// 
        ///    [To be supplied.] 
        ///  
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler DragLeave { 
            add {
                base.DragLeave += value;
            }
            remove { 
                base.DragLeave -= value;
            } 
        } 

        ///  
        /// 
        ///    [To be supplied.]
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 
        public new event DragEventHandler DragOver {
            add { 
                base.DragOver += value; 
            }
            remove { 
                base.DragOver -= value;
            }
        }
 
        /// 
        ///  
        ///    [To be supplied.] 
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 
        public new event GiveFeedbackEventHandler GiveFeedback {
            add {
                base.GiveFeedback += value;
            } 
            remove {
                base.GiveFeedback -= value; 
            } 
        }
 
        /// 
        /// 
        ///    [To be supplied.]
        ///  
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event QueryContinueDragEventHandler QueryContinueDrag { 
            add { 
                base.QueryContinueDrag += value;
            } 
            remove {
                base.QueryContinueDrag -= value;
            }
        } 

        ///  
        ///  
        ///    [To be supplied.]
        ///  
        [SRCategory(SR.CatBehavior), SRDescription(SR.RichTextBoxHScroll)]
        public event EventHandler HScroll {
            add {
                Events.AddHandler(EVENT_HSCROLL, value); 
            }
            remove { 
                Events.RemoveHandler(EVENT_HSCROLL, value); 
            }
        } 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
        [SRCategory(SR.CatBehavior), SRDescription(SR.RichTextBoxLinkClick)] 
        public event LinkClickedEventHandler LinkClicked { 
            add {
                Events.AddHandler(EVENT_LINKACTIVATE, value); 
            }
            remove {
                Events.RemoveHandler(EVENT_LINKACTIVATE, value);
            } 
        }
 
 
        /// 
        ///  
        ///    [To be supplied.]
        /// 
        [SRCategory(SR.CatBehavior), SRDescription(SR.RichTextBoxIMEChange)]
        public event EventHandler ImeChange { 
            add {
                Events.AddHandler(EVENT_IMECHANGE, value); 
            } 
            remove {
                Events.RemoveHandler(EVENT_IMECHANGE, value); 
            }
        }

 
        /// 
        ///  
        ///    [To be supplied.] 
        /// 
        [SRCategory(SR.CatBehavior), SRDescription(SR.RichTextBoxProtected)] 
        public event EventHandler Protected {
            add {
                Events.AddHandler(EVENT_PROTECTED, value);
            } 
            remove {
                Events.RemoveHandler(EVENT_PROTECTED, value); 
            } 
        }
 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
        [SRCategory(SR.CatBehavior), SRDescription(SR.RichTextBoxSelChange)] 
        public event EventHandler SelectionChanged { 
            add {
                Events.AddHandler(EVENT_SELCHANGE, value); 
            }
            remove {
                Events.RemoveHandler(EVENT_SELCHANGE, value);
            } 
        }
 
 
        /// 
        ///  
        ///    [To be supplied.]
        /// 
        [SRCategory(SR.CatBehavior), SRDescription(SR.RichTextBoxVScroll)]
        public event EventHandler VScroll { 
            add {
                Events.AddHandler(EVENT_VSCROLL, value); 
            } 
            remove {
                Events.RemoveHandler(EVENT_VSCROLL, value); 
            }
        }

        ///  
        /// 
        ///     Returns a boolean indicating whether the RichTextBoxConstants control can paste the 
        ///     given clipboard format. 
        /// 
        public bool CanPaste(DataFormats.Format clipFormat) { 
            bool b = false;
            b = (int)SendMessage(RichTextBoxConstants.EM_CANPASTE, clipFormat.Id, 0) != 0;

            return b; 
        }
 
        //DrawToBitmap doesn't work for this control, so we should hide it.  We'll 
        //still call base so that this has a chance to work if it can.
        [EditorBrowsable(EditorBrowsableState.Never)] 
        new public void DrawToBitmap(Bitmap bitmap, Rectangle targetBounds)
        {
            base.DrawToBitmap(bitmap, targetBounds);
        } 

        private unsafe int EditStreamProc(IntPtr dwCookie, IntPtr buf, int cb, out int transferred) { 
            int ret = 0;    // assume that everything is Okay 

            byte[] bytes = new byte[cb]; 

            int cookieVal = (int)dwCookie;

            transferred = 0; 
            try {
                switch (cookieVal & DIRECTIONMASK) { 
                    case RichTextBox.OUTPUT: { 
                        if (editStream == null) {
                            editStream = new MemoryStream(); 
                        }

                        switch (cookieVal & KINDMASK) {
                            case RichTextBox.RTF: 
                            case RichTextBox.TEXTCRLF:
                                Marshal.Copy(buf, bytes, 0, cb); 
                                editStream.Write(bytes, 0, cb); 
                                break;
                            case RichTextBox.TEXTLF: 
                            // Strip out \r characters so that we consistently return
                            // \n for linefeeds. In a future version the RichEdit control
                            // may support a SF_NOXLATCRLF flag which would do this for
                            // us. Internally the RichEdit stores the text with only 
                            // a \n, so we want to keep that the same here.
                            // 
                            if ((cookieVal & UNICODE) != 0) { 
                                Debug.Assert(cb % 2 == 0, "EditStreamProc call out of cycle. Expected to always get character boundary calls");
                                int requestedCharCount = cb/2; 
                                int consumedCharCount = 0;

                                fixed (byte* pb = bytes) {
                                    char* pChars = (char*)pb; 
                                    char* pBuffer = (char*)(long)buf;
 
                                    for (int i=0; i
        ///  
        ///     Searches the text in a RichTextBox control for a given string.
        /// 
        public int Find(string str) {
            return Find(str, 0, 0, RichTextBoxFinds.None); 
        }
 
        ///  
        /// 
        ///     Searches the text in a RichTextBox control for a given string. 
        /// 
        public int Find(string str, RichTextBoxFinds options) {
            return Find(str, 0, 0, options);
        } 

        ///  
        ///  
        ///     Searches the text in a RichTextBox control for a given string.
        ///  
        public int Find(string str, int start, RichTextBoxFinds options) {
            return Find(str, start, -1, options);
        }
 
        /// 
        ///  
        ///     Searches the text in a RichTextBox control for a given string. 
        /// 
        public int Find(string str, int start, int end, RichTextBoxFinds options) { 

            int textLen = TextLength;

            if (str == null) 
                throw new ArgumentNullException("str");
            if (start < 0 || start > textLen) 
                throw new ArgumentOutOfRangeException("start", SR.GetString(SR.InvalidBoundArgument, "start", start, 0, textLen)); 
            if (end < -1)
                throw new ArgumentOutOfRangeException("end", SR.GetString(SR.RichTextFindEndInvalid, end)); 

            bool selectWord = true;
            NativeMethods.FINDTEXT ft = new NativeMethods.FINDTEXT();
            ft.chrg = new NativeMethods.CHARRANGE(); 

            // set up the default values for the FINDTEXT structure, that is 
            // the given string and the whole range of the text stream 
            ft.lpstrText = str;
            if (end == -1) { 
                end = textLen;
            }

            if (start > end) { 
                throw new ArgumentException(SR.GetString(SR.RichTextFindEndInvalid, end));
            } 
 
            if ((options & RichTextBoxFinds.Reverse) != RichTextBoxFinds.Reverse) {
                // normal 
                //
                ft.chrg.cpMin = start;
                ft.chrg.cpMax = end;
            } 
            else {
                // reverse 
                // 
                ft.chrg.cpMin = end;
                ft.chrg.cpMax = start; 
            }

            // force complete search if we ended up with a zero length search
            if (ft.chrg.cpMin == ft.chrg.cpMax) { 
                if ((options & RichTextBoxFinds.Reverse) != RichTextBoxFinds.Reverse) {
                    ft.chrg.cpMin = 0; 
                    ft.chrg.cpMax = -1; 
                }
                else { 
                    ft.chrg.cpMin = textLen;
                    ft.chrg.cpMax = 0;
                }
            } 

            // set up the options for the search 
            int findOptions = 0; 
            if ((options & RichTextBoxFinds.WholeWord) == RichTextBoxFinds.WholeWord)
                findOptions |= RichTextBoxConstants.FR_WHOLEWORD; 
            if ((options & RichTextBoxFinds.MatchCase) == RichTextBoxFinds.MatchCase)
                findOptions |= RichTextBoxConstants.FR_MATCHCASE;
            if ((options & RichTextBoxFinds.NoHighlight) == RichTextBoxFinds.NoHighlight)
                selectWord = false; 
            if ((options & RichTextBoxFinds.Reverse) != RichTextBoxFinds.Reverse) {
                // The default for RichEdit 2.0 is to search in reverse 
                findOptions |= RichTextBoxConstants.FR_DOWN; 
            }
 
            // Perform the find, will return ubyte position
            int position;

            position = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_FINDTEXT, findOptions, ft); 

 
            // if we didn't find anything, or we don't have to select what was found, 
            // we're done
            if (position != -1 && selectWord) { 
                // Select the string found, this is done in ubyte units
                NativeMethods.CHARRANGE chrg = new NativeMethods.CHARRANGE();
                chrg.cpMin = position;
                //Look for kashidas in the string.  A kashida is an arabic visual justification character 
                //that's not semantically meaningful.  Searching for ABC might find AB_C (where A,B, and C
                //represent Arabic characters and _ represents a kashida).  We should highlight the text 
                //including the kashida (VSWhidbey 94809). 
                char kashida = (char)0x640;
                string text = this.Text; 
                string foundString = text.Substring(position, str.Length);
                int startIndex = foundString.IndexOf(kashida);
                if (startIndex == -1)
                { 
                    //No kashida in the string
                    chrg.cpMax = position + str.Length; 
                } 
                else
                { 
                    //There's at least one kashida
                    int searchingCursor; //index into search string
                    int foundCursor; //index into Text
                    for (searchingCursor = startIndex, foundCursor = position + startIndex; searchingCursor < str.Length; 
                        searchingCursor++, foundCursor++)
                    { 
                        while (text[foundCursor] == kashida && str[searchingCursor] != kashida) 
                        {
                            foundCursor++; 
                        }
                    }
                    chrg.cpMax = foundCursor;
                } 

                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_EXSETSEL, 0, chrg); 
                SendMessage(NativeMethods.EM_SCROLLCARET, 0, 0); 

            } 

            return position;
        }
 
        /// 
        ///  
        ///     Searches the text in a RichTextBox control for the given characters. 
        /// 
        public int Find(char[] characterSet) { 
            return Find(characterSet, 0, -1);
        }

        ///  
        /// 
        ///     Searches the text in a RichTextBox control for the given characters. 
        ///  
        public int Find(char[] characterSet, int start) {
            return Find(characterSet, start, -1); 
        }

        /// 
        ///  
        ///     Searches the text in a RichTextBox control for the given characters.
        ///  
        public int Find(char[] characterSet, int start, int end) { 
            // Code used to support ability to search backwards and negate character sets.
            // The API no longer supports this, but in case we change our mind, I'm leaving 
            // the ability in here.
            bool forward = true;
            bool negate = false;
 
            int textLength = TextLength;
 
            if (characterSet == null) 
                throw new ArgumentNullException("characterSet");
            if (start < 0 || start > textLength) 
                throw new ArgumentOutOfRangeException("start", SR.GetString(SR.InvalidBoundArgument, "start", start, 0, textLength));
            if (end < start && end != -1)
                throw new ArgumentOutOfRangeException("end", SR.GetString(SR.InvalidLowBoundArgumentEx, "end", end, "start"));
 
            // Don't do anything if we get nothing to look for
            if (characterSet.Length == 0) 
                return -1; 

            int textLen = SafeNativeMethods.GetWindowTextLength(new HandleRef(this, Handle)); 
            if (start == end) {
                start = 0;
                end = textLen;
            } 
            if (end == -1) {
                end = textLen; 
            } 

            NativeMethods.CHARRANGE chrg = new NativeMethods.CHARRANGE(); // The range of characters we have searched 
            chrg.cpMax = chrg.cpMin = start;

            // Use the TEXTRANGE to move our text buffer forward
            // or backwards within the main text 
            NativeMethods.TEXTRANGE txrg = new NativeMethods.TEXTRANGE(); // Characters we have slurped into memory in order to search
            txrg.chrg = new NativeMethods.CHARRANGE(); 
 
            txrg.chrg.cpMin = chrg.cpMin;
            txrg.chrg.cpMax = chrg.cpMax; 
            UnsafeNativeMethods.CharBuffer charBuffer;
            charBuffer = UnsafeNativeMethods.CharBuffer.CreateBuffer(CHAR_BUFFER_LEN + 1);

            txrg.lpstrText = charBuffer.AllocCoTaskMem(); 
            if (txrg.lpstrText == IntPtr.Zero)
                throw new OutOfMemoryException(); 
 
            try {
                bool done = false; 

                // We want to loop as long as it takes.  This loop will grab a
                // chunk of text out from the control as directed by txrg.chrg;
                while (!done) { 
                    if (forward) {
                        // Move forward by starting at the end of the 
                        // previous text window and extending by the 
                        // size of our buffer
                        txrg.chrg.cpMin = chrg.cpMax; 
                        txrg.chrg.cpMax += CHAR_BUFFER_LEN;
                    }
                    else {
                        // Move backwards by anchoring at the start 
                        // of the previous buffer window, and backing
                        // up by the desired size of our buffer 
                        txrg.chrg.cpMax = chrg.cpMin; 
                        txrg.chrg.cpMin -= CHAR_BUFFER_LEN;
 
                        // We need to keep our request within the
                        // lower bound of zero
                        if (txrg.chrg.cpMin < 0)
                            txrg.chrg.cpMin = 0; 
                    }
 
                    if (end != -1) 
                        txrg.chrg.cpMax = Math.Min(txrg.chrg.cpMax, end);
 
                    // go get the text in this range, if we didn't get any text then punt
                    int len;
                    len = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETTEXTRANGE, 0, txrg);
                    if (len == 0) { 
                        chrg.cpMax = chrg.cpMin = -1; // Hit end of control without finding what we wanted
                        break; 
                    } 

                    // get the data from RichTextBoxConstants into a string for us to use. 
                    charBuffer.PutCoTaskMem(txrg.lpstrText);
                    string str = charBuffer.GetString();

                    // Loop through our text 
                    if (forward) {
                        // Start at the begining of the buffer 
                        for (int x = 0; x < len; x++) { 
                            // Is it in char set?
                            bool found = GetCharInCharSet(str[x], characterSet, negate); 

                            if (found) {
                                done = true;
                                break; 
                            }
 
                            // Advance the buffer 
                            chrg.cpMax++;
                        } 
                    }
                    else { // Span reverse.
                        int x = len;
                        while (x-- != 0) { 
                            // Is it in char set?
                            bool found = GetCharInCharSet(str[x], characterSet, negate); 
 
                            if (found) {
                                done = true; 
                                break;
                            }

                            // Bring the selection back while keeping it anchored 
                            chrg.cpMin--;
                        } 
                    } 
                }
            } 
            finally {
                // release the resources we got for our GETTEXTRANGE operation.
                if (txrg.lpstrText != IntPtr.Zero) Marshal.FreeCoTaskMem(txrg.lpstrText);
            } 

            int index = (forward) ? chrg.cpMax : chrg.cpMin; 
            return index; 
        }
 
        private void ForceHandleCreate() {
            if (!IsHandleCreated)
            {
                CreateHandle(); 
            }
        } 
 
        // Sends set color message to HWND; doesn't call Control.SetForeColor
        private bool InternalSetForeColor(Color value) { 
            NativeMethods.CHARFORMATA cf = GetCharFormat(false);
            if ((cf.dwMask & RichTextBoxConstants.CFM_COLOR) != 0
                && ColorTranslator.ToWin32(value) == cf.crTextColor) {
 
                return true;
            } 
 
            cf.dwMask = RichTextBoxConstants.CFM_COLOR;
            cf.dwEffects = 0; 
            cf.crTextColor = ColorTranslator.ToWin32(value);
            return SetCharFormat(RichTextBoxConstants.SCF_ALL, cf);
        }
 

        private NativeMethods.CHARFORMATA GetCharFormat(bool fSelection) { 
            NativeMethods.CHARFORMATA cf = new NativeMethods.CHARFORMATA(); 
            UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETCHARFORMAT, fSelection ? RichTextBoxConstants.SCF_SELECTION : RichTextBoxConstants.SCF_DEFAULT, cf);
            return cf; 
        }

        private NativeMethods.CHARFORMAT2A GetCharFormat2(bool fSelection) {
            NativeMethods.CHARFORMAT2A cf2 = new NativeMethods.CHARFORMAT2A(); 
            UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETCHARFORMAT, fSelection ? RichTextBoxConstants.SCF_SELECTION : RichTextBoxConstants.SCF_DEFAULT, cf2);
            return cf2; 
        } 

        ///  
        /// 
        /// 
        /// 
        private RichTextBoxSelectionAttribute GetCharFormat(int mask, int effect) { 
            RichTextBoxSelectionAttribute charFormat = RichTextBoxSelectionAttribute.None;
 
            // check to see if the control has been created 
            if (IsHandleCreated) {
                NativeMethods.CHARFORMATA cf = GetCharFormat(true); 
                // if the effects member contains valid info
                if ((cf.dwMask & mask) != 0)
                    // if the text has the desired effect
                    if ((cf.dwEffects & effect) != 0) 
                        charFormat = RichTextBoxSelectionAttribute.All;
            } 
 
            return charFormat;
        } 

        Font GetCharFormatFont(bool selectionOnly) {
            ForceHandleCreate();
 
            NativeMethods.CHARFORMATA cf = GetCharFormat(selectionOnly);
            if ((cf.dwMask & RichTextBoxConstants.CFM_FACE) == 0) { 
                return null; 
            }
 
            string fontName = Encoding.Default.GetString(cf.szFaceName);
            int index = fontName.IndexOf('\0');
            if (index != -1) {
                fontName = fontName.Substring(0, index); 
            }
 
            float fontSize = 13; 
            if ((cf.dwMask & RichTextBoxConstants.CFM_SIZE) != 0) {
                fontSize = (float)cf.yHeight/(float)20.0; 
                if (fontSize == 0 && cf.yHeight > 0) {
                    fontSize = 1;
                }
            } 

            FontStyle style = FontStyle.Regular; 
            if ((cf.dwMask & RichTextBoxConstants.CFM_BOLD) != 0 && (cf.dwEffects & RichTextBoxConstants.CFE_BOLD) != 0) 
                style |= FontStyle.Bold;
            if ((cf.dwMask & RichTextBoxConstants.CFM_ITALIC) != 0 && (cf.dwEffects & RichTextBoxConstants.CFE_ITALIC) != 0) 
                style |= FontStyle.Italic;
            if ((cf.dwMask & RichTextBoxConstants.CFM_STRIKEOUT) != 0 && (cf.dwEffects & RichTextBoxConstants.CFE_STRIKEOUT) != 0)
                style |= FontStyle.Strikeout;
            if ((cf.dwMask & RichTextBoxConstants.CFM_UNDERLINE) != 0 && (cf.dwEffects & RichTextBoxConstants.CFE_UNDERLINE) != 0) 
                style |= FontStyle.Underline;
 
            try { 
                return new Font(fontName, fontSize, style, GraphicsUnit.Point, cf.bCharSet);
            } 
            catch {
            }

            return null; 
        }
 
        ///  
        /// 
        ///     Returns the index of the character nearest to the given point. 
        /// 
        public override int GetCharIndexFromPosition(Point pt) {
            NativeMethods.POINT wpt = new NativeMethods.POINT(pt.X, pt.Y);
            int index = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.EM_CHARFROMPOS, 0, wpt); 

            string t = this.Text; 
            // EM_CHARFROMPOS will return an invalid number if the last character in the RichEdit 
            // is a newline.
            // 
            if (index >= t.Length) {
                index = Math.Max(t.Length - 1, 0);
            }
            return index; 
        }
 
        ///  
        /// 
        ///  
        /// 
        private bool GetCharInCharSet(char c, char[] charSet, bool negate) {
            bool match = false;
            int charSetLen = charSet.Length; 

            // Loop through the given character set and compare for a match 
            for (int i = 0; !match && i < charSetLen; i++) 
                match = c == charSet[i];
 
            return negate ? !match : match;
        }

        ///  
        /// 
        ///     Returns the number of the line containing a specified character position 
        ///     in a RichTextBox control. Note that this returns the physical line number 
        ///     and not the conceptual line number. For example, if the first conceptual
        ///     line (line number 0) word-wraps and extends to the second line, and if 
        ///     you pass the index of a overflowed character, GetLineFromCharIndex would
        ///     return 1 and not 0.
        /// 
        public override int GetLineFromCharIndex(int index) { 
            return (int)SendMessage(RichTextBoxConstants.EM_EXLINEFROMCHAR, 0, index);
        } 
 
        /// 
        ///  
        ///     Returns the location of the character at the given index.
        /// 
        public override Point GetPositionFromCharIndex(int index) {
            if (richEditMajorVersion == 2) { 
                return base.GetPositionFromCharIndex(index);
            } 
 
            if (index < 0 || index > Text.Length) {
                return Point.Empty; 
            }

            NativeMethods.POINT pt = new NativeMethods.POINT();
            UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.EM_POSFROMCHAR, pt, index); 
            return new Point(pt.x, pt.y);
        } 
 
        /// 
        ///  
        /// 
        /// 
        private bool GetProtectedError() {
            if (ProtectedError) { 
                ProtectedError = false;
                return true; 
            } 

            return false; 
        }

        /// 
        ///  
        ///     Loads the contents of the given RTF or text file into a RichTextBox control.
        ///  
        public void LoadFile(string path) { 
            LoadFile(path, RichTextBoxStreamType.RichText);
        } 

        /// 
        /// 
        ///     Loads the contents of a RTF or text into a RichTextBox control. 
        /// 
        public void LoadFile(string path, RichTextBoxStreamType fileType) { 
            //valid values are 0x0 to 0x4 
            if (!ClientUtils.IsEnumValid(fileType, (int)fileType, (int)RichTextBoxStreamType.RichText, (int)RichTextBoxStreamType.UnicodePlainText)){
                throw new InvalidEnumArgumentException("fileType", (int)fileType, typeof(RichTextBoxStreamType)); 
            }

            Stream file = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
            try { 
                LoadFile(file, fileType);
            } 
            finally { 
                file.Close();
            } 
        }

        /// 
        ///  
        ///     Loads the contents of a RTF or text into a RichTextBox control.
        ///  
        public void LoadFile(Stream data, RichTextBoxStreamType fileType) { 
            //valid values are 0x0 to 0x4
            if (!ClientUtils.IsEnumValid(fileType, (int)fileType, (int)RichTextBoxStreamType.RichText, (int)RichTextBoxStreamType.UnicodePlainText)) 
            {
                throw new InvalidEnumArgumentException("fileType", (int)fileType, typeof(RichTextBoxStreamType));
            }
 
            int flags;
            switch (fileType) { 
                case RichTextBoxStreamType.RichText: 
                    flags = RichTextBoxConstants.SF_RTF;
                    break; 
                case RichTextBoxStreamType.PlainText:
                    this.Rtf = "";
                    flags = RichTextBoxConstants.SF_TEXT;
                    break; 
                case RichTextBoxStreamType.UnicodePlainText:
                    flags = RichTextBoxConstants.SF_UNICODE | RichTextBoxConstants.SF_TEXT; 
                    break; 
                default:
                    throw new ArgumentException(SR.GetString(SR.InvalidFileType)); 
            }

            StreamIn(data, flags);
        } 

 
        ///  
        /// 
        ///    [To be supplied.] 
        /// 
        protected override void OnBackColorChanged(EventArgs e) {
            if (IsHandleCreated)
            { 
                SendMessage(RichTextBoxConstants.EM_SETBKGNDCOLOR, 0, ColorTranslator.ToWin32(BackColor));
            } 
            base.OnBackColorChanged(e); 
        }
 
        /// 
        protected override void OnContextMenuChanged(EventArgs e)
        {
            base.OnContextMenuChanged(e); 
            UpdateOleCallback();
        } 
 
        /// 
        ///  
        ///    [To be supplied.]
        /// 
        protected override void OnRightToLeftChanged(EventArgs e) {
            base.OnRightToLeftChanged(e); 
            //VSWhidbey# 325345.
            // When the RTL property is changed, here's what happens. Let's assume that we change from 
            // RTL.No to RTL.Yes. 

            // 1.   RecreateHandle is called. 
            // 2.   In RTB.OnHandleDestroyed, we cache off any RTF that might have been set.
            //      The RTB has been set to the empty string, so we do get RTF back. The RTF
            //      contains formatting info, but doesn't contain any reading-order info,
            //      so RichEdit defaults to LTR reading order. 
            // 3.   In RTB.OnHandleCreated, we check if we have any cached RTF, and if so,
            //      we want to set the RTF to that value. This is to ensure that the original 
            //      text doesn't get lost. 
            // 4.   In the RTF setter, we get the current RTF, compare it to the old RTF, and
            //      since those are not equal, we set the RichEdit content to the old RTF. 
            // 5.   But... since the original RTF had no reading-order info, the reading-order
            //      will default to LTR - thus VSWhidbey #325345.

            // That's why in Everett we set the text back since that clears the RTF, thus restoring 
            // the reading order to that of the window style. The problem here is that when there's
            // no initial text (the empty string), then WindowText would not actually set the text, 
            // and we were left with the LTR reading order. There's no longer any initial text (as in Everett, 
            // e.g richTextBox1), since we changed the designers to not set text. Sigh...
 
            // So the fix is to force windowtext, whether or not that window text is equal to what's already there.
            // Note that in doing so we will lose any formatting info you might have set on the RTF. We are okay with that.

            // We use WindowText rather than Text because this way we can avoid 
            // spurious TextChanged events.
            // 
            string oldText = WindowText; 
            ForceWindowText(null);
            ForceWindowText(oldText); 
        }

        /// 
        ///  
        ///     Fires an event when the user changes the control's contents
        ///     are either smaller or larger than the control's window size. 
        ///  
        protected virtual void OnContentsResized(ContentsResizedEventArgs e) {
            ContentsResizedEventHandler handler = (ContentsResizedEventHandler)Events[EVENT_REQUESTRESIZE]; 
            if (handler != null) handler(this,e);
        }

        ///  
        /// 
        ///    [To be supplied.] 
        ///  
        protected override void OnHandleCreated(EventArgs e) {
            // base.OnHandleCreated is called somewhere in the middle of this 

            curSelStart = curSelEnd = curSelType = -1;

            // We will always set the control to use the maximum text, it defaults to 32k.. 
            // This must be done before we start loading files, because some files may
            // be larger than 32k. 
            // 
            UpdateMaxLength();
 
            // This is needed so that the control will fire change and update events
            // even if it is hidden
            //
            SendMessage(RichTextBoxConstants.EM_SETEVENTMASK, 
                        0,
                        RichTextBoxConstants.ENM_PROTECTED | RichTextBoxConstants.ENM_SELCHANGE | 
                        RichTextBoxConstants.ENM_DROPFILES | RichTextBoxConstants.ENM_REQUESTRESIZE | 
                        RichTextBoxConstants.ENM_IMECHANGE | RichTextBoxConstants.ENM_CHANGE |
                        RichTextBoxConstants.ENM_UPDATE    | RichTextBoxConstants.ENM_SCROLL | 
                        RichTextBoxConstants.ENM_KEYEVENTS | RichTextBoxConstants.ENM_MOUSEEVENTS |
                        RichTextBoxConstants.ENM_SCROLLEVENTS | RichTextBoxConstants.ENM_LINK);

            int rm = rightMargin; 
            rightMargin = 0;
            RightMargin = rm; 
 
            //
 

            this.SendMessage(RichTextBoxConstants.EM_AUTOURLDETECT, DetectUrls ? 1 : 0, 0);
            if (selectionBackColorToSetOnHandleCreated != Color.Empty) {
                this.SelectionBackColor = selectionBackColorToSetOnHandleCreated; 
            }
 
            // Initialize colors before initializing RTF, otherwise CFE_AUTOCOLOR will be in effect 
            // and our text will all be Color.WindowText.
            AutoWordSelection = AutoWordSelection; 
            SendMessage(RichTextBoxConstants.EM_SETBKGNDCOLOR, 0, ColorTranslator.ToWin32(BackColor));
            InternalSetForeColor(ForeColor);

            // base sets the Text property.  It's important to do this *after* setting EM_AUTOUrlDETECT. 
            base.OnHandleCreated(e);
 
            // vsWhidbey 371584: for some reason, we need to set the OleCallback before setting the RTF property. 
            UpdateOleCallback();
 
            // RTF property takes precedence over Text property
            //
            try {
                SuppressTextChangedEvent = true; 
                if (textRtf != null) {
                    // setting RTF calls back on Text, which relies on textRTF being null 
                    string text = textRtf; 
                    textRtf = null;
                    Rtf = text; 
                }
                else if (textPlain != null) {
                    string text = textPlain;
                    textPlain = null; 
                    Text = text;
                } 
            } 
            finally {
                SuppressTextChangedEvent = false; 
            }

            // Since we can't send EM_SETSEL until RTF has been set,
            // we can't rely on base to do it for us. 
            base.SetSelectionOnHandle();
 
            if (ShowSelectionMargin) { 
                // If you call SendMessage instead of PostMessage, the control
                // will resize itself to the size of the parent's client area.  Don't know why... 
                UnsafeNativeMethods.PostMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETOPTIONS, (IntPtr)RichTextBoxConstants.ECOOP_OR,
                                                (IntPtr)RichTextBoxConstants.ECO_SELECTIONBAR);
            }
 
            if (languageOption != this.LanguageOption) {
                this.LanguageOption = languageOption; 
            } 

            ClearUndo(); 

            SendZoomFactor(zoomMultiplier);

            SystemEvents.UserPreferenceChanged += new UserPreferenceChangedEventHandler(UserPreferenceChangedHandler); 
        }
 
        ///  
        /// 
        ///    [To be supplied.] 
        /// 
        protected override void OnHandleDestroyed(EventArgs e) {
            base.OnHandleDestroyed(e);
 
            if (!InConstructor) {
                textRtf = Rtf; 
                if (textRtf.Length == 0) 
                    textRtf = null;
            } 

            oleCallback = null;
            SystemEvents.UserPreferenceChanged -= new UserPreferenceChangedEventHandler(UserPreferenceChangedHandler);
        } 

        ///  
        ///  
        ///     Fires an event when the user clicks a RichTextBox control's horizontal
        ///     scroll bar. 
        /// 
        protected virtual void OnHScroll(EventArgs e) {
            EventHandler handler = (EventHandler)Events[EVENT_HSCROLL];
            if (handler != null) handler(this,e); 
        }
 
        ///  
        /// 
        ///     Fires an event when the user clicks on a link 
        ///     in a rich-edit control.
        /// 
        protected virtual void OnLinkClicked(LinkClickedEventArgs e) {
            LinkClickedEventHandler handler = (LinkClickedEventHandler)Events[EVENT_LINKACTIVATE]; 
            if (handler != null) handler(this,e);
        } 
 

        ///  
        /// 
        ///     Fires an event when the user changes the control's IME conversion status.
        /// 
        protected virtual void OnImeChange(EventArgs e) { 
            EventHandler handler = (EventHandler)Events[EVENT_IMECHANGE];
            if (handler != null) handler(this,e); 
        } 

        ///  
        /// 
        ///     Fires an event when the user is taking an action that would change
        ///     a protected range of text in the RichTextBox control.
        ///  
        protected virtual void OnProtected(EventArgs e) {
            ProtectedError = true; 
            EventHandler handler = (EventHandler)Events[EVENT_PROTECTED]; 
            if (handler != null) handler(this,e);
        } 

        /// 
        /// 
        ///     Fires an event when the current selection of text in the RichTextBox 
        ///     control has changed or the insertion point has moved.
        ///  
        protected virtual void OnSelectionChanged(EventArgs e) { 
            EventHandler handler = (EventHandler)Events[EVENT_SELCHANGE];
            if (handler != null) handler(this,e); 
        }

        /// 
        ///  
        ///     Fires an event when the user clicks a RichTextBox control's vertical
        ///     scroll bar. 
        ///  
        protected virtual void OnVScroll(EventArgs e) {
            EventHandler handler = (EventHandler)Events[EVENT_VSCROLL]; 
            if (handler != null) handler(this,e);
        }

        ///  
        /// 
        ///     Pastes the contents of the clipboard in the given clipboard format. 
        ///  
        public void Paste(DataFormats.Format clipFormat) {
            Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "ClipboardRead Demanded"); 
            IntSecurity.ClipboardRead.Demand();

            PasteUnsafe(clipFormat, 0);
        } 

        ///  
        ///  
        /// Note that this doesn't make a security demand: functions that call this should.
        ///  
        private void PasteUnsafe(DataFormats.Format clipFormat, int hIcon) {
            NativeMethods.REPASTESPECIAL rps = null;

            if (hIcon != 0) { 
                rps = new NativeMethods.REPASTESPECIAL();
                rps.dwAspect = DVASPECT_ICON; 
                rps.dwParam = hIcon; 
            }
            UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_PASTESPECIAL, clipFormat.Id, rps); 
        }

        /// 
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] 
        protected override bool ProcessCmdKey(ref Message m, Keys keyData) {
            if (this.RichTextShortcutsEnabled == false) { 
                foreach (int shortcutValue in shortcutsToDisable) { 
                    if ((int)keyData == shortcutValue) {
                        return true; 
                    }
                }
            }
            return base.ProcessCmdKey(ref m, keyData); 
        }
 
        ///  
        /// 
        ///     Redoes the last undone editing operation. 
        /// 
        public void Redo() {
            SendMessage(RichTextBoxConstants.EM_REDO, 0, 0);
        } 

        //NOTE: Undo is implemented on TextBox 
 
        /// 
        ///  
        ///     Saves the contents of a RichTextBox control to a file.
        /// 
        public void SaveFile(string path) {
            SaveFile(path, RichTextBoxStreamType.RichText); 
        }
 
        ///  
        /// 
        ///     Saves the contents of a RichTextBox control to a file. 
        /// 
        public void SaveFile(string path, RichTextBoxStreamType fileType) {
            //valid values are 0x0 to 0x4
            if (!ClientUtils.IsEnumValid(fileType, (int)fileType, (int)RichTextBoxStreamType.RichText, (int)RichTextBoxStreamType.UnicodePlainText)) 
            {
                throw new InvalidEnumArgumentException("fileType", (int)fileType, typeof(RichTextBoxStreamType)); 
            } 

            Stream file = File.Create(path); 
            try {
                SaveFile(file, fileType);
            }
            finally { 
                file.Close();
            } 
        } 

        ///  
        /// 
        ///     Saves the contents of a RichTextBox control to a file.
        /// 
        public void SaveFile(Stream data, RichTextBoxStreamType fileType) { 
            int flags;
            switch (fileType) { 
                case RichTextBoxStreamType.RichText: 
                    flags = RichTextBoxConstants.SF_RTF;
                    break; 
                case RichTextBoxStreamType.PlainText:
                    flags = RichTextBoxConstants.SF_TEXT;
                    break;
                case RichTextBoxStreamType.UnicodePlainText: 
                    flags = RichTextBoxConstants.SF_UNICODE | RichTextBoxConstants.SF_TEXT;
                    break; 
                case RichTextBoxStreamType.RichNoOleObjs: 
                    flags = RichTextBoxConstants.SF_RTFNOOBJS;
                    break; 
                case RichTextBoxStreamType.TextTextOleObjs:
                    flags = RichTextBoxConstants.SF_TEXTIZED;
                    break;
                default: 
                    throw new InvalidEnumArgumentException("fileType", (int)fileType, typeof(RichTextBoxStreamType));
            } 
 
            StreamOut(data, flags, true);
        } 

        /// 
        /// 
        ///     Core Zoom calculation and message passing (used by ZoomFactor property and CreateHandle() 
        /// 
        ///  
        private void SendZoomFactor(float zoom) { 
            int numerator;
            int denominator; 

            if (zoom == 1.0f) {
                denominator = 0;
                numerator = 0; 
            }
            else { 
                denominator = 1000; 
                float multiplier = 1000 * zoom;
                numerator = (int)Math.Ceiling(multiplier); 
                if (numerator >= 64000) {
                    numerator = (int)Math.Floor(multiplier);
                }
            } 

            if (IsHandleCreated) { 
                SendMessage(RichTextBoxConstants.EM_SETZOOM, numerator, denominator); 

#if DEBUG 

                // DEBUG CODE: Verify that EM_SETZOOM actually set the zoom
                int n = 0, d = 0;
                SendMessage(RichTextBoxConstants.EM_GETZOOM, ref n, ref d); 
                Debug.Assert(n == numerator && d == denominator, "EM_SETZOOM failed");
                // END DEBUG CODE 
#endif 
            }
 
            if (numerator != 0) {
                zoomMultiplier = ((float)numerator)/((float)denominator);
            }
            else { 
                zoomMultiplier = 1.0f;
            } 
        } 

        ///  
        /// 
        /// 
        /// 
        private bool SetCharFormat(int mask, int effect, RichTextBoxSelectionAttribute charFormat) { 
            // check to see if the control has been created
            if (IsHandleCreated) { 
                NativeMethods.CHARFORMATA cf = new NativeMethods.CHARFORMATA(); 

                cf.dwMask = mask; 

                switch (charFormat) {
                    case RichTextBoxSelectionAttribute.All:
                        cf.dwEffects = effect; 
                        break;
                    case RichTextBoxSelectionAttribute.None: 
                        cf.dwEffects = 0; 
                        break;
                    default: 
                        throw new ArgumentException(SR.GetString(SR.UnknownAttr));
                }

                // set the format information 
                return IntPtr.Zero != UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETCHARFORMAT, RichTextBoxConstants.SCF_SELECTION, cf);
            } 
            return false; 
        }
 
        private bool SetCharFormat(int charRange, NativeMethods.CHARFORMATA cf) {
            return IntPtr.Zero != UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETCHARFORMAT, charRange, cf);
        }
 
        private void SetCharFormatFont(bool selectionOnly, Font value) {
            ForceHandleCreate(); 
            NativeMethods.LOGFONT logfont = new NativeMethods.LOGFONT(); 

            FontToLogFont(value, logfont); 

            byte[] bytesFaceName;

            int dwMask = RichTextBoxConstants.CFM_FACE | RichTextBoxConstants.CFM_SIZE | RichTextBoxConstants.CFM_BOLD | 
                RichTextBoxConstants.CFM_ITALIC | RichTextBoxConstants.CFM_STRIKEOUT | RichTextBoxConstants.CFM_UNDERLINE |
                RichTextBoxConstants.CFM_CHARSET; 
 
            int dwEffects = 0;
            if (value.Bold) dwEffects |= RichTextBoxConstants.CFE_BOLD; 
            if (value.Italic) dwEffects |= RichTextBoxConstants.CFE_ITALIC;
            if (value.Strikeout) dwEffects |= RichTextBoxConstants.CFE_STRIKEOUT;
            if (value.Underline) dwEffects |= RichTextBoxConstants.CFE_UNDERLINE;
 
            if (Marshal.SystemDefaultCharSize == 1)
            { 
                bytesFaceName = Encoding.Default.GetBytes(logfont.lfFaceName); 

                NativeMethods.CHARFORMATA cfA = new NativeMethods.CHARFORMATA(); 
                for (int i=0; i 
        /// 
        /// This is just here as a minor perf improvement, so we don't have to call expensive RevertAssert.
        /// When the method exits, we effectively revert the assert.
        ///  
        [SecurityPermission(SecurityAction.Assert, Flags=SecurityPermissionFlag.UnmanagedCode)]
        [SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts")] 
        static private void FontToLogFont(Font value, NativeMethods.LOGFONT logfont) { 
            value.ToLogFont(logfont);
        } 


        /// 
        ///  
        /// 
        private static void SetupLogPixels(IntPtr hDC) { 
            bool release = false; 
            if (hDC == IntPtr.Zero) {
                hDC = UnsafeNativeMethods.GetDC(NativeMethods.NullHandleRef); 
                release = true;
            }
            if (hDC == IntPtr.Zero) return;
            logPixelsX = UnsafeNativeMethods.GetDeviceCaps(new HandleRef(null, hDC), NativeMethods.LOGPIXELSX); 
            logPixelsY = UnsafeNativeMethods.GetDeviceCaps(new HandleRef(null, hDC), NativeMethods.LOGPIXELSY);
            if (release) 
                UnsafeNativeMethods.ReleaseDC(NativeMethods.NullHandleRef, new HandleRef(null, hDC)); 
        }
 
        private static int Pixel2Twip(IntPtr hDC, int v, bool xDirection) {
            SetupLogPixels(hDC);
            int logP = xDirection ? logPixelsX : logPixelsY;
            return(int) ((((double)v) / logP) * 72.0 * 20.0); 
        }
 
        private static int Twip2Pixel(IntPtr hDC, int v, bool xDirection) { 
            SetupLogPixels(hDC);
            int logP = xDirection ? logPixelsX : logPixelsY; 
            return(int) (((((double) v) / 20.0) / 72.0) * logP);
        }

        ///  
        /// 
        ///  
        ///  
        private void StreamIn(string str, int flags) {
            if (str.Length == 0 ) { 
                // Destroy the selection if callers was setting
                // selection text
                //
                if ((RichTextBoxConstants.SFF_SELECTION & flags) != 0) { 
                    SendMessage(NativeMethods.WM_CLEAR, 0, 0);
                    ProtectedError = false; 
                    return; 
                }
                // WM_SETTEXT is allowed even if we have protected text 
                //
                SendMessage(NativeMethods.WM_SETTEXT, 0, "");
                return;
            } 

            // Rather than work only some of the time with null characters, 
            // we're going to be consistent and never work with them. 
            int nullTerminatedLength = str.IndexOf((char) 0);
            if (nullTerminatedLength != -1) { 
                str = str.Substring(0, nullTerminatedLength);
            }

            // get the string into a byte array 
            byte[] encodedBytes;
            if ((flags & RichTextBoxConstants.SF_UNICODE) != 0) { 
                encodedBytes = Encoding.Unicode.GetBytes(str); 
            }
            else { 
                encodedBytes = Encoding.Default.GetBytes(str);
            }
            editStream = new MemoryStream(encodedBytes.Length);
            editStream.Write(encodedBytes, 0, encodedBytes.Length); 
            editStream.Position = 0;
            StreamIn(editStream, flags); 
        } 

        private void StreamIn(Stream data, int flags) { 
            // clear out the selection only if we are replacing all the text
            //
            if ((flags & RichTextBoxConstants.SFF_SELECTION) == 0) {
                NativeMethods.CHARRANGE cr = new NativeMethods.CHARRANGE(); 
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_EXSETSEL, 0, cr);
            } 
 
            try {
                editStream = data; 
                Debug.Assert(data != null, "StreamIn passed a null stream");

                // If SF_RTF is requested then check for the RTF tag at the start
                // of the file.  We don't load if the tag is not there 
                //
                if ((flags & RichTextBoxConstants.SF_RTF) != 0) { 
                    long streamStart = editStream.Position; 
                    byte[] bytes = new byte[SZ_RTF_TAG.Length];
                    editStream.Read(bytes, (int)streamStart, SZ_RTF_TAG.Length); 
                    string str = Encoding.Default.GetString(bytes);
                    if (!SZ_RTF_TAG.Equals(str))
                        throw new ArgumentException(SR.GetString(SR.InvalidFileFormat));
 
                    // put us back at the start of the file
                    editStream.Position = streamStart; 
                } 

                int cookieVal = 0; 
                // set up structure to do stream operation
                NativeMethods.EDITSTREAM es = new NativeMethods.EDITSTREAM();
                if ((flags & RichTextBoxConstants.SF_UNICODE) != 0) {
                    cookieVal = INPUT | UNICODE; 
                }
                else { 
                    cookieVal = INPUT | ANSI; 
                }
                if ((flags & RichTextBoxConstants.SF_RTF) != 0) { 
                    cookieVal |= RTF;
                }
                else {
                    cookieVal |= TEXTLF; 
                }
                es.dwCookie = (IntPtr) cookieVal; 
                es.pfnCallback = new NativeMethods.EditStreamCallback(this.EditStreamProc); 

                // gives us TextBox compatible behavior, programatic text change shouldn't 
                // be limited...
                //
                SendMessage(RichTextBoxConstants.EM_EXLIMITTEXT, 0, Int32.MaxValue);
 

 
                // go get the text for the control 
                //Weird hack needed for 64-bit
                if (IntPtr.Size == 8) { 
                    NativeMethods.EDITSTREAM64 es64 = ConvertToEDITSTREAM64(es);
                    UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_STREAMIN, flags, es64);

                    //Assign back dwError value 
                    es.dwError = GetErrorValue64(es64);
                } 
                else { 
                    UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_STREAMIN, flags, es);
                } 

                UpdateMaxLength();

                // If we failed to load because of protected 
                // text then return protect event was fired so no
                // exception is required for the the error 
                if (GetProtectedError()) 
                    return;
 
                if (es.dwError != 0)
                    throw new InvalidOperationException(SR.GetString(SR.LoadTextError));

                // set the modify tag on the control 
                SendMessage(NativeMethods.EM_SETMODIFY, -1, 0);
 
                // EM_GETLINECOUNT will cause the RichTextBoxConstants to recalculate its line indexes 
                SendMessage(NativeMethods.EM_GETLINECOUNT, 0, 0);
 

            }
            finally {
                // release any storage space held. 
                editStream = null;
            } 
        } 

        ///  
        /// 
        /// 
        /// 
        private string StreamOut(int flags) { 
            Stream stream = new MemoryStream();
            StreamOut(stream, flags, false); 
            stream.Position = 0; 
            int streamLength = (int)stream.Length;
            string result = string.Empty; 

            if (streamLength > 0) {
                byte[] bytes = new byte[streamLength];
                stream.Read(bytes, 0, streamLength); 

                if ((flags & RichTextBoxConstants.SF_UNICODE) != 0) { 
                    result = Encoding.Unicode.GetString(bytes,0 , bytes.Length); 
                }
                else { 
                    result = Encoding.Default.GetString(bytes, 0, bytes.Length);
                }
                // workaround ??? for bug 117325. When the string is modified is can return
                // with an extra null termination (always?). If it does, get rid of it. 
                if(!String.IsNullOrEmpty(result) && (result[result.Length-1] == '\0')) {
                    result = result.Substring(0, result.Length-1); 
                } 
            }
 
            return result;
        }

        private void StreamOut(Stream data, int flags, bool includeCrLfs) { 
            // set up the EDITSTREAM structure for the callback.
            Debug.Assert(data != null, "StreamOut passed a null stream"); 
            editStream = data; 

            try { 
                int cookieVal = 0;
                NativeMethods.EDITSTREAM es = new NativeMethods.EDITSTREAM();
                if ((flags & RichTextBoxConstants.SF_UNICODE) != 0) {
                    cookieVal = OUTPUT | UNICODE; 
                }
                else { 
                    cookieVal = OUTPUT | ANSI; 
                }
                if ((flags & RichTextBoxConstants.SF_RTF) != 0) { 
                    cookieVal |= RTF;
                }
                else {
                    if (includeCrLfs) { 
                        cookieVal |= TEXTCRLF;
                    } 
                    else { 
                        cookieVal |= TEXTLF;
                    } 
                }
                es.dwCookie = (IntPtr) cookieVal;
                es.pfnCallback = new NativeMethods.EditStreamCallback(this.EditStreamProc);
 
                //Get Text
                //Weird hack needed for 64-bit 
                if (IntPtr.Size == 8) { 
                    NativeMethods.EDITSTREAM64 es64 = ConvertToEDITSTREAM64(es);
                    UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_STREAMOUT, flags, es64); 

                    //Assign back dwError value
                    es.dwError = GetErrorValue64(es64);
                } 
                else {
                    UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_STREAMOUT, flags, es); 
                } 

                // check to make sure things went well 
                if (es.dwError != 0)
                    throw new InvalidOperationException(SR.GetString(SR.SaveTextError));
            }
            finally { 
                // release any storage space held.
                editStream = null; 
            } 
        }
 
        private unsafe NativeMethods.EDITSTREAM64 ConvertToEDITSTREAM64(NativeMethods.EDITSTREAM es) {
            NativeMethods.EDITSTREAM64 es64 = new NativeMethods.EDITSTREAM64();

            fixed (byte* es64p =  &es64.contents[0]) { 
                byte *bp;
                long l; 
 
                /*
                l = (long) es.dwCookie; 
                bp = (byte *) &l;
                for (int i=0; i < sizeof(long); i++) {
                    es64.contents[i] = bp[i];
                }*/ 
                *((long *)es64p) = (long) es.dwCookie;
                /* 
                int il = es.dwError; 
                bp = (byte *) &il;
                for (int i=0; i < sizeof(int); i++) { 
                    es64.contents[i+8] = bp[i];
                }*/
                *((int *)(es64p + 8)) = es.dwError;
 
                l = (long) Marshal.GetFunctionPointerForDelegate(es.pfnCallback);
                bp = (byte *) &l; 
                for (int i=0; i < sizeof(long); i++) { 
                    es64.contents[i+12] = bp[i];
                } 
                //*((long *)(es64p + 12)) = (long) Marshal.GetFunctionPointerForDelegate(es.pfnCallback);
            }

            return es64; 
        }
 
        private unsafe int GetErrorValue64(NativeMethods.EDITSTREAM64 es64) { 
            int errorVal;
 
            fixed (byte* es64p =  &es64.contents[0]) {
                errorVal = *((int *)(es64p + 8));
            }
 
            return errorVal;
        } 
 
/* FOR 64 BIT DEBUGGING
        private unsafe string PrintBytes(NativeMethods.EDITSTREAM es) { 
            StringBuilder sb = new StringBuilder();
            fixed (IntPtr *ip = &es.dwCookie) {
                byte *bytep = (byte *) ip;
                for (int i=0; i < Marshal.SizeOf(es); i++) { 
                    sb.Append(bytep[i].ToString() + " ");
                } 
            } 
            return sb.ToString();
        } 

        private unsafe string PrintBytes(NativeMethods.EDITSTREAM64 es64) {
            StringBuilder sb = new StringBuilder();
            fixed (byte *bytep = &es64.contents[0]) { 
                for (int i=0; i < Marshal.SizeOf(es64); i++) {
                    sb.Append(bytep[i].ToString() + " "); 
                } 
            }
            return sb.ToString(); 
        }
*/

 
        private void UpdateOleCallback() {
            Debug.WriteLineIf(RichTextDbg.TraceVerbose, "update ole callback (" + AllowDrop + ")"); 
            if (IsHandleCreated) { 
                if (oleCallback == null) {
                    Debug.WriteLineIf(RichTextDbg.TraceVerbose, "binding ole callback"); 
                    bool unrestricted = false;
                    try {
                        IntSecurity.UnmanagedCode.Demand();
                        unrestricted = true; 
                    }
                    catch (SecurityException) { 
                        unrestricted = false; 
                    }
                    if (unrestricted) { 
                        this.AllowOleObjects = true;
                    }
                    else {
                        this.AllowOleObjects = (0 != (int) SendMessage(RichTextBoxConstants.EM_SETQUERYRTFOBJ, 0, 1)); 
                    }
 
                    oleCallback = CreateRichEditOleCallback(); 

                    // Forcibly QI (through IUnknown::QueryInterface) to handle multiple 
                    // definitions of the interface.
                    //
                    IntPtr punk = Marshal.GetIUnknownForObject(oleCallback);
                    try { 
                        IntPtr pRichEditOleCallback;
                        Guid iidRichEditOleCallback = typeof(UnsafeNativeMethods.IRichEditOleCallback).GUID; 
                        Marshal.QueryInterface(punk, ref iidRichEditOleCallback, out pRichEditOleCallback); 
                        try {
                            UnsafeNativeMethods.SendCallbackMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETOLECALLBACK, IntPtr.Zero, pRichEditOleCallback); 
                        }
                        finally {
                            Marshal.Release(pRichEditOleCallback);
                        } 
                    } finally {
                        Marshal.Release(punk); 
                    } 
                }
                UnsafeNativeMethods.DragAcceptFiles(new HandleRef(this, Handle), false); 
            }
        }

        //Note: RichTextBox doesn't work like other controls as far as setting ForeColor/ 
        //BackColor -- you need to send messages to update the colors
        private void UserPreferenceChangedHandler(object o, UserPreferenceChangedEventArgs e) 
        { 
            if (IsHandleCreated)
            { 
                if (this.BackColor.IsSystemColor)
                {
                    SendMessage(RichTextBoxConstants.EM_SETBKGNDCOLOR, 0, ColorTranslator.ToWin32(BackColor));
                } 
                if (this.ForeColor.IsSystemColor)
                { 
                    InternalSetForeColor(ForeColor); 
                }
            } 
        }

        /// 
        ///  
        ///   Creates the IRichEditOleCallback compatible object for handling RichEdit callbacks. For more
        ///   information look up the MSDN info on this interface. This is designed to be a back door of 
        ///   sorts, which is why it is fairly obscure, and uses the RichEdit name instead of RichTextBox. 
        /// 
        [SecurityPermission(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] 
        protected virtual object CreateRichEditOleCallback() {
            return new OleCallback(this);
        }
 
        /// 
        ///  
        ///      Handles link messages (mouse move, down, up, dblclk, etc) 
        /// 
        ///  
        private void EnLinkMsgHandler(ref Message m) {
            NativeMethods.ENLINK enlink;
            //On 64-bit, we do some custom marshalling to get this to work. The richedit control
            //unfortunately does not respect IA64 struct alignment conventions. See VSWhidbey #122276 & 504502. 
            if (IntPtr.Size == 8) {
                enlink = ConvertFromENLINK64((NativeMethods.ENLINK64)m.GetLParam(typeof(NativeMethods.ENLINK64))); 
            } 
            else {
                enlink = (NativeMethods.ENLINK)m.GetLParam(typeof(NativeMethods.ENLINK)); 
            }

            switch (enlink.msg) {
                case NativeMethods.WM_SETCURSOR: 
                    LinkCursor = true;
                    m.Result = (IntPtr)1; 
                    return; 
                // Mouse-down triggers Url; this matches Outlook 2000's behavior.
                case NativeMethods.WM_LBUTTONDOWN: 
                    string linktext = CharRangeToString(enlink.charrange);
                    if (!string.IsNullOrEmpty(linktext))
                    {
                        OnLinkClicked(new LinkClickedEventArgs(linktext)); 
                    }
                    m.Result = (IntPtr)1; 
                    return; 
            }
            m.Result = IntPtr.Zero; 
            return;
        }

        ///  
        /// 
        ///     Converts a CHARRANGE to a string. Note: The behavior of this is dependent on the current window 
        ///     class name being used. We have to create a CharBuffer of the type of RichTextBox DLL we're using, 
        ///     not based on the SystemCharWidth.
        ///  
        /// 
        private string CharRangeToString(NativeMethods.CHARRANGE c) {
            NativeMethods.TEXTRANGE txrg = new NativeMethods.TEXTRANGE();
            txrg.chrg = c; 
            Debug.Assert((c.cpMax-c.cpMin)>0, "CHARRANGE was null or negative - can't do it!");
 
            //Windows bug: 64-bit windows returns a bad range for us.  VSWhidbey 504502. 
            //Putting in a hack to avoid an unhandled exception.
            if (c.cpMax > Text.Length || c.cpMax-c.cpMin <= 0) { 
                return string.Empty;
            }

            int characters = (c.cpMax-c.cpMin) + 1; // +1 for null termination 
            UnsafeNativeMethods.CharBuffer charBuffer = UnsafeNativeMethods.CharBuffer.CreateBuffer(characters);
            IntPtr unmanagedBuffer = charBuffer.AllocCoTaskMem(); 
            if (unmanagedBuffer == IntPtr.Zero) 
                throw new OutOfMemoryException(SR.GetString(SR.OutOfMemory));
 
            txrg.lpstrText = unmanagedBuffer;
            int len = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETTEXTRANGE, 0, txrg);
            Debug.Assert(len != 0, "CHARRANGE from RichTextBox was bad! - impossible?");
            charBuffer.PutCoTaskMem(unmanagedBuffer); 
            if (txrg.lpstrText != IntPtr.Zero)
                Marshal.FreeCoTaskMem(unmanagedBuffer); 
 
            string result = charBuffer.GetString();
            return result; 
        }

        internal override void UpdateMaxLength() {
            if (IsHandleCreated) { 
                SendMessage(RichTextBoxConstants.EM_EXLIMITTEXT, 0, MaxLength);
            } 
        } 

        ///  
        /// 
        /// 
        /// 
        private void WmReflectCommand(ref Message m) { 

            // We check if we're in the middle of handle creation because 
            // the rich edit control fires spurious events during this time. 
            //
            if (m.LParam == Handle && !GetState(STATE_CREATINGHANDLE)) 
            {
                switch (Util.HIWORD(m.WParam)) {

                    case NativeMethods.EN_HSCROLL: 
                        OnHScroll(EventArgs.Empty);
                        break; 
 
                    case NativeMethods.EN_VSCROLL:
                        OnVScroll(EventArgs.Empty); 
                        break;

                    default:
                        base.WndProc(ref m); 
                        break;
                } 
            } 
            else {
                base.WndProc(ref m); 
            }
        }

        ///  
        /// 
        ///  
        ///  
        internal void WmReflectNotify(ref Message m) {
            if (m.HWnd == Handle) { 
                NativeMethods.NMHDR nmhdr = (NativeMethods.NMHDR)m.GetLParam(typeof(NativeMethods.NMHDR));
                switch (nmhdr.code) {
                    case RichTextBoxConstants.EN_LINK:
                        EnLinkMsgHandler(ref m); 
                        break;
                    case RichTextBoxConstants.EN_DROPFILES: 
                        NativeMethods.ENDROPFILES endropfiles = (NativeMethods.ENDROPFILES)m.GetLParam(typeof(NativeMethods.ENDROPFILES)); 

                        // Only look at the first file. 
                        StringBuilder path = new StringBuilder(NativeMethods.MAX_PATH);
                        UnsafeNativeMethods.DragQueryFile(new HandleRef(endropfiles, endropfiles.hDrop), 0, path, NativeMethods.MAX_PATH);

                        // Try to load the file as an RTF 
                        try {
                            LoadFile(path.ToString(), RichTextBoxStreamType.RichText); 
                        } 
                        catch {
                            // we failed to load as rich text so try it as plain text 
                            try {
                                LoadFile(path.ToString(), RichTextBoxStreamType.PlainText);
                            }
                            catch { 
                                // ignore any problems we have
                            } 
                        } 
                        m.Result = (IntPtr)1;   // tell them we did the drop
                        break; 

                    case RichTextBoxConstants.EN_REQUESTRESIZE:
                        if (!CallOnContentsResized) {
                            NativeMethods.REQRESIZE reqResize = (NativeMethods.REQRESIZE)m.GetLParam(typeof(NativeMethods.REQRESIZE)); 
                            if (BorderStyle == System.Windows.Forms.BorderStyle.Fixed3D) {
                                reqResize.rc.bottom++; 
                            } 
                            OnContentsResized(new ContentsResizedEventArgs(Rectangle.FromLTRB(reqResize.rc.left, reqResize.rc.top, reqResize.rc.right, reqResize.rc.bottom)));
                            } 
                            break;

                    case RichTextBoxConstants.EN_SELCHANGE:
                        NativeMethods.SELCHANGE selChange = (NativeMethods.SELCHANGE)m.GetLParam(typeof(NativeMethods.SELCHANGE)); 
                        WmSelectionChange(selChange);
                        break; 
 
                    case RichTextBoxConstants.EN_PROTECTED: {
                            NativeMethods.ENPROTECTED enprotected; 

                            //On 64-bit, we do some custom marshalling to get this to work. The richedit control
                            //unfortunately does not respect IA64 struct alignment conventions. See VSWhidbey #122276
                            if (IntPtr.Size == 8) { 
                                enprotected = ConvertFromENPROTECTED64((NativeMethods.ENPROTECTED64)m.GetLParam(typeof(NativeMethods.ENPROTECTED64)));
                            } 
                            else { 
                                enprotected = (NativeMethods.ENPROTECTED)m.GetLParam(typeof(NativeMethods.ENPROTECTED));
                            } 


                            switch (enprotected.msg) {
                                case RichTextBoxConstants.EM_SETCHARFORMAT: 
                                    // Allow change of protected style
                                    // 
                                    NativeMethods.CHARFORMATA charFormat = (NativeMethods.CHARFORMATA)UnsafeNativeMethods.PtrToStructure(enprotected.lParam, typeof(NativeMethods.CHARFORMATA)); 
                                    if ((charFormat.dwMask & RichTextBoxConstants.CFM_PROTECTED) != 0) {
                                        m.Result = IntPtr.Zero; 
                                        return;
                                    }
                                    break;
 
                                    // Throw an exception for the following
                                    // 
                                case RichTextBoxConstants.EM_SETPARAFORMAT: 
                                case NativeMethods.EM_REPLACESEL:
                                    break; 

                                case RichTextBoxConstants.EM_STREAMIN:
                                    // Don't allow STREAMIN to replace protected selection
                                    // 
                                    if (((int)enprotected.wParam & RichTextBoxConstants.SFF_SELECTION) != 0)
                                        break; 
                                    m.Result = IntPtr.Zero; 
                                    return;
 
                                    // Allow the following
                                    //
                                case NativeMethods.WM_COPY:
                                case NativeMethods.WM_SETTEXT: 
                                case RichTextBoxConstants.EM_EXLIMITTEXT:
                                    m.Result = IntPtr.Zero; 
                                    return; 

                                    // Beep and disallow change for all other messages 
                                    //
                                default:
                                    SafeNativeMethods.MessageBeep(0);
                                    break; 
                            }
 
                            OnProtected(EventArgs.Empty); 
                            m.Result = (IntPtr)1;
                            break; 
                        }

                    default:
                        base.WndProc(ref m); 
                        break;
                } 
            } 
            else {
                base.WndProc(ref m); 
            }
        }

        private unsafe NativeMethods.ENPROTECTED ConvertFromENPROTECTED64(NativeMethods.ENPROTECTED64 es64) { 
            NativeMethods.ENPROTECTED es = new NativeMethods.ENPROTECTED();
 
            fixed (byte* es64p =  &es64.contents[0]) { 
                es.nmhdr = new NativeMethods.NMHDR();
                es.chrg  = new NativeMethods.CHARRANGE(); 

                es.nmhdr.hwndFrom = Marshal.ReadIntPtr((IntPtr)es64p);
                es.nmhdr.idFrom = Marshal.ReadIntPtr((IntPtr)(es64p + 8));
                es.nmhdr.code = Marshal.ReadInt32((IntPtr)(es64p + 16)); 
                es.msg = Marshal.ReadInt32((IntPtr)(es64p + 24));
                es.wParam = Marshal.ReadIntPtr((IntPtr)(es64p + 28)); 
                es.lParam = Marshal.ReadIntPtr((IntPtr)(es64p + 36)); 
                es.chrg.cpMin = Marshal.ReadInt32((IntPtr)(es64p + 44));
                es.chrg.cpMax = Marshal.ReadInt32((IntPtr)(es64p + 48)); 
            }

            return es;
        } 

        private static unsafe NativeMethods.ENLINK ConvertFromENLINK64(NativeMethods.ENLINK64 es64) { 
            NativeMethods.ENLINK es = new NativeMethods.ENLINK(); 

            fixed (byte* es64p =  &es64.contents[0]) { 
                es.nmhdr = new NativeMethods.NMHDR();
                es.charrange  = new NativeMethods.CHARRANGE();

                es.nmhdr.hwndFrom = Marshal.ReadIntPtr((IntPtr)es64p); 
                es.nmhdr.idFrom = Marshal.ReadIntPtr((IntPtr)(es64p + 8));
                es.nmhdr.code = Marshal.ReadInt32((IntPtr)(es64p + 16)); 
                es.msg = Marshal.ReadInt32((IntPtr)(es64p + 24)); 
                es.wParam = Marshal.ReadIntPtr((IntPtr)(es64p + 28));
                es.lParam = Marshal.ReadIntPtr((IntPtr)(es64p + 36)); 
                es.charrange.cpMin = Marshal.ReadInt32((IntPtr)(es64p + 44));
                es.charrange.cpMax = Marshal.ReadInt32((IntPtr)(es64p + 48));
            }
 
            return es;
        } 
 
        /// 
        ///  
        /// 
        /// 
        private void WmSelectionChange(NativeMethods.SELCHANGE selChange) {
            int selStart = selChange.chrg.cpMin; 
            int selEnd = selChange.chrg.cpMax;
            short selType = (short)selChange.seltyp; 
 
            // VSWhidbey 94804: The IME retains characters in the composition window even after MaxLength
            // has been reached in the rich edit control. So, if the Hangul or HangulFull IME is in use, and the 
            // number of characters in the control is equal to MaxLength, and the selection start equals the
            // selection end (nothing is currently selected), then kill and restore focus to the control. Then,
            // to prevent any further partial composition from occurring, post a message back to myself to select
            // the last character being composed so that any further composition will occur within the context of 
            // the string contained within the control.
            // 
            // Since the IME window completes the composition string when the control loses focus and the 
            // EIMES_COMPLETECOMPSTRKILLFOCUS status type is set in the control by the EM_SETIMESTATUS message,
            // simply killing focus and resetting focus to the control will force the contents of the composition 
            // window to be removed. This forces the undo buffer to be emptied and the backspace key will properly
            // remove the last completed character typed.

            // Is either the Hangul or HangulFull IME currently in use? 
            if( ImeMode == ImeMode.Hangul || ImeMode == ImeMode.HangulFull ) {
 
                // Is the IME CompositionWindow open? 
                int compMode = (int)SendMessage(RichTextBoxConstants.EM_GETIMECOMPMODE, 0, 0);
                if (RichTextBoxConstants.ICM_NOTOPEN != compMode) { 

                    int textLength = SafeNativeMethods.GetWindowTextLength(new HandleRef(this, Handle));
                    if (selStart == selEnd && textLength == MaxLength) {
 
                        SendMessage(NativeMethods.WM_KILLFOCUS, 0, 0);
                        SendMessage(NativeMethods.WM_SETFOCUS, 0, 0); 
                        UnsafeNativeMethods.PostMessage(new HandleRef(this, Handle), NativeMethods.EM_SETSEL, selEnd - 1, selEnd); 
                    }
                } 
            }

            if (selStart != curSelStart || selEnd != curSelEnd || selType != curSelType) {
                curSelStart = selStart; 
                curSelEnd   = selEnd;
                curSelType  = selType; 
                OnSelectionChanged(EventArgs.Empty); 
            }
        } 

        /// 
        /// 
        ///  
        /// 
        private void WmSetFont(ref Message m) { 
 
            // This function would normally cause two TextChanged events to be fired, one
            // from the base.WndProc, and another from InternalSetForeColor. 
            // To prevent this, we suppress the first event fire.
            //
            try {
                SuppressTextChangedEvent = true; 
                base.WndProc(ref m);
            } 
            finally { 
                SuppressTextChangedEvent = false;
            } 

            InternalSetForeColor(ForeColor);
        }
 
        // 
        //  
        // 
        /// 
        ///  
        ///    [To be supplied.]
        /// 
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        protected override void WndProc(ref Message m) { 
            switch (m.Msg) {
                case NativeMethods.WM_REFLECT + NativeMethods.WM_NOTIFY: 
                    WmReflectNotify(ref m); 
                    break;
 
                case NativeMethods.WM_REFLECT + NativeMethods.WM_COMMAND:
                    WmReflectCommand(ref m);
                    break;
 
                case NativeMethods.WM_SETCURSOR:
                    //NOTE: RichTextBox uses the WM_SETCURSOR message over links to allow us to 
                    //      change the cursor to a hand. It does this through a synchronous notification 
                    //      message. So we have to pass the message to the DefWndProc first, and
                    //      then, if we receive a notification message in the meantime (indicated by 
                    //      changing "LinkCursor", we set it to a hand. Otherwise, we call the
                    //      WM_SETCURSOR implementation on Control to set it to the user's selection for
                    //      the RichTextBox's cursor.
                    // 
                    //      Similarly,
                    LinkCursor = false; 
                    DefWndProc(ref m); 
                    if (LinkCursor && !Cursor.Equals(Cursors.WaitCursor)) {
                        UnsafeNativeMethods.SetCursor(new HandleRef(Cursors.Hand, Cursors.Hand.Handle)); 
                        m.Result = (IntPtr)1;
                    }
                    else {
                        base.WndProc(ref m); 
                    }
                    break; 
 
                case NativeMethods.WM_SETFONT:
                    WmSetFont(ref m); 
                    break;

                case NativeMethods.WM_IME_NOTIFY:
                    OnImeChange(EventArgs.Empty); 
                    base.WndProc(ref m);
                    break; 
 
                case NativeMethods.WM_GETDLGCODE:
                    base.WndProc(ref m); 
                    m.Result = (IntPtr)((AcceptsTab) ? (int)m.Result | NativeMethods.DLGC_WANTTAB : (int)m.Result & ~NativeMethods.DLGC_WANTTAB);
                    break;

                case NativeMethods.WM_GETOBJECT: 
                    base.WndProc(ref m);
 
                    // OLEACC.DLL uses window class names to identify standard control types. But WinForm controls use app-specific window 
                    // classes. Usually this doesn't matter, because system controls always identify their window class explicitly through
                    // the WM_GETOBJECT+OBJID_QUERYCLASSNAMEIDX message. But RICHEDIT20 doesn't do that - so we must do it ourselves. 
                    // Otherwise OLEACC will treat rich edit controls as custom controls, so the accessible Role and Value will be wrong.
                    if (unchecked((int)(long)m.LParam) == NativeMethods.OBJID_QUERYCLASSNAMEIDX) {
                        m.Result = (IntPtr) ((Marshal.SystemDefaultCharSize == 1) ? (65536+29) : (65536+30));
                    } 
                    break;
 
                case NativeMethods.WM_RBUTTONUP: 
                    //Whidbey 317086
                    //since RichEdit eats up the WM_CONTEXTMENU message, we need to force DefWndProc 
                    //to spit out this message again on receiving WM_RBUTTONUP message. By setting UserMouse
                    //style to true, we effectily let the WmMouseUp method in Control.cs to generate
                    //the WM_CONTEXTMENU message for us.
                    bool oldStyle = GetStyle(ControlStyles.UserMouse); 
                    SetStyle(ControlStyles.UserMouse, true);
                    base.WndProc(ref m); 
                    SetStyle(ControlStyles.UserMouse, oldStyle); 
                    break;
 
                case NativeMethods.WM_VSCROLL:
                    base.WndProc(ref m);
                    int loWord = Util.LOWORD(m.WParam);
                    if (loWord == NativeMethods.SB_THUMBTRACK) 
                    {
                        OnVScroll(EventArgs.Empty); 
                    } else 
                        if (loWord == NativeMethods.SB_THUMBPOSITION)
                        { 
                            OnVScroll(EventArgs.Empty);
                        }
                    break;
 
                case NativeMethods.WM_HSCROLL:
                    base.WndProc(ref m); 
                    loWord = Util.LOWORD(m.WParam); 
                    if (loWord == NativeMethods.SB_THUMBTRACK)
                    { 
                        OnHScroll(EventArgs.Empty);
                    }
                    if (loWord == NativeMethods.SB_THUMBPOSITION)
                    { 
                        OnHScroll(EventArgs.Empty);
                    } 
                    break; 

                default: 
                    base.WndProc(ref m);
                    break;
            }
        } 

        // I used the visual basic 6 RichText (REOleCB.CPP) as a guide for this 
        private class OleCallback : UnsafeNativeMethods.IRichEditOleCallback { 

            private RichTextBox owner; 
            IDataObject lastDataObject;
            DragDropEffects lastEffect;

            internal OleCallback(RichTextBox owner) { 
                this.owner = owner;
            } 
 

            public int GetNewStorage(out UnsafeNativeMethods.IStorage storage) { 
                Debug.WriteLineIf(RichTextDbg.TraceVerbose, "IRichEditOleCallback::GetNewStorage");
                if (!this.owner.AllowOleObjects) {
                    storage = null;
                    return NativeMethods.E_FAIL; 
                }
                // Debug.WriteLine("get new storage"); 
                UnsafeNativeMethods.ILockBytes pLockBytes = UnsafeNativeMethods.CreateILockBytesOnHGlobal(NativeMethods.NullHandleRef, true); 

                Debug.Assert(pLockBytes != null, "pLockBytes is NULL!"); 

                storage = UnsafeNativeMethods.StgCreateDocfileOnILockBytes(pLockBytes,
                                                                           NativeMethods.STGM_SHARE_EXCLUSIVE | NativeMethods.STGM_CREATE | NativeMethods.STGM_READWRITE,
                                                                           0); 
                Debug.Assert(storage != null, "storage is NULL!");
 
                return NativeMethods.S_OK; 
            }
 
            public int GetInPlaceContext(IntPtr lplpFrame,
                                         IntPtr lplpDoc,
                                         IntPtr lpFrameInfo) {
                Debug.WriteLineIf(RichTextDbg.TraceVerbose, "IRichEditOleCallback::GetInPlaceContext"); 
                return NativeMethods.E_NOTIMPL;
            } 
 
            public int ShowContainerUI(int fShow) {
                Debug.WriteLineIf(RichTextDbg.TraceVerbose, "IRichEditOleCallback::ShowContainerUI"); 
                // Do nothing
                return NativeMethods.S_OK;
            }
 
            public int QueryInsertObject(ref Guid lpclsid, IntPtr lpstg, int cp)
            { 
                Debug.WriteLineIf(RichTextDbg.TraceVerbose, "IRichEditOleCallback::QueryInsertObject(" + lpclsid.ToString() + ")"); 

                try 
                {
                    IntSecurity.UnmanagedCode.Demand();
                    return NativeMethods.S_OK;
                } 
                catch (SecurityException)
                { 
                    // We do not have unmanaged code access, so 
                    // we need to restrict what we allow to be loaded
                } 
                Guid realClsid = new Guid();


                int hr = UnsafeNativeMethods.ReadClassStg(new HandleRef(null, lpstg), ref realClsid); 
                Debug.WriteLineIf(RichTextDbg.TraceVerbose, "real clsid:" + realClsid.ToString() + " (hr=" + hr.ToString("X", CultureInfo.InvariantCulture) + ")");
 
                if (!NativeMethods.Succeeded(hr)) 
                {
                    return NativeMethods.S_FALSE; 
                }

                if (realClsid == Guid.Empty)
                { 
                    realClsid = lpclsid;
                } 
 
                switch (realClsid.ToString().ToUpper(CultureInfo.InvariantCulture))
                { 
                    case "00000315-0000-0000-C000-000000000046": // Metafile
                    case "00000316-0000-0000-C000-000000000046": // DIB
                    case "00000319-0000-0000-C000-000000000046": // EMF
                    case "0003000A-0000-0000-C000-000000000046": //BMP 
                        return NativeMethods.S_OK;
                    default: 
                        Debug.WriteLineIf(RichTextDbg.TraceVerbose, "   denying '" + lpclsid.ToString() + "' from being inserted due to security restrictions"); 
                        return NativeMethods.S_FALSE;
                } 
            }

            public int DeleteObject(IntPtr lpoleobj) {
                Debug.WriteLineIf(RichTextDbg.TraceVerbose, "IRichEditOleCallback::DeleteObject"); 
                // Do nothing
                return NativeMethods.S_OK; 
            } 

            public int QueryAcceptData(IComDataObject lpdataobj, 
                                       /* CLIPFORMAT* */ IntPtr lpcfFormat, int reco,
                                       int fReally, IntPtr hMetaPict) {

                Debug.WriteLineIf(RichTextDbg.TraceVerbose, "IRichEditOleCallback::QueryAcceptData(reco=" + reco + ")"); 

                if (reco == NativeMethods.RECO_DROP) { 
                    if (owner.AllowDrop || owner.EnableAutoDragDrop) { 

                        MouseButtons b = Control.MouseButtons; 
                        Keys k = Control.ModifierKeys;

                        int keyState = 0;
 
                        // Due to the order in which we get called, we have to set up the keystate here.
                        // First GetDragDropEffect is called with grfKeyState == 0, and then 
                        // QueryAcceptData is called. Since this is the time we want to fire 
                        // OnDragEnter, but we have yet to get the keystate, we set it up ourselves.
 
                        if ((b & MouseButtons.Left) == MouseButtons.Left) {
                            keyState |= NativeMethods.MK_LBUTTON;
                        }
 
                        if ((b & MouseButtons.Right) == MouseButtons.Right) {
                            keyState |= NativeMethods.MK_RBUTTON; 
                        } 

                        if ((b & MouseButtons.Middle) == MouseButtons.Middle) { 
                            keyState |= NativeMethods.MK_MBUTTON;
                        }

                        if ((k & Keys.Control) == Keys.Control) { 
                            keyState |= NativeMethods.MK_CONTROL;
                        } 
 
                        if ((k & Keys.Shift) == Keys.Shift) {
                            keyState |= NativeMethods.MK_SHIFT; 
                        }

                        lastDataObject = new DataObject(lpdataobj);
 
                        if (!owner.EnableAutoDragDrop) {
                            lastEffect = DragDropEffects.None; 
                        } 

                        DragEventArgs e = new DragEventArgs(lastDataObject, 
                                                        keyState,
                                                        Control.MousePosition.X,
                                                        Control.MousePosition.Y,
                                                        DragDropEffects.All, 
                                                        lastEffect);
                        if (fReally == 0) { 
                            // we are just querying 

                            // We can get here without GetDragDropEffects actually being called first. 
                            // This happens when you drag/drop between two rtb's. Say you drag from rtb1 to rtb2.
                            // GetDragDropEffects will first be called for rtb1, then QueryAcceptData for rtb1 just
                            // like in the local drag case. Then you drag into rtb2. rtb2 will first be called in this method,
                            // and not GetDragDropEffects. Now lastEffect is initialized to None for rtb2, so we would not allow 
                            // the drag. Thus we need to set the effect here as well.
                            e.Effect = ((keyState & NativeMethods.MK_CONTROL) == NativeMethods.MK_CONTROL) ? DragDropEffects.Copy : DragDropEffects.Move; 
                            owner.OnDragEnter(e); 
                        }
                        else { 
                            owner.OnDragDrop(e);
                            lastDataObject = null;
                        }
 
                        lastEffect = e.Effect;
                        if (e.Effect == DragDropEffects.None) { 
                            Debug.WriteLineIf(RichTextDbg.TraceVerbose, "\tCancel data"); 
                            return NativeMethods.E_FAIL;
                        } 
                        else {
                            Debug.WriteLineIf(RichTextDbg.TraceVerbose, "\tAccept data");
                            return NativeMethods.S_OK;
                        } 
                    }
                    else { 
                        Debug.WriteLineIf(RichTextDbg.TraceVerbose, "\tCancel data, allowdrop == false"); 
                        lastDataObject = null;
                        return NativeMethods.E_FAIL; 
                    }
                }
                else {
                    return NativeMethods.E_NOTIMPL; 
                }
            } 
 
            public int ContextSensitiveHelp(int fEnterMode) {
                Debug.WriteLineIf(RichTextDbg.TraceVerbose, "IRichEditOleCallback::ContextSensitiveHelp"); 
                return NativeMethods.E_NOTIMPL;
            }

            public int GetClipboardData(NativeMethods.CHARRANGE lpchrg, int reco, 
                                        IntPtr lplpdataobj) {
                Debug.WriteLineIf(RichTextDbg.TraceVerbose, "IRichEditOleCallback::GetClipboardData"); 
                return NativeMethods.E_NOTIMPL; 
            }
 
            public int GetDragDropEffect(bool fDrag, int grfKeyState, ref int pdwEffect) {
                Debug.WriteLineIf(RichTextDbg.TraceVerbose, "IRichEditOleCallback::GetDragDropEffect");

                if (owner.AllowDrop || owner.EnableAutoDragDrop) { 

                    if (fDrag && grfKeyState == 0) { 
                        // This is the very first call we receive in a Drag-Drop operation, 
                        // so we will let the control know what we support.
 
                        // Note that we haven't gotten any data yet, so we will let QueryAcceptData
                        // do the OnDragEnter. Note too, that grfKeyState does not yet reflect the
                        // current keystate
                        if (owner.EnableAutoDragDrop) { 
                            lastEffect = (DragDropEffects.All | DragDropEffects.None);
                        } 
                        else 
                            lastEffect = DragDropEffects.None;
 
                    }
                    else {
                        // We are either dragging over or dropping
 

                        // The below is the complete reverse of what the docs on MSDN suggest, 
                        // but if we follow the docs, we would be firing OnDragDrop all the 
                        // time instead of OnDragOver (see bug 99294). MSDN seems to be wrong here.
 
                        // drag - fDrag = false, grfKeyState != 0
                        // drop - fDrag = false, grfKeyState = 0
                        // We only care about the drag.
                        // 
                        // When we drop, lastEffect will have the right state
                        if (!fDrag && lastDataObject != null && grfKeyState != 0) { 
 
                            DragEventArgs e = new DragEventArgs(lastDataObject,
                                                                grfKeyState, 
                                                                Control.MousePosition.X,
                                                                Control.MousePosition.Y,
                                                                DragDropEffects.All,
                                                                lastEffect); 

                            // Now tell which of the allowable effects we want to use, but only if we are not already none 
                            if (lastEffect != DragDropEffects.None) { 
                                e.Effect = ((grfKeyState & NativeMethods.MK_CONTROL) == NativeMethods.MK_CONTROL) ? DragDropEffects.Copy : DragDropEffects.Move;
                            } 

                            owner.OnDragOver(e);
                            lastEffect = e.Effect;
                        } 
                    }
 
                    pdwEffect = (int)lastEffect; 

                } 
                else {
                    pdwEffect = (int)DragDropEffects.None;
                }
                return NativeMethods.S_OK; 
            }
 
            public int GetContextMenu(short seltype, IntPtr lpoleobj, NativeMethods.CHARRANGE lpchrg, out IntPtr hmenu) { 
                Debug.WriteLineIf(RichTextDbg.TraceVerbose, "IRichEditOleCallback::GetContextMenu");
                ContextMenu cm = owner.ContextMenu; 
                if (cm == null || owner.ShortcutsEnabled == false)
                    hmenu = IntPtr.Zero;
                else {
                    cm.sourceControl = owner; 
                    cm.OnPopup(EventArgs.Empty);
                    // RichEd calls DestroyMenu after displaying the context menu 
                    IntPtr handle = cm.Handle; 
                    // if another control shares the same context menu
                    // then we have to mark the context menu's handles empty because 
                    // RichTextBox will delete the menu handles once the popup menu is dismissed.
                    Menu menu = cm;
                    while (true) {
                        int i = 0; 
                        int count = menu.ItemCount;
                        for (; i< count; i++) { 
                            if (menu.items[i].handle != IntPtr.Zero) { 
                                menu = menu.items[i];
                                break; 
                            }
                        }
                        if (i == count) {
                            menu.handle = IntPtr.Zero; 
                            menu.created = false;
                            if (menu == cm) 
                                break; 
                            else
                                menu = ((MenuItem) menu).Menu; 
                        }
                    }

                    hmenu = handle; 
                }
 
                return NativeMethods.S_OK; 
            }
        } 
    }
}


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Windows.Forms { 
    using Microsoft.Win32; 
    using System;
    using System.Collections.Specialized; 
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;
    using System.Drawing; 
    using System.Drawing.Design;
    using System.Globalization; 
    using System.IO; 
    using System.Runtime.InteropServices;
    using System.Runtime.Remoting; 
    using System.Runtime.Serialization.Formatters;
    using System.Security;
    using System.Security.Permissions;
    using System.Text; 
    using System.Windows.Forms.ComponentModel;
    using System.Windows.Forms.Design; 
    using System.Windows.Forms.Layout; 

    using IComDataObject = System.Runtime.InteropServices.ComTypes.IDataObject; 
    using Util = NativeMethods.Util;

    //
 

 
 

 
    /// 
    /// 
    ///     Rich Text control. The RichTextBox is a control that contains formatted text.
    ///     It supports font selection, boldface, and other type attributes. 
    /// 
 
    [ClassInterface(ClassInterfaceType.AutoDispatch), 
     ComVisible(true),
     Docking(DockingBehavior.Ask), 
     Designer("System.Windows.Forms.Design.RichTextBoxDesigner, " + AssemblyRef.SystemDesign),
     SRDescription(SR.DescriptionRichTextBox)
   ]
    public class RichTextBox : TextBoxBase { 
        static TraceSwitch richTextDbg;
        static TraceSwitch RichTextDbg { 
            get { 
                if (richTextDbg == null) {
                    richTextDbg = new TraceSwitch("RichTextDbg", "Debug info about RichTextBox"); 
                }
                return richTextDbg;
            }
        } 

        ///  
        ///  
        ///     Paste special flags.
        ///  
        private const int DV_E_DVASPECT      = unchecked((int)0x8004006B);
        private const int DVASPECT_CONTENT   = 1;
        private const int DVASPECT_THUMBNAIL = 2;
        private const int DVASPECT_ICON      = 4; 
        private const int DVASPECT_DOCPRINT  = 8;
 
        internal const int INPUT             = 0x0001; 
        internal const int OUTPUT            = 0x0002;
        internal const int DIRECTIONMASK     = INPUT | OUTPUT; 
        internal const int ANSI              = 0x0004;
        internal const int UNICODE           = 0x0008;
        internal const int FORMATMASK        = ANSI | UNICODE;
        internal const int TEXTLF            = 0x0010; 
        internal const int TEXTCRLF          = 0x0020;
        internal const int RTF               = 0x0040; 
        internal const int KINDMASK          = TEXTLF | TEXTCRLF | RTF; 

        // This is where we store the reched library. 
        private static IntPtr moduleHandle;

        private static readonly string SZ_RTF_TAG      = "{\\rtf";
        private const int CHAR_BUFFER_LEN    = 512; 

        // Event objects 
        // 
        private static readonly object EVENT_HSCROLL          = new object();
        private static readonly object EVENT_LINKACTIVATE     = new object(); 
        private static readonly object EVENT_IMECHANGE        = new object();
        private static readonly object EVENT_PROTECTED        = new object();
        private static readonly object EVENT_REQUESTRESIZE    = new object();
        private static readonly object EVENT_SELCHANGE        = new object(); 
        private static readonly object EVENT_VSCROLL          = new object();
 
 
        // Persistent state
        // 
        private int         bulletIndent;
        private int         rightMargin;
        private string      textRtf; // If not null, takes precedence over cached Text value
        private string      textPlain; 
        private Color selectionBackColorToSetOnHandleCreated;
        RichTextBoxLanguageOptions languageOption = RichTextBoxLanguageOptions.AutoFont | RichTextBoxLanguageOptions.DualFont; 
 
        // Non-persistent state
        // 
        static int logPixelsX;
        static int logPixelsY;
        Stream editStream = null;
        float zoomMultiplier = 1.0f; 

        // used to decide when to fire the selectionChange event. 
        private int curSelStart; 
        private int curSelEnd;
        private short curSelType; 
        object oleCallback;

        private static int[] shortcutsToDisable;
        private static int richEditMajorVersion = 3; //Assume version 3: it'll only be version 2 on Win98, and we don't yet load version 4. 

        private BitVector32 richTextBoxFlags = new BitVector32(); 
        private static readonly BitVector32.Section autoWordSelectionSection = BitVector32.CreateSection(1); 
        private static readonly BitVector32.Section showSelBarSection = BitVector32.CreateSection(1, autoWordSelectionSection);
        private static readonly BitVector32.Section autoUrlDetectSection = BitVector32.CreateSection(1, showSelBarSection); 
        private static readonly BitVector32.Section fInCtorSection = BitVector32.CreateSection(1, autoUrlDetectSection);
        private static readonly BitVector32.Section protectedErrorSection = BitVector32.CreateSection(1, fInCtorSection);
        private static readonly BitVector32.Section linkcursorSection = BitVector32.CreateSection(1, protectedErrorSection);
        private static readonly BitVector32.Section allowOleDropSection = BitVector32.CreateSection(1, linkcursorSection); 
        private static readonly BitVector32.Section suppressTextChangedEventSection = BitVector32.CreateSection(1, allowOleDropSection);
        private static readonly BitVector32.Section callOnContentsResizedSection = BitVector32.CreateSection(1, suppressTextChangedEventSection); 
        private static readonly BitVector32.Section richTextShortcutsEnabledSection = BitVector32.CreateSection(1, callOnContentsResizedSection); 
        private static readonly BitVector32.Section allowOleObjectsSection = BitVector32.CreateSection(1, richTextShortcutsEnabledSection);
        private static readonly BitVector32.Section scrollBarsSection = BitVector32.CreateSection((short) RichTextBoxScrollBars.ForcedBoth, allowOleObjectsSection); 
        private static readonly BitVector32.Section enableAutoDragDropSection = BitVector32.CreateSection(1, scrollBarsSection);

        /// 
        ///  
        ///     Constructs a new RichTextBox.
        ///  
        public RichTextBox() { 
            InConstructor = true;
            richTextBoxFlags[autoWordSelectionSection] = 0;// This is false by default 
            DetectUrls = true;
            ScrollBars = RichTextBoxScrollBars.Both;
            RichTextShortcutsEnabled = true;
            MaxLength = int.MaxValue; 
            Multiline = true;
            AutoSize = false; 
            curSelStart = curSelEnd = curSelType = -1; 
            InConstructor = false;
        } 

        /// 
        /// 
        ///     RichTextBox controls have built-in drag and drop support, but AllowDrop, DragEnter, DragDrop 
        ///     may still be used: this should be hidden in the property grid, but not in code
        ///  
        [Browsable(false)] 
        public override bool AllowDrop {
            get { 
                return richTextBoxFlags[allowOleDropSection] != 0;
            }
            set {
                if (value) { 
                    try
                    { 
                        IntSecurity.ClipboardRead.Demand(); 
                    }
                    catch (Exception e) 
                    {
                        throw new InvalidOperationException(SR.GetString(SR.DragDropRegFailed), e);
                    }
                } 
                richTextBoxFlags[allowOleDropSection] = value ? 1 : 0;
                UpdateOleCallback(); 
            } 
        }
 
        internal bool AllowOleObjects {
            get {
                return richTextBoxFlags[allowOleObjectsSection] != 0;
            } 
            set {
                richTextBoxFlags[allowOleObjectsSection] = value ? 1 : 0; 
            } 
        }
 
        /// 
        /// 
        ///    
        ///       Gets or sets a value indicating whether the size 
        ///       of the control automatically adjusts when the font assigned to the control
        ///       is changed. 
        /// 
        ///       Note: this works differently than other Controls' AutoSize, so we're hiding
        ///       it to avoid confusion. 
        ///    
        /// 
        [
        DefaultValue(false), 
        RefreshProperties(RefreshProperties.Repaint),
        Browsable(false), EditorBrowsable(EditorBrowsableState.Never), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible) 
        ]
        public override bool AutoSize { 
            get {
                return base.AutoSize;
            }
            set { 
                base.AutoSize = value;
            } 
        } 

        ///  
        /// 
        ///     Controls whether whether mouse selection snaps to whole words.
        /// 
        [ 
        SRCategory(SR.CatBehavior),
        DefaultValue(false), 
        SRDescription(SR.RichTextBoxAutoWordSelection) 
        ]
        public bool AutoWordSelection { 
            get { return richTextBoxFlags[autoWordSelectionSection] != 0; }
            set {
                richTextBoxFlags[autoWordSelectionSection] = value ? 1 : 0;
                if (IsHandleCreated) { 
                    SendMessage(RichTextBoxConstants.EM_SETOPTIONS,
                                value ? RichTextBoxConstants.ECOOP_OR : RichTextBoxConstants.ECOOP_XOR, 
                                RichTextBoxConstants.ECO_AUTOWORDSELECTION); 
                }
            } 
        }

        /// 
        ///  
        ///    [To be supplied.]
        ///  
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 
        public override Image BackgroundImage {
            get { 
                return base.BackgroundImage;
            }
            set {
                base.BackgroundImage = value; 
            }
        } 
 
        /// 
        ///  
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler BackgroundImageChanged {
            add {
                base.BackgroundImageChanged += value; 
            }
            remove { 
                base.BackgroundImageChanged -= value; 
            }
        } 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 
        public override ImageLayout BackgroundImageLayout { 
            get {
                return base.BackgroundImageLayout; 
            }
            set {
                base.BackgroundImageLayout = value;
            } 
        }
 
        ///  
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 
        new public event EventHandler BackgroundImageLayoutChanged {
            add {
                base.BackgroundImageLayoutChanged += value;
            } 
            remove {
                base.BackgroundImageLayoutChanged -= value; 
            } 
        }
 
        /// 
        /// 
        ///     Returns the amount of indent used in a RichTextBox control when
        ///     SelectionBullet is set to true. 
        /// 
        [ 
        SRCategory(SR.CatBehavior), 
        DefaultValue(0),
        Localizable(true), 
        SRDescription(SR.RichTextBoxBulletIndent)
        ]
        public int BulletIndent {
            get { 
                return bulletIndent;
            } 
 
            set {
 
                if (value < 0) {
                    throw new ArgumentOutOfRangeException("BulletIndent", SR.GetString(SR.InvalidArgument, "BulletIndent", (value).ToString(CultureInfo.CurrentCulture)));
                }
 
                this.bulletIndent = value;
 
                // Call to update the control only if the bullet is set. 
                if (IsHandleCreated && SelectionBullet)
                    SelectionBullet = true; 
            }
        }

        private bool CallOnContentsResized { 
            get { return richTextBoxFlags[callOnContentsResizedSection] != 0; }
            set { richTextBoxFlags[callOnContentsResizedSection] = value ? 1 : 0; } 
        } 

        internal override bool CanRaiseTextChangedEvent { 
            get {
                return !SuppressTextChangedEvent;
            }
        } 

        ///  
        ///  
        ///      Whether or not there are actions that can be Redone on the RichTextBox control.
        ///  
        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.RichTextBoxCanRedoDescr) 
        ]
        public bool CanRedo { 
            get { 
                if (IsHandleCreated) {
                    bool b; 
                    b = (int)SendMessage(RichTextBoxConstants.EM_CANREDO, 0, 0) != 0;

                    return b;
                } 
                return false;
            } 
        } 

        ///  
        /// 
        ///    [To be supplied.]
        /// 
        protected override CreateParams CreateParams { 
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
            get { 
                // Check for library 
                if (moduleHandle == IntPtr.Zero) {
                    moduleHandle = UnsafeNativeMethods.LoadLibrary(RichTextBoxConstants.DLL_RICHEDIT); 

                    int lastWin32Error = Marshal.GetLastWin32Error();
                    if ((long)moduleHandle < (long)32) {
                        throw new Win32Exception(lastWin32Error, SR.GetString(SR.LoadDLLError,RichTextBoxConstants.DLL_RICHEDIT)); 
                    }
 
                    //Determine whether we're Rich Edit 2.0 or 3.0: see 
                    //http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/richedit/richeditcontrols/aboutricheditcontrols.asp
                    StringBuilder pathBuilder = new StringBuilder(NativeMethods.MAX_PATH); 
                    UnsafeNativeMethods.GetModuleFileName(new HandleRef(null, moduleHandle), pathBuilder, pathBuilder.Capacity);
                    string path = pathBuilder.ToString();
                    new FileIOPermission(FileIOPermissionAccess.Read, path).Assert();
                    FileVersionInfo versionInfo; 
                    try {
                        versionInfo = FileVersionInfo.GetVersionInfo(path); 
                    } 
                    finally {
                        CodeAccessPermission.RevertAssert(); 
                    }
                    Debug.Assert(versionInfo != null && !string.IsNullOrEmpty(versionInfo.ProductVersion), "Couldn't get the version info for the richedit dll");
                    if (versionInfo != null && !string.IsNullOrEmpty(versionInfo.ProductVersion)) {
                        //Note: this only allows for one digit version 
                        int parsedValue;
                        if (int.TryParse(versionInfo.ProductVersion[0].ToString(), out parsedValue)) { 
                            richEditMajorVersion = parsedValue; 
                        }
                    } 
                }

                CreateParams cp = base.CreateParams;
                if (Marshal.SystemDefaultCharSize == 1) { 
                    cp.ClassName = RichTextBoxConstants.WC_RICHEDITA;
                } 
                else { 
                    cp.ClassName = RichTextBoxConstants.WC_RICHEDITW;
                } 

                if (Multiline) {
                    if (((int)ScrollBars & RichTextBoxConstants.RTB_HORIZ) != 0 && !WordWrap) {
                        // RichEd infers word wrap from the absence of horizontal scroll bars 
                        cp.Style |= NativeMethods.WS_HSCROLL;
                        if (((int)ScrollBars & RichTextBoxConstants.RTB_FORCE) != 0) 
                            cp.Style |= RichTextBoxConstants.ES_DISABLENOSCROLL; 
                    }
 
                    if (((int)ScrollBars & RichTextBoxConstants.RTB_VERT) != 0) {
                        cp.Style |= NativeMethods.WS_VSCROLL;
                        if (((int)ScrollBars & RichTextBoxConstants.RTB_FORCE) != 0)
                            cp.Style |= RichTextBoxConstants.ES_DISABLENOSCROLL; 
                    }
                } 
 
                // VSWhidbey 94843: Remove the WS_BORDER style from the control, if we're trying to set it,
                // to prevent the control from displaying the single point rectangle around the 3D border 
                if (BorderStyle.FixedSingle == BorderStyle && ((cp.Style & NativeMethods.WS_BORDER) != 0)) {
                    cp.Style &= (~NativeMethods.WS_BORDER);
                    cp.ExStyle |= NativeMethods.WS_EX_CLIENTEDGE;
                } 

                return cp; 
            } 
        }
 
        // public bool CanUndo {}; <-- inherited from TextBoxBase

        /// 
        ///  
        ///     Controls whether or not the rich edit control will automatically highlight URLs.
        ///     By default, this is true. Note that changing this property will not update text that is 
        ///     already present in the RichTextBox control; it only affects text which is entered after the 
        ///     property is changed.
        ///  
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(true),
        SRDescription(SR.RichTextBoxDetectURLs) 
        ]
        public bool DetectUrls { 
            get { 
                return richTextBoxFlags[autoUrlDetectSection] != 0;
            } 
            set {
                if (value != DetectUrls) {
                    richTextBoxFlags[autoUrlDetectSection] = value ? 1 : 0;
                    if (IsHandleCreated) { 
                        this.SendMessage(RichTextBoxConstants.EM_AUTOURLDETECT, value ? 1 : 0, 0);
                        RecreateHandle(); 
                    } 
                }
            } 
        }

        /// 
        protected override Size DefaultSize { 
            get {
                return new Size(100, 96); 
            } 
        }
 
        /// 
        /// 
        ///     We can't just enable drag/drop of text by default: it's a breaking change (VSWhidbey
        ///     375177).  Should be false by default. 
        /// 
        [ 
        SRCategory(SR.CatBehavior), 
        DefaultValue(false),
        SRDescription(SR.RichTextBoxEnableAutoDragDrop) 
        ]
        public bool EnableAutoDragDrop
        {
            get 
            {
                return richTextBoxFlags[enableAutoDragDropSection] != 0; 
            } 
            set
            { 
                if (value)
                {
                    try
                    { 
                        IntSecurity.ClipboardRead.Demand();
                    } 
                    catch (Exception e) 
                    {
                        throw new InvalidOperationException(SR.GetString(SR.DragDropRegFailed), e); 
                    }
                }
                richTextBoxFlags[enableAutoDragDropSection] = value ? 1 : 0;
                UpdateOleCallback(); 
            }
        } 
 
        /// 
        public override Color ForeColor { 
            get {
                return base.ForeColor;
            }
            set { 
                if (IsHandleCreated) {
                    if (InternalSetForeColor(value)) { 
                        base.ForeColor = value; 
                    }
                } 
                else {
                    base.ForeColor = value;
                }
            } 
        }
 
        ///  
        public override Font Font {
            get { 
                return base.Font;
            }
            set {
                if (IsHandleCreated) 
                {
                    if (SafeNativeMethods.GetWindowTextLength(new HandleRef(this, Handle)) > 0) { 
                        if (value == null) { 
                            base.Font = null;
                            SetCharFormatFont(false, Font); 
                        }
                        else {
                            try{
                                Font f = GetCharFormatFont(false); 
                                if (f == null || !f.Equals (value)) {
                                    SetCharFormatFont(false, value); 
                                    // update controlfont from "resolved" font from the attempt 
                                    // to set the document font...
                                    // 
                                    CallOnContentsResized = true;
                                    base.Font = GetCharFormatFont(false);
                                }
                            } 
                            finally{
                                CallOnContentsResized = false; 
                            } 
                        }
                    } 
                    else {
                        base.Font = value;
                    }
                } 
                else {
                    base.Font = value; 
                } 
            }
        } 

        internal override Size GetPreferredSizeCore(Size proposedConstraints) {
            Size scrollBarPadding = Size.Empty;
 
            //If the RTB is multiline, we won't have a horizontal scrollbar.
            if (!WordWrap && Multiline && (ScrollBars & RichTextBoxScrollBars.Horizontal) != 0) { 
                scrollBarPadding.Height += SystemInformation.HorizontalScrollBarHeight; 
            }
            if (Multiline && (ScrollBars & RichTextBoxScrollBars.Vertical) != 0) { 
                scrollBarPadding.Width += SystemInformation.VerticalScrollBarWidth;
            }

            // Subtract the scroll bar padding before measuring 
            proposedConstraints -= scrollBarPadding;
 
            Size prefSize = base.GetPreferredSizeCore(proposedConstraints); 

            return prefSize + scrollBarPadding; 
        }

        private bool InConstructor {
            get { return richTextBoxFlags[fInCtorSection] != 0; } 
            set { richTextBoxFlags[fInCtorSection] = value ? 1 : 0; }
        } 
 
        /// 
        ///     Sets or gets the rich text box control' language option. 
        ///     The IMF_AUTOFONT flag is set by default.
        ///     The IMF_AUTOKEYBOARD and IMF_IMECANCELCOMPLETE flags are cleared by default.
        /// 
        [ 
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) 
        ] 
        public RichTextBoxLanguageOptions LanguageOption
        { 
            get
            {
                RichTextBoxLanguageOptions opt;
                if (IsHandleCreated) { 
                    opt = (RichTextBoxLanguageOptions)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETLANGOPTIONS, 0, 0);
                } 
                else { 
                    opt = languageOption;
                } 
                return opt;
            }
            set
            { 
                if (this.LanguageOption != value)
                { 
                    this.languageOption = value; 
                    if (IsHandleCreated) {
                        UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETLANGOPTIONS, 0, (int) value); 
                    }
                }
            }
        } 

        private bool LinkCursor { 
            get { return richTextBoxFlags[linkcursorSection] != 0; } 
            set { richTextBoxFlags[linkcursorSection] = value ? 1 : 0; }
        } 

        /// 
        [
        DefaultValue(int.MaxValue), 
        ]
        public override int MaxLength { 
            get { 
                return base.MaxLength;
            } 
            set {
                base.MaxLength = value;
            }
        } 
        /// 
        ///  
        ///    [To be supplied.] 
        /// 
        [DefaultValue(true)] 
        public override bool Multiline {
            get {
                return base.Multiline;
            } 
            set {
                base.Multiline = value; 
            } 
        }
 
        private bool ProtectedError {
            get { return richTextBoxFlags[protectedErrorSection] != 0; }
            set { richTextBoxFlags[protectedErrorSection] = value ? 1 : 0; }
        } 

        ///  
        ///  
        ///     Returns the name of the action that will be performed if the user
        ///     Redo's their last Undone operation. If no operation can be redone, 
        ///     an empty string ("") is returned.
        /// 
        //NOTE: This is overridable, because we want people to be able to
        //      mess with the names if necessary...? 
        [
        SRCategory(SR.CatBehavior), 
        Browsable(false), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.RichTextBoxRedoActionNameDescr) 
        ]
        public string RedoActionName {
            get {
                if (!CanRedo) return ""; 
                int n;
                n = (int)SendMessage(RichTextBoxConstants.EM_GETREDONAME, 0, 0); 
                return GetEditorActionName(n); 
            }
        } 

        /// 
        //Description: Specifies whether rich text formatting keyboard shortcuts are enabled.
        [ 
        DefaultValue(true),
        Browsable(false), 
        EditorBrowsable(EditorBrowsableState.Never) 
        ]
        public bool RichTextShortcutsEnabled { 
            get { return richTextBoxFlags[richTextShortcutsEnabledSection] != 0; }
            set {
                if (shortcutsToDisable == null) {
                    shortcutsToDisable = new int[] {(int)Shortcut.CtrlL, (int)Shortcut.CtrlR, (int)Shortcut.CtrlE, (int)Shortcut.CtrlJ}; 
                }
                richTextBoxFlags[richTextShortcutsEnabledSection] = value ? 1 : 0; 
            } 
        }
 
        /// 
        /// 
        ///     The right margin of a RichTextBox control.  A nonzero margin implies WordWrap.
        ///  
        [
        SRCategory(SR.CatBehavior), 
        DefaultValue(0), 
        Localizable(true),
        SRDescription(SR.RichTextBoxRightMargin) 
        ]
        public int RightMargin {
            get {
                return rightMargin; 
            }
            set { 
                if (this.rightMargin != value) { 
                    if (value < 0)
                        throw new ArgumentOutOfRangeException("RightMargin", SR.GetString(SR.InvalidLowBoundArgumentEx, "RightMargin", value.ToString(CultureInfo.CurrentCulture), (0).ToString(CultureInfo.CurrentCulture))); 
                    this.rightMargin = value;

                    if (value == 0) {
                        // Once you set EM_SETTARGETDEVICE to something nonzero, RichEd will assume 
                        // word wrap forever and ever.
                        RecreateHandle(); 
                    } 
                    else if (IsHandleCreated) {
                        IntPtr hDC = UnsafeNativeMethods.CreateIC("DISPLAY", null, null, new HandleRef(null, IntPtr.Zero)); 
                        try {
                            SendMessage(RichTextBoxConstants.EM_SETTARGETDEVICE, hDC, (IntPtr)Pixel2Twip(hDC, value, true));
                        }
                        finally { 
                            if (hDC != IntPtr.Zero) {
                                UnsafeNativeMethods.DeleteDC(new HandleRef(null, hDC)); 
                            } 
                        }
                    } 
                }
            }
        }
 
        /// 
        ///  
        ///     The text of a RichTextBox control, including all Rtf codes. 
        /// 
        [ 
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.RichTextBoxRTF),
        RefreshProperties(RefreshProperties.All) 
        ]
        public string Rtf { 
            get { 
                if (IsHandleCreated)
                { 
                    return StreamOut(RichTextBoxConstants.SF_RTF);
                }
                else if (textPlain != null)
                { 
                    ForceHandleCreate();
                    return StreamOut(RichTextBoxConstants.SF_RTF); 
                } 
                else
                { 
                    return textRtf;
                }
            }
            set { 
                if (value == null) value = "";
 
                if (value.Equals(Rtf)) 
                    return;
 
                ForceHandleCreate();
                textRtf = value;
                StreamIn(value, RichTextBoxConstants.SF_RTF);
                if (CanRaiseTextChangedEvent) { 
                    OnTextChanged(EventArgs.Empty);
                } 
            } 
        }
 
        /// 
        /// 
        ///     The current scrollbar settings for a multi-line rich edit control.
        ///     Possible return values are given by the RichTextBoxScrollBars enumeration. 
        /// 
        [ 
        SRCategory(SR.CatAppearance), 
        DefaultValue(RichTextBoxScrollBars.Both),
        Localizable(true), 
        SRDescription(SR.RichTextBoxScrollBars)
        ]
        public RichTextBoxScrollBars ScrollBars {
            get { 
                return (RichTextBoxScrollBars) richTextBoxFlags[scrollBarsSection];
            } 
            set { 
                // we could be more clever here, but it doesnt seem like this would get set enough
                // to warrant a clever bitmask. 
                if (!ClientUtils.IsEnumValid_NotSequential(value,
                    (int)value,
                    (int)RichTextBoxScrollBars.Both,
                    (int)RichTextBoxScrollBars.None, 
                    (int)RichTextBoxScrollBars.Horizontal,
                    (int)RichTextBoxScrollBars.Vertical, 
                    (int)RichTextBoxScrollBars.ForcedHorizontal, 
                    (int)RichTextBoxScrollBars.ForcedVertical,
                    (int)RichTextBoxScrollBars.ForcedBoth)) { 

                    throw new InvalidEnumArgumentException("value", (int)value, typeof(RichTextBoxScrollBars));
                }
 
                if (value != ScrollBars) {
                    using (LayoutTransaction.CreateTransactionIf(AutoSize, ParentInternal, this, PropertyNames.ScrollBars)) { 
                        richTextBoxFlags[scrollBarsSection] = (int) value; 
                        RecreateHandle();
                    } 
                }
            }
        }
 
        /// 
        ///  
        ///     The alignment of the paragraphs in a RichTextBox control. 
        /// 
        [ 
        DefaultValue(HorizontalAlignment.Left),
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.RichTextBoxSelAlignment) 
        ]
        public HorizontalAlignment SelectionAlignment { 
            get { 
                HorizontalAlignment selectionAlignment = HorizontalAlignment.Left;
 
                ForceHandleCreate();
                NativeMethods.PARAFORMAT pf = new NativeMethods.PARAFORMAT();
                pf.rgxTabs = new int[RichTextBoxConstants.MAX_TAB_STOPS];
 
                // get the format for our currently selected paragraph
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETPARAFORMAT, 0, pf); 
 
                // check if alignment has been set yet
                if ((RichTextBoxConstants.PFM_ALIGNMENT & pf.dwMask) != 0) { 
                    switch (pf.wAlignment) {
                        case RichTextBoxConstants.PFA_LEFT:
                            selectionAlignment = HorizontalAlignment.Left;
                            break; 

                        case RichTextBoxConstants.PFA_RIGHT: 
                            selectionAlignment = HorizontalAlignment.Right; 
                            break;
 
                        case RichTextBoxConstants.PFA_CENTER:
                            selectionAlignment = HorizontalAlignment.Center;
                            break;
                    } 
                }
 
                return selectionAlignment; 
            }
            set { 
                //valid values are 0x0 to 0x2
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)HorizontalAlignment.Left, (int)HorizontalAlignment.Center))
                {
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(HorizontalAlignment)); 
                }
 
                ForceHandleCreate(); 
                NativeMethods.PARAFORMAT pf = new NativeMethods.PARAFORMAT();
                pf.dwMask = RichTextBoxConstants.PFM_ALIGNMENT; 
                switch (value) {

                    case HorizontalAlignment.Left:
                        pf.wAlignment = RichTextBoxConstants.PFA_LEFT; 
                        break;
 
                    case HorizontalAlignment.Right: 
                        pf.wAlignment = RichTextBoxConstants.PFA_RIGHT;
                        break; 

                    case HorizontalAlignment.Center:
                        pf.wAlignment = RichTextBoxConstants.PFA_CENTER;
                        break; 
                }
 
                // set the format for our current paragraph or selection 
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETPARAFORMAT, 0, pf);
            } 
        }

        /// 
        ///  
        ///     Determines if a paragraph in the RichTextBox control
        ///     contains the current selection or insertion point has the bullet style. 
        ///  
        [
        DefaultValue(false), 
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.RichTextBoxSelBullet)
        ] 
        public bool SelectionBullet {
            get { 
                RichTextBoxSelectionAttribute selectionBullet = RichTextBoxSelectionAttribute.None; 

                ForceHandleCreate(); 
                NativeMethods.PARAFORMAT pf = new NativeMethods.PARAFORMAT();
                pf.rgxTabs = new int[RichTextBoxConstants.MAX_TAB_STOPS];

                // get the format for our currently selected paragraph 
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETPARAFORMAT, 0, pf);
 
                // check if alignment has been set yet 
                if ((RichTextBoxConstants.PFM_NUMBERING & pf.dwMask) != 0) {
                    if (RichTextBoxConstants.PFN_BULLET == pf.wNumbering) { 
                        selectionBullet = RichTextBoxSelectionAttribute.All;
                    }
                }
                else { 
                    // For paragraphs with mixed SelectionBullets, we just return false
                    return false; 
                } 

                return selectionBullet == RichTextBoxSelectionAttribute.All; 
            }
            set {
                ForceHandleCreate();
 
                NativeMethods.PARAFORMAT pf = new NativeMethods.PARAFORMAT();
                pf.dwMask = RichTextBoxConstants.PFM_NUMBERING | RichTextBoxConstants.PFM_OFFSET; 
 
                if (!value) {
                    pf.wNumbering = 0; 
                    pf.dxOffset = 0;
                }
                else {
                    pf.wNumbering = RichTextBoxConstants.PFN_BULLET; 
                    pf.dxOffset = Pixel2Twip(IntPtr.Zero, bulletIndent, true);
                } 
                // set the format for our current paragraph or selection 
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETPARAFORMAT, 0, pf);
            } 
        }

        /// 
        ///  
        ///     Determines whether text in the RichTextBox control
        ///     appears on the baseline (normal), as a superscript above the baseline, 
        ///     or as a subscript below the baseline. 
        /// 
        [ 
        DefaultValue(0),
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.RichTextBoxSelCharOffset) 
        ]
        public int SelectionCharOffset { 
            get { 
                int selCharOffset = 0;
 
                ForceHandleCreate();
                NativeMethods.CHARFORMATA cf = GetCharFormat(true);
                // if the effects member contains valid info
                if ((cf.dwMask & RichTextBoxConstants.CFM_OFFSET) != 0) { 
                    selCharOffset = cf.yOffset;
                } 
                else { 
                    // The selection contains characters of different offsets,
                    // so we just return the offset of the first character. 
                    selCharOffset = cf.yOffset;
                }

                return Twip2Pixel(IntPtr.Zero,selCharOffset,false); 
            }
            set { 
                if (value > 2000 || value < -2000) 
                    throw new ArgumentOutOfRangeException("SelectionCharOffset", SR.GetString(SR.InvalidBoundArgument, "SelectionCharOffset", value, -2000, 2000));
 
                ForceHandleCreate();
                NativeMethods.CHARFORMATA cf = new NativeMethods.CHARFORMATA();
                cf.dwMask = RichTextBoxConstants.CFM_OFFSET;
                cf.yOffset = Pixel2Twip(IntPtr.Zero, value, false); 

                // Set the format information 
                // SendMessage will force the handle to be created if it hasn't already. Normally, 
                // we would cache property values until the handle is created - but for this property,
                // it's far more simple to just create the handle. 
                //
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETCHARFORMAT, RichTextBoxConstants.SCF_SELECTION, cf);
            }
        } 

        ///  
        ///  
        ///     The color of the currently selected text in the
        ///     RichTextBox control. 
        ///     Returns Color.Empty if the selection has more than one color.
        /// 
        [
        Browsable(false), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.RichTextBoxSelColor) 
        ] 
        public Color SelectionColor {
            get { 
                Color selColor = Color.Empty;

                ForceHandleCreate();
                NativeMethods.CHARFORMATA cf = GetCharFormat(true); 
                // if the effects member contains valid info
                if ((cf.dwMask & RichTextBoxConstants.CFM_COLOR) != 0) 
                    selColor = ColorTranslator.FromOle(cf.crTextColor); 

                return selColor; 
            }
            set {
                ForceHandleCreate();
                NativeMethods.CHARFORMATA cf = GetCharFormat(true); 
                cf.dwMask = RichTextBoxConstants.CFM_COLOR;
                cf.dwEffects = 0; 
                cf.crTextColor = ColorTranslator.ToWin32(value); 

                // set the format information 
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETCHARFORMAT, RichTextBoxConstants.SCF_SELECTION, cf);
            }
        }
 
        /// 
        ///  
        ///     The background color of the currently selected text in the RichTextBox control. 
        ///     Returns Color.Empty if the selection has more than one color.
        ///  
        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.RichTextBoxSelBackColor) 
        ]
        public Color SelectionBackColor { 
            get { 
                Color selColor = Color.Empty;
 
                if (IsHandleCreated) {
                    NativeMethods.CHARFORMAT2A cf2 = GetCharFormat2(true);
                    // If the effects member contains valid info
                    if ((cf2.dwEffects & RichTextBoxConstants.CFE_AUTOBACKCOLOR) != 0) { 
                        selColor = this.BackColor;
                    } 
                    else if ((cf2.dwMask & RichTextBoxConstants.CFM_BACKCOLOR) != 0) { 
                        selColor = ColorTranslator.FromOle(cf2.crBackColor);
                    } 
                }
                else {
                    selColor = selectionBackColorToSetOnHandleCreated;
                } 
                return selColor;
            } 
            set 
            {
                //Note: don't compare the value to the old value here: it's possible that 
                //you have a different range selected.
                selectionBackColorToSetOnHandleCreated = value;
                if (IsHandleCreated)
                { 
                    NativeMethods.CHARFORMAT2A cf2 = new NativeMethods.CHARFORMAT2A();
                    if (value == Color.Empty) 
                    { 
                        cf2.dwEffects = RichTextBoxConstants.CFE_AUTOBACKCOLOR;
                    } 
                    else
                    {
                        cf2.dwMask = RichTextBoxConstants.CFM_BACKCOLOR;
                        cf2.crBackColor = ColorTranslator.ToWin32(value); 
                    }
 
                    UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETCHARFORMAT, RichTextBoxConstants.SCF_SELECTION, cf2); 
                }
            } 
        }

        /// 
        ///  
        ///     The font used to display the currently selected text
        ///     or the characters(s) immediately following the insertion point in the 
        ///     RichTextBox control.  Null if the selection has more than one font. 
        /// 
        [ 
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.RichTextBoxSelFont)
        ] 
        public Font SelectionFont {
            get { 
                return GetCharFormatFont(true); 
            }
            set { 
                SetCharFormatFont(true, value);
            }
        }
 

        ///  
        ///  
        ///     The distance (in pixels) between the left edge of the first line of text
        ///     in the selected paragraph(s) (as specified by the SelectionIndent property) 
        ///     and the left edge of subsequent lines of text in the same paragraph(s).
        /// 
        [
        DefaultValue(0), 
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 
        SRDescription(SR.RichTextBoxSelHangingIndent) 
        ]
        public int SelectionHangingIndent { 
            get {
                int selHangingIndent = 0;

                ForceHandleCreate(); 
                NativeMethods.PARAFORMAT pf = new NativeMethods.PARAFORMAT();
                pf.rgxTabs = new int[RichTextBoxConstants.MAX_TAB_STOPS]; 
 
                // get the format for our currently selected paragraph
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETPARAFORMAT, 0, pf); 

                // check if alignment has been set yet
                if ((RichTextBoxConstants.PFM_OFFSET & pf.dwMask) != 0)
                    selHangingIndent = pf.dxOffset; 

                return Twip2Pixel(IntPtr.Zero, selHangingIndent, true); 
            } 
            set {
                ForceHandleCreate(); 

                NativeMethods.PARAFORMAT pf = new NativeMethods.PARAFORMAT();
                pf.dwMask = RichTextBoxConstants.PFM_OFFSET;
                pf.dxOffset = Pixel2Twip(IntPtr.Zero, value, true); 

                // set the format for our current paragraph or selection 
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETPARAFORMAT, 0, pf); 
            }
        } 

        /// 
        /// 
        ///     The distance (in pixels) between the left edge of the RichTextBox control and 
        ///     the left edge of the text that is selected or added at the current
        ///     insertion point. 
        ///  
        [
        DefaultValue(0), 
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.RichTextBoxSelIndent)
        ] 
        public int SelectionIndent {
            get { 
                int selIndent = 0; 

                ForceHandleCreate(); 
                NativeMethods.PARAFORMAT pf = new NativeMethods.PARAFORMAT();
                pf.rgxTabs = new int[RichTextBoxConstants.MAX_TAB_STOPS];

                // get the format for our currently selected paragraph 
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETPARAFORMAT, 0, pf);
 
                // check if alignment has been set yet 
                if ((RichTextBoxConstants.PFM_STARTINDENT & pf.dwMask) != 0)
                    selIndent = pf.dxStartIndent; 

                return Twip2Pixel(IntPtr.Zero, selIndent, true);
            }
            set { 
                ForceHandleCreate();
 
                NativeMethods.PARAFORMAT pf = new NativeMethods.PARAFORMAT(); 
                pf.dwMask = RichTextBoxConstants.PFM_STARTINDENT;
                pf.dxStartIndent = Pixel2Twip(IntPtr.Zero, value, true); 

                // set the format for our current paragraph or selection
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETPARAFORMAT, 0, pf);
            } 
        }
 
        ///  
        /// 
        ///     
        ///       Gets or sets the number of characters selected in the text
        ///       box.
        ///    
        ///  
        [
        SRCategory(SR.CatAppearance), 
        Browsable(false), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.TextBoxSelectionLengthDescr) 
        ]
        public override int SelectionLength {
            get {
 
                if (!IsHandleCreated) {
                    return base.SelectionLength; 
                } 

                // RichTextBox allows the user to select the EOF character, 
                // but we don't want to include this in the SelectionLength.
                // So instead of sending EM_GETSEL, we just obtain the SelectedText and return
                // the length of it.
                // 
                return SelectedText.Length;
            } 
 
            set {
                base.SelectionLength = value; 
            }
        }

        ///  
        /// 
        ///     true if the current selection prevents any changes to its contents. 
        ///  
        [
        DefaultValue(false), 
        SRDescription(SR.RichTextBoxSelProtected),
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ] 
        public bool SelectionProtected {
            get { 
                ForceHandleCreate(); 
                return GetCharFormat(RichTextBoxConstants.CFM_PROTECTED, RichTextBoxConstants.CFM_PROTECTED) == RichTextBoxSelectionAttribute.All;
            } 
            set {
                ForceHandleCreate();
                SetCharFormat(RichTextBoxConstants.CFM_PROTECTED, value ? RichTextBoxConstants.CFE_PROTECTED : 0, RichTextBoxSelectionAttribute.All);
            } 
        }
 
        ///  
        ///     Specifies whether the control uses unicode to set/get text selection information (WM_GESEL/WM_SETSEL)
        ///     in Win9x. 
        /// 
        internal override bool SelectionUsesDbcsOffsetsInWin9x {
            get {
                return false; // false for RichEdit, true for Edit. 
            }
        } 
 
        /// 
        ///  
        ///     The currently selected text of a RichTextBox control, including
        ///     all Rtf codes.
        /// 
        [ 
        DefaultValue(""),
        Browsable(false), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 
        SRDescription(SR.RichTextBoxSelRTF)
        ] 
        public string SelectedRtf {
            get {
                ForceHandleCreate();
                return StreamOut(RichTextBoxConstants.SFF_SELECTION | RichTextBoxConstants.SF_RTF); 
            }
            set { 
                ForceHandleCreate(); 
                if (value == null) value = "";
                StreamIn(value, RichTextBoxConstants.SFF_SELECTION | RichTextBoxConstants.SF_RTF); 
            }
        }

        ///  
        /// 
        ///     The distance (in pixels) between the right edge of the RichTextBox control and 
        ///     the right edge of the text that is selected or added at the current 
        ///     insertion point.
        ///  
        [
        DefaultValue(0),
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 
        SRDescription(SR.RichTextBoxSelRightIndent)
        ] 
        public int SelectionRightIndent { 
            get {
                int selRightIndent = 0; 

                ForceHandleCreate();

                NativeMethods.PARAFORMAT pf = new NativeMethods.PARAFORMAT(); 
                pf.rgxTabs = new int[RichTextBoxConstants.MAX_TAB_STOPS];
 
                // get the format for our currently selected paragraph 
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETPARAFORMAT, 0, pf);
 
                // check if alignment has been set yet
                if ((RichTextBoxConstants.PFM_RIGHTINDENT & pf.dwMask) != 0)
                    selRightIndent = pf.dxRightIndent;
 
                return Twip2Pixel(IntPtr.Zero, selRightIndent, true);
            } 
            set { 
                if (value < 0)
                    throw new ArgumentOutOfRangeException("SelectionRightIndent", SR.GetString(SR.InvalidLowBoundArgumentEx, "SelectionRightIndent", value, 0)); 

                ForceHandleCreate();
                NativeMethods.PARAFORMAT pf = new NativeMethods.PARAFORMAT();
                pf.dwMask = RichTextBoxConstants.PFM_RIGHTINDENT; 
                pf.dxRightIndent = Pixel2Twip(IntPtr.Zero, value, true);
 
                // set the format for our current paragraph or selection 
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETPARAFORMAT, 0, pf);
            } 
        }

        /// 
        ///  
        ///     The absolute tab positions (in pixels) of text in a RichTextBox control.
        ///  
        [ 
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 
        SRDescription(SR.RichTextBoxSelTabs)
        ]
        public int[] SelectionTabs {
            get { 
                int[] selTabs = new int[0];
 
                ForceHandleCreate(); 
                NativeMethods.PARAFORMAT pf = new NativeMethods.PARAFORMAT();
                pf.rgxTabs = new int[RichTextBoxConstants.MAX_TAB_STOPS]; 

                // get the format for our currently selected paragraph
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETPARAFORMAT, 0, pf);
 
                // check if alignment has been set yet
                if ((RichTextBoxConstants.PFM_TABSTOPS & pf.dwMask) != 0) { 
                    selTabs = new int[pf.cTabCount]; 
                    for (int x = 0; x < pf.cTabCount; x++)
                        selTabs[x] = Twip2Pixel(IntPtr.Zero, pf.rgxTabs[x], true); 
                }

                return selTabs;
            } 
            set {
                // Verify the argument, and throw an error if is bad 
                if (value != null && value.Length > RichTextBoxConstants.MAX_TAB_STOPS) 
                    throw new ArgumentOutOfRangeException("SelectionTabs", SR.GetString(SR.SelTabCountRange));
 
                ForceHandleCreate();
                NativeMethods.PARAFORMAT pf = new NativeMethods.PARAFORMAT();
                pf.rgxTabs = new int[RichTextBoxConstants.MAX_TAB_STOPS];
 
                // get the format for our currently selected paragraph because
                // we need to get the number of tabstops to copy 
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETPARAFORMAT, 0, pf); 

                pf.cTabCount = (short)((value == null) ? 0 : value.Length); 
                pf.dwMask = RichTextBoxConstants.PFM_TABSTOPS;
                for (int x = 0; x < pf.cTabCount; x++)
                    pf.rgxTabs[x] = Pixel2Twip(IntPtr.Zero, value[x], true);
 
                // set the format for our current paragraph or selection
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETPARAFORMAT, 0, pf); 
            } 
        }
 
        /// 
        /// 
        ///     The currently selected text of a RichTextBox control; consists of a
        ///     zero length string if no characters are selected. 
        /// 
        [ 
        DefaultValue(""), 
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 
        SRDescription(SR.RichTextBoxSelText)
        ]
        public override string SelectedText {
            get { 
                ForceHandleCreate();
 
                String text = StreamOut(RichTextBoxConstants.SFF_SELECTION | RichTextBoxConstants.SF_TEXT | RichTextBoxConstants.SF_UNICODE); 
                return text;
            } 
            set {
                ForceHandleCreate();
                StreamIn(value, RichTextBoxConstants.SFF_SELECTION | RichTextBoxConstants.SF_TEXT | RichTextBoxConstants.SF_UNICODE);
            } 
        }
 
        ///  
        /// 
        ///     The type of the current selection. The returned value is one 
        ///     of the values enumerated in RichTextBoxSelectionType.
        /// 
        [
        SRCategory(SR.CatBehavior), 
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 
        SRDescription(SR.RichTextBoxSelTypeDescr) 
        ]
        public RichTextBoxSelectionTypes SelectionType { 
            get {
                ForceHandleCreate();
                if (SelectionLength > 0) {
                    int n; 
                    n =  (int)SendMessage(RichTextBoxConstants.EM_SELECTIONTYPE, 0, 0);
                    return (RichTextBoxSelectionTypes)n; 
                } 
                else {
                    return RichTextBoxSelectionTypes.Empty; 
                }
            }
        }
 
        /// 
        ///  
        ///     Whether or not the left edge of the control will have a "selection margin" which 
        ///     can be used to select entire lines
        ///  
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(false),
        SRDescription(SR.RichTextBoxSelMargin) 
        ]
        public bool ShowSelectionMargin { 
            get { return richTextBoxFlags[showSelBarSection] != 0; } 
            set {
                if (value != ShowSelectionMargin) { 
                    richTextBoxFlags[showSelBarSection] = value ? 1 : 0;
                    if (IsHandleCreated) {
                        SendMessage(RichTextBoxConstants.EM_SETOPTIONS,
                            value ? RichTextBoxConstants.ECOOP_OR : 
                            RichTextBoxConstants.ECOOP_XOR,
                            RichTextBoxConstants.ECO_SELECTIONBAR); 
                    } 
                }
            } 
        }

        /// 
        ///  
        ///    [To be supplied.]
        ///  
        [ 
        Localizable(true),
        RefreshProperties(RefreshProperties.All) 
        ]
        public override string Text {
            get {
                if (IsDisposed) { 
                    return base.Text;
                } 
 
                if (RecreatingHandle || GetAnyDisposingInHierarchy()) {
                    // We can return any old garbage if we're in the process of recreating the handle 
                    return "";
                }

                if (!IsHandleCreated && textRtf == null) { 
                    if (textPlain != null) {
                        return textPlain; 
                    } 
                    else {
                        return base.Text; 
                    }
                }
                else {
                    // if the handle is created, we are golden, however 
                    // if the handle isn't created, but textRtf was
                    // specified, we need the RichEdit to translate 
                    // for us, so we must create the handle; 
                    //
                    ForceHandleCreate(); 

                    return StreamOut(RichTextBoxConstants.SF_TEXT | RichTextBoxConstants.SF_UNICODE);
                }
            } 
            set {
                using(LayoutTransaction.CreateTransactionIf(AutoSize, ParentInternal, this, PropertyNames.Text)) { 
                    textRtf = null; 
                    if (!IsHandleCreated) {
                        textPlain = value; 
                    }
                    else {
                        textPlain = null;
                        if (value == null) { 
                            value = "";
                        } 
                        StreamIn(value, RichTextBoxConstants.SF_TEXT | RichTextBoxConstants.SF_UNICODE); 
                        // reset Modified
                        SendMessage(NativeMethods.EM_SETMODIFY, 0, 0); 
                    }
                }
            }
        } 

        private bool SuppressTextChangedEvent { 
            get { return richTextBoxFlags[suppressTextChangedEventSection] != 0; } 
            set {
                bool oldValue = SuppressTextChangedEvent; 
                if (value != oldValue) {
                    richTextBoxFlags[suppressTextChangedEventSection] = value ? 1 : 0;
                    CommonProperties.xClearPreferredSizeCache(this);
                } 
            }
        } 
 
        /// 
        [Browsable(false)] 
        public override int TextLength {
            get
            {
                NativeMethods.GETTEXTLENGTHEX gtl = new NativeMethods.GETTEXTLENGTHEX(); 

                gtl.flags = RichTextBoxConstants.GTL_NUMCHARS; 
 
                if (Marshal.SystemDefaultCharSize == 1 /*ANSI*/)
                { 
                    gtl.codepage = 0;  /* CP_ANSI */;
                }
                else
                { 
                    gtl.codepage = 1200; /* CP_UNICODE */
                } 
 
                return (int) UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETTEXTLENGTHEX, gtl, 0 /*ignored*/);
            } 
        }

        /// 
        ///  
        ///     Returns the name of the action that will be undone if the user
        ///     Undo's their last operation. If no operation can be undone, it will 
        ///     return an empty string (""). 
        /// 
        //NOTE: This is overridable, because we want people to be able to 
        //      mess with the names if necessary...?
        [
        SRCategory(SR.CatBehavior),
        Browsable(false), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.RichTextBoxUndoActionNameDescr) 
        ] 
        public string UndoActionName {
            get { 
                if (!CanUndo) return "";
                int n;
                n = (int)SendMessage(RichTextBoxConstants.EM_GETUNDONAME, 0, 0);
                return GetEditorActionName(n); 
            }
        } 
 
        private string GetEditorActionName(int actionID) {
            switch (actionID) { 
                case 0:
                    return SR.GetString(SR.RichTextBox_IDUnknown);
                case 1:
                    return SR.GetString(SR.RichTextBox_IDTyping); 
                case 2:
                    return SR.GetString(SR.RichTextBox_IDDelete); 
                case 3: 
                    return SR.GetString(SR.RichTextBox_IDDragDrop);
                case 4: 
                    return SR.GetString(SR.RichTextBox_IDCut);
                case 5:
                    return SR.GetString(SR.RichTextBox_IDPaste);
                default: 
                    goto
                case 0; 
            } 
        }
 
        /// 
        /// 
        ///     The current zoom level for the RichTextBox control. This may be between 1/64 and 64. 1.0 indicates
        ///     no zoom (i.e. normal viewing).  Zoom works best with TrueType fonts; 
        ///     for non-TrueType fonts, ZoomFactor will be treated as the nearest whole number.
        ///  
        [ 
        SRCategory(SR.CatBehavior),
        DefaultValue(1.0f), 
        Localizable(true),
        SRDescription(SR.RichTextBoxZoomFactor)
        ]
        public float ZoomFactor { 
            get {
                if (IsHandleCreated) { 
                    int numerator = 0; 
                    int denominator = 0;
                    SendMessage(RichTextBoxConstants.EM_GETZOOM, ref numerator, ref denominator); 
                    if ( (numerator != 0) && (denominator != 0) ) {
                        zoomMultiplier = ((float)numerator)/((float)denominator);
                    }
                    else { 
                        zoomMultiplier = 1.0f;
                    } 
                    return zoomMultiplier; 
                }
                else return zoomMultiplier; 
            }

            set {
                if (zoomMultiplier == value) return; 

                if (value <= 0.015625f || value >= 64.0f) 
                    throw new ArgumentOutOfRangeException("ZoomFactor", SR.GetString(SR.InvalidExBoundArgument, "ZoomFactor", (value).ToString(CultureInfo.CurrentCulture), (0.015625f).ToString(CultureInfo.CurrentCulture), (64.0f).ToString(CultureInfo.CurrentCulture))); 
                SendZoomFactor(value);
            } 
        }


        ///  
        /// 
        ///    [To be supplied.] 
        ///  
        [SRCategory(SR.CatBehavior), SRDescription(SR.RichTextBoxContentsResized)]
        public event ContentsResizedEventHandler ContentsResized { 
            add {
                Events.AddHandler(EVENT_REQUESTRESIZE, value);
            }
            remove { 
                Events.RemoveHandler(EVENT_REQUESTRESIZE, value);
            } 
        } 

 
        /// 
        /// 
        ///     RichTextBox controls have built-in drag and drop support, but AllowDrop, DragEnter, DragDrop
        ///     may still be used: this should be hidden in the property grid, but not in code 
        /// 
        [Browsable(false)] 
        public new event DragEventHandler DragDrop { 
            add {
                base.DragDrop += value; 
            }
            remove {
                base.DragDrop -= value;
            } 
        }
 
        ///  
        /// 
        ///     RichTextBox controls have built-in drag and drop support, but AllowDrop, DragEnter, DragDrop 
        ///     may still be used: this should be hidden in the property grid, but not in code
        /// 
        [Browsable(false)]
        public new event DragEventHandler DragEnter { 
            add {
                base.DragEnter += value; 
            } 
            remove {
                base.DragEnter -= value; 
            }
        }

        ///  
        /// 
        ///    [To be supplied.] 
        ///  
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler DragLeave { 
            add {
                base.DragLeave += value;
            }
            remove { 
                base.DragLeave -= value;
            } 
        } 

        ///  
        /// 
        ///    [To be supplied.]
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 
        public new event DragEventHandler DragOver {
            add { 
                base.DragOver += value; 
            }
            remove { 
                base.DragOver -= value;
            }
        }
 
        /// 
        ///  
        ///    [To be supplied.] 
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 
        public new event GiveFeedbackEventHandler GiveFeedback {
            add {
                base.GiveFeedback += value;
            } 
            remove {
                base.GiveFeedback -= value; 
            } 
        }
 
        /// 
        /// 
        ///    [To be supplied.]
        ///  
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event QueryContinueDragEventHandler QueryContinueDrag { 
            add { 
                base.QueryContinueDrag += value;
            } 
            remove {
                base.QueryContinueDrag -= value;
            }
        } 

        ///  
        ///  
        ///    [To be supplied.]
        ///  
        [SRCategory(SR.CatBehavior), SRDescription(SR.RichTextBoxHScroll)]
        public event EventHandler HScroll {
            add {
                Events.AddHandler(EVENT_HSCROLL, value); 
            }
            remove { 
                Events.RemoveHandler(EVENT_HSCROLL, value); 
            }
        } 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
        [SRCategory(SR.CatBehavior), SRDescription(SR.RichTextBoxLinkClick)] 
        public event LinkClickedEventHandler LinkClicked { 
            add {
                Events.AddHandler(EVENT_LINKACTIVATE, value); 
            }
            remove {
                Events.RemoveHandler(EVENT_LINKACTIVATE, value);
            } 
        }
 
 
        /// 
        ///  
        ///    [To be supplied.]
        /// 
        [SRCategory(SR.CatBehavior), SRDescription(SR.RichTextBoxIMEChange)]
        public event EventHandler ImeChange { 
            add {
                Events.AddHandler(EVENT_IMECHANGE, value); 
            } 
            remove {
                Events.RemoveHandler(EVENT_IMECHANGE, value); 
            }
        }

 
        /// 
        ///  
        ///    [To be supplied.] 
        /// 
        [SRCategory(SR.CatBehavior), SRDescription(SR.RichTextBoxProtected)] 
        public event EventHandler Protected {
            add {
                Events.AddHandler(EVENT_PROTECTED, value);
            } 
            remove {
                Events.RemoveHandler(EVENT_PROTECTED, value); 
            } 
        }
 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
        [SRCategory(SR.CatBehavior), SRDescription(SR.RichTextBoxSelChange)] 
        public event EventHandler SelectionChanged { 
            add {
                Events.AddHandler(EVENT_SELCHANGE, value); 
            }
            remove {
                Events.RemoveHandler(EVENT_SELCHANGE, value);
            } 
        }
 
 
        /// 
        ///  
        ///    [To be supplied.]
        /// 
        [SRCategory(SR.CatBehavior), SRDescription(SR.RichTextBoxVScroll)]
        public event EventHandler VScroll { 
            add {
                Events.AddHandler(EVENT_VSCROLL, value); 
            } 
            remove {
                Events.RemoveHandler(EVENT_VSCROLL, value); 
            }
        }

        ///  
        /// 
        ///     Returns a boolean indicating whether the RichTextBoxConstants control can paste the 
        ///     given clipboard format. 
        /// 
        public bool CanPaste(DataFormats.Format clipFormat) { 
            bool b = false;
            b = (int)SendMessage(RichTextBoxConstants.EM_CANPASTE, clipFormat.Id, 0) != 0;

            return b; 
        }
 
        //DrawToBitmap doesn't work for this control, so we should hide it.  We'll 
        //still call base so that this has a chance to work if it can.
        [EditorBrowsable(EditorBrowsableState.Never)] 
        new public void DrawToBitmap(Bitmap bitmap, Rectangle targetBounds)
        {
            base.DrawToBitmap(bitmap, targetBounds);
        } 

        private unsafe int EditStreamProc(IntPtr dwCookie, IntPtr buf, int cb, out int transferred) { 
            int ret = 0;    // assume that everything is Okay 

            byte[] bytes = new byte[cb]; 

            int cookieVal = (int)dwCookie;

            transferred = 0; 
            try {
                switch (cookieVal & DIRECTIONMASK) { 
                    case RichTextBox.OUTPUT: { 
                        if (editStream == null) {
                            editStream = new MemoryStream(); 
                        }

                        switch (cookieVal & KINDMASK) {
                            case RichTextBox.RTF: 
                            case RichTextBox.TEXTCRLF:
                                Marshal.Copy(buf, bytes, 0, cb); 
                                editStream.Write(bytes, 0, cb); 
                                break;
                            case RichTextBox.TEXTLF: 
                            // Strip out \r characters so that we consistently return
                            // \n for linefeeds. In a future version the RichEdit control
                            // may support a SF_NOXLATCRLF flag which would do this for
                            // us. Internally the RichEdit stores the text with only 
                            // a \n, so we want to keep that the same here.
                            // 
                            if ((cookieVal & UNICODE) != 0) { 
                                Debug.Assert(cb % 2 == 0, "EditStreamProc call out of cycle. Expected to always get character boundary calls");
                                int requestedCharCount = cb/2; 
                                int consumedCharCount = 0;

                                fixed (byte* pb = bytes) {
                                    char* pChars = (char*)pb; 
                                    char* pBuffer = (char*)(long)buf;
 
                                    for (int i=0; i
        ///  
        ///     Searches the text in a RichTextBox control for a given string.
        /// 
        public int Find(string str) {
            return Find(str, 0, 0, RichTextBoxFinds.None); 
        }
 
        ///  
        /// 
        ///     Searches the text in a RichTextBox control for a given string. 
        /// 
        public int Find(string str, RichTextBoxFinds options) {
            return Find(str, 0, 0, options);
        } 

        ///  
        ///  
        ///     Searches the text in a RichTextBox control for a given string.
        ///  
        public int Find(string str, int start, RichTextBoxFinds options) {
            return Find(str, start, -1, options);
        }
 
        /// 
        ///  
        ///     Searches the text in a RichTextBox control for a given string. 
        /// 
        public int Find(string str, int start, int end, RichTextBoxFinds options) { 

            int textLen = TextLength;

            if (str == null) 
                throw new ArgumentNullException("str");
            if (start < 0 || start > textLen) 
                throw new ArgumentOutOfRangeException("start", SR.GetString(SR.InvalidBoundArgument, "start", start, 0, textLen)); 
            if (end < -1)
                throw new ArgumentOutOfRangeException("end", SR.GetString(SR.RichTextFindEndInvalid, end)); 

            bool selectWord = true;
            NativeMethods.FINDTEXT ft = new NativeMethods.FINDTEXT();
            ft.chrg = new NativeMethods.CHARRANGE(); 

            // set up the default values for the FINDTEXT structure, that is 
            // the given string and the whole range of the text stream 
            ft.lpstrText = str;
            if (end == -1) { 
                end = textLen;
            }

            if (start > end) { 
                throw new ArgumentException(SR.GetString(SR.RichTextFindEndInvalid, end));
            } 
 
            if ((options & RichTextBoxFinds.Reverse) != RichTextBoxFinds.Reverse) {
                // normal 
                //
                ft.chrg.cpMin = start;
                ft.chrg.cpMax = end;
            } 
            else {
                // reverse 
                // 
                ft.chrg.cpMin = end;
                ft.chrg.cpMax = start; 
            }

            // force complete search if we ended up with a zero length search
            if (ft.chrg.cpMin == ft.chrg.cpMax) { 
                if ((options & RichTextBoxFinds.Reverse) != RichTextBoxFinds.Reverse) {
                    ft.chrg.cpMin = 0; 
                    ft.chrg.cpMax = -1; 
                }
                else { 
                    ft.chrg.cpMin = textLen;
                    ft.chrg.cpMax = 0;
                }
            } 

            // set up the options for the search 
            int findOptions = 0; 
            if ((options & RichTextBoxFinds.WholeWord) == RichTextBoxFinds.WholeWord)
                findOptions |= RichTextBoxConstants.FR_WHOLEWORD; 
            if ((options & RichTextBoxFinds.MatchCase) == RichTextBoxFinds.MatchCase)
                findOptions |= RichTextBoxConstants.FR_MATCHCASE;
            if ((options & RichTextBoxFinds.NoHighlight) == RichTextBoxFinds.NoHighlight)
                selectWord = false; 
            if ((options & RichTextBoxFinds.Reverse) != RichTextBoxFinds.Reverse) {
                // The default for RichEdit 2.0 is to search in reverse 
                findOptions |= RichTextBoxConstants.FR_DOWN; 
            }
 
            // Perform the find, will return ubyte position
            int position;

            position = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_FINDTEXT, findOptions, ft); 

 
            // if we didn't find anything, or we don't have to select what was found, 
            // we're done
            if (position != -1 && selectWord) { 
                // Select the string found, this is done in ubyte units
                NativeMethods.CHARRANGE chrg = new NativeMethods.CHARRANGE();
                chrg.cpMin = position;
                //Look for kashidas in the string.  A kashida is an arabic visual justification character 
                //that's not semantically meaningful.  Searching for ABC might find AB_C (where A,B, and C
                //represent Arabic characters and _ represents a kashida).  We should highlight the text 
                //including the kashida (VSWhidbey 94809). 
                char kashida = (char)0x640;
                string text = this.Text; 
                string foundString = text.Substring(position, str.Length);
                int startIndex = foundString.IndexOf(kashida);
                if (startIndex == -1)
                { 
                    //No kashida in the string
                    chrg.cpMax = position + str.Length; 
                } 
                else
                { 
                    //There's at least one kashida
                    int searchingCursor; //index into search string
                    int foundCursor; //index into Text
                    for (searchingCursor = startIndex, foundCursor = position + startIndex; searchingCursor < str.Length; 
                        searchingCursor++, foundCursor++)
                    { 
                        while (text[foundCursor] == kashida && str[searchingCursor] != kashida) 
                        {
                            foundCursor++; 
                        }
                    }
                    chrg.cpMax = foundCursor;
                } 

                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_EXSETSEL, 0, chrg); 
                SendMessage(NativeMethods.EM_SCROLLCARET, 0, 0); 

            } 

            return position;
        }
 
        /// 
        ///  
        ///     Searches the text in a RichTextBox control for the given characters. 
        /// 
        public int Find(char[] characterSet) { 
            return Find(characterSet, 0, -1);
        }

        ///  
        /// 
        ///     Searches the text in a RichTextBox control for the given characters. 
        ///  
        public int Find(char[] characterSet, int start) {
            return Find(characterSet, start, -1); 
        }

        /// 
        ///  
        ///     Searches the text in a RichTextBox control for the given characters.
        ///  
        public int Find(char[] characterSet, int start, int end) { 
            // Code used to support ability to search backwards and negate character sets.
            // The API no longer supports this, but in case we change our mind, I'm leaving 
            // the ability in here.
            bool forward = true;
            bool negate = false;
 
            int textLength = TextLength;
 
            if (characterSet == null) 
                throw new ArgumentNullException("characterSet");
            if (start < 0 || start > textLength) 
                throw new ArgumentOutOfRangeException("start", SR.GetString(SR.InvalidBoundArgument, "start", start, 0, textLength));
            if (end < start && end != -1)
                throw new ArgumentOutOfRangeException("end", SR.GetString(SR.InvalidLowBoundArgumentEx, "end", end, "start"));
 
            // Don't do anything if we get nothing to look for
            if (characterSet.Length == 0) 
                return -1; 

            int textLen = SafeNativeMethods.GetWindowTextLength(new HandleRef(this, Handle)); 
            if (start == end) {
                start = 0;
                end = textLen;
            } 
            if (end == -1) {
                end = textLen; 
            } 

            NativeMethods.CHARRANGE chrg = new NativeMethods.CHARRANGE(); // The range of characters we have searched 
            chrg.cpMax = chrg.cpMin = start;

            // Use the TEXTRANGE to move our text buffer forward
            // or backwards within the main text 
            NativeMethods.TEXTRANGE txrg = new NativeMethods.TEXTRANGE(); // Characters we have slurped into memory in order to search
            txrg.chrg = new NativeMethods.CHARRANGE(); 
 
            txrg.chrg.cpMin = chrg.cpMin;
            txrg.chrg.cpMax = chrg.cpMax; 
            UnsafeNativeMethods.CharBuffer charBuffer;
            charBuffer = UnsafeNativeMethods.CharBuffer.CreateBuffer(CHAR_BUFFER_LEN + 1);

            txrg.lpstrText = charBuffer.AllocCoTaskMem(); 
            if (txrg.lpstrText == IntPtr.Zero)
                throw new OutOfMemoryException(); 
 
            try {
                bool done = false; 

                // We want to loop as long as it takes.  This loop will grab a
                // chunk of text out from the control as directed by txrg.chrg;
                while (!done) { 
                    if (forward) {
                        // Move forward by starting at the end of the 
                        // previous text window and extending by the 
                        // size of our buffer
                        txrg.chrg.cpMin = chrg.cpMax; 
                        txrg.chrg.cpMax += CHAR_BUFFER_LEN;
                    }
                    else {
                        // Move backwards by anchoring at the start 
                        // of the previous buffer window, and backing
                        // up by the desired size of our buffer 
                        txrg.chrg.cpMax = chrg.cpMin; 
                        txrg.chrg.cpMin -= CHAR_BUFFER_LEN;
 
                        // We need to keep our request within the
                        // lower bound of zero
                        if (txrg.chrg.cpMin < 0)
                            txrg.chrg.cpMin = 0; 
                    }
 
                    if (end != -1) 
                        txrg.chrg.cpMax = Math.Min(txrg.chrg.cpMax, end);
 
                    // go get the text in this range, if we didn't get any text then punt
                    int len;
                    len = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETTEXTRANGE, 0, txrg);
                    if (len == 0) { 
                        chrg.cpMax = chrg.cpMin = -1; // Hit end of control without finding what we wanted
                        break; 
                    } 

                    // get the data from RichTextBoxConstants into a string for us to use. 
                    charBuffer.PutCoTaskMem(txrg.lpstrText);
                    string str = charBuffer.GetString();

                    // Loop through our text 
                    if (forward) {
                        // Start at the begining of the buffer 
                        for (int x = 0; x < len; x++) { 
                            // Is it in char set?
                            bool found = GetCharInCharSet(str[x], characterSet, negate); 

                            if (found) {
                                done = true;
                                break; 
                            }
 
                            // Advance the buffer 
                            chrg.cpMax++;
                        } 
                    }
                    else { // Span reverse.
                        int x = len;
                        while (x-- != 0) { 
                            // Is it in char set?
                            bool found = GetCharInCharSet(str[x], characterSet, negate); 
 
                            if (found) {
                                done = true; 
                                break;
                            }

                            // Bring the selection back while keeping it anchored 
                            chrg.cpMin--;
                        } 
                    } 
                }
            } 
            finally {
                // release the resources we got for our GETTEXTRANGE operation.
                if (txrg.lpstrText != IntPtr.Zero) Marshal.FreeCoTaskMem(txrg.lpstrText);
            } 

            int index = (forward) ? chrg.cpMax : chrg.cpMin; 
            return index; 
        }
 
        private void ForceHandleCreate() {
            if (!IsHandleCreated)
            {
                CreateHandle(); 
            }
        } 
 
        // Sends set color message to HWND; doesn't call Control.SetForeColor
        private bool InternalSetForeColor(Color value) { 
            NativeMethods.CHARFORMATA cf = GetCharFormat(false);
            if ((cf.dwMask & RichTextBoxConstants.CFM_COLOR) != 0
                && ColorTranslator.ToWin32(value) == cf.crTextColor) {
 
                return true;
            } 
 
            cf.dwMask = RichTextBoxConstants.CFM_COLOR;
            cf.dwEffects = 0; 
            cf.crTextColor = ColorTranslator.ToWin32(value);
            return SetCharFormat(RichTextBoxConstants.SCF_ALL, cf);
        }
 

        private NativeMethods.CHARFORMATA GetCharFormat(bool fSelection) { 
            NativeMethods.CHARFORMATA cf = new NativeMethods.CHARFORMATA(); 
            UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETCHARFORMAT, fSelection ? RichTextBoxConstants.SCF_SELECTION : RichTextBoxConstants.SCF_DEFAULT, cf);
            return cf; 
        }

        private NativeMethods.CHARFORMAT2A GetCharFormat2(bool fSelection) {
            NativeMethods.CHARFORMAT2A cf2 = new NativeMethods.CHARFORMAT2A(); 
            UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETCHARFORMAT, fSelection ? RichTextBoxConstants.SCF_SELECTION : RichTextBoxConstants.SCF_DEFAULT, cf2);
            return cf2; 
        } 

        ///  
        /// 
        /// 
        /// 
        private RichTextBoxSelectionAttribute GetCharFormat(int mask, int effect) { 
            RichTextBoxSelectionAttribute charFormat = RichTextBoxSelectionAttribute.None;
 
            // check to see if the control has been created 
            if (IsHandleCreated) {
                NativeMethods.CHARFORMATA cf = GetCharFormat(true); 
                // if the effects member contains valid info
                if ((cf.dwMask & mask) != 0)
                    // if the text has the desired effect
                    if ((cf.dwEffects & effect) != 0) 
                        charFormat = RichTextBoxSelectionAttribute.All;
            } 
 
            return charFormat;
        } 

        Font GetCharFormatFont(bool selectionOnly) {
            ForceHandleCreate();
 
            NativeMethods.CHARFORMATA cf = GetCharFormat(selectionOnly);
            if ((cf.dwMask & RichTextBoxConstants.CFM_FACE) == 0) { 
                return null; 
            }
 
            string fontName = Encoding.Default.GetString(cf.szFaceName);
            int index = fontName.IndexOf('\0');
            if (index != -1) {
                fontName = fontName.Substring(0, index); 
            }
 
            float fontSize = 13; 
            if ((cf.dwMask & RichTextBoxConstants.CFM_SIZE) != 0) {
                fontSize = (float)cf.yHeight/(float)20.0; 
                if (fontSize == 0 && cf.yHeight > 0) {
                    fontSize = 1;
                }
            } 

            FontStyle style = FontStyle.Regular; 
            if ((cf.dwMask & RichTextBoxConstants.CFM_BOLD) != 0 && (cf.dwEffects & RichTextBoxConstants.CFE_BOLD) != 0) 
                style |= FontStyle.Bold;
            if ((cf.dwMask & RichTextBoxConstants.CFM_ITALIC) != 0 && (cf.dwEffects & RichTextBoxConstants.CFE_ITALIC) != 0) 
                style |= FontStyle.Italic;
            if ((cf.dwMask & RichTextBoxConstants.CFM_STRIKEOUT) != 0 && (cf.dwEffects & RichTextBoxConstants.CFE_STRIKEOUT) != 0)
                style |= FontStyle.Strikeout;
            if ((cf.dwMask & RichTextBoxConstants.CFM_UNDERLINE) != 0 && (cf.dwEffects & RichTextBoxConstants.CFE_UNDERLINE) != 0) 
                style |= FontStyle.Underline;
 
            try { 
                return new Font(fontName, fontSize, style, GraphicsUnit.Point, cf.bCharSet);
            } 
            catch {
            }

            return null; 
        }
 
        ///  
        /// 
        ///     Returns the index of the character nearest to the given point. 
        /// 
        public override int GetCharIndexFromPosition(Point pt) {
            NativeMethods.POINT wpt = new NativeMethods.POINT(pt.X, pt.Y);
            int index = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.EM_CHARFROMPOS, 0, wpt); 

            string t = this.Text; 
            // EM_CHARFROMPOS will return an invalid number if the last character in the RichEdit 
            // is a newline.
            // 
            if (index >= t.Length) {
                index = Math.Max(t.Length - 1, 0);
            }
            return index; 
        }
 
        ///  
        /// 
        ///  
        /// 
        private bool GetCharInCharSet(char c, char[] charSet, bool negate) {
            bool match = false;
            int charSetLen = charSet.Length; 

            // Loop through the given character set and compare for a match 
            for (int i = 0; !match && i < charSetLen; i++) 
                match = c == charSet[i];
 
            return negate ? !match : match;
        }

        ///  
        /// 
        ///     Returns the number of the line containing a specified character position 
        ///     in a RichTextBox control. Note that this returns the physical line number 
        ///     and not the conceptual line number. For example, if the first conceptual
        ///     line (line number 0) word-wraps and extends to the second line, and if 
        ///     you pass the index of a overflowed character, GetLineFromCharIndex would
        ///     return 1 and not 0.
        /// 
        public override int GetLineFromCharIndex(int index) { 
            return (int)SendMessage(RichTextBoxConstants.EM_EXLINEFROMCHAR, 0, index);
        } 
 
        /// 
        ///  
        ///     Returns the location of the character at the given index.
        /// 
        public override Point GetPositionFromCharIndex(int index) {
            if (richEditMajorVersion == 2) { 
                return base.GetPositionFromCharIndex(index);
            } 
 
            if (index < 0 || index > Text.Length) {
                return Point.Empty; 
            }

            NativeMethods.POINT pt = new NativeMethods.POINT();
            UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.EM_POSFROMCHAR, pt, index); 
            return new Point(pt.x, pt.y);
        } 
 
        /// 
        ///  
        /// 
        /// 
        private bool GetProtectedError() {
            if (ProtectedError) { 
                ProtectedError = false;
                return true; 
            } 

            return false; 
        }

        /// 
        ///  
        ///     Loads the contents of the given RTF or text file into a RichTextBox control.
        ///  
        public void LoadFile(string path) { 
            LoadFile(path, RichTextBoxStreamType.RichText);
        } 

        /// 
        /// 
        ///     Loads the contents of a RTF or text into a RichTextBox control. 
        /// 
        public void LoadFile(string path, RichTextBoxStreamType fileType) { 
            //valid values are 0x0 to 0x4 
            if (!ClientUtils.IsEnumValid(fileType, (int)fileType, (int)RichTextBoxStreamType.RichText, (int)RichTextBoxStreamType.UnicodePlainText)){
                throw new InvalidEnumArgumentException("fileType", (int)fileType, typeof(RichTextBoxStreamType)); 
            }

            Stream file = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
            try { 
                LoadFile(file, fileType);
            } 
            finally { 
                file.Close();
            } 
        }

        /// 
        ///  
        ///     Loads the contents of a RTF or text into a RichTextBox control.
        ///  
        public void LoadFile(Stream data, RichTextBoxStreamType fileType) { 
            //valid values are 0x0 to 0x4
            if (!ClientUtils.IsEnumValid(fileType, (int)fileType, (int)RichTextBoxStreamType.RichText, (int)RichTextBoxStreamType.UnicodePlainText)) 
            {
                throw new InvalidEnumArgumentException("fileType", (int)fileType, typeof(RichTextBoxStreamType));
            }
 
            int flags;
            switch (fileType) { 
                case RichTextBoxStreamType.RichText: 
                    flags = RichTextBoxConstants.SF_RTF;
                    break; 
                case RichTextBoxStreamType.PlainText:
                    this.Rtf = "";
                    flags = RichTextBoxConstants.SF_TEXT;
                    break; 
                case RichTextBoxStreamType.UnicodePlainText:
                    flags = RichTextBoxConstants.SF_UNICODE | RichTextBoxConstants.SF_TEXT; 
                    break; 
                default:
                    throw new ArgumentException(SR.GetString(SR.InvalidFileType)); 
            }

            StreamIn(data, flags);
        } 

 
        ///  
        /// 
        ///    [To be supplied.] 
        /// 
        protected override void OnBackColorChanged(EventArgs e) {
            if (IsHandleCreated)
            { 
                SendMessage(RichTextBoxConstants.EM_SETBKGNDCOLOR, 0, ColorTranslator.ToWin32(BackColor));
            } 
            base.OnBackColorChanged(e); 
        }
 
        /// 
        protected override void OnContextMenuChanged(EventArgs e)
        {
            base.OnContextMenuChanged(e); 
            UpdateOleCallback();
        } 
 
        /// 
        ///  
        ///    [To be supplied.]
        /// 
        protected override void OnRightToLeftChanged(EventArgs e) {
            base.OnRightToLeftChanged(e); 
            //VSWhidbey# 325345.
            // When the RTL property is changed, here's what happens. Let's assume that we change from 
            // RTL.No to RTL.Yes. 

            // 1.   RecreateHandle is called. 
            // 2.   In RTB.OnHandleDestroyed, we cache off any RTF that might have been set.
            //      The RTB has been set to the empty string, so we do get RTF back. The RTF
            //      contains formatting info, but doesn't contain any reading-order info,
            //      so RichEdit defaults to LTR reading order. 
            // 3.   In RTB.OnHandleCreated, we check if we have any cached RTF, and if so,
            //      we want to set the RTF to that value. This is to ensure that the original 
            //      text doesn't get lost. 
            // 4.   In the RTF setter, we get the current RTF, compare it to the old RTF, and
            //      since those are not equal, we set the RichEdit content to the old RTF. 
            // 5.   But... since the original RTF had no reading-order info, the reading-order
            //      will default to LTR - thus VSWhidbey #325345.

            // That's why in Everett we set the text back since that clears the RTF, thus restoring 
            // the reading order to that of the window style. The problem here is that when there's
            // no initial text (the empty string), then WindowText would not actually set the text, 
            // and we were left with the LTR reading order. There's no longer any initial text (as in Everett, 
            // e.g richTextBox1), since we changed the designers to not set text. Sigh...
 
            // So the fix is to force windowtext, whether or not that window text is equal to what's already there.
            // Note that in doing so we will lose any formatting info you might have set on the RTF. We are okay with that.

            // We use WindowText rather than Text because this way we can avoid 
            // spurious TextChanged events.
            // 
            string oldText = WindowText; 
            ForceWindowText(null);
            ForceWindowText(oldText); 
        }

        /// 
        ///  
        ///     Fires an event when the user changes the control's contents
        ///     are either smaller or larger than the control's window size. 
        ///  
        protected virtual void OnContentsResized(ContentsResizedEventArgs e) {
            ContentsResizedEventHandler handler = (ContentsResizedEventHandler)Events[EVENT_REQUESTRESIZE]; 
            if (handler != null) handler(this,e);
        }

        ///  
        /// 
        ///    [To be supplied.] 
        ///  
        protected override void OnHandleCreated(EventArgs e) {
            // base.OnHandleCreated is called somewhere in the middle of this 

            curSelStart = curSelEnd = curSelType = -1;

            // We will always set the control to use the maximum text, it defaults to 32k.. 
            // This must be done before we start loading files, because some files may
            // be larger than 32k. 
            // 
            UpdateMaxLength();
 
            // This is needed so that the control will fire change and update events
            // even if it is hidden
            //
            SendMessage(RichTextBoxConstants.EM_SETEVENTMASK, 
                        0,
                        RichTextBoxConstants.ENM_PROTECTED | RichTextBoxConstants.ENM_SELCHANGE | 
                        RichTextBoxConstants.ENM_DROPFILES | RichTextBoxConstants.ENM_REQUESTRESIZE | 
                        RichTextBoxConstants.ENM_IMECHANGE | RichTextBoxConstants.ENM_CHANGE |
                        RichTextBoxConstants.ENM_UPDATE    | RichTextBoxConstants.ENM_SCROLL | 
                        RichTextBoxConstants.ENM_KEYEVENTS | RichTextBoxConstants.ENM_MOUSEEVENTS |
                        RichTextBoxConstants.ENM_SCROLLEVENTS | RichTextBoxConstants.ENM_LINK);

            int rm = rightMargin; 
            rightMargin = 0;
            RightMargin = rm; 
 
            //
 

            this.SendMessage(RichTextBoxConstants.EM_AUTOURLDETECT, DetectUrls ? 1 : 0, 0);
            if (selectionBackColorToSetOnHandleCreated != Color.Empty) {
                this.SelectionBackColor = selectionBackColorToSetOnHandleCreated; 
            }
 
            // Initialize colors before initializing RTF, otherwise CFE_AUTOCOLOR will be in effect 
            // and our text will all be Color.WindowText.
            AutoWordSelection = AutoWordSelection; 
            SendMessage(RichTextBoxConstants.EM_SETBKGNDCOLOR, 0, ColorTranslator.ToWin32(BackColor));
            InternalSetForeColor(ForeColor);

            // base sets the Text property.  It's important to do this *after* setting EM_AUTOUrlDETECT. 
            base.OnHandleCreated(e);
 
            // vsWhidbey 371584: for some reason, we need to set the OleCallback before setting the RTF property. 
            UpdateOleCallback();
 
            // RTF property takes precedence over Text property
            //
            try {
                SuppressTextChangedEvent = true; 
                if (textRtf != null) {
                    // setting RTF calls back on Text, which relies on textRTF being null 
                    string text = textRtf; 
                    textRtf = null;
                    Rtf = text; 
                }
                else if (textPlain != null) {
                    string text = textPlain;
                    textPlain = null; 
                    Text = text;
                } 
            } 
            finally {
                SuppressTextChangedEvent = false; 
            }

            // Since we can't send EM_SETSEL until RTF has been set,
            // we can't rely on base to do it for us. 
            base.SetSelectionOnHandle();
 
            if (ShowSelectionMargin) { 
                // If you call SendMessage instead of PostMessage, the control
                // will resize itself to the size of the parent's client area.  Don't know why... 
                UnsafeNativeMethods.PostMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETOPTIONS, (IntPtr)RichTextBoxConstants.ECOOP_OR,
                                                (IntPtr)RichTextBoxConstants.ECO_SELECTIONBAR);
            }
 
            if (languageOption != this.LanguageOption) {
                this.LanguageOption = languageOption; 
            } 

            ClearUndo(); 

            SendZoomFactor(zoomMultiplier);

            SystemEvents.UserPreferenceChanged += new UserPreferenceChangedEventHandler(UserPreferenceChangedHandler); 
        }
 
        ///  
        /// 
        ///    [To be supplied.] 
        /// 
        protected override void OnHandleDestroyed(EventArgs e) {
            base.OnHandleDestroyed(e);
 
            if (!InConstructor) {
                textRtf = Rtf; 
                if (textRtf.Length == 0) 
                    textRtf = null;
            } 

            oleCallback = null;
            SystemEvents.UserPreferenceChanged -= new UserPreferenceChangedEventHandler(UserPreferenceChangedHandler);
        } 

        ///  
        ///  
        ///     Fires an event when the user clicks a RichTextBox control's horizontal
        ///     scroll bar. 
        /// 
        protected virtual void OnHScroll(EventArgs e) {
            EventHandler handler = (EventHandler)Events[EVENT_HSCROLL];
            if (handler != null) handler(this,e); 
        }
 
        ///  
        /// 
        ///     Fires an event when the user clicks on a link 
        ///     in a rich-edit control.
        /// 
        protected virtual void OnLinkClicked(LinkClickedEventArgs e) {
            LinkClickedEventHandler handler = (LinkClickedEventHandler)Events[EVENT_LINKACTIVATE]; 
            if (handler != null) handler(this,e);
        } 
 

        ///  
        /// 
        ///     Fires an event when the user changes the control's IME conversion status.
        /// 
        protected virtual void OnImeChange(EventArgs e) { 
            EventHandler handler = (EventHandler)Events[EVENT_IMECHANGE];
            if (handler != null) handler(this,e); 
        } 

        ///  
        /// 
        ///     Fires an event when the user is taking an action that would change
        ///     a protected range of text in the RichTextBox control.
        ///  
        protected virtual void OnProtected(EventArgs e) {
            ProtectedError = true; 
            EventHandler handler = (EventHandler)Events[EVENT_PROTECTED]; 
            if (handler != null) handler(this,e);
        } 

        /// 
        /// 
        ///     Fires an event when the current selection of text in the RichTextBox 
        ///     control has changed or the insertion point has moved.
        ///  
        protected virtual void OnSelectionChanged(EventArgs e) { 
            EventHandler handler = (EventHandler)Events[EVENT_SELCHANGE];
            if (handler != null) handler(this,e); 
        }

        /// 
        ///  
        ///     Fires an event when the user clicks a RichTextBox control's vertical
        ///     scroll bar. 
        ///  
        protected virtual void OnVScroll(EventArgs e) {
            EventHandler handler = (EventHandler)Events[EVENT_VSCROLL]; 
            if (handler != null) handler(this,e);
        }

        ///  
        /// 
        ///     Pastes the contents of the clipboard in the given clipboard format. 
        ///  
        public void Paste(DataFormats.Format clipFormat) {
            Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "ClipboardRead Demanded"); 
            IntSecurity.ClipboardRead.Demand();

            PasteUnsafe(clipFormat, 0);
        } 

        ///  
        ///  
        /// Note that this doesn't make a security demand: functions that call this should.
        ///  
        private void PasteUnsafe(DataFormats.Format clipFormat, int hIcon) {
            NativeMethods.REPASTESPECIAL rps = null;

            if (hIcon != 0) { 
                rps = new NativeMethods.REPASTESPECIAL();
                rps.dwAspect = DVASPECT_ICON; 
                rps.dwParam = hIcon; 
            }
            UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_PASTESPECIAL, clipFormat.Id, rps); 
        }

        /// 
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] 
        protected override bool ProcessCmdKey(ref Message m, Keys keyData) {
            if (this.RichTextShortcutsEnabled == false) { 
                foreach (int shortcutValue in shortcutsToDisable) { 
                    if ((int)keyData == shortcutValue) {
                        return true; 
                    }
                }
            }
            return base.ProcessCmdKey(ref m, keyData); 
        }
 
        ///  
        /// 
        ///     Redoes the last undone editing operation. 
        /// 
        public void Redo() {
            SendMessage(RichTextBoxConstants.EM_REDO, 0, 0);
        } 

        //NOTE: Undo is implemented on TextBox 
 
        /// 
        ///  
        ///     Saves the contents of a RichTextBox control to a file.
        /// 
        public void SaveFile(string path) {
            SaveFile(path, RichTextBoxStreamType.RichText); 
        }
 
        ///  
        /// 
        ///     Saves the contents of a RichTextBox control to a file. 
        /// 
        public void SaveFile(string path, RichTextBoxStreamType fileType) {
            //valid values are 0x0 to 0x4
            if (!ClientUtils.IsEnumValid(fileType, (int)fileType, (int)RichTextBoxStreamType.RichText, (int)RichTextBoxStreamType.UnicodePlainText)) 
            {
                throw new InvalidEnumArgumentException("fileType", (int)fileType, typeof(RichTextBoxStreamType)); 
            } 

            Stream file = File.Create(path); 
            try {
                SaveFile(file, fileType);
            }
            finally { 
                file.Close();
            } 
        } 

        ///  
        /// 
        ///     Saves the contents of a RichTextBox control to a file.
        /// 
        public void SaveFile(Stream data, RichTextBoxStreamType fileType) { 
            int flags;
            switch (fileType) { 
                case RichTextBoxStreamType.RichText: 
                    flags = RichTextBoxConstants.SF_RTF;
                    break; 
                case RichTextBoxStreamType.PlainText:
                    flags = RichTextBoxConstants.SF_TEXT;
                    break;
                case RichTextBoxStreamType.UnicodePlainText: 
                    flags = RichTextBoxConstants.SF_UNICODE | RichTextBoxConstants.SF_TEXT;
                    break; 
                case RichTextBoxStreamType.RichNoOleObjs: 
                    flags = RichTextBoxConstants.SF_RTFNOOBJS;
                    break; 
                case RichTextBoxStreamType.TextTextOleObjs:
                    flags = RichTextBoxConstants.SF_TEXTIZED;
                    break;
                default: 
                    throw new InvalidEnumArgumentException("fileType", (int)fileType, typeof(RichTextBoxStreamType));
            } 
 
            StreamOut(data, flags, true);
        } 

        /// 
        /// 
        ///     Core Zoom calculation and message passing (used by ZoomFactor property and CreateHandle() 
        /// 
        ///  
        private void SendZoomFactor(float zoom) { 
            int numerator;
            int denominator; 

            if (zoom == 1.0f) {
                denominator = 0;
                numerator = 0; 
            }
            else { 
                denominator = 1000; 
                float multiplier = 1000 * zoom;
                numerator = (int)Math.Ceiling(multiplier); 
                if (numerator >= 64000) {
                    numerator = (int)Math.Floor(multiplier);
                }
            } 

            if (IsHandleCreated) { 
                SendMessage(RichTextBoxConstants.EM_SETZOOM, numerator, denominator); 

#if DEBUG 

                // DEBUG CODE: Verify that EM_SETZOOM actually set the zoom
                int n = 0, d = 0;
                SendMessage(RichTextBoxConstants.EM_GETZOOM, ref n, ref d); 
                Debug.Assert(n == numerator && d == denominator, "EM_SETZOOM failed");
                // END DEBUG CODE 
#endif 
            }
 
            if (numerator != 0) {
                zoomMultiplier = ((float)numerator)/((float)denominator);
            }
            else { 
                zoomMultiplier = 1.0f;
            } 
        } 

        ///  
        /// 
        /// 
        /// 
        private bool SetCharFormat(int mask, int effect, RichTextBoxSelectionAttribute charFormat) { 
            // check to see if the control has been created
            if (IsHandleCreated) { 
                NativeMethods.CHARFORMATA cf = new NativeMethods.CHARFORMATA(); 

                cf.dwMask = mask; 

                switch (charFormat) {
                    case RichTextBoxSelectionAttribute.All:
                        cf.dwEffects = effect; 
                        break;
                    case RichTextBoxSelectionAttribute.None: 
                        cf.dwEffects = 0; 
                        break;
                    default: 
                        throw new ArgumentException(SR.GetString(SR.UnknownAttr));
                }

                // set the format information 
                return IntPtr.Zero != UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETCHARFORMAT, RichTextBoxConstants.SCF_SELECTION, cf);
            } 
            return false; 
        }
 
        private bool SetCharFormat(int charRange, NativeMethods.CHARFORMATA cf) {
            return IntPtr.Zero != UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETCHARFORMAT, charRange, cf);
        }
 
        private void SetCharFormatFont(bool selectionOnly, Font value) {
            ForceHandleCreate(); 
            NativeMethods.LOGFONT logfont = new NativeMethods.LOGFONT(); 

            FontToLogFont(value, logfont); 

            byte[] bytesFaceName;

            int dwMask = RichTextBoxConstants.CFM_FACE | RichTextBoxConstants.CFM_SIZE | RichTextBoxConstants.CFM_BOLD | 
                RichTextBoxConstants.CFM_ITALIC | RichTextBoxConstants.CFM_STRIKEOUT | RichTextBoxConstants.CFM_UNDERLINE |
                RichTextBoxConstants.CFM_CHARSET; 
 
            int dwEffects = 0;
            if (value.Bold) dwEffects |= RichTextBoxConstants.CFE_BOLD; 
            if (value.Italic) dwEffects |= RichTextBoxConstants.CFE_ITALIC;
            if (value.Strikeout) dwEffects |= RichTextBoxConstants.CFE_STRIKEOUT;
            if (value.Underline) dwEffects |= RichTextBoxConstants.CFE_UNDERLINE;
 
            if (Marshal.SystemDefaultCharSize == 1)
            { 
                bytesFaceName = Encoding.Default.GetBytes(logfont.lfFaceName); 

                NativeMethods.CHARFORMATA cfA = new NativeMethods.CHARFORMATA(); 
                for (int i=0; i 
        /// 
        /// This is just here as a minor perf improvement, so we don't have to call expensive RevertAssert.
        /// When the method exits, we effectively revert the assert.
        ///  
        [SecurityPermission(SecurityAction.Assert, Flags=SecurityPermissionFlag.UnmanagedCode)]
        [SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts")] 
        static private void FontToLogFont(Font value, NativeMethods.LOGFONT logfont) { 
            value.ToLogFont(logfont);
        } 


        /// 
        ///  
        /// 
        private static void SetupLogPixels(IntPtr hDC) { 
            bool release = false; 
            if (hDC == IntPtr.Zero) {
                hDC = UnsafeNativeMethods.GetDC(NativeMethods.NullHandleRef); 
                release = true;
            }
            if (hDC == IntPtr.Zero) return;
            logPixelsX = UnsafeNativeMethods.GetDeviceCaps(new HandleRef(null, hDC), NativeMethods.LOGPIXELSX); 
            logPixelsY = UnsafeNativeMethods.GetDeviceCaps(new HandleRef(null, hDC), NativeMethods.LOGPIXELSY);
            if (release) 
                UnsafeNativeMethods.ReleaseDC(NativeMethods.NullHandleRef, new HandleRef(null, hDC)); 
        }
 
        private static int Pixel2Twip(IntPtr hDC, int v, bool xDirection) {
            SetupLogPixels(hDC);
            int logP = xDirection ? logPixelsX : logPixelsY;
            return(int) ((((double)v) / logP) * 72.0 * 20.0); 
        }
 
        private static int Twip2Pixel(IntPtr hDC, int v, bool xDirection) { 
            SetupLogPixels(hDC);
            int logP = xDirection ? logPixelsX : logPixelsY; 
            return(int) (((((double) v) / 20.0) / 72.0) * logP);
        }

        ///  
        /// 
        ///  
        ///  
        private void StreamIn(string str, int flags) {
            if (str.Length == 0 ) { 
                // Destroy the selection if callers was setting
                // selection text
                //
                if ((RichTextBoxConstants.SFF_SELECTION & flags) != 0) { 
                    SendMessage(NativeMethods.WM_CLEAR, 0, 0);
                    ProtectedError = false; 
                    return; 
                }
                // WM_SETTEXT is allowed even if we have protected text 
                //
                SendMessage(NativeMethods.WM_SETTEXT, 0, "");
                return;
            } 

            // Rather than work only some of the time with null characters, 
            // we're going to be consistent and never work with them. 
            int nullTerminatedLength = str.IndexOf((char) 0);
            if (nullTerminatedLength != -1) { 
                str = str.Substring(0, nullTerminatedLength);
            }

            // get the string into a byte array 
            byte[] encodedBytes;
            if ((flags & RichTextBoxConstants.SF_UNICODE) != 0) { 
                encodedBytes = Encoding.Unicode.GetBytes(str); 
            }
            else { 
                encodedBytes = Encoding.Default.GetBytes(str);
            }
            editStream = new MemoryStream(encodedBytes.Length);
            editStream.Write(encodedBytes, 0, encodedBytes.Length); 
            editStream.Position = 0;
            StreamIn(editStream, flags); 
        } 

        private void StreamIn(Stream data, int flags) { 
            // clear out the selection only if we are replacing all the text
            //
            if ((flags & RichTextBoxConstants.SFF_SELECTION) == 0) {
                NativeMethods.CHARRANGE cr = new NativeMethods.CHARRANGE(); 
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_EXSETSEL, 0, cr);
            } 
 
            try {
                editStream = data; 
                Debug.Assert(data != null, "StreamIn passed a null stream");

                // If SF_RTF is requested then check for the RTF tag at the start
                // of the file.  We don't load if the tag is not there 
                //
                if ((flags & RichTextBoxConstants.SF_RTF) != 0) { 
                    long streamStart = editStream.Position; 
                    byte[] bytes = new byte[SZ_RTF_TAG.Length];
                    editStream.Read(bytes, (int)streamStart, SZ_RTF_TAG.Length); 
                    string str = Encoding.Default.GetString(bytes);
                    if (!SZ_RTF_TAG.Equals(str))
                        throw new ArgumentException(SR.GetString(SR.InvalidFileFormat));
 
                    // put us back at the start of the file
                    editStream.Position = streamStart; 
                } 

                int cookieVal = 0; 
                // set up structure to do stream operation
                NativeMethods.EDITSTREAM es = new NativeMethods.EDITSTREAM();
                if ((flags & RichTextBoxConstants.SF_UNICODE) != 0) {
                    cookieVal = INPUT | UNICODE; 
                }
                else { 
                    cookieVal = INPUT | ANSI; 
                }
                if ((flags & RichTextBoxConstants.SF_RTF) != 0) { 
                    cookieVal |= RTF;
                }
                else {
                    cookieVal |= TEXTLF; 
                }
                es.dwCookie = (IntPtr) cookieVal; 
                es.pfnCallback = new NativeMethods.EditStreamCallback(this.EditStreamProc); 

                // gives us TextBox compatible behavior, programatic text change shouldn't 
                // be limited...
                //
                SendMessage(RichTextBoxConstants.EM_EXLIMITTEXT, 0, Int32.MaxValue);
 

 
                // go get the text for the control 
                //Weird hack needed for 64-bit
                if (IntPtr.Size == 8) { 
                    NativeMethods.EDITSTREAM64 es64 = ConvertToEDITSTREAM64(es);
                    UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_STREAMIN, flags, es64);

                    //Assign back dwError value 
                    es.dwError = GetErrorValue64(es64);
                } 
                else { 
                    UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_STREAMIN, flags, es);
                } 

                UpdateMaxLength();

                // If we failed to load because of protected 
                // text then return protect event was fired so no
                // exception is required for the the error 
                if (GetProtectedError()) 
                    return;
 
                if (es.dwError != 0)
                    throw new InvalidOperationException(SR.GetString(SR.LoadTextError));

                // set the modify tag on the control 
                SendMessage(NativeMethods.EM_SETMODIFY, -1, 0);
 
                // EM_GETLINECOUNT will cause the RichTextBoxConstants to recalculate its line indexes 
                SendMessage(NativeMethods.EM_GETLINECOUNT, 0, 0);
 

            }
            finally {
                // release any storage space held. 
                editStream = null;
            } 
        } 

        ///  
        /// 
        /// 
        /// 
        private string StreamOut(int flags) { 
            Stream stream = new MemoryStream();
            StreamOut(stream, flags, false); 
            stream.Position = 0; 
            int streamLength = (int)stream.Length;
            string result = string.Empty; 

            if (streamLength > 0) {
                byte[] bytes = new byte[streamLength];
                stream.Read(bytes, 0, streamLength); 

                if ((flags & RichTextBoxConstants.SF_UNICODE) != 0) { 
                    result = Encoding.Unicode.GetString(bytes,0 , bytes.Length); 
                }
                else { 
                    result = Encoding.Default.GetString(bytes, 0, bytes.Length);
                }
                // workaround ??? for bug 117325. When the string is modified is can return
                // with an extra null termination (always?). If it does, get rid of it. 
                if(!String.IsNullOrEmpty(result) && (result[result.Length-1] == '\0')) {
                    result = result.Substring(0, result.Length-1); 
                } 
            }
 
            return result;
        }

        private void StreamOut(Stream data, int flags, bool includeCrLfs) { 
            // set up the EDITSTREAM structure for the callback.
            Debug.Assert(data != null, "StreamOut passed a null stream"); 
            editStream = data; 

            try { 
                int cookieVal = 0;
                NativeMethods.EDITSTREAM es = new NativeMethods.EDITSTREAM();
                if ((flags & RichTextBoxConstants.SF_UNICODE) != 0) {
                    cookieVal = OUTPUT | UNICODE; 
                }
                else { 
                    cookieVal = OUTPUT | ANSI; 
                }
                if ((flags & RichTextBoxConstants.SF_RTF) != 0) { 
                    cookieVal |= RTF;
                }
                else {
                    if (includeCrLfs) { 
                        cookieVal |= TEXTCRLF;
                    } 
                    else { 
                        cookieVal |= TEXTLF;
                    } 
                }
                es.dwCookie = (IntPtr) cookieVal;
                es.pfnCallback = new NativeMethods.EditStreamCallback(this.EditStreamProc);
 
                //Get Text
                //Weird hack needed for 64-bit 
                if (IntPtr.Size == 8) { 
                    NativeMethods.EDITSTREAM64 es64 = ConvertToEDITSTREAM64(es);
                    UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_STREAMOUT, flags, es64); 

                    //Assign back dwError value
                    es.dwError = GetErrorValue64(es64);
                } 
                else {
                    UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_STREAMOUT, flags, es); 
                } 

                // check to make sure things went well 
                if (es.dwError != 0)
                    throw new InvalidOperationException(SR.GetString(SR.SaveTextError));
            }
            finally { 
                // release any storage space held.
                editStream = null; 
            } 
        }
 
        private unsafe NativeMethods.EDITSTREAM64 ConvertToEDITSTREAM64(NativeMethods.EDITSTREAM es) {
            NativeMethods.EDITSTREAM64 es64 = new NativeMethods.EDITSTREAM64();

            fixed (byte* es64p =  &es64.contents[0]) { 
                byte *bp;
                long l; 
 
                /*
                l = (long) es.dwCookie; 
                bp = (byte *) &l;
                for (int i=0; i < sizeof(long); i++) {
                    es64.contents[i] = bp[i];
                }*/ 
                *((long *)es64p) = (long) es.dwCookie;
                /* 
                int il = es.dwError; 
                bp = (byte *) &il;
                for (int i=0; i < sizeof(int); i++) { 
                    es64.contents[i+8] = bp[i];
                }*/
                *((int *)(es64p + 8)) = es.dwError;
 
                l = (long) Marshal.GetFunctionPointerForDelegate(es.pfnCallback);
                bp = (byte *) &l; 
                for (int i=0; i < sizeof(long); i++) { 
                    es64.contents[i+12] = bp[i];
                } 
                //*((long *)(es64p + 12)) = (long) Marshal.GetFunctionPointerForDelegate(es.pfnCallback);
            }

            return es64; 
        }
 
        private unsafe int GetErrorValue64(NativeMethods.EDITSTREAM64 es64) { 
            int errorVal;
 
            fixed (byte* es64p =  &es64.contents[0]) {
                errorVal = *((int *)(es64p + 8));
            }
 
            return errorVal;
        } 
 
/* FOR 64 BIT DEBUGGING
        private unsafe string PrintBytes(NativeMethods.EDITSTREAM es) { 
            StringBuilder sb = new StringBuilder();
            fixed (IntPtr *ip = &es.dwCookie) {
                byte *bytep = (byte *) ip;
                for (int i=0; i < Marshal.SizeOf(es); i++) { 
                    sb.Append(bytep[i].ToString() + " ");
                } 
            } 
            return sb.ToString();
        } 

        private unsafe string PrintBytes(NativeMethods.EDITSTREAM64 es64) {
            StringBuilder sb = new StringBuilder();
            fixed (byte *bytep = &es64.contents[0]) { 
                for (int i=0; i < Marshal.SizeOf(es64); i++) {
                    sb.Append(bytep[i].ToString() + " "); 
                } 
            }
            return sb.ToString(); 
        }
*/

 
        private void UpdateOleCallback() {
            Debug.WriteLineIf(RichTextDbg.TraceVerbose, "update ole callback (" + AllowDrop + ")"); 
            if (IsHandleCreated) { 
                if (oleCallback == null) {
                    Debug.WriteLineIf(RichTextDbg.TraceVerbose, "binding ole callback"); 
                    bool unrestricted = false;
                    try {
                        IntSecurity.UnmanagedCode.Demand();
                        unrestricted = true; 
                    }
                    catch (SecurityException) { 
                        unrestricted = false; 
                    }
                    if (unrestricted) { 
                        this.AllowOleObjects = true;
                    }
                    else {
                        this.AllowOleObjects = (0 != (int) SendMessage(RichTextBoxConstants.EM_SETQUERYRTFOBJ, 0, 1)); 
                    }
 
                    oleCallback = CreateRichEditOleCallback(); 

                    // Forcibly QI (through IUnknown::QueryInterface) to handle multiple 
                    // definitions of the interface.
                    //
                    IntPtr punk = Marshal.GetIUnknownForObject(oleCallback);
                    try { 
                        IntPtr pRichEditOleCallback;
                        Guid iidRichEditOleCallback = typeof(UnsafeNativeMethods.IRichEditOleCallback).GUID; 
                        Marshal.QueryInterface(punk, ref iidRichEditOleCallback, out pRichEditOleCallback); 
                        try {
                            UnsafeNativeMethods.SendCallbackMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETOLECALLBACK, IntPtr.Zero, pRichEditOleCallback); 
                        }
                        finally {
                            Marshal.Release(pRichEditOleCallback);
                        } 
                    } finally {
                        Marshal.Release(punk); 
                    } 
                }
                UnsafeNativeMethods.DragAcceptFiles(new HandleRef(this, Handle), false); 
            }
        }

        //Note: RichTextBox doesn't work like other controls as far as setting ForeColor/ 
        //BackColor -- you need to send messages to update the colors
        private void UserPreferenceChangedHandler(object o, UserPreferenceChangedEventArgs e) 
        { 
            if (IsHandleCreated)
            { 
                if (this.BackColor.IsSystemColor)
                {
                    SendMessage(RichTextBoxConstants.EM_SETBKGNDCOLOR, 0, ColorTranslator.ToWin32(BackColor));
                } 
                if (this.ForeColor.IsSystemColor)
                { 
                    InternalSetForeColor(ForeColor); 
                }
            } 
        }

        /// 
        ///  
        ///   Creates the IRichEditOleCallback compatible object for handling RichEdit callbacks. For more
        ///   information look up the MSDN info on this interface. This is designed to be a back door of 
        ///   sorts, which is why it is fairly obscure, and uses the RichEdit name instead of RichTextBox. 
        /// 
        [SecurityPermission(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] 
        protected virtual object CreateRichEditOleCallback() {
            return new OleCallback(this);
        }
 
        /// 
        ///  
        ///      Handles link messages (mouse move, down, up, dblclk, etc) 
        /// 
        ///  
        private void EnLinkMsgHandler(ref Message m) {
            NativeMethods.ENLINK enlink;
            //On 64-bit, we do some custom marshalling to get this to work. The richedit control
            //unfortunately does not respect IA64 struct alignment conventions. See VSWhidbey #122276 & 504502. 
            if (IntPtr.Size == 8) {
                enlink = ConvertFromENLINK64((NativeMethods.ENLINK64)m.GetLParam(typeof(NativeMethods.ENLINK64))); 
            } 
            else {
                enlink = (NativeMethods.ENLINK)m.GetLParam(typeof(NativeMethods.ENLINK)); 
            }

            switch (enlink.msg) {
                case NativeMethods.WM_SETCURSOR: 
                    LinkCursor = true;
                    m.Result = (IntPtr)1; 
                    return; 
                // Mouse-down triggers Url; this matches Outlook 2000's behavior.
                case NativeMethods.WM_LBUTTONDOWN: 
                    string linktext = CharRangeToString(enlink.charrange);
                    if (!string.IsNullOrEmpty(linktext))
                    {
                        OnLinkClicked(new LinkClickedEventArgs(linktext)); 
                    }
                    m.Result = (IntPtr)1; 
                    return; 
            }
            m.Result = IntPtr.Zero; 
            return;
        }

        ///  
        /// 
        ///     Converts a CHARRANGE to a string. Note: The behavior of this is dependent on the current window 
        ///     class name being used. We have to create a CharBuffer of the type of RichTextBox DLL we're using, 
        ///     not based on the SystemCharWidth.
        ///  
        /// 
        private string CharRangeToString(NativeMethods.CHARRANGE c) {
            NativeMethods.TEXTRANGE txrg = new NativeMethods.TEXTRANGE();
            txrg.chrg = c; 
            Debug.Assert((c.cpMax-c.cpMin)>0, "CHARRANGE was null or negative - can't do it!");
 
            //Windows bug: 64-bit windows returns a bad range for us.  VSWhidbey 504502. 
            //Putting in a hack to avoid an unhandled exception.
            if (c.cpMax > Text.Length || c.cpMax-c.cpMin <= 0) { 
                return string.Empty;
            }

            int characters = (c.cpMax-c.cpMin) + 1; // +1 for null termination 
            UnsafeNativeMethods.CharBuffer charBuffer = UnsafeNativeMethods.CharBuffer.CreateBuffer(characters);
            IntPtr unmanagedBuffer = charBuffer.AllocCoTaskMem(); 
            if (unmanagedBuffer == IntPtr.Zero) 
                throw new OutOfMemoryException(SR.GetString(SR.OutOfMemory));
 
            txrg.lpstrText = unmanagedBuffer;
            int len = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETTEXTRANGE, 0, txrg);
            Debug.Assert(len != 0, "CHARRANGE from RichTextBox was bad! - impossible?");
            charBuffer.PutCoTaskMem(unmanagedBuffer); 
            if (txrg.lpstrText != IntPtr.Zero)
                Marshal.FreeCoTaskMem(unmanagedBuffer); 
 
            string result = charBuffer.GetString();
            return result; 
        }

        internal override void UpdateMaxLength() {
            if (IsHandleCreated) { 
                SendMessage(RichTextBoxConstants.EM_EXLIMITTEXT, 0, MaxLength);
            } 
        } 

        ///  
        /// 
        /// 
        /// 
        private void WmReflectCommand(ref Message m) { 

            // We check if we're in the middle of handle creation because 
            // the rich edit control fires spurious events during this time. 
            //
            if (m.LParam == Handle && !GetState(STATE_CREATINGHANDLE)) 
            {
                switch (Util.HIWORD(m.WParam)) {

                    case NativeMethods.EN_HSCROLL: 
                        OnHScroll(EventArgs.Empty);
                        break; 
 
                    case NativeMethods.EN_VSCROLL:
                        OnVScroll(EventArgs.Empty); 
                        break;

                    default:
                        base.WndProc(ref m); 
                        break;
                } 
            } 
            else {
                base.WndProc(ref m); 
            }
        }

        ///  
        /// 
        ///  
        ///  
        internal void WmReflectNotify(ref Message m) {
            if (m.HWnd == Handle) { 
                NativeMethods.NMHDR nmhdr = (NativeMethods.NMHDR)m.GetLParam(typeof(NativeMethods.NMHDR));
                switch (nmhdr.code) {
                    case RichTextBoxConstants.EN_LINK:
                        EnLinkMsgHandler(ref m); 
                        break;
                    case RichTextBoxConstants.EN_DROPFILES: 
                        NativeMethods.ENDROPFILES endropfiles = (NativeMethods.ENDROPFILES)m.GetLParam(typeof(NativeMethods.ENDROPFILES)); 

                        // Only look at the first file. 
                        StringBuilder path = new StringBuilder(NativeMethods.MAX_PATH);
                        UnsafeNativeMethods.DragQueryFile(new HandleRef(endropfiles, endropfiles.hDrop), 0, path, NativeMethods.MAX_PATH);

                        // Try to load the file as an RTF 
                        try {
                            LoadFile(path.ToString(), RichTextBoxStreamType.RichText); 
                        } 
                        catch {
                            // we failed to load as rich text so try it as plain text 
                            try {
                                LoadFile(path.ToString(), RichTextBoxStreamType.PlainText);
                            }
                            catch { 
                                // ignore any problems we have
                            } 
                        } 
                        m.Result = (IntPtr)1;   // tell them we did the drop
                        break; 

                    case RichTextBoxConstants.EN_REQUESTRESIZE:
                        if (!CallOnContentsResized) {
                            NativeMethods.REQRESIZE reqResize = (NativeMethods.REQRESIZE)m.GetLParam(typeof(NativeMethods.REQRESIZE)); 
                            if (BorderStyle == System.Windows.Forms.BorderStyle.Fixed3D) {
                                reqResize.rc.bottom++; 
                            } 
                            OnContentsResized(new ContentsResizedEventArgs(Rectangle.FromLTRB(reqResize.rc.left, reqResize.rc.top, reqResize.rc.right, reqResize.rc.bottom)));
                            } 
                            break;

                    case RichTextBoxConstants.EN_SELCHANGE:
                        NativeMethods.SELCHANGE selChange = (NativeMethods.SELCHANGE)m.GetLParam(typeof(NativeMethods.SELCHANGE)); 
                        WmSelectionChange(selChange);
                        break; 
 
                    case RichTextBoxConstants.EN_PROTECTED: {
                            NativeMethods.ENPROTECTED enprotected; 

                            //On 64-bit, we do some custom marshalling to get this to work. The richedit control
                            //unfortunately does not respect IA64 struct alignment conventions. See VSWhidbey #122276
                            if (IntPtr.Size == 8) { 
                                enprotected = ConvertFromENPROTECTED64((NativeMethods.ENPROTECTED64)m.GetLParam(typeof(NativeMethods.ENPROTECTED64)));
                            } 
                            else { 
                                enprotected = (NativeMethods.ENPROTECTED)m.GetLParam(typeof(NativeMethods.ENPROTECTED));
                            } 


                            switch (enprotected.msg) {
                                case RichTextBoxConstants.EM_SETCHARFORMAT: 
                                    // Allow change of protected style
                                    // 
                                    NativeMethods.CHARFORMATA charFormat = (NativeMethods.CHARFORMATA)UnsafeNativeMethods.PtrToStructure(enprotected.lParam, typeof(NativeMethods.CHARFORMATA)); 
                                    if ((charFormat.dwMask & RichTextBoxConstants.CFM_PROTECTED) != 0) {
                                        m.Result = IntPtr.Zero; 
                                        return;
                                    }
                                    break;
 
                                    // Throw an exception for the following
                                    // 
                                case RichTextBoxConstants.EM_SETPARAFORMAT: 
                                case NativeMethods.EM_REPLACESEL:
                                    break; 

                                case RichTextBoxConstants.EM_STREAMIN:
                                    // Don't allow STREAMIN to replace protected selection
                                    // 
                                    if (((int)enprotected.wParam & RichTextBoxConstants.SFF_SELECTION) != 0)
                                        break; 
                                    m.Result = IntPtr.Zero; 
                                    return;
 
                                    // Allow the following
                                    //
                                case NativeMethods.WM_COPY:
                                case NativeMethods.WM_SETTEXT: 
                                case RichTextBoxConstants.EM_EXLIMITTEXT:
                                    m.Result = IntPtr.Zero; 
                                    return; 

                                    // Beep and disallow change for all other messages 
                                    //
                                default:
                                    SafeNativeMethods.MessageBeep(0);
                                    break; 
                            }
 
                            OnProtected(EventArgs.Empty); 
                            m.Result = (IntPtr)1;
                            break; 
                        }

                    default:
                        base.WndProc(ref m); 
                        break;
                } 
            } 
            else {
                base.WndProc(ref m); 
            }
        }

        private unsafe NativeMethods.ENPROTECTED ConvertFromENPROTECTED64(NativeMethods.ENPROTECTED64 es64) { 
            NativeMethods.ENPROTECTED es = new NativeMethods.ENPROTECTED();
 
            fixed (byte* es64p =  &es64.contents[0]) { 
                es.nmhdr = new NativeMethods.NMHDR();
                es.chrg  = new NativeMethods.CHARRANGE(); 

                es.nmhdr.hwndFrom = Marshal.ReadIntPtr((IntPtr)es64p);
                es.nmhdr.idFrom = Marshal.ReadIntPtr((IntPtr)(es64p + 8));
                es.nmhdr.code = Marshal.ReadInt32((IntPtr)(es64p + 16)); 
                es.msg = Marshal.ReadInt32((IntPtr)(es64p + 24));
                es.wParam = Marshal.ReadIntPtr((IntPtr)(es64p + 28)); 
                es.lParam = Marshal.ReadIntPtr((IntPtr)(es64p + 36)); 
                es.chrg.cpMin = Marshal.ReadInt32((IntPtr)(es64p + 44));
                es.chrg.cpMax = Marshal.ReadInt32((IntPtr)(es64p + 48)); 
            }

            return es;
        } 

        private static unsafe NativeMethods.ENLINK ConvertFromENLINK64(NativeMethods.ENLINK64 es64) { 
            NativeMethods.ENLINK es = new NativeMethods.ENLINK(); 

            fixed (byte* es64p =  &es64.contents[0]) { 
                es.nmhdr = new NativeMethods.NMHDR();
                es.charrange  = new NativeMethods.CHARRANGE();

                es.nmhdr.hwndFrom = Marshal.ReadIntPtr((IntPtr)es64p); 
                es.nmhdr.idFrom = Marshal.ReadIntPtr((IntPtr)(es64p + 8));
                es.nmhdr.code = Marshal.ReadInt32((IntPtr)(es64p + 16)); 
                es.msg = Marshal.ReadInt32((IntPtr)(es64p + 24)); 
                es.wParam = Marshal.ReadIntPtr((IntPtr)(es64p + 28));
                es.lParam = Marshal.ReadIntPtr((IntPtr)(es64p + 36)); 
                es.charrange.cpMin = Marshal.ReadInt32((IntPtr)(es64p + 44));
                es.charrange.cpMax = Marshal.ReadInt32((IntPtr)(es64p + 48));
            }
 
            return es;
        } 
 
        /// 
        ///  
        /// 
        /// 
        private void WmSelectionChange(NativeMethods.SELCHANGE selChange) {
            int selStart = selChange.chrg.cpMin; 
            int selEnd = selChange.chrg.cpMax;
            short selType = (short)selChange.seltyp; 
 
            // VSWhidbey 94804: The IME retains characters in the composition window even after MaxLength
            // has been reached in the rich edit control. So, if the Hangul or HangulFull IME is in use, and the 
            // number of characters in the control is equal to MaxLength, and the selection start equals the
            // selection end (nothing is currently selected), then kill and restore focus to the control. Then,
            // to prevent any further partial composition from occurring, post a message back to myself to select
            // the last character being composed so that any further composition will occur within the context of 
            // the string contained within the control.
            // 
            // Since the IME window completes the composition string when the control loses focus and the 
            // EIMES_COMPLETECOMPSTRKILLFOCUS status type is set in the control by the EM_SETIMESTATUS message,
            // simply killing focus and resetting focus to the control will force the contents of the composition 
            // window to be removed. This forces the undo buffer to be emptied and the backspace key will properly
            // remove the last completed character typed.

            // Is either the Hangul or HangulFull IME currently in use? 
            if( ImeMode == ImeMode.Hangul || ImeMode == ImeMode.HangulFull ) {
 
                // Is the IME CompositionWindow open? 
                int compMode = (int)SendMessage(RichTextBoxConstants.EM_GETIMECOMPMODE, 0, 0);
                if (RichTextBoxConstants.ICM_NOTOPEN != compMode) { 

                    int textLength = SafeNativeMethods.GetWindowTextLength(new HandleRef(this, Handle));
                    if (selStart == selEnd && textLength == MaxLength) {
 
                        SendMessage(NativeMethods.WM_KILLFOCUS, 0, 0);
                        SendMessage(NativeMethods.WM_SETFOCUS, 0, 0); 
                        UnsafeNativeMethods.PostMessage(new HandleRef(this, Handle), NativeMethods.EM_SETSEL, selEnd - 1, selEnd); 
                    }
                } 
            }

            if (selStart != curSelStart || selEnd != curSelEnd || selType != curSelType) {
                curSelStart = selStart; 
                curSelEnd   = selEnd;
                curSelType  = selType; 
                OnSelectionChanged(EventArgs.Empty); 
            }
        } 

        /// 
        /// 
        ///  
        /// 
        private void WmSetFont(ref Message m) { 
 
            // This function would normally cause two TextChanged events to be fired, one
            // from the base.WndProc, and another from InternalSetForeColor. 
            // To prevent this, we suppress the first event fire.
            //
            try {
                SuppressTextChangedEvent = true; 
                base.WndProc(ref m);
            } 
            finally { 
                SuppressTextChangedEvent = false;
            } 

            InternalSetForeColor(ForeColor);
        }
 
        // 
        //  
        // 
        /// 
        ///  
        ///    [To be supplied.]
        /// 
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        protected override void WndProc(ref Message m) { 
            switch (m.Msg) {
                case NativeMethods.WM_REFLECT + NativeMethods.WM_NOTIFY: 
                    WmReflectNotify(ref m); 
                    break;
 
                case NativeMethods.WM_REFLECT + NativeMethods.WM_COMMAND:
                    WmReflectCommand(ref m);
                    break;
 
                case NativeMethods.WM_SETCURSOR:
                    //NOTE: RichTextBox uses the WM_SETCURSOR message over links to allow us to 
                    //      change the cursor to a hand. It does this through a synchronous notification 
                    //      message. So we have to pass the message to the DefWndProc first, and
                    //      then, if we receive a notification message in the meantime (indicated by 
                    //      changing "LinkCursor", we set it to a hand. Otherwise, we call the
                    //      WM_SETCURSOR implementation on Control to set it to the user's selection for
                    //      the RichTextBox's cursor.
                    // 
                    //      Similarly,
                    LinkCursor = false; 
                    DefWndProc(ref m); 
                    if (LinkCursor && !Cursor.Equals(Cursors.WaitCursor)) {
                        UnsafeNativeMethods.SetCursor(new HandleRef(Cursors.Hand, Cursors.Hand.Handle)); 
                        m.Result = (IntPtr)1;
                    }
                    else {
                        base.WndProc(ref m); 
                    }
                    break; 
 
                case NativeMethods.WM_SETFONT:
                    WmSetFont(ref m); 
                    break;

                case NativeMethods.WM_IME_NOTIFY:
                    OnImeChange(EventArgs.Empty); 
                    base.WndProc(ref m);
                    break; 
 
                case NativeMethods.WM_GETDLGCODE:
                    base.WndProc(ref m); 
                    m.Result = (IntPtr)((AcceptsTab) ? (int)m.Result | NativeMethods.DLGC_WANTTAB : (int)m.Result & ~NativeMethods.DLGC_WANTTAB);
                    break;

                case NativeMethods.WM_GETOBJECT: 
                    base.WndProc(ref m);
 
                    // OLEACC.DLL uses window class names to identify standard control types. But WinForm controls use app-specific window 
                    // classes. Usually this doesn't matter, because system controls always identify their window class explicitly through
                    // the WM_GETOBJECT+OBJID_QUERYCLASSNAMEIDX message. But RICHEDIT20 doesn't do that - so we must do it ourselves. 
                    // Otherwise OLEACC will treat rich edit controls as custom controls, so the accessible Role and Value will be wrong.
                    if (unchecked((int)(long)m.LParam) == NativeMethods.OBJID_QUERYCLASSNAMEIDX) {
                        m.Result = (IntPtr) ((Marshal.SystemDefaultCharSize == 1) ? (65536+29) : (65536+30));
                    } 
                    break;
 
                case NativeMethods.WM_RBUTTONUP: 
                    //Whidbey 317086
                    //since RichEdit eats up the WM_CONTEXTMENU message, we need to force DefWndProc 
                    //to spit out this message again on receiving WM_RBUTTONUP message. By setting UserMouse
                    //style to true, we effectily let the WmMouseUp method in Control.cs to generate
                    //the WM_CONTEXTMENU message for us.
                    bool oldStyle = GetStyle(ControlStyles.UserMouse); 
                    SetStyle(ControlStyles.UserMouse, true);
                    base.WndProc(ref m); 
                    SetStyle(ControlStyles.UserMouse, oldStyle); 
                    break;
 
                case NativeMethods.WM_VSCROLL:
                    base.WndProc(ref m);
                    int loWord = Util.LOWORD(m.WParam);
                    if (loWord == NativeMethods.SB_THUMBTRACK) 
                    {
                        OnVScroll(EventArgs.Empty); 
                    } else 
                        if (loWord == NativeMethods.SB_THUMBPOSITION)
                        { 
                            OnVScroll(EventArgs.Empty);
                        }
                    break;
 
                case NativeMethods.WM_HSCROLL:
                    base.WndProc(ref m); 
                    loWord = Util.LOWORD(m.WParam); 
                    if (loWord == NativeMethods.SB_THUMBTRACK)
                    { 
                        OnHScroll(EventArgs.Empty);
                    }
                    if (loWord == NativeMethods.SB_THUMBPOSITION)
                    { 
                        OnHScroll(EventArgs.Empty);
                    } 
                    break; 

                default: 
                    base.WndProc(ref m);
                    break;
            }
        } 

        // I used the visual basic 6 RichText (REOleCB.CPP) as a guide for this 
        private class OleCallback : UnsafeNativeMethods.IRichEditOleCallback { 

            private RichTextBox owner; 
            IDataObject lastDataObject;
            DragDropEffects lastEffect;

            internal OleCallback(RichTextBox owner) { 
                this.owner = owner;
            } 
 

            public int GetNewStorage(out UnsafeNativeMethods.IStorage storage) { 
                Debug.WriteLineIf(RichTextDbg.TraceVerbose, "IRichEditOleCallback::GetNewStorage");
                if (!this.owner.AllowOleObjects) {
                    storage = null;
                    return NativeMethods.E_FAIL; 
                }
                // Debug.WriteLine("get new storage"); 
                UnsafeNativeMethods.ILockBytes pLockBytes = UnsafeNativeMethods.CreateILockBytesOnHGlobal(NativeMethods.NullHandleRef, true); 

                Debug.Assert(pLockBytes != null, "pLockBytes is NULL!"); 

                storage = UnsafeNativeMethods.StgCreateDocfileOnILockBytes(pLockBytes,
                                                                           NativeMethods.STGM_SHARE_EXCLUSIVE | NativeMethods.STGM_CREATE | NativeMethods.STGM_READWRITE,
                                                                           0); 
                Debug.Assert(storage != null, "storage is NULL!");
 
                return NativeMethods.S_OK; 
            }
 
            public int GetInPlaceContext(IntPtr lplpFrame,
                                         IntPtr lplpDoc,
                                         IntPtr lpFrameInfo) {
                Debug.WriteLineIf(RichTextDbg.TraceVerbose, "IRichEditOleCallback::GetInPlaceContext"); 
                return NativeMethods.E_NOTIMPL;
            } 
 
            public int ShowContainerUI(int fShow) {
                Debug.WriteLineIf(RichTextDbg.TraceVerbose, "IRichEditOleCallback::ShowContainerUI"); 
                // Do nothing
                return NativeMethods.S_OK;
            }
 
            public int QueryInsertObject(ref Guid lpclsid, IntPtr lpstg, int cp)
            { 
                Debug.WriteLineIf(RichTextDbg.TraceVerbose, "IRichEditOleCallback::QueryInsertObject(" + lpclsid.ToString() + ")"); 

                try 
                {
                    IntSecurity.UnmanagedCode.Demand();
                    return NativeMethods.S_OK;
                } 
                catch (SecurityException)
                { 
                    // We do not have unmanaged code access, so 
                    // we need to restrict what we allow to be loaded
                } 
                Guid realClsid = new Guid();


                int hr = UnsafeNativeMethods.ReadClassStg(new HandleRef(null, lpstg), ref realClsid); 
                Debug.WriteLineIf(RichTextDbg.TraceVerbose, "real clsid:" + realClsid.ToString() + " (hr=" + hr.ToString("X", CultureInfo.InvariantCulture) + ")");
 
                if (!NativeMethods.Succeeded(hr)) 
                {
                    return NativeMethods.S_FALSE; 
                }

                if (realClsid == Guid.Empty)
                { 
                    realClsid = lpclsid;
                } 
 
                switch (realClsid.ToString().ToUpper(CultureInfo.InvariantCulture))
                { 
                    case "00000315-0000-0000-C000-000000000046": // Metafile
                    case "00000316-0000-0000-C000-000000000046": // DIB
                    case "00000319-0000-0000-C000-000000000046": // EMF
                    case "0003000A-0000-0000-C000-000000000046": //BMP 
                        return NativeMethods.S_OK;
                    default: 
                        Debug.WriteLineIf(RichTextDbg.TraceVerbose, "   denying '" + lpclsid.ToString() + "' from being inserted due to security restrictions"); 
                        return NativeMethods.S_FALSE;
                } 
            }

            public int DeleteObject(IntPtr lpoleobj) {
                Debug.WriteLineIf(RichTextDbg.TraceVerbose, "IRichEditOleCallback::DeleteObject"); 
                // Do nothing
                return NativeMethods.S_OK; 
            } 

            public int QueryAcceptData(IComDataObject lpdataobj, 
                                       /* CLIPFORMAT* */ IntPtr lpcfFormat, int reco,
                                       int fReally, IntPtr hMetaPict) {

                Debug.WriteLineIf(RichTextDbg.TraceVerbose, "IRichEditOleCallback::QueryAcceptData(reco=" + reco + ")"); 

                if (reco == NativeMethods.RECO_DROP) { 
                    if (owner.AllowDrop || owner.EnableAutoDragDrop) { 

                        MouseButtons b = Control.MouseButtons; 
                        Keys k = Control.ModifierKeys;

                        int keyState = 0;
 
                        // Due to the order in which we get called, we have to set up the keystate here.
                        // First GetDragDropEffect is called with grfKeyState == 0, and then 
                        // QueryAcceptData is called. Since this is the time we want to fire 
                        // OnDragEnter, but we have yet to get the keystate, we set it up ourselves.
 
                        if ((b & MouseButtons.Left) == MouseButtons.Left) {
                            keyState |= NativeMethods.MK_LBUTTON;
                        }
 
                        if ((b & MouseButtons.Right) == MouseButtons.Right) {
                            keyState |= NativeMethods.MK_RBUTTON; 
                        } 

                        if ((b & MouseButtons.Middle) == MouseButtons.Middle) { 
                            keyState |= NativeMethods.MK_MBUTTON;
                        }

                        if ((k & Keys.Control) == Keys.Control) { 
                            keyState |= NativeMethods.MK_CONTROL;
                        } 
 
                        if ((k & Keys.Shift) == Keys.Shift) {
                            keyState |= NativeMethods.MK_SHIFT; 
                        }

                        lastDataObject = new DataObject(lpdataobj);
 
                        if (!owner.EnableAutoDragDrop) {
                            lastEffect = DragDropEffects.None; 
                        } 

                        DragEventArgs e = new DragEventArgs(lastDataObject, 
                                                        keyState,
                                                        Control.MousePosition.X,
                                                        Control.MousePosition.Y,
                                                        DragDropEffects.All, 
                                                        lastEffect);
                        if (fReally == 0) { 
                            // we are just querying 

                            // We can get here without GetDragDropEffects actually being called first. 
                            // This happens when you drag/drop between two rtb's. Say you drag from rtb1 to rtb2.
                            // GetDragDropEffects will first be called for rtb1, then QueryAcceptData for rtb1 just
                            // like in the local drag case. Then you drag into rtb2. rtb2 will first be called in this method,
                            // and not GetDragDropEffects. Now lastEffect is initialized to None for rtb2, so we would not allow 
                            // the drag. Thus we need to set the effect here as well.
                            e.Effect = ((keyState & NativeMethods.MK_CONTROL) == NativeMethods.MK_CONTROL) ? DragDropEffects.Copy : DragDropEffects.Move; 
                            owner.OnDragEnter(e); 
                        }
                        else { 
                            owner.OnDragDrop(e);
                            lastDataObject = null;
                        }
 
                        lastEffect = e.Effect;
                        if (e.Effect == DragDropEffects.None) { 
                            Debug.WriteLineIf(RichTextDbg.TraceVerbose, "\tCancel data"); 
                            return NativeMethods.E_FAIL;
                        } 
                        else {
                            Debug.WriteLineIf(RichTextDbg.TraceVerbose, "\tAccept data");
                            return NativeMethods.S_OK;
                        } 
                    }
                    else { 
                        Debug.WriteLineIf(RichTextDbg.TraceVerbose, "\tCancel data, allowdrop == false"); 
                        lastDataObject = null;
                        return NativeMethods.E_FAIL; 
                    }
                }
                else {
                    return NativeMethods.E_NOTIMPL; 
                }
            } 
 
            public int ContextSensitiveHelp(int fEnterMode) {
                Debug.WriteLineIf(RichTextDbg.TraceVerbose, "IRichEditOleCallback::ContextSensitiveHelp"); 
                return NativeMethods.E_NOTIMPL;
            }

            public int GetClipboardData(NativeMethods.CHARRANGE lpchrg, int reco, 
                                        IntPtr lplpdataobj) {
                Debug.WriteLineIf(RichTextDbg.TraceVerbose, "IRichEditOleCallback::GetClipboardData"); 
                return NativeMethods.E_NOTIMPL; 
            }
 
            public int GetDragDropEffect(bool fDrag, int grfKeyState, ref int pdwEffect) {
                Debug.WriteLineIf(RichTextDbg.TraceVerbose, "IRichEditOleCallback::GetDragDropEffect");

                if (owner.AllowDrop || owner.EnableAutoDragDrop) { 

                    if (fDrag && grfKeyState == 0) { 
                        // This is the very first call we receive in a Drag-Drop operation, 
                        // so we will let the control know what we support.
 
                        // Note that we haven't gotten any data yet, so we will let QueryAcceptData
                        // do the OnDragEnter. Note too, that grfKeyState does not yet reflect the
                        // current keystate
                        if (owner.EnableAutoDragDrop) { 
                            lastEffect = (DragDropEffects.All | DragDropEffects.None);
                        } 
                        else 
                            lastEffect = DragDropEffects.None;
 
                    }
                    else {
                        // We are either dragging over or dropping
 

                        // The below is the complete reverse of what the docs on MSDN suggest, 
                        // but if we follow the docs, we would be firing OnDragDrop all the 
                        // time instead of OnDragOver (see bug 99294). MSDN seems to be wrong here.
 
                        // drag - fDrag = false, grfKeyState != 0
                        // drop - fDrag = false, grfKeyState = 0
                        // We only care about the drag.
                        // 
                        // When we drop, lastEffect will have the right state
                        if (!fDrag && lastDataObject != null && grfKeyState != 0) { 
 
                            DragEventArgs e = new DragEventArgs(lastDataObject,
                                                                grfKeyState, 
                                                                Control.MousePosition.X,
                                                                Control.MousePosition.Y,
                                                                DragDropEffects.All,
                                                                lastEffect); 

                            // Now tell which of the allowable effects we want to use, but only if we are not already none 
                            if (lastEffect != DragDropEffects.None) { 
                                e.Effect = ((grfKeyState & NativeMethods.MK_CONTROL) == NativeMethods.MK_CONTROL) ? DragDropEffects.Copy : DragDropEffects.Move;
                            } 

                            owner.OnDragOver(e);
                            lastEffect = e.Effect;
                        } 
                    }
 
                    pdwEffect = (int)lastEffect; 

                } 
                else {
                    pdwEffect = (int)DragDropEffects.None;
                }
                return NativeMethods.S_OK; 
            }
 
            public int GetContextMenu(short seltype, IntPtr lpoleobj, NativeMethods.CHARRANGE lpchrg, out IntPtr hmenu) { 
                Debug.WriteLineIf(RichTextDbg.TraceVerbose, "IRichEditOleCallback::GetContextMenu");
                ContextMenu cm = owner.ContextMenu; 
                if (cm == null || owner.ShortcutsEnabled == false)
                    hmenu = IntPtr.Zero;
                else {
                    cm.sourceControl = owner; 
                    cm.OnPopup(EventArgs.Empty);
                    // RichEd calls DestroyMenu after displaying the context menu 
                    IntPtr handle = cm.Handle; 
                    // if another control shares the same context menu
                    // then we have to mark the context menu's handles empty because 
                    // RichTextBox will delete the menu handles once the popup menu is dismissed.
                    Menu menu = cm;
                    while (true) {
                        int i = 0; 
                        int count = menu.ItemCount;
                        for (; i< count; i++) { 
                            if (menu.items[i].handle != IntPtr.Zero) { 
                                menu = menu.items[i];
                                break; 
                            }
                        }
                        if (i == count) {
                            menu.handle = IntPtr.Zero; 
                            menu.created = false;
                            if (menu == cm) 
                                break; 
                            else
                                menu = ((MenuItem) menu).Menu; 
                        }
                    }

                    hmenu = handle; 
                }
 
                return NativeMethods.S_OK; 
            }
        } 
    }
}


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK