MaskedTextBox.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / fx / src / WinForms / Managed / System / WinForms / MaskedTextBox.cs / 1 / MaskedTextBox.cs

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

namespace System.Windows.Forms 
{ 
    using System;
    using System.Text; 
    using System.ComponentModel;
    using System.Runtime.InteropServices;
    using System.Globalization;
    using System.Security; 
    using System.Security.Permissions;
    using System.Diagnostics; 
    using System.Collections; 
    using System.Collections.Specialized;
    using System.Drawing; 
    using System.Drawing.Design;
    using System.Windows.Forms.Layout;
    using System.Windows.Forms.VisualStyles;
 
    /// 
    ///     MaskedTextBox control definition class. 
    ///     Uses the services from the System.ComponentModel.MaskedTextBoxProvider class. 
    ///     See spec at http://dotnetclient/whidbey/Specs/MaskEdit.doc
    ///  
    [
    ComVisible(true),
    ClassInterface(ClassInterfaceType.AutoDispatch),
    DefaultEvent("MaskInputRejected"), 
    DefaultBindingProperty("Text"),
    DefaultProperty("Mask"), 
    Designer("System.Windows.Forms.Design.MaskedTextBoxDesigner, " + AssemblyRef.SystemDesign), 
    SRDescription(SR.DescriptionMaskedTextBox)
    ] 
    public class MaskedTextBox : TextBoxBase
    {
        // Consider: The MaskedTextBox control, when initialized with a non-null/empty mask, processes all
        // WM_CHAR messages and always sets the text using the SetWindowText Windows function in the furthest base 
        // class.  This means that the underlying Edit control won't enable Undo operations and the context
        // menu behavior will be a bit different (for instance Copy option is enabled when PasswordChar is set). 
        // To provide Undo functionality and make the context menu behave like the Edit control, we would have 
        // to implement our own.  See http://msdn.microsoft.com/msdnmag/issues/1100/c/default.aspx for more info
        // about how to do this. See postponed bug VSWhidbey#218402. 

        private const bool   forward         = true;
        private const bool   backward        = false;
        private const string nullMask        = "<>"; // any char/str is OK here. 

        private static readonly object EVENT_MASKINPUTREJECTED      = new object(); 
        private static readonly object EVENT_VALIDATIONCOMPLETED    = new object(); 
        private static readonly object EVENT_TEXTALIGNCHANGED       = new object();
        private static readonly object EVENT_ISOVERWRITEMODECHANGED = new object(); 
        private static readonly object EVENT_MASKCHANGED            = new object();

        // The native edit control's default password char (per thread). See corresponding property for more info.
        private static char systemPwdChar; 

        // Values to track changes in IME composition string (if any).  Having const variables is a bit more efficient 
        // than having an enum (which creates a class). 
        private const byte imeConvertionNone      = 0;  // no convertion has been performed in the composition string.
        private const byte imeConvertionUpdate    = 1;  // the char being composed has been updated but not coverted yet. 
        private const byte imeConvertionCompleted = 2;  // the char being composed has been fully converted.

        ///////// Instance fields
 
        // Used for keeping selection when prompt is hidden on leave (text changes).
        private int lastSelLength; 
 
        // Used for caret positioning.
        private int caretTestPos; 

        // Bit mask - Determines when the Korean IME composition string is completed so converted character can be processed.
        private static int IME_ENDING_COMPOSITION = BitVector32.CreateMask();
 
        // Bit mask - Determines when the Korean IME is completing a composition, used when forcing convertion.
        private static int IME_COMPLETING = BitVector32.CreateMask(IME_ENDING_COMPOSITION); 
 
        // Used for handling characters that have a modifier (Ctrl-A, Shift-Del...).
        private static int HANDLE_KEY_PRESS = BitVector32.CreateMask(IME_COMPLETING); 

        // Bit mask - Used to simulate a null mask.  Needed since a MaskedTextProvider object cannot be
        // initialized with a null mask but we need one even in this case as a backend for
        // default properties.  This is to support creating a MaskedTextBox with the default 
        // constructor, specially at design time.
        private static int IS_NULL_MASK = BitVector32.CreateMask(HANDLE_KEY_PRESS); 
 
        // Bit mask - Used in conjuction with get_Text to return the text that is actually set in the native
        // control.  This is required to be able to measure text correctly (GetPreferredSize) and 
        // to compare against during set_Text (to bail if the same and not to raise TextChanged event).
        private static int QUERY_BASE_TEXT = BitVector32.CreateMask(IS_NULL_MASK);

        // If true, the input text is rejected whenever a character does not comply with the mask; a MaskInputRejected 
        // event is fired for the failing character.
        // If false, characters in the input string are processed one by one accepting the ones that comply 
        // with the mask and raising the MaskInputRejected event for the rejected ones. 
        private static int REJECT_INPUT_ON_FIRST_FAILURE = BitVector32.CreateMask( QUERY_BASE_TEXT );
 
        // Bit masks for boolean properties.
        private static int HIDE_PROMPT_ON_LEAVE     = BitVector32.CreateMask(REJECT_INPUT_ON_FIRST_FAILURE);
        private static int BEEP_ON_ERROR            = BitVector32.CreateMask(HIDE_PROMPT_ON_LEAVE);
        private static int USE_SYSTEM_PASSWORD_CHAR = BitVector32.CreateMask(BEEP_ON_ERROR); 
        private static int INSERT_TOGGLED           = BitVector32.CreateMask(USE_SYSTEM_PASSWORD_CHAR);
        private static int CUTCOPYINCLUDEPROMPT     = BitVector32.CreateMask(INSERT_TOGGLED); 
        private static int CUTCOPYINCLUDELITERALS   = BitVector32.CreateMask(CUTCOPYINCLUDEPROMPT); 

        ///////// Properties backend fields. See corresponding property comments for more info. 

        private char                    passwordChar; // control's pwd char, it could be different from the one displayed if using system password.
        private Type                    validatingType;
        private IFormatProvider         formatProvider; 
        private MaskedTextProvider      maskedTextProvider;
        private InsertKeyMode           insertMode; 
        private HorizontalAlignment     textAlign; 

        // Bit vector to represent bool variables. 
        private BitVector32 flagState;

        /// 
        ///     Constructs the MaskedTextBox with the specified MaskedTextProvider object. 
        /// 
        public MaskedTextBox() 
        { 
            MaskedTextProvider maskedTextProvider = new MaskedTextProvider(nullMask, CultureInfo.CurrentCulture);
            this.flagState[IS_NULL_MASK] = true; 
            Initialize(maskedTextProvider);
        }

        ///  
        ///     Constructs the MaskedTextBox with the specified MaskedTextProvider object.
        ///  
        public MaskedTextBox(string mask) 
        {
            if (mask == null) 
            {
                throw new ArgumentNullException();
            }
 
            MaskedTextProvider maskedTextProvider = new MaskedTextProvider(mask, CultureInfo.CurrentCulture);
            this.flagState[IS_NULL_MASK] = false; 
            Initialize(maskedTextProvider); 
        }
 
        /// 
        ///     Constructs the MaskedTextBox with the specified MaskedTextProvider object.
        /// 
        public MaskedTextBox(MaskedTextProvider maskedTextProvider) 
        {
            if (maskedTextProvider == null) 
            { 
                throw new ArgumentNullException();
            } 

            this.flagState[IS_NULL_MASK] = false;
            Initialize(maskedTextProvider);
        } 

        ///  
        ///     Initializes the object with the specified MaskedTextProvider object and default 
        ///     property values.
        ///  
        private void Initialize(MaskedTextProvider maskedTextProvider)
        {
            Debug.Assert(maskedTextProvider != null, "Initializing from a null MaskProvider ref.");
 
            this.maskedTextProvider = maskedTextProvider;
 
            // set the initial display text. 
            if (!this.flagState[IS_NULL_MASK])
            { 
                SetWindowText();
            }

            // set default values. 
            this.passwordChar = this.maskedTextProvider.PasswordChar;
            this.insertMode   = InsertKeyMode.Default; 
 
            this.flagState[HIDE_PROMPT_ON_LEAVE         ] = false;
            this.flagState[BEEP_ON_ERROR                ] = false; 
            this.flagState[USE_SYSTEM_PASSWORD_CHAR     ] = false;
            this.flagState[REJECT_INPUT_ON_FIRST_FAILURE] = false;

            // CutCopyMaskFormat - set same defaults as TextMaskFormat (IncludePromptAndLiterals). 
            // It is a lot easier to handle this flags individually since that's the way the MaskedTextProvider does it.
            this.flagState[CUTCOPYINCLUDEPROMPT         ] = this.maskedTextProvider.IncludePrompt; 
            this.flagState[CUTCOPYINCLUDELITERALS       ] = this.maskedTextProvider.IncludeLiterals; 

            // fields for internal use. 
            this.flagState[HANDLE_KEY_PRESS] = true;
            this.caretTestPos           = 0;
        }
 

        /////////////////// Properties 
        /// 

        ///  
        ///     Unsupported method/property.
        /// 
        [
        Browsable(false), 
        EditorBrowsable(EditorBrowsableState.Never),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) 
        ] 
        public new bool AcceptsTab
        { 
            get { return false; }
            set {}
        }
 
        /// 
        ///     Specifies whether the prompt character should be treated as a valid input character or not. 
        ///     The setter resets the underlying MaskedTextProvider object and attempts 
        ///     to add the existing input text (if any) using the new mask, failure is ignored.
        ///     This property has no particular effect if no mask has been set. 
        /// 
        [
        SRCategory(SR.CatBehavior),
        SRDescription(SR.MaskedTextBoxAllowPromptAsInputDescr), 
        DefaultValue(true)
        ] 
        public bool AllowPromptAsInput 
        {
            get 
            {
                return this.maskedTextProvider.AllowPromptAsInput;
            }
            set 
            {
                if( value != this.maskedTextProvider.AllowPromptAsInput ) 
                { 
                    // Recreate masked text provider since this property is read-only.
                    MaskedTextProvider newProvider = new MaskedTextProvider( 
                        this.maskedTextProvider.Mask,
                        this.maskedTextProvider.Culture,
                        value,
                        this.maskedTextProvider.PromptChar, 
                        this.maskedTextProvider.PasswordChar,
                        this.maskedTextProvider.AsciiOnly ); 
 
                    SetMaskedTextProvider( newProvider );
                } 
            }
        }

        ///  
        ///     Unsupported method/property.
        ///  
        [ 
        Browsable(false),
        EditorBrowsable(EditorBrowsableState.Never), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        public new event EventHandler AcceptsTabChanged
        { 
            add { }
            remove { } 
        } 

        ///  
        ///     Specifies whether only ASCII characters are accepted as valid input.
        ///     This property has no particular effect if no mask has been set.
        /// 
        [ 
        SRCategory(SR.CatBehavior),
        SRDescription(SR.MaskedTextBoxAsciiOnlyDescr), 
        RefreshProperties(RefreshProperties.Repaint), 
        DefaultValue(false)
        ] 
        public bool AsciiOnly
        {
            get
            { 
                return this.maskedTextProvider.AsciiOnly;
            } 
 
            set
            { 
                if( value != this.maskedTextProvider.AsciiOnly )
                {
                    // Recreate masked text provider since this property is read-only.
                    MaskedTextProvider newProvider = new MaskedTextProvider( 
                        this.maskedTextProvider.Mask,
                        this.maskedTextProvider.Culture, 
                        this.maskedTextProvider.AllowPromptAsInput, 
                        this.maskedTextProvider.PromptChar,
                        this.maskedTextProvider.PasswordChar, 
                        value );

                    SetMaskedTextProvider( newProvider );
                } 
            }
        } 
 
        /// 
        ///     Specifies whether to play a beep when the input is not valid according to the mask. 
        /// 
        [
        SRCategory(SR.CatBehavior),
        SRDescription(SR.MaskedTextBoxBeepOnErrorDescr), 
        DefaultValue(false)
        ] 
        public bool BeepOnError 
        {
            get 
            {
                return this.flagState[BEEP_ON_ERROR];
            }
            set 
            {
                this.flagState[BEEP_ON_ERROR] = value; 
            } 
        }
 
        /// 
        ///       Gets a value indicating whether the user can undo the previous operation in a text box control.
        ///       Unsupported method/property.
        ///       WndProc ignores EM_CANUNDO. 
        /// 
        [ 
        Browsable(false), 
        EditorBrowsable(EditorBrowsableState.Never),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) 
        ]
        public new bool CanUndo
        {
            get 
            {
                return false; 
            } 
        }
 
