WindowsTab.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / UIAutomation / Win32Providers / MS / Internal / AutomationProxies / WindowsTab.cs / 1 / WindowsTab.cs

                            /****************************************************************************\ 
*
* File: WindowsTab.cs
*
* Description: 
* HWND-based tab control proxy
* 
* Copyright (C) 2002 by Microsoft Corporation.  All rights reserved. 
*
\***************************************************************************/ 

using System;
using System.Collections;
using System.Text; 
using System.Windows.Automation;
using System.Windows.Automation.Provider; 
using System.Runtime.InteropServices; 
using System.ComponentModel;
using System.Windows; 
using System.Windows.Input;
using MS.Win32;

namespace MS.Internal.AutomationProxies 
{
    class WindowsTab: ProxyHwnd, ISelectionProvider, IScrollProvider, IRawElementProviderHwndOverride 
    { 
        // -----------------------------------------------------
        // 
        // Constructors
        //
        // -----------------------------------------------------
 
        #region Constructors
 
        public WindowsTab (IntPtr hwnd, ProxyFragment parent, int item) 
            : base( hwnd, parent, item )
        { 
            // Set the strings to return properly the properties.
            _cControlType = ControlType.Tab;

            // force initialisation of this so it can be used later 
            _windowsForms = WindowsFormsHelper.GetControlState (hwnd);
 
            // support for events 
            _createOnEvent = new WinEventTracker.ProxyRaiseEvents (RaiseEvents);
 
            _fIsContent = IsValidControl(_hwnd);
        }

        static WindowsTab () 
        {
            _upDownEvents = new WinEventTracker.EvtIdProperty [1]; 
            _upDownEvents[0]._evtId = NativeMethods.EventObjectValueChange; 
            _upDownEvents[0]._idProp = ScrollPattern.HorizontalScrollPercentProperty;
        } 

        #endregion

        #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);
        }

        private static IRawElementProviderSimple Create(IntPtr hwnd, int idChild) 
        {
            WindowsTab wTab = new WindowsTab(hwnd, null, 0); 
 
            return idChild == 0 ? wTab : wTab.CreateTabItem (idChild - 1);
        } 

        // Static Create method called by the event tracker system
        // WinEvents are one throwns because items exist. so it makes sense to create the item and
        // check for details afterward. 
        internal static void RaiseEvents (IntPtr hwnd, int eventId, object idProp, int idObject, int idChild)
        { 
            ProxySimple el = null; 

            switch (idObject) 
            {
                case NativeMethods.OBJID_CLIENT :
                {
                    WindowsTab wlv = new WindowsTab (hwnd, null, -1); 

                    if (eventId == NativeMethods.EventObjectSelection || eventId == NativeMethods.EventObjectSelectionRemove || eventId == NativeMethods.EventObjectSelectionAdd) 
                    { 
                        el = wlv.CreateTabItem (idChild - 1);
                    } 
                    else
                    {
                        el = wlv;
                    } 

                    break; 
                } 

                default : 
                    if ((idProp == ScrollPattern.VerticalScrollPercentProperty && idObject != NativeMethods.OBJID_VSCROLL) ||
                        (idProp == ScrollPattern.HorizontalScrollPercentProperty && idObject != NativeMethods.OBJID_HSCROLL))
                    {
                        return; 
                    }
 
                    el = new WindowsTab(hwnd, null, -1); 
                    break;
            } 
            if (el != null)
            {
                el.DispatchEvents (eventId, idProp, idObject, idChild);
            } 
        }
 
        #endregion 

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

        #region ProxySimple Interface 
 
        // Returns a pattern interface if supported.
        // Param name="iid", UIAutomation Pattern 
        // Returns null or pattern interface
        internal override object GetPatternProvider (AutomationPattern iid)
        {
            if (iid == SelectionPattern.Pattern) 
            {
                return this; 
            } 

            if (iid == ScrollPattern.Pattern) 
            {
                return this;
            }
 
            return null;
        } 
 
        // Process all the Logical and Raw Element Properties
        internal override object GetElementProperty(AutomationProperty idProp) 
        {
            if (idProp == AutomationElement.IsControlElementProperty)
            {
                return IsValidControl(_hwnd); 
            }
            else if (idProp == AutomationElement.OrientationProperty) 
            { 
                return IsVerticalTab() ? OrientationType.Vertical : OrientationType.Horizontal;
            } 
            else if (idProp == ScrollPatternIdentifiers.HorizontalScrollPercentProperty)
            {
                return ((IScrollProvider)this).HorizontalScrollPercent;
            } 
            else if (idProp == ScrollPatternIdentifiers.HorizontallyScrollableProperty)
            { 
                return ((IScrollProvider)this).HorizontallyScrollable; 
            }
            else if (idProp == ScrollPatternIdentifiers.HorizontalViewSizeProperty) 
            {
                return ((IScrollProvider)this).HorizontalViewSize;
            }
 
            return base.GetElementProperty(idProp);
        } 
 
        #endregion ProxySimple Interface
 
        #region ProxyFragment Interface

        // Returns the next sibling element in the raw hierarchy.
        // Peripheral controls have always negative values. 
        // Param name="child", the current child
        // Returns null if no next child 
        internal override ProxySimple GetNextSibling (ProxySimple child) 
        {
            int item = child._item; 

            if (item != SpinControl)
            {
                int count = GetItemCount(_hwnd); 

                // Next for an item that does not exist in the list 
                if (item >= count) 
                {
                    throw new ElementNotAvailableException (); 
                }

                if (item + 1 < count)
                { 
                    return CreateTabItem(item + 1);
                } 
            } 

            return null; 
        }

        // Returns the previous sibling element in the raw hierarchy.
        // Peripheral controls have always negative values. 
        // Param name="child", the current child
        // Returns null is no previous 
        internal override ProxySimple GetPreviousSibling (ProxySimple child) 
        {
            int count = GetItemCount(_hwnd); 
            int item = child._item;

            if (item == SpinControl)
                item = count; 

            // Next for an item that does not exist in the list 
            if (item >= count) 
            {
                throw new ElementNotAvailableException (); 
            }

            if (item > 0 && item <= count)
            { 
                return CreateTabItem(item - 1);
            } 
 
            return null;
        } 

        // Returns the first child element in the raw hierarchy.
        internal override ProxySimple GetFirstChild ()
        { 
            int count = GetItemCount(_hwnd);
 
            if (count > 0) 
            {
                return CreateTabItem(0); 
            }

            return null;
        } 

        // Returns the last child element in the raw hierarchy. 
        internal override ProxySimple GetLastChild () 
        {
            int count = GetItemCount(_hwnd); 

            if (count > 0)
            {
                return CreateTabItem(count - 1); 
            }
 
            return null; 
        }
 
        // Returns a Proxy element corresponding to the specified screen coordinates.
        internal override ProxySimple ElementProviderFromPoint (int x, int y)
        {
            UnsafeNativeMethods.TCHITTESTINFO hti = new UnsafeNativeMethods.TCHITTESTINFO(); 

            hti.pt = new NativeMethods.Win32Point (x, y); 
 
            if (!Misc.MapWindowPoints(IntPtr.Zero, _hwnd, ref hti.pt, 1))
            { 
                return null;
            }

            // updown control goes over the tabs hence the order of the check 
            // We cannot let UIAutomation do the do the drilling for the updown as the spinner covers the tab
            IntPtr updownHwnd = this.GetUpDownHwnd (); 
 
            if (updownHwnd != IntPtr.Zero && Misc.PtInWindowRect(updownHwnd, x, y))
            { 
                return null;
            }

            int index; 
            unsafe
            { 
                index = XSendMessage.XSendGetIndex(_hwnd, NativeMethods.TCM_HITTEST, IntPtr.Zero, new IntPtr(&hti), Marshal.SizeOf(hti.GetType())); 
            }
 
            if (index >= 0)
            {
                return CreateTabItem (index);
            } 

            return null; 
        } 

        // Returns an item corresponding to the focused element (if there is one), or null otherwise. 
        internal override ProxySimple GetFocus ()
        {
            int focusIndex = Misc.ProxySendMessageInt(_hwnd, NativeMethods.TCM_GETCURFOCUS, IntPtr.Zero, IntPtr.Zero);
 
            if (focusIndex >= 0 && focusIndex < GetItemCount(_hwnd))
            { 
                return CreateTabItem (focusIndex); 
            }
            else 
            {
                return null;
            }
        } 

        #endregion 
 
        #region ProxyHwnd Interface
 
        internal override void AdviseEventAdded(
            AutomationEvent eventId, AutomationProperty[] aidProps)
        {
            if (eventId == AutomationElementIdentifiers.AutomationPropertyChangedEvent 
                && aidProps.Length > 0
                && aidProps[0] == ScrollPatternIdentifiers.HorizontalScrollPercentProperty) 
            { 
                IntPtr upDownHwnd = GetUpDownHwnd();
                if (upDownHwnd != IntPtr.Zero) 
                {
                    // Register for UpDown ValueChange WinEvents, which will be
                    // translated to scrolling events for the tab control.
                    WinEventTracker.AddToNotificationList( 
                        upDownHwnd,
                        new WinEventTracker.ProxyRaiseEvents(UpDownControlRaiseEvents), 
                        _upDownEvents, 1); 
                }
            } 

            base.AdviseEventAdded(eventId, aidProps);
        }
 
        internal override void AdviseEventRemoved(
            AutomationEvent eventId, AutomationProperty[] aidProps) 
        { 
            if (eventId == AutomationElementIdentifiers.AutomationPropertyChangedEvent
                && aidProps.Length > 0 
                && aidProps[0] == ScrollPatternIdentifiers.HorizontalScrollPercentProperty)
            {
                IntPtr upDownHwnd = GetUpDownHwnd();
                if (upDownHwnd != IntPtr.Zero) 
                {
                    WinEventTracker.RemoveToNotificationList( 
                        upDownHwnd, _upDownEvents, null, 1); 
                }
            } 
            base.AdviseEventRemoved(eventId, aidProps);
        }

        #endregion ProxyHwnd Interface 

        #region IRawElementProviderHwndOverride Interface 
 
        //-----------------------------------------------------
        // 
        //  Interface IRawElementProviderHwndOverride
        //
        //------------------------------------------------------
        IRawElementProviderSimple IRawElementProviderHwndOverride.GetOverrideProviderForHwnd (IntPtr hwnd) 
        {
            // return the appropriate placeholder for the given hwnd... 
            // loop over all the tabs to find it. 

            string sTitle = Misc.ProxyGetText(hwnd); 

            // If there is no hwnd title there is no way to match to the tab item.
            if (string.IsNullOrEmpty(sTitle))
            { 
                return null;
            } 
 
            for (int i = 0, c = GetItemCount(_hwnd); i < c; i++)
            { 
                if (sTitle == WindowsTabItem.GetName(_hwnd, i, true))
                {
                    return new WindowsTabChildOverrideProxy(hwnd, CreateTabItem(i), i);
                } 
            }
 
            return null; 
        }
 
