WindowsRichEdit.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / UIAutomation / Win32Providers / MS / Internal / AutomationProxies / WindowsRichEdit.cs / 1305600 / WindowsRichEdit.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: HWND-based RichEdit Proxy 
//
// History: 
//          nbatchu                 Created
//          Jean-Francois Peyroux.  Revised
//
//--------------------------------------------------------------------------- 
using System;
using System.Collections; 
using System.ComponentModel; 
using System.Diagnostics;
using System.Runtime.InteropServices; 
using System.Text;
using System.Windows;
using System.Windows.Automation;
using System.Windows.Automation.Provider; 
using System.Windows.Automation.Text;
using Accessibility; 
using MS.Win32; 

namespace MS.Internal.AutomationProxies 
{
    class WindowsRichEdit : ProxyHwnd, IValueProvider, ITextProvider
    {
        // ----------------------------------------------------- 
        //
        // Constructors 
        // 
        // -----------------------------------------------------
 
        #region Constructors

        WindowsRichEdit (IntPtr hwnd, ProxyFragment parent, int style)
            : base( hwnd, parent, style ) 
        {
            _type = WindowsEditBox.GetEditboxtype(hwnd); 
            if (IsMultiline) 
            {
                _cControlType = ControlType.Document; 
            }
            else
            {
                _cControlType = ControlType.Edit; 
            }
 
            _fIsKeyboardFocusable = true; 

            // support for events 
            _createOnEvent = new WinEventTracker.ProxyRaiseEvents (RaiseEvents);
        }

        #endregion Initialization 

        #region Proxy Create 
 
        // Static Create method called by UIAutomation to create this proxy.
        // returns null if unsuccessful 
        internal static IRawElementProviderSimple Create(IntPtr hwnd, int idChild, int idObject)
        {
            return Create(hwnd, idChild);
        } 

        internal static IRawElementProviderSimple Create(IntPtr hwnd, int idChild) 
        { 
            // Something is wrong if idChild is not zero
            if (idChild != 0) 
            {
                Debug.Assert (idChild == 0, "Invalid Child Id, idChild != 0");
                throw new ArgumentOutOfRangeException("idChild", idChild, SR.Get(SRID.ShouldBeZero));
            } 

            return new WindowsRichEdit(hwnd, null, 0); 
        } 

        // Static Create method called by the event tracker system 
        internal static void RaiseEvents (IntPtr hwnd, int eventId, object idProp, int idObject, int idChild)
        {
            if (idObject != NativeMethods.OBJID_VSCROLL && idObject != NativeMethods.OBJID_HSCROLL)
            { 
                WindowsRichEdit wtv = new WindowsRichEdit (hwnd, null, 0);
 
                // If this event means the selection may have changed, raise that event 
                // here instead of relying on the generic DispatchEvents mechanism below.
                // The RichTextEdit provider needs to handle this event specially. 
                if (eventId == NativeMethods.EventObjectLocationChange
                    && idObject == NativeMethods.OBJID_CARET)
                {
                    wtv.RaiseTextSelectionEvent(eventId, idProp, idObject, idChild); 
                }
                else 
                { 
                    wtv.DispatchEvents(eventId, idProp, idObject, idChild);
                } 
            }
        }

        #endregion Proxy Create 

        //------------------------------------------------------ 
        // 
        //  Patterns Implementation
        // 
        //-----------------------------------------------------

        #region ProxySimple Interface
 
        // Returns a pattern interface if supported.
        internal override object GetPatternProvider(AutomationPattern iid) 
        { 
            try
            { 
                if (iid == ValuePattern.Pattern && !IsMultiline)
                {
                    if (IsDocument())
                    { 
                        EnsureTextDocument();
                    } 
                    return this; 
                }
 
                // text pattern is supported for non-password boxes
                if (iid == TextPattern.Pattern && _type != WindowsEditBox.EditboxType.Password && IsDocument())
                {
                    EnsureTextDocument(); 
                    return this;
                } 
 
                return null;
            } 
                //If tom.dll is missing
            catch (System.IO.FileNotFoundException)
            {
                return null; 
            }
        } 
 
        // Process all the Logical and Raw Element Properties
        internal override object GetElementProperty(AutomationProperty idProp) 
        {
            if (idProp == AutomationElement.IsPasswordProperty)
            {
                return _type == WindowsEditBox.EditboxType.Password; 
            }
            else if (idProp == AutomationElement.NameProperty) 
            { 
                // Per ControlType.Edit spec if there is no static text
                // label for an Edit then it must NEVER return the contents 
                // of the edit as the Name property. This relies on the
                // default ProxyHwnd impl looking for a label for Name and
                // not using WM_GETTEXT on the edit hwnd.
                string name = base.GetElementProperty(idProp) as string; 
                if (string.IsNullOrEmpty(name))
                { 
                    // Stop UIA from asking other providers 
                    return AutomationElement.NotSupported;
                } 

                return name;
            }
 
            return base.GetElementProperty(idProp);
        } 
        #endregion ProxySimple Interface 

        #region Value Pattern 

        // Sets the text of the edit.
        void IValueProvider.SetValue(string str)
        { 
            // Check if the window is disabled
            if (!SafeNativeMethods.IsWindowEnabled(_hwnd)) 
            { 
                throw new ElementNotEnabledException();
            } 

            if (Misc.IsBitSet(WindowStyle, NativeMethods.ES_READONLY))
            {
                throw new InvalidOperationException(SR.Get(SRID.ValueReadonly)); 
            }
 
            // check if control only accepts numbers 
            if (Misc.IsBitSet(WindowStyle, NativeMethods.ES_NUMBER) && !WindowsFormsHelper.IsWindowsFormsControl(_hwnd))
            { 
                // check if string contains any non-numeric characters.
                foreach (char ch in str)
                {
                    if (char.IsLetter(ch)) 
                    {
                        throw new ArgumentException(SR.Get(SRID.NotAValidValue, str), "val"); 
                    } 
                }
            } 

            // bug# 11147, Text/edit box should not enter more characters than what is allowed through keyboard.
            // Determine the max number of chars this editbox accepts
 
            int result = Misc.ProxySendMessageInt(_hwnd, NativeMethods.EM_GETLIMITTEXT, IntPtr.Zero, IntPtr.Zero);
            if (result < str.Length) 
            { 
                throw new InvalidOperationException (SR.Get(SRID.OperationCannotBePerformed));
            } 

            // Send the message...
            result = Misc.ProxySendMessageInt(_hwnd, NativeMethods.WM_SETTEXT, IntPtr.Zero, new StringBuilder(str));
            if (result != 1) 
            {
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); 
            } 
        }
 