        /// 
        ///     Returns the parameters needed to create the handle. Inheriting classes
        ///     can override this to provide extra functionality. They should not,
        ///     however, forget to call base.getCreateParams() first to get the struct 
        ///     filled up with the basic info.
        ///  
        protected override CreateParams CreateParams 
        {
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] 
            get
            {
                CreateParams cp = base.CreateParams;
 
                // Translate for Rtl if necessary
                // 
                HorizontalAlignment align = RtlTranslateHorizontal(textAlign); 
                cp.ExStyle &= ~NativeMethods.WS_EX_RIGHT;   // WS_EX_RIGHT overrides the ES_XXXX alignment styles
                switch (align) 
                {
                    case HorizontalAlignment.Left:
                        cp.Style |= NativeMethods.ES_LEFT;
                        break; 
                    case HorizontalAlignment.Center:
                        cp.Style |= NativeMethods.ES_CENTER; 
                        break; 
                    case HorizontalAlignment.Right:
                        cp.Style |= NativeMethods.ES_RIGHT; 
                        break;
                }

                return cp; 
            }
        } 
 
        /// 
        ///     The culture that determines the value of the localizable mask language separators and placeholders. 
        /// 
        [
        SRCategory(SR.CatBehavior),
        SRDescription(SR.MaskedTextBoxCultureDescr), 
        RefreshProperties(RefreshProperties.Repaint),
        ] 
        public CultureInfo Culture 
        {
            get 
            {
                return this.maskedTextProvider.Culture;
            }
 
            set
            { 
                if( value == null ) 
                {
                    throw new ArgumentNullException(); 
                }

                if( !this.maskedTextProvider.Culture.Equals(value) )
                { 
                    // Recreate masked text provider since this property is read-only.
                    MaskedTextProvider newProvider = new MaskedTextProvider( 
                        this.maskedTextProvider.Mask, 
                        value,
                        this.maskedTextProvider.AllowPromptAsInput, 
                        this.maskedTextProvider.PromptChar,
                        this.maskedTextProvider.PasswordChar,
                        this.maskedTextProvider.AsciiOnly );
 
                    SetMaskedTextProvider( newProvider );
                } 
            } 
        }
 
        /// 
        ///    Specifies the formatting options for text cut/copited to the clipboard (Whether the mask returned from the Text
        ///    property includes Literals and/or prompt characters).
        ///    When prompt characters are excluded, theyare returned as spaces in the string returned. 
        /// 
        [ 
        SRCategory(SR.CatBehavior), 
        SRDescription(SR.MaskedTextBoxCutCopyMaskFormat),
        RefreshProperties(RefreshProperties.Repaint), 
        DefaultValue(MaskFormat.IncludeLiterals)
        ]
        public MaskFormat CutCopyMaskFormat
        { 
            get
            { 
                if( this.flagState[CUTCOPYINCLUDEPROMPT] ) 
                {
                    if( this.flagState[CUTCOPYINCLUDELITERALS] ) 
                    {
                        return MaskFormat.IncludePromptAndLiterals;
                    }
 
                    return MaskFormat.IncludePrompt;
                } 
 
                if( this.flagState[CUTCOPYINCLUDELITERALS] )
                { 
                    return MaskFormat.IncludeLiterals;
                }

                return MaskFormat.ExcludePromptAndLiterals; 
            }
 
            set 
            {
                //valid values are 0x0 to 0x3 
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)MaskFormat.ExcludePromptAndLiterals, (int)MaskFormat.IncludePromptAndLiterals))
                {
                      throw new InvalidEnumArgumentException("value", (int)value, typeof(MaskFormat));
                } 

                if( value == MaskFormat.IncludePrompt ) 
                { 
                    this.flagState[CUTCOPYINCLUDEPROMPT]   = true;
                    this.flagState[CUTCOPYINCLUDELITERALS] = false; 
                }
                else if( value == MaskFormat.IncludeLiterals )
                {
                    this.flagState[CUTCOPYINCLUDEPROMPT]   = false; 
                    this.flagState[CUTCOPYINCLUDELITERALS] = true;
                } 
                else // value == MaskFormat.IncludePromptAndLiterals || value == MaskFormat.ExcludePromptAndLiterals 
                {
                    bool include = value == MaskFormat.IncludePromptAndLiterals; 
                    this.flagState[CUTCOPYINCLUDEPROMPT]   = include;
                    this.flagState[CUTCOPYINCLUDELITERALS] = include;
                }
            } 
        }
 
        ///  
        ///     Specifies the IFormatProvider to be used when parsing the string to the ValidatingType.
        ///  
        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ] 
        public IFormatProvider FormatProvider
        { 
            get 
            {
                return this.formatProvider; 
            }

            set
            { 
                this.formatProvider = value;
            } 
        } 

        ///  
        ///     Specifies whether the PromptCharacter is displayed when the control loses focus.
        /// 
        [
        SRCategory(SR.CatBehavior), 
        SRDescription(SR.MaskedTextBoxHidePromptOnLeaveDescr),
        RefreshProperties(RefreshProperties.Repaint), 
        DefaultValue(false) 
        ]
        public bool HidePromptOnLeave 
        {
            get
            {
                return this.flagState[HIDE_PROMPT_ON_LEAVE]; 
            }
            set 
            { 
                if( this.flagState[HIDE_PROMPT_ON_LEAVE]  != value )
                { 
                    this.flagState[HIDE_PROMPT_ON_LEAVE] = value;

                    // If the control is not focused and there are available edit positions (mask not full) we need to
                    // update the displayed text. 
                    if( !this.flagState[IS_NULL_MASK]&& !this.Focused && !this.MaskFull && !this.DesignMode )
                    { 
                        SetWindowText(); 
                    }
                } 
            }
        }

        ///  
        ///     Specifies whether to include mask literal characters when formatting the text.
        ///  
        private bool IncludeLiterals 
        {
            get 
            {
                return this.maskedTextProvider.IncludeLiterals;
            }
            set 
            {
                this.maskedTextProvider.IncludeLiterals = value; 
            } 
        }
 
        /// 
        ///     Specifies whether to include the mask prompt character when formatting the text in places
        ///     where an edit char has not being assigned.
        ///  
        private bool IncludePrompt
        { 
            get 
            {
                return this.maskedTextProvider.IncludePrompt; 
            }
            set
            {
                this.maskedTextProvider.IncludePrompt = value; 
            }
        } 
 
        /// 
        ///     Specifies the text insertion mode of the text box.  This can be used to simulated the Access masked text 
        ///     control behavior where insertion is set to TextInsertionMode.AlwaysOverwrite
        ///     This property has no particular effect if no mask has been set.
        /// 
        [ 
        SRCategory(SR.CatBehavior),
        SRDescription(SR.MaskedTextBoxInsertKeyModeDescr), 
        DefaultValue(InsertKeyMode.Default) 
        ]
        public InsertKeyMode InsertKeyMode 
        {
            get
            {
                return this.insertMode; 
            }
            set 
            { 
                //valid values are 0x0 to 0x2
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)InsertKeyMode.Default, (int)InsertKeyMode.Overwrite)) 
                {
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(InsertKeyMode));
                }
 
                if (this.insertMode != value)
                { 
                    bool isOverwrite = this.IsOverwriteMode; 
                    this.insertMode  = value;
 
                    if (isOverwrite != this.IsOverwriteMode)
                    {
                        OnIsOverwriteModeChanged(EventArgs.Empty);
                    } 
                }
            } 
        } 

        ///  
        ///     Overridden to handle unsupported RETURN key.
        /// 
        protected override bool IsInputKey(Keys keyData)
        { 
            if ((keyData & Keys.KeyCode) == Keys.Return)
            { 
                return false; 
            }
            return base.IsInputKey(keyData); 
        }

        /// 
        ///     Specifies whether text insertion mode in 'on' or not. 
        /// 
        [ 
        Browsable(false) 
        ]
        public bool IsOverwriteMode 
        {
            get
            {
                if( this.flagState[IS_NULL_MASK]) 
                {
                    return false; // EditBox always inserts. 
                } 

                switch (this.insertMode) 
                {
                    case InsertKeyMode.Overwrite:
                        return true;
 
                    case InsertKeyMode.Insert:
                        return false; 
 
                    case InsertKeyMode.Default:
 
                        // Note that the insert key state should be per process and its initial state insert, this is the
                        // behavior of apps like WinWord, WordPad and VS; so we have to keep track of it and not query its
                        // system value.
                        //return Control.IsKeyLocked(Keys.Insert); 
                        return this.flagState[INSERT_TOGGLED];
 
                    default: 
                        Debug.Fail("Invalid InsertKeyMode.  This code path should have never been executed.");
                        return false; 
                }
            }
        }
 

        ///  
        ///   Event to notify when the insert mode has changed.  This is required for data binding. 
        /// 
        [ 
        SRCategory(SR.CatPropertyChanged),
        SRDescription(SR.MaskedTextBoxIsOverwriteModeChangedDescr)
        ]
        public event EventHandler IsOverwriteModeChanged 
        {
            add 
            { 
                Events.AddHandler(EVENT_ISOVERWRITEMODECHANGED, value);
            } 
            remove
            {
                Events.RemoveHandler(EVENT_ISOVERWRITEMODECHANGED, value);
            } 
        }
 
        ///  
        ///     Unsupported method/property.
        ///  
        [
        Browsable(false),
        EditorBrowsable(EditorBrowsableState.Never),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) 
        ]
        public new string[] Lines 
        { 
            get
            { 
                string[] lines;

                this.flagState[QUERY_BASE_TEXT] = true;
                try 
                {
                    lines = base.Lines; 
                } 
                finally
                { 
                    this.flagState[QUERY_BASE_TEXT] = false;
                }

                return lines; 
            }
 
            set {} 
        }
 
        /// 
        ///     The mask applied to this control.  The setter resets the underlying MaskedTextProvider object and attempts
        ///     to add the existing input text (if any) using the new mask, failure is ignored.
        ///  
        [
        SRCategory(SR.CatBehavior), 
        SRDescription(SR.MaskedTextBoxMaskDescr), 
        RefreshProperties(RefreshProperties.Repaint),
        DefaultValue(""), 
        MergableProperty(false),
        Localizable(true),
        Editor("System.Windows.Forms.Design.MaskPropertyEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor))
        ] 
        public string Mask
        { 
            get 
            {
                return this.flagState[IS_NULL_MASK]? string.Empty : this.maskedTextProvider.Mask; 
            }
            set
            {
                // 
                // We dont' do anything if:
                // 1.  IsNullOrEmpty( value )->[Reset control] && this.flagState[IS_NULL_MASK]==>Already Reset. 
                // 2. !IsNullOrEmpty( value )->[Set control] && !this.flagState[IS_NULL_MASK][control is set] && [value is the same]==>No need to update. 
                //
                if( this.flagState[IS_NULL_MASK] == string.IsNullOrEmpty( value ) && (this.flagState[IS_NULL_MASK] || value == this.maskedTextProvider.Mask) ) 
                {
                    return;
                }
 
                string text    = null;
                string newMask = value; 
 
                // We need to update the this.flagState[IS_NULL_MASK]field before raising any events (when setting the maskedTextProvider) so
                // querying for properties from an event handler returns the right value (i.e: Text). 

                if( string.IsNullOrEmpty( value ) ) // Resetting the control, the native edit control will be in charge.
                {
                    // Need to get the formatted & unformatted text before resetting the mask, they'll be used to determine whether we need to 
                    // raise the TextChanged event.
                    string formattedText   = TextOutput; 
                    string unformattedText = this.maskedTextProvider.ToString(false, false); 

                    this.flagState[IS_NULL_MASK] = true; 

                    if( this.maskedTextProvider.IsPassword )
                    {
                        SetEditControlPasswordChar(this.maskedTextProvider.PasswordChar); 
                    }
 
                    // Set the window text to the unformatted text before raising events. Also, TextChanged needs to be raised after MaskChanged so 
                    // pass false to SetWindowText 'raiseTextChanged' param.
                    SetWindowText(unformattedText, false, false ); 

                    EventArgs e = EventArgs.Empty;

                    OnMaskChanged(e); 

                    if( unformattedText != formattedText ) 
                    { 
                        OnTextChanged(e);
                    } 

                    newMask = nullMask;
                }
                else    // Setting control to a new value. 
                {
                    foreach( char c in value ) 
                    { 
                        if( !MaskedTextProvider.IsValidMaskChar( c ) )
                        { 
                            // Same message as in SR.MaskedTextProviderMaskInvalidChar in System.txt
                            throw new ArgumentException( SR.GetString( SR.MaskedTextBoxMaskInvalidChar) );
                        }
                    } 

                    if( this.flagState[IS_NULL_MASK] ) 
                    { 
                        // If this.IsNullMask, we are setting the mask to a new value; in this case we need to get the text because
                        // the underlying MTP does not have it (used as a property backend only) and pass it to SetMaskedTextProvider 
                        // method below to update the provider.

                        text = this.Text;
                    } 
                }
 
                // Recreate masked text provider since this property is read-only. 
                MaskedTextProvider newProvider = new MaskedTextProvider(
                    newMask, 
                    this.maskedTextProvider.Culture,
                    this.maskedTextProvider.AllowPromptAsInput,
                    this.maskedTextProvider.PromptChar,
                    this.maskedTextProvider.PasswordChar, 
                    this.maskedTextProvider.AsciiOnly );
 
                //text == null when setting to a different mask value or when resetting the mask to null. 
                //text != null only when setting the mask from null to some value.
                SetMaskedTextProvider( newProvider, text ); 
            }
        }

        ///  
        ///   Event to notify when the mask has changed.
        ///  
        [ 
        SRCategory(SR.CatPropertyChanged),
        SRDescription(SR.MaskedTextBoxMaskChangedDescr) 
        ]
        public event EventHandler MaskChanged
        {
            add 
            {
                Events.AddHandler(EVENT_MASKCHANGED, value); 
            } 
            remove
            { 
                Events.RemoveHandler(EVENT_MASKCHANGED, value);
            }
        }
 
        /// 
        ///     Specifies whether the test string required input positions, as specified by the mask, have 
        ///     all been assigned. 
        /// 
        [ 
        Browsable(false)
        ]
        public bool MaskCompleted
        { 
            get
            { 
                return this.maskedTextProvider.MaskCompleted; 
            }
        } 

        /// 
        ///     Specifies whether all inputs (required and optional) have been provided into the mask successfully.
        ///  
        [
        Browsable(false) 
        ] 
        public bool MaskFull
        { 
            get
            {
                return this.maskedTextProvider.MaskFull;
            } 
        }
 
        ///  
        ///     Returns a copy of the control's internal MaskedTextProvider.  This is useful for user's to provide
        ///     cloning semantics for the control (we don't want to do it) w/o incurring in any perf penalty since 
        ///     some of the properties require recreating the underlying provider when they are changed.
        /// 
        [
        Browsable(false), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ] 
        public MaskedTextProvider MaskedTextProvider 
        {
            get 
            {
                return this.flagState[IS_NULL_MASK] ? null : (MaskedTextProvider) this.maskedTextProvider.Clone();
            }
        } 

        ///  
        ///     Event to notify when an input has been rejected according to the mask. 
        /// 
        [ 
        SRCategory(SR.CatBehavior),
        SRDescription(SR.MaskedTextBoxMaskInputRejectedDescr)
        ]
        public event MaskInputRejectedEventHandler MaskInputRejected 
        {
            add 
            { 
                Events.AddHandler(EVENT_MASKINPUTREJECTED, value);
            } 
            remove
            {
                Events.RemoveHandler(EVENT_MASKINPUTREJECTED, value);
            } 
        }
 
        ///  
        ///     Unsupported method/property.
        ///     WndProc ignores EM_LIMITTEXT & this is a virtual method. 
        /// 
        [
        Browsable(false),
        EditorBrowsable(EditorBrowsableState.Never), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ] 
        public override int MaxLength 
        {
            get{ return base.MaxLength; } 
            set{}
        }

        ///  
        ///     Unsupported method/property.
        ///     virtual method. 
        ///  
        [
        Browsable(false), 
        EditorBrowsable(EditorBrowsableState.Never),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        public override bool Multiline 
        {
            get { return false; } 
            set {} 
        }
 
        /// 
        ///     Unsupported method/property.
        /// 
        [ 
        Browsable(false),
        EditorBrowsable(EditorBrowsableState.Never), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) 
        ]
        public new event EventHandler MultilineChanged 
        {
            add { }
            remove { }
        } 

        ///  
        ///     Specifies the character to be used in the formatted string in place of editable characters, if 
        ///     set to any printable character, the text box becomes a password text box, to reset it use the null
        ///     character. 
        /// 
        [
        SRCategory(SR.CatBehavior),
        SRDescription(SR.MaskedTextBoxPasswordCharDescr), 
        RefreshProperties(RefreshProperties.Repaint),
        DefaultValue('\0') // This property is shadowed by MaskedTextBoxDesigner. 
        ] 
        public char PasswordChar
        { 
            get
            {
                // The password char could be the one set in the control or the system password char,
                // in any case the maskedTextProvider has the correct one. 
                return this.maskedTextProvider.PasswordChar;
            } 
            set 
            {
                if( !MaskedTextProvider.IsValidPasswordChar(value) ) // null character accepted (resets value) 
                {
                    // Same message as in SR.MaskedTextProviderInvalidCharError.
                    throw new ArgumentException(SR.GetString(SR.MaskedTextBoxInvalidCharError) );
                } 

                if( this.passwordChar != value ) 
                { 
                    if( value == this.maskedTextProvider.PromptChar )
                    { 
                        // Prompt and password chars must be different.
                        throw new InvalidOperationException( SR.GetString(SR.MaskedTextBoxPasswordAndPromptCharError) );
                    }
 
                    this.passwordChar = value;
 
                    // UseSystemPasswordChar take precedence over PasswordChar...Let's check. 
                    if (!this.UseSystemPasswordChar)
                    { 
                        this.maskedTextProvider.PasswordChar = value;

                        if( this.flagState[IS_NULL_MASK])
                        { 
                            SetEditControlPasswordChar(value);
                        } 
                        else 
                        {
                            SetWindowText(); 
                        }

                        VerifyImeRestrictedModeChanged();
                    } 
                }
            } 
        } 

        ///  
        ///     Determines if the control is in password protect mode.
        /// 
        internal override bool PasswordProtect
        { 
            get
            { 
                if( this.maskedTextProvider != null ) // could be queried during object construction. 
                {
                     return this.maskedTextProvider.IsPassword; 
                }
                return base.PasswordProtect;
            }
        } 

        ///  
        ///     Specifies the prompt character to be used in the formatted string for unsupplied characters. 
        /// 
        [ 
        SRCategory(SR.CatAppearance),
        SRDescription(SR.MaskedTextBoxPromptCharDescr),
        RefreshProperties(RefreshProperties.Repaint),
        Localizable(true), 
        DefaultValue('_')
        ] 
        public char PromptChar 
        {
            get 
            {
                return this.maskedTextProvider.PromptChar;
            }
            set 
            {
                if( !MaskedTextProvider.IsValidInputChar(value) ) 
                { 
                    // This message is the same as the one in SR.MaskedTextProviderInvalidCharError.
                    throw new ArgumentException(SR.GetString(SR.MaskedTextBoxInvalidCharError) ); 
                }

                if( this.maskedTextProvider.PromptChar != value )
                { 
                    // We need to check maskedTextProvider password char in case it is using the system password.
                    if( value == this.passwordChar || value == this.maskedTextProvider.PasswordChar ) 
                    { 
                        // Prompt and password chars must be different.
                        throw new InvalidOperationException( SR.GetString(SR.MaskedTextBoxPasswordAndPromptCharError) ); 
                    }

                    // Recreate masked text provider to be consistent with AllowPromptAsInput - current text may have chars with same value as new prompt.
                    MaskedTextProvider newProvider = new MaskedTextProvider( 
                        this.maskedTextProvider.Mask,
                        this.maskedTextProvider.Culture, 
                        this.maskedTextProvider.AllowPromptAsInput, 
                        value,
                        this.maskedTextProvider.PasswordChar, 
                        this.maskedTextProvider.AsciiOnly );

                    SetMaskedTextProvider( newProvider );
                } 
            }
        } 
 
        /// 
        ///     Overwrite base class' property. 
        /// 
        public new bool ReadOnly
        {
            get 
            {
                return base.ReadOnly; 
            } 

            set 
            {
                if (this.ReadOnly != value)
                {
                    // if true, this disables IME in the base class. 
                    base.ReadOnly = value;
 
                    if (!this.flagState[IS_NULL_MASK]) 
                    {
                        // Prompt will be hidden. 
                        SetWindowText();
                    }
                }
            } 
        }
 
        ///  
        ///     Specifies whether to include the mask prompt character when formatting the text in places
        ///     where an edit char has not being assigned. 
        /// 
        [
        SRCategory(SR.CatBehavior),
        SRDescription(SR.MaskedTextBoxRejectInputOnFirstFailureDescr), 
        DefaultValue(false)
        ] 
        public bool RejectInputOnFirstFailure 
        {
            get 
            {
                return this.flagState[REJECT_INPUT_ON_FIRST_FAILURE];
            }
            set 
            {
                this.flagState[REJECT_INPUT_ON_FIRST_FAILURE] = value; 
            } 
        }
 
        /// 
        ///     Designe time support for resetting the Culture property.
        /// 
        /* No longer needed since Culture has been removed from the property browser - Left here for documentation. 
        [EditorBrowsable(EditorBrowsableState.Never)]
        private void ResetCulture() 
        { 
            this.Culture = CultureInfo.CurrentCulture;
        }*/ 


        /// 
        ///     Specifies whether to reset and skip the current position if editable, when the input character 
        ///     has the same value as the prompt.  This property takes precedence over AllowPromptAsInput.
        ///  
        [ 
        SRCategory(SR.CatBehavior),
        SRDescription(SR.MaskedTextBoxResetOnPrompt), 
        DefaultValue(true)
        ]
        public bool ResetOnPrompt
        { 
            get
            { 
                return this.maskedTextProvider.ResetOnPrompt; 
            }
            set 
            {
                this.maskedTextProvider.ResetOnPrompt = value;
            }
        } 

        ///  
        ///     Specifies whether to reset and skip the current position if editable, when the input 
        ///     is the space character.
        ///  
        [
        SRCategory(SR.CatBehavior),
        SRDescription(SR.MaskedTextBoxResetOnSpace),
        DefaultValue(true) 
        ]
        public bool ResetOnSpace 
        { 
            get
            { 
                return this.maskedTextProvider.ResetOnSpace;
            }
            set
            { 
                this.maskedTextProvider.ResetOnSpace = value;
            } 
        } 

        ///  
        ///     Specifies whether to skip the current position if non-editable and the input character has
        ///     the same value as the literal at that position.
        /// 
        [ 
        SRCategory(SR.CatBehavior),
        SRDescription(SR.MaskedTextBoxSkipLiterals), 
        DefaultValue(true) 
        ]
        public bool SkipLiterals 
        {
            get
            {
                return this.maskedTextProvider.SkipLiterals; 
            }
            set 
            { 
                this.maskedTextProvider.SkipLiterals = value;
            } 
        }

        /// 
        ///       The currently selected text (if any) in the control. 
        /// 
        public override string SelectedText 
        { 
            get
            { 
                if( this.flagState[IS_NULL_MASK])
                {
                    return base.SelectedText;
                } 

                return GetSelectedText(); 
            } 
            set
            { 
                SetSelectedTextInternal(value, true);
            }
        }
 
        internal override void SetSelectedTextInternal(string value, bool clearUndo)
        { 
            if (this.flagState[IS_NULL_MASK]) 
            {
                base.SetSelectedTextInternal(value, true); // Operates as a regular text box base. 
                return;
            }

            PasteInt( value ); 
        }
 
        ///  
        ///     Set the composition string as the result string.
        ///  
        private void ImeComplete()
        {
            this.flagState[IME_COMPLETING] = true;
            ImeNotify(NativeMethods.CPS_COMPLETE); 
        }
 
        ///  
        ///     Notifies the IMM about changes to the status of the IME input context.
        ///  
        private void ImeNotify(int action)
        {
            HandleRef handle    = new HandleRef(this, this.Handle);
            IntPtr inputContext = UnsafeNativeMethods.ImmGetContext(handle); 

            if (inputContext != IntPtr.Zero) 
            { 
                try
                { 
                    UnsafeNativeMethods.ImmNotifyIME(new HandleRef(null, inputContext), NativeMethods.NI_COMPOSITIONSTR, action, 0);
                }
                finally
                { 
                    UnsafeNativeMethods.ImmReleaseContext(handle, new HandleRef(null, inputContext));
                } 
            } 
            else
            { 
                Debug.Fail("Could not get IME input context.");
            }
        }
 
        /// 
        ///     Sets the underlying edit control's password char to the one obtained from this.PasswordChar. 
        ///     This is used when the control is passworded and this.flagState[IS_NULL_MASK]. 
        /// 
        private void SetEditControlPasswordChar( char pwdChar ) 
        {
            if (this.IsHandleCreated)
            {
                // This message does not return a value. 
                SendMessage(NativeMethods.EM_SETPASSWORDCHAR, pwdChar, 0);
                Invalidate(); 
            } 
        }
 
        /// 
        ///     The value of the Edit control default password char.
        /// 
        private char SystemPasswordChar 
        {
            get 
            { 
                if (MaskedTextBox.systemPwdChar == '\0')
                { 
                    // This is the hard way to get the password char - left here for information.
                    // It is picked up from Comctl32.dll. If VisualStyles is enabled it will get the dot char.
                    /*
                    StringBuilder charVal = new StringBuilder(20);  // it could be 0x0000000000009999 format. 
                    bool foundRsc         = false;
                    int IDS_PASSWORDCHAR  = 0x1076; // %ntsdx%\shell\comctrl32\v6\rcids.h 
                                                    // defined in en.rc as: IDS_PASSWORDCHAR "9679" // 0x25cf - Black Circle 

                    IntSecurity.UnmanagedCode.Assert(); 

                    try
                    {
                        // The GetModuleHandle function returns a handle to a mapped module without incrementing its reference count. 
                        // @"C:\windows\winsxs\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.10.0_x-ww_f7fb5805\comctl32.dll if VisulaStyles enabled.
 
                        IntPtr hModule = UnsafeNativeMethods.GetModuleHandle("comctl32.dll"); 
                        Debug.Assert(hModule != IntPtr.Zero, String.Format("Could not get a handle to comctl32.dll - Error: 0x{0:X8}", Marshal.GetLastWin32Error()));
 
                        foundRsc = UnsafeNativeMethods.LoadString(new HandleRef(null, hModule), IDS_PASSWORDCHAR, charVal, charVal.Capacity);
                    }
                    catch( Exception ex )
                    { 
                        if( ClientUtils.IsSecurityOrCriticalException( ex ) )
                        { 
                            throw; 
                        }
                    } 
                    finally
                    {
                        CodeAccessPermission.RevertAssert();
                    } 

                    MaskedTextBox.systemPwdChar = foundRsc ? (char) int.Parse(charVal.ToString()) : MaskedTextProvider.DefaultPasswordChar; 
                    */ 

                    // We need to temporarily create an edit control to get the default password character. 
                    // We cannot use this control because we would have to reset the native control's password char to use
                    // the defult one so we can get it; this would change the text displayed in the box (even for a short time)
                    // opening a sec hole.
 
                    TextBox txtBox = new TextBox();
                    txtBox.UseSystemPasswordChar = true; // this forces the creation of the control handle. 
 
                    MaskedTextBox.systemPwdChar = txtBox.PasswordChar;
 
                    txtBox.Dispose();
                }

                return MaskedTextBox.systemPwdChar; 
            }
        } 
 
        /// 
        ///     The Text setter validates the input char by char, raising the MaskInputRejected event for invalid chars. 
        ///     The Text getter returns the formatted text according to the IncludeLiterals and IncludePrompt properties.
        /// 
        [
        Editor("System.Windows.Forms.Design.MaskedTextBoxTextEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)), 
        SRCategory(SR.CatAppearance),
        RefreshProperties(RefreshProperties.Repaint), 
        Bindable(true), 
        DefaultValue(""), // This property is shadowed by MaskedTextBoxDesigner.
        Localizable(true) 
        ]
        public override string Text
        {
            get 
            {
                if( this.flagState[IS_NULL_MASK] || this.flagState[QUERY_BASE_TEXT]) 
                { 
                    return base.Text;
                } 

                return TextOutput;
            }
            set 
            {
                if (this.flagState[IS_NULL_MASK]) 
                { 
                    base.Text = value;
                    return; 
                }

                if (string.IsNullOrEmpty(value))
                { 
                    // reset the input text.
                    Delete(Keys.Delete, 0, this.maskedTextProvider.Length); 
                } 
                else
                { 
                    if( this.RejectInputOnFirstFailure )
                    {
                        MaskedTextResultHint hint;
                        string oldText = TextOutput; 
                        if (this.maskedTextProvider.Set(value, out this.caretTestPos, out hint))
                        { 
                            //if( hint == MaskedTextResultHint.Success || hint == MaskedTextResultHint.SideEffect ) 
                            if( TextOutput != oldText )
                            { 
                                SetText();
                            }
                            this.SelectionStart = ++this.caretTestPos;
                        } 
                        else
                        { 
                            OnMaskInputRejected(new MaskInputRejectedEventArgs(this.caretTestPos, hint)); 
                        }
                    } 
                    else
                    {
                        Replace(value, /*startPosition*/ 0, /*selectionLen*/ this.maskedTextProvider.Length);
                    } 
                }
            } 
        } 

        ///  
        ///     Returns the length of the displayed text.  See VSW#502543.
        /// 
        [Browsable( false )]
        public override int TextLength 
        {
            get 
            { 
                if( this.flagState[IS_NULL_MASK] )
                { 
                    return base.TextLength;
                }

                // In Win9x systems TextBoxBase.TextLength calls Text.Length directly and does not query the window for the actual text length. 
                // If TextMaskFormat is set to a anything different from IncludePromptAndLiterals or HidePromptOnLeave is true the return value
                // may be incorrect because the Text property value and the display text may be different.  We need to handle this here. 
 
                return GetFormattedDisplayString().Length;
            } 
        }

        /// 
        ///     The formatted text, it is what the Text getter returns when a mask has been applied to the control. 
        ///     The text format follows the IncludeLiterals and IncludePrompt properties (See MaskedTextProvider.ToString()).
        ///  
        private string TextOutput 
        {
            get 
            {
                Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." );
                return this.maskedTextProvider.ToString();
            } 
        }
 
        ///  
        ///     Gets or sets how text is aligned in the control.
        ///     Note: This code is duplicated in TextBox for simplicity. 
        /// 
        [
        Localizable(true),
        SRCategory(SR.CatAppearance), 
        DefaultValue(HorizontalAlignment.Left),
        SRDescription(SR.TextBoxTextAlignDescr) 
        ] 
        public HorizontalAlignment TextAlign
        { 
            get
            {
                return textAlign;
            } 
            set
            { 
                if (textAlign != value) 
                {
                    //verify that 'value' is a valid enum type... 
                    //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)); 
                    }
 
                    textAlign = value; 
                    RecreateHandle();
                    OnTextAlignChanged(EventArgs.Empty); 
                }
            }
        }
 
        /// 
        ///     Event to notify the text alignment has changed. 
        ///  
        [
        SRCategory(SR.CatPropertyChanged), 
        SRDescription(SR.RadioButtonOnTextAlignChangedDescr)
        ]
        public event EventHandler TextAlignChanged
        { 
            add
            { 
                Events.AddHandler(EVENT_TEXTALIGNCHANGED, value); 
            }
 
            remove
            {
                Events.RemoveHandler(EVENT_TEXTALIGNCHANGED, value);
            } 
        }
 
        ///  
        ///    Specifies the formatting options for text output (Whether the mask returned from the Text
        ///    property includes Literals and/or prompt characters). 
        ///    When prompt characters are excluded, theyare returned as spaces in the string returned.
        /// 
        [
        SRCategory(SR.CatBehavior), 
        SRDescription(SR.MaskedTextBoxTextMaskFormat),
        RefreshProperties(RefreshProperties.Repaint), 
        DefaultValue(MaskFormat.IncludeLiterals) 
        ]
        public MaskFormat TextMaskFormat 
        {
            get
            {
                if( this.IncludePrompt ) 
                {
                    if( this.IncludeLiterals ) 
                    { 
                        return MaskFormat.IncludePromptAndLiterals;
                    } 

                    return MaskFormat.IncludePrompt;
                }
 
                if( this.IncludeLiterals )
                { 
                    return MaskFormat.IncludeLiterals; 
                }
 
                return MaskFormat.ExcludePromptAndLiterals;
            }

            set 
            {
                if( this.TextMaskFormat == value ) 
                { 
                    return;
                } 

                //valid values are 0x0 to 0x3
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)MaskFormat.ExcludePromptAndLiterals, (int)MaskFormat.IncludePromptAndLiterals))
                { 
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(MaskFormat));
                } 
 
                // Changing the TextMaskFormat will likely change the 'output' text (Text getter value).  Cache old value to
                // verify it against the new value and raise OnTextChange if needed. 
                string oldText = this.flagState[IS_NULL_MASK] ? null : TextOutput;

                if( value == MaskFormat.IncludePrompt )
                { 
                    this.IncludePrompt   = true;
                    this.IncludeLiterals = false; 
                } 
                else if( value == MaskFormat.IncludeLiterals )
                { 
                    this.IncludePrompt   = false;
                    this.IncludeLiterals = true;
                }
                else // value == MaskFormat.IncludePromptAndLiterals || value == MaskFormat.ExcludePromptAndLiterals 
                {
                    bool include = value == MaskFormat.IncludePromptAndLiterals; 
                    this.IncludePrompt   = include; 
                    this.IncludeLiterals = include;
                } 

                if( oldText != null && oldText != TextOutput )
                {
                    OnTextChanged(EventArgs.Empty); 
                }
            } 
        } 

        ///  
        ///    Provides some interesting information for the TextBox control in String form.
        ///    Returns the test string (no password, including literals and prompt).
        /// 
        public override string ToString() 
        {
            if( this.flagState[IS_NULL_MASK] ) 
            { 
                return base.ToString();
            } 

            // base.ToString will call Text, we want to always display prompt and literals.
            bool includePrompt = this.IncludePrompt;
            bool includeLits   = this.IncludeLiterals; 
            string str;
            try 
            { 
                this.IncludePrompt = this.IncludeLiterals = true;
                str = base.ToString(); 
            }
            finally
            {
                this.IncludePrompt = includePrompt; 
                this.IncludeLiterals = includeLits;
            } 
 
            return str;
        } 

        /// 
        ///     Event to notify when the validating object completes parsing the formatted text.
        ///  
        [
        SRCategory(SR.CatFocus), 
        SRDescription(SR.MaskedTextBoxTypeValidationCompletedDescr) 
        ]
        public event TypeValidationEventHandler TypeValidationCompleted 
        {
            add
            {
                Events.AddHandler(EVENT_VALIDATIONCOMPLETED, value); 
            }
            remove 
            { 
                Events.RemoveHandler(EVENT_VALIDATIONCOMPLETED, value);
            } 
        }

        /// 
        ///    Indicates if the text in the edit control should appear as the default password character. 
        ///    This property has precedence over the PasswordChar property.
        ///  
        [ 
        SRCategory(SR.CatBehavior),
        SRDescription(SR.MaskedTextBoxUseSystemPasswordCharDescr), 
        RefreshProperties(RefreshProperties.Repaint),
        DefaultValue(false)
        ]
        public bool UseSystemPasswordChar 
        {
            get 
            { 
                return this.flagState[USE_SYSTEM_PASSWORD_CHAR];
            } 
            set
            {
                if (value != this.flagState[USE_SYSTEM_PASSWORD_CHAR])
                { 
                    if (value)
                    { 
                        if( this.SystemPasswordChar == this.PromptChar ) 
                        {
                            // Prompt and password chars must be different. 
                            throw new InvalidOperationException( SR.GetString(SR.MaskedTextBoxPasswordAndPromptCharError) );
                        }

                        this.maskedTextProvider.PasswordChar = this.SystemPasswordChar; 
                    }
                    else 
                    { 
                        // this.passwordChar could be '\0', in which case we are resetting the display to show the input char.
                        this.maskedTextProvider.PasswordChar = this.passwordChar; 
                    }

                    this.flagState[USE_SYSTEM_PASSWORD_CHAR] = value;
 
                    if( this.flagState[IS_NULL_MASK])
                    { 
                        SetEditControlPasswordChar(this.maskedTextProvider.PasswordChar); 
                    }
                    else 
                    {
                        SetWindowText();
                    }
 
                    VerifyImeRestrictedModeChanged();
                } 
            } 
        }
 
        /// 
        ///     Type of the object to be used to parse the text when the user leaves the control.
        ///     A ValidatingType object must implement a method with one fo the following signature:
        ///         public static Object Parse(string) 
        ///         public static Object Parse(string, IFormatProvider)
        ///     See DateTime.Parse(...) for an example. 
        ///  
        [
        Browsable(false), 
        DefaultValue(null)
        ]
        public Type ValidatingType
        { 
            get
            { 
                return this.validatingType; 
            }
            set 
            {
                if( this.validatingType != value )
                {
                    this.validatingType = value; 
                }
            } 
        } 

        ///  
        ///     Unsupported method/property.
        /// 
        [
        Browsable(false), 
        EditorBrowsable(EditorBrowsableState.Never),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) 
        ] 
        public new bool WordWrap
        { 
            get { return false; }
            set {}
        }
 

        ////////////// Methods 
 
        /// 
        ///     Clears information about the most recent operation from the undo buffer of the control. 
        ///     Unsupported property/method.
        /// 
        [
        EditorBrowsable(EditorBrowsableState.Never) 
        ]
        public new void ClearUndo() 
        { 
        }
 
        /// 
        ///     Creates a handle for this control. This method is called by the .NET Framework, this should
        ///     not be called. Inheriting classes should always call base.createHandle when overriding this method.
        ///     Overridden to be able to set the control text with the masked (passworded) value when recreating 
        ///     handle, since the underlying native edit control is not aware of it.
        ///  
        [ 
        EditorBrowsable(EditorBrowsableState.Advanced),
        UIPermission(SecurityAction.InheritanceDemand, Window = UIPermissionWindow.AllWindows) 
        ]
        protected override void CreateHandle()
        {
            if (!this.flagState[IS_NULL_MASK] && RecreatingHandle) 
            {
                // update cached text value in Control. Don't preserve caret, cannot query for selection start at this time. 
                SetWindowText(GetFormattedDisplayString(), false, false); 
            }
 
            base.CreateHandle();
        }

        /// 
        /// 
        ///     Deletes characters from the control's text according to the key pressed (Delete/Backspace). 
        ///     Returns true if something gets actually deleted, false otherwise. 
        /// 
        private void Delete(Keys keyCode, int startPosition, int selectionLen) 
        {
            Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." );
            Debug.Assert( keyCode == Keys.Delete || keyCode == Keys.Back, "Delete called with keyCode == " + keyCode.ToString() );
            Debug.Assert( startPosition >= 0 && ((startPosition + selectionLen) <= this.maskedTextProvider.Length), "Invalid position range." ); 

            // On backspace, moving the start postion back by one has the same effect as delete.  If text is selected, there is no 
            // need for moving the position back. 

            this.caretTestPos = startPosition; 

            if( selectionLen == 0 )
            {
                if( keyCode == Keys.Back ) 
                {
                    if( startPosition == 0 ) // At beginning of string, backspace does nothing. 
                    { 
                        return;
                    } 

                    startPosition--; // so it can be treated as delete.
                }
                else // (keyCode == Keys.Delete) 
                {
                    if( (startPosition + selectionLen) == this.maskedTextProvider.Length ) // At end of string, delete does nothing. 
                    { 
                        return;
                    } 
                }
            }

            int tempPos; 
            int endPos = selectionLen > 0 ? startPosition + selectionLen - 1 : startPosition;
            MaskedTextResultHint hint; 
 
            string oldText = TextOutput;
            if (this.maskedTextProvider.RemoveAt(startPosition, endPos, out tempPos, out hint)) 
            {
                //if( hint == MaskedTextResultHint.Success || hint == MaskedTextResultHint.SideEffect) // Text was changed.
                if( TextOutput != oldText )
                { 
                    SetText();
                    this.caretTestPos = startPosition; 
                } 
                else
                { 
                    // If succeeded but nothing removed, the caret should move as follows:
                    // 1. If selectionLen > 0, or on back and hint == SideEffect: move to selectionStart.
                    // 2. If hint == NoEffect, On Delete move to next edit position, if any or not already in one.
                    //    On back move to the next edit postion at the left if no more assigned position at the right, 
                    //    in such case find an assigned position and move one past or one position left if no assigned pos found
                    //    (taken care by 'startPosition--' above). 
                    // 3. If hint == SideEffect, on Back move like arrow key, (startPosition is already moved, startPosition-- above). 

                    if( selectionLen > 0 ) 
                    {
                        this.caretTestPos = startPosition;
                    }
                    else 
                    {
                        if( hint == MaskedTextResultHint.NoEffect ) // Case 2. 
                        { 
                            if( keyCode == Keys.Delete )
                            { 
                                this.caretTestPos = this.maskedTextProvider.FindEditPositionFrom(startPosition, forward);
                            }
                            else
                            { 
                                if( this.maskedTextProvider.FindAssignedEditPositionFrom( startPosition, forward ) == MaskedTextProvider.InvalidIndex )
                                { 
                                    // No assigned position at the right, nothing to shift then move to the next assigned position at the 
                                    // left (if any).
                                    this.caretTestPos = this.maskedTextProvider.FindAssignedEditPositionFrom(startPosition, backward); 
                                }
                                else
                                {
                                    // there are assigned positions at the right so move to an edit position at the left to get ready for 
                                    // removing the character on it or just shifting the characters at the right
                                    this.caretTestPos = this.maskedTextProvider.FindEditPositionFrom(startPosition, backward); 
                                } 

                                if( this.caretTestPos != MaskedTextProvider.InvalidIndex ) 
                                {
                                    this.caretTestPos++; // backspace gets ready to remove one position past the edit position.
                                }
                            } 

                            if( this.caretTestPos == MaskedTextProvider.InvalidIndex ) 
                            { 
                                this.caretTestPos = startPosition;
                            } 
                        }
                        else // (hint == MaskedTextProvider.OperationHint.SideEffect)
                        {
                            if( keyCode == Keys.Back )  // Case 3. 
                            {
                                this.caretTestPos = startPosition; 
                            } 
                        }
                    } 
                }
            }
            else
            { 
                OnMaskInputRejected(new MaskInputRejectedEventArgs(tempPos, hint));
            } 
 
            // Reposition caret.  Call base.SelectInternal for perf reasons.
            //this.SelectionLength = 0; 
            //this.SelectionStart  = this.caretTestPos; // new caret position.
            base.SelectInternal( this.caretTestPos, 0, this.maskedTextProvider.Length );

            return; 
        }
 
        ///  
        ///     Returns the character nearest to the given point.
        ///  
        public override char GetCharFromPosition(Point pt)
        {
            char ch;
 
            this.flagState[QUERY_BASE_TEXT] = true;
            try 
            { 
                ch = base.GetCharFromPosition(pt);
            } 
            finally
            {
                this.flagState[QUERY_BASE_TEXT] = false;
            } 
            return ch;
        } 
 

        ///  
        ///     Returns the index of the character nearest to the given point.
        /// 
        public override int GetCharIndexFromPosition(Point pt)
        { 
            int index;
 
            this.flagState[QUERY_BASE_TEXT] = true; 
            try
            { 
                index = base.GetCharIndexFromPosition(pt);
            }
            finally
            { 
                this.flagState[QUERY_BASE_TEXT] = false;
            } 
            return index; 
        }
 
        /// 
        ///     Returns the position of the last input character (or if available, the next edit position).
        ///     This is used by base.AppendText.
        ///  
        internal override int GetEndPosition()
        { 
            if( this.flagState[IS_NULL_MASK]) 
            {
                return base.GetEndPosition(); 
            }

            int pos = this.maskedTextProvider.FindEditPositionFrom( this.maskedTextProvider.LastAssignedPosition + 1, forward );
 
            if( pos == MaskedTextProvider.InvalidIndex )
            { 
                pos = this.maskedTextProvider.LastAssignedPosition + 1; 
            }
 
            return pos;
        }

        ///  
        ///     Unsupported method/property.
        ///  
        [ 
        EditorBrowsable(EditorBrowsableState.Never)
        ] 
        public new int GetFirstCharIndexOfCurrentLine()
        {
            return 0;
        } 

        ///  
        ///     Unsupported method/property. 
        /// 
        [ 
        EditorBrowsable(EditorBrowsableState.Never)
        ]
        public new int GetFirstCharIndexFromLine(int lineNumber)
        { 
            return 0;
        } 
 
        /// 
        ///     Gets the string in the text box following the formatting parameters includePrompt and includeLiterals and 
        ///     honoring the PasswordChar property.
        /// 
        private string GetFormattedDisplayString()
        { 
            Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." );
 
            bool includePrompt; 

            if (this.ReadOnly) // Always hide prompt. 
            {
                includePrompt = false;
            }
            else if (this.DesignMode) // Not RO and at design time, always show prompt. 
            {
                includePrompt = true; 
            } 
            else // follow HidePromptOnLeave property.
            { 
                includePrompt = !(this.HidePromptOnLeave && !this.Focused);
            }

            return this.maskedTextProvider.ToString(/*ignorePwdChar */ false, includePrompt, /*includeLiterals*/ true, 0, this.maskedTextProvider.Length); 
        }
 
        ///  
        ///     Unsupported method/property.
        ///     virtual method. 
        /// 
        [
        EditorBrowsable(EditorBrowsableState.Never)
        ] 
        public override int GetLineFromCharIndex(int index)
        { 
            return 0; 
        }
 
        /// 
        ///     Returns the location of the character at the given index.
        /// 
        public override Point GetPositionFromCharIndex(int index) 
        {
            Point pos; 
 
            this.flagState[QUERY_BASE_TEXT] = true;
            try 
            {
                pos = base.GetPositionFromCharIndex(index);
            }
            finally 
            {
                this.flagState[QUERY_BASE_TEXT] = false; 
            } 
            return pos;
        } 

        /// 
        ///     Need to override this method so when get_Text is called we return the text that is actually
        ///     painted in the control so measuring text works on the actual text and not the formatted one. 
        /// 
        internal override Size GetPreferredSizeCore(Size proposedConstraints) 
        { 
            Size size;
 
            this.flagState[QUERY_BASE_TEXT] = true;
            try
            {
                size = base.GetPreferredSizeCore( proposedConstraints ); 
            }
            finally 
            { 
                this.flagState[QUERY_BASE_TEXT] = false;
            } 
            return size;
        }

        ///  
        ///     The selected text in the control according to the CutCopyMaskFormat properties (IncludePrompt/IncludeLiterals).
        ///     This is used in Cut/Copy operations (SelectedText). 
        ///     The prompt character is always replaced with a blank character. 
        /// 
        private string GetSelectedText() 
        {
            Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." );

            int selStart, selLength; 
            base.GetSelectionStartAndLength( out selStart, out selLength );
 
            if( selLength == 0 ) 
            {
                return string.Empty; 
            }

            bool includePrompt   = (CutCopyMaskFormat & MaskFormat.IncludePrompt  ) != 0;
            bool includeLiterals = (CutCopyMaskFormat & MaskFormat.IncludeLiterals) != 0; 

            return this.maskedTextProvider.ToString( /*ignorePasswordChar*/ true, includePrompt, includeLiterals, selStart, selLength ); 
        } 

 
        /// 
        protected override void OnBackColorChanged(EventArgs e)
        {
            base.OnBackColorChanged(e); 
            // VSWhidbey 465708. Force repainting of the entire window frame
            if (Application.RenderWithVisualStyles && this.IsHandleCreated && this.BorderStyle == BorderStyle.Fixed3D) 
            { 
                SafeNativeMethods.RedrawWindow(new HandleRef(this, this.Handle), null, NativeMethods.NullHandleRef, NativeMethods.RDW_INVALIDATE | NativeMethods.RDW_FRAME);
            } 
        }

        /// 
        ///    Overridden to update the newly created handle with the settings of the PasswordChar properties 
        ///    if no mask has been set.
        ///  
        protected override void OnHandleCreated(EventArgs e) 
        {
            base.OnHandleCreated(e); 
            base.SetSelectionOnHandle();

            if( this.flagState[IS_NULL_MASK]&& this.maskedTextProvider.IsPassword )
            { 
                SetEditControlPasswordChar(this.maskedTextProvider.PasswordChar);
            } 
        } 

        ///  
        ///    Raises the IsOverwriteModeChanged event.
        /// 
        [
        EditorBrowsable(EditorBrowsableState.Advanced) 
        ]
        protected virtual void OnIsOverwriteModeChanged(EventArgs e) 
        { 
            EventHandler eh = Events[EVENT_ISOVERWRITEMODECHANGED] as EventHandler;
 
            if (eh != null)
            {
                eh(this, e);
            } 
        }
 
        ///  
        ///     Raises the  event.
        ///  
        protected override void OnKeyDown(KeyEventArgs e)
        {
            base.OnKeyDown(e);
 
            if( this.flagState[IS_NULL_MASK])
            { 
                // Operates as a regular text box base. 
                return;
            } 

            Keys keyCode = e.KeyCode;

            // Special-case Return & Esc since they generate invalid characters we should not process OnKeyPress. 
            if( keyCode == Keys.Return || keyCode == Keys.Escape )
            { 
                this.flagState[HANDLE_KEY_PRESS] = false; 
            }
 

            // Insert is toggled when not modified with some other key (ctrl, shift...).  Note that shift-Insert is
            // same as paste.
            if (keyCode == Keys.Insert && e.Modifiers == Keys.None && this.insertMode == InsertKeyMode.Default) 
            {
                this.flagState[INSERT_TOGGLED] = !this.flagState[INSERT_TOGGLED]; 
                OnIsOverwriteModeChanged(EventArgs.Empty); 
                return;
            } 

            if (e.Control && char.IsLetter((char)keyCode))
            {
                switch (keyCode) 
                {
                    // Unsupported keys should not be handled to allow generatating the corresponding message 
                    // which is handled in the WndProc. 
                    //case Keys.Z:  // ctrl-z == Undo.
                    //case Keys.Y:  // ctrl-y == Redo. 
                    //    e.Handled = true;
                    //    return;

                    // Note: Ctrl-Insert (Copy -Shortcut.CtrlIns) and Shft-Insert (Paste - Shortcut.ShiftIns) are 
                    // handled by the base class and behavior depend on ShortcutsEnabled property.
 
                    // Special cases: usually cases where the native edit control would modify the mask. 
                    case Keys.H:  // ctrl-h == Backspace == '\b'
                        keyCode = Keys.Back; // handle it below. 
                        break;

                    default:
                        // Next OnKeyPress should not be handled to allow Ctrl- to be processed in the 
                        // base class so corresponding messages can be generated (WM_CUT/WM_COPY/WM_PASTE).
                        // Combined characters don't generate OnKeyDown by themselves but they generate OnKeyPress. 
                        this.flagState[HANDLE_KEY_PRESS] = false; 
                        return;
                } 
            }

            if ( keyCode == Keys.Delete || keyCode == Keys.Back ) // Deletion keys.
            { 
                if (!this.ReadOnly)
                { 
                    int selectionLen; 
                    int startPosition;
 
                    base.GetSelectionStartAndLength( out startPosition, out selectionLen );

                    switch (e.Modifiers)
                    { 
                        case Keys.Shift:
                            if( keyCode == Keys.Delete ) 
                            { 
                                keyCode = Keys.Back;
                            } 
                            goto default;

                        case Keys.Control:
                            if( selectionLen == 0 ) // In other case, the selected text should be deleted. 
                            {
                                if( keyCode == Keys.Delete ) // delete to the end of the string. 
                                { 
                                    selectionLen = this.maskedTextProvider.Length - startPosition;
                                } 
                                else // ( keyCode == Keys.Back ) // delete to the beginning of the string.
                                {
                                    selectionLen = startPosition == this.maskedTextProvider.Length /*at end of text*/ ? startPosition : startPosition + 1;
                                    startPosition     = 0; 
                                }
                            } 
                            goto default; 

                        default: 
                            if( !this.flagState[HANDLE_KEY_PRESS] )
                            {
                                this.flagState[HANDLE_KEY_PRESS] = true;
                            } 
                            break;
                    } 
 
                    //
                    // Handle special case when using Korean IME and ending a composition. 
                    //
                    /*  This code is no longer needed after fixing bug#517013 - Left here for reference DON'T DELETE.
                    if ((ImeModeConversion.InputLanguageTable == ImeModeConversion.KoreanTable) && this.flagState[IME_ENDING_COMPOSITION])
                    { 
                        // Korean IME & Edit control weirdness in action:
                        // When pressing Del/Esc/Enter/BckSpc during a composition, the character is converted and a 
                        // corresponding WM_IME_CHAR in placed in the app queue. 

                        if(keyCode == Keys.Back && selectionLen == 0) 
                        {
                            // After the WM_IME_CHAR message is processed, a WM_CHAR message is queued for the backspace; the
                            // edit control processes the message deleting the previous character.  Since we don't pass this
                            // message to the edit control we need to do it ourselves (move position one ahead because it is 
                            // set at the composition window which is inserted in the test string.
                            startPosition++; 
 
                            // Note: If the converted character is invalid and there is a character already placed in the previous
                            // position, it will be deleted.  THIS IS BY DESIGN: It is exactly like the user performing the convertion 
                            // and then pressing backspace, there's no way to differenciate these two scenarios.
                            // See VSWhidbey#200690 for the sequence of messages generated.
                        }
                    } 
                    */
 
                    Delete(keyCode, startPosition, selectionLen); 
                    e.SuppressKeyPress = true;
                } 
            }
        }

 
        /// 
        ///     Raises the  event. 
        ///  
        protected override void OnKeyPress(KeyPressEventArgs e)
        { 
            base.OnKeyPress(e);

            if( this.flagState[IS_NULL_MASK])
            { 
                // Operates as a regular text box base.
                return; 
            } 

            // This key may be a combined key involving a letter, like Ctrl-A; let the native control handle it. 
            if( !this.flagState[HANDLE_KEY_PRESS] )
            {
                this.flagState[HANDLE_KEY_PRESS] = true;
 
                // When the combined key involves a letter, the final character is not a letter. There are some
                // Ctrl combined keys that generate a letter and can be confusing; we do not mean to pass those 
                // characters to the underlying Edit control.  These combinations are: Ctrl-F<#> and Ctrl-Atl- 
                if (!char.IsLetter(e.KeyChar))
                { 
                    return;
                }
            }
 
            if( !this.ReadOnly)
            { 
                // At this point the character needs to be processed ... 

                MaskedTextResultHint hint; 

                int selectionStart;
                int selectionLen;
 
                base.GetSelectionStartAndLength( out selectionStart, out selectionLen );
 
                string oldText = TextOutput; 
                if (PlaceChar(e.KeyChar, selectionStart, selectionLen, this.IsOverwriteMode, out hint))
                { 
                    //if( hint == MaskedTextResultHint.Success || hint == MaskedTextResultHint.SideEffect )
                    if( TextOutput != oldText )
                    {
                        SetText(); // Now set the text in the display. 
                    }
 
                    this.SelectionStart = ++this.caretTestPos; // caretTestPos is updated in PlaceChar. 

                    if (ImeModeConversion.InputLanguageTable == ImeModeConversion.KoreanTable) 
                    {
                        // Korean IMEs complete composition when a character has been fully converted, so the composition string
                        // is only one-character long; once composed we block the IME if there ins't more room in the test string.
 
                        int editPos = this.maskedTextProvider.FindUnassignedEditPositionFrom(this.caretTestPos, forward);
                        if (editPos == MaskedTextProvider.InvalidIndex) 
                        { 
                            ImeComplete();  // Force completion of compostion.
                        } 
                    }
                }
                else
                { 
                    OnMaskInputRejected(new MaskInputRejectedEventArgs(this.caretTestPos, hint)); // caretTestPos is updated in PlaceChar.
                } 
 
                if( selectionLen > 0 )
                { 
                    this.SelectionLength = 0;
                }

                e.Handled = true; 
            }
        } 
 
        /// 
        /// Raises the  event. 
        /// 
        protected override void OnKeyUp(KeyEventArgs e)
        {
            base.OnKeyUp(e); 

            // KeyUp is the last message to be processed so it is the best place to reset these flags. 
 
            if (this.flagState[IME_COMPLETING])
            { 
                this.flagState[IME_COMPLETING] = false;
            }

            if( this.flagState[IME_ENDING_COMPOSITION] ) 
            {
                this.flagState[IME_ENDING_COMPOSITION] = false; 
            } 
        }
 
        /// 
        ///    Raises the MaskChanged event.
        /// 
        [ 
        EditorBrowsable(EditorBrowsableState.Advanced)
        ] 
        protected virtual void OnMaskChanged(EventArgs e) 
        {
            EventHandler eh = Events[EVENT_MASKCHANGED] as EventHandler; 

            if (eh != null)
            {
                eh(this, e); 
            }
        } 
 
        /// 
        ///     Raises the MaskInputRejected event. 
        /// 
        private void OnMaskInputRejected(MaskInputRejectedEventArgs e)
        {
            Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." ); 

            if (this.BeepOnError) 
            { 
                System.Media.SoundPlayer sp = new System.Media.SoundPlayer();
                sp.Play(); 
            }

            MaskInputRejectedEventHandler eh = Events[EVENT_MASKINPUTREJECTED] as MaskInputRejectedEventHandler;
 
            if (eh != null)
            { 
                eh(this, e); 
            }
        } 

        /// 
        ///     Unsupported method/property.
        ///     virtual method. 
        /// 
        [ 
        EditorBrowsable(EditorBrowsableState.Never) 
        ]
        protected override void OnMultilineChanged(EventArgs e) 
        {
        }

        ///  
        ///    Raises the TextAlignChanged event.
        ///  
        protected virtual void OnTextAlignChanged(EventArgs e) 
        {
            EventHandler eh = Events[EVENT_TEXTALIGNCHANGED] as EventHandler; 
            if (eh != null)
            {
                eh(this, e);
            } 
        }
 
 
        /// 
        ///     Raises the TypeValidationCompleted event. 
        /// 
        private void OnTypeValidationCompleted(TypeValidationEventArgs e)
        {
            TypeValidationEventHandler eh = Events[EVENT_VALIDATIONCOMPLETED] as TypeValidationEventHandler; 
            if (eh != null)
            { 
                eh(this, e); 
            }
        } 

        /// 
        ///     Raises the  System.Windows.Forms.Control.Validating event.
        ///     Overridden here to be able to control the order validating events are 
        ///     raised [TypeValidationCompleted - Validating - Validated - Leave - KillFocus]
        ///  
        [EditorBrowsable(EditorBrowsableState.Advanced)] 
        protected override void OnValidating(CancelEventArgs e)
        { 
            // Note: It seems impractical to perform type validation here if the control is read only but we need
            // to be consistent with other TextBoxBase controls which don't check for RO; and we don't want
            // to fix them to avoid introducing breaking changes.
            PerformTypeValidation(e); 
            base.OnValidating(e);
        } 
 
        /// 
        ///    Raises the TextChanged event and related Input/Output text events when mask is null. 
        ///    Overriden here to be able to control order of text changed events.
        /// 
        protected override void OnTextChanged(EventArgs e)
        { 
            // A text changed event handler will most likely query for the Text value, we need to return the
            // formatted one. 
            bool queryBaseText = this.flagState[QUERY_BASE_TEXT]; 
            this.flagState[QUERY_BASE_TEXT] = false;
            try 
            {
                base.OnTextChanged(e);
            }
            finally 
            {
                this.flagState[QUERY_BASE_TEXT] = queryBaseText; 
            } 
        }
        ///  
        ///     Replaces the current selection in the text box specified by the startPosition and selectionLen parameters
        ///     with the contents of the supplied string.
        /// 
        private void Replace(string text, int startPosition, int selectionLen) 
        {
            Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." ); 
            Debug.Assert(text != null, "text is null."); 

            // Clone the MaskedTextProvider so text properties are not modified until the paste operation is 
            // completed.  This is needed in case one of these properties is retreived in a MaskedInputRejected
            // event handler (clipboard text is attempted to be set into the input text char by char).

            MaskedTextProvider clonedProvider = (MaskedTextProvider) this.maskedTextProvider.Clone(); 

            // Cache the current caret position so we restore it in case the text does not change. VSW#498875. 
            int currentCaretPos = this.caretTestPos; 

            // First replace characters in the selection (if any and if any edit positions) until completed, or the test position falls 
            // outside the selection range, or there's no more room in the test string for editable characters.
            // Then insert any remaining characters from the input.

            MaskedTextResultHint hint = MaskedTextResultHint.NoEffect; 
            int endPos = startPosition + selectionLen - 1;
 
            if( this.RejectInputOnFirstFailure ) 
            {
                bool succeeded; 

                succeeded = (startPosition > endPos) ?
                    clonedProvider.InsertAt(text, startPosition, out this.caretTestPos, out hint ) :
                    clonedProvider.Replace(text, startPosition, endPos, out this.caretTestPos, out hint); 

                if( !succeeded ) 
                { 
                    OnMaskInputRejected(new MaskInputRejectedEventArgs(this.caretTestPos, hint));
                } 
            }
            else
            {
                // temp hint used to preserve the 'primary' operation hint (no side effects). 
                MaskedTextResultHint tempHint = hint;
                int testPos; 
 
                foreach (char ch in text)
                { 
                    if( !this.maskedTextProvider.VerifyEscapeChar( ch, startPosition ))  // char won't be escaped, find and edit position for it.
                    {
                        // Observe that we look for a position w/o respecting the selection length, because the input text could be larger than
                        // the number of edit positions in the selection. 
                        testPos = clonedProvider.FindEditPositionFrom(startPosition, forward);
 
                        if( testPos == MaskedTextProvider.InvalidIndex ) 
                        {
                            // this will continue to execute (fail) until the end of the text so we fire the event for each remaining char. 
                            OnMaskInputRejected(new MaskInputRejectedEventArgs(startPosition, MaskedTextResultHint.UnavailableEditPosition));
                            continue;
                        }
 
                        startPosition = testPos;
                    } 
 
                    int length = endPos >= startPosition ? 1 : 0;
 
                    // if length > 0 we are (re)placing the input char in the current startPosition, otherwise we are inserting the input.
                    bool replace = length > 0;

                    if (PlaceChar(clonedProvider, ch, startPosition, length, replace, out tempHint)) 
                    {
                        // caretTestPos is updated in PlaceChar call. 
                        startPosition = this.caretTestPos + 1; 

                        // place char will insert or replace a single character so the hint must be success, and that will be the final operation 
                        // result hint.
                        if (tempHint == MaskedTextResultHint.Success && hint != tempHint)
                        {
                            hint = tempHint; 
                        }
                    } 
                    else 
                    {
                        OnMaskInputRejected(new MaskInputRejectedEventArgs(startPosition, tempHint)); 
                    }
                }

                if (selectionLen > 0) 
                {
                    // At this point we have processed all characters from the input text (if any) but still need to 
                    // remove remaining characters from the selected text (if editable and valid chars). 

                    if (startPosition <= endPos) 
                    {
                        if (!clonedProvider.RemoveAt(startPosition, endPos, out this.caretTestPos, out tempHint))
                        {
                            OnMaskInputRejected(new MaskInputRejectedEventArgs(this.caretTestPos, tempHint)); 
                        }
 
                        // If 'replace' is not actually performed (maybe the input is empty which means 'remove', hint will be whatever 
                        // the 'remove' operation result hint is.
                        if (hint == MaskedTextResultHint.NoEffect && hint != tempHint) 
                        {
                            hint = tempHint;
                        }
                    } 
                }
            } 
 
            bool updateText = TextOutput != clonedProvider.ToString();
 
            // Always set the mtp, the formatted text could be the same but the assigned positions may be different.
            this.maskedTextProvider = clonedProvider;

            // Update text if needed. 
            if( updateText )
            { 
                SetText(); 

                // Update caret position. 
                this.caretTestPos = startPosition;
                base.SelectInternal( this.caretTestPos, 0, this.maskedTextProvider.Length );
            }
            else 
            {
                this.caretTestPos = currentCaretPos; 
            } 

            return; 
        }

        /// 
        ///     Pastes specified text over the currently selected text (if any) shifting upper characters if 
        ///     input is longer than selected text, and/or removing remaining characters from the selection if
        ///     input contains less characters. 
        ///  
        private void PasteInt( string text )
        { 
            Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." );

            int selStart, selLength;
            base.GetSelectionStartAndLength(out selStart, out selLength); 

            if( string.IsNullOrEmpty(text) ) 
            { 
                Delete( Keys.Delete, selStart, selLength );
            } 
            else
            {
                Replace(text, selStart, selLength);
            } 
        }
 
        ///  
        ///     Performs validation of the input string using the provided ValidatingType object (if any).
        ///     Returns an object created from the formatted text. 
        ///     If the CancelEventArgs param is not null, it is assumed the control is leaving focus and
        ///     the validation event chain is being executed (TypeValidationCompleted - Validating - Validated...);
        ///     the value of the CancelEventArgs.Cancel property is the same as the TypeValidationEventArgs.Cancel
        ///     on output (Cancel provides proper handling of focus shifting at the Control class level). 
        ///     Note: The text being validated does not include prompt chars.
        ///  
        private object PerformTypeValidation(CancelEventArgs e) 
        {
            object parseRetVal = null; 

            if (this.validatingType != null)
            {
                string message = null; 

                if (!this.flagState[IS_NULL_MASK]&& this.maskedTextProvider.MaskCompleted == false) 
                { 
                    message = SR.GetString(SR.MaskedTextBoxIncompleteMsg);
                } 
                else
                {
                    string textValue;
 
                    if( !this.flagState[IS_NULL_MASK]) // replace prompt with space.
                    { 
                        textValue = this.maskedTextProvider.ToString(/*includePrompt*/ false, this.IncludeLiterals); 
                    }
                    else 
                    {
                        textValue = base.Text;
                    }
 
                    try
                    { 
                        parseRetVal = Formatter.ParseObject( 
                            textValue,              // data
                            this.validatingType,    // targetType 
                            typeof(string),         // sourceType
                            null,                   // targetConverter
                            null,                   // sourceConverter
                            this.formatProvider,    // formatInfo 
                            null,                   // nullValue
                            Formatter.GetDefaultDataSourceNullValue(this.validatingType));   // dataSourceNullValue 
                    } 
                    catch (Exception exception)
                    { 
                        if (ClientUtils.IsSecurityOrCriticalException(exception))
                        {
                            throw;
                        } 

                        if (exception.InnerException != null) // Outer exception is a generic TargetInvocationException. 
                        { 
                            exception = exception.InnerException;
                        } 

                        message = exception.GetType().ToString() + ": " + exception.Message;
                    }
                } 

                bool isValidInput = false; 
                if (message == null) 
                {
                    isValidInput = true; 
                    message = SR.GetString(SR.MaskedTextBoxTypeValidationSucceeded);
                }

                TypeValidationEventArgs tve = new TypeValidationEventArgs(this.validatingType, isValidInput, parseRetVal, message); 
                OnTypeValidationCompleted(tve);
 
                if( e != null ) 
                {
                    e.Cancel = tve.Cancel; 
                }
            }

            return parseRetVal; 
        }
 
        ///  
        ///     Insert or replaces the specified character into the control's text and updates the caret position.
        ///     If overwrite is true, it replaces the character at the selection start position. 
        /// 
        private bool PlaceChar(char ch, int startPosition, int length, bool overwrite,
            out MaskedTextResultHint hint)
        { 
            return PlaceChar(this.maskedTextProvider, ch, startPosition, length, overwrite, out hint );
        } 
 
        /// 
        ///     Override version to be able to perform the operation on a cloned provider. 
        /// 
        private bool PlaceChar(MaskedTextProvider provider, char ch, int startPosition, int length, bool overwrite,
            out MaskedTextResultHint hint)
        { 
            Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." );
 
            this.caretTestPos = startPosition; 

            if (startPosition < this.maskedTextProvider.Length) 
            {
                if (length > 0)  // Replacing selection with input char.
                {
                    int endPos = startPosition + length - 1; 
                    return provider.Replace(ch, startPosition, endPos, out this.caretTestPos, out hint);
                } 
                else 
                {
                    if (overwrite) 
                    {
                        // overwrite character at next edit position from startPosition (inclusive).
                        return provider.Replace(ch, startPosition, out this.caretTestPos, out hint);
                    } 
                    else // insert.
                    { 
                        return provider.InsertAt(ch, startPosition, out this.caretTestPos, out hint); 
                    }
                } 
            }

            hint = MaskedTextResultHint.UnavailableEditPosition;
            return false; 
        }
 
        ///  
        ///     :
        ///     Processes a command key. This method is called during message 
        ///     pre-processing to handle command keys. Command keys are keys that always
        ///     take precedence over regular input keys. Examples of command keys
        ///     include accelerators and menu shortcuts. The method must return true to
        ///     indicate that it has processed the command key, or false to indicate 
        ///     that the key is not a command key.
        /// 
        ///     processCmdKey() first checks if the control has a context menu, and if 
        ///     so calls the menu's processCmdKey() to check for menu shortcuts. If the
        ///     command key isn't a menu shortcut, and if the control has a parent, the 
        ///     key is passed to the parent's processCmdKey() method. The net effect is
        ///     that command keys are "bubbled" up the control hierarchy.
        ///
        ///     When overriding processCmdKey(), a control should return true to 
        ///     indicate that it has processed the key. For keys that aren't processed by
        ///     the control, the result of "base.processCmdKey()" should be returned. 
        /// 
        ///     Controls will seldom, if ever, need to override this method.
        ///      
        ///
        ///     Implements the handling of Ctrl+A (select all). Note: Code copied from TextBox.
        /// 
        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] 
        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        { 
            // 
            // The base class should be called first because it implements ShortcutsEnabled,
            // which takes precedence over Ctrl+A 
            //
            bool msgProcessed = base.ProcessCmdKey(ref msg, keyData);

            if (!msgProcessed) 
            {
                if ((int)keyData == (int)Shortcut.CtrlA) 
                { 
                    base.SelectAll();
                    msgProcessed = true; // This prevents generating a WM_CHAR for 'A'. 
                }
            }

            return msgProcessed; 
        }
 
        ///  
        ///     We need to override this method so we can handle input language changes properly.  Control
        ///     doesn't handle the WM_CHAR messages generated after WM_IME_CHAR messages, it passes them 
        ///     to DefWndProc (the characters would be displayed in the text box always).
        ///
        /// 
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] 
        protected internal override bool ProcessKeyMessage(ref Message m)
        { 
            // call base's method so the WM_CHAR and other messages are processed; this gives Control the 
            // chance to flush all pending WM_CHAR processing after WM_IME_CHAR messages are generated.
 
            bool msgProcessed = base.ProcessKeyMessage(ref m);

            if (this.flagState[IS_NULL_MASK])
            { 
                return msgProcessed; // Operates as a regular text box base.
            } 
 
            // If this WM_CHAR message is sent after WM_IME_CHAR, we ignore it since we already processed
            // the corresponding WM_IME_CHAR message. 

            if( m.Msg == NativeMethods.WM_CHAR && base.ImeWmCharsToIgnore > 0 ) {
                return true;    // meaning, we handled the message so it is not passed to the default WndProc.
            } 

            return msgProcessed; 
        } 

 
        /// 
        ///     Designe time support for resetting Culture property..
        /// 
        private void ResetCulture() 
        {
            this.Culture = CultureInfo.CurrentCulture; 
        } 

        ///  
        ///     Unsupported method/property.
        /// 
        [
        EditorBrowsable(EditorBrowsableState.Never) 
        ]
        public new void ScrollToCaret() 
        { 
        }
 
        /// 
        ///     Sets the underlying MaskedTextProvider object.  Used when the control is initialized
        ///     and one of its properties, backed up by the MaskedTextProvider, changes; this requires
        ///     recreating the provider because it is immutable. 
        /// 
        private void SetMaskedTextProvider( MaskedTextProvider newProvider ) 
        { 
            SetMaskedTextProvider( newProvider, null);
        } 

        /// 
        ///     Overload to allow for passing the text when the mask is being changed from null,
        ///     in this case the maskedTextProvider holds backend info only (not the text). 
        /// 
        private void SetMaskedTextProvider( MaskedTextProvider newProvider, string textOnInitializingMask ) 
        { 
            Debug.Assert( newProvider != null, "Initializing from a null MaskProvider ref." );
 
            // Set R/W properties.
            newProvider.IncludePrompt    = this.maskedTextProvider.IncludePrompt;
            newProvider.IncludeLiterals  = this.maskedTextProvider.IncludeLiterals;
            newProvider.SkipLiterals     = this.maskedTextProvider.SkipLiterals; 
            newProvider.ResetOnPrompt    = this.maskedTextProvider.ResetOnPrompt;
            newProvider.ResetOnSpace     = this.maskedTextProvider.ResetOnSpace; 
 
            // If mask not initialized and not initializing it, the new provider is just a property backend.
            // Change won't have any effect in text. 
            if( this.flagState[IS_NULL_MASK] && textOnInitializingMask == null)
            {
                this.maskedTextProvider = newProvider;
                return; 
            }
 
            int testPos = 0; 
            bool raiseOnMaskInputRejected = false; // Raise if new provider rejects old text.
            MaskedTextResultHint hint = MaskedTextResultHint.NoEffect; 
            MaskedTextProvider oldProvider = this.maskedTextProvider;

            // Attempt to add previous text.
            // If the mask is the same, we need to preserve the caret and character positions if the text is added successfully. 
            bool preserveCharPos = oldProvider.Mask == newProvider.Mask;
 
            // Cache text output text before setting the new provider to determine whether we need to raise the TextChanged event. 
            string oldText;
 
            // NOTE: Whenever changing the MTP, the text is lost if any character in the old text violates the new provider's mask.

            if( textOnInitializingMask != null ) // Changing Mask (from null), which is the only RO property that requires passing text.
            { 
                oldText  = textOnInitializingMask;
                raiseOnMaskInputRejected = !newProvider.Set( textOnInitializingMask, out testPos, out hint ); 
            } 
            else
            { 
                oldText  = TextOutput;

                // We need to attempt to set the input characters one by one in the edit positions so they are not
                // escaped. 
                int assignedCount = oldProvider.AssignedEditPositionCount;
                int srcPos = 0; 
                int dstPos = 0; 

                while( assignedCount > 0 ) 
                {
                    srcPos = oldProvider.FindAssignedEditPositionFrom( srcPos, forward );
                    Debug.Assert( srcPos != MaskedTextProvider.InvalidIndex, "InvalidIndex unexpected at this time." );
 
                    if (preserveCharPos)
                    { 
                        dstPos = srcPos; 
                    }
                    else 
                    {
                        dstPos = newProvider.FindEditPositionFrom(dstPos, forward);

                        if (dstPos == MaskedTextProvider.InvalidIndex) 
                        {
                            newProvider.Clear(); 
 
                            testPos = newProvider.Length;
                            hint = MaskedTextResultHint.UnavailableEditPosition; 
                            break;
                        }
                    }
 
                    if( !newProvider.Replace( oldProvider[srcPos], dstPos, out testPos, out hint ))
                    { 
                        preserveCharPos = false; 
                        newProvider.Clear();
                        break; 
                    }

                    srcPos++;
                    dstPos++; 
                    assignedCount--;
                } 
 
                raiseOnMaskInputRejected = !MaskedTextProvider.GetOperationResultFromHint(hint);
            } 


            // Set provider.
            this.maskedTextProvider = newProvider; 

            if( this.flagState[IS_NULL_MASK] ) 
            { 
                this.flagState[IS_NULL_MASK] = false;
            } 

            // Raising events need to be done only after the new provider has been set so the MTB is in a state where properties
            // can be queried from event handlers safely.
            if( raiseOnMaskInputRejected ) 
            {
                OnMaskInputRejected(new MaskInputRejectedEventArgs(testPos, hint)); 
            } 

            if( newProvider.IsPassword ) 
            {
                // Reset native edit control so the MaskedTextBox will take control over the characters that
                // need to be replaced with the password char (the input text characters).
                // MTB takes over. 
                SetEditControlPasswordChar('\0');
            } 
 
            EventArgs e = EventArgs.Empty;
 
            if (textOnInitializingMask != null /*changing mask from null*/ || oldProvider.Mask != newProvider.Mask)
            {
                OnMaskChanged(e);
            } 

            SetWindowText(GetFormattedDisplayString(), oldText != TextOutput, preserveCharPos); 
        } 

        ///  
        ///     Sets the control's text to the formatted text obtained from the underlying MaskedTextProvider.
        ///     TextChanged is raised always, this assumes the display or the output text changed.
        ///     The caret position is lost (unless cached somewhere else like when lossing the focus).
        ///     This is the common way of changing the text in the control. 
        /// 
        private void SetText() 
        { 
            SetWindowText(GetFormattedDisplayString(), true, false);
        } 

        /// 
        ///     Sets the control's text to the formatted text obtained from the underlying MaskedTextProvider.
        ///     TextChanged is not raised. [PasswordChar] 
        ///     The caret position is preserved.
        ///  
        private void SetWindowText() 
        {
            SetWindowText(GetFormattedDisplayString(), false, true); 
        }

        /// 
        ///     Sets the text directly in the underlying edit control to the value specified. 
        ///     The 'raiseTextChangedEvent' param determines whether TextChanged event is raised or not.
        ///     The 'preserveCaret' param determines whether an attempt to preserve the caret position should be made or not 
        ///     after the call to SetWindowText (WindowText) is performed. 
        /// 
        private void SetWindowText(string text, bool raiseTextChangedEvent, bool preserveCaret) 
        {
            this.flagState[QUERY_BASE_TEXT] = true;

            try 
            {
                if( preserveCaret ) 
                { 
                    this.caretTestPos = this.SelectionStart;
                } 

                WindowText = text;  // this calls Win32::SetWindowText directly, no OnTextChanged raised.

                if( raiseTextChangedEvent ) 
                {
                    OnTextChanged(EventArgs.Empty); 
                } 

                if( preserveCaret ) 
                {
                    this.SelectionStart = this.caretTestPos;
                }
            } 
            finally
            { 
                this.flagState[QUERY_BASE_TEXT] = false; 
            }
        } 

        /// 
        ///     Designe time support for checking if Culture value in the designer should be serialized.
        ///  
        private bool ShouldSerializeCulture()
        { 
            return !CultureInfo.CurrentCulture.Equals(this.Culture); 
        }
 
        /// 
        ///       Undoes the last edit operation in the text box.
        ///       Unsupported property/method.
        ///       WndProc ignores EM_UNDO. 
        /// 
        [ 
        EditorBrowsable(EditorBrowsableState.Never) 
        ]
        public new void Undo() 
        {
        }

        ///  
        ///       Forces type validation.  Returns the validated text value.
        ///  
        public object ValidateText() 
        {
            return PerformTypeValidation(null); 
        }

        /// 
        ///     Deletes all input characters in the current selection. 
        /// 
        private bool WmClear() 
        { 
            Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." );
 
            if( !this.ReadOnly )
            {
                int selStart, selLength;
                base.GetSelectionStartAndLength( out selStart, out selLength ); 
                Delete(Keys.Delete, selStart, selLength);
                return true; 
            } 

            return false; 
        }

        /// 
        ///     Copies current selection text to the clipboard, formatted according to the IncludeLiterals properties but 
        ///     ignoring the prompt character.
        ///     Returns true if the operation succeeded, false otherwise. 
        ///  
        private bool WmCopy()
        { 
            Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." );

            if (this.maskedTextProvider.IsPassword) // cannot copy password to clipboard.
            { 
                return false;
            } 
 
            string text = GetSelectedText();
 
            try
            {
                // SECREVIEW : Copy needs to work even if the OwnClipboard permission isn't available. We need to assert here.
                //             This assert is ok, observe that if the control is in password mode it won't reach this point, 
                //             see code above.
                //             Be careful if code is added after the security assert, you may need to put it in a try-finally 
                //             block to revert the security assert. 
                IntSecurity.ClipboardWrite.Assert();
 
                if (text.Length == 0)
                {
                    Clipboard.Clear();
                } 
                else
                { 
                    Clipboard.SetText(text); 
                }
            } 
            catch (Exception ex)
            {
                // Note: Sometimes the above operation throws but it successfully sets the
                // data in the clipboard. This usually happens when the Application's Main 
                // is not attributed with [STAThread].
                if (ClientUtils.IsSecurityOrCriticalException(ex)) 
                { 
                    throw;
                } 
            }
            return true;
        }
 
        /// 
        ///     Processes the WM_IME_COMPOSITION message when using Korean IME. 
        ///     Korean IME uses the control's caret as the composition string (it processes only one character at a time), 
        ///     we need to have special message handling for it.
        ///     Returns true if the message is handled, false otherwise. 
        /// 
        private bool WmImeComposition(ref Message m)
        {
            Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." ); 

#if DEBUG 
            if (this.ReadOnly || this.maskedTextProvider.IsPassword) 
            {
                // This should have been already handled by the ReadOnly, PasswordChar and ImeMode properties. 
                Debug.Assert(this.ImeMode == ImeMode.Disable, "IME enabled when in RO or Pwd mode.");
            }
#endif
            // Non-Korean IMEs complete compositon when all characters in the string has been composed (when user hits enter); 
            // Currently, we don't support checking the composition string characters because it would require similar logic
            // as the MaskedTextBox itself. 
 
            if (ImeModeConversion.InputLanguageTable == ImeModeConversion.KoreanTable)
            { 
                byte imeConvertionType = imeConvertionNone;

                // Check if there's an update to the compositon string:
                if ((m.LParam.ToInt32() & NativeMethods.GCS_COMPSTR) != 0) 
                {
                    // The character in the composition has been updated but not yet converted. 
                    imeConvertionType = imeConvertionUpdate; 
                }
                else if ((m.LParam.ToInt32() & NativeMethods.GCS_RESULTSTR) != 0) 
                {
                    // The character(s) in the composition has been fully converted.
                    imeConvertionType = imeConvertionCompleted;
                } 

                // Process any update in the composition string. 
                if (imeConvertionType != imeConvertionNone) 
                {
                    if (this.flagState[IME_ENDING_COMPOSITION]) 
                    {
                        // If IME is completing the convertion, we don't want to process further characters.
                        return this.flagState[IME_COMPLETING];
                    } 
                }
            } 
 
            return false; //message not handled.
        } 

        /// 
        ///     Processes the WM_IME_STARTCOMPOSITION message.
        ///     Returns true if the message is handled, false otherwise. 
        /// 
        private bool WmImeStartComposition() 
        { 
            Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." );
 
            // Position the composition window in a valid place.

            int startPosition, selectionLen;
            base.GetSelectionStartAndLength( out startPosition, out selectionLen ); 

            int startEditPos = this.maskedTextProvider.FindEditPositionFrom( startPosition, forward ); 
 
            if( startEditPos != MaskedTextProvider.InvalidIndex )
            { 
                if (selectionLen > 0  && (ImeModeConversion.InputLanguageTable == ImeModeConversion.KoreanTable))
                {
                    // Korean IME: We need to delete the selected text and reposition the caret so the IME processes one
                    // character only, otherwise it would overwrite the selection with the caret (composition string), 
                    // deleting a portion of the mask.
 
                    int endEditPos = this.maskedTextProvider.FindEditPositionFrom(startPosition + selectionLen - 1, backward); 

                    if (endEditPos >= startEditPos) 
                    {
                        selectionLen = endEditPos - startEditPos + 1;
                        Delete(Keys.Delete, startEditPos, selectionLen);
                    } 
                    else
                    { 
                        ImeComplete(); 
                        OnMaskInputRejected(new MaskInputRejectedEventArgs(startPosition, MaskedTextResultHint.UnavailableEditPosition));
                        return true; 
                    }
                }

                // update caret position. 
                if( startPosition != startEditPos )
                { 
                    this.caretTestPos   = startEditPos; 
                    this.SelectionStart = this.caretTestPos;
                } 

                this.SelectionLength = 0;
            }
            else 
            {
                ImeComplete(); 
                OnMaskInputRejected(new MaskInputRejectedEventArgs(startPosition, MaskedTextResultHint.UnavailableEditPosition)); 
                return true;
            } 

            return false;
        }
 

        ///  
        ///     Processes the WM_PASTE message. Copies the text from the clipboard, if is valid, 
        ///     formatted according to the mask applied to this control.
        ///     Returns true if the operation succeeded, false otherwise. 
        /// 
        private void WmPaste()
        {
            Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." ); 

            if( this.ReadOnly ) 
            { 
                return;
            } 

            // Get the text from the clipboard.

            string text; 

            try 
            { 
                IntSecurity.ClipboardRead.Assert();
                text = Clipboard.GetText(); 
            }
            catch (Exception ex)
            {
                if (ClientUtils.IsSecurityOrCriticalException(ex)) 
                {
                    throw; 
                } 
                Debug.Fail(ex.ToString());
                return; 
            }

            PasteInt( text );
        } 

        private void WmPrint(ref Message m) { 
            base.WndProc(ref m); 
            if ((NativeMethods.PRF_NONCLIENT & (int)m.LParam) != 0 && Application.RenderWithVisualStyles && this.BorderStyle == BorderStyle.Fixed3D) {
                IntSecurity.UnmanagedCode.Assert(); 
                try {
                    using (Graphics g = Graphics.FromHdc(m.WParam)) {
                        Rectangle rect = new Rectangle(0, 0, this.Size.Width - 1, this.Size.Height - 1);
                        g.DrawRectangle(new Pen(VisualStyleInformation.TextControlBorder), rect); 
                        rect.Inflate(-1, -1);
                        g.DrawRectangle(SystemPens.Window, rect); 
                    } 
                }
                finally { 
                    CodeAccessPermission.RevertAssert();
                }
            }
        } 

        ///  
        ///     We need to override the WndProc method to have full control over what characters can be 
        ///     displayed in the text box; particularly, we have special handling when IME is turned on.
        ///  
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        protected override void WndProc(ref Message m)
        {
            // Handle messages for special cases (unsupported operations or cases where mask doesn not matter). 
            switch (m.Msg)
            { 
                case NativeMethods.WM_PRINT: 
                    WmPrint(ref m);
                    return; 
                case NativeMethods.WM_CONTEXTMENU:
                case NativeMethods.EM_CANUNDO:
                    base.ClearUndo(); // resets undo buffer.
                    base.WndProc(ref m); 
                    return;
 
                case NativeMethods.EM_SCROLLCARET:  // No scroll for single-line control. 
                case NativeMethods.EM_LIMITTEXT:    // Max/Min text is defined by the mask.
                case NativeMethods.EM_UNDO: 
                case NativeMethods.WM_UNDO:
                    return;

                default: 
                    break;  // continue.
            } 
 
            if( this.flagState[IS_NULL_MASK])
            { 
                base.WndProc(ref m); // Operates as a regular text box base.
                return;
            }
 
            switch (m.Msg)
            { 
                case NativeMethods.WM_IME_STARTCOMPOSITION: 
                    if( WmImeStartComposition() )
                    { 
                        break;
                    }
                    goto default;
 
                case NativeMethods.WM_IME_ENDCOMPOSITION:
                    this.flagState[IME_ENDING_COMPOSITION] = true; 
                    goto default; 

                case NativeMethods.WM_IME_COMPOSITION: 
                    if( WmImeComposition( ref m ) )
                    {
                        break;
                    } 
                    goto default;
 
                case NativeMethods.WM_CUT: 
                    if (!this.ReadOnly && WmCopy())
                    { 
                        WmClear();
                    }
                    break;
 
                case NativeMethods.WM_COPY:
                    WmCopy(); 
                    break; 

                case NativeMethods.WM_PASTE: 
                    WmPaste();
                    break;

                case NativeMethods.WM_CLEAR: 
                    WmClear();
                    break; 
 
                case NativeMethods.WM_KILLFOCUS:
                    base.WndProc(ref m); 
                    WmKillFocus();
                    break;

                case NativeMethods.WM_SETFOCUS: 
                    WmSetFocus();
                    base.WndProc(ref m); 
                    break; 

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

        ///  
        ///     Processes the WM_KILLFOCUS message. Updates control's text replacing promp chars with space. 
        /// 
        private void WmKillFocus() 
        {
            Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." );

            base.GetSelectionStartAndLength( out this.caretTestPos, out this.lastSelLength ); 

            if (this.HidePromptOnLeave && !this.MaskFull) 
            { 
                SetWindowText(); // Update text w/ no prompt.
 
                // We need to update selection info in case the control is queried for it while it doesn't have the focus.
                base.SelectInternal( this.caretTestPos, this.lastSelLength, this.maskedTextProvider.Length );
            }
        } 

        ///  
        ///     Processes the WM_SETFOCUS message. Updates control's text with formatted text according to 
        ///     the include prompt property.
        ///  
        private void WmSetFocus()
        {
            Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." );
 
            if (this.HidePromptOnLeave && !this.MaskFull) // Prompt will show up.
            { 
                SetWindowText(); 
            }
 
            // Restore previous selection. Do this always (as opposed to within the condition above as in WmKillFocus)
            // because HidePromptOnLeave could have changed while the control did not have the focus.
            base.SelectInternal( this.caretTestPos, this.lastSelLength, this.maskedTextProvider.Length );
        } 
    }
} 
 

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

