WindowsTreeView.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 / WindowsTreeView.cs / 1 / WindowsTreeView.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: Win32 TreeView proxy 
//
// History: 
//        Jean-Francois Peyroux, alexsn - Created (in DotNet)
//
//---------------------------------------------------------------------------
 
using System;
using System.Text; 
using System.Collections; 
using System.Windows.Automation;
using System.Windows.Automation.Provider; 
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Windows;
using MS.Win32; 

namespace MS.Internal.AutomationProxies 
{ 
    class WindowsTreeView : ProxyHwnd, ISelectionProvider
    { 

        // -----------------------------------------------------
        //
        // Constructors 
        //
        // ----------------------------------------------------- 
 
        #region Constructors
 
        internal WindowsTreeView (IntPtr hwnd, ProxyFragment parent, int item)
            : base(hwnd, parent, item)
        {
            // Set the strings to return properly the properties. 
            _cControlType = ControlType.Tree;
 
            // Can be focused 
            _fIsKeyboardFocusable = true;
 
            // support for events
            _createOnEvent = new WinEventTracker.ProxyRaiseEvents (RaiseEvents);
        }
 
        #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) 
        {
            WindowsTreeView wtv = new WindowsTreeView(hwnd, null, 0); 
            return idChild == 0 ? wtv : wtv.CreateParents(hwnd, TreeItemFromChildID(hwnd, idChild));
        }

        // 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 : 
                    {
                        WindowsTreeView wtv = new WindowsTreeView (hwnd, null, -1); 
 
                        // Selection or Expand/Collapse
                        if (idChild != 0 && (eventId == NativeMethods.EventObjectSelection || 
                                             eventId == NativeMethods.EventObjectSelectionRemove ||
                                             eventId == NativeMethods.EventObjectSelectionAdd ||
                                             eventId == NativeMethods.EventObjectStateChange ||
                                             eventId == NativeMethods.EventObjectDestroy || 
                                             eventId == NativeMethods.EventObjectCreate ||
                                             eventId == NativeMethods.EventObjectNameChange)) 
                        { 
                            el = wtv.CreateParents(hwnd, TreeItemFromChildID(hwnd, idChild));
                        } 
                        else
                        {
                            el = wtv;
                        } 

                        break; 
                    } 

                case NativeMethods.OBJID_VSCROLL : 
                case NativeMethods.OBJID_HSCROLL :
                    break;

                default : 
                    el = new WindowsTreeView (hwnd, null, -1);
                    break; 
            } 

            // Expand/Collapse is too peculiar per control to be processed in the dispatch code 
            if (idProp == ExpandCollapsePattern.ExpandCollapseStateProperty && el is TreeViewItem && eventId == NativeMethods.EventObjectStateChange)
            {
                ((TreeViewItem) el).RaiseExpandCollapsedStateChangedEvent ();
                return; 
            }
 
            // Special case for logical element change for a tree view item on Expand/Collapse 
            if (((idProp as AutomationEvent) == AutomationElement.StructureChangedEvent && el is TreeViewItem) && !(eventId == NativeMethods.EventObjectDestroy || eventId == NativeMethods.EventObjectCreate))
            { 
                ((TreeViewItem) el).RaiseStructureChangedEvent ();
                return;
            }
 