        // Request to get the value that this UI element is representing as a string
        string IValueProvider.Value
        {
            get 
            {
                return GetValue(); 
            } 
        }
 
        bool IValueProvider.IsReadOnly
        {
            get
            { 
                return IsReadOnly();
            } 
        } 

        #endregion 

        #region Text Pattern Methods

        ITextRangeProvider [] ITextProvider.GetSelection() 
        {
            // we must have called EnsureTextDocument() before arriving here. 
            Debug.Assert(_document != null); 

            // clone a range from the documents selection 
            ITextRange range = null;
            ITextSelection selection = _document.Selection;
            if (selection != null)
            { 
                // duplicate the selection range since we don't want their modifications to affect the selection
                range = selection.GetDuplicate(); 
 
                // for future reference: active endpoint is
                // ((selection.Flags & TomSelectionFlags.tomSelStartActive) == TomSelectionFlags.tomSelStartActive) ? TextPatternRangeEndpoint.Start : TextPatternRangeEndpoint.End; 
            }

            if (range == null)
                return new ITextRangeProvider[] { }; 
            else
                return new ITextRangeProvider[] { new WindowsRichEditRange(range, this) }; 
        } 

        ITextRangeProvider [] ITextProvider.GetVisibleRanges() 
        {
            ITextRange range = GetVisibleRange();

            if (range == null) 
                return new ITextRangeProvider[] { };
            else 
                return new ITextRangeProvider[] { new WindowsRichEditRange(range, this) }; 
        }
 
        ITextRangeProvider ITextProvider.RangeFromChild(IRawElementProviderSimple childElement)
        {
            // we don't have any children so this call must be in error.
            // if we implement children for hyperlinks and embedded objects then we'll need to change this. 
            throw new InvalidOperationException(SR.Get(SRID.RichEditTextPatternHasNoChildren,GetType().FullName));
        } 
 
        ITextRangeProvider ITextProvider.RangeFromPoint(Point screenLocation)
        { 
            // we must have called EnsureTextDocument() before arriving here.
            Debug.Assert(_document != null);

            // TextPattern has verified that the point is inside our client area so we don't need to check for that. 

            // get the degenerate range at the point 
            // we're assuming ITextDocument::RangeFromPoint always returns a degenerate range 
            ITextRange range = _document.RangeFromPoint((int)screenLocation.X, (int)screenLocation.Y);
            Debug.Assert(range.Start == range.End); 

            // if you wanted to get the character under the point instead of the degenerate range nearest
            // the point, then you would add:
 
            //// if the point is within the character to the right then expand the degenerate range to
            //// include the character. 
            //Rect rect; 
            //range.MoveEnd(TomUnit.tomCharacter, 1);
            //rect = WindowsRichEditRange.GetSingleLineRangeRectangle(range, BoundingRectangle); 
            //if (!rect.Contains(screenLocation))
            //{
            //    // if the point is within the character to the left then expand the degenerate range
            //    // to include the character. 
            //    range.Collapse(TomStartEnd.tomStart);
            //    range.MoveStart(TomUnit.tomCharacter, -1); 
            //    rect = WindowsRichEditRange.GetSingleLineRangeRectangle(range, BoundingRectangle); 
            //    if (!rect.Contains(screenLocation))
            //    { 
            //        // the point is not in an adjacent character cell so leave it degenerate.
            //        range.Collapse(TomStartEnd.tomEnd);
            //    }
            //} 

            return range != null ? new WindowsRichEditRange(range, this) : null; 
        } 

        #endregion TextPattern Methods 

        #region TextPattern Properties

        ITextRangeProvider ITextProvider.DocumentRange 
        {
            get 
            { 
                // we must have called EnsureTextDocument() before arriving here.
                Debug.Assert(_document != null); 

                // create a text range that covers the entire main story.
                ITextRange range = _document.Range(0, 0);
                range.SetRange(0, range.StoryLength); 
                return new WindowsRichEditRange(range, this);
            } 
        } 

        // THESE PROPERTIES ARE REMOVED IN 8.2 BREAKING CHANGE. 
        //


 

 
 

 



 

 
 

 



 

 
 

 

        SupportedTextSelection ITextProvider.SupportedTextSelection
        {
            get 
            {
                return SupportedTextSelection.Single; 
            } 
        }
 
        #endregion Text Properties

        //------------------------------------------------------
        // 
        //  Internal Methods
        // 
        //------------------------------------------------------ 

        #region Internal Methods 