namespace System.Windows.Forms 
{ 
    using System;
    using System.Text; 
    using System.ComponentModel;
    using System.Runtime.InteropServices;
    using System.Globalization;
    using System.Security; 
    using System.Security.Permissions;
    using System.Diagnostics; 
    using System.Collections; 
    using System.Collections.Specialized;
    using System.Drawing; 
    using System.Drawing.Design;
    using System.Windows.Forms.Layout;
    using System.Windows.Forms.VisualStyles;
 
    /// 
    ///     MaskedTextBox control definition class. 
    ///     Uses the services from the System.ComponentModel.MaskedTextBoxProvider class. 
    ///     See spec at http://dotnetclient/whidbey/Specs/MaskEdit.doc
    ///  
    [
    ComVisible(true),
    ClassInterface(ClassInterfaceType.AutoDispatch),
    DefaultEvent("MaskInputRejected"), 
    DefaultBindingProperty("Text"),
    DefaultProperty("Mask"), 
    Designer("System.Windows.Forms.Design.MaskedTextBoxDesigner, " + AssemblyRef.SystemDesign), 
    SRDescription(SR.DescriptionMaskedTextBox)
    ] 
    public class MaskedTextBox : TextBoxBase
    {
        // Consider: The MaskedTextBox control, when initialized with a non-null/empty mask, processes all
        // WM_CHAR messages and always sets the text using the SetWindowText Windows function in the furthest base 
        // class.  This means that the underlying Edit control won't enable Undo operations and the context
        // menu behavior will be a bit different (for instance Copy option is enabled when PasswordChar is set). 
        // To provide Undo functionality and make the context menu behave like the Edit control, we would have 
        // to implement our own.  See http://msdn.microsoft.com/msdnmag/issues/1100/c/default.aspx for more info
        // about how to do this. See postponed bug VSWhidbey#218402. 

