Ejemplo n.º 1
0
        private unsafe void WmNotify(ref Message m) {
            NativeMethods.NMHDR* nmhdr = (NativeMethods.NMHDR *)m.LParam;
            
            // Custom draw code is handled separately.
            //
            if ((nmhdr->code ==  NativeMethods.NM_CUSTOMDRAW)) {
                CustomDraw(ref m);
            }
            else {
                
                NativeMethods.NMTREEVIEW* nmtv = (NativeMethods.NMTREEVIEW*)m.LParam;

                switch (nmtv->nmhdr.code) {
                    case NativeMethods.TVN_ITEMEXPANDINGA:
                    case NativeMethods.TVN_ITEMEXPANDINGW:
                        m.Result = TvnExpanding(nmtv);
                        break;
                    case NativeMethods.TVN_ITEMEXPANDEDA:
                    case NativeMethods.TVN_ITEMEXPANDEDW:
                        TvnExpanded(nmtv);
                        break;
                    case NativeMethods.TVN_SELCHANGINGA:
                    case NativeMethods.TVN_SELCHANGINGW:
                        m.Result = TvnSelecting(nmtv);
                        break;
                    case NativeMethods.TVN_SELCHANGEDA:
                    case NativeMethods.TVN_SELCHANGEDW:
                        TvnSelected(nmtv);
                        break;
                    case NativeMethods.TVN_BEGINDRAGA:
                    case NativeMethods.TVN_BEGINDRAGW:
                        TvnBeginDrag(MouseButtons.Left, nmtv);
                        break;
                    case NativeMethods.TVN_BEGINRDRAGA:
                    case NativeMethods.TVN_BEGINRDRAGW:
                        TvnBeginDrag(MouseButtons.Right, nmtv);
                        break;
                    case NativeMethods.TVN_BEGINLABELEDITA:
                    case NativeMethods.TVN_BEGINLABELEDITW:
                        m.Result = TvnBeginLabelEdit((NativeMethods.NMTVDISPINFO)m.GetLParam(typeof(NativeMethods.NMTVDISPINFO)));
                        break;
                    case NativeMethods.TVN_ENDLABELEDITA:
                    case NativeMethods.TVN_ENDLABELEDITW:
                        m.Result = TvnEndLabelEdit((NativeMethods.NMTVDISPINFO)m.GetLParam(typeof(NativeMethods.NMTVDISPINFO)));
                        break;
                    case NativeMethods.NM_CLICK:
                    case NativeMethods.NM_RCLICK:
                        MouseButtons button = MouseButtons.Left;

                        NativeMethods.TV_HITTESTINFO tvhip = new NativeMethods.TV_HITTESTINFO();
                        Point pos = Cursor.Position;
                        pos = PointToClientInternal(pos);
                        tvhip.pt_x = pos.X;
                        tvhip.pt_y = pos.Y;
                        IntPtr hnode = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_HITTEST, 0, tvhip);
                        if (nmtv->nmhdr.code != NativeMethods.NM_CLICK
                                    || (tvhip.flags & NativeMethods.TVHT_ONITEM) != 0) {
                                button = nmtv->nmhdr.code == NativeMethods.NM_CLICK
                                    ? MouseButtons.Left : MouseButtons.Right;
                        }

                        // The treeview's WndProc doesn't get the WM_LBUTTONUP messages when
                        // LBUTTONUP happens on TVHT_ONITEM. This is a comctl quirk.
                        // We work around that by calling OnMouseUp here.
                        if (nmtv->nmhdr.code != NativeMethods.NM_CLICK
                            || (tvhip.flags & NativeMethods.TVHT_ONITEM) != 0 || FullRowSelect) {
                            if (hnode != IntPtr.Zero && !ValidationCancelled) {
                                OnNodeMouseClick(new TreeNodeMouseClickEventArgs(NodeFromHandle(hnode), button, 1, pos.X, pos.Y));
                                OnClick(new MouseEventArgs(button, 1, pos.X, pos.Y, 0));
                                OnMouseClick(new MouseEventArgs(button, 1, pos.X, pos.Y, 0));

                            }
                        }
                        if (nmtv->nmhdr.code == NativeMethods.NM_RCLICK) {
                            TreeNode treeNode = NodeFromHandle(hnode);
                            if (treeNode != null && (treeNode.ContextMenu != null || treeNode.ContextMenuStrip != null)) {
                                ShowContextMenu(treeNode);
                            }
                            else {
                                treeViewState[TREEVIEWSTATE_showTreeViewContextMenu] = true;
                                SendMessage(NativeMethods.WM_CONTEXTMENU, Handle, SafeNativeMethods.GetMessagePos());
                            }
                            m.Result = (IntPtr)1;

                        }

                        if (!treeViewState[TREEVIEWSTATE_mouseUpFired]) {
                            if (nmtv->nmhdr.code != NativeMethods.NM_CLICK
                            || (tvhip.flags & NativeMethods.TVHT_ONITEM) != 0) {
                                // The treeview's WndProc doesn't get the WM_LBUTTONUP messages when
                                // LBUTTONUP happens on TVHT_ONITEM. This is a comctl quirk.
                                // We work around that by calling OnMouseUp here.
                                OnMouseUp(new MouseEventArgs(button, 1, pos.X, pos.Y, 0));
                                treeViewState[TREEVIEWSTATE_mouseUpFired] = true;
                            }

                        }
                        break;
                }
            }
        }