        // returns the range that is visible in the RichEdit window
        internal ITextRange GetVisibleRange()
        { 
            // get a range from the center point of the client rectangle
            Rect rect = BoundingRectangle; 
            int x = ((int)rect.Left + (int)rect.Right) / 2; 
            int y = ((int)rect.Top + (int)rect.Bottom) / 2;
            ITextRange range = _document.RangeFromPoint(x, y); 

            // expand it to fill the window.
            range.Expand(TomUnit.tomWindow);
 
            // There is a bug with RichEdit 3.0.  The expand to tomWindow may gets 0 as the range's cpBegin (Start).
            // So need to trim off what is outside of the window. 
            int start = range.Start; 
            // The ITextRange::SetRange method sets this range�s Start = min(cp1, cp2) and End = max(cp1, cp2).
            // If the range is a nondegenerate selection, cp2 is the active end; if it�s a degenerate selection, 
            // the ambiguous cp is displayed at the start of the line (rather than at the end of the previous line).
            // Set the end to the start and the start to the end to create an ambiguous cp.
            range.SetRange(range.End, range.Start);
            bool gotPoint = WindowsRichEditRange.RangeGetPoint(range, TomGetPoint.tomStart, out x, out y); 
            while (!gotPoint || !Misc.PtInRect(ref rect, x, y))
            { 
                range.MoveStart(TomUnit.tomWord, 1); 
                gotPoint = WindowsRichEditRange.RangeGetPoint(range, TomGetPoint.tomStart, out x, out y);
            } 

            if (start != range.Start)
            {
                // The trimming was done based on the left edge of the range.  The last visiable partial 
                // character/word has been also added back into the range, need to remove it.  Do the comparing
                // against the characters right edge and the window rectangle. 
                ITextRange rangeAdjust = _document.Range(0, range.Start - 1); 
                gotPoint = WindowsRichEditRange.RangeGetPoint(rangeAdjust, TomGetPoint.TA_BOTTOM | TomGetPoint.TA_RIGHT, out x, out y);
 
                while (gotPoint && Misc.PtInRect(ref rect, x, y) && rangeAdjust.Start != rangeAdjust.End)
                {
                    rangeAdjust.MoveEnd(TomUnit.tomCharacter, -1);
                    range.MoveStart(TomUnit.tomCharacter, -1); 
                    gotPoint = WindowsRichEditRange.RangeGetPoint(rangeAdjust, TomGetPoint.TA_BOTTOM | TomGetPoint.TA_RIGHT, out x, out y);
                } 
            } 

            // There is a bug with RichEdit 3.0.  The expand to tomWindow gets the last cp of the bottom 
            // line in the window as the range's cpLim (End).  The cpLim may be passed the right side of
            // the window.
            // So need to trim off what is on the right side of the window.
            int end = range.End; 
            gotPoint = WindowsRichEditRange.RangeGetPoint(range, TomGetPoint.TA_RIGHT, out x, out y);
            while (!gotPoint || !Misc.PtInRect(ref rect, x, y)) 
            { 
                range.MoveEnd(TomUnit.tomWord, -1);
                gotPoint = WindowsRichEditRange.RangeGetPoint(range, TomGetPoint.TA_RIGHT, out x, out y); 
            }

            if (end != range.End)
            { 
                // The trimming was done based on the right edge of the range.  The last visiable partial
                // character/word has been also trimmed so add it back to the range.  Do the comparing 
                // against the characters left edge and the window rectangle. 
                ITextRange rangeAdjust = _document.Range(range.End, end);
                do 
                {
                    if (range.MoveEnd(TomUnit.tomCharacter, 1) == 0)
                    {
                        break; 
                    }
                    rangeAdjust.MoveStart(TomUnit.tomCharacter, 1); 
                    gotPoint = WindowsRichEditRange.RangeGetPoint(rangeAdjust, TomGetPoint.tomStart, out x, out y); 
                } while (gotPoint && Misc.PtInRect(ref rect, x, y));
            } 

            return range;
        }
 
        #endregion Internal Methods
 
        //----------------------------------------------------- 
        //
        //  Internal Properties 
        //
        //------------------------------------------------------

        #region Internal Properties 

        internal ITextDocument Document 
        { 
            get
            { 
                return _document;
            }
        }
 
        internal bool IsMultiline
        { 
            get 
            {
                return _type == WindowsEditBox.EditboxType.Multiline; 
            }
        }

        internal bool ReadOnly 
        {
            get 
            { 
                return (WindowStyle & NativeMethods.ES_READONLY) == NativeMethods.ES_READONLY;
            } 
        }

        #endregion Internal Properties
 
        //-----------------------------------------------------
        // 
        //  Internal Methods 
        //
        //----------------------------------------------------- 

        #region Internal Methods

        // return true if the user can modify the text in the edit control. 
        internal bool IsReadOnly()
        { 
            return (!SafeNativeMethods.IsWindowEnabled(WindowHandle) || 
                    Misc.IsBitSet(WindowStyle, NativeMethods.ES_READONLY));
        } 

        #endregion

        //----------------------------------------------------- 
        //
        //  Private Methods 
        // 
        //------------------------------------------------------
 
        #region Private Methods

        // call this method before allowing access to any TextPattern properties or methods.
        // it ensures that we have an ITextDocument pointer to the richedit control. 
        private void EnsureTextDocument()
        { 
            // if we don't have a document pointer yet then get one by sending richedit a WM_GETOBJECT message 
            // with object id asking for the native OM.
            if (_document == null) 
            {
                object obj = null;

                if (UnsafeNativeMethods.AccessibleObjectFromWindow(WindowHandle, NativeMethods.OBJID_NATIVEOM, ref UnsafeNativeMethods.IID_IDispatch, ref obj) != NativeMethods.S_OK) 
                {
                    throw new System.NotImplementedException(SR.Get(SRID.NoITextDocumentFromRichEdit)); 
                } 

                // review: - alexsn - This is temp solution which will prevent exception in the case 
                //                    when we cannot obtain the ITextDocument from a RichEdit control
                //                    The direct cast does not work for RichEdit20w controls used in MS Office
                //                    Susia will do the real fix
                _document = obj as ITextDocument; 
                if (_document == null)
                { 
                    // review: proper exception? 
                    throw new System.NotImplementedException(SR.Get(SRID.NoITextDocumentFromRichEdit));
                } 
            }
        }

        private string GetValue() 
        {
            if (_type == WindowsEditBox.EditboxType.Password) 
            { 
                // Trying to retrieve the text (through WM_GETTEXT) from an edit box that has
                // the ES_PASSWORD style throws an UnauthorizedAccessException. 
                throw new UnauthorizedAccessException();
            }

            if (IsDocument()) 
            {
                ITextRange range = _document.Range(0, 0); 
                int start = 0; 
                int end = range.StoryLength;
 
                range.SetRange(start, end);

                string text = range.Text;
                // Empty edits contain a degenerate/empty range, and will return null 
                // for their text - treat this as "", not null, since we do want to expose
                // a non-null value. 
                if (string.IsNullOrEmpty(text)) 
                {
                    return ""; 
                }

                int embeddedObjectOffset = text.IndexOf((char)0xFFFC);
                if (embeddedObjectOffset != -1) 
                {
                    StringBuilder sbText = new StringBuilder(); 
                    object embeddedObject; 
                    while (start < end && embeddedObjectOffset != -1)
                    { 
                        sbText.Append(text.Substring(start, embeddedObjectOffset - start));
                        range.SetRange(embeddedObjectOffset, end);
                        if (range.GetEmbeddedObject(out embeddedObject) == NativeMethods.S_OK && embeddedObject != null)
                        { 
                            GetEmbeddedObjectText(embeddedObject, sbText);
                        } 
                        else 
                        {
                            // If there is some kind of error, just append a space to the text.  In this way 
                            // we will be no worse of then before implementing the embedded object get text.
                            sbText.Append(" ");
                        }
                        start = embeddedObjectOffset + 1; 
                        embeddedObjectOffset = text.IndexOf((char)0xFFFC, start);
                    } 
 
                    if (start < end)
                    { 
                        sbText.Append(text.Substring(start, end - start));
                    }

                    text = sbText.ToString(); 
                }
 
                return text; 
            }
            else 
            {
                return Misc.ProxyGetText(_hwnd);
            }
        } 