        #endregion IRawElementProviderHwndOverride Interface

        #region Selection Pattern
 
        // Returns an enumerator over the current selection.
        IRawElementProviderSimple[] ISelectionProvider.GetSelection() 
        { 
            IRawElementProviderSimple[] selection = null;
 
            // If only one selection allowed, get selected item, if any, and add to list
            if (!WindowsTab.SupportMultipleSelection (_hwnd))
            {
                int selectedItem = WindowsTabItem.GetCurrentSelectedItem(_hwnd); 

                if (selectedItem >= 0) 
                { 
                    selection = new IRawElementProviderSimple[1];
                    selection[0] = CreateTabItem(selectedItem); 
                }
            }

            // If multiple selections allowed, check each tab for selected state 
                else
            { 
                ArrayList list = new ArrayList(); 
                for (ProxySimple child = GetFirstChild(); child != null; child = GetNextSibling(child))
                { 
                    if (((ISelectionItemProvider) child).IsSelected)
                    {
                        list.Add (child);
                    } 
                }
 
                int count = list.Count; 
                if (count <= 0)
                { 
                    return null;
                }

                selection = new IRawElementProviderSimple[count]; 
                for (int i = 0; i < count; i++)
                { 
                    selection[i] = (ProxySimple)list[i]; 
                }
            } 

            return selection;
        }
 
        // Returns whether the control supports multiple selection.
        bool ISelectionProvider.CanSelectMultiple 
        { 
            get
            { 
                return SupportMultipleSelection (_hwnd);
            }
        }
 
        // Returns whether the control requires a minimum of one selected element at all times.
        bool ISelectionProvider.IsSelectionRequired 
        { 
            get
            { 
                return !Misc.IsBitSet(WindowStyle, NativeMethods.TCS_BUTTONS);
            }
        }
 
        #endregion ISelectionProvider
 
        #region Scroll Pattern 

        void IScrollProvider.Scroll (ScrollAmount horizontalAmount, ScrollAmount verticalAmount) 
        {
            // Make sure that the control is enabled
            if (!SafeNativeMethods.IsWindowEnabled(_hwnd))
            { 
                throw new ElementNotEnabledException();
            } 
 
            if (!IsScrollable())
            { 
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
            }

            if (verticalAmount != ScrollAmount.NoAmount) 
            {
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); 
            } 