Ejemplo n.º 2
0
        protected override void WndProc(ref Message m) {
            switch (m.Msg) {
                case NativeMethods.WM_WINDOWPOSCHANGING:
                case NativeMethods.WM_NCCALCSIZE:
                case NativeMethods.WM_WINDOWPOSCHANGED:
                case NativeMethods.WM_SIZE:
                    // While we are changing size of treeView to avoid the scrollbar; dont respond to the window-sizing messages.
                    if (treeViewState[TREEVIEWSTATE_stopResizeWindowMsgs])
                    {
                        //Debug.WriteLineIf(treeViewState[TREEVIEWSTATE_stopResizeWindowMsgs], "Sending message directly to DefWndProc() : " + m.ToString());
                        DefWndProc(ref m);
                    }
                    else
                    {
                        base.WndProc(ref m);
                    }
                    break;                        
               case NativeMethods.WM_HSCROLL:
                    base.WndProc(ref m);
                    if (DrawMode == TreeViewDrawMode.OwnerDrawAll)
                    {
                        //VsW : 432718
                        Invalidate();
                    }
                    break;

        case NativeMethods.WM_PRINT:
            WmPrint(ref m);
            break;
                case NativeMethods.TVM_SETITEMA:
                case NativeMethods.TVM_SETITEMW:
                    base.WndProc(ref m);
                    if (this.CheckBoxes) {
                        NativeMethods.TV_ITEM item = (NativeMethods.TV_ITEM) m.GetLParam(typeof(NativeMethods.TV_ITEM));
                        // Check for invalid node handle
                        if (item.hItem != IntPtr.Zero) {
                            NativeMethods.TV_ITEM item1 = new NativeMethods.TV_ITEM();
                            item1.mask = NativeMethods.TVIF_HANDLE | NativeMethods.TVIF_STATE;
                            item1.hItem = item.hItem;
                            item1.stateMask = NativeMethods.TVIS_STATEIMAGEMASK;
                            UnsafeNativeMethods.SendMessage(new HandleRef(null, this.Handle), NativeMethods.TVM_GETITEM, 0, ref item1);

                            TreeNode node = NodeFromHandle(item.hItem);
                            node.CheckedStateInternal = ((item1.state >> 12) > 1);
                        }
                    }
                    break;
                case NativeMethods.WM_NOTIFY:
                    NativeMethods.NMHDR nmhdr = (NativeMethods.NMHDR) m.GetLParam(typeof(NativeMethods.NMHDR));
                    switch (nmhdr.code) {
                        case NativeMethods.TTN_GETDISPINFOA:
                        case NativeMethods.TTN_GETDISPINFOW:
                            // MSDN:
                            // Setting the max width has the added benefit of enabling multiline
                            // tool tips!
                            //
                            UnsafeNativeMethods.SendMessage(new HandleRef(nmhdr, nmhdr.hwndFrom), NativeMethods.TTM_SETMAXTIPWIDTH, 0, SystemInformation.MaxWindowTrackSize.Width);
                            WmNeedText(ref m);
                            m.Result = (IntPtr)1;
                            return;
						case NativeMethods.TTN_SHOW:
                            if (WmShowToolTip(ref m))
                            {
                                m.Result = (IntPtr)1;
                                return;  
                            }
                            else
                            {
                                base.WndProc(ref m);
                                break;
                            }
                            
                        default:
                             base.WndProc(ref m);
                             break;
                    }
                    break;
                case NativeMethods.WM_REFLECT + NativeMethods.WM_NOTIFY:
                        WmNotify(ref m);
                        break;
                case NativeMethods.WM_LBUTTONDBLCLK:
                    WmMouseDown(ref m, MouseButtons.Left, 2);
                    //just maintain state and fire double click.. in final mouseUp...
                    treeViewState[TREEVIEWSTATE_doubleclickFired] = true;
                    //fire Up in the Wndproc !!
                    treeViewState[TREEVIEWSTATE_mouseUpFired] = false;
                    //problem getting the UP... outside the control...
                    //
                    CaptureInternal = true;
                    break;
                case NativeMethods.WM_LBUTTONDOWN:
                    try
                    {
                        treeViewState[TREEVIEWSTATE_ignoreSelects] = true;
                        FocusInternal();
                    }
                    finally
                    {
                       treeViewState[ TREEVIEWSTATE_ignoreSelects] = false;
                    }
                    //Always Reset the MouseupFired....
                    treeViewState[TREEVIEWSTATE_mouseUpFired] = false;
                    NativeMethods.TV_HITTESTINFO tvhip = new NativeMethods.TV_HITTESTINFO();
                    tvhip.pt_x = NativeMethods.Util.SignedLOWORD(m.LParam);
                    tvhip.pt_y = NativeMethods.Util.SignedHIWORD(m.LParam);
                    hNodeMouseDown = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_HITTEST, 0, tvhip);

                    // This gets around the TreeView behavior of temporarily moving the selection
                    // highlight to a node when the user clicks on its checkbox.
                    if ((tvhip.flags & NativeMethods.TVHT_ONITEMSTATEICON) != 0) {
                        //We donot pass the Message to the Control .. so fire MouseDowm ...
                        OnMouseDown(new MouseEventArgs(MouseButtons.Left, 1, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0));
                        if (!ValidationCancelled && CheckBoxes)
                        {
                            TreeNode node = NodeFromHandle(hNodeMouseDown);
                            bool eventReturn = TreeViewBeforeCheck(node, TreeViewAction.ByMouse);
                            if (!eventReturn && node != null) {
                                node.CheckedInternal = !node.CheckedInternal;
                                TreeViewAfterCheck(node, TreeViewAction.ByMouse);
                            }
                        }
                        m.Result = IntPtr.Zero;
                    }
                    else {
                        WmMouseDown(ref m, MouseButtons.Left, 1);
                    }
                    downButton = MouseButtons.Left;
                    break;
                case NativeMethods.WM_LBUTTONUP:
                case NativeMethods.WM_RBUTTONUP:
                    NativeMethods.TV_HITTESTINFO tvhi = new NativeMethods.TV_HITTESTINFO();
                    tvhi.pt_x = NativeMethods.Util.SignedLOWORD(m.LParam);
                    tvhi.pt_y = NativeMethods.Util.SignedHIWORD(m.LParam);
                    IntPtr hnode = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_HITTEST, 0, tvhi);
                    //Important for CheckBoxes ... click needs to be fired ...
                    //
                    if(hnode != IntPtr.Zero) {
                        if (!ValidationCancelled && !treeViewState[TREEVIEWSTATE_doubleclickFired] & !treeViewState[TREEVIEWSTATE_mouseUpFired]) {
                            //OnClick(EventArgs.Empty);

                            //If the hit-tested node here is the same as the node we hit-tested
                            //on mouse down then we will fire our OnNodeMoseClick event.
                            if (hnode == hNodeMouseDown) {
                                OnNodeMouseClick(new TreeNodeMouseClickEventArgs(NodeFromHandle(hnode), downButton, 1, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam)));
                            }
                            
                            OnClick(new MouseEventArgs(downButton, 1, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0));
                            OnMouseClick(new MouseEventArgs(downButton, 1, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0));
                        }

                        if (treeViewState[TREEVIEWSTATE_doubleclickFired]) {
                            treeViewState[TREEVIEWSTATE_doubleclickFired] = false;
                            if (!ValidationCancelled) {
                                 //OnDoubleClick(EventArgs.Empty);
                                 OnNodeMouseDoubleClick(new TreeNodeMouseClickEventArgs(NodeFromHandle(hnode), downButton, 2, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam)));
                                 OnDoubleClick(new MouseEventArgs(downButton, 2, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0));
                                 OnMouseDoubleClick(new MouseEventArgs(downButton, 2, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0));
                            }
                        }
                    }
                    if (!treeViewState[TREEVIEWSTATE_mouseUpFired])
                        OnMouseUp(new MouseEventArgs(downButton, 1, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0));
                    treeViewState[TREEVIEWSTATE_doubleclickFired] = false;
                    treeViewState[TREEVIEWSTATE_mouseUpFired] = false;
                    CaptureInternal = false;

                    //always clear our hit-tested node we cached on mouse down
                    hNodeMouseDown = IntPtr.Zero;
                    break;
                case NativeMethods.WM_MBUTTONDBLCLK:
                    //fire Up in the Wndproc !!
                    treeViewState[TREEVIEWSTATE_mouseUpFired] = false;
                    WmMouseDown(ref m, MouseButtons.Middle, 2);
                    break;
                case NativeMethods.WM_MBUTTONDOWN:
                    //Always Reset the MouseupFired....
                    treeViewState[TREEVIEWSTATE_mouseUpFired] = false;
                    WmMouseDown(ref m, MouseButtons.Middle, 1);
                    downButton = MouseButtons.Middle;
                    break;
                case NativeMethods.WM_MOUSELEAVE:
                    // if the mouse leaves and then reenters the TreeView
                    // NodeHovered events should be raised.
                    prevHoveredNode = null;
                    base.WndProc(ref m);
                    break;
                case NativeMethods.WM_RBUTTONDBLCLK:
                    WmMouseDown(ref m, MouseButtons.Right, 2);
                    //just maintain state and fire double click.. in final mouseUp...
                    treeViewState[TREEVIEWSTATE_doubleclickFired] = true;
                    //fire Up in the Wndproc !!
                    treeViewState[TREEVIEWSTATE_mouseUpFired] = false;
                    //problem getting the UP... outside the control...
                    //
                    CaptureInternal = true;
                    break;
                case NativeMethods.WM_RBUTTONDOWN:
                    //Always Reset the MouseupFired....
                    treeViewState[TREEVIEWSTATE_mouseUpFired] = false;
                    //Cache the hit-tested node for verification when mouse up is fired
                    NativeMethods.TV_HITTESTINFO tvhit = new NativeMethods.TV_HITTESTINFO();
                    tvhit.pt_x = NativeMethods.Util.SignedLOWORD(m.LParam);
                    tvhit.pt_y = NativeMethods.Util.SignedHIWORD(m.LParam);
                    hNodeMouseDown = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_HITTEST, 0, tvhit);
                    
                    WmMouseDown(ref m, MouseButtons.Right, 1);
                    downButton = MouseButtons.Right;
                    break;
                    //# VS7 15052
                case NativeMethods.WM_SYSCOLORCHANGE:
                    SendMessage(NativeMethods.TVM_SETINDENT, Indent, 0);
                    base.WndProc(ref m);
                    break;
                case NativeMethods.WM_SETFOCUS:
                     // If we get focus through the LBUttonDown .. we might have done the validation...
                     // so skip it..
                     if (treeViewState[TREEVIEWSTATE_lastControlValidated])
                     {
                        treeViewState[TREEVIEWSTATE_lastControlValidated] = false;
                        WmImeSetFocus();
                        DefWndProc(ref m);
                        OnGotFocus(EventArgs.Empty);
                     }
                     else 
                     {
                        base.WndProc(ref m);
                     }
                     break;
                case NativeMethods.WM_CONTEXTMENU:
                    if (treeViewState[TREEVIEWSTATE_showTreeViewContextMenu]) {
                        treeViewState[TREEVIEWSTATE_showTreeViewContextMenu] = false;
                        base.WndProc(ref m);
                    }
                    else {
                        // this is the Shift + F10 Case....
                        TreeNode treeNode = SelectedNode;
                        if (treeNode != null && (treeNode.ContextMenu != null || treeNode.ContextMenuStrip !=null)) {
                            Point client;
                            client = new Point(treeNode.Bounds.X , treeNode.Bounds.Y + treeNode.Bounds.Height / 2);
                            // VisualStudio7 # 156, only show the context menu when clicked in the client area
                            if (ClientRectangle.Contains( client )) {
                                if (treeNode.ContextMenu != null) {
                                    treeNode.ContextMenu.Show(this, client);
                                }
                                else if (treeNode.ContextMenuStrip !=null) {
                                    bool keyboardActivated =  (unchecked((int)(long)m.LParam) == -1);
                                    treeNode.ContextMenuStrip.ShowInternal(this, client, keyboardActivated);
                                }
                            }
                        }
                        else {
                            // in this case we dont have a selected node.  The base
                            // will ensure we're constrained to the client area.
                            base.WndProc (ref m);
                        }
                    }
                    break;


                default:
                    base.WndProc(ref m);
                    break;
            }
        }