        private void GetEmbeddedObjectText(object embeddedObject, StringBuilder sbText) 
        { 
            string text;
 
            IAccessible acc = embeddedObject as IAccessible;
            if (acc != null)
            {
                text = acc.get_accName(NativeMethods.CHILD_SELF); 
                if (!string.IsNullOrEmpty(text))
                { 
                    sbText.Append(text); 
                    return;
                } 
            }

            // Didn't get IAccessible (or didn't get a name from it).
            // Try the IDataObject technique instead... 

            int hr = NativeMethods.S_FALSE; 
            IDataObject dataObject = null; 
            IOleObject oleObject = embeddedObject as IOleObject;
            if (oleObject != null) 
            {
                // Try IOleObject::GetClipboardData (which returns an IDataObject) first...
                hr = oleObject.GetClipboardData(0, out dataObject);
            } 

            // If that didn't work, try the embeddedObject as a IDataObject instead... 
            if (hr != NativeMethods.S_OK) 
            {
                dataObject = embeddedObject as IDataObject; 
            }

            if (dataObject == null)
            { 
                return;
            } 
 
            // Got the IDataObject. Now query it for text formats. Try Unicode first...
 
            bool fGotUnicode = true;

            UnsafeNativeMethods.FORMATETC fetc = new UnsafeNativeMethods.FORMATETC();
            fetc.cfFormat = DataObjectConstants.CF_UNICODETEXT; 
            fetc.ptd = IntPtr.Zero;
            fetc.dwAspect = DataObjectConstants.DVASPECT_CONTENT; 
            fetc.lindex = -1; 
            fetc.tymed = DataObjectConstants.TYMED_HGLOBAL;
 
            UnsafeNativeMethods.STGMEDIUM med = new UnsafeNativeMethods.STGMEDIUM();
            med.tymed = DataObjectConstants.TYMED_HGLOBAL;
            med.pUnkForRelease = IntPtr.Zero;
            med.hGlobal = IntPtr.Zero; 

            hr = dataObject.GetData(ref fetc, ref med); 
 
            if (hr != NativeMethods.S_OK || med.hGlobal == IntPtr.Zero)
            { 
                // If we didn't get Unicode, try for ANSI instead...
                fGotUnicode = false;
                fetc.cfFormat = DataObjectConstants.CF_TEXT;
 
                hr = dataObject.GetData(ref fetc, ref med);
            } 
 
            // Did we get anything?
            if (hr != NativeMethods.S_OK || med.hGlobal == IntPtr.Zero) 
            {
                return;
            }
 
            //lock the memory, so data can be copied into
            IntPtr globalMem = UnsafeNativeMethods.GlobalLock(med.hGlobal); 
 
            try
            { 
                //error check for the memory pointer
                if (globalMem == IntPtr.Zero)
                {
                    return; 
                }
 
                unsafe 
                {
                    //get the string 
                    if (fGotUnicode)
                    {
                        text = new string((char*)globalMem);
                    } 
                    else
                    { 
                        text = new string((sbyte*)globalMem); 
                    }
                } 

                sbText.Append(text);
            }
            finally 
            {
                //unlock the memory 
                UnsafeNativeMethods.GlobalUnlock(med.hGlobal); 
                UnsafeNativeMethods.ReleaseStgMedium(ref med);
            } 
        }

        private bool IsDocument()
        { 
            return !OnCommandBar();
        } 
 
        private bool OnCommandBar()
        { 
            IntPtr hwndParent = UnsafeNativeMethods.GetAncestor(_hwnd, NativeMethods.GA_PARENT);

            if (hwndParent != IntPtr.Zero)
            { 
                return Misc.GetClassName(hwndParent).Equals("MsoCommandBar");
            } 
            return false; 
        }
 
        // Raise the TextSelectionChanged event, if appropriate.
        private void RaiseTextSelectionEvent(int eventId, object idProp, int idObject, int idChild)
        {
            // We cannot use the generic DispatchEvents mechanism to raise 
            // the TextSelection event, since DispatchEvents() will eventually call
            // EventManager.HandleTextSelectionChangedEvent(), 
            // which will use logic inappropriate for the RichTextEdit control: 
            // namely, that wtv._document.Selection.GetSelection() returns
            // an ITextRange which can *change* when e.g. backspace is pressed 
            // in the control.  To reliably detect an actual change in selection,
            // we have to perform a specific test of the old and new selection
            // endpoints and raise the event ourselves if appropriate.
 
            bool raiseTextSelectionEvent = false;
 
            EnsureTextDocument(); 
            ITextSelection textSelection = _document.Selection;
            if (textSelection != null) 
            {
                raiseTextSelectionEvent =
                    (_raiseEventsOldSelectionStart != textSelection.Start
                        || _raiseEventsOldSelectionEnd != textSelection.End); 

                _raiseEventsOldSelectionStart = textSelection.Start; 
                _raiseEventsOldSelectionEnd = textSelection.End; 
            }
            else 
            {
                raiseTextSelectionEvent =
                    (_raiseEventsOldSelectionStart != _NO_ENDPOINT
                        || _raiseEventsOldSelectionEnd != _NO_ENDPOINT); 

                _raiseEventsOldSelectionStart = _NO_ENDPOINT; 
                _raiseEventsOldSelectionEnd = _NO_ENDPOINT; 
            }
 
            if (raiseTextSelectionEvent)
            {
                AutomationInteropProvider.RaiseAutomationEvent(
                    TextPattern.TextSelectionChangedEvent, 
                    this, new AutomationEventArgs(TextPattern.TextSelectionChangedEvent));
            } 
        } 

        #endregion private Methods 

        //-----------------------------------------------------
        //
        //  Private Fields 
        //
        //------------------------------------------------------ 
 
        #region Private Fields
 
        private ITextDocument _document;
        private WindowsEditBox.EditboxType _type;

        // Used in RaiseEvents() to track changes in the selection endpoints. 
        static private int _raiseEventsOldSelectionStart;
        static private int _raiseEventsOldSelectionEnd; 
        private const int _NO_ENDPOINT = -1; 