            if (el != null)
            { 
                el.DispatchEvents (eventId, idProp, idObject, idChild); 
            }
        } 

        #endregion Proxy Create

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

        // ------------------------------------------------------
        // 
        // RawElementProvider interface implementation
        // 
        // ------------------------------------------------------ 

        // Returns a pattern interface if supported. 
        internal override object GetPatternProvider (AutomationPattern iid)
        {
            // This is the treeview container
            if (iid == SelectionPattern.Pattern) 
            {
                return this; 
            } 

            return null; 
        }

        #endregion ProxySimple Interface
 
        #region ProxyFragment Interface
 
        // Returns the next sibling element in the raw hierarchy. 
        // Peripheral controls have always negative values.
        // Returns null if no next child 
        internal override ProxySimple GetNextSibling (ProxySimple child)
        {
            TVItem item = (TVItem)child._item;
 
            // root child
            if (item == TVItem.TopLevel) 
            { 
                IntPtr hNext = GetNextItem (_hwnd, ((TreeViewItem) child)._hItem);
 
                if (hNext != IntPtr.Zero)
                    return new TreeViewItem (_hwnd, this, hNext, (int) TVItem.TopLevel);
            }
 
            return base.GetNextSibling (child);
        } 
 
        // Returns the previous sibling element in the raw hierarchy.
        // Peripheral controls have always negative values. 
        // Returns null is no previous
        internal override ProxySimple GetPreviousSibling (ProxySimple child)
        {
            // start with the scrollbars 
            ProxySimple ret = base.GetPreviousSibling (child);
 
            if (ret != null) 
            {
                return ret; 
            }

            // top level Treeview return the prev
            TVItem item = (TVItem)child._item; 

            if (item == TVItem.TopLevel) 
            { 
                IntPtr hPrev = GetPreviousItem (_hwnd, ((TreeViewItem) child)._hItem);
 
                return hPrev != IntPtr.Zero ? new TreeViewItem (_hwnd, this, hPrev, (int) TVItem.TopLevel) : null;
            }

            // either scroll bar or nothing as prev 
            IntPtr hChild = GetRoot (_hwnd);
 
            if (hChild != IntPtr.Zero) 
            {
                // First Child found, now retrieve the last one (no specific msg, need to walk thru all of them) 
                IntPtr temp;

                for (temp = GetNextItem (_hwnd, hChild); temp != IntPtr.Zero; temp = GetNextItem (_hwnd, hChild))
                { 
                    hChild = temp;
                } 
 
                return new TreeViewItem (_hwnd, this, hChild, (int) TVItem.TopLevel);
            } 

            return null;
        }
 
        // Returns the first child element in the raw hierarchy.
        internal override ProxySimple GetFirstChild () 
        { 
            IntPtr hChild = IntPtr.Zero;
 
            hChild = GetRoot (_hwnd);
            if (hChild != IntPtr.Zero)
            {
                return CreateTreeViewItem (hChild, (int) TVItem.TopLevel); 
            }
 
            return base.GetFirstChild (); 
        }
 
        // Returns the last child element in the raw hierarchy.
        internal override ProxySimple GetLastChild ()
        {
            // start with the scrollbars 
            ProxySimple ret = base.GetFirstChild ();
 
            if (ret != null) 
            {
                return ret; 
            }

            // get the root (or the very first item in the tree)
            IntPtr hChild = GetRoot (_hwnd); 

            if (hChild != IntPtr.Zero) 
            { 
                // First Child found, now retrieve the last one (no specific msg, need to walk thru all of them)
                for (IntPtr temp = GetNextItem (_hwnd, hChild); temp != IntPtr.Zero; temp = GetNextItem (_hwnd, hChild)) 
                {
                    hChild = temp;
                }
 
                return CreateTreeViewItem (hChild, (int) TVItem.TopLevel);
            } 
 
            return null;
        } 

        // Returns a Proxy element corresponding to the specified screen coordinates.
        internal override ProxySimple ElementProviderFromPoint (int x, int y)
        { 
            IntPtr hItem = XSendMessage.HitTestTreeView(_hwnd, x, y);
            if (hItem != IntPtr.Zero) 
            { 
                return CreateTreeViewItemAndParents(hItem);
            } 
            return base.ElementProviderFromPoint (x, y);
        }

        // Returns an item corresponding to the focused element (if there is one), or null otherwise. 
        internal override ProxySimple GetFocus ()
        { 
            IntPtr treeItem = GetSelection (_hwnd); 

            if (treeItem != IntPtr.Zero) 
            {
                return CreateTreeViewItemAndParents (treeItem);
            }
 
            return this;
        } 
 
        #endregion Interface ContextProvider
 
        #region Selection Pattern

        // Returns an enumerator over the current selection.
        IRawElementProviderSimple[] ISelectionProvider.GetSelection() 
        {
            IntPtr treeItem = GetSelection(_hwnd); 
 
            if (treeItem == IntPtr.Zero)
            { 
                // framework will handle this one correctly
                return null;
            }
 
            // no native support for multi-selection
            IRawElementProviderSimple[] selection = new IRawElementProviderSimple[1]; 
            selection [0] = CreateTreeViewItemAndParents(treeItem); 

            return selection; 
        }

        // Returns whether the control requires a minimum of one selected element at all times.
        bool ISelectionProvider.IsSelectionRequired 
        {
            // NOTE: this property is dynamic 
            // In the case when TV does not have a selected tvitem we will return false 
            // if there is a tvitem with the selection we will return true
            get 
            {
                return (IntPtr.Zero != GetSelection (_hwnd));
            }
        } 

        // Returns whether the control supports multiple selection. 
        bool ISelectionProvider.CanSelectMultiple 
        {
            get 
            {
                // Windows tree view does not provide native support
                // for multiple selection
                return false; 
            }
        } 
 
        #endregion Selection Pattern
 
        // -----------------------------------------------------
        //
        // Protected Methods
        // 
        // ------------------------------------------------------
 
        #region Protected Methods 

        // Picks a WinEvent to track for a UIA property 
        // Returns the WinEvent ID or 0 if no WinEvents matches a the UIA property
        protected override int [] PropertyToWinEvent (AutomationProperty idProp)
        {
            if (idProp == ValuePattern.ValueProperty) 
            {
                return new int[] { NativeMethods.EventObjectNameChange, 
                                   NativeMethods.EventObjectStateChange }; 
            }
            else if (idProp == ExpandCollapsePattern.ExpandCollapseStateProperty) 
            {
                return new int[] { NativeMethods.EventObjectStateChange };
            }
            return base.PropertyToWinEvent (idProp); 
        }
 
        // Builds a list of Win32 WinEvents to process a UIAutomation Event. 
        // Returns an array of Events to Set. The number of valid entries in this array pass back in cEvent.
        protected override WinEventTracker.EvtIdProperty [] EventToWinEvent (AutomationEvent idEvent, out int cEvent) 
        {
            if (idEvent == AutomationElement.StructureChangedEvent)
            {
                cEvent = 3; 
                return new WinEventTracker.EvtIdProperty [3] {
                    new WinEventTracker.EvtIdProperty (NativeMethods.EventObjectStateChange, idEvent), 
                    new WinEventTracker.EvtIdProperty (NativeMethods.EventObjectCreate, idEvent), 
                    new WinEventTracker.EvtIdProperty (NativeMethods.EventObjectDestroy, idEvent)
                }; 
            }

            return base.EventToWinEvent (idEvent, out cEvent);
        } 

        #endregion 
 
        // -----------------------------------------------------
        // 
        // Private Methods
        //
        // -----------------------------------------------------
 
        #region Private Methods
 
        #region SubItem Creation Helper 

        // private Create called by this proxy to generate Sibling, child, parent, ... 
        private ProxyFragment CreateTreeViewItem (IntPtr hItem, int depth)
        {
            return new TreeViewItem (_hwnd, this, hItem, depth);
        } 

        private ProxyFragment CreateTreeViewItemAndParents (IntPtr hItem) 
        { 
            return CreateParents (_hwnd, hItem);
        } 

        private ProxyFragment CreateParents (IntPtr hwnd, IntPtr hItem)
        {
            IntPtr hItemParent = Parent (hwnd, hItem); 

            if (hItemParent == IntPtr.Zero) 
            { 
                return new TreeViewItem (hwnd, this, hItem, 0);
            } 
            else
            {
                ProxyFragment elParent = CreateParents (hwnd, hItemParent);
 
                return new TreeViewItem(hwnd, elParent, hItem, elParent._item + 1);
            } 
        } 

        #endregion 

        #region Expand/Collapse Helpers

        // expand tree view item 
        private static bool Expand (IntPtr hwnd, IntPtr treeItem)
        { 
            return Misc.ProxySendMessageInt(hwnd, NativeMethods.TVM_EXPAND, new IntPtr(NativeMethods.TVE_EXPAND), treeItem) != 0; 
        }
 
        // collapse tree view item
        private static bool Collapse (IntPtr hwnd, IntPtr treeItem)
        {
            return Misc.ProxySendMessageInt(hwnd, NativeMethods.TVM_EXPAND, new IntPtr(NativeMethods.TVE_COLLAPSE), treeItem) != 0; 
        }
 
        // detect if tree view item is expanded. 
        private static bool IsItemExpanded (IntPtr hwnd, IntPtr treeItem)
        { 
            int expanded = GetItemState(hwnd, treeItem, NativeMethods.TVIS_EXPANDED);

            return (Misc.IsBitSet(expanded, NativeMethods.TVIS_EXPANDED));
        } 

        #endregion 
 
        #region Selection Helpers
 
        // select tree view item
        private static bool SelectItem (IntPtr hwnd, IntPtr treeItem)
        {
            bool fRet; 
            if (Misc.ProxySendMessageInt(hwnd, NativeMethods.TVM_SELECTITEM, new IntPtr(NativeMethods.TVGN_CARET | NativeMethods.TVSI_NOSINGLEEXPAND), treeItem) != 0)
            { 
                fRet = true; 
            }
            else 
            {
                fRet = Misc.ProxySendMessageInt(hwnd, NativeMethods.TVM_SELECTITEM, new IntPtr(NativeMethods.TVGN_CARET), treeItem) != 0;
            }
 
            return fRet;
        } 
 
        // retrieve currently selected item
        private static IntPtr GetSelection (IntPtr hwnd) 
        {
            return GetNext(hwnd, IntPtr.Zero, NativeMethods.TVGN_CARET);
        }
 
        #endregion
 
        #region Navigation Helper 

        // retrieve the parent of the current item 
        private static IntPtr Parent (IntPtr hwnd, IntPtr treeItem)
        {
            return GetNext(hwnd, treeItem, NativeMethods.TVGN_PARENT);
        } 

        // retrieve the next item 
        private static IntPtr GetNextItem (IntPtr hwnd, IntPtr treeItem) 
        {
            return GetNext(hwnd, treeItem, NativeMethods.TVGN_NEXT); 
        }

        // retrieve the previous item
        private static IntPtr GetPreviousItem (IntPtr hwnd, IntPtr treeItem) 
        {
            return GetNext(hwnd, treeItem, NativeMethods.TVGN_PREVIOUS); 
        } 

        // retrieve root of the tree view 
        private static IntPtr GetRoot (IntPtr hwnd)
        {
            return GetNext(hwnd, IntPtr.Zero, NativeMethods.TVGN_ROOT);
        } 

        // retrieve the first child of the current tree view item 
        private static IntPtr GetFirstChild (IntPtr hwnd, IntPtr treeItem) 
        {
            return GetNext(hwnd, treeItem, NativeMethods.TVGN_CHILD); 
        }

        #endregion
 
        #region Value Helpers
 
        // retrieve the checked state for the specified item 
        private static int GetCheckState (IntPtr hwnd, IntPtr treeItem)
        { 
            int state = GetItemState(hwnd, treeItem, NativeMethods.TVIS_STATEIMAGEMASK);

            return ((state >> 12) - 1);
        } 

        // set the check state for the specified item 
        private unsafe static bool SetCheckState (IntPtr hwnd, IntPtr item, bool check) 
        {
            uint val = (check) ? 2U : 1U; 

            val <<= 12;

            NativeMethods.TVITEM treeItem = new NativeMethods.TVITEM (); 
            treeItem.Init (item);
            treeItem.mask = NativeMethods.TVIF_STATE; 
            treeItem.state = val; 
            treeItem.stateMask = NativeMethods.TVIS_STATEIMAGEMASK;
 
            return XSendMessage.SetItem(hwnd, treeItem);
        }

        #endregion 

        #region Common Helpers 
 
        // generic method for TVM_GETNEXTITEM message
        private static IntPtr GetNext (IntPtr hwnd, IntPtr treeItem, int flag) 
        {
            return Misc.ProxySendMessage(hwnd, NativeMethods.TVM_GETNEXTITEM, new IntPtr(flag), treeItem);
        }
 
        // generic way to retrieve item's state
        private static int GetItemState (IntPtr hwnd, IntPtr treeItem, int stateMask) 
        { 
            return Misc.ProxySendMessageInt(hwnd, NativeMethods.TVM_GETITEMSTATE, treeItem, new IntPtr(stateMask));
        } 

        // detect if tree view item has children
        private static bool TreeViewItem_HasChildren (IntPtr hwnd, IntPtr item)
        { 
            NativeMethods.TVITEM treeItem;
 
            if (!GetItem(hwnd, item, NativeMethods.TVIF_CHILDREN, out treeItem)) 
            {
                // @review: should we throw here 
                return false;
            }

            return (treeItem.cChildren > 0); 
        }
 
        // retrieve rectangle for the treeview 
        // set labelOnly to true if you only care about label rectangle
        private static unsafe NativeMethods.Win32Rect GetItemRect (IntPtr hwnd, IntPtr treeItem, bool labelOnly) 
        {
            NativeMethods.Win32Rect rc = NativeMethods.Win32Rect.Empty;

            // This strange line of code is here to make the TVM_GETITEMRECT work on 64 bit platform 
            // This message expcects an IntPtr on input and a Rect for output.  On a 64 bit platform we
            // will just overwrite the first 2 members of the rect structure with the IntPtr. 
            *((IntPtr *)&(rc.left)) = treeItem; 

            IntPtr rectangle = new IntPtr (&(rc.left)); 
            IntPtr partialDisplay = (labelOnly) ? new IntPtr (1) : IntPtr.Zero;

            if (!XSendMessage.XSend(hwnd, NativeMethods.TVM_GETITEMRECT, partialDisplay, rectangle, Marshal.SizeOf(rc.GetType())))
            { 
                return NativeMethods.Win32Rect.Empty;
            } 
 
            // Temporarily allow the possibility of returning a bounding rect for scrolled off items.
            // Will need to revisit this when there is a method that can scroll items into view. 
            //if (Misc.IsItemVisible(hwnd, ref rc))

            return Misc.MapWindowPoints(hwnd, IntPtr.Zero, ref rc, 2) ? rc : NativeMethods.Win32Rect.Empty;
        } 

        // generic method to retrieve info about tree view item 
        // NOTE: this method should not be used to retrieve a text 
        // instead use GetItemText
        private static bool GetItem (IntPtr hwnd, IntPtr item, int mask, out NativeMethods.TVITEM treeItem) 
        {
            treeItem = new NativeMethods.TVITEM ();
            treeItem.Init (item);
            treeItem.mask = (uint) mask; 

            return XSendMessage.GetItem(hwnd, ref treeItem); 
        } 

        private static string GetItemText(IntPtr hwnd, IntPtr item) 
        {
            NativeMethods.TVITEM treeItem = new NativeMethods.TVITEM();
            treeItem.Init(item);
            treeItem.mask = NativeMethods.TVIF_TEXT; 
            treeItem.cchTextMax = Misc.MaxLengthNameProperty;
 
            return XSendMessage.GetItemText(hwnd, treeItem); 
        }
 
        private static bool SetItemText(IntPtr hwnd, IntPtr item, string text)
        {
            // TVM_SETITEMW with TVIF_TEXT will not work here.  It does not notify parent of the change.
 
            // Begins in-place editing of the specified item's text, replacing the text of the item with a single-line
            // edit control containing the text. This message implicitly selects and focuses the specified item. 
            IntPtr hwndEdit = Misc.ProxySendMessage(hwnd, NativeMethods.TVM_EDITLABELW, IntPtr.Zero, item); 

            if (hwndEdit == IntPtr.Zero) 
            {
                // assume that the hwnd was bad
                throw new ElementNotAvailableException();
            } 

            // Now set the text to the edit control 
            // Note: The lParam of the WM_SETTEXT is NOT a receive parameter. Just used this overloaded version 
            // of ProxySendMessage() for convinces.
            if (Misc.ProxySendMessageInt(hwndEdit, NativeMethods.WM_SETTEXT, IntPtr.Zero, new StringBuilder(text)) != 1) 
            {
                // Cancel the edit.
                Misc.ProxySendMessage(hwnd, NativeMethods.TVM_ENDEDITLABELNOW, (IntPtr)1, IntPtr.Zero);
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); 
            }
 
            // TVM_ENDEDITLABELNOW ends the editing of a tree-view item's label. 
            // The wParam indicates whether the editing is canceled without being saved to the label.
            // If this parameter is TRUE, the system cancels editing without saving the changes. 
            // Otherwise, the system saves the changes to the label.
            Misc.ProxySendMessage(hwnd, NativeMethods.TVM_ENDEDITLABELNOW, IntPtr.Zero, IntPtr.Zero);

            // Need to give some time for the control to do all its proceeing. 
            bool wasTextSet = false;
            for(int i=0; i < 10; i++) 
            { 
                System.Threading.Thread.Sleep(1);
 
                // Now see if the treeviewitem really got set.
                if (text.Equals(WindowsTreeView.GetItemText(hwnd, item)))
                {
                    wasTextSet = true; 
                    break;
                } 
            } 
            if (!wasTextSet)
            { 
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
            }

            return true; 
        }
 
        //Converts child id to handle to tree item. 
        private static IntPtr TreeItemFromChildID(IntPtr hwnd, int idChild)
        { 
            IntPtr hItem = Misc.ProxySendMessage(hwnd, NativeMethods.TVM_MAPACCIDTOHTREEITEM, new IntPtr(idChild), IntPtr.Zero);

            if (hItem != IntPtr.Zero)
            { 
                return hItem;
            } 
 
#if WIN64
            return IntPtr.Zero; 
#else
            //Fallback for older 32-bit comctls that don't implement the mapping message
            return new IntPtr(idChild);
#endif 
        }
        #endregion 
 
        #endregion Private Methods
 
        // -----------------------------------------------------
        //
        // Private Fields
        // 
        // ------------------------------------------------------
 
        #region Private Fields 

        // Represent the state of the checkbox 
        // Remark: ListView and TreeView will share this enum
        private enum CheckState: int
        {
            NoCheckbox = -1, 
            Unchecked = 0,
            Checked = 1 
        } 

        //  const defining the container (if depth == Proxy_container, the proxy is on the container, negative scroll bar, else an item) 
        private enum TVItem
        {
            // must be different than the VtScroll and HzScroll
            TopLevel = 0, 
        }
 
        #endregion 

        // ----------------------------------------------------- 
        //
        //  TreeViewItem Private Class
        //
        //------------------------------------------------------ 

        #region TreeViewItem 
 
        // Summary description for TreeViewItem.
        class TreeViewItem : ProxyFragment, ISelectionItemProvider, IExpandCollapseProvider, IValueProvider, IToggleProvider, IScrollItemProvider, IInvokeProvider 
        {
            // ------------------------------------------------------
            //
            //  Constructors 
            //
            //----------------------------------------------------- 
 
            #region Constructors
 
            internal TreeViewItem (IntPtr hwnd, ProxyFragment parent, IntPtr hItem, int depth)
                : base(hwnd, parent, depth)
            {
                // windows handle to this substree 
                _hItem = hItem;
 
                // Set the strings to return properly the properties. 
                _cControlType = ControlType.TreeItem;
                _fHasPersistentID = false; 
                _fIsKeyboardFocusable = true;
            }

            #endregion 

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

            #region ProxyFragment Interface
 
            // Returns the next sibling element in the raw hierarchy.
            // Peripheral controls have always negative values. 
            // Returns null if no next child 
            internal override ProxySimple GetNextSibling (ProxySimple child)
            { 
                CheckForElementAvailable ();
                return IsItemExpanded (_hwnd, _hItem) ? NextSibling (child) : null;
            }
 
            // Returns the previous sibling element in the raw hierarchy.
            // Peripheral controls have always negative values. 
            // Returns null is no previous 
            internal override ProxySimple GetPreviousSibling (ProxySimple child)
            { 
                CheckForElementAvailable ();
                return IsItemExpanded (_hwnd, _hItem) ? PreviousSibling (child) : null;
            }
 
            // Returns the first child element in the raw hierarchy.
            internal override ProxySimple GetFirstChild () 
            { 
                CheckForElementAvailable ();
                return IsItemExpanded (_hwnd, _hItem) ? FirstChild () : null; 
            }

            // Returns the last child element in the raw hierarchy.
            internal override ProxySimple GetLastChild () 
            {
                CheckForElementAvailable (); 
                return IsItemExpanded (_hwnd, _hItem) ? LastChild () : null; 
            }
 
            #endregion

            #region ProxySimple Interface
 
            // Returns a pattern interface if supported.
            internal override object GetPatternProvider (AutomationPattern iid) 
            { 
                CheckForElementAvailable ();
 
                // This is an item
                if (iid == SelectionItemPattern.Pattern
#if HIERARCHY_PATTERN
                    || iid == HierarchyItemPattern.Pattern 
#endif
                    ) 
                { 
                    return this;
                } 
                else if (iid == ScrollItemPattern.Pattern && WindowScroll.IsScrollable(_hwnd))
                {
                    return this;
                } 
                else if (iid == ValuePattern.Pattern && IsItemEditable())
                { 
                    return this; 
                }
                else if (iid == ExpandCollapsePattern.Pattern) 
                {
                    return this;
                }
                else if (iid == TogglePattern.Pattern && IsItemWithCheckbox()) 
                {
                    return this; 
                } 
                //Special case handling for vista windows explorer's tree view implementation.
                //Reason: Selecting the node does not refresh the folder items in the right pane 
                //So, implement the Invoke pattern and let the client call invoke to get behavior
                //similar to windows explorer of windows XP
                else if (iid == InvokePattern.Pattern)
                { 
                    //This condition is to avoid calling CreateNativeFromEvent repeatedly.
                    if (_nativeAcc == null && System.Environment.OSVersion.Version.Major >= 6 && Misc.IsWindowInGivenProcess(_hwnd, "explorer")) 
                    { 
                        int childId = ChildIDFromTVItem();
                        _nativeAcc = Accessible.CreateNativeFromEvent(_hwnd, NativeMethods.OBJID_CLIENT, childId); 
                    }
                    //This is to check whether native IAccessible is implemented and only then expose the invoke pattern.
                    if (_nativeAcc != null)
                    { 
                        return this;
                    } 
                } 

                return null; 
            }

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

            // Process all the Element Properties 
            internal override object GetElementProperty(AutomationProperty idProp) 
            {
                if (idProp == AutomationElement.IsOffscreenProperty) 
                {
                    NativeMethods.Win32Rect itemRect = GetItemRect(_hwnd, _hItem, true);

                    // Need to check if this item is visible on the whole control not just its immediate parent. 
                    if (!Misc.IsItemVisible(_hwnd, ref itemRect))
                    { 
                        return true; 
                    }
                } 

                return base.GetElementProperty(idProp);
            }
 
            //Gets the controls help text
            internal override string HelpText 
            { 
                get
                { 
                    CheckForElementAvailable();

                    IntPtr hwndToolTip = Misc.ProxySendMessage(_hwnd, NativeMethods.TVM_GETTOOLTIPS, IntPtr.Zero, IntPtr.Zero);
                    return Misc.GetItemToolTipText(_hwnd, hwndToolTip, _item); 
                }
            } 
 
            internal override bool IsOffscreen()
            { 
                Rect itemRect = BoundingRectangle;

                if (itemRect.IsEmpty)
                { 
                    return true;
                } 
 
                // Sub-TreeViewItems are not with in the parents bounding rectangle.  So check if
                // the sub item is visible with in the whole control. 
                ProxySimple parent;
                ProxySimple current = this;
                do
                { 
                    parent = current.GetParent();
                    if (parent is WindowsTreeView) 
                    { 
                        break;
                    } 
                    current = parent;
                } while (parent != null);

                if (parent != null) 
                {
                    if ((bool)parent.GetElementProperty(AutomationElement.IsOffscreenProperty)) 
                    { 
                        return true;
                    } 

                    // Now check to see if this item in visible on its parent
                    Rect parentRect = parent.BoundingRectangle;
                    if (!parentRect.IsEmpty && !Misc.IsItemVisible(ref parentRect, ref itemRect)) 
                    {
                        return true; 
                    } 
                }
 
                // if this element is not on any monitor than it is off the screen.
                NativeMethods.Win32Rect itemWin32Rect = new NativeMethods.Win32Rect(itemRect);
                return UnsafeNativeMethods.MonitorFromRect(ref itemWin32Rect, UnsafeNativeMethods.MONITOR_DEFAULTTONULL) == IntPtr.Zero;
            } 

            //Gets the localized name 
            internal override string LocalizedName 
            {
                get 
                {
                    CheckForElementAvailable();
                    return Text;
                } 
            }
 
            // Returns an item corresponding to the focused element (if there is one), or null otherwise. 
            internal override bool SetFocus ()
            { 
                // try to select an item, hence unselecting everything else
                return WindowsTreeView.SelectItem (_hwnd, _hItem);
            }
 
            // Returns the Run Time Id, an array of ints as the concatenation of IDs.
            // Remark: Implement it locally, since it is normal to have many items on the same 
            // level, which in turn leads to the duplication of the runtime id 
            internal override int[] GetRuntimeId()
            { 
                CheckForElementAvailable ();

                if (Marshal.SizeOf(_hItem.GetType()) > sizeof(int))
                { 
                    // if this is 64 bit break the _hItem into two parts so we don't overflow
                    int highPart = NativeMethods.Util.HIDWORD((long)_hItem); 
                    int lowPart = NativeMethods.Util.LODWORD((long)_hItem); 

                    return new int [4] { ProxySimple.Win32ProviderRuntimeIdBase, unchecked((int)(long)_hwnd), highPart, lowPart }; 
                }
                else
                {
                    return new int[3] { ProxySimple.Win32ProviderRuntimeIdBase, (int)_hwnd, (int)_hItem }; 
                }
            } 
 
            #endregion
 
            #region SelectionItem Pattern

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

                CheckForElementAvailable();
 
                // simple case: item already selected
                if (IsItemSelected()) 
                { 
                    return;
                } 

                if (HasMSAAImageMap())
                {
                    Invoke(); 
                }
                else 
                { 
                    // try to select an item, hence unselecting everything else
                    if (!WindowsTreeView.SelectItem(_hwnd, _hItem)) 
                    {
                        throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
                    }
                } 
            }
 
            // Adds this element to the selection 
            void ISelectionItemProvider.AddToSelection ()
            { 
                // Make sure that the control is enabled
                if (!SafeNativeMethods.IsWindowEnabled(_hwnd))
                {
                    throw new ElementNotEnabledException(); 
                }
 
                CheckForElementAvailable(); 

                // simple case: item already selected 
                if (IsItemSelected())
                {
                    return;
                } 

                IRawElementProviderSimple container = ((ISelectionItemProvider)this).SelectionContainer; 
                bool selectionRequired = container != null ? ((ISelectionProvider)container).IsSelectionRequired : true; 

                // For single selection containers that IsSelectionRequired == false and nothing is selected 
                // an AddToSelection is valid.
                if (selectionRequired || WindowsTreeView.GetSelection(_hwnd) != IntPtr.Zero)
                {
                    // NOTE: TreeView do not natively support multiple selection 
                    throw new InvalidOperationException(SR.Get(SRID.DoesNotSupportMultipleSelection));
                } 
 
                // Since nothing is selected try to select the item
                if (!WindowsTreeView.SelectItem(_hwnd, _hItem)) 
                {
                    throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
                }
            } 

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

                CheckForElementAvailable(); 
 
                if (IsItemSelected())
                { 
                    // NOTE: TreeView do not natively support multiple selection
                    throw new InvalidOperationException(SR.Get(SRID.SelectionRequired));
                }
            } 

            // True if this element is part of the the selection 
            bool ISelectionItemProvider.IsSelected 
            {
                get 
                {
                    CheckForElementAvailable();
                    return IsItemSelected();
                } 
            }
 
            // Returns the container for this element 
            IRawElementProviderSimple ISelectionItemProvider.SelectionContainer
            { 
                get
                {
                    CheckForElementAvailable ();
 
                    for (ProxyFragment topLevelParent = _parent; ; topLevelParent = topLevelParent._parent)
                    { 
                        if (topLevelParent._parent == null) 
                        {
                            System.Diagnostics.Debug.Assert (topLevelParent is WindowsTreeView, "Invalid Parent for a TreeView Item"); 
                            return topLevelParent;
                        }
                    }
               } 
            }
 
            #endregion SelectionItem Pattern 

            #region ExpandCollapse Pattern 

            // Show all Children
            void IExpandCollapseProvider.Expand ()
            { 
                // Make sure that the control is enabled
                if (!SafeNativeMethods.IsWindowEnabled(_hwnd)) 
                { 
                    throw new ElementNotEnabledException();
                } 

                CheckForElementAvailable();

                // check if item can be expanded 
                switch (GetExpandCollapseState())
                { 
                    default: 
                    case ExpandCollapseState.LeafNode :
                        throw new InvalidOperationException (SR.Get(SRID.OperationCannotBePerformed)); 

                    case ExpandCollapseState.Expanded :
                        // Simple case, already done.
                        break; 

                    case ExpandCollapseState.Collapsed : 
                        // Do the action. 
                        WindowsTreeView.Expand (_hwnd, _hItem);
                        break; 
                }
            }

            // Hide all Children 
            void IExpandCollapseProvider.Collapse ()
            { 
                // Make sure that the control is enabled 
                if (!SafeNativeMethods.IsWindowEnabled(_hwnd))
                { 
                    throw new ElementNotEnabledException();
                }

                CheckForElementAvailable(); 

                // check if item can be collapsed 
                switch (GetExpandCollapseState()) 
                {
                    default: 
                    case ExpandCollapseState.LeafNode :
                        throw new InvalidOperationException (SR.Get(SRID.OperationCannotBePerformed));

                    case ExpandCollapseState.Expanded : 
                        // Do the action.
                        WindowsTreeView.Collapse (_hwnd, _hItem); 
                        break; 

                    case ExpandCollapseState.Collapsed : 
                        // Simple case, already done.
                        break;
                }
            } 

            // Indicates an elements current Collapsed or Expanded state 
            ExpandCollapseState IExpandCollapseProvider.ExpandCollapseState 
            {
                get 
                {
                    CheckForElementAvailable();
                    return GetExpandCollapseState();
                } 
            }
 
            #endregion ExpandCollapse Pattern 

            #region Value Pattern 

            void IValueProvider.SetValue (string val)
            {
                // Make sure that the control is enabled 
                if (!SafeNativeMethods.IsWindowEnabled(_hwnd))
                { 
                    throw new ElementNotEnabledException(); 
                }
 
                CheckForElementAvailable();

                if (!WindowsTreeView.SetItemText(_hwnd, _hItem, val))
                { 
                    throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
                } 
            } 

            // Request to get the value that this UI element is representing as a string 
            string IValueProvider.Value
            {
                get
                { 
                    CheckForElementAvailable();
                    return Text; 
                } 
            }
 
            // Read only status
            bool IValueProvider.IsReadOnly
            {
                get 
                {
                    CheckForElementAvailable(); 
                    return false; 
                }
            } 

            #endregion IValueProvider

            #region IToggleProvider 

            void IToggleProvider.Toggle() 
            { 
                // Make sure that the control is enabled
                if (!SafeNativeMethods.IsWindowEnabled(_hwnd)) 
                {
                    throw new ElementNotEnabledException();
                }
 
                CheckForElementAvailable();
 
                if (HasMSAAImageMap()) 
                {
                    Invoke(); 
                }
                else
                {
                    WindowsTreeView.SetCheckState(_hwnd, _hItem, GetToggleState() != ToggleState.On); 
                }
            } 
 
            ToggleState IToggleProvider.ToggleState
            { 
                get
                {
                    CheckForElementAvailable();
 
                    return GetToggleState();
                } 
            } 

            #endregion IToggleProvider 

            #region ScrollItem Pattern

            void IScrollItemProvider.ScrollIntoView() 
            {
                CheckForElementAvailable(); 
 
                if (!WindowScroll.IsScrollable(_hwnd))
                { 
                    throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
                }

                Misc.SetFocus(_hwnd); 

                // Currently this ignores the alignToTop, as there is no easy way to set where it 
                // will be in the Treeview, it just makes sure it is visible. 
                Misc.ProxySendMessage(_hwnd, NativeMethods.TVM_ENSUREVISIBLE, IntPtr.Zero, _hItem);
            } 

            #endregion ScrollItem Pattern

            #region Invoke Pattern 
            //Special case handling for vista windows explorer's tree view implementation.
            //when the client calls Invoke method, call DoDefaultAction on its native 
            //IAccessible (this should have been set when GetPatternProviders 
            //is called earlier). Vista Explorer's treeview has its own implementation of DoDefaultAction
            //to display the subfolders and files of the selected folder on the right pane. 
            void IInvokeProvider.Invoke()
            {
                if (_nativeAcc != null)
                { 
                    SetFocus();
                    _nativeAcc.DoDefaultAction(); 
                } 
            }
            #endregion Invoke Pattern 

            // -----------------------------------------------------
            //
            // Internal Methods 
            //
            // ----------------------------------------------------- 
 
            #region Internal Methods
 
            internal void RaiseStructureChangedEvent ()
            {
                StructureChangeType changeType = GetExpandCollapseState() == ExpandCollapseState.Expanded ? StructureChangeType.ChildrenBulkAdded : StructureChangeType.ChildrenBulkRemoved;
                AutomationInteropProvider.RaiseStructureChangedEvent( this, new StructureChangedEventArgs( changeType, GetRuntimeId() ) ); 
            }
 
            internal void RaiseExpandCollapsedStateChangedEvent () 
            {
                AutomationInteropProvider.RaiseAutomationPropertyChangedEvent(this, new AutomationPropertyChangedEventArgs(ExpandCollapsePattern.ExpandCollapseStateProperty, null, GetExpandCollapseState())); 
            }

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

            #region Protected Methods

            // This routine is only called on elements belonging to an hwnd that has the focus. 
            protected override bool IsFocused ()
            { 
                int selected = Misc.ProxySendMessageInt(_hwnd, NativeMethods.TVM_GETITEMSTATE, _hItem, new IntPtr(NativeMethods.TVIS_SELECTED)); 

                return Misc.IsBitSet(selected, NativeMethods.TVIS_SELECTED); 
            }

            #endregion
 
            // ------------------------------------------------------
            // 
            // Private Methods 
            //
            // ------------------------------------------------------ 

            #region Private Methods

            // Go up the hierarchy of parents to make sure that they are all expanded. 
            // If one of the tree view node is not expanded, it means that the element
            // is not visible 
            private void CheckForElementAvailable() 
            {
                TreeViewItem current = this; 
                while ((current = current.GetParent() as TreeViewItem) != null)
                {
                    if (!WindowsTreeView.IsItemExpanded (_hwnd, current._hItem))
                    { 
                        throw new ElementNotAvailableException ();
                    } 
                } 
            }
 
            // Returns the next sibling element in the raw hierarchy.
            // Peripheral controls have always negative values.
            // Returns null if no next child.
            private ProxySimple NextSibling (ProxySimple child) 
            {
                IntPtr hNext = WindowsTreeView.GetNextItem (_hwnd, ((TreeViewItem) child)._hItem); 
 
                return hNext != IntPtr.Zero ? new TreeViewItem(_hwnd, this, hNext, _item + 1) : null;
            } 

            // Returns the previous sibling element in the raw hierarchy.
            // Peripheral controls have always negative values.
            // Returns null is no previous. 
            private ProxySimple PreviousSibling (ProxySimple child)
            { 
                IntPtr hPrev = WindowsTreeView.GetPreviousItem (_hwnd, ((TreeViewItem) child)._hItem); 

                return hPrev != IntPtr.Zero ? new TreeViewItem(_hwnd, this, hPrev, _item + 1) : null; 
            }

            // Returns the first child element in the raw hierarchy.
            private ProxySimple FirstChild () 
            {
                IntPtr hChild = WindowsTreeView.GetFirstChild (_hwnd, _hItem); 
 
                return hChild != IntPtr.Zero ? new TreeViewItem(_hwnd, this, hChild, _item + 1) : null;
            } 

            // Returns the last child element in the raw hierarchy.
            private ProxySimple LastChild ()
            { 
                if (!IsItemExpanded (_hwnd, _hItem))
                { 
                    return null; 
                }
 
                IntPtr hChild = WindowsTreeView.GetFirstChild (_hwnd, _hItem);

                if (hChild != IntPtr.Zero)
                { 
                    // First Child found, now retrieve the last one (no specific msg, need to walk thru all of them)
                    for (IntPtr temp = WindowsTreeView.GetNextItem (_hwnd, hChild); temp != IntPtr.Zero; temp = WindowsTreeView.GetNextItem (_hwnd, hChild)) 
                    { 
                        hChild = temp;
                    } 

                    return new TreeViewItem(_hwnd, this, hChild, _item + 1);
                }
 
                return null;
            } 
 
            // Retrieve state of the treeview item
            private ExpandCollapseState GetExpandCollapseState() 
            {
                bool expanded = WindowsTreeView.IsItemExpanded (_hwnd, _hItem);

                if (expanded) 
                {
                    return ExpandCollapseState.Expanded; 
                } 

                // need to decide between leaf and collapsed 
                bool hasChildren = WindowsTreeView.TreeViewItem_HasChildren (_hwnd, _hItem);

                return (hasChildren) ? ExpandCollapseState.Collapsed : ExpandCollapseState.LeafNode;
            } 

            // get the current state for the tree view item checkbox 
            private ToggleState GetToggleState () 
            {
                WindowsTreeView.CheckState state = WindowsTreeView.CheckState.NoCheckbox; 

                if (HasMSAAImageMap())
                {
                    int image; 
                    uint overlay;
                    uint stateMSAA; 
 
                    if (GetItemImageIndex(out image, out overlay, out stateMSAA))
                    { 
                        if (stateMSAA == 0)
                        {
                            GetStateFromStateImageMap(image, ref stateMSAA);
                        } 

                        state = Misc.IsBitSet((int)stateMSAA, (int)AccessibleState.Checked) ? WindowsTreeView.CheckState.Checked : WindowsTreeView.CheckState.Unchecked; 
                    } 
                }
 
                if (state == WindowsTreeView.CheckState.NoCheckbox)
                {
                    state = (WindowsTreeView.CheckState)WindowsTreeView.GetCheckState(_hwnd, _hItem);
                } 

                switch (state) 
                { 
                    case WindowsTreeView.CheckState.NoCheckbox :
                        { 
                            // we should not call this method on the non-checkboxed treeview items
                            throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
                        }
 
                    case WindowsTreeView.CheckState.Checked :
                        { 
                            return ToggleState.On; 
                        }
 
                    case WindowsTreeView.CheckState.Unchecked :
                        {
                            return ToggleState.Off;
                        } 
                }
 
                // developer defined custom values which cannot be interpret outside of the app's scope 
                return ToggleState.Indeterminate;
            } 

            // Check the checked state of a MSAA treeview radio button item.
            private bool GetCheckState()
            { 
                WindowsTreeView.CheckState state = WindowsTreeView.CheckState.NoCheckbox;
 
                int image; 
                uint overlay;
                uint stateMSAA; 

                if (GetItemImageIndex(out image, out overlay, out stateMSAA))
                {
                    if (stateMSAA == 0) 
                    {
                        GetStateFromStateImageMap(image, ref stateMSAA); 
                    } 

                    state = Misc.IsBitSet((int)stateMSAA, (int)AccessibleState.Checked) ? WindowsTreeView.CheckState.Checked : WindowsTreeView.CheckState.Unchecked; 
                }

                return state == WindowsTreeView.CheckState.Checked;
            } 

            private void Invoke() 
            { 
                // get item rect
                NativeMethods.Win32Rect rectItem = WindowsTreeView.GetItemRect(_hwnd, _hItem, true); 

                if (rectItem.IsEmpty)
                {
                    throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); 
                }
 
                // get control coordinates at which we will "click" 
                NativeMethods.Win32Point pt = new NativeMethods.Win32Point(((rectItem.left + rectItem.right) / 2), ((rectItem.top + rectItem.bottom) / 2));
 
                // convert back to client
                if (Misc.MapWindowPoints(IntPtr.Zero, _hwnd, ref pt, 1))
                {
                    // click 
                    SimulateClick(pt);
                } 
            } 

            private bool IsItemEditable() 
            {
                return Misc.IsBitSet(WindowStyle, NativeMethods.TVS_EDITLABELS);
            }
 
            // detect if given tree view item selected
            private bool IsItemSelected() 
            { 
                int selected = WindowsTreeView.GetItemState(_hwnd, _hItem, NativeMethods.TVIS_SELECTED);
 
                if (Misc.IsBitSet(selected, NativeMethods.TVIS_SELECTED))
                {
                    return true;
                } 

                // Now check to see if this is a MSAA treeview radiobutton item 
                return GetCheckState(); 
            }
 
            // detect if current item has a checkbox associated with it
            private bool IsItemWithCheckbox ()
            {
                bool isCheckbox = Misc.IsBitSet(WindowStyle, NativeMethods.TVS_CHECKBOXES); 

                if (isCheckbox) 
                { 
                    // treeview does support the checkboxes
                    // now we need to make sure that our item supports the checkbox 
                    isCheckbox = WindowsTreeView.CheckState.NoCheckbox != (WindowsTreeView.CheckState)WindowsTreeView.GetCheckState(_hwnd, _hItem);
                }

                if (!isCheckbox) 
                {
                    int image; 
                    uint overlay; 
                    uint state;
 
                    if (GetItemImageIndex(out image, out overlay, out state))
                    {
                        if (overlay == 0)
                        { 
                            GetRoleFromStateImageMap(image, ref overlay);
                        } 
 
                        isCheckbox = (AccessibleRole)overlay == AccessibleRole.CheckButton;
                    } 
                }

                return isCheckbox;
            } 

            //  Return the TreeView Item Text or the Container text (usually hiden text) 
            private string Text 
            {
                get 
                {
                    // this is an item
                    return WindowsTreeView.GetItemText (_hwnd, _hItem);
                } 
            }
 
            // simulate click via posting WM_LBUTTONDOWN(UP) 
            private void SimulateClick(NativeMethods.Win32Point pt)
            { 
                // Fails if a SendMessage is used instead of the Post.
                Misc.PostMessage(_hwnd, NativeMethods.WM_LBUTTONDOWN, IntPtr.Zero, NativeMethods.Util.MAKELPARAM(pt.x, pt.y));
                Misc.PostMessage(_hwnd, NativeMethods.WM_LBUTTONUP, IntPtr.Zero, NativeMethods.Util.MAKELPARAM(pt.x, pt.y));
            } 

            private bool GetItemImageIndex(out int image, out uint overlay, out uint state) 
            { 
                NativeMethods.TVITEM treeItem;
                if (WindowsTreeView.GetItem(_hwnd, _hItem, NativeMethods.TVIF_IMAGE | NativeMethods.TVIF_STATE, out treeItem)) 
                {
                    image = treeItem.iImage;
                    overlay = (treeItem.state >> 8) & 0x0F;
                    state = (treeItem.state >> 12) & 0x0F; 

                    return true; 
                } 

                image = 0; 
                overlay = 0;
                state = 0;

                return false; 
            }
 
 
            private bool GetStateImageMapEnt(int image, ref uint state, ref uint role)
            { 
                // NOTE: This method may have issues with cross proc/cross bitness.

                IntPtr address = UnsafeNativeMethods.GetProp(_hwnd, "MSAAStateImageMapAddr");
                if (address == IntPtr.Zero) 
                {
                    return false; 
                } 

                int numStates = unchecked((int)UnsafeNativeMethods.GetProp(_hwnd, "MSAAStateImageMapCount")); 
                if (numStates == 0)
                {
                    return false;
                } 

                // <= used since number is a 1-based count, iImage is a 0-based index. 
                // If iImage is 0, should be at least one state. 
                if (numStates <= image)
                { 
                    return false;
                }

                using (SafeProcessHandle hProcess = new SafeProcessHandle(_hwnd)) 
                {
                    if (hProcess.IsInvalid) 
                    { 
                        return false;
                    } 

                    MSAASTATEIMAGEMAPENT ent = new MSAASTATEIMAGEMAPENT();
                    int readSize = Marshal.SizeOf(ent.GetType());
                    int count; 

                    // Adjust to image into array... 
                    IntPtr pAddress = new IntPtr((long)address + (image * readSize)); 

                    unsafe 
                    {
                        if (!Misc.ReadProcessMemory(hProcess, pAddress, new IntPtr(&ent), new IntPtr(readSize), out count))
                        {
                            return false; 
                        }
                    } 
 
                    state = (uint)ent.state;
                    role = (uint)ent.role; 
                }
                return true;
            }
 
            private bool GetRoleFromStateImageMap(int image, ref uint role)
            { 
                uint state = unchecked((uint)-1); 
                return GetStateImageMapEnt(image, ref state, ref role);
            } 

            private bool GetStateFromStateImageMap(int image, ref uint state)
            {
                uint role = unchecked((uint)-1); 
                return GetStateImageMapEnt(image, ref state, ref role);
            } 
 
            private bool HasMSAAImageMap()
            { 
                return UnsafeNativeMethods.GetProp(_hwnd, "MSAAStateImageMapAddr") != IntPtr.Zero;
            }

            //Wrapper method to get child id from treeview item. 
            //Similar to OLEACC implementation
            private int ChildIDFromTVItem() 
            { 
                if (_hItem == IntPtr.Zero)
                    return 0; 

                int childId = Misc.ProxySendMessageInt(_hwnd, TVM_MAPHTREEITEMTOACCID, _hItem, IntPtr.Zero);

                if( childId != 0 ) 
                {
                    return childId; 
                } 

            #if WIN64 
                return 0;
            #else
                // Fallback for older 32-bit comctls that don't implement the mapping
                // message 
                return _hItem.ToInt32();
            #endif 
            } 
            #endregion
 
            //-----------------------------------------------------
            //
            //  Private Fields
            // 
            //------------------------------------------------------
 
            #region Private Fields 

            // The HTREEITEM value of the treeview item (internal) 
            internal IntPtr _hItem;

            [StructLayout(LayoutKind.Sequential)]
            private struct MSAASTATEIMAGEMAPENT 
            {
                internal int role; 
                internal int state; 
            }
 
            //native IAccessible interface for TreeViewItem for special handling in
            //Vista Windows Explorer
            private Accessible _nativeAcc;
 
            //Tree view item specific constants.
            private const int TV_FIRST = 0x1100; 
            private const int TVM_MAPHTREEITEMTOACCID = TV_FIRST + 43; 
            #endregion
        } 

        #endregion

    } 
}
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: Win32 TreeView proxy 
//
// History: 
//        Jean-Francois Peyroux, alexsn - Created (in DotNet)
//
//---------------------------------------------------------------------------
 