Ejemplo n.º 3
0
        /// <include file='doc\TreeView.uex' path='docs/doc[@for="TreeView.WmNeedText"]/*' />
        /// <devdoc>
        /// </devdoc>
        /// <internalonly/>
        private void WmNeedText(ref Message m) {
            NativeMethods.TOOLTIPTEXT ttt = (NativeMethods.TOOLTIPTEXT) m.GetLParam(typeof(NativeMethods.TOOLTIPTEXT));
            string tipText = controlToolTipText;
            
            NativeMethods.TV_HITTESTINFO tvhip = new NativeMethods.TV_HITTESTINFO();
            Point pos = Cursor.Position;
            pos = PointToClientInternal(pos);
            tvhip.pt_x = pos.X;
            tvhip.pt_y = pos.Y;
            IntPtr hnode = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_HITTEST, 0, tvhip);
            if (hnode != IntPtr.Zero && ((tvhip.flags & NativeMethods.TVHT_ONITEM) != 0)) {
                TreeNode tn = NodeFromHandle(hnode);
                if (ShowNodeToolTips && tn != null && (!string.IsNullOrEmpty(tn.ToolTipText))) {
                    tipText = tn.ToolTipText;
                }
                else if (tn != null && tn.Bounds.Right > this.Bounds.Right) {
                    tipText = tn.Text;
                }
                else {
                    tipText = null;
                }
            }
            ttt.lpszText = tipText;
            ttt.hinst = IntPtr.Zero;

            // RightToLeft reading order
            //
            if (RightToLeft == RightToLeft.Yes) {
                ttt.uFlags |= NativeMethods.TTF_RTLREADING;
            }
            Marshal.StructureToPtr(ttt, m.LParam, false);
        }