        #endregion private Fields 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: HWND-based RichEdit Proxy 
//
// History: 
//          nbatchu                 Created
//          Jean-Francois Peyroux.  Revised
//
//--------------------------------------------------------------------------- 
using System;
using System.Collections; 
using System.ComponentModel; 
using System.Diagnostics;
using System.Runtime.InteropServices; 
using System.Text;
using System.Windows;
using System.Windows.Automation;
using System.Windows.Automation.Provider; 
using System.Windows.Automation.Text;
using Accessibility; 
using MS.Win32; 

namespace MS.Internal.AutomationProxies 
{
    class WindowsRichEdit : ProxyHwnd, IValueProvider, ITextProvider
    {
        // ----------------------------------------------------- 
        //
        // Constructors 
        // 
        // -----------------------------------------------------
 
        #region Constructors

        WindowsRichEdit (IntPtr hwnd, ProxyFragment parent, int style)
            : base( hwnd, parent, style ) 
        {
            _type = WindowsEditBox.GetEditboxtype(hwnd); 
            if (IsMultiline) 
            {
                _cControlType = ControlType.Document; 
            }
            else
            {
                _cControlType = ControlType.Edit; 
            }
 
            _fIsKeyboardFocusable = true; 

            // support for events 
            _createOnEvent = new WinEventTracker.ProxyRaiseEvents (RaiseEvents);
        }

        #endregion Initialization 

        #region Proxy Create 
 
        // Static Create method called by UIAutomation to create this proxy.
        // returns null if unsuccessful 
        internal static IRawElementProviderSimple Create(IntPtr hwnd, int idChild, int idObject)
        {
            return Create(hwnd, idChild);
        } 

        internal static IRawElementProviderSimple Create(IntPtr hwnd, int idChild) 
        { 
            // Something is wrong if idChild is not zero
            if (idChild != 0) 
            {
                Debug.Assert (idChild == 0, "Invalid Child Id, idChild != 0");
                throw new ArgumentOutOfRangeException("idChild", idChild, SR.Get(SRID.ShouldBeZero));
            } 

            return new WindowsRichEdit(hwnd, null, 0); 
        } 

        // Static Create method called by the event tracker system 
        internal static void RaiseEvents (IntPtr hwnd, int eventId, object idProp, int idObject, int idChild)
        {
            if (idObject != NativeMethods.OBJID_VSCROLL && idObject != NativeMethods.OBJID_HSCROLL)
            { 
                WindowsRichEdit wtv = new WindowsRichEdit (hwnd, null, 0);
 
                // If this event means the selection may have changed, raise that event 
                // here instead of relying on the generic DispatchEvents mechanism below.
                // The RichTextEdit provider needs to handle this event specially. 
                if (eventId == NativeMethods.EventObjectLocationChange
                    && idObject == NativeMethods.OBJID_CARET)
                {
                    wtv.RaiseTextSelectionEvent(eventId, idProp, idObject, idChild); 
                }
                else 
                { 
                    wtv.DispatchEvents(eventId, idProp, idObject, idChild);
                } 
            }
        }

        #endregion Proxy Create 

        //------------------------------------------------------ 
        // 
        //  Patterns Implementation
        // 
        //-----------------------------------------------------

        #region ProxySimple Interface
 
        // Returns a pattern interface if supported.
        internal override object GetPatternProvider(AutomationPattern iid) 
        { 
            try
            { 
                if (iid == ValuePattern.Pattern && !IsMultiline)
                {
                    if (IsDocument())
                    { 
                        EnsureTextDocument();
                    } 
                    return this; 
                }
 
                // text pattern is supported for non-password boxes
                if (iid == TextPattern.Pattern && _type != WindowsEditBox.EditboxType.Password && IsDocument())
                {
                    EnsureTextDocument(); 
                    return this;
                } 
 
                return null;
            } 
                //If tom.dll is missing
            catch (System.IO.FileNotFoundException)
            {
                return null; 
            }
        } 
 
        // Process all the Logical and Raw Element Properties
        internal override object GetElementProperty(AutomationProperty idProp) 
        {
            if (idProp == AutomationElement.IsPasswordProperty)
            {
                return _type == WindowsEditBox.EditboxType.Password; 
            }
            else if (idProp == AutomationElement.NameProperty) 
            { 
                // Per ControlType.Edit spec if there is no static text
                // label for an Edit then it must NEVER return the contents 
                // of the edit as the Name property. This relies on the
                // default ProxyHwnd impl looking for a label for Name and
                // not using WM_GETTEXT on the edit hwnd.
                string name = base.GetElementProperty(idProp) as string; 
                if (string.IsNullOrEmpty(name))
                { 
                    // Stop UIA from asking other providers 
                    return AutomationElement.NotSupported;
                } 

                return name;
            }
 
            return base.GetElementProperty(idProp);
        } 
        #endregion ProxySimple Interface 

        #region Value Pattern 

        // Sets the text of the edit.
        void IValueProvider.SetValue(string str)
        { 
            // Check if the window is disabled
            if (!SafeNativeMethods.IsWindowEnabled(_hwnd)) 
            { 
                throw new ElementNotEnabledException();
            } 

            if (Misc.IsBitSet(WindowStyle, NativeMethods.ES_READONLY))
            {
                throw new InvalidOperationException(SR.Get(SRID.ValueReadonly)); 
            }
 
            // check if control only accepts numbers 
            if (Misc.IsBitSet(WindowStyle, NativeMethods.ES_NUMBER) && !WindowsFormsHelper.IsWindowsFormsControl(_hwnd))
            { 
                // check if string contains any non-numeric characters.
                foreach (char ch in str)
                {
                    if (char.IsLetter(ch)) 
                    {
                        throw new ArgumentException(SR.Get(SRID.NotAValidValue, str), "val"); 
                    } 
                }
            } 

            // bug# 11147, Text/edit box should not enter more characters than what is allowed through keyboard.
            // Determine the max number of chars this editbox accepts
 
            int result = Misc.ProxySendMessageInt(_hwnd, NativeMethods.EM_GETLIMITTEXT, IntPtr.Zero, IntPtr.Zero);
            if (result < str.Length) 
            { 
                throw new InvalidOperationException (SR.Get(SRID.OperationCannotBePerformed));
            } 

            // Send the message...
            result = Misc.ProxySendMessageInt(_hwnd, NativeMethods.WM_SETTEXT, IntPtr.Zero, new StringBuilder(str));
            if (result != 1) 
            {
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); 
            } 
        }
 