            if (!Scroll(horizontalAmount)) 
            {
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
            }
        } 

        void IScrollProvider.SetScrollPercent (double horizontalPercent, double verticalPercent) 
        { 
            // Make sure that the control is enabled
            if (!SafeNativeMethods.IsWindowEnabled(_hwnd)) 
            {
                throw new ElementNotEnabledException();
            }
 
            if (!IsScrollable())
            { 
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); 
            }
 
            if ((int)verticalPercent != (int)ScrollPattern.NoScroll)
            {
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
            } 
            else if ((int)horizontalPercent == (int)ScrollPattern.NoScroll)
            { 
                return; 
            }
            else if (horizontalPercent < 0 || horizontalPercent > 100) 
            {
                throw new ArgumentOutOfRangeException("horizontalPercent", SR.Get(SRID.ScrollBarOutOfRange));
            }
 
            // Get up/down control's hwnd
            IntPtr updownHwnd = this.GetUpDownHwnd (); 
 
            if (updownHwnd == IntPtr.Zero)
            { 
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
            }

            // Get available range 
            int range = Misc.ProxySendMessageInt(updownHwnd, NativeMethods.UDM_GETRANGE, IntPtr.Zero, IntPtr.Zero);
            int minPos = NativeMethods.Util.HIWORD(range); 
            int maxPos = NativeMethods.Util.LOWORD(range); 

            // Calculate new position 
            int newPos = (int) Math.Round ((maxPos - minPos) * horizontalPercent / 100) + minPos;

            // Set position
            Misc.ProxySendMessage(updownHwnd, NativeMethods.UDM_SETPOS, IntPtr.Zero, (IntPtr)newPos); 
            Misc.ProxySendMessage(_hwnd, NativeMethods.WM_HSCROLL, (IntPtr)NativeMethods.Util.MAKELPARAM(NativeMethods.SB_THUMBPOSITION, newPos), IntPtr.Zero);
        } 
 

        // Calc the position of the horizontal scroll bar thumb in the 0..100 % range 
        double IScrollProvider.HorizontalScrollPercent
        {
            get
            { 
                double minPos, maxPos, currentPos;
 
                // Get up/down control's hwnd 
                IntPtr updownHwnd = this.GetUpDownHwnd ();
 
                if (updownHwnd == IntPtr.Zero)
                {
                    return (double)ScrollPattern.NoScroll;
                } 

                // Get range of position values 
                int range = Misc.ProxySendMessageInt(updownHwnd, NativeMethods.UDM_GETRANGE, IntPtr.Zero, IntPtr.Zero); 

                // Get current position 
                int posResult = Misc.ProxySendMessageInt(updownHwnd, NativeMethods.UDM_GETPOS, IntPtr.Zero, IntPtr.Zero);

                // Calculate percentage position
                minPos = NativeMethods.Util.HIWORD(range); 
                maxPos = NativeMethods.Util.LOWORD(range);
                currentPos = NativeMethods.Util.LOWORD(posResult); 
                return (currentPos - minPos) / (maxPos - minPos) * 100; 
            }
        } 

        // Calc the position of the Vertical scroll bar thumb in the 0..100 % range
        double IScrollProvider.VerticalScrollPercent
        { 
            get
            { 
                // Tab controls can never be vertically scrolling 
                // since vertical tab controls must have the multiline style
                return (double)ScrollPattern.NoScroll; 
            }
        }

        // Percentage of the window that is visible along the horizontal axis. 
        // Value 0..100
        double IScrollProvider.HorizontalViewSize 
        { 
            get
            { 
                ProxySimple firstChild = GetFirstChild ();
                ProxySimple lastChild = GetLastChild ();

                // Get rectangles 
                Rect firstRect = firstChild.BoundingRectangle;
                Rect lastRect = lastChild.BoundingRectangle; 
                NativeMethods.Win32Rect viewable = new NativeMethods.Win32Rect (); 

                viewable.left = 0; 
                if (!Misc.GetWindowRect(_hwnd, ref viewable))
                {
                    return 100.0;
                } 

                // Calculate ranges 
                double totalRange = (double)lastRect.Right - (double)firstRect.Left; 
                double viewableRange = viewable.right - viewable.left;
 
                // Get the rectangle of the up/down control and adjust viewable range
                IntPtr updownHwnd = this.GetUpDownHwnd ();

                if (updownHwnd == IntPtr.Zero) 
                {
                    return 100.0; 
                } 

                NativeMethods.Win32Rect rectW32 = new NativeMethods.Win32Rect (); 

                if (!Misc.GetWindowRect(updownHwnd, ref rectW32))
                {
                    return 100.0; 
                }
 
                viewableRange -= rectW32.right - rectW32.left; 
                return viewableRange / totalRange * 100;
            } 
        }

        // Percentage of the window that is visible along the vertical axis.
        // Value 0..100 
        double IScrollProvider.VerticalViewSize
        { 
            get 
            {
                return 100.0; 
            }
        }

        // Can the element be horizontaly scrolled 
        bool IScrollProvider.HorizontallyScrollable
        { 
            get 
            {
                return IsScrollable(); 
            }
        }

        // Can the element be verticaly scrolled 
        bool IScrollProvider.VerticallyScrollable
        { 
            get 
            {
                return false; 
            }
        }

        #endregion IScrollProvider 

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

        #region Internal Methods
 
        internal static int GetItemCount(IntPtr hwnd)
        { 
            // The Display Property Dialog is doing something strange with the their tab control.  The 
            // last tab is invisable. So if that is the case remove it from the count, since UIAutomation
            // can not do anything with it. 
            int count = Misc.ProxySendMessageInt(hwnd, NativeMethods.TCM_GETITEMCOUNT, IntPtr.Zero, IntPtr.Zero);

            if (count > 0)
            { 
                NativeMethods.Win32Rect rectW32 = NativeMethods.Win32Rect.Empty;
                bool result; 
                unsafe 
                {
                    result = XSendMessage.XSend(hwnd, NativeMethods.TCM_GETITEMRECT, new IntPtr(count - 1), new IntPtr(&rectW32), Marshal.SizeOf(rectW32.GetType()), XSendMessage.ErrorValue.Zero); 
                }
                if (!result)
                {
                    count--; 
                }
                if (rectW32.IsEmpty) 
                { 
                    count--;
                } 
            }

            return count;
        } 

        // Create a WindowsTab instance 
        internal ProxyFragment CreateTabItem(int index) 
        {
            return new WindowsTabItem(_hwnd, this, index, _windowsForms == WindowsFormsHelper.FormControlState.True); 
        }

        internal void ScrollToItem(int index)
        { 
            if (!IsScrollable())
            { 
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); 
            }
 
            // Get up/down control's hwnd
            IntPtr updownHwnd = this.GetUpDownHwnd();

            if (updownHwnd == IntPtr.Zero) 
                return;
 
            int range = Misc.ProxySendMessageInt(updownHwnd, NativeMethods.UDM_GETRANGE, IntPtr.Zero, IntPtr.Zero); 
            int max = NativeMethods.Util.LOWORD(range);
            int newPos = index < max ? index : max; 

            Misc.ProxySendMessage(updownHwnd, NativeMethods.UDM_SETPOS, IntPtr.Zero, (IntPtr)newPos);
            Misc.ProxySendMessage(_hwnd, NativeMethods.WM_HSCROLL, NativeMethods.Util.MAKELPARAM(NativeMethods.SB_THUMBPOSITION, newPos), IntPtr.Zero);
        } 

        internal bool IsScrollable() 
        { 
            return GetUpDownHwnd(_hwnd) != IntPtr.Zero;
        } 

        // if all the tab items have no name then the control is not useful
        internal static bool IsValidControl(IntPtr hwnd)
        { 
            for (int i = 0, c = GetItemCount(hwnd); i < c; i++)
            { 
                if (!string.IsNullOrEmpty(WindowsTabItem.GetName(hwnd, i, true))) 
                {
                    return true; 
                }
            }

            return false; 
        }
 
        // Process events for the associated UpDown control, and relay 
        // them to the WindowsTab control instead.
        internal static void UpDownControlRaiseEvents( 
            IntPtr hwnd, int eventId, object idProp, int idObject, int idChild)
        {
            if (eventId == NativeMethods.EventObjectValueChange
                && idProp == ScrollPattern.HorizontalScrollPercentProperty) 
            {
                IntPtr hwndParent = UnsafeNativeMethods.GetAncestor(hwnd, NativeMethods.GA_PARENT); 
                if (hwndParent != IntPtr.Zero 
                   && Misc.ProxyGetClassName(hwndParent).Contains("SysTabControl32"))
                { 
                    WindowsTab el = new WindowsTab(hwndParent, null, 0);
                    el.DispatchEvents(eventId, idProp, 0, 0);
                }
            } 
        }
 
        #endregion Internal Methods 

        // ------------------------------------------------------ 
        //
        // Private Methods
        //
        // ----------------------------------------------------- 

        #region Private Methods 
 
        // Gets the windows handle of the UpDown control in the tab control
        // Returns the handle to the UpDown control or IntPtr.Zero if this tab control isn't scrollable. 
        private IntPtr GetUpDownHwnd()
        {
            return GetUpDownHwnd(_hwnd);
        } 
        private static IntPtr GetUpDownHwnd(IntPtr hwnd)
        { 
            IntPtr childHwnd = Misc.GetWindow(hwnd, NativeMethods.GW_CHILD); 
            string className;
            int i; 

            // UpDown control is either the first or last child, so do this check twice
            for (i = 0; i < 2; i++)
            { 
                if (childHwnd != IntPtr.Zero)
                { 
                    className = Misc.ProxyGetClassName(childHwnd); 
                    if (className.IndexOf("updown", StringComparison.Ordinal) > -1)
                    { 
                        // found it
                        return childHwnd;
                    }
 
                    childHwnd = Misc.GetWindow(childHwnd, NativeMethods.GW_HWNDLAST);
                } 
                else 
                {
                    // didn't find it 
                    break;
                }
            }
 
            return IntPtr.Zero;
        } 
 
        private bool IsVerticalTab()
        { 
            int style = WindowStyle;
            return Misc.IsBitSet(style, NativeMethods.TCS_MULTILINE) &&
                    (Misc.IsBitSet(style, NativeMethods.TCS_RIGHT) ||
                     Misc.IsBitSet(style, NativeMethods.TCS_VERTICAL)); 
        }
 
        #endregion Private Methods 

        #region Scroll Helper 

        private bool Scroll(ScrollAmount amount)
        {
            // Done 
            if (amount == ScrollAmount.NoAmount)
            { 
                return true; 
            }
 
            // Get up/down control's hwnd
            IntPtr updownHwnd = this.GetUpDownHwnd ();

            if (updownHwnd == IntPtr.Zero) 
            {
                return false; 
            } 

            // 

            int newPos = Misc.ProxySendMessageInt(updownHwnd, NativeMethods.UDM_GETPOS, IntPtr.Zero, IntPtr.Zero);
            int range = Misc.ProxySendMessageInt(updownHwnd, NativeMethods.UDM_GETRANGE, IntPtr.Zero, IntPtr.Zero);
            int max = NativeMethods.Util.LOWORD(range); 
            int min = NativeMethods.Util.HIWORD(range);
 
            if (NativeMethods.Util.HIWORD (newPos) == 0) 
            {
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); 
            }

            newPos = NativeMethods.Util.LOWORD (newPos);
            switch (amount) 
            {
                case ScrollAmount.LargeDecrement : 
                case ScrollAmount.LargeIncrement : 
                    // Not supported.
                    return false; 

                case ScrollAmount.SmallDecrement :
                    newPos--;
                    break; 

                case ScrollAmount.SmallIncrement : 
                    newPos++; 
                    break;
 
                default :  // should never get here
                    return false;
            }
 
            if (newPos < min || newPos > max)
            { 
                // Attempt to scroll before beginning or past end. 
                // As long as this is a supported operation (namely,
                // SmallIncrement or SmallDecrement), do nothing but 
                // return success.
                return true;
            }
 
            // Update both the spiner and the tabs
            Misc.ProxySendMessage(updownHwnd, NativeMethods.UDM_SETPOS, IntPtr.Zero, (IntPtr)newPos); 
            Misc.ProxySendMessage(_hwnd, NativeMethods.WM_HSCROLL, NativeMethods.Util.MAKELPARAM(NativeMethods.SB_THUMBPOSITION, newPos), IntPtr.Zero); 

            return true; 
        }

        #endregion
 
        #region Selection Helper
 
        // detect if tab-control supports multiple selection 
        static internal bool SupportMultipleSelection (IntPtr hwnd)
        { 
            return Misc.IsBitSet(Misc.GetWindowStyle(hwnd), (NativeMethods.TCS_BUTTONS | NativeMethods.TCS_MULTISELECT));
        }

        #endregion 

        // ----------------------------------------------------- 
        // 
        // Private Fields
        // 
        // -----------------------------------------------------

        #region Private Fields
 
        private const int SpinControl = -2;
 
        // Updown specific events. 
        private readonly static WinEventTracker.EvtIdProperty[] _upDownEvents;
 
        #endregion
    }

    // ------------------------------------------------------ 
    //
    // WindowsTabItem Private Class 
    // 
    // -----------------------------------------------------
 
    #region WindowsTabItem

    class WindowsTabItem : ProxyFragment, ISelectionItemProvider, IScrollItemProvider
    { 
        // ------------------------------------------------------
        // 
        // Constructors 
        //
        // ------------------------------------------------------ 

        #region Constructors

        internal WindowsTabItem(IntPtr hwnd, ProxyFragment parent, int item, bool fIsWinform) 
            : base( hwnd, parent, item )
        { 
            // Set the strings to return properly the properties. 
            _cControlType = ControlType.TabItem;
            _fIsKeyboardFocusable = true; 

            _fIsWinform = fIsWinform;
            _fIsContent = !string.IsNullOrEmpty(GetName(_hwnd, _item, true));
        } 

        #endregion 
 
        // -----------------------------------------------------
        // 
        //  Patterns Implementation
        //
        // ------------------------------------------------------
 
        #region ProxySimple Interface
 
        // Returns a pattern interface if supported. 
        internal override object GetPatternProvider(AutomationPattern iid)
        { 
            if(iid == SelectionItemPattern.Pattern)
            {
                return this;
            } 
            else if (iid == ScrollItemPattern.Pattern)
            { 
                return this; 
            }
 
            return null;
        }

        // Gets the bounding rectangle for this element 
        internal override Rect BoundingRectangle
        { 
            get 
            {
                return BoundingRect().ToRect(Misc.IsControlRTL(_hwnd)); 
            }
        }

        // Process all the Logical and Raw Element Properties 
        internal override object GetElementProperty(AutomationProperty idProp)
        { 
            if (idProp == AutomationElement.AccessKeyProperty && _windowsForms != WindowsFormsHelper.FormControlState.True) 
            {
                return Misc.AccessKey(WindowsTabItem.GetItemText(_hwnd, _item)); 
            }
            else if (idProp == AutomationElement.IsControlElementProperty)
            {
                return !string.IsNullOrEmpty(GetName(_hwnd, _item, true)); 
            }
 
            return base.GetElementProperty(idProp); 
        }
 
        //Gets the controls help text
        internal override string HelpText
        {
            get 
            {
                IntPtr hwndToolTip = Misc.ProxySendMessage(_hwnd, NativeMethods.TCM_GETTOOLTIPS, IntPtr.Zero, IntPtr.Zero); 
                return Misc.GetItemToolTipText(_hwnd, hwndToolTip, _item); 
            }
        } 

        //Gets the localized name
        internal override string LocalizedName
        { 
            get
            { 
                // If this is a winforms tab page and the AccessibleName is set, use it. 
                if (WindowsFormsHelper.IsWindowsFormsControl(_hwnd, ref _windowsForms))
                { 
                    string name = GetAccessibleName(_item + 1);
                    if (!string.IsNullOrEmpty(name))
                    {
                        return name; 
                    }
                } 
 
                return GetName(_hwnd, _item, _windowsForms == WindowsFormsHelper.FormControlState.True);
            } 
        }

        // Sets the focus to this item.
        internal override bool SetFocus() 
        {
            if (Misc.IsBitSet(WindowStyle, NativeMethods.TCS_FOCUSNEVER)) 
            { 
                return false;
            } 

            WindowsTab tab = (WindowsTab)_parent;
            ProxySimple focused = tab.GetFocus();
 
            if (focused == null || _item != focused._item)
            { 
                Misc.ProxySendMessage(_hwnd, NativeMethods.TCM_SETCURFOCUS, new IntPtr(_item), IntPtr.Zero); 
            }
 
            return true;
        }

        #endregion ProxySimple Interface 

        #region ProxyFragment Interface 
 
        // Returns the next sibling element in the raw hierarchy.
        // Peripheral controls have always negative values. 
        // Param name="child", the current child
        // Returns null if no next child
        internal override ProxySimple GetNextSibling(ProxySimple child)
        { 
            return null;
        } 
 
        // Returns the previous sibling element in the raw hierarchy.
        // Peripheral controls have always negative values. 
        // Param name="child", the current child
        // Returns null is no previous
        internal override ProxySimple GetPreviousSibling(ProxySimple child)
        { 
            return null;
        } 
 
        // Returns the first child element in the raw hierarchy.
        internal override ProxySimple GetFirstChild() 
        {
            IntPtr hwndChild = GetItemHwndByIndex();
            if (hwndChild != IntPtr.Zero && SafeNativeMethods.IsWindowVisible(hwndChild))
            { 
                return new WindowsTabChildOverrideProxy(hwndChild, this, _item);
            } 
 
            return null;
        } 

        // Returns the last child element in the raw hierarchy.
        internal override ProxySimple GetLastChild()
        { 
            // One children at most for form or nothing for Win32 controls.
            return GetFirstChild(); 
        } 

        #endregion ProxyFragment Interface 

        #region Selection Pattern

        // Selects this element 
        void ISelectionItemProvider.Select()
        { 
            // Make sure that the control is enabled 
            if (!SafeNativeMethods.IsWindowEnabled(_hwnd))
            { 
                throw new ElementNotEnabledException();
            }

            if (!IsSelectable()) 
            {
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); 
            } 

            if (((ISelectionItemProvider)this).IsSelected == false) 
            {
                Select();
            }
        } 

        // Adds this element to the selection 
        void ISelectionItemProvider.AddToSelection() 
        {
            // Make sure that the control is enabled 
            if (!SafeNativeMethods.IsWindowEnabled(_hwnd))
            {
                throw new ElementNotEnabledException();
            } 

            // If not selectable, can't add to selection 
            if (!IsSelectable()) 
            {
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); 
            }

            // If already selected, done
            if (((ISelectionItemProvider)this).IsSelected) 
            {
                return; 
            } 

            // If multiple selections allowed, add requested selection 
            if (WindowsTab.SupportMultipleSelection(_hwnd) == true)
            {
                // Press ctrl and mouse click tab
                NativeMethods.Win32Point pt = new NativeMethods.Win32Point(); 
                if (GetClickablePoint(out pt, true))
                { 
                    Input.SendKeyboardInput(Key.LeftCtrl, true); 
                    Misc.MouseClick(pt.x, pt.y);
                    Input.SendKeyboardInput(Key.LeftCtrl, false); 
                    return;
                }

                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); 
            }
            // else only single selection allowed 
            else 
            {
                throw new InvalidOperationException(SR.Get(SRID.DoesNotSupportMultipleSelection)); 
            }
        }

        // Removes this element from the selection 
        void ISelectionItemProvider.RemoveFromSelection()
        { 
            // Make sure that the control is enabled 
            if (!SafeNativeMethods.IsWindowEnabled(_hwnd))
            { 
                throw new ElementNotEnabledException();
            }

            // If not selected, done 
            if (!((ISelectionItemProvider)this).IsSelected)
            { 
                return; 
            }
 
            // If multiple selections allowed, unselect element
            if (WindowsTab.SupportMultipleSelection(_hwnd) == true)
            {
                NativeMethods.Win32Point pt = new NativeMethods.Win32Point(); 
                if (GetClickablePoint(out pt, true))
                { 
                    Input.SendKeyboardInput(Key.LeftCtrl, true); 
                    Misc.MouseClick(pt.x, pt.y);
                    Input.SendKeyboardInput(Key.LeftCtrl, false); 
                    return;
                }

                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); 
            }
            // else if button style and single select, send deselectall message 
            else if (Misc.IsBitSet(WindowStyle, NativeMethods.TCS_BUTTONS)) 
            {
                Misc.ProxySendMessage(_hwnd, NativeMethods.TCM_DESELECTALL, IntPtr.Zero, IntPtr.Zero); 
                return;
            }

            throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); 
        }
 
        // True if this element is part of the the selection 
        bool ISelectionItemProvider.IsSelected
        { 
            get
            {
                // If only a single selection is allowed, check which one is selected and compare
                if (!WindowsTab.SupportMultipleSelection(_hwnd)) 
                {
                    int selectedItem = GetCurrentSelectedItem(_hwnd); 
 
                    return (_item == selectedItem);
                } 

                // If multiple selections possible, get state information on the tab
                else
                { 
                    NativeMethods.TCITEM TCItem = new NativeMethods.TCITEM();
                    TCItem.Init(NativeMethods.TCIF_STATE); 
 
                    if (!XSendMessage.GetItem(_hwnd, _item, ref TCItem))
                    { 
                        System.Diagnostics.Debug.Assert(false, "XSendMessage.GetItem() failed!");
                        return false;
                    }
 
                    return Misc.IsBitSet(TCItem.dwState, NativeMethods.TCIS_BUTTONPRESSED);
                } 
            } 
        }
 
        // Returns the container for this element
        IRawElementProviderSimple ISelectionItemProvider.SelectionContainer
        {
            get 
            {
                System.Diagnostics.Debug.Assert(_parent is WindowsTab, "Invalid Parent for a Tab Item"); 
                return _parent; 
            }
        } 

        #endregion SelectionItem Pattern

        #region ScrollItem Pattern 

        void IScrollItemProvider.ScrollIntoView() 
        { 
            // Make sure that the control is enabled
            if (!SafeNativeMethods.IsWindowEnabled(_hwnd)) 
            {
                throw new ElementNotEnabledException();
            }
 
            WindowsTab parent = (WindowsTab)_parent;
 
            if (!parent.IsScrollable()) 
            {
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); 
            }

            parent.ScrollToItem(_item);
        } 

        #endregion ScrollItem Pattern 
 
        // -----------------------------------------------------
        // 
        // Internal Methods
        //
        // -----------------------------------------------------
 
        #region Internal Methods
 
        // Retrieve the text in a tab item 
        internal static string GetName(IntPtr hwnd, int item, bool fIsWinform)
        { 
            string sName = GetItemText(hwnd, item);

            // Win32 controls '&' is used as an accelerator. This is not the case for winforms !!!
            return !fIsWinform ? Misc.StripMnemonic(sName) : sName; 
        }
 
        internal static int GetCurrentSelectedItem(IntPtr hwnd) 
        {
            return Misc.ProxySendMessageInt(hwnd, NativeMethods.TCM_GETCURSEL, IntPtr.Zero, IntPtr.Zero); 
        }

        #endregion Internal Methods
 
        //-----------------------------------------------------
        // 
        //  Protected Methods 
        //
        //------------------------------------------------------ 

        #region Protected Methods

        // This routine is only called on elements belonging to an hwnd that has the focus. 
        protected override bool IsFocused()
        { 
            return Misc.ProxySendMessageInt(_hwnd, NativeMethods.TCM_GETCURFOCUS, IntPtr.Zero, IntPtr.Zero) == _item; 
        }
 
        #endregion Protected Methods

        // -----------------------------------------------------
        // 
        // Private Methods
        // 
        // ------------------------------------------------------ 

        #region Private Methods 

        private unsafe NativeMethods.Win32Rect BoundingRect()
        {
            NativeMethods.Win32Rect rectW32 = new NativeMethods.Win32Rect(); 

            if (!XSendMessage.XSend(_hwnd, NativeMethods.TCM_GETITEMRECT, new IntPtr(_item), new IntPtr(&rectW32), Marshal.SizeOf(rectW32.GetType()), XSendMessage.ErrorValue.Zero)) 
            { 
                return NativeMethods.Win32Rect.Empty;
            } 

            return Misc.MapWindowPoints(_hwnd, IntPtr.Zero, ref rectW32, 2) ? rectW32 : NativeMethods.Win32Rect.Empty;
        }
 
        private bool IsSelectable()
        { 
            return (SafeNativeMethods.IsWindowEnabled(_hwnd) && SafeNativeMethods.IsWindowVisible(_hwnd)); 
        }
 
        // Press a tab
        private void Select()
        {
            if (Misc.IsBitSet(WindowStyle, (NativeMethods.TCS_BUTTONS | NativeMethods.TCS_FOCUSNEVER))) 
            {
                // The TCM_SETCURFOCUS message cannot be used with TCS_FOCUSNEVER 
                // use a convulated way faking a mouse action 

                NativeMethods.Win32Point pt = new NativeMethods.Win32Point(); 
                if (GetClickablePoint(out pt, true))
                {
                    // Convert screen coordinates to client coordinates.
                    if (Misc.MapWindowPoints(IntPtr.Zero, _hwnd, ref pt, 1)) 
                    {
                        Misc.PostMessage(_hwnd, NativeMethods.WM_LBUTTONDOWN, (IntPtr)NativeMethods.MK_LBUTTON, NativeMethods.Util.MAKELPARAM(pt.x, pt.y)); 
                        Misc.PostMessage(_hwnd, NativeMethods.WM_LBUTTONUP, (IntPtr)NativeMethods.MK_LBUTTON, NativeMethods.Util.MAKELPARAM(pt.x, pt.y)); 
                    }
                } 
            }
            else
            {
                Misc.ProxySendMessage(_hwnd, NativeMethods.TCM_SETCURFOCUS, new IntPtr(_item), IntPtr.Zero); 
            }
 
        } 

        // Gets the windows handle of an individual tab in a Windows Forms control 
        private IntPtr GetItemHwndByIndex()
        {
            // On Win32 Tab controls the table page is parented by the dialog box not the
            // Tab control. 
            IntPtr hwndParent = _hwnd;
            if (!_fIsWinform) 
            { 
                hwndParent = Misc.GetParent(hwndParent);
            } 

            if (hwndParent != IntPtr.Zero)
            {
                // Get the tab name and match it with the window title of one of the children 
                string sName = WindowsTabItem.GetName(_hwnd, _item, true);
 
                // If there is no tab name there is no way to match to one of the childrens window title. 
                if (!string.IsNullOrEmpty(sName))
                { 
                    return Misc.FindWindowEx(hwndParent, IntPtr.Zero, null, sName);
                }
            }
 
            return IntPtr.Zero;
        } 
 

        private static string GetItemText(IntPtr hwnd, int itemIndex) 
        {
            NativeMethods.TCITEM tcitem = new NativeMethods.TCITEM();
            tcitem.Init();
 
            tcitem.mask = NativeMethods.TCIF_TEXT;
            tcitem.cchTextMax = Misc.MaxLengthNameProperty; 
 
            return XSendMessage.GetItemText(hwnd, itemIndex, tcitem);
        } 

        #endregion Private Methods

        // ------------------------------------------------------ 
        //
        // Private Fields 
        // 
        // -----------------------------------------------------
 
        #region Private Fields

        // Cached value for a winform
        bool _fIsWinform; 

        #endregion Private Fields 
    } 

    #endregion 

    // ------------------------------------------------------
    //
    //  WindowsTabChildOverrideProxy Class 
    //
    //----------------------------------------------------- 
 
    #region WindowsTabChildOverrideProxy
 
    class WindowsTabChildOverrideProxy : ProxyHwnd
    {
        // -----------------------------------------------------
        // 
        // Constructors
        // 
        // ----------------------------------------------------- 

        #region Constructors 

        // Constructor
        // Usually the hwnd passed to the constructor is wrong. As the base class is doing
        // nothing this does not matter. 
        // This avoid to making some extra calls to get this right.
        internal WindowsTabChildOverrideProxy(IntPtr hwnd, ProxyFragment parent, int item) 
            : base (hwnd, parent, item) 
        {
        } 

            #endregion

        //------------------------------------------------------ 
        //
        //  Patterns Implementation 
        // 
        //-----------------------------------------------------
 
        #region ProxySimple Interface

        internal override ProviderOptions ProviderOptions
        { 
            get
            { 
                return base.ProviderOptions | ProviderOptions.OverrideProvider; 
            }
        } 

        // Process all the Logical and Raw Element Properties
        internal override object GetElementProperty(AutomationProperty idProp)
        { 
            if (idProp == AutomationElement.IsControlElementProperty)
            { 
                return false; 
            }
            // Overrides the ProxySimple implementation to remove and default 
            // property handling
            // This proxy is about tree rearranging, it does not do any
            // property overrride.
            return null; 
        }
 
        #endregion 
    }
 
    #endregion
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
/****************************************************************************\ 
*
* File: WindowsTab.cs
*
* Description: 
* HWND-based tab control proxy
* 
* Copyright (C) 2002 by Microsoft Corporation.  All rights reserved. 
*
\***************************************************************************/ 