Ejemplo n.º 4
0
        private unsafe bool WmShowToolTip(ref Message m)
        {
            NativeMethods.NMHDR* nmhdr = (NativeMethods.NMHDR*)m.LParam;
            IntPtr tooltipHandle = nmhdr->hwndFrom;
            
                
            NativeMethods.TV_HITTESTINFO tvhip = new NativeMethods.TV_HITTESTINFO();
            Point pos = Cursor.Position;
            pos = PointToClientInternal(pos);
            tvhip.pt_x = pos.X;
            tvhip.pt_y = pos.Y;
            IntPtr hnode = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_HITTEST, 0, tvhip);

            if (hnode != IntPtr.Zero && ((tvhip.flags & NativeMethods.TVHT_ONITEM) != 0)) {

                TreeNode tn = NodeFromHandle(hnode);
                if (tn != null) 
                {
                    if (!ShowNodeToolTips) // default ToolTips
                    {
                        Rectangle bounds = tn.Bounds;
                        bounds.Location = this.PointToScreen(bounds.Location);

                        UnsafeNativeMethods.SendMessage(new HandleRef(this, tooltipHandle), NativeMethods.TTM_ADJUSTRECT, 1, ref bounds);
                        SafeNativeMethods.SetWindowPos(new HandleRef(this, tooltipHandle),
                                NativeMethods.HWND_TOPMOST, bounds.Left, bounds.Top, 0, 0, NativeMethods.SWP_NOACTIVATE | NativeMethods.SWP_NOSIZE | NativeMethods.SWP_NOZORDER);
                        return true;
                    }
                }
            }
            return false;
        }