        // Request to get the value that this UI element is representing as a string
        string IValueProvider.Value
        {
            get 
            {
                return GetValue(); 
            } 
        }
 
        bool IValueProvider.IsReadOnly
        {
            get
            { 
                return IsReadOnly();
            } 
        } 

        #endregion 

        #region Text Pattern Methods

        ITextRangeProvider [] ITextProvider.GetSelection() 
        {
            // we must have called EnsureTextDocument() before arriving here. 
            Debug.Assert(_document != null); 

            // clone a range from the documents selection 
            ITextRange range = null;
            ITextSelection selection = _document.Selection;
            if (selection != null)
            { 
                // duplicate the selection range since we don't want their modifications to affect the selection
                range = selection.GetDuplicate(); 
 
                // for future reference: active endpoint is
                // ((selection.Flags & TomSelectionFlags.tomSelStartActive) == TomSelectionFlags.tomSelStartActive) ? TextPatternRangeEndpoint.Start : TextPatternRangeEndpoint.End; 
            }

            if (range == null)
                return new ITextRangeProvider[] { }; 
            else
                return new ITextRangeProvider[] { new WindowsRichEditRange(range, this) }; 
        } 

        ITextRangeProvider [] ITextProvider.GetVisibleRanges() 
        {
            ITextRange range = GetVisibleRange();

            if (range == null) 
                return new ITextRangeProvider[] { };
            else 
                return new ITextRangeProvider[] { new WindowsRichEditRange(range, this) }; 
        }
 
        ITextRangeProvider ITextProvider.RangeFromChild(IRawElementProviderSimple childElement)
        {
            // we don't have any children so this call must be in error.
            // if we implement children for hyperlinks and embedded objects then we'll need to change this. 
            throw new InvalidOperationException(SR.Get(SRID.RichEditTextPatternHasNoChildren,GetType().FullName));
        } 
 
        ITextRangeProvider ITextProvider.RangeFromPoint(Point screenLocation)
        { 
            // we must have called EnsureTextDocument() before arriving here.
            Debug.Assert(_document != null);

            // TextPattern has verified that the point is inside our client area so we don't need to check for that. 

            // get the degenerate range at the point 
            // we're assuming ITextDocument::RangeFromPoint always returns a degenerate range 
            ITextRange range = _document.RangeFromPoint((int)screenLocation.X, (int)screenLocation.Y);
            Debug.Assert(range.Start == range.End); 

            // if you wanted to get the character under the point instead of the degenerate range nearest
            // the point, then you would add:
 
            //// if the point is within the character to the right then expand the degenerate range to
            //// include the character. 
            //Rect rect; 
            //range.MoveEnd(TomUnit.tomCharacter, 1);
            //rect = WindowsRichEditRange.GetSingleLineRangeRectangle(range, BoundingRectangle); 
            //if (!rect.Contains(screenLocation))
            //{
            //    // if the point is within the character to the left then expand the degenerate range
            //    // to include the character. 
            //    range.Collapse(TomStartEnd.tomStart);
            //    range.MoveStart(TomUnit.tomCharacter, -1); 
            //    rect = WindowsRichEditRange.GetSingleLineRangeRectangle(range, BoundingRectangle); 
            //    if (!rect.Contains(screenLocation))
            //    { 
            //        // the point is not in an adjacent character cell so leave it degenerate.
            //        range.Collapse(TomStartEnd.tomEnd);
            //    }
            //} 

            return range != null ? new WindowsRichEditRange(range, this) : null; 
        } 

        #endregion TextPattern Methods 

        #region TextPattern Properties

        ITextRangeProvider ITextProvider.DocumentRange 
        {
            get 
            { 
                // we must have called EnsureTextDocument() before arriving here.
                Debug.Assert(_document != null); 

                // create a text range that covers the entire main story.
                ITextRange range = _document.Range(0, 0);
                range.SetRange(0, range.StoryLength); 
                return new WindowsRichEditRange(range, this);
            } 
        } 

        // THESE PROPERTIES ARE REMOVED IN 8.2 BREAKING CHANGE. 
        //


 

 
 

 



 

 
 

 



 

 
 

 

        SupportedTextSelection ITextProvider.SupportedTextSelection
        {
            get 
            {
                return SupportedTextSelection.Single; 
            } 
        }
 
        #endregion Text Properties

        //------------------------------------------------------
        // 
        //  Internal Methods
        // 
        //------------------------------------------------------ 

        #region Internal Methods 