using System;
using System.Collections;
using System.Text; 
using System.Windows.Automation;
using System.Windows.Automation.Provider; 
using System.Runtime.InteropServices; 
using System.ComponentModel;
using System.Windows; 
using System.Windows.Input;
using MS.Win32;

namespace MS.Internal.AutomationProxies 
{
    class WindowsTab: ProxyHwnd, ISelectionProvider, IScrollProvider, IRawElementProviderHwndOverride 
    { 
        // -----------------------------------------------------
        // 
        // Constructors
        //
        // -----------------------------------------------------
 
        #region Constructors
 
        public WindowsTab (IntPtr hwnd, ProxyFragment parent, int item) 
            : base( hwnd, parent, item )
        { 
            // Set the strings to return properly the properties.
            _cControlType = ControlType.Tab;

            // force initialisation of this so it can be used later 
            _windowsForms = WindowsFormsHelper.GetControlState (hwnd);
 
            // support for events 
            _createOnEvent = new WinEventTracker.ProxyRaiseEvents (RaiseEvents);
 
            _fIsContent = IsValidControl(_hwnd);
        }

        static WindowsTab () 
        {
            _upDownEvents = new WinEventTracker.EvtIdProperty [1]; 
            _upDownEvents[0]._evtId = NativeMethods.EventObjectValueChange; 
            _upDownEvents[0]._idProp = ScrollPattern.HorizontalScrollPercentProperty;
        } 