using System;
using System.Text; 
using System.Collections; 
using System.Windows.Automation;
using System.Windows.Automation.Provider; 
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Windows;
using MS.Win32; 

namespace MS.Internal.AutomationProxies 
{ 
    class WindowsTreeView : ProxyHwnd, ISelectionProvider
    { 

        // -----------------------------------------------------
        //
        // Constructors 
        //
        // ----------------------------------------------------- 
 
        #region Constructors
 
        internal WindowsTreeView (IntPtr hwnd, ProxyFragment parent, int item)
            : base(hwnd, parent, item)
        {
            // Set the strings to return properly the properties. 
            _cControlType = ControlType.Tree;
 
            // Can be focused 
            _fIsKeyboardFocusable = true;
 
            // support for events
            _createOnEvent = new WinEventTracker.ProxyRaiseEvents (RaiseEvents);
        }
 
        #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) 
        {
            WindowsTreeView wtv = new WindowsTreeView(hwnd, null, 0); 
            return idChild == 0 ? wtv : wtv.CreateParents(hwnd, TreeItemFromChildID(hwnd, idChild));
        }

        // 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 : 
                    {
                        WindowsTreeView wtv = new WindowsTreeView (hwnd, null, -1); 
 
                        // Selection or Expand/Collapse
                        if (idChild != 0 && (eventId == NativeMethods.EventObjectSelection || 
                                             eventId == NativeMethods.EventObjectSelectionRemove ||
                                             eventId == NativeMethods.EventObjectSelectionAdd ||
                                             eventId == NativeMethods.EventObjectStateChange ||
                                             eventId == NativeMethods.EventObjectDestroy || 
                                             eventId == NativeMethods.EventObjectCreate ||
                                             eventId == NativeMethods.EventObjectNameChange)) 
                        { 
                            el = wtv.CreateParents(hwnd, TreeItemFromChildID(hwnd, idChild));
                        } 
                        else
                        {
                            el = wtv;
                        } 

                        break; 
                    } 