        // returns the range that is visible in the RichEdit window
        internal ITextRange GetVisibleRange()
        { 
            // get a range from the center point of the client rectangle
            Rect rect = BoundingRectangle; 
            int x = ((int)rect.Left + (int)rect.Right) / 2; 
            int y = ((int)rect.Top + (int)rect.Bottom) / 2;
            ITextRange range = _document.RangeFromPoint(x, y); 

            // expand it to fill the window.
            range.Expand(TomUnit.tomWindow);
 
            // There is a bug with RichEdit 3.0.  The expand to tomWindow may gets 0 as the range's cpBegin (Start).
            // So need to trim off what is outside of the window. 
            int start = range.Start; 
            // The ITextRange::SetRange method sets this range�s Start = min(cp1, cp2) and End = max(cp1, cp2).
            // If the range is a nondegenerate selection, cp2 is the active end; if it�s a degenerate selection, 
            // the ambiguous cp is displayed at the start of the line (rather than at the end of the previous line).
            // Set the end to the start and the start to the end to create an ambiguous cp.
            range.SetRange(range.End, range.Start);
            bool gotPoint = WindowsRichEditRange.RangeGetPoint(range, TomGetPoint.tomStart, out x, out y); 
            while (!gotPoint || !Misc.PtInRect(ref rect, x, y))
            { 
                range.MoveStart(TomUnit.tomWord, 1); 
                gotPoint = WindowsRichEditRange.RangeGetPoint(range, TomGetPoint.tomStart, out x, out y);
            } 

            if (start != range.Start)
            {
                // The trimming was done based on the left edge of the range.  The last visiable partial 
                // character/word has been also added back into the range, need to remove it.  Do the comparing
                // against the characters right edge and the window rectangle. 
                ITextRange rangeAdjust = _document.Range(0, range.Start - 1); 
                gotPoint = WindowsRichEditRange.RangeGetPoint(rangeAdjust, TomGetPoint.TA_BOTTOM | TomGetPoint.TA_RIGHT, out x, out y);
 
                while (gotPoint && Misc.PtInRect(ref rect, x, y) && rangeAdjust.Start != rangeAdjust.End)
                {
                    rangeAdjust.MoveEnd(TomUnit.tomCharacter, -1);
                    range.MoveStart(TomUnit.tomCharacter, -1); 
                    gotPoint = WindowsRichEditRange.RangeGetPoint(rangeAdjust, TomGetPoint.TA_BOTTOM | TomGetPoint.TA_RIGHT, out x, out y);
                } 
            } 

            // There is a bug with RichEdit 3.0.  The expand to tomWindow gets the last cp of the bottom 
            // line in the window as the range's cpLim (End).  The cpLim may be passed the right side of
            // the window.
            // So need to trim off what is on the right side of the window.
            int end = range.End; 
            gotPoint = WindowsRichEditRange.RangeGetPoint(range, TomGetPoint.TA_RIGHT, out x, out y);
            while (!gotPoint || !Misc.PtInRect(ref rect, x, y)) 
            { 
                range.MoveEnd(TomUnit.tomWord, -1);
                gotPoint = WindowsRichEditRange.RangeGetPoint(range, TomGetPoint.TA_RIGHT, out x, out y); 
            }

            if (end != range.End)
            { 
                // The trimming was done based on the right edge of the range.  The last visiable partial
                // character/word has been also trimmed so add it back to the range.  Do the comparing 
                // against the characters left edge and the window rectangle. 
                ITextRange rangeAdjust = _document.Range(range.End, end);
                do 
                {
                    if (range.MoveEnd(TomUnit.tomCharacter, 1) == 0)
                    {
                        break; 
                    }
                    rangeAdjust.MoveStart(TomUnit.tomCharacter, 1); 
                    gotPoint = WindowsRichEditRange.RangeGetPoint(rangeAdjust, TomGetPoint.tomStart, out x, out y); 
                } while (gotPoint && Misc.PtInRect(ref rect, x, y));
            } 

            return range;
        }
 
        #endregion Internal Methods
 
        //----------------------------------------------------- 
        //
        //  Internal Properties 
        //
        //------------------------------------------------------

        #region Internal Properties 

        internal ITextDocument Document 
        { 
            get
            { 
                return _document;
            }
        }
 
        internal bool IsMultiline
        { 
            get 
            {
                return _type == WindowsEditBox.EditboxType.Multiline; 
            }
        }

        internal bool ReadOnly 
        {
            get 
            { 
                return (WindowStyle & NativeMethods.ES_READONLY) == NativeMethods.ES_READONLY;
            } 
        }

        #endregion Internal Properties
 
        //-----------------------------------------------------
        // 
        //  Internal Methods 
        //
        //----------------------------------------------------- 

        #region Internal Methods

        // return true if the user can modify the text in the edit control. 
        internal bool IsReadOnly()
        { 
            return (!SafeNativeMethods.IsWindowEnabled(WindowHandle) || 
                    Misc.IsBitSet(WindowStyle, NativeMethods.ES_READONLY));
        } 

        #endregion

        //----------------------------------------------------- 
        //
        //  Private Methods 
        // 
        //------------------------------------------------------
 
        #region Private Methods

        // call this method before allowing access to any TextPattern properties or methods.
        // it ensures that we have an ITextDocument pointer to the richedit control. 
        private void EnsureTextDocument()
        { 
            // if we don't have a document pointer yet then get one by sending richedit a WM_GETOBJECT message 
            // with object id asking for the native OM.
            if (_document == null) 
            {
                object obj = null;

                if (UnsafeNativeMethods.AccessibleObjectFromWindow(WindowHandle, NativeMethods.OBJID_NATIVEOM, ref UnsafeNativeMethods.IID_IDispatch, ref obj) != NativeMethods.S_OK) 
                {
                    throw new System.NotImplementedException(SR.Get(SRID.NoITextDocumentFromRichEdit)); 
                } 

                // review: - alexsn - This is temp solution which will prevent exception in the case 
                //                    when we cannot obtain the ITextDocument from a RichEdit control
                //                    The direct cast does not work for RichEdit20w controls used in MS Office
                //                    Susia will do the real fix
                _document = obj as ITextDocument; 
                if (_document == null)
                { 
                    // review: proper exception? 
                    throw new System.NotImplementedException(SR.Get(SRID.NoITextDocumentFromRichEdit));
                } 
            }
        }

        private string GetValue() 
        {
            if (_type == WindowsEditBox.EditboxType.Password) 
            { 
                // Trying to retrieve the text (through WM_GETTEXT) from an edit box that has
                // the ES_PASSWORD style throws an UnauthorizedAccessException. 
                throw new UnauthorizedAccessException();
            }

            if (IsDocument()) 
            {
                ITextRange range = _document.Range(0, 0); 
                int start = 0; 
                int end = range.StoryLength;
 
                range.SetRange(start, end);

                string text = range.Text;
                // Empty edits contain a degenerate/empty range, and will return null 
                // for their text - treat this as "", not null, since we do want to expose
                // a non-null value. 
                if (string.IsNullOrEmpty(text)) 
                {
                    return ""; 
                }

                int embeddedObjectOffset = text.IndexOf((char)0xFFFC);
                if (embeddedObjectOffset != -1) 
                {
                    StringBuilder sbText = new StringBuilder(); 
                    object embeddedObject; 
                    while (start < end && embeddedObjectOffset != -1)
                    { 
                        sbText.Append(text.Substring(start, embeddedObjectOffset - start));
                        range.SetRange(embeddedObjectOffset, end);
                        if (range.GetEmbeddedObject(out embeddedObject) == NativeMethods.S_OK && embeddedObject != null)
                        { 
                            GetEmbeddedObjectText(embeddedObject, sbText);
                        } 
                        else 
                        {
                            // If there is some kind of error, just append a space to the text.  In this way 
                            // we will be no worse of then before implementing the embedded object get text.
                            sbText.Append(" ");
                        }
                        start = embeddedObjectOffset + 1; 
                        embeddedObjectOffset = text.IndexOf((char)0xFFFC, start);
                    } 
 
                    if (start < end)
                    { 
                        sbText.Append(text.Substring(start, end - start));
                    }

                    text = sbText.ToString(); 
                }
 
                return text; 
            }
            else 
            {
                return Misc.ProxyGetText(_hwnd);
            }
        } 