        #endregion

        #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);
        }

        private static IRawElementProviderSimple Create(IntPtr hwnd, int idChild) 
        {
            WindowsTab wTab = new WindowsTab(hwnd, null, 0); 
 
            return idChild == 0 ? wTab : wTab.CreateTabItem (idChild - 1);
        } 

        // Static Create method called by the event tracker system
        // WinEvents are one throwns because items exist. so it makes sense to create the item and
        // check for details afterward. 
        internal static void RaiseEvents (IntPtr hwnd, int eventId, object idProp, int idObject, int idChild)
        { 
            ProxySimple el = null; 

            switch (idObject) 
            {
                case NativeMethods.OBJID_CLIENT :
                {
                    WindowsTab wlv = new WindowsTab (hwnd, null, -1); 

                    if (eventId == NativeMethods.EventObjectSelection || eventId == NativeMethods.EventObjectSelectionRemove || eventId == NativeMethods.EventObjectSelectionAdd) 
                    { 
                        el = wlv.CreateTabItem (idChild - 1);
                    } 
                    else
                    {
                        el = wlv;
                    } 

                    break; 
                } 

                default : 
                    if ((idProp == ScrollPattern.VerticalScrollPercentProperty && idObject != NativeMethods.OBJID_VSCROLL) ||
                        (idProp == ScrollPattern.HorizontalScrollPercentProperty && idObject != NativeMethods.OBJID_HSCROLL))
                    {
                        return; 
                    }
 
                    el = new WindowsTab(hwnd, null, -1); 
                    break;
            } 
            if (el != null)
            {
                el.DispatchEvents (eventId, idProp, idObject, idChild);
            } 
        }
 
        #endregion 

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

        #region ProxySimple Interface 
 
        // Returns a pattern interface if supported.
        // Param name="iid", UIAutomation Pattern 
        // Returns null or pattern interface
        internal override object GetPatternProvider (AutomationPattern iid)
        {
            if (iid == SelectionPattern.Pattern) 
            {
                return this; 
            } 

            if (iid == ScrollPattern.Pattern) 
            {
                return this;
            }
 
            return null;
        } 
 
        // Process all the Logical and Raw Element Properties
        internal override object GetElementProperty(AutomationProperty idProp) 
        {
            if (idProp == AutomationElement.IsControlElementProperty)
            {
                return IsValidControl(_hwnd); 
            }
            else if (idProp == AutomationElement.OrientationProperty) 
            { 
                return IsVerticalTab() ? OrientationType.Vertical : OrientationType.Horizontal;
            } 
            else if (idProp == ScrollPatternIdentifiers.HorizontalScrollPercentProperty)
            {
                return ((IScrollProvider)this).HorizontalScrollPercent;
            } 
            else if (idProp == ScrollPatternIdentifiers.HorizontallyScrollableProperty)
            { 
                return ((IScrollProvider)this).HorizontallyScrollable; 
            }
            else if (idProp == ScrollPatternIdentifiers.HorizontalViewSizeProperty) 
            {
                return ((IScrollProvider)this).HorizontalViewSize;
            }
 
            return base.GetElementProperty(idProp);
        } 
 
        #endregion ProxySimple Interface
 
        #region ProxyFragment Interface

        // Returns the next sibling element in the raw hierarchy.
        // Peripheral controls have always negative values. 
        // Param name="child", the current child
        // Returns null if no next child 
        internal override ProxySimple GetNextSibling (ProxySimple child) 
        {
            int item = child._item; 

            if (item != SpinControl)
            {
                int count = GetItemCount(_hwnd); 

                // Next for an item that does not exist in the list 
                if (item >= count) 
                {
                    throw new ElementNotAvailableException (); 
                }

                if (item + 1 < count)
                { 
                    return CreateTabItem(item + 1);
                } 
            } 

            return null; 
        }

        // Returns the previous sibling element in the raw hierarchy.
        // Peripheral controls have always negative values. 
        // Param name="child", the current child
        // Returns null is no previous 
        internal override ProxySimple GetPreviousSibling (ProxySimple child) 
        {
            int count = GetItemCount(_hwnd); 
            int item = child._item;

            if (item == SpinControl)
                item = count; 

            // Next for an item that does not exist in the list 
            if (item >= count) 
            {
                throw new ElementNotAvailableException (); 
            }

            if (item > 0 && item <= count)
            { 
                return CreateTabItem(item - 1);
            } 
 
            return null;
        } 

        // Returns the first child element in the raw hierarchy.
        internal override ProxySimple GetFirstChild ()
        { 
            int count = GetItemCount(_hwnd);
 
            if (count > 0) 
            {
                return CreateTabItem(0); 
            }

            return null;
        } 

        // Returns the last child element in the raw hierarchy. 
        internal override ProxySimple GetLastChild () 
        {
            int count = GetItemCount(_hwnd); 

            if (count > 0)
            {
                return CreateTabItem(count - 1); 
            }
 
            return null; 
        }
 
        // Returns a Proxy element corresponding to the specified screen coordinates.
        internal override ProxySimple ElementProviderFromPoint (int x, int y)
        {
            UnsafeNativeMethods.TCHITTESTINFO hti = new UnsafeNativeMethods.TCHITTESTINFO(); 

            hti.pt = new NativeMethods.Win32Point (x, y); 
 
            if (!Misc.MapWindowPoints(IntPtr.Zero, _hwnd, ref hti.pt, 1))
            { 
                return null;
            }

            // updown control goes over the tabs hence the order of the check 
            // We cannot let UIAutomation do the do the drilling for the updown as the spinner covers the tab
            IntPtr updownHwnd = this.GetUpDownHwnd (); 
 
            if (updownHwnd != IntPtr.Zero && Misc.PtInWindowRect(updownHwnd, x, y))
            { 
                return null;
            }

            int index; 
            unsafe
            { 
                index = XSendMessage.XSendGetIndex(_hwnd, NativeMethods.TCM_HITTEST, IntPtr.Zero, new IntPtr(&hti), Marshal.SizeOf(hti.GetType())); 
            }
 
            if (index >= 0)
            {
                return CreateTabItem (index);
            } 

            return null; 
        } 

        // Returns an item corresponding to the focused element (if there is one), or null otherwise. 
        internal override ProxySimple GetFocus ()
        {
            int focusIndex = Misc.ProxySendMessageInt(_hwnd, NativeMethods.TCM_GETCURFOCUS, IntPtr.Zero, IntPtr.Zero);
 
            if (focusIndex >= 0 && focusIndex < GetItemCount(_hwnd))
            { 
                return CreateTabItem (focusIndex); 
            }
            else 
            {
                return null;
            }
        } 

        #endregion 
 
        #region ProxyHwnd Interface
 
        internal override void AdviseEventAdded(
            AutomationEvent eventId, AutomationProperty[] aidProps)
        {
            if (eventId == AutomationElementIdentifiers.AutomationPropertyChangedEvent 
                && aidProps.Length > 0
                && aidProps[0] == ScrollPatternIdentifiers.HorizontalScrollPercentProperty) 
            { 
                IntPtr upDownHwnd = GetUpDownHwnd();
                if (upDownHwnd != IntPtr.Zero) 
                {
                    // Register for UpDown ValueChange WinEvents, which will be
                    // translated to scrolling events for the tab control.
                    WinEventTracker.AddToNotificationList( 
                        upDownHwnd,
                        new WinEventTracker.ProxyRaiseEvents(UpDownControlRaiseEvents), 
                        _upDownEvents, 1); 
                }
            } 

            base.AdviseEventAdded(eventId, aidProps);
        }
 
        internal override void AdviseEventRemoved(
            AutomationEvent eventId, AutomationProperty[] aidProps) 
        { 
            if (eventId == AutomationElementIdentifiers.AutomationPropertyChangedEvent
                && aidProps.Length > 0 
                && aidProps[0] == ScrollPatternIdentifiers.HorizontalScrollPercentProperty)
            {
                IntPtr upDownHwnd = GetUpDownHwnd();
                if (upDownHwnd != IntPtr.Zero) 
                {
                    WinEventTracker.RemoveToNotificationList( 
                        upDownHwnd, _upDownEvents, null, 1); 
                }
            } 
            base.AdviseEventRemoved(eventId, aidProps);
        }

        #endregion ProxyHwnd Interface 

        #region IRawElementProviderHwndOverride Interface 
 
        //-----------------------------------------------------
        // 
        //  Interface IRawElementProviderHwndOverride
        //
        //------------------------------------------------------
        IRawElementProviderSimple IRawElementProviderHwndOverride.GetOverrideProviderForHwnd (IntPtr hwnd) 
        {
            // return the appropriate placeholder for the given hwnd... 
            // loop over all the tabs to find it. 

            string sTitle = Misc.ProxyGetText(hwnd); 

            // If there is no hwnd title there is no way to match to the tab item.
            if (string.IsNullOrEmpty(sTitle))
            { 
                return null;
            } 
 
            for (int i = 0, c = GetItemCount(_hwnd); i < c; i++)
            { 
                if (sTitle == WindowsTabItem.GetName(_hwnd, i, true))
                {
                    return new WindowsTabChildOverrideProxy(hwnd, CreateTabItem(i), i);
                } 
            }
 
            return null; 
        }
 