Ejemplo n.º 5
0
        /// <include file='doc\TreeView.uex' path='docs/doc[@for="TreeView.OnMouseHover"]/*' />
        /// <devdoc>
        ///     In order for the MouseHover event to fire for each item in a TreeView,
        ///     the node the mouse is hovering over is found. Each time a new node is hovered
        ///     over a new event is raised.
        /// </devdoc>
        protected override void OnMouseHover(EventArgs e)  {

            /// Hover events need to be caught for each node
            /// within the TreeView so the appropriate
            /// NodeHovered event can be raised.

            NativeMethods.TV_HITTESTINFO tvhip = new NativeMethods.TV_HITTESTINFO();
            Point pos = Cursor.Position;
            pos = PointToClientInternal(pos);
            tvhip.pt_x = pos.X;
            tvhip.pt_y = pos.Y;
            IntPtr hnode = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_HITTEST, 0, tvhip);

            if (hnode != IntPtr.Zero && ((tvhip.flags & NativeMethods.TVHT_ONITEM) != 0)) {
                TreeNode tn = NodeFromHandle(hnode);
                if (tn != prevHoveredNode && tn != null) {
                    OnNodeMouseHover( new TreeNodeMouseHoverEventArgs(tn));
                    prevHoveredNode = tn;
                }
            }

            if (!hoveredAlready) {
                base.OnMouseHover(e);
                hoveredAlready = true;
            }

            ResetMouseEventArgs();

        }