        private void GetEmbeddedObjectText(object embeddedObject, StringBuilder sbText) 
        { 
            string text;
 
            IAccessible acc = embeddedObject as IAccessible;
            if (acc != null)
            {
                text = acc.get_accName(NativeMethods.CHILD_SELF); 
                if (!string.IsNullOrEmpty(text))
                { 
                    sbText.Append(text); 
                    return;
                } 
            }

            // Didn't get IAccessible (or didn't get a name from it).
            // Try the IDataObject technique instead... 

            int hr = NativeMethods.S_FALSE; 
            IDataObject dataObject = null; 
            IOleObject oleObject = embeddedObject as IOleObject;
            if (oleObject != null) 
            {
                // Try IOleObject::GetClipboardData (which returns an IDataObject) first...
                hr = oleObject.GetClipboardData(0, out dataObject);
            } 

            // If that didn't work, try the embeddedObject as a IDataObject instead... 
            if (hr != NativeMethods.S_OK) 
            {
                dataObject = embeddedObject as IDataObject; 
            }

            if (dataObject == null)
            { 
                return;
            } 
 
            // Got the IDataObject. Now query it for text formats. Try Unicode first...
 
            bool fGotUnicode = true;

            UnsafeNativeMethods.FORMATETC fetc = new UnsafeNativeMethods.FORMATETC();
            fetc.cfFormat = DataObjectConstants.CF_UNICODETEXT; 
            fetc.ptd = IntPtr.Zero;
            fetc.dwAspect = DataObjectConstants.DVASPECT_CONTENT; 
            fetc.lindex = -1; 
            fetc.tymed = DataObjectConstants.TYMED_HGLOBAL;
 
            UnsafeNativeMethods.STGMEDIUM med = new UnsafeNativeMethods.STGMEDIUM();
            med.tymed = DataObjectConstants.TYMED_HGLOBAL;
            med.pUnkForRelease = IntPtr.Zero;
            med.hGlobal = IntPtr.Zero; 

            hr = dataObject.GetData(ref fetc, ref med); 
 
            if (hr != NativeMethods.S_OK || med.hGlobal == IntPtr.Zero)
            { 
                // If we didn't get Unicode, try for ANSI instead...
                fGotUnicode = false;
                fetc.cfFormat = DataObjectConstants.CF_TEXT;
 
                hr = dataObject.GetData(ref fetc, ref med);
            } 
 
            // Did we get anything?
            if (hr != NativeMethods.S_OK || med.hGlobal == IntPtr.Zero) 
            {
                return;
            }
 
            //lock the memory, so data can be copied into
            IntPtr globalMem = UnsafeNativeMethods.GlobalLock(med.hGlobal); 
 
            try
            { 
                //error check for the memory pointer
                if (globalMem == IntPtr.Zero)
                {
                    return; 
                }
 
                unsafe 
                {
                    //get the string 
                    if (fGotUnicode)
                    {
                        text = new string((char*)globalMem);
                    } 
                    else
                    { 
                        text = new string((sbyte*)globalMem); 
                    }
                } 

                sbText.Append(text);
            }
            finally 
            {
                //unlock the memory 
                UnsafeNativeMethods.GlobalUnlock(med.hGlobal); 
                UnsafeNativeMethods.ReleaseStgMedium(ref med);
            } 
        }

        private bool IsDocument()
        { 
            return !OnCommandBar();
        } 
 
        private bool OnCommandBar()
        { 
            IntPtr hwndParent = UnsafeNativeMethods.GetAncestor(_hwnd, NativeMethods.GA_PARENT);

            if (hwndParent != IntPtr.Zero)
            { 
                return Misc.GetClassName(hwndParent).Equals("MsoCommandBar");
            } 
            return false; 
        }
 
        // Raise the TextSelectionChanged event, if appropriate.
        private void RaiseTextSelectionEvent(int eventId, object idProp, int idObject, int idChild)
        {
            // We cannot use the generic DispatchEvents mechanism to raise 
            // the TextSelection event, since DispatchEvents() will eventually call
            // EventManager.HandleTextSelectionChangedEvent(), 
            // which will use logic inappropriate for the RichTextEdit control: 
            // namely, that wtv._document.Selection.GetSelection() returns
            // an ITextRange which can *change* when e.g. backspace is pressed 
            // in the control.  To reliably detect an actual change in selection,
            // we have to perform a specific test of the old and new selection
            // endpoints and raise the event ourselves if appropriate.
 
            bool raiseTextSelectionEvent = false;
 
            EnsureTextDocument(); 
            ITextSelection textSelection = _document.Selection;
            if (textSelection != null) 
            {
                raiseTextSelectionEvent =
                    (_raiseEventsOldSelectionStart != textSelection.Start
                        || _raiseEventsOldSelectionEnd != textSelection.End); 

                _raiseEventsOldSelectionStart = textSelection.Start; 
                _raiseEventsOldSelectionEnd = textSelection.End; 
            }
            else 
            {
                raiseTextSelectionEvent =
                    (_raiseEventsOldSelectionStart != _NO_ENDPOINT
                        || _raiseEventsOldSelectionEnd != _NO_ENDPOINT); 

                _raiseEventsOldSelectionStart = _NO_ENDPOINT; 
                _raiseEventsOldSelectionEnd = _NO_ENDPOINT; 
            }
 
            if (raiseTextSelectionEvent)
            {
                AutomationInteropProvider.RaiseAutomationEvent(
                    TextPattern.TextSelectionChangedEvent, 
                    this, new AutomationEventArgs(TextPattern.TextSelectionChangedEvent));
            } 
        } 

        #endregion private Methods 

        //-----------------------------------------------------
        //
        //  Private Fields 
        //
        //------------------------------------------------------ 
 
        #region Private Fields
 
        private ITextDocument _document;
        private WindowsEditBox.EditboxType _type;

        // Used in RaiseEvents() to track changes in the selection endpoints. 
        static private int _raiseEventsOldSelectionStart;
        static private int _raiseEventsOldSelectionEnd; 
        private const int _NO_ENDPOINT = -1; 

        #endregion private Fields 
    }
}

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

                        

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