        #endregion IRawElementProviderHwndOverride Interface

        #region Selection Pattern
 
        // Returns an enumerator over the current selection.
        IRawElementProviderSimple[] ISelectionProvider.GetSelection() 
        { 
            IRawElementProviderSimple[] selection = null;
 
            // If only one selection allowed, get selected item, if any, and add to list
            if (!WindowsTab.SupportMultipleSelection (_hwnd))
            {
                int selectedItem = WindowsTabItem.GetCurrentSelectedItem(_hwnd); 

                if (selectedItem >= 0) 
                { 
                    selection = new IRawElementProviderSimple[1];
                    selection[0] = CreateTabItem(selectedItem); 
                }
            }

            // If multiple selections allowed, check each tab for selected state 
                else
            { 
                ArrayList list = new ArrayList(); 
                for (ProxySimple child = GetFirstChild(); child != null; child = GetNextSibling(child))
                { 
                    if (((ISelectionItemProvider) child).IsSelected)
                    {
                        list.Add (child);
                    } 
                }
 
                int count = list.Count; 
                if (count <= 0)
                { 
                    return null;
                }

                selection = new IRawElementProviderSimple[count]; 
                for (int i = 0; i < count; i++)
                { 
                    selection[i] = (ProxySimple)list[i]; 
                }
            } 

            return selection;
        }
 
        // Returns whether the control supports multiple selection.
        bool ISelectionProvider.CanSelectMultiple 
        { 
            get
            { 
                return SupportMultipleSelection (_hwnd);
            }
        }
 
        // Returns whether the control requires a minimum of one selected element at all times.
        bool ISelectionProvider.IsSelectionRequired 
        { 
            get
            { 
                return !Misc.IsBitSet(WindowStyle, NativeMethods.TCS_BUTTONS);
            }
        }
 
        #endregion ISelectionProvider
 
        #region Scroll Pattern 

        void IScrollProvider.Scroll (ScrollAmount horizontalAmount, ScrollAmount verticalAmount) 
        {
            // Make sure that the control is enabled
            if (!SafeNativeMethods.IsWindowEnabled(_hwnd))
            { 
                throw new ElementNotEnabledException();
            } 
 
            if (!IsScrollable())
            { 
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
            }

            if (verticalAmount != ScrollAmount.NoAmount) 
            {
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); 
            } 