        private const bool   forward         = true;
        private const bool   backward        = false;
        private const string nullMask        = "<>"; // any char/str is OK here. 

        private static readonly object EVENT_MASKINPUTREJECTED      = new object(); 
        private static readonly object EVENT_VALIDATIONCOMPLETED    = new object(); 
        private static readonly object EVENT_TEXTALIGNCHANGED       = new object();
        private static readonly object EVENT_ISOVERWRITEMODECHANGED = new object(); 
        private static readonly object EVENT_MASKCHANGED            = new object();

        // The native edit control's default password char (per thread). See corresponding property for more info.
        private static char systemPwdChar; 

        // Values to track changes in IME composition string (if any).  Having const variables is a bit more efficient 
        // than having an enum (which creates a class). 
        private const byte imeConvertionNone      = 0;  // no convertion has been performed in the composition string.
        private const byte imeConvertionUpdate    = 1;  // the char being composed has been updated but not coverted yet. 
        private const byte imeConvertionCompleted = 2;  // the char being composed has been fully converted.

        ///////// Instance fields
 
        // Used for keeping selection when prompt is hidden on leave (text changes).
        private int lastSelLength; 
 
        // Used for caret positioning.
        private int caretTestPos; 

        // Bit mask - Determines when the Korean IME composition string is completed so converted character can be processed.
        private static int IME_ENDING_COMPOSITION = BitVector32.CreateMask();
 