Ejemplo n.º 6
0
        /// <include file='doc\TreeView.uex' path='docs/doc[@for="TreeView.GetNodeAt1"]/*' />
        /// <devdoc>
        ///     Returns the TreeNode at the given location in tree view coordinates.
        /// </devdoc>
        public TreeNode GetNodeAt(int x, int y) {
            NativeMethods.TV_HITTESTINFO tvhi = new NativeMethods.TV_HITTESTINFO();

            tvhi.pt_x = x;
            tvhi.pt_y = y;

            IntPtr hnode = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_HITTEST, 0, tvhi);

            return(hnode == IntPtr.Zero ? null : NodeFromHandle(hnode));
        }
Ejemplo n.º 7
0
 /// <include file='doc\TreeView.uex' path='docs/doc[@for="TreeView.HitTest"]/*' />
 /// <devdoc>
 ///     Gives the information about which part of the treeNode is at the given x, y.
 /// </devdoc>
 public TreeViewHitTestInfo HitTest(int x, int y) {
     NativeMethods.TV_HITTESTINFO tvhi = new NativeMethods.TV_HITTESTINFO();
     tvhi.pt_x = x;
     tvhi.pt_y = y;
     IntPtr hnode = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_HITTEST, 0, tvhi);
     TreeNode node = (hnode == IntPtr.Zero ? null : NodeFromHandle(hnode));
     TreeViewHitTestLocations loc = (TreeViewHitTestLocations)tvhi.flags;
     return (new TreeViewHitTestInfo(node, loc));
 }