            if (!Scroll(horizontalAmount)) 
            {
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
            }
        } 

        void IScrollProvider.SetScrollPercent (double horizontalPercent, double verticalPercent) 
        { 
            // Make sure that the control is enabled
            if (!SafeNativeMethods.IsWindowEnabled(_hwnd)) 
            {
                throw new ElementNotEnabledException();
            }
 
            if (!IsScrollable())
            { 
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); 
            }
 
            if ((int)verticalPercent != (int)ScrollPattern.NoScroll)
            {
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
            } 
            else if ((int)horizontalPercent == (int)ScrollPattern.NoScroll)
            { 
                return; 
            }
            else if (horizontalPercent < 0 || horizontalPercent > 100) 
            {
                throw new ArgumentOutOfRangeException("horizontalPercent", SR.Get(SRID.ScrollBarOutOfRange));
            }
 
            // Get up/down control's hwnd
            IntPtr updownHwnd = this.GetUpDownHwnd (); 
 
            if (updownHwnd == IntPtr.Zero)
            { 
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
            }

            // Get available range 
            int range = Misc.ProxySendMessageInt(updownHwnd, NativeMethods.UDM_GETRANGE, IntPtr.Zero, IntPtr.Zero);
            int minPos = NativeMethods.Util.HIWORD(range); 
            int maxPos = NativeMethods.Util.LOWORD(range); 

            // Calculate new position 
            int newPos = (int) Math.Round ((maxPos - minPos) * horizontalPercent / 100) + minPos;

            // Set position
            Misc.ProxySendMessage(updownHwnd, NativeMethods.UDM_SETPOS, IntPtr.Zero, (IntPtr)newPos); 
            Misc.ProxySendMessage(_hwnd, NativeMethods.WM_HSCROLL, (IntPtr)NativeMethods.Util.MAKELPARAM(NativeMethods.SB_THUMBPOSITION, newPos), IntPtr.Zero);
        } 
 

        // Calc the position of the horizontal scroll bar thumb in the 0..100 % range 
        double IScrollProvider.HorizontalScrollPercent
        {
            get
            { 
                double minPos, maxPos, currentPos;
 
                // Get up/down control's hwnd 
                IntPtr updownHwnd = this.GetUpDownHwnd ();
 
                if (updownHwnd == IntPtr.Zero)
                {
                    return (double)ScrollPattern.NoScroll;
                } 

                // Get range of position values 
                int range = Misc.ProxySendMessageInt(updownHwnd, NativeMethods.UDM_GETRANGE, IntPtr.Zero, IntPtr.Zero); 

                // Get current position 
                int posResult = Misc.ProxySendMessageInt(updownHwnd, NativeMethods.UDM_GETPOS, IntPtr.Zero, IntPtr.Zero);

                // Calculate percentage position
                minPos = NativeMethods.Util.HIWORD(range); 
                maxPos = NativeMethods.Util.LOWORD(range);
                currentPos = NativeMethods.Util.LOWORD(posResult); 
                return (currentPos - minPos) / (maxPos - minPos) * 100; 
            }
        } 

        // Calc the position of the Vertical scroll bar thumb in the 0..100 % range
        double IScrollProvider.VerticalScrollPercent
        { 
            get
            { 
                // Tab controls can never be vertically scrolling 
                // since vertical tab controls must have the multiline style
                return (double)ScrollPattern.NoScroll; 
            }
        }

        // Percentage of the window that is visible along the horizontal axis. 
        // Value 0..100
        double IScrollProvider.HorizontalViewSize 
        { 
            get
            { 
                ProxySimple firstChild = GetFirstChild ();
                ProxySimple lastChild = GetLastChild ();

                // Get rectangles 
                Rect firstRect = firstChild.BoundingRectangle;
                Rect lastRect = lastChild.BoundingRectangle; 
                NativeMethods.Win32Rect viewable = new NativeMethods.Win32Rect (); 

                viewable.left = 0; 
                if (!Misc.GetWindowRect(_hwnd, ref viewable))
                {
                    return 100.0;
                } 

                // Calculate ranges 
                double totalRange = (double)lastRect.Right - (double)firstRect.Left; 
                double viewableRange = viewable.right - viewable.left;
 
                // Get the rectangle of the up/down control and adjust viewable range
                IntPtr updownHwnd = this.GetUpDownHwnd ();

                if (updownHwnd == IntPtr.Zero) 
                {
                    return 100.0; 
                } 

                NativeMethods.Win32Rect rectW32 = new NativeMethods.Win32Rect (); 

                if (!Misc.GetWindowRect(updownHwnd, ref rectW32))
                {
                    return 100.0; 
                }
 
                viewableRange -= rectW32.right - rectW32.left; 
                return viewableRange / totalRange * 100;
            } 
        }

        // Percentage of the window that is visible along the vertical axis.
        // Value 0..100 
        double IScrollProvider.VerticalViewSize
        { 
            get 
            {
                return 100.0; 
            }
        }

        // Can the element be horizontaly scrolled 
        bool IScrollProvider.HorizontallyScrollable
        { 
            get 
            {
                return IsScrollable(); 
            }
        }

        // Can the element be verticaly scrolled 
        bool IScrollProvider.VerticallyScrollable
        { 
            get 
            {
                return false; 
            }
        }

        #endregion IScrollProvider 

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

        #region Internal Methods
 
        internal static int GetItemCount(IntPtr hwnd)
        { 
            // The Display Property Dialog is doing something strange with the their tab control.  The 
            // last tab is invisable. So if that is the case remove it from the count, since UIAutomation
            // can not do anything with it. 
            int count = Misc.ProxySendMessageInt(hwnd, NativeMethods.TCM_GETITEMCOUNT, IntPtr.Zero, IntPtr.Zero);

            if (count > 0)
            { 
                NativeMethods.Win32Rect rectW32 = NativeMethods.Win32Rect.Empty;
                bool result; 
                unsafe 
                {
                    result = XSendMessage.XSend(hwnd, NativeMethods.TCM_GETITEMRECT, new IntPtr(count - 1), new IntPtr(&rectW32), Marshal.SizeOf(rectW32.GetType()), XSendMessage.ErrorValue.Zero); 
                }
                if (!result)
                {
                    count--; 
                }
                if (rectW32.IsEmpty) 
                { 
                    count--;
                } 
            }

            return count;
        } 

        // Create a WindowsTab instance 
        internal ProxyFragment CreateTabItem(int index) 
        {
            return new WindowsTabItem(_hwnd, this, index, _windowsForms == WindowsFormsHelper.FormControlState.True); 
        }

        internal void ScrollToItem(int index)
        { 
            if (!IsScrollable())
            { 
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); 
            }
 
            // Get up/down control's hwnd
            IntPtr updownHwnd = this.GetUpDownHwnd();

            if (updownHwnd == IntPtr.Zero) 
                return;
 
            int range = Misc.ProxySendMessageInt(updownHwnd, NativeMethods.UDM_GETRANGE, IntPtr.Zero, IntPtr.Zero); 
            int max = NativeMethods.Util.LOWORD(range);
            int newPos = index < max ? index : max; 

            Misc.ProxySendMessage(updownHwnd, NativeMethods.UDM_SETPOS, IntPtr.Zero, (IntPtr)newPos);
            Misc.ProxySendMessage(_hwnd, NativeMethods.WM_HSCROLL, NativeMethods.Util.MAKELPARAM(NativeMethods.SB_THUMBPOSITION, newPos), IntPtr.Zero);
        } 

        internal bool IsScrollable() 
        { 
            return GetUpDownHwnd(_hwnd) != IntPtr.Zero;
        } 

        // if all the tab items have no name then the control is not useful
        internal static bool IsValidControl(IntPtr hwnd)
        { 
            for (int i = 0, c = GetItemCount(hwnd); i < c; i++)
            { 
                if (!string.IsNullOrEmpty(WindowsTabItem.GetName(hwnd, i, true))) 
                {
                    return true; 
                }
            }

            return false; 
        }
 
        // Process events for the associated UpDown control, and relay 
        // them to the WindowsTab control instead.
        internal static void UpDownControlRaiseEvents( 
            IntPtr hwnd, int eventId, object idProp, int idObject, int idChild)
        {
            if (eventId == NativeMethods.EventObjectValueChange
                && idProp == ScrollPattern.HorizontalScrollPercentProperty) 
            {
                IntPtr hwndParent = UnsafeNativeMethods.GetAncestor(hwnd, NativeMethods.GA_PARENT); 
                if (hwndParent != IntPtr.Zero 
                   && Misc.ProxyGetClassName(hwndParent).Contains("SysTabControl32"))
                { 
                    WindowsTab el = new WindowsTab(hwndParent, null, 0);
                    el.DispatchEvents(eventId, idProp, 0, 0);
                }
            } 
        }
 
        #endregion Internal Methods 

        // ------------------------------------------------------ 
        //
        // Private Methods
        //
        // ----------------------------------------------------- 

        #region Private Methods 
 
        // Gets the windows handle of the UpDown control in the tab control
        // Returns the handle to the UpDown control or IntPtr.Zero if this tab control isn't scrollable. 
        private IntPtr GetUpDownHwnd()
        {
            return GetUpDownHwnd(_hwnd);
        } 
        private static IntPtr GetUpDownHwnd(IntPtr hwnd)
        { 
            IntPtr childHwnd = Misc.GetWindow(hwnd, NativeMethods.GW_CHILD); 
            string className;
            int i; 

            // UpDown control is either the first or last child, so do this check twice
            for (i = 0; i < 2; i++)
            { 
                if (childHwnd != IntPtr.Zero)
                { 
                    className = Misc.ProxyGetClassName(childHwnd); 
                    if (className.IndexOf("updown", StringComparison.Ordinal) > -1)
                    { 
                        // found it
                        return childHwnd;
                    }
 
                    childHwnd = Misc.GetWindow(childHwnd, NativeMethods.GW_HWNDLAST);
                } 
                else 
                {
                    // didn't find it 
                    break;
                }
            }
 
            return IntPtr.Zero;
        } 
 
        private bool IsVerticalTab()
        { 
            int style = WindowStyle;
            return Misc.IsBitSet(style, NativeMethods.TCS_MULTILINE) &&
                    (Misc.IsBitSet(style, NativeMethods.TCS_RIGHT) ||
                     Misc.IsBitSet(style, NativeMethods.TCS_VERTICAL)); 
        }
 
        #endregion Private Methods 

        #region Scroll Helper 

        private bool Scroll(ScrollAmount amount)
        {
            // Done 
            if (amount == ScrollAmount.NoAmount)
            { 
                return true; 
            }
 
            // Get up/down control's hwnd
            IntPtr updownHwnd = this.GetUpDownHwnd ();

            if (updownHwnd == IntPtr.Zero) 
            {
                return false; 
            } 

            // 

            int newPos = Misc.ProxySendMessageInt(updownHwnd, NativeMethods.UDM_GETPOS, IntPtr.Zero, IntPtr.Zero);
            int range = Misc.ProxySendMessageInt(updownHwnd, NativeMethods.UDM_GETRANGE, IntPtr.Zero, IntPtr.Zero);
            int max = NativeMethods.Util.LOWORD(range); 
            int min = NativeMethods.Util.HIWORD(range);
 
            if (NativeMethods.Util.HIWORD (newPos) == 0) 
            {
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); 
            }

            newPos = NativeMethods.Util.LOWORD (newPos);
            switch (amount) 
            {
                case ScrollAmount.LargeDecrement : 
                case ScrollAmount.LargeIncrement : 
                    // Not supported.
                    return false; 

                case ScrollAmount.SmallDecrement :
                    newPos--;
                    break; 

                case ScrollAmount.SmallIncrement : 
                    newPos++; 
                    break;
 
                default :  // should never get here
                    return false;
            }
 
            if (newPos < min || newPos > max)
            { 
                // Attempt to scroll before beginning or past end. 
                // As long as this is a supported operation (namely,
                // SmallIncrement or SmallDecrement), do nothing but 
                // return success.
                return true;
            }
 
            // Update both the spiner and the tabs
            Misc.ProxySendMessage(updownHwnd, NativeMethods.UDM_SETPOS, IntPtr.Zero, (IntPtr)newPos); 
            Misc.ProxySendMessage(_hwnd, NativeMethods.WM_HSCROLL, NativeMethods.Util.MAKELPARAM(NativeMethods.SB_THUMBPOSITION, newPos), IntPtr.Zero); 

            return true; 
        }

        #endregion
 
        #region Selection Helper
 
        // detect if tab-control supports multiple selection 
        static internal bool SupportMultipleSelection (IntPtr hwnd)
        { 
            return Misc.IsBitSet(Misc.GetWindowStyle(hwnd), (NativeMethods.TCS_BUTTONS | NativeMethods.TCS_MULTISELECT));
        }

        #endregion 

        // ----------------------------------------------------- 
        // 
        // Private Fields
        // 
        // -----------------------------------------------------

        #region Private Fields
 
        private const int SpinControl = -2;
 
        // Updown specific events. 
        private readonly static WinEventTracker.EvtIdProperty[] _upDownEvents;
 
        #endregion
    }

    // ------------------------------------------------------ 
    //
    // WindowsTabItem Private Class 
    // 
    // -----------------------------------------------------
 
    #region WindowsTabItem

    class WindowsTabItem : ProxyFragment, ISelectionItemProvider, IScrollItemProvider
    { 
        // ------------------------------------------------------
        // 
        // Constructors 
        //
        // ------------------------------------------------------ 

        #region Constructors

        internal WindowsTabItem(IntPtr hwnd, ProxyFragment parent, int item, bool fIsWinform) 
            : base( hwnd, parent, item )
        { 
            // Set the strings to return properly the properties. 
            _cControlType = ControlType.TabItem;
            _fIsKeyboardFocusable = true; 

            _fIsWinform = fIsWinform;
            _fIsContent = !string.IsNullOrEmpty(GetName(_hwnd, _item, true));
        } 

        #endregion 
 
        // -----------------------------------------------------
        // 
        //  Patterns Implementation
        //
        // ------------------------------------------------------
 
        #region ProxySimple Interface
 
        // Returns a pattern interface if supported. 
        internal override object GetPatternProvider(AutomationPattern iid)
        { 
            if(iid == SelectionItemPattern.Pattern)
            {
                return this;
            } 
            else if (iid == ScrollItemPattern.Pattern)
            { 
                return this; 
            }
 
            return null;
        }

        // Gets the bounding rectangle for this element 
        internal override Rect BoundingRectangle
        { 
            get 
            {
                return BoundingRect().ToRect(Misc.IsControlRTL(_hwnd)); 
            }
        }

        // Process all the Logical and Raw Element Properties 
        internal override object GetElementProperty(AutomationProperty idProp)
        { 
            if (idProp == AutomationElement.AccessKeyProperty && _windowsForms != WindowsFormsHelper.FormControlState.True) 
            {
                return Misc.AccessKey(WindowsTabItem.GetItemText(_hwnd, _item)); 
            }
            else if (idProp == AutomationElement.IsControlElementProperty)
            {
                return !string.IsNullOrEmpty(GetName(_hwnd, _item, true)); 
            }
 
            return base.GetElementProperty(idProp); 
        }
 
        //Gets the controls help text
        internal override string HelpText
        {
            get 
            {
                IntPtr hwndToolTip = Misc.ProxySendMessage(_hwnd, NativeMethods.TCM_GETTOOLTIPS, IntPtr.Zero, IntPtr.Zero); 
                return Misc.GetItemToolTipText(_hwnd, hwndToolTip, _item); 
            }
        } 

        //Gets the localized name
        internal override string LocalizedName
        { 
            get
            { 
                // If this is a winforms tab page and the AccessibleName is set, use it. 
                if (WindowsFormsHelper.IsWindowsFormsControl(_hwnd, ref _windowsForms))
                { 
                    string name = GetAccessibleName(_item + 1);
                    if (!string.IsNullOrEmpty(name))
                    {
                        return name; 
                    }
                } 
 
                return GetName(_hwnd, _item, _windowsForms == WindowsFormsHelper.FormControlState.True);
            } 
        }

        // Sets the focus to this item.
        internal override bool SetFocus() 
        {
            if (Misc.IsBitSet(WindowStyle, NativeMethods.TCS_FOCUSNEVER)) 
            { 
                return false;
            } 

            WindowsTab tab = (WindowsTab)_parent;
            ProxySimple focused = tab.GetFocus();
 
            if (focused == null || _item != focused._item)
            { 
                Misc.ProxySendMessage(_hwnd, NativeMethods.TCM_SETCURFOCUS, new IntPtr(_item), IntPtr.Zero); 
            }
 
            return true;
        }

        #endregion ProxySimple Interface 

        #region ProxyFragment Interface 
 
        // Returns the next sibling element in the raw hierarchy.
        // Peripheral controls have always negative values. 
        // Param name="child", the current child
        // Returns null if no next child
        internal override ProxySimple GetNextSibling(ProxySimple child)
        { 
            return null;
        } 
 
        // Returns the previous sibling element in the raw hierarchy.
        // Peripheral controls have always negative values. 
        // Param name="child", the current child
        // Returns null is no previous
        internal override ProxySimple GetPreviousSibling(ProxySimple child)
        { 
            return null;
        } 
 
        // Returns the first child element in the raw hierarchy.
        internal override ProxySimple GetFirstChild() 
        {
            IntPtr hwndChild = GetItemHwndByIndex();
            if (hwndChild != IntPtr.Zero && SafeNativeMethods.IsWindowVisible(hwndChild))
            { 
                return new WindowsTabChildOverrideProxy(hwndChild, this, _item);
            } 
 
            return null;
        } 

        // Returns the last child element in the raw hierarchy.
        internal override ProxySimple GetLastChild()
        { 
            // One children at most for form or nothing for Win32 controls.
            return GetFirstChild(); 
        } 

        #endregion ProxyFragment Interface 

        #region Selection Pattern

        // Selects this element 
        void ISelectionItemProvider.Select()
        { 
            // Make sure that the control is enabled 
            if (!SafeNativeMethods.IsWindowEnabled(_hwnd))
            { 
                throw new ElementNotEnabledException();
            }

            if (!IsSelectable()) 
            {
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); 
            } 

            if (((ISelectionItemProvider)this).IsSelected == false) 
            {
                Select();
            }
        } 

        // Adds this element to the selection 
        void ISelectionItemProvider.AddToSelection() 
        {
            // Make sure that the control is enabled 
            if (!SafeNativeMethods.IsWindowEnabled(_hwnd))
            {
                throw new ElementNotEnabledException();
            } 

            // If not selectable, can't add to selection 
            if (!IsSelectable()) 
            {
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); 
            }

            // If already selected, done
            if (((ISelectionItemProvider)this).IsSelected) 
            {
                return; 
            } 

            // If multiple selections allowed, add requested selection 
            if (WindowsTab.SupportMultipleSelection(_hwnd) == true)
            {
                // Press ctrl and mouse click tab
                NativeMethods.Win32Point pt = new NativeMethods.Win32Point(); 
                if (GetClickablePoint(out pt, true))
                { 
                    Input.SendKeyboardInput(Key.LeftCtrl, true); 
                    Misc.MouseClick(pt.x, pt.y);
                    Input.SendKeyboardInput(Key.LeftCtrl, false); 
                    return;
                }

                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); 
            }
            // else only single selection allowed 
            else 
            {
                throw new InvalidOperationException(SR.Get(SRID.DoesNotSupportMultipleSelection)); 
            }
        }

        // Removes this element from the selection 
        void ISelectionItemProvider.RemoveFromSelection()
        { 
            // Make sure that the control is enabled 
            if (!SafeNativeMethods.IsWindowEnabled(_hwnd))
            { 
                throw new ElementNotEnabledException();
            }

            // If not selected, done 
            if (!((ISelectionItemProvider)this).IsSelected)
            { 
                return; 
            }
 
            // If multiple selections allowed, unselect element
            if (WindowsTab.SupportMultipleSelection(_hwnd) == true)
            {
                NativeMethods.Win32Point pt = new NativeMethods.Win32Point(); 
                if (GetClickablePoint(out pt, true))
                { 
                    Input.SendKeyboardInput(Key.LeftCtrl, true); 
                    Misc.MouseClick(pt.x, pt.y);
                    Input.SendKeyboardInput(Key.LeftCtrl, false); 
                    return;
                }

                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); 
            }
            // else if button style and single select, send deselectall message 
            else if (Misc.IsBitSet(WindowStyle, NativeMethods.TCS_BUTTONS)) 
            {
                Misc.ProxySendMessage(_hwnd, NativeMethods.TCM_DESELECTALL, IntPtr.Zero, IntPtr.Zero); 
                return;
            }

            throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); 
        }
 
        // True if this element is part of the the selection 
        bool ISelectionItemProvider.IsSelected
        { 
            get
            {
                // If only a single selection is allowed, check which one is selected and compare
                if (!WindowsTab.SupportMultipleSelection(_hwnd)) 
                {
                    int selectedItem = GetCurrentSelectedItem(_hwnd); 
 
                    return (_item == selectedItem);
                } 

                // If multiple selections possible, get state information on the tab
                else
                { 
                    NativeMethods.TCITEM TCItem = new NativeMethods.TCITEM();
                    TCItem.Init(NativeMethods.TCIF_STATE); 
 
                    if (!XSendMessage.GetItem(_hwnd, _item, ref TCItem))
                    { 
                        System.Diagnostics.Debug.Assert(false, "XSendMessage.GetItem() failed!");
                        return false;
                    }
 
                    return Misc.IsBitSet(TCItem.dwState, NativeMethods.TCIS_BUTTONPRESSED);
                } 
            } 
        }
 
        // Returns the container for this element
        IRawElementProviderSimple ISelectionItemProvider.SelectionContainer
        {
            get 
            {
                System.Diagnostics.Debug.Assert(_parent is WindowsTab, "Invalid Parent for a Tab Item"); 
                return _parent; 
            }
        } 

        #endregion SelectionItem Pattern

        #region ScrollItem Pattern 

        void IScrollItemProvider.ScrollIntoView() 
        { 
            // Make sure that the control is enabled
            if (!SafeNativeMethods.IsWindowEnabled(_hwnd)) 
            {
                throw new ElementNotEnabledException();
            }
 
            WindowsTab parent = (WindowsTab)_parent;
 
            if (!parent.IsScrollable()) 
            {
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); 
            }

            parent.ScrollToItem(_item);
        } 

        #endregion ScrollItem Pattern 
 
        // -----------------------------------------------------
        // 
        // Internal Methods
        //
        // -----------------------------------------------------
 
        #region Internal Methods
 
        // Retrieve the text in a tab item 
        internal static string GetName(IntPtr hwnd, int item, bool fIsWinform)
        { 
            string sName = GetItemText(hwnd, item);

            // Win32 controls '&' is used as an accelerator. This is not the case for winforms !!!
            return !fIsWinform ? Misc.StripMnemonic(sName) : sName; 
        }
 
        internal static int GetCurrentSelectedItem(IntPtr hwnd) 
        {
            return Misc.ProxySendMessageInt(hwnd, NativeMethods.TCM_GETCURSEL, IntPtr.Zero, IntPtr.Zero); 
        }

        #endregion Internal Methods
 
        //-----------------------------------------------------
        // 
        //  Protected Methods 
        //
        //------------------------------------------------------ 

        #region Protected Methods

        // This routine is only called on elements belonging to an hwnd that has the focus. 
        protected override bool IsFocused()
        { 
            return Misc.ProxySendMessageInt(_hwnd, NativeMethods.TCM_GETCURFOCUS, IntPtr.Zero, IntPtr.Zero) == _item; 
        }
 
        #endregion Protected Methods

        // -----------------------------------------------------
        // 
        // Private Methods
        // 
        // ------------------------------------------------------ 

        #region Private Methods 

        private unsafe NativeMethods.Win32Rect BoundingRect()
        {
            NativeMethods.Win32Rect rectW32 = new NativeMethods.Win32Rect(); 

            if (!XSendMessage.XSend(_hwnd, NativeMethods.TCM_GETITEMRECT, new IntPtr(_item), new IntPtr(&rectW32), Marshal.SizeOf(rectW32.GetType()), XSendMessage.ErrorValue.Zero)) 
            { 
                return NativeMethods.Win32Rect.Empty;
            } 

            return Misc.MapWindowPoints(_hwnd, IntPtr.Zero, ref rectW32, 2) ? rectW32 : NativeMethods.Win32Rect.Empty;
        }
 
        private bool IsSelectable()
        { 
            return (SafeNativeMethods.IsWindowEnabled(_hwnd) && SafeNativeMethods.IsWindowVisible(_hwnd)); 
        }
 
        // Press a tab
        private void Select()
        {
            if (Misc.IsBitSet(WindowStyle, (NativeMethods.TCS_BUTTONS | NativeMethods.TCS_FOCUSNEVER))) 
            {
                // The TCM_SETCURFOCUS message cannot be used with TCS_FOCUSNEVER 
                // use a convulated way faking a mouse action 

                NativeMethods.Win32Point pt = new NativeMethods.Win32Point(); 
                if (GetClickablePoint(out pt, true))
                {
                    // Convert screen coordinates to client coordinates.
                    if (Misc.MapWindowPoints(IntPtr.Zero, _hwnd, ref pt, 1)) 
                    {
                        Misc.PostMessage(_hwnd, NativeMethods.WM_LBUTTONDOWN, (IntPtr)NativeMethods.MK_LBUTTON, NativeMethods.Util.MAKELPARAM(pt.x, pt.y)); 
                        Misc.PostMessage(_hwnd, NativeMethods.WM_LBUTTONUP, (IntPtr)NativeMethods.MK_LBUTTON, NativeMethods.Util.MAKELPARAM(pt.x, pt.y)); 
                    }
                } 
            }
            else
            {
                Misc.ProxySendMessage(_hwnd, NativeMethods.TCM_SETCURFOCUS, new IntPtr(_item), IntPtr.Zero); 
            }
 
        } 

        // Gets the windows handle of an individual tab in a Windows Forms control 
        private IntPtr GetItemHwndByIndex()
        {
            // On Win32 Tab controls the table page is parented by the dialog box not the
            // Tab control. 
            IntPtr hwndParent = _hwnd;
            if (!_fIsWinform) 
            { 
                hwndParent = Misc.GetParent(hwndParent);
            } 

            if (hwndParent != IntPtr.Zero)
            {
                // Get the tab name and match it with the window title of one of the children 
                string sName = WindowsTabItem.GetName(_hwnd, _item, true);
 
                // If there is no tab name there is no way to match to one of the childrens window title. 
                if (!string.IsNullOrEmpty(sName))
                { 
                    return Misc.FindWindowEx(hwndParent, IntPtr.Zero, null, sName);
                }
            }
 
            return IntPtr.Zero;
        } 
 

        private static string GetItemText(IntPtr hwnd, int itemIndex) 
        {
            NativeMethods.TCITEM tcitem = new NativeMethods.TCITEM();
            tcitem.Init();
 
            tcitem.mask = NativeMethods.TCIF_TEXT;
            tcitem.cchTextMax = Misc.MaxLengthNameProperty; 
 
            return XSendMessage.GetItemText(hwnd, itemIndex, tcitem);
        } 

        #endregion Private Methods

        // ------------------------------------------------------ 
        //
        // Private Fields 
        // 
        // -----------------------------------------------------
 
        #region Private Fields

        // Cached value for a winform
        bool _fIsWinform; 

        #endregion Private Fields 
    } 

    #endregion 

    // ------------------------------------------------------
    //
    //  WindowsTabChildOverrideProxy Class 
    //
    //----------------------------------------------------- 
 
    #region WindowsTabChildOverrideProxy
 
    class WindowsTabChildOverrideProxy : ProxyHwnd
    {
        // -----------------------------------------------------
        // 
        // Constructors
        // 
        // ----------------------------------------------------- 

        #region Constructors 

        // Constructor
        // Usually the hwnd passed to the constructor is wrong. As the base class is doing
        // nothing this does not matter. 
        // This avoid to making some extra calls to get this right.
        internal WindowsTabChildOverrideProxy(IntPtr hwnd, ProxyFragment parent, int item) 
            : base (hwnd, parent, item) 
        {
        } 

            #endregion

        //------------------------------------------------------ 
        //
        //  Patterns Implementation 
        // 
        //-----------------------------------------------------
 
        #region ProxySimple Interface

        internal override ProviderOptions ProviderOptions
        { 
            get
            { 
                return base.ProviderOptions | ProviderOptions.OverrideProvider; 
            }
        } 

        // Process all the Logical and Raw Element Properties
        internal override object GetElementProperty(AutomationProperty idProp)
        { 
            if (idProp == AutomationElement.IsControlElementProperty)
            { 
                return false; 
            }
            // Overrides the ProxySimple implementation to remove and default 
            // property handling
            // This proxy is about tree rearranging, it does not do any
            // property overrride.
            return null; 
        }
 
        #endregion 
    }
 
    #endregion
}

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