        // Bit mask - Determines when the Korean IME is completing a composition, used when forcing convertion.
        private static int IME_COMPLETING = BitVector32.CreateMask(IME_ENDING_COMPOSITION); 
 
        // Used for handling characters that have a modifier (Ctrl-A, Shift-Del...).
        private static int HANDLE_KEY_PRESS = BitVector32.CreateMask(IME_COMPLETING); 

        // Bit mask - Used to simulate a null mask.  Needed since a MaskedTextProvider object cannot be
        // initialized with a null mask but we need one even in this case as a backend for
        // default properties.  This is to support creating a MaskedTextBox with the default 
        // constructor, specially at design time.
        private static int IS_NULL_MASK = BitVector32.CreateMask(HANDLE_KEY_PRESS); 
 
        // Bit mask - Used in conjuction with get_Text to return the text that is actually set in the native
        // control.  This is required to be able to measure text correctly (GetPreferredSize) and 
        // to compare against during set_Text (to bail if the same and not to raise TextChanged event).
        private static int QUERY_BASE_TEXT = BitVector32.CreateMask(IS_NULL_MASK);

        // If true, the input text is rejected whenever a character does not comply with the mask; a MaskInputRejected 
        // event is fired for the failing character.
        // If false, characters in the input string are processed one by one accepting the ones that comply 
        // with the mask and raising the MaskInputRejected event for the rejected ones. 
        private static int REJECT_INPUT_ON_FIRST_FAILURE = BitVector32.CreateMask( QUERY_BASE_TEXT );
 
        // Bit masks for boolean properties.
        private static int HIDE_PROMPT_ON_LEAVE     = BitVector32.CreateMask(REJECT_INPUT_ON_FIRST_FAILURE);
        private static int BEEP_ON_ERROR            = BitVector32.CreateMask(HIDE_PROMPT_ON_LEAVE);
        private static int USE_SYSTEM_PASSWORD_CHAR = BitVector32.CreateMask(BEEP_ON_ERROR); 
        private static int INSERT_TOGGLED           = BitVector32.CreateMask(USE_SYSTEM_PASSWORD_CHAR);
        private static int CUTCOPYINCLUDEPROMPT     = BitVector32.CreateMask(INSERT_TOGGLED); 
        private static int CUTCOPYINCLUDELITERALS   = BitVector32.CreateMask(CUTCOPYINCLUDEPROMPT); 

        ///////// Properties backend fields. See corresponding property comments for more info. 

        private char                    passwordChar; // control's pwd char, it could be different from the one displayed if using system password.
        private Type                    validatingType;
        private IFormatProvider         formatProvider; 
        private MaskedTextProvider      maskedTextProvider;
        private InsertKeyMode           insertMode; 
        private HorizontalAlignment     textAlign; 

        // Bit vector to represent bool variables. 
        private BitVector32 flagState;

        /// 
        ///     Constructs the MaskedTextBox with the specified MaskedTextProvider object. 
        /// 
        public MaskedTextBox() 
        { 
            MaskedTextProvider maskedTextProvider = new MaskedTextProvider(nullMask, CultureInfo.CurrentCulture);
            this.flagState[IS_NULL_MASK] = true; 
            Initialize(maskedTextProvider);
        }

        ///  
        ///     Constructs the MaskedTextBox with the specified MaskedTextProvider object.
        ///  
        public MaskedTextBox(string mask) 
        {
            if (mask == null) 
            {
                throw new ArgumentNullException();
            }
 
            MaskedTextProvider maskedTextProvider = new MaskedTextProvider(mask, CultureInfo.CurrentCulture);
            this.flagState[IS_NULL_MASK] = false; 
            Initialize(maskedTextProvider); 
        }
 
        /// 
        ///     Constructs the MaskedTextBox with the specified MaskedTextProvider object.
        /// 
        public MaskedTextBox(MaskedTextProvider maskedTextProvider) 
        {
            if (maskedTextProvider == null) 
            { 
                throw new ArgumentNullException();
            } 

            this.flagState[IS_NULL_MASK] = false;
            Initialize(maskedTextProvider);
        } 

        ///  
        ///     Initializes the object with the specified MaskedTextProvider object and default 
        ///     property values.
        ///  
        private void Initialize(MaskedTextProvider maskedTextProvider)
        {
            Debug.Assert(maskedTextProvider != null, "Initializing from a null MaskProvider ref.");
 
            this.maskedTextProvider = maskedTextProvider;
 
            // set the initial display text. 
            if (!this.flagState[IS_NULL_MASK])
            { 
                SetWindowText();
            }

            // set default values. 
            this.passwordChar = this.maskedTextProvider.PasswordChar;
            this.insertMode   = InsertKeyMode.Default; 
 
            this.flagState[HIDE_PROMPT_ON_LEAVE         ] = false;
            this.flagState[BEEP_ON_ERROR                ] = false; 
            this.flagState[USE_SYSTEM_PASSWORD_CHAR     ] = false;
            this.flagState[REJECT_INPUT_ON_FIRST_FAILURE] = false;

            // CutCopyMaskFormat - set same defaults as TextMaskFormat (IncludePromptAndLiterals). 
            // It is a lot easier to handle this flags individually since that's the way the MaskedTextProvider does it.
            this.flagState[CUTCOPYINCLUDEPROMPT         ] = this.maskedTextProvider.IncludePrompt; 
            this.flagState[CUTCOPYINCLUDELITERALS       ] = this.maskedTextProvider.IncludeLiterals; 

            // fields for internal use. 
            this.flagState[HANDLE_KEY_PRESS] = true;
            this.caretTestPos           = 0;
        }
 

        /////////////////// Properties 
        /// 

        ///  
        ///     Unsupported method/property.
        /// 
        [
        Browsable(false), 
        EditorBrowsable(EditorBrowsableState.Never),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) 
        ] 
        public new bool AcceptsTab
        { 
            get { return false; }
            set {}
        }
 
        /// 
        ///     Specifies whether the prompt character should be treated as a valid input character or not. 
        ///     The setter resets the underlying MaskedTextProvider object and attempts 
        ///     to add the existing input text (if any) using the new mask, failure is ignored.
        ///     This property has no particular effect if no mask has been set. 
        /// 
        [
        SRCategory(SR.CatBehavior),
        SRDescription(SR.MaskedTextBoxAllowPromptAsInputDescr), 
        DefaultValue(true)
        ] 
        public bool AllowPromptAsInput 
        {
            get 
            {
                return this.maskedTextProvider.AllowPromptAsInput;
            }
            set 
            {
                if( value != this.maskedTextProvider.AllowPromptAsInput ) 
                { 
                    // Recreate masked text provider since this property is read-only.
                    MaskedTextProvider newProvider = new MaskedTextProvider( 
                        this.maskedTextProvider.Mask,
                        this.maskedTextProvider.Culture,
                        value,
                        this.maskedTextProvider.PromptChar, 
                        this.maskedTextProvider.PasswordChar,
                        this.maskedTextProvider.AsciiOnly ); 
 
                    SetMaskedTextProvider( newProvider );
                } 
            }
        }

        ///  
        ///     Unsupported method/property.
        ///  
        [ 
        Browsable(false),
        EditorBrowsable(EditorBrowsableState.Never), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        public new event EventHandler AcceptsTabChanged
        { 
            add { }
            remove { } 
        } 

        ///  
        ///     Specifies whether only ASCII characters are accepted as valid input.
        ///     This property has no particular effect if no mask has been set.
        /// 
        [ 
        SRCategory(SR.CatBehavior),
        SRDescription(SR.MaskedTextBoxAsciiOnlyDescr), 
        RefreshProperties(RefreshProperties.Repaint), 
        DefaultValue(false)
        ] 
        public bool AsciiOnly
        {
            get
            { 
                return this.maskedTextProvider.AsciiOnly;
            } 
 
            set
            { 
                if( value != this.maskedTextProvider.AsciiOnly )
                {
                    // Recreate masked text provider since this property is read-only.
                    MaskedTextProvider newProvider = new MaskedTextProvider( 
                        this.maskedTextProvider.Mask,
                        this.maskedTextProvider.Culture, 
                        this.maskedTextProvider.AllowPromptAsInput, 
                        this.maskedTextProvider.PromptChar,
                        this.maskedTextProvider.PasswordChar, 
                        value );

                    SetMaskedTextProvider( newProvider );
                } 
            }
        } 
 
        /// 
        ///     Specifies whether to play a beep when the input is not valid according to the mask. 
        /// 
        [
        SRCategory(SR.CatBehavior),
        SRDescription(SR.MaskedTextBoxBeepOnErrorDescr), 
        DefaultValue(false)
        ] 
        public bool BeepOnError 
        {
            get 
            {
                return this.flagState[BEEP_ON_ERROR];
            }
            set 
            {
                this.flagState[BEEP_ON_ERROR] = value; 
            } 
        }
 
        /// 
        ///       Gets a value indicating whether the user can undo the previous operation in a text box control.
        ///       Unsupported method/property.
        ///       WndProc ignores EM_CANUNDO. 
        /// 
        [ 
        Browsable(false), 
        EditorBrowsable(EditorBrowsableState.Never),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) 
        ]
        public new bool CanUndo
        {
            get 
            {
                return false; 
            } 
        }
 