                case NativeMethods.OBJID_VSCROLL : 
                case NativeMethods.OBJID_HSCROLL :
                    break;

                default : 
                    el = new WindowsTreeView (hwnd, null, -1);
                    break; 
            } 

            // Expand/Collapse is too peculiar per control to be processed in the dispatch code 
            if (idProp == ExpandCollapsePattern.ExpandCollapseStateProperty && el is TreeViewItem && eventId == NativeMethods.EventObjectStateChange)
            {
                ((TreeViewItem) el).RaiseExpandCollapsedStateChangedEvent ();
                return; 
            }
 
            // Special case for logical element change for a tree view item on Expand/Collapse 
            if (((idProp as AutomationEvent) == AutomationElement.StructureChangedEvent && el is TreeViewItem) && !(eventId == NativeMethods.EventObjectDestroy || eventId == NativeMethods.EventObjectCreate))
            { 
                ((TreeViewItem) el).RaiseStructureChangedEvent ();
                return;
            }
 
            if (el != null)
            { 
                el.DispatchEvents (eventId, idProp, idObject, idChild); 
            }
        } 

        #endregion Proxy Create

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

        // ------------------------------------------------------
        // 
        // RawElementProvider interface implementation
        // 
        // ------------------------------------------------------ 

        // Returns a pattern interface if supported. 
        internal override object GetPatternProvider (AutomationPattern iid)
        {
            // This is the treeview container
            if (iid == SelectionPattern.Pattern) 
            {
                return this; 
            } 

            return null; 
        }

        #endregion ProxySimple Interface
 
        #region ProxyFragment Interface
 
        // Returns the next sibling element in the raw hierarchy. 
        // Peripheral controls have always negative values.
        // Returns null if no next child 
        internal override ProxySimple GetNextSibling (ProxySimple child)
        {
            TVItem item = (TVItem)child._item;
 
            // root child
            if (item == TVItem.TopLevel) 
            { 
                IntPtr hNext = GetNextItem (_hwnd, ((TreeViewItem) child)._hItem);
 
                if (hNext != IntPtr.Zero)
                    return new TreeViewItem (_hwnd, this, hNext, (int) TVItem.TopLevel);
            }
 
            return base.GetNextSibling (child);
        } 
 
        // Returns the previous sibling element in the raw hierarchy.
        // Peripheral controls have always negative values. 
        // Returns null is no previous
        internal override ProxySimple GetPreviousSibling (ProxySimple child)
        {
            // start with the scrollbars 
            ProxySimple ret = base.GetPreviousSibling (child);
 
            if (ret != null) 
            {
                return ret; 
            }

            // top level Treeview return the prev
            TVItem item = (TVItem)child._item; 

            if (item == TVItem.TopLevel) 
            { 
                IntPtr hPrev = GetPreviousItem (_hwnd, ((TreeViewItem) child)._hItem);
 
                return hPrev != IntPtr.Zero ? new TreeViewItem (_hwnd, this, hPrev, (int) TVItem.TopLevel) : null;
            }

            // either scroll bar or nothing as prev 
            IntPtr hChild = GetRoot (_hwnd);
 
            if (hChild != IntPtr.Zero) 
            {
                // First Child found, now retrieve the last one (no specific msg, need to walk thru all of them) 
                IntPtr temp;

                for (temp = GetNextItem (_hwnd, hChild); temp != IntPtr.Zero; temp = GetNextItem (_hwnd, hChild))
                { 
                    hChild = temp;
                } 
 
                return new TreeViewItem (_hwnd, this, hChild, (int) TVItem.TopLevel);
            } 

            return null;
        }
 
        // Returns the first child element in the raw hierarchy.
        internal override ProxySimple GetFirstChild () 
        { 
            IntPtr hChild = IntPtr.Zero;
 
            hChild = GetRoot (_hwnd);
            if (hChild != IntPtr.Zero)
            {
                return CreateTreeViewItem (hChild, (int) TVItem.TopLevel); 
            }
 
            return base.GetFirstChild (); 
        }
 
        // Returns the last child element in the raw hierarchy.
        internal override ProxySimple GetLastChild ()
        {
            // start with the scrollbars 
            ProxySimple ret = base.GetFirstChild ();
 
            if (ret != null) 
            {
                return ret; 
            }

            // get the root (or the very first item in the tree)
            IntPtr hChild = GetRoot (_hwnd); 

            if (hChild != IntPtr.Zero) 
            { 
                // First Child found, now retrieve the last one (no specific msg, need to walk thru all of them)
                for (IntPtr temp = GetNextItem (_hwnd, hChild); temp != IntPtr.Zero; temp = GetNextItem (_hwnd, hChild)) 
                {
                    hChild = temp;
                }
 
                return CreateTreeViewItem (hChild, (int) TVItem.TopLevel);
            } 
 
            return null;
        } 

        // Returns a Proxy element corresponding to the specified screen coordinates.
        internal override ProxySimple ElementProviderFromPoint (int x, int y)
        { 
            IntPtr hItem = XSendMessage.HitTestTreeView(_hwnd, x, y);
            if (hItem != IntPtr.Zero) 
            { 
                return CreateTreeViewItemAndParents(hItem);
            } 
            return base.ElementProviderFromPoint (x, y);
        }

        // Returns an item corresponding to the focused element (if there is one), or null otherwise. 
        internal override ProxySimple GetFocus ()
        { 
            IntPtr treeItem = GetSelection (_hwnd); 

            if (treeItem != IntPtr.Zero) 
            {
                return CreateTreeViewItemAndParents (treeItem);
            }
 
            return this;
        } 
 
        #endregion Interface ContextProvider
 
        #region Selection Pattern

        // Returns an enumerator over the current selection.
        IRawElementProviderSimple[] ISelectionProvider.GetSelection() 
        {
            IntPtr treeItem = GetSelection(_hwnd); 
 
            if (treeItem == IntPtr.Zero)
            { 
                // framework will handle this one correctly
                return null;
            }
 
            // no native support for multi-selection
            IRawElementProviderSimple[] selection = new IRawElementProviderSimple[1]; 
            selection [0] = CreateTreeViewItemAndParents(treeItem); 

            return selection; 
        }

        // Returns whether the control requires a minimum of one selected element at all times.
        bool ISelectionProvider.IsSelectionRequired 
        {
            // NOTE: this property is dynamic 
            // In the case when TV does not have a selected tvitem we will return false 
            // if there is a tvitem with the selection we will return true
            get 
            {
                return (IntPtr.Zero != GetSelection (_hwnd));
            }
        } 

        // Returns whether the control supports multiple selection. 
        bool ISelectionProvider.CanSelectMultiple 
        {
            get 
            {
                // Windows tree view does not provide native support
                // for multiple selection
                return false; 
            }
        } 
 
        #endregion Selection Pattern
 
        // -----------------------------------------------------
        //
        // Protected Methods
        // 
        // ------------------------------------------------------
 
        #region Protected Methods 

        // Picks a WinEvent to track for a UIA property 
        // Returns the WinEvent ID or 0 if no WinEvents matches a the UIA property
        protected override int [] PropertyToWinEvent (AutomationProperty idProp)
        {
            if (idProp == ValuePattern.ValueProperty) 
            {
                return new int[] { NativeMethods.EventObjectNameChange, 
                                   NativeMethods.EventObjectStateChange }; 
            }
            else if (idProp == ExpandCollapsePattern.ExpandCollapseStateProperty) 
            {
                return new int[] { NativeMethods.EventObjectStateChange };
            }
            return base.PropertyToWinEvent (idProp); 
        }
 
        // Builds a list of Win32 WinEvents to process a UIAutomation Event. 
        // Returns an array of Events to Set. The number of valid entries in this array pass back in cEvent.
        protected override WinEventTracker.EvtIdProperty [] EventToWinEvent (AutomationEvent idEvent, out int cEvent) 
        {
            if (idEvent == AutomationElement.StructureChangedEvent)
            {
                cEvent = 3; 
                return new WinEventTracker.EvtIdProperty [3] {
                    new WinEventTracker.EvtIdProperty (NativeMethods.EventObjectStateChange, idEvent), 
                    new WinEventTracker.EvtIdProperty (NativeMethods.EventObjectCreate, idEvent), 
                    new WinEventTracker.EvtIdProperty (NativeMethods.EventObjectDestroy, idEvent)
                }; 
            }

            return base.EventToWinEvent (idEvent, out cEvent);
        } 

        #endregion 
 
        // -----------------------------------------------------
        // 
        // Private Methods
        //
        // -----------------------------------------------------
 
        #region Private Methods
 
        #region SubItem Creation Helper 

        // private Create called by this proxy to generate Sibling, child, parent, ... 
        private ProxyFragment CreateTreeViewItem (IntPtr hItem, int depth)
        {
            return new TreeViewItem (_hwnd, this, hItem, depth);
        } 

        private ProxyFragment CreateTreeViewItemAndParents (IntPtr hItem) 
        { 
            return CreateParents (_hwnd, hItem);
        } 

        private ProxyFragment CreateParents (IntPtr hwnd, IntPtr hItem)
        {
            IntPtr hItemParent = Parent (hwnd, hItem); 

            if (hItemParent == IntPtr.Zero) 
            { 
                return new TreeViewItem (hwnd, this, hItem, 0);
            } 
            else
            {
                ProxyFragment elParent = CreateParents (hwnd, hItemParent);
 
                return new TreeViewItem(hwnd, elParent, hItem, elParent._item + 1);
            } 
        } 

        #endregion 

        #region Expand/Collapse Helpers

        // expand tree view item 
        private static bool Expand (IntPtr hwnd, IntPtr treeItem)
        { 
            return Misc.ProxySendMessageInt(hwnd, NativeMethods.TVM_EXPAND, new IntPtr(NativeMethods.TVE_EXPAND), treeItem) != 0; 
        }
 
        // collapse tree view item
        private static bool Collapse (IntPtr hwnd, IntPtr treeItem)
        {
            return Misc.ProxySendMessageInt(hwnd, NativeMethods.TVM_EXPAND, new IntPtr(NativeMethods.TVE_COLLAPSE), treeItem) != 0; 
        }
 
        // detect if tree view item is expanded. 
        private static bool IsItemExpanded (IntPtr hwnd, IntPtr treeItem)
        { 
            int expanded = GetItemState(hwnd, treeItem, NativeMethods.TVIS_EXPANDED);

            return (Misc.IsBitSet(expanded, NativeMethods.TVIS_EXPANDED));
        } 

        #endregion 
 
        #region Selection Helpers
 
        // select tree view item
        private static bool SelectItem (IntPtr hwnd, IntPtr treeItem)
        {
            bool fRet; 
            if (Misc.ProxySendMessageInt(hwnd, NativeMethods.TVM_SELECTITEM, new IntPtr(NativeMethods.TVGN_CARET | NativeMethods.TVSI_NOSINGLEEXPAND), treeItem) != 0)
            { 
                fRet = true; 
            }
            else 
            {
                fRet = Misc.ProxySendMessageInt(hwnd, NativeMethods.TVM_SELECTITEM, new IntPtr(NativeMethods.TVGN_CARET), treeItem) != 0;
            }
 
            return fRet;
        } 
 
        // retrieve currently selected item
        private static IntPtr GetSelection (IntPtr hwnd) 
        {
            return GetNext(hwnd, IntPtr.Zero, NativeMethods.TVGN_CARET);
        }
 
        #endregion
 
        #region Navigation Helper 

        // retrieve the parent of the current item 
        private static IntPtr Parent (IntPtr hwnd, IntPtr treeItem)
        {
            return GetNext(hwnd, treeItem, NativeMethods.TVGN_PARENT);
        } 

        // retrieve the next item 
        private static IntPtr GetNextItem (IntPtr hwnd, IntPtr treeItem) 
        {
            return GetNext(hwnd, treeItem, NativeMethods.TVGN_NEXT); 
        }

        // retrieve the previous item
        private static IntPtr GetPreviousItem (IntPtr hwnd, IntPtr treeItem) 
        {
            return GetNext(hwnd, treeItem, NativeMethods.TVGN_PREVIOUS); 
        } 

        // retrieve root of the tree view 
        private static IntPtr GetRoot (IntPtr hwnd)
        {
            return GetNext(hwnd, IntPtr.Zero, NativeMethods.TVGN_ROOT);
        } 

        // retrieve the first child of the current tree view item 
        private static IntPtr GetFirstChild (IntPtr hwnd, IntPtr treeItem) 
        {
            return GetNext(hwnd, treeItem, NativeMethods.TVGN_CHILD); 
        }

        #endregion
 
        #region Value Helpers
 
        // retrieve the checked state for the specified item 
        private static int GetCheckState (IntPtr hwnd, IntPtr treeItem)
        { 
            int state = GetItemState(hwnd, treeItem, NativeMethods.TVIS_STATEIMAGEMASK);

            return ((state >> 12) - 1);
        } 

        // set the check state for the specified item 
        private unsafe static bool SetCheckState (IntPtr hwnd, IntPtr item, bool check) 
        {
            uint val = (check) ? 2U : 1U; 

            val <<= 12;

            NativeMethods.TVITEM treeItem = new NativeMethods.TVITEM (); 
            treeItem.Init (item);
            treeItem.mask = NativeMethods.TVIF_STATE; 
            treeItem.state = val; 
            treeItem.stateMask = NativeMethods.TVIS_STATEIMAGEMASK;
 
            return XSendMessage.SetItem(hwnd, treeItem);
        }

        #endregion 

        #region Common Helpers 
 
        // generic method for TVM_GETNEXTITEM message
        private static IntPtr GetNext (IntPtr hwnd, IntPtr treeItem, int flag) 
        {
            return Misc.ProxySendMessage(hwnd, NativeMethods.TVM_GETNEXTITEM, new IntPtr(flag), treeItem);
        }
 
        // generic way to retrieve item's state
        private static int GetItemState (IntPtr hwnd, IntPtr treeItem, int stateMask) 
        { 
            return Misc.ProxySendMessageInt(hwnd, NativeMethods.TVM_GETITEMSTATE, treeItem, new IntPtr(stateMask));
        } 

        // detect if tree view item has children
        private static bool TreeViewItem_HasChildren (IntPtr hwnd, IntPtr item)
        { 
            NativeMethods.TVITEM treeItem;
 
            if (!GetItem(hwnd, item, NativeMethods.TVIF_CHILDREN, out treeItem)) 
            {
                // @review: should we throw here 
                return false;
            }

            return (treeItem.cChildren > 0); 
        }
 
        // retrieve rectangle for the treeview 
        // set labelOnly to true if you only care about label rectangle
        private static unsafe NativeMethods.Win32Rect GetItemRect (IntPtr hwnd, IntPtr treeItem, bool labelOnly) 
        {
            NativeMethods.Win32Rect rc = NativeMethods.Win32Rect.Empty;

            // This strange line of code is here to make the TVM_GETITEMRECT work on 64 bit platform 
            // This message expcects an IntPtr on input and a Rect for output.  On a 64 bit platform we
            // will just overwrite the first 2 members of the rect structure with the IntPtr. 
            *((IntPtr *)&(rc.left)) = treeItem; 

            IntPtr rectangle = new IntPtr (&(rc.left)); 
            IntPtr partialDisplay = (labelOnly) ? new IntPtr (1) : IntPtr.Zero;

            if (!XSendMessage.XSend(hwnd, NativeMethods.TVM_GETITEMRECT, partialDisplay, rectangle, Marshal.SizeOf(rc.GetType())))
            { 
                return NativeMethods.Win32Rect.Empty;
            } 
 
            // Temporarily allow the possibility of returning a bounding rect for scrolled off items.
            // Will need to revisit this when there is a method that can scroll items into view. 
            //if (Misc.IsItemVisible(hwnd, ref rc))

            return Misc.MapWindowPoints(hwnd, IntPtr.Zero, ref rc, 2) ? rc : NativeMethods.Win32Rect.Empty;
        } 

        // generic method to retrieve info about tree view item 
        // NOTE: this method should not be used to retrieve a text 
        // instead use GetItemText
        private static bool GetItem (IntPtr hwnd, IntPtr item, int mask, out NativeMethods.TVITEM treeItem) 
        {
            treeItem = new NativeMethods.TVITEM ();
            treeItem.Init (item);
            treeItem.mask = (uint) mask; 

            return XSendMessage.GetItem(hwnd, ref treeItem); 
        } 

        private static string GetItemText(IntPtr hwnd, IntPtr item) 
        {
            NativeMethods.TVITEM treeItem = new NativeMethods.TVITEM();
            treeItem.Init(item);
            treeItem.mask = NativeMethods.TVIF_TEXT; 
            treeItem.cchTextMax = Misc.MaxLengthNameProperty;
 
            return XSendMessage.GetItemText(hwnd, treeItem); 
        }
 
        private static bool SetItemText(IntPtr hwnd, IntPtr item, string text)
        {
            // TVM_SETITEMW with TVIF_TEXT will not work here.  It does not notify parent of the change.
 
            // Begins in-place editing of the specified item's text, replacing the text of the item with a single-line
            // edit control containing the text. This message implicitly selects and focuses the specified item. 
            IntPtr hwndEdit = Misc.ProxySendMessage(hwnd, NativeMethods.TVM_EDITLABELW, IntPtr.Zero, item); 

            if (hwndEdit == IntPtr.Zero) 
            {
                // assume that the hwnd was bad
                throw new ElementNotAvailableException();
            } 

            // Now set the text to the edit control 
            // Note: The lParam of the WM_SETTEXT is NOT a receive parameter. Just used this overloaded version 
            // of ProxySendMessage() for convinces.
            if (Misc.ProxySendMessageInt(hwndEdit, NativeMethods.WM_SETTEXT, IntPtr.Zero, new StringBuilder(text)) != 1) 
            {
                // Cancel the edit.
                Misc.ProxySendMessage(hwnd, NativeMethods.TVM_ENDEDITLABELNOW, (IntPtr)1, IntPtr.Zero);
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); 
            }
 
            // TVM_ENDEDITLABELNOW ends the editing of a tree-view item's label. 
            // The wParam indicates whether the editing is canceled without being saved to the label.
            // If this parameter is TRUE, the system cancels editing without saving the changes. 
            // Otherwise, the system saves the changes to the label.
            Misc.ProxySendMessage(hwnd, NativeMethods.TVM_ENDEDITLABELNOW, IntPtr.Zero, IntPtr.Zero);

            // Need to give some time for the control to do all its proceeing. 
            bool wasTextSet = false;
            for(int i=0; i < 10; i++) 
            { 
                System.Threading.Thread.Sleep(1);
 
                // Now see if the treeviewitem really got set.
                if (text.Equals(WindowsTreeView.GetItemText(hwnd, item)))
                {
                    wasTextSet = true; 
                    break;
                } 
            } 
            if (!wasTextSet)
            { 
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
            }

            return true; 
        }
 
        //Converts child id to handle to tree item. 
        private static IntPtr TreeItemFromChildID(IntPtr hwnd, int idChild)
        { 
            IntPtr hItem = Misc.ProxySendMessage(hwnd, NativeMethods.TVM_MAPACCIDTOHTREEITEM, new IntPtr(idChild), IntPtr.Zero);

            if (hItem != IntPtr.Zero)
            { 
                return hItem;
            } 
 
#if WIN64
            return IntPtr.Zero; 
#else
            //Fallback for older 32-bit comctls that don't implement the mapping message
            return new IntPtr(idChild);
#endif 
        }
        #endregion 
 
        #endregion Private Methods
 
        // -----------------------------------------------------
        //
        // Private Fields
        // 
        // ------------------------------------------------------
 
        #region Private Fields 

        // Represent the state of the checkbox 
        // Remark: ListView and TreeView will share this enum
        private enum CheckState: int
        {
            NoCheckbox = -1, 
            Unchecked = 0,
            Checked = 1 
        } 

        //  const defining the container (if depth == Proxy_container, the proxy is on the container, negative scroll bar, else an item) 
        private enum TVItem
        {
            // must be different than the VtScroll and HzScroll
            TopLevel = 0, 
        }
 
        #endregion 

        // ----------------------------------------------------- 
        //
        //  TreeViewItem Private Class
        //
        //------------------------------------------------------ 

        #region TreeViewItem 
 
        // Summary description for TreeViewItem.
        class TreeViewItem : ProxyFragment, ISelectionItemProvider, IExpandCollapseProvider, IValueProvider, IToggleProvider, IScrollItemProvider, IInvokeProvider 
        {
            // ------------------------------------------------------
            //
            //  Constructors 
            //
            //----------------------------------------------------- 
 
            #region Constructors
 
            internal TreeViewItem (IntPtr hwnd, ProxyFragment parent, IntPtr hItem, int depth)
                : base(hwnd, parent, depth)
            {
                // windows handle to this substree 
                _hItem = hItem;
 
                // Set the strings to return properly the properties. 
                _cControlType = ControlType.TreeItem;
                _fHasPersistentID = false; 
                _fIsKeyboardFocusable = true;
            }

            #endregion 

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

            #region ProxyFragment Interface
 
            // Returns the next sibling element in the raw hierarchy.
            // Peripheral controls have always negative values. 
            // Returns null if no next child 
            internal override ProxySimple GetNextSibling (ProxySimple child)
            { 
                CheckForElementAvailable ();
                return IsItemExpanded (_hwnd, _hItem) ? NextSibling (child) : null;
            }
 
            // Returns the previous sibling element in the raw hierarchy.
            // Peripheral controls have always negative values. 
            // Returns null is no previous 
            internal override ProxySimple GetPreviousSibling (ProxySimple child)
            { 
                CheckForElementAvailable ();
                return IsItemExpanded (_hwnd, _hItem) ? PreviousSibling (child) : null;
            }
 
            // Returns the first child element in the raw hierarchy.
            internal override ProxySimple GetFirstChild () 
            { 
                CheckForElementAvailable ();
                return IsItemExpanded (_hwnd, _hItem) ? FirstChild () : null; 
            }

            // Returns the last child element in the raw hierarchy.
            internal override ProxySimple GetLastChild () 
            {
                CheckForElementAvailable (); 
                return IsItemExpanded (_hwnd, _hItem) ? LastChild () : null; 
            }
 
            #endregion

            #region ProxySimple Interface
 
            // Returns a pattern interface if supported.
            internal override object GetPatternProvider (AutomationPattern iid) 
            { 
                CheckForElementAvailable ();
 
                // This is an item
                if (iid == SelectionItemPattern.Pattern
#if HIERARCHY_PATTERN
                    || iid == HierarchyItemPattern.Pattern 
#endif
                    ) 
                { 
                    return this;
                } 
                else if (iid == ScrollItemPattern.Pattern && WindowScroll.IsScrollable(_hwnd))
                {
                    return this;
                } 
                else if (iid == ValuePattern.Pattern && IsItemEditable())
                { 
                    return this; 
                }
                else if (iid == ExpandCollapsePattern.Pattern) 
                {
                    return this;
                }
                else if (iid == TogglePattern.Pattern && IsItemWithCheckbox()) 
                {
                    return this; 
                } 
                //Special case handling for vista windows explorer's tree view implementation.
                //Reason: Selecting the node does not refresh the folder items in the right pane 
                //So, implement the Invoke pattern and let the client call invoke to get behavior
                //similar to windows explorer of windows XP
                else if (iid == InvokePattern.Pattern)
                { 
                    //This condition is to avoid calling CreateNativeFromEvent repeatedly.
                    if (_nativeAcc == null && System.Environment.OSVersion.Version.Major >= 6 && Misc.IsWindowInGivenProcess(_hwnd, "explorer")) 
                    { 
                        int childId = ChildIDFromTVItem();
                        _nativeAcc = Accessible.CreateNativeFromEvent(_hwnd, NativeMethods.OBJID_CLIENT, childId); 
                    }
                    //This is to check whether native IAccessible is implemented and only then expose the invoke pattern.
                    if (_nativeAcc != null)
                    { 
                        return this;
                    } 
                } 

                return null; 
            }

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

            // Process all the Element Properties 
            internal override object GetElementProperty(AutomationProperty idProp) 
            {
                if (idProp == AutomationElement.IsOffscreenProperty) 
                {
                    NativeMethods.Win32Rect itemRect = GetItemRect(_hwnd, _hItem, true);

                    // Need to check if this item is visible on the whole control not just its immediate parent. 
                    if (!Misc.IsItemVisible(_hwnd, ref itemRect))
                    { 
                        return true; 
                    }
                } 

                return base.GetElementProperty(idProp);
            }
 
            //Gets the controls help text
            internal override string HelpText 
            { 
                get
                { 
                    CheckForElementAvailable();

                    IntPtr hwndToolTip = Misc.ProxySendMessage(_hwnd, NativeMethods.TVM_GETTOOLTIPS, IntPtr.Zero, IntPtr.Zero);
                    return Misc.GetItemToolTipText(_hwnd, hwndToolTip, _item); 
                }
            } 
 
            internal override bool IsOffscreen()
            { 
                Rect itemRect = BoundingRectangle;

                if (itemRect.IsEmpty)
                { 
                    return true;
                } 
 
                // Sub-TreeViewItems are not with in the parents bounding rectangle.  So check if
                // the sub item is visible with in the whole control. 
                ProxySimple parent;
                ProxySimple current = this;
                do
                { 
                    parent = current.GetParent();
                    if (parent is WindowsTreeView) 
                    { 
                        break;
                    } 
                    current = parent;
                } while (parent != null);

                if (parent != null) 
                {
                    if ((bool)parent.GetElementProperty(AutomationElement.IsOffscreenProperty)) 
                    { 
                        return true;
                    } 

                    // Now check to see if this item in visible on its parent
                    Rect parentRect = parent.BoundingRectangle;
                    if (!parentRect.IsEmpty && !Misc.IsItemVisible(ref parentRect, ref itemRect)) 
                    {
                        return true; 
                    } 
                }
 
                // if this element is not on any monitor than it is off the screen.
                NativeMethods.Win32Rect itemWin32Rect = new NativeMethods.Win32Rect(itemRect);
                return UnsafeNativeMethods.MonitorFromRect(ref itemWin32Rect, UnsafeNativeMethods.MONITOR_DEFAULTTONULL) == IntPtr.Zero;
            } 

            //Gets the localized name 
            internal override string LocalizedName 
            {
                get 
                {
                    CheckForElementAvailable();
                    return Text;
                } 
            }
 
            // Returns an item corresponding to the focused element (if there is one), or null otherwise. 
            internal override bool SetFocus ()
            { 
                // try to select an item, hence unselecting everything else
                return WindowsTreeView.SelectItem (_hwnd, _hItem);
            }
 
            // Returns the Run Time Id, an array of ints as the concatenation of IDs.
            // Remark: Implement it locally, since it is normal to have many items on the same 
            // level, which in turn leads to the duplication of the runtime id 
            internal override int[] GetRuntimeId()
            { 
                CheckForElementAvailable ();

                if (Marshal.SizeOf(_hItem.GetType()) > sizeof(int))
                { 
                    // if this is 64 bit break the _hItem into two parts so we don't overflow
                    int highPart = NativeMethods.Util.HIDWORD((long)_hItem); 
                    int lowPart = NativeMethods.Util.LODWORD((long)_hItem); 

                    return new int [4] { ProxySimple.Win32ProviderRuntimeIdBase, unchecked((int)(long)_hwnd), highPart, lowPart }; 
                }
                else
                {
                    return new int[3] { ProxySimple.Win32ProviderRuntimeIdBase, (int)_hwnd, (int)_hItem }; 
                }
            } 
 
            #endregion
 
            #region SelectionItem Pattern

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

                CheckForElementAvailable();
 
                // simple case: item already selected
                if (IsItemSelected()) 
                { 
                    return;
                } 

                if (HasMSAAImageMap())
                {
                    Invoke(); 
                }
                else 
                { 
                    // try to select an item, hence unselecting everything else
                    if (!WindowsTreeView.SelectItem(_hwnd, _hItem)) 
                    {
                        throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
                    }
                } 
            }
 
            // Adds this element to the selection 
            void ISelectionItemProvider.AddToSelection ()
            { 
                // Make sure that the control is enabled
                if (!SafeNativeMethods.IsWindowEnabled(_hwnd))
                {
                    throw new ElementNotEnabledException(); 
                }
 
                CheckForElementAvailable(); 

                // simple case: item already selected 
                if (IsItemSelected())
                {
                    return;
                } 

                IRawElementProviderSimple container = ((ISelectionItemProvider)this).SelectionContainer; 
                bool selectionRequired = container != null ? ((ISelectionProvider)container).IsSelectionRequired : true; 

                // For single selection containers that IsSelectionRequired == false and nothing is selected 
                // an AddToSelection is valid.
                if (selectionRequired || WindowsTreeView.GetSelection(_hwnd) != IntPtr.Zero)
                {
                    // NOTE: TreeView do not natively support multiple selection 
                    throw new InvalidOperationException(SR.Get(SRID.DoesNotSupportMultipleSelection));
                } 
 
                // Since nothing is selected try to select the item
                if (!WindowsTreeView.SelectItem(_hwnd, _hItem)) 
                {
                    throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
                }
            } 

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

                CheckForElementAvailable(); 
 
                if (IsItemSelected())
                { 
                    // NOTE: TreeView do not natively support multiple selection
                    throw new InvalidOperationException(SR.Get(SRID.SelectionRequired));
                }
            } 

            // True if this element is part of the the selection 
            bool ISelectionItemProvider.IsSelected 
            {
                get 
                {
                    CheckForElementAvailable();
                    return IsItemSelected();
                } 
            }
 
            // Returns the container for this element 
            IRawElementProviderSimple ISelectionItemProvider.SelectionContainer
            { 
                get
                {
                    CheckForElementAvailable ();
 
                    for (ProxyFragment topLevelParent = _parent; ; topLevelParent = topLevelParent._parent)
                    { 
                        if (topLevelParent._parent == null) 
                        {
                            System.Diagnostics.Debug.Assert (topLevelParent is WindowsTreeView, "Invalid Parent for a TreeView Item"); 
                            return topLevelParent;
                        }
                    }
               } 
            }
 
            #endregion SelectionItem Pattern 

            #region ExpandCollapse Pattern 

            // Show all Children
            void IExpandCollapseProvider.Expand ()
            { 
                // Make sure that the control is enabled
                if (!SafeNativeMethods.IsWindowEnabled(_hwnd)) 
                { 
                    throw new ElementNotEnabledException();
                } 

                CheckForElementAvailable();

                // check if item can be expanded 
                switch (GetExpandCollapseState())
                { 
                    default: 
                    case ExpandCollapseState.LeafNode :
                        throw new InvalidOperationException (SR.Get(SRID.OperationCannotBePerformed)); 

                    case ExpandCollapseState.Expanded :
                        // Simple case, already done.
                        break; 

                    case ExpandCollapseState.Collapsed : 
                        // Do the action. 
                        WindowsTreeView.Expand (_hwnd, _hItem);
                        break; 
                }
            }

            // Hide all Children 
            void IExpandCollapseProvider.Collapse ()
            { 
                // Make sure that the control is enabled 
                if (!SafeNativeMethods.IsWindowEnabled(_hwnd))
                { 
                    throw new ElementNotEnabledException();
                }

                CheckForElementAvailable(); 

                // check if item can be collapsed 
                switch (GetExpandCollapseState()) 
                {
                    default: 
                    case ExpandCollapseState.LeafNode :
                        throw new InvalidOperationException (SR.Get(SRID.OperationCannotBePerformed));

                    case ExpandCollapseState.Expanded : 
                        // Do the action.
                        WindowsTreeView.Collapse (_hwnd, _hItem); 
                        break; 

                    case ExpandCollapseState.Collapsed : 
                        // Simple case, already done.
                        break;
                }
            } 

            // Indicates an elements current Collapsed or Expanded state 
            ExpandCollapseState IExpandCollapseProvider.ExpandCollapseState 
            {
                get 
                {
                    CheckForElementAvailable();
                    return GetExpandCollapseState();
                } 
            }
 
            #endregion ExpandCollapse Pattern 

            #region Value Pattern 

            void IValueProvider.SetValue (string val)
            {
                // Make sure that the control is enabled 
                if (!SafeNativeMethods.IsWindowEnabled(_hwnd))
                { 
                    throw new ElementNotEnabledException(); 
                }
 
                CheckForElementAvailable();

                if (!WindowsTreeView.SetItemText(_hwnd, _hItem, val))
                { 
                    throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
                } 
            } 

            // Request to get the value that this UI element is representing as a string 
            string IValueProvider.Value
            {
                get
                { 
                    CheckForElementAvailable();
                    return Text; 
                } 
            }
 
            // Read only status
            bool IValueProvider.IsReadOnly
            {
                get 
                {
                    CheckForElementAvailable(); 
                    return false; 
                }
            } 

            #endregion IValueProvider

            #region IToggleProvider 

            void IToggleProvider.Toggle() 
            { 
                // Make sure that the control is enabled
                if (!SafeNativeMethods.IsWindowEnabled(_hwnd)) 
                {
                    throw new ElementNotEnabledException();
                }
 
                CheckForElementAvailable();
 
                if (HasMSAAImageMap()) 
                {
                    Invoke(); 
                }
                else
                {
                    WindowsTreeView.SetCheckState(_hwnd, _hItem, GetToggleState() != ToggleState.On); 
                }
            } 
 
            ToggleState IToggleProvider.ToggleState
            { 
                get
                {
                    CheckForElementAvailable();
 
                    return GetToggleState();
                } 
            } 

            #endregion IToggleProvider 

            #region ScrollItem Pattern

            void IScrollItemProvider.ScrollIntoView() 
            {
                CheckForElementAvailable(); 
 
                if (!WindowScroll.IsScrollable(_hwnd))
                { 
                    throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
                }

                Misc.SetFocus(_hwnd); 

                // Currently this ignores the alignToTop, as there is no easy way to set where it 
                // will be in the Treeview, it just makes sure it is visible. 
                Misc.ProxySendMessage(_hwnd, NativeMethods.TVM_ENSUREVISIBLE, IntPtr.Zero, _hItem);
            } 

            #endregion ScrollItem Pattern

            #region Invoke Pattern 
            //Special case handling for vista windows explorer's tree view implementation.
            //when the client calls Invoke method, call DoDefaultAction on its native 
            //IAccessible (this should have been set when GetPatternProviders 
            //is called earlier). Vista Explorer's treeview has its own implementation of DoDefaultAction
            //to display the subfolders and files of the selected folder on the right pane. 
            void IInvokeProvider.Invoke()
            {
                if (_nativeAcc != null)
                { 
                    SetFocus();
                    _nativeAcc.DoDefaultAction(); 
                } 
            }
            #endregion Invoke Pattern 

            // -----------------------------------------------------
            //
            // Internal Methods 
            //
            // ----------------------------------------------------- 
 
            #region Internal Methods
 
            internal void RaiseStructureChangedEvent ()
            {
                StructureChangeType changeType = GetExpandCollapseState() == ExpandCollapseState.Expanded ? StructureChangeType.ChildrenBulkAdded : StructureChangeType.ChildrenBulkRemoved;
                AutomationInteropProvider.RaiseStructureChangedEvent( this, new StructureChangedEventArgs( changeType, GetRuntimeId() ) ); 
            }
 
            internal void RaiseExpandCollapsedStateChangedEvent () 
            {
                AutomationInteropProvider.RaiseAutomationPropertyChangedEvent(this, new AutomationPropertyChangedEventArgs(ExpandCollapsePattern.ExpandCollapseStateProperty, null, GetExpandCollapseState())); 
            }

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

            #region Protected Methods

            // This routine is only called on elements belonging to an hwnd that has the focus. 
            protected override bool IsFocused ()
            { 
                int selected = Misc.ProxySendMessageInt(_hwnd, NativeMethods.TVM_GETITEMSTATE, _hItem, new IntPtr(NativeMethods.TVIS_SELECTED)); 

                return Misc.IsBitSet(selected, NativeMethods.TVIS_SELECTED); 
            }

            #endregion
 
            // ------------------------------------------------------
            // 
            // Private Methods 
            //
            // ------------------------------------------------------ 

            #region Private Methods

            // Go up the hierarchy of parents to make sure that they are all expanded. 
            // If one of the tree view node is not expanded, it means that the element
            // is not visible 
            private void CheckForElementAvailable() 
            {
                TreeViewItem current = this; 
                while ((current = current.GetParent() as TreeViewItem) != null)
                {
                    if (!WindowsTreeView.IsItemExpanded (_hwnd, current._hItem))
                    { 
                        throw new ElementNotAvailableException ();
                    } 
                } 
            }
 
            // Returns the next sibling element in the raw hierarchy.
            // Peripheral controls have always negative values.
            // Returns null if no next child.
            private ProxySimple NextSibling (ProxySimple child) 
            {
                IntPtr hNext = WindowsTreeView.GetNextItem (_hwnd, ((TreeViewItem) child)._hItem); 
 
                return hNext != IntPtr.Zero ? new TreeViewItem(_hwnd, this, hNext, _item + 1) : null;
            } 

            // Returns the previous sibling element in the raw hierarchy.
            // Peripheral controls have always negative values.
            // Returns null is no previous. 
            private ProxySimple PreviousSibling (ProxySimple child)
            { 
                IntPtr hPrev = WindowsTreeView.GetPreviousItem (_hwnd, ((TreeViewItem) child)._hItem); 

                return hPrev != IntPtr.Zero ? new TreeViewItem(_hwnd, this, hPrev, _item + 1) : null; 
            }

            // Returns the first child element in the raw hierarchy.
            private ProxySimple FirstChild () 
            {
                IntPtr hChild = WindowsTreeView.GetFirstChild (_hwnd, _hItem); 
 
                return hChild != IntPtr.Zero ? new TreeViewItem(_hwnd, this, hChild, _item + 1) : null;
            } 

            // Returns the last child element in the raw hierarchy.
            private ProxySimple LastChild ()
            { 
                if (!IsItemExpanded (_hwnd, _hItem))
                { 
                    return null; 
                }
 
                IntPtr hChild = WindowsTreeView.GetFirstChild (_hwnd, _hItem);

                if (hChild != IntPtr.Zero)
                { 
                    // First Child found, now retrieve the last one (no specific msg, need to walk thru all of them)
                    for (IntPtr temp = WindowsTreeView.GetNextItem (_hwnd, hChild); temp != IntPtr.Zero; temp = WindowsTreeView.GetNextItem (_hwnd, hChild)) 
                    { 
                        hChild = temp;
                    } 

                    return new TreeViewItem(_hwnd, this, hChild, _item + 1);
                }
 
                return null;
            } 
 
            // Retrieve state of the treeview item
            private ExpandCollapseState GetExpandCollapseState() 
            {
                bool expanded = WindowsTreeView.IsItemExpanded (_hwnd, _hItem);

                if (expanded) 
                {
                    return ExpandCollapseState.Expanded; 
                } 

                // need to decide between leaf and collapsed 
                bool hasChildren = WindowsTreeView.TreeViewItem_HasChildren (_hwnd, _hItem);

                return (hasChildren) ? ExpandCollapseState.Collapsed : ExpandCollapseState.LeafNode;
            } 

            // get the current state for the tree view item checkbox 
            private ToggleState GetToggleState () 
            {
                WindowsTreeView.CheckState state = WindowsTreeView.CheckState.NoCheckbox; 

                if (HasMSAAImageMap())
                {
                    int image; 
                    uint overlay;
                    uint stateMSAA; 
 
                    if (GetItemImageIndex(out image, out overlay, out stateMSAA))
                    { 
                        if (stateMSAA == 0)
                        {
                            GetStateFromStateImageMap(image, ref stateMSAA);
                        } 

                        state = Misc.IsBitSet((int)stateMSAA, (int)AccessibleState.Checked) ? WindowsTreeView.CheckState.Checked : WindowsTreeView.CheckState.Unchecked; 
                    } 
                }
 
                if (state == WindowsTreeView.CheckState.NoCheckbox)
                {
                    state = (WindowsTreeView.CheckState)WindowsTreeView.GetCheckState(_hwnd, _hItem);
                } 

                switch (state) 
                { 
                    case WindowsTreeView.CheckState.NoCheckbox :
                        { 
                            // we should not call this method on the non-checkboxed treeview items
                            throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
                        }
 
                    case WindowsTreeView.CheckState.Checked :
                        { 
                            return ToggleState.On; 
                        }
 
                    case WindowsTreeView.CheckState.Unchecked :
                        {
                            return ToggleState.Off;
                        } 
                }
 
                // developer defined custom values which cannot be interpret outside of the app's scope 
                return ToggleState.Indeterminate;
            } 

            // Check the checked state of a MSAA treeview radio button item.
            private bool GetCheckState()
            { 
                WindowsTreeView.CheckState state = WindowsTreeView.CheckState.NoCheckbox;
 
                int image; 
                uint overlay;
                uint stateMSAA; 

                if (GetItemImageIndex(out image, out overlay, out stateMSAA))
                {
                    if (stateMSAA == 0) 
                    {
                        GetStateFromStateImageMap(image, ref stateMSAA); 
                    } 

                    state = Misc.IsBitSet((int)stateMSAA, (int)AccessibleState.Checked) ? WindowsTreeView.CheckState.Checked : WindowsTreeView.CheckState.Unchecked; 
                }

                return state == WindowsTreeView.CheckState.Checked;
            } 

            private void Invoke() 
            { 
                // get item rect
                NativeMethods.Win32Rect rectItem = WindowsTreeView.GetItemRect(_hwnd, _hItem, true); 

                if (rectItem.IsEmpty)
                {
                    throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); 
                }
 
                // get control coordinates at which we will "click" 
                NativeMethods.Win32Point pt = new NativeMethods.Win32Point(((rectItem.left + rectItem.right) / 2), ((rectItem.top + rectItem.bottom) / 2));
 
                // convert back to client
                if (Misc.MapWindowPoints(IntPtr.Zero, _hwnd, ref pt, 1))
                {
                    // click 
                    SimulateClick(pt);
                } 
            } 

            private bool IsItemEditable() 
            {
                return Misc.IsBitSet(WindowStyle, NativeMethods.TVS_EDITLABELS);
            }
 
            // detect if given tree view item selected
            private bool IsItemSelected() 
            { 
                int selected = WindowsTreeView.GetItemState(_hwnd, _hItem, NativeMethods.TVIS_SELECTED);
 
                if (Misc.IsBitSet(selected, NativeMethods.TVIS_SELECTED))
                {
                    return true;
                } 

                // Now check to see if this is a MSAA treeview radiobutton item 
                return GetCheckState(); 
            }
 
            // detect if current item has a checkbox associated with it
            private bool IsItemWithCheckbox ()
            {
                bool isCheckbox = Misc.IsBitSet(WindowStyle, NativeMethods.TVS_CHECKBOXES); 

                if (isCheckbox) 
                { 
                    // treeview does support the checkboxes
                    // now we need to make sure that our item supports the checkbox 
                    isCheckbox = WindowsTreeView.CheckState.NoCheckbox != (WindowsTreeView.CheckState)WindowsTreeView.GetCheckState(_hwnd, _hItem);
                }

                if (!isCheckbox) 
                {
                    int image; 
                    uint overlay; 
                    uint state;
 
                    if (GetItemImageIndex(out image, out overlay, out state))
                    {
                        if (overlay == 0)
                        { 
                            GetRoleFromStateImageMap(image, ref overlay);
                        } 
 
                        isCheckbox = (AccessibleRole)overlay == AccessibleRole.CheckButton;
                    } 
                }

                return isCheckbox;
            } 

            //  Return the TreeView Item Text or the Container text (usually hiden text) 
            private string Text 
            {
                get 
                {
                    // this is an item
                    return WindowsTreeView.GetItemText (_hwnd, _hItem);
                } 
            }
 
            // simulate click via posting WM_LBUTTONDOWN(UP) 
            private void SimulateClick(NativeMethods.Win32Point pt)
            { 
                // Fails if a SendMessage is used instead of the Post.
                Misc.PostMessage(_hwnd, NativeMethods.WM_LBUTTONDOWN, IntPtr.Zero, NativeMethods.Util.MAKELPARAM(pt.x, pt.y));
                Misc.PostMessage(_hwnd, NativeMethods.WM_LBUTTONUP, IntPtr.Zero, NativeMethods.Util.MAKELPARAM(pt.x, pt.y));
            } 

            private bool GetItemImageIndex(out int image, out uint overlay, out uint state) 
            { 
                NativeMethods.TVITEM treeItem;
                if (WindowsTreeView.GetItem(_hwnd, _hItem, NativeMethods.TVIF_IMAGE | NativeMethods.TVIF_STATE, out treeItem)) 
                {
                    image = treeItem.iImage;
                    overlay = (treeItem.state >> 8) & 0x0F;
                    state = (treeItem.state >> 12) & 0x0F; 

                    return true; 
                } 

                image = 0; 
                overlay = 0;
                state = 0;

                return false; 
            }
 
 
            private bool GetStateImageMapEnt(int image, ref uint state, ref uint role)
            { 
                // NOTE: This method may have issues with cross proc/cross bitness.

                IntPtr address = UnsafeNativeMethods.GetProp(_hwnd, "MSAAStateImageMapAddr");
                if (address == IntPtr.Zero) 
                {
                    return false; 
                } 

                int numStates = unchecked((int)UnsafeNativeMethods.GetProp(_hwnd, "MSAAStateImageMapCount")); 
                if (numStates == 0)
                {
                    return false;
                } 

                // <= used since number is a 1-based count, iImage is a 0-based index. 
                // If iImage is 0, should be at least one state. 
                if (numStates <= image)
                { 
                    return false;
                }

                using (SafeProcessHandle hProcess = new SafeProcessHandle(_hwnd)) 
                {
                    if (hProcess.IsInvalid) 
                    { 
                        return false;
                    } 

                    MSAASTATEIMAGEMAPENT ent = new MSAASTATEIMAGEMAPENT();
                    int readSize = Marshal.SizeOf(ent.GetType());
                    int count; 

                    // Adjust to image into array... 
                    IntPtr pAddress = new IntPtr((long)address + (image * readSize)); 

                    unsafe 
                    {
                        if (!Misc.ReadProcessMemory(hProcess, pAddress, new IntPtr(&ent), new IntPtr(readSize), out count))
                        {
                            return false; 
                        }
                    } 
 
                    state = (uint)ent.state;
                    role = (uint)ent.role; 
                }
                return true;
            }
 
            private bool GetRoleFromStateImageMap(int image, ref uint role)
            { 
                uint state = unchecked((uint)-1); 
                return GetStateImageMapEnt(image, ref state, ref role);
            } 

            private bool GetStateFromStateImageMap(int image, ref uint state)
            {
                uint role = unchecked((uint)-1); 
                return GetStateImageMapEnt(image, ref state, ref role);
            } 
 
            private bool HasMSAAImageMap()
            { 
                return UnsafeNativeMethods.GetProp(_hwnd, "MSAAStateImageMapAddr") != IntPtr.Zero;
            }

            //Wrapper method to get child id from treeview item. 
            //Similar to OLEACC implementation
            private int ChildIDFromTVItem() 
            { 
                if (_hItem == IntPtr.Zero)
                    return 0; 

                int childId = Misc.ProxySendMessageInt(_hwnd, TVM_MAPHTREEITEMTOACCID, _hItem, IntPtr.Zero);

                if( childId != 0 ) 
                {
                    return childId; 
                } 

            #if WIN64 
                return 0;
            #else
                // Fallback for older 32-bit comctls that don't implement the mapping
                // message 
                return _hItem.ToInt32();
            #endif 
            } 
            #endregion
 
            //-----------------------------------------------------
            //
            //  Private Fields
            // 
            //------------------------------------------------------
 
            #region Private Fields 

            // The HTREEITEM value of the treeview item (internal) 
            internal IntPtr _hItem;

            [StructLayout(LayoutKind.Sequential)]
            private struct MSAASTATEIMAGEMAPENT 
            {
                internal int role; 
                internal int state; 
            }
 
            //native IAccessible interface for TreeViewItem for special handling in
            //Vista Windows Explorer
            private Accessible _nativeAcc;
 
            //Tree view item specific constants.
            private const int TV_FIRST = 0x1100; 
            private const int TVM_MAPHTREEITEMTOACCID = TV_FIRST + 43; 
            #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