        /// 
        ///     Returns the parameters needed to create the handle. Inheriting classes
        ///     can override this to provide extra functionality. They should not,
        ///     however, forget to call base.getCreateParams() first to get the struct 
        ///     filled up with the basic info.
        ///  
        protected override CreateParams CreateParams 
        {
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] 
            get
            {
                CreateParams cp = base.CreateParams;
 
                // Translate for Rtl if necessary
                // 
                HorizontalAlignment align = RtlTranslateHorizontal(textAlign); 
                cp.ExStyle &= ~NativeMethods.WS_EX_RIGHT;   // WS_EX_RIGHT overrides the ES_XXXX alignment styles
                switch (align) 
                {
                    case HorizontalAlignment.Left:
                        cp.Style |= NativeMethods.ES_LEFT;
                        break; 
                    case HorizontalAlignment.Center:
                        cp.Style |= NativeMethods.ES_CENTER; 
                        break; 
                    case HorizontalAlignment.Right:
                        cp.Style |= NativeMethods.ES_RIGHT; 
                        break;
                }

                return cp; 
            }
        } 
 
        /// 
        ///     The culture that determines the value of the localizable mask language separators and placeholders. 
        /// 
        [
        SRCategory(SR.CatBehavior),
        SRDescription(SR.MaskedTextBoxCultureDescr), 
        RefreshProperties(RefreshProperties.Repaint),
        ] 
        public CultureInfo Culture 
        {
            get 
            {
                return this.maskedTextProvider.Culture;
            }
 
            set
            { 
                if( value == null ) 
                {
                    throw new ArgumentNullException(); 
                }

                if( !this.maskedTextProvider.Culture.Equals(value) )
                { 
                    // Recreate masked text provider since this property is read-only.
                    MaskedTextProvider newProvider = new MaskedTextProvider( 
                        this.maskedTextProvider.Mask, 
                        value,
                        this.maskedTextProvider.AllowPromptAsInput, 
                        this.maskedTextProvider.PromptChar,
                        this.maskedTextProvider.PasswordChar,
                        this.maskedTextProvider.AsciiOnly );
 
                    SetMaskedTextProvider( newProvider );
                } 
            } 
        }
 
        /// 
        ///    Specifies the formatting options for text cut/copited to the clipboard (Whether the mask returned from the Text
        ///    property includes Literals and/or prompt characters).
        ///    When prompt characters are excluded, theyare returned as spaces in the string returned. 
        /// 
        [ 
        SRCategory(SR.CatBehavior), 
        SRDescription(SR.MaskedTextBoxCutCopyMaskFormat),
        RefreshProperties(RefreshProperties.Repaint), 
        DefaultValue(MaskFormat.IncludeLiterals)
        ]
        public MaskFormat CutCopyMaskFormat
        { 
            get
            { 
                if( this.flagState[CUTCOPYINCLUDEPROMPT] ) 
                {
                    if( this.flagState[CUTCOPYINCLUDELITERALS] ) 
                    {
                        return MaskFormat.IncludePromptAndLiterals;
                    }
 
                    return MaskFormat.IncludePrompt;
                } 
 
                if( this.flagState[CUTCOPYINCLUDELITERALS] )
                { 
                    return MaskFormat.IncludeLiterals;
                }

                return MaskFormat.ExcludePromptAndLiterals; 
            }
 
            set 
            {
                //valid values are 0x0 to 0x3 
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)MaskFormat.ExcludePromptAndLiterals, (int)MaskFormat.IncludePromptAndLiterals))
                {
                      throw new InvalidEnumArgumentException("value", (int)value, typeof(MaskFormat));
                } 

                if( value == MaskFormat.IncludePrompt ) 
                { 
                    this.flagState[CUTCOPYINCLUDEPROMPT]   = true;
                    this.flagState[CUTCOPYINCLUDELITERALS] = false; 
                }
                else if( value == MaskFormat.IncludeLiterals )
                {
                    this.flagState[CUTCOPYINCLUDEPROMPT]   = false; 
                    this.flagState[CUTCOPYINCLUDELITERALS] = true;
                } 
                else // value == MaskFormat.IncludePromptAndLiterals || value == MaskFormat.ExcludePromptAndLiterals 
                {
                    bool include = value == MaskFormat.IncludePromptAndLiterals; 
                    this.flagState[CUTCOPYINCLUDEPROMPT]   = include;
                    this.flagState[CUTCOPYINCLUDELITERALS] = include;
                }
            } 
        }
 
        ///  
        ///     Specifies the IFormatProvider to be used when parsing the string to the ValidatingType.
        ///  
        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ] 
        public IFormatProvider FormatProvider
        { 
            get 
            {
                return this.formatProvider; 
            }

            set
            { 
                this.formatProvider = value;
            } 
        } 

        ///  
        ///     Specifies whether the PromptCharacter is displayed when the control loses focus.
        /// 
        [
        SRCategory(SR.CatBehavior), 
        SRDescription(SR.MaskedTextBoxHidePromptOnLeaveDescr),
        RefreshProperties(RefreshProperties.Repaint), 
        DefaultValue(false) 
        ]
        public bool HidePromptOnLeave 
        {
            get
            {
                return this.flagState[HIDE_PROMPT_ON_LEAVE]; 
            }
            set 
            { 
                if( this.flagState[HIDE_PROMPT_ON_LEAVE]  != value )
                { 
                    this.flagState[HIDE_PROMPT_ON_LEAVE] = value;

                    // If the control is not focused and there are available edit positions (mask not full) we need to
                    // update the displayed text. 
                    if( !this.flagState[IS_NULL_MASK]&& !this.Focused && !this.MaskFull && !this.DesignMode )
                    { 
                        SetWindowText(); 
                    }
                } 
            }
        }

        ///  
        ///     Specifies whether to include mask literal characters when formatting the text.
        ///  
        private bool IncludeLiterals 
        {
            get 
            {
                return this.maskedTextProvider.IncludeLiterals;
            }
            set 
            {
                this.maskedTextProvider.IncludeLiterals = value; 
            } 
        }
 
        /// 
        ///     Specifies whether to include the mask prompt character when formatting the text in places
        ///     where an edit char has not being assigned.
        ///  
        private bool IncludePrompt
        { 
            get 
            {
                return this.maskedTextProvider.IncludePrompt; 
            }
            set
            {
                this.maskedTextProvider.IncludePrompt = value; 
            }
        } 
 
        /// 
        ///     Specifies the text insertion mode of the text box.  This can be used to simulated the Access masked text 
        ///     control behavior where insertion is set to TextInsertionMode.AlwaysOverwrite
        ///     This property has no particular effect if no mask has been set.
        /// 
        [ 
        SRCategory(SR.CatBehavior),
        SRDescription(SR.MaskedTextBoxInsertKeyModeDescr), 
        DefaultValue(InsertKeyMode.Default) 
        ]
        public InsertKeyMode InsertKeyMode 
        {
            get
            {
                return this.insertMode; 
            }
            set 
            { 
                //valid values are 0x0 to 0x2
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)InsertKeyMode.Default, (int)InsertKeyMode.Overwrite)) 
                {
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(InsertKeyMode));
                }
 
                if (this.insertMode != value)
                { 
                    bool isOverwrite = this.IsOverwriteMode; 
                    this.insertMode  = value;
 
                    if (isOverwrite != this.IsOverwriteMode)
                    {
                        OnIsOverwriteModeChanged(EventArgs.Empty);
                    } 
                }
            } 
        } 

        ///  
        ///     Overridden to handle unsupported RETURN key.
        /// 
        protected override bool IsInputKey(Keys keyData)
        { 
            if ((keyData & Keys.KeyCode) == Keys.Return)
            { 
                return false; 
            }
            return base.IsInputKey(keyData); 
        }

        /// 
        ///     Specifies whether text insertion mode in 'on' or not. 
        /// 
        [ 
        Browsable(false) 
        ]
        public bool IsOverwriteMode 
        {
            get
            {
                if( this.flagState[IS_NULL_MASK]) 
                {
                    return false; // EditBox always inserts. 
                } 

                switch (this.insertMode) 
                {
                    case InsertKeyMode.Overwrite:
                        return true;
 
                    case InsertKeyMode.Insert:
                        return false; 
 
                    case InsertKeyMode.Default:
 
                        // Note that the insert key state should be per process and its initial state insert, this is the
                        // behavior of apps like WinWord, WordPad and VS; so we have to keep track of it and not query its
                        // system value.
                        //return Control.IsKeyLocked(Keys.Insert); 
                        return this.flagState[INSERT_TOGGLED];
 
                    default: 
                        Debug.Fail("Invalid InsertKeyMode.  This code path should have never been executed.");
                        return false; 
                }
            }
        }
 

        ///  
        ///   Event to notify when the insert mode has changed.  This is required for data binding. 
        /// 
        [ 
        SRCategory(SR.CatPropertyChanged),
        SRDescription(SR.MaskedTextBoxIsOverwriteModeChangedDescr)
        ]
        public event EventHandler IsOverwriteModeChanged 
        {
            add 
            { 
                Events.AddHandler(EVENT_ISOVERWRITEMODECHANGED, value);
            } 
            remove
            {
                Events.RemoveHandler(EVENT_ISOVERWRITEMODECHANGED, value);
            } 
        }
 
        ///  
        ///     Unsupported method/property.
        ///  
        [
        Browsable(false),
        EditorBrowsable(EditorBrowsableState.Never),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) 
        ]
        public new string[] Lines 
        { 
            get
            { 
                string[] lines;

                this.flagState[QUERY_BASE_TEXT] = true;
                try 
                {
                    lines = base.Lines; 
                } 
                finally
                { 
                    this.flagState[QUERY_BASE_TEXT] = false;
                }

                return lines; 
            }
 
            set {} 
        }
 
        /// 
        ///     The mask applied to this control.  The setter resets the underlying MaskedTextProvider object and attempts
        ///     to add the existing input text (if any) using the new mask, failure is ignored.
        ///  
        [
        SRCategory(SR.CatBehavior), 
        SRDescription(SR.MaskedTextBoxMaskDescr), 
        RefreshProperties(RefreshProperties.Repaint),
        DefaultValue(""), 
        MergableProperty(false),
        Localizable(true),
        Editor("System.Windows.Forms.Design.MaskPropertyEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor))
        ] 
        public string Mask
        { 
            get 
            {
                return this.flagState[IS_NULL_MASK]? string.Empty : this.maskedTextProvider.Mask; 
            }
            set
            {
                // 
                // We dont' do anything if:
                // 1.  IsNullOrEmpty( value )->[Reset control] && this.flagState[IS_NULL_MASK]==>Already Reset. 
                // 2. !IsNullOrEmpty( value )->[Set control] && !this.flagState[IS_NULL_MASK][control is set] && [value is the same]==>No need to update. 
                //
                if( this.flagState[IS_NULL_MASK] == string.IsNullOrEmpty( value ) && (this.flagState[IS_NULL_MASK] || value == this.maskedTextProvider.Mask) ) 
                {
                    return;
                }
 
                string text    = null;
                string newMask = value; 
 
                // We need to update the this.flagState[IS_NULL_MASK]field before raising any events (when setting the maskedTextProvider) so
                // querying for properties from an event handler returns the right value (i.e: Text). 

                if( string.IsNullOrEmpty( value ) ) // Resetting the control, the native edit control will be in charge.
                {
                    // Need to get the formatted & unformatted text before resetting the mask, they'll be used to determine whether we need to 
                    // raise the TextChanged event.
                    string formattedText   = TextOutput; 
                    string unformattedText = this.maskedTextProvider.ToString(false, false); 

                    this.flagState[IS_NULL_MASK] = true; 

                    if( this.maskedTextProvider.IsPassword )
                    {
                        SetEditControlPasswordChar(this.maskedTextProvider.PasswordChar); 
                    }
 
                    // Set the window text to the unformatted text before raising events. Also, TextChanged needs to be raised after MaskChanged so 
                    // pass false to SetWindowText 'raiseTextChanged' param.
                    SetWindowText(unformattedText, false, false ); 

                    EventArgs e = EventArgs.Empty;

                    OnMaskChanged(e); 

                    if( unformattedText != formattedText ) 
                    { 
                        OnTextChanged(e);
                    } 

                    newMask = nullMask;
                }
                else    // Setting control to a new value. 
                {
                    foreach( char c in value ) 
                    { 
                        if( !MaskedTextProvider.IsValidMaskChar( c ) )
                        { 
                            // Same message as in SR.MaskedTextProviderMaskInvalidChar in System.txt
                            throw new ArgumentException( SR.GetString( SR.MaskedTextBoxMaskInvalidChar) );
                        }
                    } 

                    if( this.flagState[IS_NULL_MASK] ) 
                    { 
                        // If this.IsNullMask, we are setting the mask to a new value; in this case we need to get the text because
                        // the underlying MTP does not have it (used as a property backend only) and pass it to SetMaskedTextProvider 
                        // method below to update the provider.

                        text = this.Text;
                    } 
                }
 
                // Recreate masked text provider since this property is read-only. 
                MaskedTextProvider newProvider = new MaskedTextProvider(
                    newMask, 
                    this.maskedTextProvider.Culture,
                    this.maskedTextProvider.AllowPromptAsInput,
                    this.maskedTextProvider.PromptChar,
                    this.maskedTextProvider.PasswordChar, 
                    this.maskedTextProvider.AsciiOnly );
 
                //text == null when setting to a different mask value or when resetting the mask to null. 
                //text != null only when setting the mask from null to some value.
                SetMaskedTextProvider( newProvider, text ); 
            }
        }

        ///  
        ///   Event to notify when the mask has changed.
        ///  
        [ 
        SRCategory(SR.CatPropertyChanged),
        SRDescription(SR.MaskedTextBoxMaskChangedDescr) 
        ]
        public event EventHandler MaskChanged
        {
            add 
            {
                Events.AddHandler(EVENT_MASKCHANGED, value); 
            } 
            remove
            { 
                Events.RemoveHandler(EVENT_MASKCHANGED, value);
            }
        }
 
        /// 
        ///     Specifies whether the test string required input positions, as specified by the mask, have 
        ///     all been assigned. 
        /// 
        [ 
        Browsable(false)
        ]
        public bool MaskCompleted
        { 
            get
            { 
                return this.maskedTextProvider.MaskCompleted; 
            }
        } 

        /// 
        ///     Specifies whether all inputs (required and optional) have been provided into the mask successfully.
        ///  
        [
        Browsable(false) 
        ] 
        public bool MaskFull
        { 
            get
            {
                return this.maskedTextProvider.MaskFull;
            } 
        }
 
        ///  
        ///     Returns a copy of the control's internal MaskedTextProvider.  This is useful for user's to provide
        ///     cloning semantics for the control (we don't want to do it) w/o incurring in any perf penalty since 
        ///     some of the properties require recreating the underlying provider when they are changed.
        /// 
        [
        Browsable(false), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ] 
        public MaskedTextProvider MaskedTextProvider 
        {
            get 
            {
                return this.flagState[IS_NULL_MASK] ? null : (MaskedTextProvider) this.maskedTextProvider.Clone();
            }
        } 

        ///  
        ///     Event to notify when an input has been rejected according to the mask. 
        /// 
        [ 
        SRCategory(SR.CatBehavior),
        SRDescription(SR.MaskedTextBoxMaskInputRejectedDescr)
        ]
        public event MaskInputRejectedEventHandler MaskInputRejected 
        {
            add 
            { 
                Events.AddHandler(EVENT_MASKINPUTREJECTED, value);
            } 
            remove
            {
                Events.RemoveHandler(EVENT_MASKINPUTREJECTED, value);
            } 
        }
 
        ///  
        ///     Unsupported method/property.
        ///     WndProc ignores EM_LIMITTEXT & this is a virtual method. 
        /// 
        [
        Browsable(false),
        EditorBrowsable(EditorBrowsableState.Never), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ] 
        public override int MaxLength 
        {
            get{ return base.MaxLength; } 
            set{}
        }

        ///  
        ///     Unsupported method/property.
        ///     virtual method. 
        ///  
        [
        Browsable(false), 
        EditorBrowsable(EditorBrowsableState.Never),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        public override bool Multiline 
        {
            get { return false; } 
            set {} 
        }
 
        /// 
        ///     Unsupported method/property.
        /// 
        [ 
        Browsable(false),
        EditorBrowsable(EditorBrowsableState.Never), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) 
        ]
        public new event EventHandler MultilineChanged 
        {
            add { }
            remove { }
        } 

        ///  
        ///     Specifies the character to be used in the formatted string in place of editable characters, if 
        ///     set to any printable character, the text box becomes a password text box, to reset it use the null
        ///     character. 
        /// 
        [
        SRCategory(SR.CatBehavior),
        SRDescription(SR.MaskedTextBoxPasswordCharDescr), 
        RefreshProperties(RefreshProperties.Repaint),
        DefaultValue('\0') // This property is shadowed by MaskedTextBoxDesigner. 
        ] 
        public char PasswordChar
        { 
            get
            {
                // The password char could be the one set in the control or the system password char,
                // in any case the maskedTextProvider has the correct one. 
                return this.maskedTextProvider.PasswordChar;
            } 
            set 
            {
                if( !MaskedTextProvider.IsValidPasswordChar(value) ) // null character accepted (resets value) 
                {
                    // Same message as in SR.MaskedTextProviderInvalidCharError.
                    throw new ArgumentException(SR.GetString(SR.MaskedTextBoxInvalidCharError) );
                } 

                if( this.passwordChar != value ) 
                { 
                    if( value == this.maskedTextProvider.PromptChar )
                    { 
                        // Prompt and password chars must be different.
                        throw new InvalidOperationException( SR.GetString(SR.MaskedTextBoxPasswordAndPromptCharError) );
                    }
 
                    this.passwordChar = value;
 
                    // UseSystemPasswordChar take precedence over PasswordChar...Let's check. 
                    if (!this.UseSystemPasswordChar)
                    { 
                        this.maskedTextProvider.PasswordChar = value;

                        if( this.flagState[IS_NULL_MASK])
                        { 
                            SetEditControlPasswordChar(value);
                        } 
                        else 
                        {
                            SetWindowText(); 
                        }

                        VerifyImeRestrictedModeChanged();
                    } 
                }
            } 
        } 

        ///  
        ///     Determines if the control is in password protect mode.
        /// 
        internal override bool PasswordProtect
        { 
            get
            { 
                if( this.maskedTextProvider != null ) // could be queried during object construction. 
                {
                     return this.maskedTextProvider.IsPassword; 
                }
                return base.PasswordProtect;
            }
        } 

        ///  
        ///     Specifies the prompt character to be used in the formatted string for unsupplied characters. 
        /// 
        [ 
        SRCategory(SR.CatAppearance),
        SRDescription(SR.MaskedTextBoxPromptCharDescr),
        RefreshProperties(RefreshProperties.Repaint),
        Localizable(true), 
        DefaultValue('_')
        ] 
        public char PromptChar 
        {
            get 
            {
                return this.maskedTextProvider.PromptChar;
            }
            set 
            {
                if( !MaskedTextProvider.IsValidInputChar(value) ) 
                { 
                    // This message is the same as the one in SR.MaskedTextProviderInvalidCharError.
                    throw new ArgumentException(SR.GetString(SR.MaskedTextBoxInvalidCharError) ); 
                }

                if( this.maskedTextProvider.PromptChar != value )
                { 
                    // We need to check maskedTextProvider password char in case it is using the system password.
                    if( value == this.passwordChar || value == this.maskedTextProvider.PasswordChar ) 
                    { 
                        // Prompt and password chars must be different.
                        throw new InvalidOperationException( SR.GetString(SR.MaskedTextBoxPasswordAndPromptCharError) ); 
                    }

                    // Recreate masked text provider to be consistent with AllowPromptAsInput - current text may have chars with same value as new prompt.
                    MaskedTextProvider newProvider = new MaskedTextProvider( 
                        this.maskedTextProvider.Mask,
                        this.maskedTextProvider.Culture, 
                        this.maskedTextProvider.AllowPromptAsInput, 
                        value,
                        this.maskedTextProvider.PasswordChar, 
                        this.maskedTextProvider.AsciiOnly );

                    SetMaskedTextProvider( newProvider );
                } 
            }
        } 
 
        /// 
        ///     Overwrite base class' property. 
        /// 
        public new bool ReadOnly
        {
            get 
            {
                return base.ReadOnly; 
            } 

            set 
            {
                if (this.ReadOnly != value)
                {
                    // if true, this disables IME in the base class. 
                    base.ReadOnly = value;
 
                    if (!this.flagState[IS_NULL_MASK]) 
                    {
                        // Prompt will be hidden. 
                        SetWindowText();
                    }
                }
            } 
        }
 
        ///  
        ///     Specifies whether to include the mask prompt character when formatting the text in places
        ///     where an edit char has not being assigned. 
        /// 
        [
        SRCategory(SR.CatBehavior),
        SRDescription(SR.MaskedTextBoxRejectInputOnFirstFailureDescr), 
        DefaultValue(false)
        ] 
        public bool RejectInputOnFirstFailure 
        {
            get 
            {
                return this.flagState[REJECT_INPUT_ON_FIRST_FAILURE];
            }
            set 
            {
                this.flagState[REJECT_INPUT_ON_FIRST_FAILURE] = value; 
            } 
        }
 
        /// 
        ///     Designe time support for resetting the Culture property.
        /// 
        /* No longer needed since Culture has been removed from the property browser - Left here for documentation. 
        [EditorBrowsable(EditorBrowsableState.Never)]
        private void ResetCulture() 
        { 
            this.Culture = CultureInfo.CurrentCulture;
        }*/ 


        /// 
        ///     Specifies whether to reset and skip the current position if editable, when the input character 
        ///     has the same value as the prompt.  This property takes precedence over AllowPromptAsInput.
        ///  
        [ 
        SRCategory(SR.CatBehavior),
        SRDescription(SR.MaskedTextBoxResetOnPrompt), 
        DefaultValue(true)
        ]
        public bool ResetOnPrompt
        { 
            get
            { 
                return this.maskedTextProvider.ResetOnPrompt; 
            }
            set 
            {
                this.maskedTextProvider.ResetOnPrompt = value;
            }
        } 

        ///  
        ///     Specifies whether to reset and skip the current position if editable, when the input 
        ///     is the space character.
        ///  
        [
        SRCategory(SR.CatBehavior),
        SRDescription(SR.MaskedTextBoxResetOnSpace),
        DefaultValue(true) 
        ]
        public bool ResetOnSpace 
        { 
            get
            { 
                return this.maskedTextProvider.ResetOnSpace;
            }
            set
            { 
                this.maskedTextProvider.ResetOnSpace = value;
            } 
        } 

        ///  
        ///     Specifies whether to skip the current position if non-editable and the input character has
        ///     the same value as the literal at that position.
        /// 
        [ 
        SRCategory(SR.CatBehavior),
        SRDescription(SR.MaskedTextBoxSkipLiterals), 
        DefaultValue(true) 
        ]
        public bool SkipLiterals 
        {
            get
            {
                return this.maskedTextProvider.SkipLiterals; 
            }
            set 
            { 
                this.maskedTextProvider.SkipLiterals = value;
            } 
        }

        /// 
        ///       The currently selected text (if any) in the control. 
        /// 
        public override string SelectedText 
        { 
            get
            { 
                if( this.flagState[IS_NULL_MASK])
                {
                    return base.SelectedText;
                } 

                return GetSelectedText(); 
            } 
            set
            { 
                SetSelectedTextInternal(value, true);
            }
        }
 
        internal override void SetSelectedTextInternal(string value, bool clearUndo)
        { 
            if (this.flagState[IS_NULL_MASK]) 
            {
                base.SetSelectedTextInternal(value, true); // Operates as a regular text box base. 
                return;
            }

            PasteInt( value ); 
        }
 
        ///  
        ///     Set the composition string as the result string.
        ///  
        private void ImeComplete()
        {
            this.flagState[IME_COMPLETING] = true;
            ImeNotify(NativeMethods.CPS_COMPLETE); 
        }
 
        ///  
        ///     Notifies the IMM about changes to the status of the IME input context.
        ///  
        private void ImeNotify(int action)
        {
            HandleRef handle    = new HandleRef(this, this.Handle);
            IntPtr inputContext = UnsafeNativeMethods.ImmGetContext(handle); 

            if (inputContext != IntPtr.Zero) 
            { 
                try
                { 
                    UnsafeNativeMethods.ImmNotifyIME(new HandleRef(null, inputContext), NativeMethods.NI_COMPOSITIONSTR, action, 0);
                }
                finally
                { 
                    UnsafeNativeMethods.ImmReleaseContext(handle, new HandleRef(null, inputContext));
                } 
            } 
            else
            { 
                Debug.Fail("Could not get IME input context.");
            }
        }
 
        /// 
        ///     Sets the underlying edit control's password char to the one obtained from this.PasswordChar. 
        ///     This is used when the control is passworded and this.flagState[IS_NULL_MASK]. 
        /// 
        private void SetEditControlPasswordChar( char pwdChar ) 
        {
            if (this.IsHandleCreated)
            {
                // This message does not return a value. 
                SendMessage(NativeMethods.EM_SETPASSWORDCHAR, pwdChar, 0);
                Invalidate(); 
            } 
        }
 
        /// 
        ///     The value of the Edit control default password char.
        /// 
        private char SystemPasswordChar 
        {
            get 
            { 
                if (MaskedTextBox.systemPwdChar == '\0')
                { 
                    // This is the hard way to get the password char - left here for information.
                    // It is picked up from Comctl32.dll. If VisualStyles is enabled it will get the dot char.
                    /*
                    StringBuilder charVal = new StringBuilder(20);  // it could be 0x0000000000009999 format. 
                    bool foundRsc         = false;
                    int IDS_PASSWORDCHAR  = 0x1076; // %ntsdx%\shell\comctrl32\v6\rcids.h 
                                                    // defined in en.rc as: IDS_PASSWORDCHAR "9679" // 0x25cf - Black Circle 

                    IntSecurity.UnmanagedCode.Assert(); 

                    try
                    {
                        // The GetModuleHandle function returns a handle to a mapped module without incrementing its reference count. 
                        // @"C:\windows\winsxs\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.10.0_x-ww_f7fb5805\comctl32.dll if VisulaStyles enabled.
 
                        IntPtr hModule = UnsafeNativeMethods.GetModuleHandle("comctl32.dll"); 
                        Debug.Assert(hModule != IntPtr.Zero, String.Format("Could not get a handle to comctl32.dll - Error: 0x{0:X8}", Marshal.GetLastWin32Error()));
 
                        foundRsc = UnsafeNativeMethods.LoadString(new HandleRef(null, hModule), IDS_PASSWORDCHAR, charVal, charVal.Capacity);
                    }
                    catch( Exception ex )
                    { 
                        if( ClientUtils.IsSecurityOrCriticalException( ex ) )
                        { 
                            throw; 
                        }
                    } 
                    finally
                    {
                        CodeAccessPermission.RevertAssert();
                    } 

                    MaskedTextBox.systemPwdChar = foundRsc ? (char) int.Parse(charVal.ToString()) : MaskedTextProvider.DefaultPasswordChar; 
                    */ 

                    // We need to temporarily create an edit control to get the default password character. 
                    // We cannot use this control because we would have to reset the native control's password char to use
                    // the defult one so we can get it; this would change the text displayed in the box (even for a short time)
                    // opening a sec hole.
 
                    TextBox txtBox = new TextBox();
                    txtBox.UseSystemPasswordChar = true; // this forces the creation of the control handle. 
 
                    MaskedTextBox.systemPwdChar = txtBox.PasswordChar;
 
                    txtBox.Dispose();
                }

                return MaskedTextBox.systemPwdChar; 
            }
        } 
 
        /// 
        ///     The Text setter validates the input char by char, raising the MaskInputRejected event for invalid chars. 
        ///     The Text getter returns the formatted text according to the IncludeLiterals and IncludePrompt properties.
        /// 
        [
        Editor("System.Windows.Forms.Design.MaskedTextBoxTextEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)), 
        SRCategory(SR.CatAppearance),
        RefreshProperties(RefreshProperties.Repaint), 
        Bindable(true), 
        DefaultValue(""), // This property is shadowed by MaskedTextBoxDesigner.
        Localizable(true) 
        ]
        public override string Text
        {
            get 
            {
                if( this.flagState[IS_NULL_MASK] || this.flagState[QUERY_BASE_TEXT]) 
                { 
                    return base.Text;
                } 

                return TextOutput;
            }
            set 
            {
                if (this.flagState[IS_NULL_MASK]) 
                { 
                    base.Text = value;
                    return; 
                }

                if (string.IsNullOrEmpty(value))
                { 
                    // reset the input text.
                    Delete(Keys.Delete, 0, this.maskedTextProvider.Length); 
                } 
                else
                { 
                    if( this.RejectInputOnFirstFailure )
                    {
                        MaskedTextResultHint hint;
                        string oldText = TextOutput; 
                        if (this.maskedTextProvider.Set(value, out this.caretTestPos, out hint))
                        { 
                            //if( hint == MaskedTextResultHint.Success || hint == MaskedTextResultHint.SideEffect ) 
                            if( TextOutput != oldText )
                            { 
                                SetText();
                            }
                            this.SelectionStart = ++this.caretTestPos;
                        } 
                        else
                        { 
                            OnMaskInputRejected(new MaskInputRejectedEventArgs(this.caretTestPos, hint)); 
                        }
                    } 
                    else
                    {
                        Replace(value, /*startPosition*/ 0, /*selectionLen*/ this.maskedTextProvider.Length);
                    } 
                }
            } 
        } 

        ///  
        ///     Returns the length of the displayed text.  See VSW#502543.
        /// 
        [Browsable( false )]
        public override int TextLength 
        {
            get 
            { 
                if( this.flagState[IS_NULL_MASK] )
                { 
                    return base.TextLength;
                }

                // In Win9x systems TextBoxBase.TextLength calls Text.Length directly and does not query the window for the actual text length. 
                // If TextMaskFormat is set to a anything different from IncludePromptAndLiterals or HidePromptOnLeave is true the return value
                // may be incorrect because the Text property value and the display text may be different.  We need to handle this here. 
 
                return GetFormattedDisplayString().Length;
            } 
        }

        /// 
        ///     The formatted text, it is what the Text getter returns when a mask has been applied to the control. 
        ///     The text format follows the IncludeLiterals and IncludePrompt properties (See MaskedTextProvider.ToString()).
        ///  
        private string TextOutput 
        {
            get 
            {
                Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." );
                return this.maskedTextProvider.ToString();
            } 
        }
 
        ///  
        ///     Gets or sets how text is aligned in the control.
        ///     Note: This code is duplicated in TextBox for simplicity. 
        /// 
        [
        Localizable(true),
        SRCategory(SR.CatAppearance), 
        DefaultValue(HorizontalAlignment.Left),
        SRDescription(SR.TextBoxTextAlignDescr) 
        ] 
        public HorizontalAlignment TextAlign
        { 
            get
            {
                return textAlign;
            } 
            set
            { 
                if (textAlign != value) 
                {
                    //verify that 'value' is a valid enum type... 
                    //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)); 
                    }
 
                    textAlign = value; 
                    RecreateHandle();
                    OnTextAlignChanged(EventArgs.Empty); 
                }
            }
        }
 
        /// 
        ///     Event to notify the text alignment has changed. 
        ///  
        [
        SRCategory(SR.CatPropertyChanged), 
        SRDescription(SR.RadioButtonOnTextAlignChangedDescr)
        ]
        public event EventHandler TextAlignChanged
        { 
            add
            { 
                Events.AddHandler(EVENT_TEXTALIGNCHANGED, value); 
            }
 
            remove
            {
                Events.RemoveHandler(EVENT_TEXTALIGNCHANGED, value);
            } 
        }
 
        ///  
        ///    Specifies the formatting options for text output (Whether the mask returned from the Text
        ///    property includes Literals and/or prompt characters). 
        ///    When prompt characters are excluded, theyare returned as spaces in the string returned.
        /// 
        [
        SRCategory(SR.CatBehavior), 
        SRDescription(SR.MaskedTextBoxTextMaskFormat),
        RefreshProperties(RefreshProperties.Repaint), 
        DefaultValue(MaskFormat.IncludeLiterals) 
        ]
        public MaskFormat TextMaskFormat 
        {
            get
            {
                if( this.IncludePrompt ) 
                {
                    if( this.IncludeLiterals ) 
                    { 
                        return MaskFormat.IncludePromptAndLiterals;
                    } 

                    return MaskFormat.IncludePrompt;
                }
 
                if( this.IncludeLiterals )
                { 
                    return MaskFormat.IncludeLiterals; 
                }
 
                return MaskFormat.ExcludePromptAndLiterals;
            }

            set 
            {
                if( this.TextMaskFormat == value ) 
                { 
                    return;
                } 

                //valid values are 0x0 to 0x3
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)MaskFormat.ExcludePromptAndLiterals, (int)MaskFormat.IncludePromptAndLiterals))
                { 
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(MaskFormat));
                } 
 
                // Changing the TextMaskFormat will likely change the 'output' text (Text getter value).  Cache old value to
                // verify it against the new value and raise OnTextChange if needed. 
                string oldText = this.flagState[IS_NULL_MASK] ? null : TextOutput;

                if( value == MaskFormat.IncludePrompt )
                { 
                    this.IncludePrompt   = true;
                    this.IncludeLiterals = false; 
                } 
                else if( value == MaskFormat.IncludeLiterals )
                { 
                    this.IncludePrompt   = false;
                    this.IncludeLiterals = true;
                }
                else // value == MaskFormat.IncludePromptAndLiterals || value == MaskFormat.ExcludePromptAndLiterals 
                {
                    bool include = value == MaskFormat.IncludePromptAndLiterals; 
                    this.IncludePrompt   = include; 
                    this.IncludeLiterals = include;
                } 

                if( oldText != null && oldText != TextOutput )
                {
                    OnTextChanged(EventArgs.Empty); 
                }
            } 
        } 

        ///  
        ///    Provides some interesting information for the TextBox control in String form.
        ///    Returns the test string (no password, including literals and prompt).
        /// 
        public override string ToString() 
        {
            if( this.flagState[IS_NULL_MASK] ) 
            { 
                return base.ToString();
            } 

            // base.ToString will call Text, we want to always display prompt and literals.
            bool includePrompt = this.IncludePrompt;
            bool includeLits   = this.IncludeLiterals; 
            string str;
            try 
            { 
                this.IncludePrompt = this.IncludeLiterals = true;
                str = base.ToString(); 
            }
            finally
            {
                this.IncludePrompt = includePrompt; 
                this.IncludeLiterals = includeLits;
            } 
 
            return str;
        } 

        /// 
        ///     Event to notify when the validating object completes parsing the formatted text.
        ///  
        [
        SRCategory(SR.CatFocus), 
        SRDescription(SR.MaskedTextBoxTypeValidationCompletedDescr) 
        ]
        public event TypeValidationEventHandler TypeValidationCompleted 
        {
            add
            {
                Events.AddHandler(EVENT_VALIDATIONCOMPLETED, value); 
            }
            remove 
            { 
                Events.RemoveHandler(EVENT_VALIDATIONCOMPLETED, value);
            } 
        }

        /// 
        ///    Indicates if the text in the edit control should appear as the default password character. 
        ///    This property has precedence over the PasswordChar property.
        ///  
        [ 
        SRCategory(SR.CatBehavior),
        SRDescription(SR.MaskedTextBoxUseSystemPasswordCharDescr), 
        RefreshProperties(RefreshProperties.Repaint),
        DefaultValue(false)
        ]
        public bool UseSystemPasswordChar 
        {
            get 
            { 
                return this.flagState[USE_SYSTEM_PASSWORD_CHAR];
            } 
            set
            {
                if (value != this.flagState[USE_SYSTEM_PASSWORD_CHAR])
                { 
                    if (value)
                    { 
                        if( this.SystemPasswordChar == this.PromptChar ) 
                        {
                            // Prompt and password chars must be different. 
                            throw new InvalidOperationException( SR.GetString(SR.MaskedTextBoxPasswordAndPromptCharError) );
                        }

                        this.maskedTextProvider.PasswordChar = this.SystemPasswordChar; 
                    }
                    else 
                    { 
                        // this.passwordChar could be '\0', in which case we are resetting the display to show the input char.
                        this.maskedTextProvider.PasswordChar = this.passwordChar; 
                    }

                    this.flagState[USE_SYSTEM_PASSWORD_CHAR] = value;
 
                    if( this.flagState[IS_NULL_MASK])
                    { 
                        SetEditControlPasswordChar(this.maskedTextProvider.PasswordChar); 
                    }
                    else 
                    {
                        SetWindowText();
                    }
 
                    VerifyImeRestrictedModeChanged();
                } 
            } 
        }
 
        /// 
        ///     Type of the object to be used to parse the text when the user leaves the control.
        ///     A ValidatingType object must implement a method with one fo the following signature:
        ///         public static Object Parse(string) 
        ///         public static Object Parse(string, IFormatProvider)
        ///     See DateTime.Parse(...) for an example. 
        ///  
        [
        Browsable(false), 
        DefaultValue(null)
        ]
        public Type ValidatingType
        { 
            get
            { 
                return this.validatingType; 
            }
            set 
            {
                if( this.validatingType != value )
                {
                    this.validatingType = value; 
                }
            } 
        } 

        ///  
        ///     Unsupported method/property.
        /// 
        [
        Browsable(false), 
        EditorBrowsable(EditorBrowsableState.Never),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) 
        ] 
        public new bool WordWrap
        { 
            get { return false; }
            set {}
        }
 

        ////////////// Methods 
 
        /// 
        ///     Clears information about the most recent operation from the undo buffer of the control. 
        ///     Unsupported property/method.
        /// 
        [
        EditorBrowsable(EditorBrowsableState.Never) 
        ]
        public new void ClearUndo() 
        { 
        }
 
        /// 
        ///     Creates a handle for this control. This method is called by the .NET Framework, this should
        ///     not be called. Inheriting classes should always call base.createHandle when overriding this method.
        ///     Overridden to be able to set the control text with the masked (passworded) value when recreating 
        ///     handle, since the underlying native edit control is not aware of it.
        ///  
        [ 
        EditorBrowsable(EditorBrowsableState.Advanced),
        UIPermission(SecurityAction.InheritanceDemand, Window = UIPermissionWindow.AllWindows) 
        ]
        protected override void CreateHandle()
        {
            if (!this.flagState[IS_NULL_MASK] && RecreatingHandle) 
            {
                // update cached text value in Control. Don't preserve caret, cannot query for selection start at this time. 
                SetWindowText(GetFormattedDisplayString(), false, false); 
            }
 
            base.CreateHandle();
        }

        /// 
        /// 
        ///     Deletes characters from the control's text according to the key pressed (Delete/Backspace). 
        ///     Returns true if something gets actually deleted, false otherwise. 
        /// 
        private void Delete(Keys keyCode, int startPosition, int selectionLen) 
        {
            Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." );
            Debug.Assert( keyCode == Keys.Delete || keyCode == Keys.Back, "Delete called with keyCode == " + keyCode.ToString() );
            Debug.Assert( startPosition >= 0 && ((startPosition + selectionLen) <= this.maskedTextProvider.Length), "Invalid position range." ); 

            // On backspace, moving the start postion back by one has the same effect as delete.  If text is selected, there is no 
            // need for moving the position back. 

            this.caretTestPos = startPosition; 

            if( selectionLen == 0 )
            {
                if( keyCode == Keys.Back ) 
                {
                    if( startPosition == 0 ) // At beginning of string, backspace does nothing. 
                    { 
                        return;
                    } 

                    startPosition--; // so it can be treated as delete.
                }
                else // (keyCode == Keys.Delete) 
                {
                    if( (startPosition + selectionLen) == this.maskedTextProvider.Length ) // At end of string, delete does nothing. 
                    { 
                        return;
                    } 
                }
            }

            int tempPos; 
            int endPos = selectionLen > 0 ? startPosition + selectionLen - 1 : startPosition;
            MaskedTextResultHint hint; 
 
            string oldText = TextOutput;
            if (this.maskedTextProvider.RemoveAt(startPosition, endPos, out tempPos, out hint)) 
            {
                //if( hint == MaskedTextResultHint.Success || hint == MaskedTextResultHint.SideEffect) // Text was changed.
                if( TextOutput != oldText )
                { 
                    SetText();
                    this.caretTestPos = startPosition; 
                } 
                else
                { 
                    // If succeeded but nothing removed, the caret should move as follows:
                    // 1. If selectionLen > 0, or on back and hint == SideEffect: move to selectionStart.
                    // 2. If hint == NoEffect, On Delete move to next edit position, if any or not already in one.
                    //    On back move to the next edit postion at the left if no more assigned position at the right, 
                    //    in such case find an assigned position and move one past or one position left if no assigned pos found
                    //    (taken care by 'startPosition--' above). 
                    // 3. If hint == SideEffect, on Back move like arrow key, (startPosition is already moved, startPosition-- above). 

                    if( selectionLen > 0 ) 
                    {
                        this.caretTestPos = startPosition;
                    }
                    else 
                    {
                        if( hint == MaskedTextResultHint.NoEffect ) // Case 2. 
                        { 
                            if( keyCode == Keys.Delete )
                            { 
                                this.caretTestPos = this.maskedTextProvider.FindEditPositionFrom(startPosition, forward);
                            }
                            else
                            { 
                                if( this.maskedTextProvider.FindAssignedEditPositionFrom( startPosition, forward ) == MaskedTextProvider.InvalidIndex )
                                { 
                                    // No assigned position at the right, nothing to shift then move to the next assigned position at the 
                                    // left (if any).
                                    this.caretTestPos = this.maskedTextProvider.FindAssignedEditPositionFrom(startPosition, backward); 
                                }
                                else
                                {
                                    // there are assigned positions at the right so move to an edit position at the left to get ready for 
                                    // removing the character on it or just shifting the characters at the right
                                    this.caretTestPos = this.maskedTextProvider.FindEditPositionFrom(startPosition, backward); 
                                } 

                                if( this.caretTestPos != MaskedTextProvider.InvalidIndex ) 
                                {
                                    this.caretTestPos++; // backspace gets ready to remove one position past the edit position.
                                }
                            } 

                            if( this.caretTestPos == MaskedTextProvider.InvalidIndex ) 
                            { 
                                this.caretTestPos = startPosition;
                            } 
                        }
                        else // (hint == MaskedTextProvider.OperationHint.SideEffect)
                        {
                            if( keyCode == Keys.Back )  // Case 3. 
                            {
                                this.caretTestPos = startPosition; 
                            } 
                        }
                    } 
                }
            }
            else
            { 
                OnMaskInputRejected(new MaskInputRejectedEventArgs(tempPos, hint));
            } 
 
            // Reposition caret.  Call base.SelectInternal for perf reasons.
            //this.SelectionLength = 0; 
            //this.SelectionStart  = this.caretTestPos; // new caret position.
            base.SelectInternal( this.caretTestPos, 0, this.maskedTextProvider.Length );

            return; 
        }
 
        ///  
        ///     Returns the character nearest to the given point.
        ///  
        public override char GetCharFromPosition(Point pt)
        {
            char ch;
 
            this.flagState[QUERY_BASE_TEXT] = true;
            try 
            { 
                ch = base.GetCharFromPosition(pt);
            } 
            finally
            {
                this.flagState[QUERY_BASE_TEXT] = false;
            } 
            return ch;
        } 
 

        ///  
        ///     Returns the index of the character nearest to the given point.
        /// 
        public override int GetCharIndexFromPosition(Point pt)
        { 
            int index;
 
            this.flagState[QUERY_BASE_TEXT] = true; 
            try
            { 
                index = base.GetCharIndexFromPosition(pt);
            }
            finally
            { 
                this.flagState[QUERY_BASE_TEXT] = false;
            } 
            return index; 
        }
 
        /// 
        ///     Returns the position of the last input character (or if available, the next edit position).
        ///     This is used by base.AppendText.
        ///  
        internal override int GetEndPosition()
        { 
            if( this.flagState[IS_NULL_MASK]) 
            {
                return base.GetEndPosition(); 
            }

            int pos = this.maskedTextProvider.FindEditPositionFrom( this.maskedTextProvider.LastAssignedPosition + 1, forward );
 
            if( pos == MaskedTextProvider.InvalidIndex )
            { 
                pos = this.maskedTextProvider.LastAssignedPosition + 1; 
            }
 
            return pos;
        }

        ///  
        ///     Unsupported method/property.
        ///  
        [ 
        EditorBrowsable(EditorBrowsableState.Never)
        ] 
        public new int GetFirstCharIndexOfCurrentLine()
        {
            return 0;
        } 

        ///  
        ///     Unsupported method/property. 
        /// 
        [ 
        EditorBrowsable(EditorBrowsableState.Never)
        ]
        public new int GetFirstCharIndexFromLine(int lineNumber)
        { 
            return 0;
        } 
 
        /// 
        ///     Gets the string in the text box following the formatting parameters includePrompt and includeLiterals and 
        ///     honoring the PasswordChar property.
        /// 
        private string GetFormattedDisplayString()
        { 
            Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." );
 
            bool includePrompt; 

            if (this.ReadOnly) // Always hide prompt. 
            {
                includePrompt = false;
            }
            else if (this.DesignMode) // Not RO and at design time, always show prompt. 
            {
                includePrompt = true; 
            } 
            else // follow HidePromptOnLeave property.
            { 
                includePrompt = !(this.HidePromptOnLeave && !this.Focused);
            }

            return this.maskedTextProvider.ToString(/*ignorePwdChar */ false, includePrompt, /*includeLiterals*/ true, 0, this.maskedTextProvider.Length); 
        }
 
        ///  
        ///     Unsupported method/property.
        ///     virtual method. 
        /// 
        [
        EditorBrowsable(EditorBrowsableState.Never)
        ] 
        public override int GetLineFromCharIndex(int index)
        { 
            return 0; 
        }
 
        /// 
        ///     Returns the location of the character at the given index.
        /// 
        public override Point GetPositionFromCharIndex(int index) 
        {
            Point pos; 
 
            this.flagState[QUERY_BASE_TEXT] = true;
            try 
            {
                pos = base.GetPositionFromCharIndex(index);
            }
            finally 
            {
                this.flagState[QUERY_BASE_TEXT] = false; 
            } 
            return pos;
        } 

        /// 
        ///     Need to override this method so when get_Text is called we return the text that is actually
        ///     painted in the control so measuring text works on the actual text and not the formatted one. 
        /// 
        internal override Size GetPreferredSizeCore(Size proposedConstraints) 
        { 
            Size size;
 
            this.flagState[QUERY_BASE_TEXT] = true;
            try
            {
                size = base.GetPreferredSizeCore( proposedConstraints ); 
            }
            finally 
            { 
                this.flagState[QUERY_BASE_TEXT] = false;
            } 
            return size;
        }

        ///  
        ///     The selected text in the control according to the CutCopyMaskFormat properties (IncludePrompt/IncludeLiterals).
        ///     This is used in Cut/Copy operations (SelectedText). 
        ///     The prompt character is always replaced with a blank character. 
        /// 
        private string GetSelectedText() 
        {
            Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." );

            int selStart, selLength; 
            base.GetSelectionStartAndLength( out selStart, out selLength );
 
            if( selLength == 0 ) 
            {
                return string.Empty; 
            }

            bool includePrompt   = (CutCopyMaskFormat & MaskFormat.IncludePrompt  ) != 0;
            bool includeLiterals = (CutCopyMaskFormat & MaskFormat.IncludeLiterals) != 0; 

            return this.maskedTextProvider.ToString( /*ignorePasswordChar*/ true, includePrompt, includeLiterals, selStart, selLength ); 
        } 

 
        /// 
        protected override void OnBackColorChanged(EventArgs e)
        {
            base.OnBackColorChanged(e); 
            // VSWhidbey 465708. Force repainting of the entire window frame
            if (Application.RenderWithVisualStyles && this.IsHandleCreated && this.BorderStyle == BorderStyle.Fixed3D) 
            { 
                SafeNativeMethods.RedrawWindow(new HandleRef(this, this.Handle), null, NativeMethods.NullHandleRef, NativeMethods.RDW_INVALIDATE | NativeMethods.RDW_FRAME);
            } 
        }

        /// 
        ///    Overridden to update the newly created handle with the settings of the PasswordChar properties 
        ///    if no mask has been set.
        ///  
        protected override void OnHandleCreated(EventArgs e) 
        {
            base.OnHandleCreated(e); 
            base.SetSelectionOnHandle();

            if( this.flagState[IS_NULL_MASK]&& this.maskedTextProvider.IsPassword )
            { 
                SetEditControlPasswordChar(this.maskedTextProvider.PasswordChar);
            } 
        } 

        ///  
        ///    Raises the IsOverwriteModeChanged event.
        /// 
        [
        EditorBrowsable(EditorBrowsableState.Advanced) 
        ]
        protected virtual void OnIsOverwriteModeChanged(EventArgs e) 
        { 
            EventHandler eh = Events[EVENT_ISOVERWRITEMODECHANGED] as EventHandler;
 
            if (eh != null)
            {
                eh(this, e);
            } 
        }
 
        ///  
        ///     Raises the  event.
        ///  
        protected override void OnKeyDown(KeyEventArgs e)
        {
            base.OnKeyDown(e);
 
            if( this.flagState[IS_NULL_MASK])
            { 
                // Operates as a regular text box base. 
                return;
            } 

            Keys keyCode = e.KeyCode;

            // Special-case Return & Esc since they generate invalid characters we should not process OnKeyPress. 
            if( keyCode == Keys.Return || keyCode == Keys.Escape )
            { 
                this.flagState[HANDLE_KEY_PRESS] = false; 
            }
 

            // Insert is toggled when not modified with some other key (ctrl, shift...).  Note that shift-Insert is
            // same as paste.
            if (keyCode == Keys.Insert && e.Modifiers == Keys.None && this.insertMode == InsertKeyMode.Default) 
            {
                this.flagState[INSERT_TOGGLED] = !this.flagState[INSERT_TOGGLED]; 
                OnIsOverwriteModeChanged(EventArgs.Empty); 
                return;
            } 

            if (e.Control && char.IsLetter((char)keyCode))
            {
                switch (keyCode) 
                {
                    // Unsupported keys should not be handled to allow generatating the corresponding message 
                    // which is handled in the WndProc. 
                    //case Keys.Z:  // ctrl-z == Undo.
                    //case Keys.Y:  // ctrl-y == Redo. 
                    //    e.Handled = true;
                    //    return;

                    // Note: Ctrl-Insert (Copy -Shortcut.CtrlIns) and Shft-Insert (Paste - Shortcut.ShiftIns) are 
                    // handled by the base class and behavior depend on ShortcutsEnabled property.
 
                    // Special cases: usually cases where the native edit control would modify the mask. 
                    case Keys.H:  // ctrl-h == Backspace == '\b'
                        keyCode = Keys.Back; // handle it below. 
                        break;

                    default:
                        // Next OnKeyPress should not be handled to allow Ctrl- to be processed in the 
                        // base class so corresponding messages can be generated (WM_CUT/WM_COPY/WM_PASTE).
                        // Combined characters don't generate OnKeyDown by themselves but they generate OnKeyPress. 
                        this.flagState[HANDLE_KEY_PRESS] = false; 
                        return;
                } 
            }

            if ( keyCode == Keys.Delete || keyCode == Keys.Back ) // Deletion keys.
            { 
                if (!this.ReadOnly)
                { 
                    int selectionLen; 
                    int startPosition;
 
                    base.GetSelectionStartAndLength( out startPosition, out selectionLen );

                    switch (e.Modifiers)
                    { 
                        case Keys.Shift:
                            if( keyCode == Keys.Delete ) 
                            { 
                                keyCode = Keys.Back;
                            } 
                            goto default;

                        case Keys.Control:
                            if( selectionLen == 0 ) // In other case, the selected text should be deleted. 
                            {
                                if( keyCode == Keys.Delete ) // delete to the end of the string. 
                                { 
                                    selectionLen = this.maskedTextProvider.Length - startPosition;
                                } 
                                else // ( keyCode == Keys.Back ) // delete to the beginning of the string.
                                {
                                    selectionLen = startPosition == this.maskedTextProvider.Length /*at end of text*/ ? startPosition : startPosition + 1;
                                    startPosition     = 0; 
                                }
                            } 
                            goto default; 

                        default: 
                            if( !this.flagState[HANDLE_KEY_PRESS] )
                            {
                                this.flagState[HANDLE_KEY_PRESS] = true;
                            } 
                            break;
                    } 
 
                    //
                    // Handle special case when using Korean IME and ending a composition. 
                    //
                    /*  This code is no longer needed after fixing bug#517013 - Left here for reference DON'T DELETE.
                    if ((ImeModeConversion.InputLanguageTable == ImeModeConversion.KoreanTable) && this.flagState[IME_ENDING_COMPOSITION])
                    { 
                        // Korean IME & Edit control weirdness in action:
                        // When pressing Del/Esc/Enter/BckSpc during a composition, the character is converted and a 
                        // corresponding WM_IME_CHAR in placed in the app queue. 

                        if(keyCode == Keys.Back && selectionLen == 0) 
                        {
                            // After the WM_IME_CHAR message is processed, a WM_CHAR message is queued for the backspace; the
                            // edit control processes the message deleting the previous character.  Since we don't pass this
                            // message to the edit control we need to do it ourselves (move position one ahead because it is 
                            // set at the composition window which is inserted in the test string.
                            startPosition++; 
 
                            // Note: If the converted character is invalid and there is a character already placed in the previous
                            // position, it will be deleted.  THIS IS BY DESIGN: It is exactly like the user performing the convertion 
                            // and then pressing backspace, there's no way to differenciate these two scenarios.
                            // See VSWhidbey#200690 for the sequence of messages generated.
                        }
                    } 
                    */
 
                    Delete(keyCode, startPosition, selectionLen); 
                    e.SuppressKeyPress = true;
                } 
            }
        }

 
        /// 
        ///     Raises the  event. 
        ///  
        protected override void OnKeyPress(KeyPressEventArgs e)
        { 
            base.OnKeyPress(e);

            if( this.flagState[IS_NULL_MASK])
            { 
                // Operates as a regular text box base.
                return; 
            } 

            // This key may be a combined key involving a letter, like Ctrl-A; let the native control handle it. 
            if( !this.flagState[HANDLE_KEY_PRESS] )
            {
                this.flagState[HANDLE_KEY_PRESS] = true;
 
                // When the combined key involves a letter, the final character is not a letter. There are some
                // Ctrl combined keys that generate a letter and can be confusing; we do not mean to pass those 
                // characters to the underlying Edit control.  These combinations are: Ctrl-F<#> and Ctrl-Atl- 
                if (!char.IsLetter(e.KeyChar))
                { 
                    return;
                }
            }
 
            if( !this.ReadOnly)
            { 
                // At this point the character needs to be processed ... 

                MaskedTextResultHint hint; 

                int selectionStart;
                int selectionLen;
 
                base.GetSelectionStartAndLength( out selectionStart, out selectionLen );
 
                string oldText = TextOutput; 
                if (PlaceChar(e.KeyChar, selectionStart, selectionLen, this.IsOverwriteMode, out hint))
                { 
                    //if( hint == MaskedTextResultHint.Success || hint == MaskedTextResultHint.SideEffect )
                    if( TextOutput != oldText )
                    {
                        SetText(); // Now set the text in the display. 
                    }
 
                    this.SelectionStart = ++this.caretTestPos; // caretTestPos is updated in PlaceChar. 

                    if (ImeModeConversion.InputLanguageTable == ImeModeConversion.KoreanTable) 
                    {
                        // Korean IMEs complete composition when a character has been fully converted, so the composition string
                        // is only one-character long; once composed we block the IME if there ins't more room in the test string.
 
                        int editPos = this.maskedTextProvider.FindUnassignedEditPositionFrom(this.caretTestPos, forward);
                        if (editPos == MaskedTextProvider.InvalidIndex) 
                        { 
                            ImeComplete();  // Force completion of compostion.
                        } 
                    }
                }
                else
                { 
                    OnMaskInputRejected(new MaskInputRejectedEventArgs(this.caretTestPos, hint)); // caretTestPos is updated in PlaceChar.
                } 
 
                if( selectionLen > 0 )
                { 
                    this.SelectionLength = 0;
                }

                e.Handled = true; 
            }
        } 
 
        /// 
        /// Raises the  event. 
        /// 
        protected override void OnKeyUp(KeyEventArgs e)
        {
            base.OnKeyUp(e); 

            // KeyUp is the last message to be processed so it is the best place to reset these flags. 
 
            if (this.flagState[IME_COMPLETING])
            { 
                this.flagState[IME_COMPLETING] = false;
            }

            if( this.flagState[IME_ENDING_COMPOSITION] ) 
            {
                this.flagState[IME_ENDING_COMPOSITION] = false; 
            } 
        }
 
        /// 
        ///    Raises the MaskChanged event.
        /// 
        [ 
        EditorBrowsable(EditorBrowsableState.Advanced)
        ] 
        protected virtual void OnMaskChanged(EventArgs e) 
        {
            EventHandler eh = Events[EVENT_MASKCHANGED] as EventHandler; 

            if (eh != null)
            {
                eh(this, e); 
            }
        } 
 
        /// 
        ///     Raises the MaskInputRejected event. 
        /// 
        private void OnMaskInputRejected(MaskInputRejectedEventArgs e)
        {
            Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." ); 

            if (this.BeepOnError) 
            { 
                System.Media.SoundPlayer sp = new System.Media.SoundPlayer();
                sp.Play(); 
            }

            MaskInputRejectedEventHandler eh = Events[EVENT_MASKINPUTREJECTED] as MaskInputRejectedEventHandler;
 
            if (eh != null)
            { 
                eh(this, e); 
            }
        } 

        /// 
        ///     Unsupported method/property.
        ///     virtual method. 
        /// 
        [ 
        EditorBrowsable(EditorBrowsableState.Never) 
        ]
        protected override void OnMultilineChanged(EventArgs e) 
        {
        }

        ///  
        ///    Raises the TextAlignChanged event.
        ///  
        protected virtual void OnTextAlignChanged(EventArgs e) 
        {
            EventHandler eh = Events[EVENT_TEXTALIGNCHANGED] as EventHandler; 
            if (eh != null)
            {
                eh(this, e);
            } 
        }
 
 
        /// 
        ///     Raises the TypeValidationCompleted event. 
        /// 
        private void OnTypeValidationCompleted(TypeValidationEventArgs e)
        {
            TypeValidationEventHandler eh = Events[EVENT_VALIDATIONCOMPLETED] as TypeValidationEventHandler; 
            if (eh != null)
            { 
                eh(this, e); 
            }
        } 

        /// 
        ///     Raises the  System.Windows.Forms.Control.Validating event.
        ///     Overridden here to be able to control the order validating events are 
        ///     raised [TypeValidationCompleted - Validating - Validated - Leave - KillFocus]
        ///  
        [EditorBrowsable(EditorBrowsableState.Advanced)] 
        protected override void OnValidating(CancelEventArgs e)
        { 
            // Note: It seems impractical to perform type validation here if the control is read only but we need
            // to be consistent with other TextBoxBase controls which don't check for RO; and we don't want
            // to fix them to avoid introducing breaking changes.
            PerformTypeValidation(e); 
            base.OnValidating(e);
        } 
 
        /// 
        ///    Raises the TextChanged event and related Input/Output text events when mask is null. 
        ///    Overriden here to be able to control order of text changed events.
        /// 
        protected override void OnTextChanged(EventArgs e)
        { 
            // A text changed event handler will most likely query for the Text value, we need to return the
            // formatted one. 
            bool queryBaseText = this.flagState[QUERY_BASE_TEXT]; 
            this.flagState[QUERY_BASE_TEXT] = false;
            try 
            {
                base.OnTextChanged(e);
            }
            finally 
            {
                this.flagState[QUERY_BASE_TEXT] = queryBaseText; 
            } 
        }
        ///  
        ///     Replaces the current selection in the text box specified by the startPosition and selectionLen parameters
        ///     with the contents of the supplied string.
        /// 
        private void Replace(string text, int startPosition, int selectionLen) 
        {
            Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." ); 
            Debug.Assert(text != null, "text is null."); 

            // Clone the MaskedTextProvider so text properties are not modified until the paste operation is 
            // completed.  This is needed in case one of these properties is retreived in a MaskedInputRejected
            // event handler (clipboard text is attempted to be set into the input text char by char).

            MaskedTextProvider clonedProvider = (MaskedTextProvider) this.maskedTextProvider.Clone(); 

            // Cache the current caret position so we restore it in case the text does not change. VSW#498875. 
            int currentCaretPos = this.caretTestPos; 

            // First replace characters in the selection (if any and if any edit positions) until completed, or the test position falls 
            // outside the selection range, or there's no more room in the test string for editable characters.
            // Then insert any remaining characters from the input.

            MaskedTextResultHint hint = MaskedTextResultHint.NoEffect; 
            int endPos = startPosition + selectionLen - 1;
 
            if( this.RejectInputOnFirstFailure ) 
            {
                bool succeeded; 

                succeeded = (startPosition > endPos) ?
                    clonedProvider.InsertAt(text, startPosition, out this.caretTestPos, out hint ) :
                    clonedProvider.Replace(text, startPosition, endPos, out this.caretTestPos, out hint); 

                if( !succeeded ) 
                { 
                    OnMaskInputRejected(new MaskInputRejectedEventArgs(this.caretTestPos, hint));
                } 
            }
            else
            {
                // temp hint used to preserve the 'primary' operation hint (no side effects). 
                MaskedTextResultHint tempHint = hint;
                int testPos; 
 
                foreach (char ch in text)
                { 
                    if( !this.maskedTextProvider.VerifyEscapeChar( ch, startPosition ))  // char won't be escaped, find and edit position for it.
                    {
                        // Observe that we look for a position w/o respecting the selection length, because the input text could be larger than
                        // the number of edit positions in the selection. 
                        testPos = clonedProvider.FindEditPositionFrom(startPosition, forward);
 
                        if( testPos == MaskedTextProvider.InvalidIndex ) 
                        {
                            // this will continue to execute (fail) until the end of the text so we fire the event for each remaining char. 
                            OnMaskInputRejected(new MaskInputRejectedEventArgs(startPosition, MaskedTextResultHint.UnavailableEditPosition));
                            continue;
                        }
 
                        startPosition = testPos;
                    } 
 
                    int length = endPos >= startPosition ? 1 : 0;
 
                    // if length > 0 we are (re)placing the input char in the current startPosition, otherwise we are inserting the input.
                    bool replace = length > 0;

                    if (PlaceChar(clonedProvider, ch, startPosition, length, replace, out tempHint)) 
                    {
                        // caretTestPos is updated in PlaceChar call. 
                        startPosition = this.caretTestPos + 1; 

                        // place char will insert or replace a single character so the hint must be success, and that will be the final operation 
                        // result hint.
                        if (tempHint == MaskedTextResultHint.Success && hint != tempHint)
                        {
                            hint = tempHint; 
                        }
                    } 
                    else 
                    {
                        OnMaskInputRejected(new MaskInputRejectedEventArgs(startPosition, tempHint)); 
                    }
                }

                if (selectionLen > 0) 
                {
                    // At this point we have processed all characters from the input text (if any) but still need to 
                    // remove remaining characters from the selected text (if editable and valid chars). 

                    if (startPosition <= endPos) 
                    {
                        if (!clonedProvider.RemoveAt(startPosition, endPos, out this.caretTestPos, out tempHint))
                        {
                            OnMaskInputRejected(new MaskInputRejectedEventArgs(this.caretTestPos, tempHint)); 
                        }
 
                        // If 'replace' is not actually performed (maybe the input is empty which means 'remove', hint will be whatever 
                        // the 'remove' operation result hint is.
                        if (hint == MaskedTextResultHint.NoEffect && hint != tempHint) 
                        {
                            hint = tempHint;
                        }
                    } 
                }
            } 
 
            bool updateText = TextOutput != clonedProvider.ToString();
 
            // Always set the mtp, the formatted text could be the same but the assigned positions may be different.
            this.maskedTextProvider = clonedProvider;

            // Update text if needed. 
            if( updateText )
            { 
                SetText(); 

                // Update caret position. 
                this.caretTestPos = startPosition;
                base.SelectInternal( this.caretTestPos, 0, this.maskedTextProvider.Length );
            }
            else 
            {
                this.caretTestPos = currentCaretPos; 
            } 

            return; 
        }

        /// 
        ///     Pastes specified text over the currently selected text (if any) shifting upper characters if 
        ///     input is longer than selected text, and/or removing remaining characters from the selection if
        ///     input contains less characters. 
        ///  
        private void PasteInt( string text )
        { 
            Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." );

            int selStart, selLength;
            base.GetSelectionStartAndLength(out selStart, out selLength); 

            if( string.IsNullOrEmpty(text) ) 
            { 
                Delete( Keys.Delete, selStart, selLength );
            } 
            else
            {
                Replace(text, selStart, selLength);
            } 
        }
 
        ///  
        ///     Performs validation of the input string using the provided ValidatingType object (if any).
        ///     Returns an object created from the formatted text. 
        ///     If the CancelEventArgs param is not null, it is assumed the control is leaving focus and
        ///     the validation event chain is being executed (TypeValidationCompleted - Validating - Validated...);
        ///     the value of the CancelEventArgs.Cancel property is the same as the TypeValidationEventArgs.Cancel
        ///     on output (Cancel provides proper handling of focus shifting at the Control class level). 
        ///     Note: The text being validated does not include prompt chars.
        ///  
        private object PerformTypeValidation(CancelEventArgs e) 
        {
            object parseRetVal = null; 

            if (this.validatingType != null)
            {
                string message = null; 

                if (!this.flagState[IS_NULL_MASK]&& this.maskedTextProvider.MaskCompleted == false) 
                { 
                    message = SR.GetString(SR.MaskedTextBoxIncompleteMsg);
                } 
                else
                {
                    string textValue;
 
                    if( !this.flagState[IS_NULL_MASK]) // replace prompt with space.
                    { 
                        textValue = this.maskedTextProvider.ToString(/*includePrompt*/ false, this.IncludeLiterals); 
                    }
                    else 
                    {
                        textValue = base.Text;
                    }
 
                    try
                    { 
                        parseRetVal = Formatter.ParseObject( 
                            textValue,              // data
                            this.validatingType,    // targetType 
                            typeof(string),         // sourceType
                            null,                   // targetConverter
                            null,                   // sourceConverter
                            this.formatProvider,    // formatInfo 
                            null,                   // nullValue
                            Formatter.GetDefaultDataSourceNullValue(this.validatingType));   // dataSourceNullValue 
                    } 
                    catch (Exception exception)
                    { 
                        if (ClientUtils.IsSecurityOrCriticalException(exception))
                        {
                            throw;
                        } 

                        if (exception.InnerException != null) // Outer exception is a generic TargetInvocationException. 
                        { 
                            exception = exception.InnerException;
                        } 

                        message = exception.GetType().ToString() + ": " + exception.Message;
                    }
                } 

                bool isValidInput = false; 
                if (message == null) 
                {
                    isValidInput = true; 
                    message = SR.GetString(SR.MaskedTextBoxTypeValidationSucceeded);
                }

                TypeValidationEventArgs tve = new TypeValidationEventArgs(this.validatingType, isValidInput, parseRetVal, message); 
                OnTypeValidationCompleted(tve);
 
                if( e != null ) 
                {
                    e.Cancel = tve.Cancel; 
                }
            }

            return parseRetVal; 
        }
 
        ///  
        ///     Insert or replaces the specified character into the control's text and updates the caret position.
        ///     If overwrite is true, it replaces the character at the selection start position. 
        /// 
        private bool PlaceChar(char ch, int startPosition, int length, bool overwrite,
            out MaskedTextResultHint hint)
        { 
            return PlaceChar(this.maskedTextProvider, ch, startPosition, length, overwrite, out hint );
        } 
 
        /// 
        ///     Override version to be able to perform the operation on a cloned provider. 
        /// 
        private bool PlaceChar(MaskedTextProvider provider, char ch, int startPosition, int length, bool overwrite,
            out MaskedTextResultHint hint)
        { 
            Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." );
 
            this.caretTestPos = startPosition; 

            if (startPosition < this.maskedTextProvider.Length) 
            {
                if (length > 0)  // Replacing selection with input char.
                {
                    int endPos = startPosition + length - 1; 
                    return provider.Replace(ch, startPosition, endPos, out this.caretTestPos, out hint);
                } 
                else 
                {
                    if (overwrite) 
                    {
                        // overwrite character at next edit position from startPosition (inclusive).
                        return provider.Replace(ch, startPosition, out this.caretTestPos, out hint);
                    } 
                    else // insert.
                    { 
                        return provider.InsertAt(ch, startPosition, out this.caretTestPos, out hint); 
                    }
                } 
            }

            hint = MaskedTextResultHint.UnavailableEditPosition;
            return false; 
        }
 
        ///  
        ///     :
        ///     Processes a command key. This method is called during message 
        ///     pre-processing to handle command keys. Command keys are keys that always
        ///     take precedence over regular input keys. Examples of command keys
        ///     include accelerators and menu shortcuts. The method must return true to
        ///     indicate that it has processed the command key, or false to indicate 
        ///     that the key is not a command key.
        /// 
        ///     processCmdKey() first checks if the control has a context menu, and if 
        ///     so calls the menu's processCmdKey() to check for menu shortcuts. If the
        ///     command key isn't a menu shortcut, and if the control has a parent, the 
        ///     key is passed to the parent's processCmdKey() method. The net effect is
        ///     that command keys are "bubbled" up the control hierarchy.
        ///
        ///     When overriding processCmdKey(), a control should return true to 
        ///     indicate that it has processed the key. For keys that aren't processed by
        ///     the control, the result of "base.processCmdKey()" should be returned. 
        /// 
        ///     Controls will seldom, if ever, need to override this method.
        ///      
        ///
        ///     Implements the handling of Ctrl+A (select all). Note: Code copied from TextBox.
        /// 
        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] 
        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        { 
            // 
            // The base class should be called first because it implements ShortcutsEnabled,
            // which takes precedence over Ctrl+A 
            //
            bool msgProcessed = base.ProcessCmdKey(ref msg, keyData);

            if (!msgProcessed) 
            {
                if ((int)keyData == (int)Shortcut.CtrlA) 
                { 
                    base.SelectAll();
                    msgProcessed = true; // This prevents generating a WM_CHAR for 'A'. 
                }
            }

            return msgProcessed; 
        }
 
        ///  
        ///     We need to override this method so we can handle input language changes properly.  Control
        ///     doesn't handle the WM_CHAR messages generated after WM_IME_CHAR messages, it passes them 
        ///     to DefWndProc (the characters would be displayed in the text box always).
        ///
        /// 
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] 
        protected internal override bool ProcessKeyMessage(ref Message m)
        { 
            // call base's method so the WM_CHAR and other messages are processed; this gives Control the 
            // chance to flush all pending WM_CHAR processing after WM_IME_CHAR messages are generated.
 
            bool msgProcessed = base.ProcessKeyMessage(ref m);

            if (this.flagState[IS_NULL_MASK])
            { 
                return msgProcessed; // Operates as a regular text box base.
            } 
 
            // If this WM_CHAR message is sent after WM_IME_CHAR, we ignore it since we already processed
            // the corresponding WM_IME_CHAR message. 

            if( m.Msg == NativeMethods.WM_CHAR && base.ImeWmCharsToIgnore > 0 ) {
                return true;    // meaning, we handled the message so it is not passed to the default WndProc.
            } 

            return msgProcessed; 
        } 

 
        /// 
        ///     Designe time support for resetting Culture property..
        /// 
        private void ResetCulture() 
        {
            this.Culture = CultureInfo.CurrentCulture; 
        } 

        ///  
        ///     Unsupported method/property.
        /// 
        [
        EditorBrowsable(EditorBrowsableState.Never) 
        ]
        public new void ScrollToCaret() 
        { 
        }
 
        /// 
        ///     Sets the underlying MaskedTextProvider object.  Used when the control is initialized
        ///     and one of its properties, backed up by the MaskedTextProvider, changes; this requires
        ///     recreating the provider because it is immutable. 
        /// 
        private void SetMaskedTextProvider( MaskedTextProvider newProvider ) 
        { 
            SetMaskedTextProvider( newProvider, null);
        } 

        /// 
        ///     Overload to allow for passing the text when the mask is being changed from null,
        ///     in this case the maskedTextProvider holds backend info only (not the text). 
        /// 
        private void SetMaskedTextProvider( MaskedTextProvider newProvider, string textOnInitializingMask ) 
        { 
            Debug.Assert( newProvider != null, "Initializing from a null MaskProvider ref." );
 
            // Set R/W properties.
            newProvider.IncludePrompt    = this.maskedTextProvider.IncludePrompt;
            newProvider.IncludeLiterals  = this.maskedTextProvider.IncludeLiterals;
            newProvider.SkipLiterals     = this.maskedTextProvider.SkipLiterals; 
            newProvider.ResetOnPrompt    = this.maskedTextProvider.ResetOnPrompt;
            newProvider.ResetOnSpace     = this.maskedTextProvider.ResetOnSpace; 
 
            // If mask not initialized and not initializing it, the new provider is just a property backend.
            // Change won't have any effect in text. 
            if( this.flagState[IS_NULL_MASK] && textOnInitializingMask == null)
            {
                this.maskedTextProvider = newProvider;
                return; 
            }
 
            int testPos = 0; 
            bool raiseOnMaskInputRejected = false; // Raise if new provider rejects old text.
            MaskedTextResultHint hint = MaskedTextResultHint.NoEffect; 
            MaskedTextProvider oldProvider = this.maskedTextProvider;

            // Attempt to add previous text.
            // If the mask is the same, we need to preserve the caret and character positions if the text is added successfully. 
            bool preserveCharPos = oldProvider.Mask == newProvider.Mask;
 
            // Cache text output text before setting the new provider to determine whether we need to raise the TextChanged event. 
            string oldText;
 
            // NOTE: Whenever changing the MTP, the text is lost if any character in the old text violates the new provider's mask.

            if( textOnInitializingMask != null ) // Changing Mask (from null), which is the only RO property that requires passing text.
            { 
                oldText  = textOnInitializingMask;
                raiseOnMaskInputRejected = !newProvider.Set( textOnInitializingMask, out testPos, out hint ); 
            } 
            else
            { 
                oldText  = TextOutput;

                // We need to attempt to set the input characters one by one in the edit positions so they are not
                // escaped. 
                int assignedCount = oldProvider.AssignedEditPositionCount;
                int srcPos = 0; 
                int dstPos = 0; 

                while( assignedCount > 0 ) 
                {
                    srcPos = oldProvider.FindAssignedEditPositionFrom( srcPos, forward );
                    Debug.Assert( srcPos != MaskedTextProvider.InvalidIndex, "InvalidIndex unexpected at this time." );
 
                    if (preserveCharPos)
                    { 
                        dstPos = srcPos; 
                    }
                    else 
                    {
                        dstPos = newProvider.FindEditPositionFrom(dstPos, forward);

                        if (dstPos == MaskedTextProvider.InvalidIndex) 
                        {
                            newProvider.Clear(); 
 
                            testPos = newProvider.Length;
                            hint = MaskedTextResultHint.UnavailableEditPosition; 
                            break;
                        }
                    }
 
                    if( !newProvider.Replace( oldProvider[srcPos], dstPos, out testPos, out hint ))
                    { 
                        preserveCharPos = false; 
                        newProvider.Clear();
                        break; 
                    }

                    srcPos++;
                    dstPos++; 
                    assignedCount--;
                } 
 
                raiseOnMaskInputRejected = !MaskedTextProvider.GetOperationResultFromHint(hint);
            } 


            // Set provider.
            this.maskedTextProvider = newProvider; 

            if( this.flagState[IS_NULL_MASK] ) 
            { 
                this.flagState[IS_NULL_MASK] = false;
            } 

            // Raising events need to be done only after the new provider has been set so the MTB is in a state where properties
            // can be queried from event handlers safely.
            if( raiseOnMaskInputRejected ) 
            {
                OnMaskInputRejected(new MaskInputRejectedEventArgs(testPos, hint)); 
            } 

            if( newProvider.IsPassword ) 
            {
                // Reset native edit control so the MaskedTextBox will take control over the characters that
                // need to be replaced with the password char (the input text characters).
                // MTB takes over. 
                SetEditControlPasswordChar('\0');
            } 
 
            EventArgs e = EventArgs.Empty;
 
            if (textOnInitializingMask != null /*changing mask from null*/ || oldProvider.Mask != newProvider.Mask)
            {
                OnMaskChanged(e);
            } 

            SetWindowText(GetFormattedDisplayString(), oldText != TextOutput, preserveCharPos); 
        } 

        ///  
        ///     Sets the control's text to the formatted text obtained from the underlying MaskedTextProvider.
        ///     TextChanged is raised always, this assumes the display or the output text changed.
        ///     The caret position is lost (unless cached somewhere else like when lossing the focus).
        ///     This is the common way of changing the text in the control. 
        /// 
        private void SetText() 
        { 
            SetWindowText(GetFormattedDisplayString(), true, false);
        } 

        /// 
        ///     Sets the control's text to the formatted text obtained from the underlying MaskedTextProvider.
        ///     TextChanged is not raised. [PasswordChar] 
        ///     The caret position is preserved.
        ///  
        private void SetWindowText() 
        {
            SetWindowText(GetFormattedDisplayString(), false, true); 
        }

        /// 
        ///     Sets the text directly in the underlying edit control to the value specified. 
        ///     The 'raiseTextChangedEvent' param determines whether TextChanged event is raised or not.
        ///     The 'preserveCaret' param determines whether an attempt to preserve the caret position should be made or not 
        ///     after the call to SetWindowText (WindowText) is performed. 
        /// 
        private void SetWindowText(string text, bool raiseTextChangedEvent, bool preserveCaret) 
        {
            this.flagState[QUERY_BASE_TEXT] = true;

            try 
            {
                if( preserveCaret ) 
                { 
                    this.caretTestPos = this.SelectionStart;
                } 

                WindowText = text;  // this calls Win32::SetWindowText directly, no OnTextChanged raised.

                if( raiseTextChangedEvent ) 
                {
                    OnTextChanged(EventArgs.Empty); 
                } 

                if( preserveCaret ) 
                {
                    this.SelectionStart = this.caretTestPos;
                }
            } 
            finally
            { 
                this.flagState[QUERY_BASE_TEXT] = false; 
            }
        } 

        /// 
        ///     Designe time support for checking if Culture value in the designer should be serialized.
        ///  
        private bool ShouldSerializeCulture()
        { 
            return !CultureInfo.CurrentCulture.Equals(this.Culture); 
        }
 
        /// 
        ///       Undoes the last edit operation in the text box.
        ///       Unsupported property/method.
        ///       WndProc ignores EM_UNDO. 
        /// 
        [ 
        EditorBrowsable(EditorBrowsableState.Never) 
        ]
        public new void Undo() 
        {
        }

        ///  
        ///       Forces type validation.  Returns the validated text value.
        ///  
        public object ValidateText() 
        {
            return PerformTypeValidation(null); 
        }

        /// 
        ///     Deletes all input characters in the current selection. 
        /// 
        private bool WmClear() 
        { 
            Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." );
 
            if( !this.ReadOnly )
            {
                int selStart, selLength;
                base.GetSelectionStartAndLength( out selStart, out selLength ); 
                Delete(Keys.Delete, selStart, selLength);
                return true; 
            } 

            return false; 
        }

        /// 
        ///     Copies current selection text to the clipboard, formatted according to the IncludeLiterals properties but 
        ///     ignoring the prompt character.
        ///     Returns true if the operation succeeded, false otherwise. 
        ///  
        private bool WmCopy()
        { 
            Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." );

            if (this.maskedTextProvider.IsPassword) // cannot copy password to clipboard.
            { 
                return false;
            } 
 
            string text = GetSelectedText();
 
            try
            {
                // SECREVIEW : Copy needs to work even if the OwnClipboard permission isn't available. We need to assert here.
                //             This assert is ok, observe that if the control is in password mode it won't reach this point, 
                //             see code above.
                //             Be careful if code is added after the security assert, you may need to put it in a try-finally 
                //             block to revert the security assert. 
                IntSecurity.ClipboardWrite.Assert();
 
                if (text.Length == 0)
                {
                    Clipboard.Clear();
                } 
                else
                { 
                    Clipboard.SetText(text); 
                }
            } 
            catch (Exception ex)
            {
                // Note: Sometimes the above operation throws but it successfully sets the
                // data in the clipboard. This usually happens when the Application's Main 
                // is not attributed with [STAThread].
                if (ClientUtils.IsSecurityOrCriticalException(ex)) 
                { 
                    throw;
                } 
            }
            return true;
        }
 
        /// 
        ///     Processes the WM_IME_COMPOSITION message when using Korean IME. 
        ///     Korean IME uses the control's caret as the composition string (it processes only one character at a time), 
        ///     we need to have special message handling for it.
        ///     Returns true if the message is handled, false otherwise. 
        /// 
        private bool WmImeComposition(ref Message m)
        {
            Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." ); 

#if DEBUG 
            if (this.ReadOnly || this.maskedTextProvider.IsPassword) 
            {
                // This should have been already handled by the ReadOnly, PasswordChar and ImeMode properties. 
                Debug.Assert(this.ImeMode == ImeMode.Disable, "IME enabled when in RO or Pwd mode.");
            }
#endif
            // Non-Korean IMEs complete compositon when all characters in the string has been composed (when user hits enter); 
            // Currently, we don't support checking the composition string characters because it would require similar logic
            // as the MaskedTextBox itself. 
 
            if (ImeModeConversion.InputLanguageTable == ImeModeConversion.KoreanTable)
            { 
                byte imeConvertionType = imeConvertionNone;

                // Check if there's an update to the compositon string:
                if ((m.LParam.ToInt32() & NativeMethods.GCS_COMPSTR) != 0) 
                {
                    // The character in the composition has been updated but not yet converted. 
                    imeConvertionType = imeConvertionUpdate; 
                }
                else if ((m.LParam.ToInt32() & NativeMethods.GCS_RESULTSTR) != 0) 
                {
                    // The character(s) in the composition has been fully converted.
                    imeConvertionType = imeConvertionCompleted;
                } 

                // Process any update in the composition string. 
                if (imeConvertionType != imeConvertionNone) 
                {
                    if (this.flagState[IME_ENDING_COMPOSITION]) 
                    {
                        // If IME is completing the convertion, we don't want to process further characters.
                        return this.flagState[IME_COMPLETING];
                    } 
                }
            } 
 
            return false; //message not handled.
        } 

        /// 
        ///     Processes the WM_IME_STARTCOMPOSITION message.
        ///     Returns true if the message is handled, false otherwise. 
        /// 
        private bool WmImeStartComposition() 
        { 
            Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." );
 
            // Position the composition window in a valid place.

            int startPosition, selectionLen;
            base.GetSelectionStartAndLength( out startPosition, out selectionLen ); 

            int startEditPos = this.maskedTextProvider.FindEditPositionFrom( startPosition, forward ); 
 
            if( startEditPos != MaskedTextProvider.InvalidIndex )
            { 
                if (selectionLen > 0  && (ImeModeConversion.InputLanguageTable == ImeModeConversion.KoreanTable))
                {
                    // Korean IME: We need to delete the selected text and reposition the caret so the IME processes one
                    // character only, otherwise it would overwrite the selection with the caret (composition string), 
                    // deleting a portion of the mask.
 
                    int endEditPos = this.maskedTextProvider.FindEditPositionFrom(startPosition + selectionLen - 1, backward); 

                    if (endEditPos >= startEditPos) 
                    {
                        selectionLen = endEditPos - startEditPos + 1;
                        Delete(Keys.Delete, startEditPos, selectionLen);
                    } 
                    else
                    { 
                        ImeComplete(); 
                        OnMaskInputRejected(new MaskInputRejectedEventArgs(startPosition, MaskedTextResultHint.UnavailableEditPosition));
                        return true; 
                    }
                }

                // update caret position. 
                if( startPosition != startEditPos )
                { 
                    this.caretTestPos   = startEditPos; 
                    this.SelectionStart = this.caretTestPos;
                } 

                this.SelectionLength = 0;
            }
            else 
            {
                ImeComplete(); 
                OnMaskInputRejected(new MaskInputRejectedEventArgs(startPosition, MaskedTextResultHint.UnavailableEditPosition)); 
                return true;
            } 

            return false;
        }
 

        ///  
        ///     Processes the WM_PASTE message. Copies the text from the clipboard, if is valid, 
        ///     formatted according to the mask applied to this control.
        ///     Returns true if the operation succeeded, false otherwise. 
        /// 
        private void WmPaste()
        {
            Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." ); 

            if( this.ReadOnly ) 
            { 
                return;
            } 

            // Get the text from the clipboard.

            string text; 

            try 
            { 
                IntSecurity.ClipboardRead.Assert();
                text = Clipboard.GetText(); 
            }
            catch (Exception ex)
            {
                if (ClientUtils.IsSecurityOrCriticalException(ex)) 
                {
                    throw; 
                } 
                Debug.Fail(ex.ToString());
                return; 
            }

            PasteInt( text );
        } 

        private void WmPrint(ref Message m) { 
            base.WndProc(ref m); 
            if ((NativeMethods.PRF_NONCLIENT & (int)m.LParam) != 0 && Application.RenderWithVisualStyles && this.BorderStyle == BorderStyle.Fixed3D) {
                IntSecurity.UnmanagedCode.Assert(); 
                try {
                    using (Graphics g = Graphics.FromHdc(m.WParam)) {
                        Rectangle rect = new Rectangle(0, 0, this.Size.Width - 1, this.Size.Height - 1);
                        g.DrawRectangle(new Pen(VisualStyleInformation.TextControlBorder), rect); 
                        rect.Inflate(-1, -1);
                        g.DrawRectangle(SystemPens.Window, rect); 
                    } 
                }
                finally { 
                    CodeAccessPermission.RevertAssert();
                }
            }
        } 

        ///  
        ///     We need to override the WndProc method to have full control over what characters can be 
        ///     displayed in the text box; particularly, we have special handling when IME is turned on.
        ///  
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        protected override void WndProc(ref Message m)
        {
            // Handle messages for special cases (unsupported operations or cases where mask doesn not matter). 
            switch (m.Msg)
            { 
                case NativeMethods.WM_PRINT: 
                    WmPrint(ref m);
                    return; 
                case NativeMethods.WM_CONTEXTMENU:
                case NativeMethods.EM_CANUNDO:
                    base.ClearUndo(); // resets undo buffer.
                    base.WndProc(ref m); 
                    return;
 
                case NativeMethods.EM_SCROLLCARET:  // No scroll for single-line control. 
                case NativeMethods.EM_LIMITTEXT:    // Max/Min text is defined by the mask.
                case NativeMethods.EM_UNDO: 
                case NativeMethods.WM_UNDO:
                    return;

                default: 
                    break;  // continue.
            } 
 
            if( this.flagState[IS_NULL_MASK])
            { 
                base.WndProc(ref m); // Operates as a regular text box base.
                return;
            }
 
            switch (m.Msg)
            { 
                case NativeMethods.WM_IME_STARTCOMPOSITION: 
                    if( WmImeStartComposition() )
                    { 
                        break;
                    }
                    goto default;
 
                case NativeMethods.WM_IME_ENDCOMPOSITION:
                    this.flagState[IME_ENDING_COMPOSITION] = true; 
                    goto default; 

                case NativeMethods.WM_IME_COMPOSITION: 
                    if( WmImeComposition( ref m ) )
                    {
                        break;
                    } 
                    goto default;
 
                case NativeMethods.WM_CUT: 
                    if (!this.ReadOnly && WmCopy())
                    { 
                        WmClear();
                    }
                    break;
 
                case NativeMethods.WM_COPY:
                    WmCopy(); 
                    break; 

                case NativeMethods.WM_PASTE: 
                    WmPaste();
                    break;

                case NativeMethods.WM_CLEAR: 
                    WmClear();
                    break; 
 
                case NativeMethods.WM_KILLFOCUS:
                    base.WndProc(ref m); 
                    WmKillFocus();
                    break;

                case NativeMethods.WM_SETFOCUS: 
                    WmSetFocus();
                    base.WndProc(ref m); 
                    break; 

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

        ///  
        ///     Processes the WM_KILLFOCUS message. Updates control's text replacing promp chars with space. 
        /// 
        private void WmKillFocus() 
        {
            Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." );

            base.GetSelectionStartAndLength( out this.caretTestPos, out this.lastSelLength ); 

            if (this.HidePromptOnLeave && !this.MaskFull) 
            { 
                SetWindowText(); // Update text w/ no prompt.
 
                // We need to update selection info in case the control is queried for it while it doesn't have the focus.
                base.SelectInternal( this.caretTestPos, this.lastSelLength, this.maskedTextProvider.Length );
            }
        } 

        ///  
        ///     Processes the WM_SETFOCUS message. Updates control's text with formatted text according to 
        ///     the include prompt property.
        ///  
        private void WmSetFocus()
        {
            Debug.Assert( !this.flagState[IS_NULL_MASK], "This method must be called when a Mask is provided." );
 
            if (this.HidePromptOnLeave && !this.MaskFull) // Prompt will show up.
            { 
                SetWindowText(); 
            }
 
            // Restore previous selection. Do this always (as opposed to within the condition above as in WmKillFocus)
            // because HidePromptOnLeave could have changed while the control did not have the focus.
            base.SelectInternal( this.caretTestPos, this.lastSelLength, this.maskedTextProvider.Length );
        } 
    }
} 
 

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