ToolTip.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / fx / src / WinForms / Managed / System / WinForms / ToolTip.cs / 4 / ToolTip.cs

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

/* 
 */ 
namespace System.Windows.Forms {
    using System.Runtime.Serialization.Formatters; 
    using System.Threading;
    using System.Runtime.Remoting;
    using System.Runtime.InteropServices;
    using System.ComponentModel; 
    using System.ComponentModel.Design;
    using System.Diagnostics; 
    using System; 
    using System.Windows.Forms;
    using System.Windows.Forms.Design; 
    using Hashtable = System.Collections.Hashtable;
    using System.Drawing;
    using Microsoft.Win32;
    using System.Security; 
    using System.Security.Permissions;
    using System.Text; 
    using System.Drawing.Design; 
    using System.Globalization;
 
    /// 
    /// 
    ///    
    ///       Provides a small pop-up window containing a line of text 
    ///       that describes the purpose of a tool or control (usually represented as a
    ///       graphical 
    ///       object) in a program. 
    ///    
    ///  
    [
    ProvideProperty("ToolTip", typeof(Control)),
    DefaultEvent("Popup"),
    ToolboxItemFilter("System.Windows.Forms"), 
    SRDescription(SR.DescriptionToolTip)
    ] 
    public class ToolTip : Component, IExtenderProvider { 

        const int DEFAULT_DELAY = 500; 
        const int RESHOW_RATIO = 5;
        const int AUTOPOP_RATIO = 10;

        const int XBALLOONOFFSET = 10; 
        const int YBALLOONOFFSET = 8;
 
        Hashtable           tools = new Hashtable(); 
        int[]               delayTimes = new int[4];
        bool                auto = true; 
        bool                showAlways = false;
        ToolTipNativeWindow window = null;
        Control             topLevelControl = null;
        bool                active = true; 
        bool                ownerDraw = false;
        object              userData; 
        Color               backColor = SystemColors.Info; 
        Color               foreColor = SystemColors.InfoText;
        bool                isBalloon; 
        bool                isDisposing;
        string              toolTipTitle = string.Empty;
        ToolTipIcon         toolTipIcon = (ToolTipIcon)0;
        ToolTipTimer        timer; 
        Hashtable           owners = new Hashtable();
        bool                stripAmpersands = false; 
        bool                useAnimation = true; 
        bool                useFading = true;
        int                 originalPopupDelay = 0; 

        // setting TTM_TRACKPOSITION will cause redundant POP and Draw Messages..
        // Hence we gaurd against this by having this private Flag..
        bool                trackPosition = false; 

        PopupEventHandler onPopup; 
        DrawToolTipEventHandler onDraw; 

        // Adding a tool twice breaks the ToolTip, so we need to track which 
        // tools are created to prevent this...
        //
        Hashtable           created = new Hashtable();
 
        private bool cancelled = false;
 
        ///  
        /// 
        ///     
        ///       Initializes a new instance of the  class, given the container.
        ///    
        /// 
        public ToolTip(IContainer cont) : this() { 
            cont.Add(this);
        } 
 
        /// 
        ///  
        ///    
        ///       Initializes a new instance of the  class in its default state.
        ///    
        ///  
        public ToolTip() {
            window = new ToolTipNativeWindow(this); 
            auto = true; 
            delayTimes[NativeMethods.TTDT_AUTOMATIC] = DEFAULT_DELAY;
            AdjustBaseFromAuto(); 
        }

        /// 
        ///  
        ///    
        ///       Gets or sets a value indicating whether the  control is currently active. 
        ///     
        /// 
        [ 
        SRDescription(SR.ToolTipActiveDescr),
        DefaultValue(true)
        ]
        public bool Active { 
            get {
                return active; 
            } 

            set { 
                if (active != value) {
                    active = value;

                    //lets not actually activate the tooltip if we're in the designer (just set the value) 
                    if (!DesignMode && GetHandleCreated()) {
                        UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TTM_ACTIVATE, (value==true)? 1: 0, 0); 
                    } 
                }
            } 
        }

        /// 
        ///  
        ///    
        ///       Gets or sets 
        ///       the time (in milliseconds) that passes before the  appears. 
        ///    
        ///  
        [
        RefreshProperties(RefreshProperties.All),
        SRDescription(SR.ToolTipAutomaticDelayDescr),
        DefaultValue(DEFAULT_DELAY) 
        ]
        public int AutomaticDelay { 
            get { 
                return delayTimes[NativeMethods.TTDT_AUTOMATIC];
            } 

            set {
                if (value < 0) {
                    throw new ArgumentOutOfRangeException("AutomaticDelay", SR.GetString(SR.InvalidLowBoundArgumentEx, "AutomaticDelay", (value).ToString(CultureInfo.CurrentCulture), (0).ToString(CultureInfo.CurrentCulture))); 
                }
                SetDelayTime(NativeMethods.TTDT_AUTOMATIC, value); 
            } 
        }
 
        /// 
        /// 
        ///    
        ///       Gets or sets the initial delay for the  control. 
        ///    
        ///  
        [ 
        RefreshProperties(RefreshProperties.All),
        SRDescription(SR.ToolTipAutoPopDelayDescr) 
        ]
        public int AutoPopDelay {
            get {
                return delayTimes[NativeMethods.TTDT_AUTOPOP]; 
            }
 
            set { 
                if (value < 0) {
                    throw new ArgumentOutOfRangeException("AutoPopDelay", SR.GetString(SR.InvalidLowBoundArgumentEx, "AutoPopDelay", (value).ToString(CultureInfo.CurrentCulture), (0).ToString(CultureInfo.CurrentCulture))); 
                }
                SetDelayTime(NativeMethods.TTDT_AUTOPOP, value);
            }
        } 

        ///  
        ///  
        ///    
        ///       Gets or sets the BackColor for the  control. 
        ///    
        /// 
        [
        SRDescription(SR.ToolTipBackColorDescr), 
        DefaultValue(typeof(Color),"Info")
        ] 
        public Color BackColor { 
            get {
                return backColor; 
            }

            set {
                backColor = value; 
                if (GetHandleCreated()) {
                    UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TTM_SETTIPBKCOLOR, ColorTranslator.ToWin32(backColor), 0); 
                } 
            }
        } 

        /// 
        /// 
        ///     The createParams to create the window. 
        /// 
        ///  
        protected virtual CreateParams CreateParams { 
            [
                SecurityPermission(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.UnmanagedCode), 
                SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)
            ]
            get {
                CreateParams cp = new CreateParams(); 
                if (TopLevelControl != null) {
                    cp.Parent = TopLevelControl.Handle; 
                } 
                cp.ClassName = NativeMethods.TOOLTIPS_CLASS;
                if (showAlways) { 
                    cp.Style = NativeMethods.TTS_ALWAYSTIP;
                }
                if (isBalloon) {
                    cp.Style |= NativeMethods.TTS_BALLOON; 
                }
                if (!stripAmpersands) { 
                    cp.Style |= NativeMethods.TTS_NOPREFIX; 
                }
                if (!useAnimation) { 
                    cp.Style |= NativeMethods.TTS_NOANIMATE;
                }
                if (!useFading) {
                    cp.Style |= NativeMethods.TTS_NOFADE; 
                }
                cp.ExStyle = 0; 
                cp.Caption = null; 

                return cp; 
            }
        }

        ///  
        /// 
        ///     
        ///       Gets or sets the ForeColor for the  control. 
        ///    
        ///  
        [
        SRDescription(SR.ToolTipForeColorDescr),
        DefaultValue(typeof(Color),"InfoText")
        ] 
        public Color ForeColor {
            get { 
                return foreColor; 
            }
 
            set {
                if (value.IsEmpty) {
                    throw new ArgumentException(SR.GetString(SR.ToolTipEmptyColor, "ForeColor"));
                } 

                foreColor = value; 
                if (GetHandleCreated()) { 
                    UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TTM_SETTIPTEXTCOLOR, ColorTranslator.ToWin32(foreColor), 0);
                } 

            }
        }
 
        internal IntPtr Handle {
            get { 
                if (!GetHandleCreated()) { 
                    CreateHandle();
                } 
                return window.Handle;
            }
        }
 
        /// 
        ///    SECREVIEW: Pattern to check if the caller has a permission without bubbling up a security exception 
        ///  
        private bool HasAllWindowsPermission {
            get { 
                try {
                    IntSecurity.AllWindows.Demand();
                    return true;
                } 
                catch (SecurityException) {
                } 
 
                return false;
            } 
        }

        /// 
        ///  
        ///    
        ///       Gets or sets the IsBalloon for the  control. 
        ///     
        /// 
        [ 
        SRDescription(SR.ToolTipIsBalloonDescr),
        DefaultValue(false)
        ]
        public bool IsBalloon { 
            get {
                return isBalloon; 
            } 

            set { 
                if (isBalloon != value) {
                    isBalloon = value;
                    if (GetHandleCreated()) {
                        RecreateHandle(); 
                    }
                } 
 
            }
        } 

        // refer VsWhidbey 498263: ToolTips should be shown only on active Windows.
        private bool IsWindowActive(IWin32Window window)
        { 
            Control windowControl = window as Control;
            // We want to enter in the IF block only if ShowParams does not return SW_SHOWNOACTIVATE. 
            // for ToolStripDropDown ShowParams returns SW_SHOWNOACTIVATE, in which case we DONT want to check IsWindowActive and hence return true. 
            if ((windowControl.ShowParams & 0xF) != NativeMethods.SW_SHOWNOACTIVATE)
            { 
                IntPtr hWnd = UnsafeNativeMethods.GetActiveWindow();
                IntPtr rootHwnd =UnsafeNativeMethods.GetAncestor(new HandleRef(window, window.Handle), NativeMethods.GA_ROOT);
                if (hWnd != rootHwnd)
                { 
                    TipInfo tt = (TipInfo)tools[windowControl];
                    if (tt != null && (tt.TipType & TipInfo.Type.SemiAbsolute) != 0) 
                    { 
                        tools.Remove(windowControl);
                        DestroyRegion(windowControl); 
                    }
                    return false;
                }
            } 
            return true;
        } 
 
        /// 
        ///  
        ///    
        ///       Gets or sets the initial delay for
        ///       the 
        ///       control. 
        ///    
        ///  
        [ 
        RefreshProperties(RefreshProperties.All),
        SRDescription(SR.ToolTipInitialDelayDescr) 
        ]
        public int InitialDelay {
            get {
                return delayTimes[NativeMethods.TTDT_INITIAL]; 
            }
 
            set { 
                if (value < 0) {
                    throw new ArgumentOutOfRangeException("InitialDelay", SR.GetString(SR.InvalidLowBoundArgumentEx, "InitialDelay", (value).ToString(CultureInfo.CurrentCulture), (0).ToString(CultureInfo.CurrentCulture))); 
                }
                SetDelayTime(NativeMethods.TTDT_INITIAL, value);
            }
        } 

        ///  
        ///  
        /// Indicates whether the ToolTip will be drawn by the system or the user.
        ///  
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(false),
        SRDescription(SR.ToolTipOwnerDrawDescr) 
        ]
        public bool OwnerDraw 
        { 
            get
            { 
                return ownerDraw;
            }
            [UIPermission(SecurityAction.Demand, Window=UIPermissionWindow.AllWindows)]
            set 
            {
                ownerDraw = value; 
            } 
        }
 
        /// 
        /// 
        ///    
        ///       Gets or sets the length of time (in milliseconds) that 
        ///       it takes subsequent ToolTip instances to appear as the mouse pointer moves from
        ///       one ToolTip region to 
        ///       another. 
        ///    
        ///  
        [
        RefreshProperties(RefreshProperties.All),
        SRDescription(SR.ToolTipReshowDelayDescr)
        ] 
        public int ReshowDelay {
            get { 
                return delayTimes[NativeMethods.TTDT_RESHOW]; 
            }
            set { 
                if (value < 0) {
                    throw new ArgumentOutOfRangeException("ReshowDelay", SR.GetString(SR.InvalidLowBoundArgumentEx, "ReshowDelay", (value).ToString(CultureInfo.CurrentCulture), (0).ToString(CultureInfo.CurrentCulture)));
                }
                SetDelayTime(NativeMethods.TTDT_RESHOW, value); 
            }
        } 
 
        /// 
        ///  
        ///    
        ///       Gets or sets a value indicating whether the 
        ///       appears even when its parent control is not active.
        ///     
        /// 
        [ 
        DefaultValue(false), 
        SRDescription(SR.ToolTipShowAlwaysDescr)
        ] 
        public bool ShowAlways {
            get {
                return showAlways;
            } 
            set {
                if (showAlways != value) { 
                    showAlways = value; 
                    if (GetHandleCreated()) {
                        RecreateHandle(); 
                    }
                }
            }
        } 

 
        ///  
        /// 
        ///     
        ///       When set to true, any ampersands in the Text property are not displayed.
        ///    
        /// 
        [ 
        SRDescription(SR.ToolTipStripAmpersandsDescr),
        Browsable(true), 
        DefaultValue(false) 
        ]
        public bool StripAmpersands { 
            get {
                return stripAmpersands;
            }
            set { 
                if (stripAmpersands != value) {
                    stripAmpersands = value; 
                    if (GetHandleCreated()) { 
                        RecreateHandle();
                    } 
                }
            }
        }
 
        /// 
        [ 
        SRCategory(SR.CatData), 
        Localizable(false),
        Bindable(true), 
        SRDescription(SR.ControlTagDescr),
        DefaultValue(null),
        TypeConverter(typeof(StringConverter)),
        ] 
        public object Tag {
            get { 
                return userData; 
            }
            set { 
                userData = value;
            }
        }
 
        /// 
        ///  
        ///     
        ///       Gets or sets an Icon on the ToolTip.
        ///     
        /// 
        [
        DefaultValue(ToolTipIcon.None),
        SRDescription(SR.ToolTipToolTipIconDescr) 
        ]
        public ToolTipIcon ToolTipIcon { 
            get { 
                return toolTipIcon;
            } 
            set {
                if (toolTipIcon != value) {
                    //valid values are 0x0 to 0x3
                    if (!ClientUtils.IsEnumValid(value, (int)value, (int)ToolTipIcon.None, (int)ToolTipIcon.Error)) 
                    {
                        throw new InvalidEnumArgumentException("value", (int)value, typeof(ToolTipIcon)); 
                    } 
                    toolTipIcon = value;
                    if (toolTipIcon > 0 && GetHandleCreated()) { 
                        // If the title is null/empty, the icon won't display.
                        string title = !String.IsNullOrEmpty(toolTipTitle) ? toolTipTitle : " ";
                        UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TTM_SETTITLE, (int)toolTipIcon, title);
 
                        // Tooltip need to be updated to reflect the changes in the icon because
                        // this operation directly affects the size of the tooltip 
                        UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TTM_UPDATE, 0, 0); 

                    } 
                }
            }
        }
 

        ///  
        ///     
        ///       Gets or sets the title of the ToolTip.
        ///     
        /// 
        [
        DefaultValue(""),
        SRDescription(SR.ToolTipTitleDescr) 
        ]
        public string ToolTipTitle 
        { 
            get
            { 
                return toolTipTitle;
            }
            set
            { 
                if (value == null)
                { 
                    value = string.Empty; 
                }
 
                if (toolTipTitle != value)
                {
                    toolTipTitle = value;
                    if (GetHandleCreated()) 
                    {
                        UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TTM_SETTITLE, (int)toolTipIcon, toolTipTitle); 
 
                        // Tooltip need to be updated to reflect the changes in the titletext because
                        // this operation directly affects the size of the tooltip 
                        UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TTM_UPDATE, 0, 0);
                    }
                }
            } 
        }
 
        private Control TopLevelControl { 
            get {
                Control baseVar = null; 
                if (topLevelControl == null) {
                    Control[] regions = new Control[tools.Keys.Count];
                    tools.Keys.CopyTo(regions, 0);
                    if (regions != null && regions.Length > 0) { 
                        for (int i=0; i 
        /// 
        ///     
        ///       When set to true, animations are used when tooltip is shown or hidden. 
        ///    
        ///  
        [
        SRDescription(SR.ToolTipUseAnimationDescr),
        Browsable(true),
        DefaultValue(true) 
        ]
        public bool UseAnimation { 
            get { 
                return useAnimation;
            } 
            set {
                if (useAnimation != value) {
                    useAnimation = value;
                    if (GetHandleCreated()) { 
                        RecreateHandle();
                    } 
                } 
            }
        } 


        /// 
        ///  
        ///    
        ///       When set to true, a fade effect is used when tooltips are shown or hidden. 
        ///     
        /// 
        [ 
        SRDescription(SR.ToolTipUseFadingDescr),
        Browsable(true),
        DefaultValue(true)
        ] 
        public bool UseFading {
            get { 
                return useFading; 
            }
            set { 
                if (useFading != value) {
                    useFading = value;
                    if (GetHandleCreated()) {
                        RecreateHandle(); 
                    }
                } 
            } 
        }
 
        /// 
        /// 
        ///    Fires in OwnerDraw mode when the tooltip needs to be drawn.
        ///  
        [SRCategory(SR.CatBehavior),SRDescription(SR.ToolTipDrawEventDescr)]
        public event DrawToolTipEventHandler Draw 
        { 
            add
            { 
                onDraw += value;
            }
            remove
            { 
                onDraw -= value;
            } 
        } 

        ///  
        /// 
        ///    Fires when the tooltip is just about to be shown.
        /// 
        [SRCategory(SR.CatBehavior),SRDescription(SR.ToolTipPopupEventDescr)] 
        public event PopupEventHandler Popup
        { 
            add 
            {
                onPopup += value; 
            }
            remove
            {
                onPopup -= value; 
            }
        } 
 

        ///  
        /// 
        ///     Adjusts the other delay values based on the Automatic value.
        /// 
        ///  
        private void AdjustBaseFromAuto() {
            delayTimes[NativeMethods.TTDT_RESHOW] = delayTimes[NativeMethods.TTDT_AUTOMATIC] / RESHOW_RATIO; 
            delayTimes[NativeMethods.TTDT_AUTOPOP] = delayTimes[NativeMethods.TTDT_AUTOMATIC] * AUTOPOP_RATIO; 
            delayTimes[NativeMethods.TTDT_INITIAL] = delayTimes[NativeMethods.TTDT_AUTOMATIC];
        } 

        private void HandleCreated(object sender, EventArgs eventargs) {
            // Reset the toplevel control when the owner's handle is recreated.
            ClearTopLevelControlEvents(); 
            topLevelControl = null;
            CreateRegion((Control)sender); 
            CheckNativeToolTip((Control)sender); 
            CheckCompositeControls((Control)sender);
        } 

        private void CheckNativeToolTip(Control associatedControl) {

            //Wait for the Handle Creation.. 
            if (!GetHandleCreated()) {
                return; 
            } 

            TreeView treeView = associatedControl as TreeView; 
            if (treeView != null) {
                if (treeView.ShowNodeToolTips) {
                    treeView.SetToolTip(this,GetToolTip(associatedControl));
                } 
            }
 
            if (associatedControl is ToolBar) { 
               ((ToolBar)associatedControl).SetToolTip(this);
            } 

            TabControl tabControl = associatedControl as TabControl;
            if (tabControl!= null) {
                if (tabControl.ShowToolTips) 
                {
                    tabControl.SetToolTip(this, GetToolTip(associatedControl)); 
                } 
            }
 
            if (associatedControl is ListView) {
               ((ListView)associatedControl).SetToolTip(this, GetToolTip(associatedControl));
            }
 
            if (associatedControl is StatusBar) {
                ((StatusBar)associatedControl).SetToolTip(this); 
            } 

            // Label now has its own Tooltip for AutoEllipsis... 
            // So this control too falls in special casing...
            // We need to disable the LABEL AutoEllipsis tooltip and show
            // this tooltip always...
            if (associatedControl is Label) { 
                ((Label)associatedControl).SetToolTip(this);
            } 
 

        } 

        private void CheckCompositeControls(Control associatedControl) {
            if (associatedControl is UpDownBase) {
                ((UpDownBase)associatedControl).SetToolTip(this, GetToolTip(associatedControl)); 
            }
        } 
 
        private void HandleDestroyed(object sender, EventArgs eventargs) {
            DestroyRegion((Control)sender); 

        }

        ///  
        /// 
        /// Fires the Draw event. 
        ///  
        private void OnDraw(DrawToolTipEventArgs e)
        { 
            if(onDraw != null)
            {
                onDraw(this,e);
            } 
        }
 
 
        /// 
        ///  
        /// Fires the Popup event.
        /// 
        private void OnPopup(PopupEventArgs e)
        { 
            if(onPopup != null)
            { 
                onPopup(this,e); 
            }
        } 

        private void TopLevelCreated(object sender, EventArgs eventargs) {
            CreateHandle();
            CreateAllRegions(); 
        }
 
        private void TopLevelDestroyed(object sender, EventArgs eventargs) { 
            DestoyAllRegions();
            DestroyHandle(); 
        }

        /// 
        ///  
        ///    Returns true if the tooltip can offer an extender property to the
        ///    specified target component. 
        ///  
        /// 
        public bool CanExtend(object target) { 
            if (target is Control &&
                !(target is ToolTip)) {

                return true; 
            }
            return false; 
        } 

        private void ClearTopLevelControlEvents() { 

            if (this.topLevelControl != null) {
                this.topLevelControl.ParentChanged -= new EventHandler(this.OnTopLevelPropertyChanged);
                this.topLevelControl.HandleCreated -= new EventHandler(this.TopLevelCreated); 
                this.topLevelControl.HandleDestroyed -= new EventHandler(this.TopLevelDestroyed);
            } 
        } 

        ///  
        /// 
        ///     Creates the handle for the control.
        /// 
        ///  
        private void CreateHandle() {
            if (GetHandleCreated()) { 
                return; 
            }
            IntPtr userCookie = UnsafeNativeMethods.ThemingScope.Activate(); 

            try {

                NativeMethods.INITCOMMONCONTROLSEX icc = new NativeMethods.INITCOMMONCONTROLSEX(); 
                icc.dwICC = NativeMethods.ICC_TAB_CLASSES;
                SafeNativeMethods.InitCommonControlsEx(icc); 
 
                CreateParams cp = CreateParams; // Avoid reentrant call to CreateHandle (VSWhidbey 570764)
                if (GetHandleCreated()) { 
                    return;
                }
                window.CreateHandle(cp);
            } 
            finally {
                UnsafeNativeMethods.ThemingScope.Deactivate(userCookie); 
            } 

            // If in ownerDraw mode, we don't want the default border. 
            if (ownerDraw) {
                int style = unchecked((int)((long)UnsafeNativeMethods.GetWindowLong(new HandleRef(this, Handle), NativeMethods.GWL_STYLE)));
                style &= ~NativeMethods.WS_BORDER;
                UnsafeNativeMethods.SetWindowLong(new HandleRef(this, Handle), NativeMethods.GWL_STYLE, new HandleRef(null, (IntPtr)style)); 
            }
 
            // Setting the max width has the added benefit of enabling multiline 
            // tool tips!
            // 
            UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TTM_SETMAXTIPWIDTH, 0, SystemInformation.MaxWindowTrackSize.Width);

            Debug.Assert(NativeMethods.TTDT_AUTOMATIC == 0, "TTDT_AUTOMATIC != 0");
 
            if (auto) {
                SetDelayTime(NativeMethods.TTDT_AUTOMATIC, delayTimes[NativeMethods.TTDT_AUTOMATIC]); 
                delayTimes[NativeMethods.TTDT_AUTOPOP] = GetDelayTime(NativeMethods.TTDT_AUTOPOP); 
                delayTimes[NativeMethods.TTDT_INITIAL] = GetDelayTime(NativeMethods.TTDT_INITIAL);
                delayTimes[NativeMethods.TTDT_RESHOW] = GetDelayTime(NativeMethods.TTDT_RESHOW); 
            }
            else {
                for (int i=1; i < delayTimes.Length; i++) {
                    if (delayTimes[i] >= 1) { 
                        SetDelayTime(i, delayTimes[i]);
                    } 
                } 
            }
 
            // Set active status
            //
            UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TTM_ACTIVATE, (active == true) ? 1 : 0, 0);
 
            if (BackColor != SystemColors.Info) {
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TTM_SETTIPBKCOLOR, ColorTranslator.ToWin32(BackColor), 0); 
            } 
            if (ForeColor != SystemColors.ControlText) {
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TTM_SETTIPTEXTCOLOR, ColorTranslator.ToWin32(ForeColor), 0); 
            }
            if (toolTipIcon > 0 || !String.IsNullOrEmpty(toolTipTitle)) {
                // If the title is null/empty, the icon won't display.
                string title = !String.IsNullOrEmpty(toolTipTitle) ? toolTipTitle : " "; 
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TTM_SETTITLE, (int)toolTipIcon, title);
            } 
        } 

        private void CreateAllRegions() { 
            Control[] ctls = new Control[tools.Keys.Count];
            tools.Keys.CopyTo(ctls, 0);
            for (int i=0; i 0;
            bool handlesCreated = ctl.IsHandleCreated
                                  && TopLevelControl != null 
                                  && TopLevelControl.IsHandleCreated;
            if (!created.ContainsKey(ctl) && captionValid 
                && handlesCreated && !DesignMode) { 

                //Call the Sendmessage thru a function.. 
                SetToolInfo(ctl, caption);
                created[ctl] = ctl;
            }
            if (ctl.IsHandleCreated && topLevelControl == null) { 
                // Remove first to purge any duplicates...
                // 
                ctl.MouseMove -= new MouseEventHandler(this.MouseMove); 
                ctl.MouseMove += new MouseEventHandler(this.MouseMove);
            } 
        }

        private void MouseMove(object sender, MouseEventArgs me) {
            Control ctl = (Control)sender; 

            if (!created.ContainsKey(ctl) 
                && ctl.IsHandleCreated 
                && TopLevelControl != null) {
 
                CreateRegion(ctl);
            }

            if (created.ContainsKey(ctl)) { 
                ctl.MouseMove -= new MouseEventHandler(this.MouseMove);
            } 
        } 

 

        /// 
        /// 
        ///     Destroys the handle for this control. 
        /// 
        ///  
        /// Required by Label to destroy the handle for the toolTip added for AutoEllipses. 
        internal void DestroyHandle() {
 
            if (GetHandleCreated()) {
                window.DestroyHandle();
            }
        } 

        private void DestroyRegion(Control ctl) { 
 
            // when the toplevelControl is a form and is Modal, the Handle of the tooltip is releasedbefore we come here.
            // In such a case the tool wont get deleted from the tooltip. 
            // So we dont check "Handle" in the handlesCreate but check it only foe Non-Nodal dialogs later

            bool handlesCreated = ctl.IsHandleCreated
                                && topLevelControl != null 
                                && topLevelControl.IsHandleCreated
                                && !this.isDisposing; 
 
            Form topForm = topLevelControl as Form;
            if (topForm == null || (topForm != null && !topForm.Modal)) 
            {
                handlesCreated = handlesCreated && GetHandleCreated();
            }
 
            if (created.ContainsKey(ctl)
                && handlesCreated && !DesignMode) { 
 
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TTM_DELTOOL, 0, GetMinTOOLINFO(ctl));
                created.Remove(ctl); 
            }
        }

        ///  
        /// 
        ///  
        ///     
        ///       Disposes of the 
        ///       component. 
        ///    
        /// 
        protected override void Dispose(bool disposing) {
 
            if (disposing) {
                this.isDisposing = true; 
                try { 
                    ClearTopLevelControlEvents();
                    StopTimer(); 

                    // always destroy the handle...
                    //
                    DestroyHandle(); 
                    RemoveAll();
 
                    window = null; 

                    //Unhook the DeactiveEvent... 
                    // Lets find the Form for associated Control ...
                    // and hook up to the Deactivated event to Hide the Shown tooltip
                    Form baseFrom = TopLevelControl as Form;
                    if (baseFrom != null) { 
                        baseFrom.Deactivate -= new EventHandler(this.BaseFormDeactivate);
                    } 
                } 
                finally {
                    this.isDisposing = false; 
                }
            }
            base.Dispose(disposing);
        } 

        ///  
        ///  
        ///     Returns the delayTime based on the NativeMethods.TTDT_* values.
        ///  
        /// 
        private int GetDelayTime(int type) {
            if (GetHandleCreated()) {
                return (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TTM_GETDELAYTIME, type, 0); 
            }
            else { 
                return delayTimes[type]; 
            }
        } 

        // Can't be a property -- there is another method called GetHandleCreated
        internal bool GetHandleCreated() {
            return (window != null ? window.Handle != IntPtr.Zero: false); 
        }
 
        ///  
        /// 
        ///     Returns a new instance of the TOOLINFO_T structure with the minimum 
        ///     required data to uniquely identify a region. This is used primarily
        ///     for delete operations. NOTE: This cannot force the creation of a handle.
        /// 
        ///  
        private NativeMethods.TOOLINFO_TOOLTIP GetMinTOOLINFO(Control ctl) {
            NativeMethods.TOOLINFO_TOOLTIP ti = new NativeMethods.TOOLINFO_TOOLTIP(); 
            ti.cbSize = Marshal.SizeOf(typeof(NativeMethods.TOOLINFO_TOOLTIP)); 
            ti.hwnd = ctl.Handle;
            ti.uFlags |= NativeMethods.TTF_IDISHWND; 
            ti.uId = ctl.Handle;
            return ti;
        }
 
        /// 
        ///  
        ///     Returns a detailed TOOLINFO_TOOLTIP structure that represents the specified 
        ///     region. NOTE: This may force the creation of a handle.
        ///     If the out parameter allocatedString has been set to true, It is the responsibility of the caller 
        ///		to free the string buffer referenced by lpszText (using Marshal.FreeHGlobal).
        /// 
        /// 
        private NativeMethods.TOOLINFO_TOOLTIP GetTOOLINFO(Control ctl, string caption, out bool allocatedString) { 
            allocatedString = false;
            NativeMethods.TOOLINFO_TOOLTIP ti = GetMinTOOLINFO(ctl); 
            ti.cbSize = Marshal.SizeOf(typeof(NativeMethods.TOOLINFO_TOOLTIP)); 
            ti.uFlags |= NativeMethods.TTF_TRANSPARENT | NativeMethods.TTF_SUBCLASS;
 
            // RightToLeft reading order
            //
            Control richParent = TopLevelControl;
            if (richParent != null && richParent.RightToLeft == RightToLeft.Yes && !ctl.IsMirrored) { 
                //Indicates that the ToolTip text will be displayed in the opposite direction
                //to the text in the parent window. 
                ti.uFlags |= NativeMethods.TTF_RTLREADING; 
            }
 
            if (ctl is TreeView || ctl is ListView) {
                TreeView tv = ctl as TreeView;
                if (tv != null && tv.ShowNodeToolTips) {
                    ti.lpszText = NativeMethods.InvalidIntPtr; 
                }
                else { 
                    ListView lv = ctl as ListView; 
                    if (lv != null && lv.ShowItemToolTips) {
                        ti.lpszText = NativeMethods.InvalidIntPtr; 
                    }
                    else {
                        ti.lpszText = Marshal.StringToHGlobalAuto(caption);
                        allocatedString = true; 
                    }
                } 
            } 
            else {
                ti.lpszText = Marshal.StringToHGlobalAuto(caption); 
                allocatedString = true;
            }

 
            return ti;
        } 
 
        private NativeMethods.TOOLINFO_TOOLTIP GetWinTOOLINFO(IntPtr hWnd) {
            NativeMethods.TOOLINFO_TOOLTIP ti = new NativeMethods.TOOLINFO_TOOLTIP(); 
            ti.cbSize = Marshal.SizeOf(typeof(NativeMethods.TOOLINFO_TOOLTIP));
            ti.hwnd = hWnd;
            ti.uFlags |= NativeMethods.TTF_IDISHWND | NativeMethods.TTF_TRANSPARENT | NativeMethods.TTF_SUBCLASS;
 
            // RightToLeft reading order
            // 
            Control richParent = TopLevelControl; 
            if (richParent != null && richParent.RightToLeft == RightToLeft.Yes) {
                bool isWindowMirrored = ((unchecked((int)(long)UnsafeNativeMethods.GetWindowLong(new HandleRef(this, hWnd), NativeMethods.GWL_STYLE)) & NativeMethods.WS_EX_LAYOUTRTL) == NativeMethods.WS_EX_LAYOUTRTL); 
                //Indicates that the ToolTip text will be displayed in the opposite direction
                //to the text in the parent window.
                if (!isWindowMirrored) {
                    ti.uFlags |= NativeMethods.TTF_RTLREADING; 
                }
            } 
 
            ti.uId = ti.hwnd;
            return ti; 
        }

        /// 
        ///  
        ///    
        ///       Retrieves the  text associated with the specified control. 
        ///     
        /// 
        [ 
        DefaultValue(""),
        Localizable(true),
        SRDescription(SR.ToolTipToolTipDescr),
        Editor("System.ComponentModel.Design.MultilineStringEditor, " + AssemblyRef.SystemDesign, typeof(System.Drawing.Design.UITypeEditor)) 
        ]
        public string GetToolTip(Control control) { 
            if (control == null) { 
                return String.Empty;
            } 
            TipInfo tt = (TipInfo)tools[control];
            if (tt == null || tt.Caption == null) {
                return "";
            } 
            else {
                return tt.Caption; 
            } 
        }
 
        /// 
        /// 
        ///     Returns the HWND of the window that is at the specified point. This
        ///     handles special cases where one Control owns multiple HWNDs (i.e. ComboBox). 
        /// 
        ///  
        private IntPtr GetWindowFromPoint(Point screenCoords, ref bool success) { 
            Control baseVar = TopLevelControl;
            //Special case the ActiveX Controls. 
            if (baseVar != null && baseVar.IsActiveX)
            {
                //find the matching HWnd matching the ScreenCoord and find if the Control has a Tooltip.
                IntPtr hwndControl = UnsafeNativeMethods.WindowFromPoint(screenCoords.X, screenCoords.Y); 
                if (hwndControl != IntPtr.Zero)
                { 
                    Control currentControl = Control.FromHandleInternal(hwndControl); 
                    if (currentControl != null && tools != null && tools.ContainsKey(currentControl))
                    { 
                        return hwndControl;
                    }
                }
                return IntPtr.Zero; 
            }
 
            IntPtr baseHwnd = IntPtr.Zero; 

            if (baseVar != null) { 
                baseHwnd = baseVar.Handle;
            }

            IntPtr hwnd = IntPtr.Zero; 
            bool finalMatch = false;
            while (!finalMatch) { 
                Point pt = screenCoords; 
                if (baseVar != null) {
                    pt = baseVar.PointToClientInternal(screenCoords); 
                }
                IntPtr found = UnsafeNativeMethods.ChildWindowFromPointEx(new HandleRef(null, baseHwnd), pt.X, pt.Y, NativeMethods.CWP_SKIPINVISIBLE);

                if (found == baseHwnd) { 
                    hwnd = found;
                    finalMatch = true; 
                } 
                else if (found == IntPtr.Zero) {
                    finalMatch = true; 
                }
                else {
                    baseVar = Control.FromHandleInternal(found);
                    if (baseVar == null) { 
                        baseVar = Control.FromChildHandleInternal(found);
                        if (baseVar != null) { 
                            hwnd = baseVar.Handle; 
                        }
                        finalMatch = true; 
                    }
                    else {
                        baseHwnd = baseVar.Handle;
                    } 
                }
            } 
 
            if (hwnd != IntPtr.Zero) {
                Control ctl = Control.FromHandleInternal(hwnd); 
                if (ctl != null) {
                    Control current = ctl;
                    while (current != null && current.Visible) {
                        current = current.ParentInternal; 
                    }
                    if (current != null) { 
                        hwnd = IntPtr.Zero; 
                    }
                    success = true; 
                }
            }

            return hwnd; 
        }
 
        private void OnTopLevelPropertyChanged(object s, EventArgs e) { 
            ClearTopLevelControlEvents();
            this.topLevelControl = null; 

            // We must re-aquire this control.  If the existing top level control's handle
            // was never created, but the new parent has a handle, if we don't re-get
            // the top level control here we won't ever create the tooltip handle. 
            //
            this.topLevelControl = TopLevelControl; 
        } 

        ///  
        /// 
        /// 
        /// 
        private void RecreateHandle() { 
            if (!DesignMode) {
                if (GetHandleCreated()) { 
                    DestroyHandle(); 
                }
                created.Clear(); 
                CreateHandle();
                CreateAllRegions();
            }
        } 

 
        ///  
        /// 
        ///     
        ///       Removes all of the tooltips currently associated
        ///       with the  control.
        ///    
        ///  
        public void RemoveAll() {
            Control[] regions = new Control[tools.Keys.Count]; 
            tools.Keys.CopyTo(regions, 0); 
            for (int i=0; i
        ///  
        ///     Sets the delayTime based on the NativeMethods.TTDT_* values. 
        /// 
        ///  
        private void SetDelayTime(int type, int time) {
            if (type == NativeMethods.TTDT_AUTOMATIC) {
                auto = true;
            } 
            else {
                auto = false; 
            } 

            delayTimes[type] = time; 

            if (GetHandleCreated() && time >= 0) {
                UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TTM_SETDELAYTIME, type, time);
 
                // Update everyone else if automatic is set... we need to do this
                // to preserve value in case of handle recreation. 
                // 
                if (auto) {
                    delayTimes[NativeMethods.TTDT_AUTOPOP] = GetDelayTime(NativeMethods.TTDT_AUTOPOP); 
                    delayTimes[NativeMethods.TTDT_INITIAL] = GetDelayTime(NativeMethods.TTDT_INITIAL);
                    delayTimes[NativeMethods.TTDT_RESHOW] = GetDelayTime(NativeMethods.TTDT_RESHOW);
                }
            } 
            else if (auto) {
                AdjustBaseFromAuto(); 
            } 
        }
 
        /// 
        /// 
        ///    
        ///       Associates  text with the specified control. 
        ///    
        ///  
        public void SetToolTip(Control control, string caption) { 

            TipInfo info = new TipInfo(caption, TipInfo.Type.Auto); 
            SetToolTipInternal(control, info);

        }
 
        /// 
        ///  
        ///     
        ///       Associates 
        ///  
        ///    Returns true if the AutomaticDelay property should be persisted. 
        /// 
        ///  
        private bool ShouldSerializeAutomaticDelay() {
            if (auto) {
                if (AutomaticDelay != DEFAULT_DELAY) {
                    return true; 
                }
            } 
            return false; 
        }
 
        /// 
        /// 
        ///    Returns true if the AutoPopDelay property should be persisted.
        ///  
        /// 
        private bool ShouldSerializeAutoPopDelay() { 
            return !auto; 
        }
 
        /// 
        /// 
        ///    Returns true if the InitialDelay property should be persisted.
        ///  
        /// 
        private bool ShouldSerializeInitialDelay() { 
            return !auto; 
        }
 
        /// 
        /// 
        ///    Returns true if the ReshowDelay property should be persisted.
        ///  
        /// 
        private bool ShouldSerializeReshowDelay() { 
            return !auto; 
        }
 

        /// 
        /// 
        ///    Shows a tooltip for specified text, window, and hotspot 
        /// 
        ///  
        private void ShowTooltip(string text, IWin32Window win, int duration) { 
            if (win == null) {
                throw new ArgumentNullException("win"); 
            }

            Control associatedControl = win as Control;
            if (associatedControl != null) { 
                NativeMethods.RECT r = new NativeMethods.RECT();
                UnsafeNativeMethods.GetWindowRect(new HandleRef(associatedControl, associatedControl.Handle), ref r); 
 
                Cursor currentCursor = Cursor.CurrentInternal;
                Point cursorLocation = Cursor.Position; 
                Point p = cursorLocation;

                Screen screen = Screen.FromPoint(cursorLocation);
 
                // Place the tool tip on the associated control if its not already there
                if ( cursorLocation.X < r.left || cursorLocation.X > r.right || 
                     cursorLocation.Y < r.top || cursorLocation.Y > r.bottom ) { 

                    // calculate the dimensions of the visible rectangle which 
                    // is used to estimate the upper x,y of the tooltip placement
                    NativeMethods.RECT visibleRect = new NativeMethods.RECT();
                    visibleRect.left = (r.left < screen.WorkingArea.Left) ? screen.WorkingArea.Left:r.left;
                    visibleRect.top = (r.top < screen.WorkingArea.Top) ? screen.WorkingArea.Top:r.top; 
                    visibleRect.right = (r.right > screen.WorkingArea.Right) ? screen.WorkingArea.Right:r.right;
                    visibleRect.bottom = (r.bottom > screen.WorkingArea.Bottom) ? screen.WorkingArea.Bottom:r.bottom; 
 
                    p.X = visibleRect.left + (visibleRect.right - visibleRect.left)/2;
                    p.Y = visibleRect.top + (visibleRect.bottom - visibleRect.top)/2; 
                    associatedControl.PointToClientInternal(p);
                    SetTrackPosition(p.X, p.Y);
                    SetTool(win, text, TipInfo.Type.SemiAbsolute, p);
 
                    if (duration > 0) {
                       StartTimer(window, duration); 
                    } 

                } 
                else {

                    TipInfo tt = (TipInfo)tools[associatedControl];
                    if (tt == null) { 
                        tt = new TipInfo(text, TipInfo.Type.SemiAbsolute);
                    } 
                    else { 
                        tt.TipType |= TipInfo.Type.SemiAbsolute;
                        tt.Caption = text; 
                    }
                    tt.Position = p;

                    if (duration > 0) { 
                       if (this.originalPopupDelay == 0) {
                          this.originalPopupDelay = AutoPopDelay; 
                       } 
                       AutoPopDelay  = duration;
                    } 
                    SetToolTipInternal(associatedControl, tt);
                }
            }
        } 

 
        ///  
        /// 
        ///     
        ///       Associates  with the specified control and displays it.
        ///    
        /// 
         public void Show(string text, IWin32Window window) { 
            //SecReview: We should not allow Semi-trust apps to call Show on a tooltip. Refer VsWhidbey : 439847
            // Check if the foreground window is the TopLevelWindow 
            if (HasAllWindowsPermission && IsWindowActive(window)) { 
                ShowTooltip(text, window, 0);
            } 

        }

        ///  
        /// 
        ///     
        ///       Associates  with the specified control 
        ///       and displays it for the specified duration.
        ///     
        /// 
        public void Show(string text, IWin32Window window, int duration) {
            if (duration < 0) {
                throw new ArgumentOutOfRangeException("duration", SR.GetString(SR.InvalidLowBoundArgumentEx, "duration", (duration).ToString(CultureInfo.CurrentCulture), (0).ToString(CultureInfo.CurrentCulture))); 
            }
 
            //SecReview: We should not allow Semi-trust apps to call Show on a tooltip. Refer VsWhidbey : 439847 
            if (HasAllWindowsPermission && IsWindowActive(window)) {
                ShowTooltip(text, window, duration); 
            }
        }

        ///  
        /// 
        ///     
        ///       Associates  with the specified control and displays it. 
        ///    
        ///  
        public void Show(string text, IWin32Window window, Point point) {
            if (window == null) {
                throw new ArgumentNullException("window");
            } 

            //SecReview: We should not allow Semi-trust apps to call Show on a tooltip. Refer VsWhidbey : 439847 
            if (HasAllWindowsPermission && IsWindowActive(window)) { 
                //Set The ToolTips...
                NativeMethods.RECT r = new NativeMethods.RECT(); 
                UnsafeNativeMethods.GetWindowRect(new HandleRef(window, Control.GetSafeHandle(window)), ref r);
                int pointX = r.left + point.X;
                int pointY = r.top + point.Y;
 
                SetTrackPosition(pointX, pointY);
                SetTool(window, text, TipInfo.Type.Absolute, new Point(pointX, pointY)); 
            } 
        }
 
        /// 
        /// 
        ///    
        ///       Associates  with the specified control and displays it. 
        ///    
        ///  
        public void Show(string text, IWin32Window window, Point point, int duration) { 
            if (window == null) {
                throw new ArgumentNullException("window"); 
            }
            if (duration < 0) {
                throw new ArgumentOutOfRangeException("duration", SR.GetString(SR.InvalidLowBoundArgumentEx, "duration", (duration).ToString(CultureInfo.CurrentCulture), (0).ToString(CultureInfo.CurrentCulture)));
            } 

            //SecReview: We should not allow Semi-trust apps to call Show on a tooltip. Refer VsWhidbey : 439847 
            if (HasAllWindowsPermission && IsWindowActive(window)) { 
                //Set The ToolTips...
                NativeMethods.RECT r = new NativeMethods.RECT(); 
                UnsafeNativeMethods.GetWindowRect(new HandleRef(window, Control.GetSafeHandle(window)), ref r);
                int pointX = r.left + point.X;
                int pointY = r.top + point.Y;
                SetTrackPosition(pointX, pointY); 
                SetTool(window, text, TipInfo.Type.Absolute, new Point(pointX, pointY));
                StartTimer(window, duration); 
            } 
        }
 


        /// 
        ///  
        ///    
        ///       Associates  with the specified control and displays it. 
        ///     
        /// 
        public void Show(string text, IWin32Window window, int x, int y) { 
            if (window == null) {
                throw new ArgumentNullException("window");
            }
 
            //SecReview: We should not allow Semi-trust apps to call Show on a tooltip. Refer VsWhidbey : 439847
            if (HasAllWindowsPermission && IsWindowActive(window)) { 
                NativeMethods.RECT r = new NativeMethods.RECT(); 
                UnsafeNativeMethods.GetWindowRect(new HandleRef(window, Control.GetSafeHandle(window)), ref r);
                int pointX = r.left + x; 
                int pointY = r.top + y;
                SetTrackPosition(pointX, pointY);
                SetTool(window, text, TipInfo.Type.Absolute, new Point(pointX, pointY));
            } 
        }
 
        ///  
        /// 
        ///     
        ///       Associates  with the specified control and displays it.
        ///    
        /// 
        public void Show(string text, IWin32Window window, int x, int y, int duration) { 
            if (window == null) {
                throw new ArgumentNullException("window"); 
            } 
            if (duration < 0) {
                throw new ArgumentOutOfRangeException("duration", SR.GetString(SR.InvalidLowBoundArgumentEx, "duration", (duration).ToString(CultureInfo.CurrentCulture), (0).ToString(CultureInfo.CurrentCulture))); 
            }

            //SecReview: We should not allow Semi-trust apps to call Show on a tooltip. Refer VsWhidbey : 439847
            if (HasAllWindowsPermission && IsWindowActive(window)) { 
                NativeMethods.RECT r = new NativeMethods.RECT();
                UnsafeNativeMethods.GetWindowRect(new HandleRef(window, Control.GetSafeHandle(window)), ref r); 
                int pointX = r.left + x; 
                int pointY = r.top + y;
                SetTrackPosition(pointX, pointY); 
                SetTool(window, text, TipInfo.Type.Absolute, new Point(pointX, pointY));
                StartTimer(window, duration);
            }
        } 

        ///  
        ///     Private Function to encapsulate TTM_TRACKPOSITION so that this doesnt fire an extra POP event 
        /// 
        private void SetTrackPosition(int pointX, int pointY) 
        {
            try
            {
                trackPosition = true; 
                UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle), NativeMethods.TTM_TRACKPOSITION, 0, NativeMethods.Util.MAKELONG(pointX, pointY));
            } 
            finally 
            {
                trackPosition= false; 
            }
        }

        ///  
        /// 
        ///     
        ///       Hides  with the specified control. 
        ///    
        ///  
        public void Hide(IWin32Window win) {
            if (win == null) {
                throw new ArgumentNullException("win");
            } 

            //SecReview: We should not allow Semi-trust apps to call Show on a tooltip. Refer VsWhidbey : 439847 
            if (HasAllWindowsPermission) { 
                if (window == null)
                { 
                    return;
                }

                // VSWhidbey 562045: Only send message if we actually have a ToolTip at this point. 
                if (GetHandleCreated())  {
                    IntPtr hWnd = Control.GetSafeHandle(win); 
                    UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle), NativeMethods.TTM_TRACKACTIVATE, 0, GetWinTOOLINFO(hWnd)); 
                    UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle), NativeMethods.TTM_DELTOOL, 0, GetWinTOOLINFO(hWnd));
                } 
                StopTimer();

                //Check if the passed in IWin32Window is a Control...
                Control tool = win as Control; 
                if (tool == null) {
                    owners.Remove(win.Handle); 
                } 
                else
                { 
                    if (tools.ContainsKey(tool)) {
                        SetToolInfo(tool, GetToolTip(tool));
                    }
                    else { 
                        owners.Remove(win.Handle);
                    } 
                    // Lets find the Form for associated Control ... 
                    // and hook up to the Deactivated event to Hide the Shown tooltip
                    Form baseFrom = tool.FindFormInternal(); 
                    if (baseFrom != null) {
                        baseFrom.Deactivate -= new EventHandler(this.BaseFormDeactivate);
                    }
                } 

                // VSWhidbey 562045 - clear off the toplevel control. 
                ClearTopLevelControlEvents(); 
                topLevelControl = null;
            } 
        }

        private void BaseFormDeactivate(System.Object sender, System.EventArgs e){
            HideAllToolTips(); 
        }
 
        private void HideAllToolTips() { 
            Control[] ctls = new Control[owners.Values.Count];
            owners.Values.CopyTo(ctls, 0); 
            for (int i=0; i 
        /// 
        ///     Starts the timer hiding Positioned ToolTips 
        ///  
        private void StartTimer(IWin32Window owner, int interval) {
 
            if (timer == null) {
                timer = new ToolTipTimer(owner);
                // Add the timer handler
                timer.Tick += new EventHandler(TimerHandler); 
            }
            timer.Interval = interval; 
            timer.Start(); 
        }
 
        /// 
        /// 
        ///     Stops the timer for hiding Positioned ToolTips
        ///  
        protected void StopTimer() {
            //VSWhidbey 363538: hold a local ref to timer 
            //so that a posted message doesn't null this 
            //out during disposal.
            ToolTipTimer timerRef = timer; 

            if (timerRef != null) {
                timerRef.Stop();
                timerRef.Dispose(); 
                timer = null;
            } 
        } 

        ///  
        /// 
        ///     Generates updown events when the timer calls this function.
        /// 
        private void TimerHandler(object source, EventArgs args) { 
            Hide(((ToolTipTimer)source).Host);
        } 
 
        /// 
        ///  
        ///    
        ///       Finalizes garbage collection.
        ///    
        ///  
        ~ToolTip() {
            DestroyHandle(); 
        } 

        ///  
        /// 
        /// 
        ///    
        ///       Returns a string representation for this control. 
        ///    
        ///  
        public override string ToString() { 

            string s = base.ToString(); 
            return s + " InitialDelay: " + InitialDelay.ToString(CultureInfo.CurrentCulture) + ", ShowAlways: " + ShowAlways.ToString(CultureInfo.CurrentCulture);
        }

        private void Reposition(Point tipPosition, Size tipSize) { 
            Point moveToLocation = tipPosition;
            Screen screen = Screen.FromPoint(moveToLocation); 
 
            // Re-adjust the X position of the tool tip if it bleeds off the screen working area
            if (moveToLocation.X + tipSize.Width > screen.WorkingArea.Right) { 
                moveToLocation.X = screen.WorkingArea.Right - tipSize.Width;
            }

            // re-adjust the Y position of the tool tip if it bleeds off the screen working area. 
            if (moveToLocation.Y + tipSize.Height> screen.WorkingArea.Bottom) {
                moveToLocation.Y = screen.WorkingArea.Bottom - tipSize.Height; 
            } 

            SafeNativeMethods.SetWindowPos(new HandleRef(this, this.Handle), 
            NativeMethods.HWND_TOPMOST,
            moveToLocation.X, moveToLocation.Y, tipSize.Width, tipSize.Height,
            NativeMethods.SWP_NOACTIVATE | NativeMethods.SWP_NOSIZE | NativeMethods.SWP_NOOWNERZORDER);
        } 

        ///  
        ///  
        ///     Handles the WM_MOVE message.
        ///  
        /// 
        private void WmMove() {
            NativeMethods.RECT r = new NativeMethods.RECT();
            UnsafeNativeMethods.GetWindowRect(new HandleRef(this, Handle), ref r); 
            NativeMethods.TOOLINFO_TOOLTIP ti = new NativeMethods.TOOLINFO_TOOLTIP();
            ti.cbSize = Marshal.SizeOf(typeof(NativeMethods.TOOLINFO_TOOLTIP)); 
            int ret = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TTM_GETCURRENTTOOL, 0, ti); 
            if (ret != 0)
            { 
                IWin32Window win = (IWin32Window)owners[ti.hwnd];
                if (win == null) {
                    win = (IWin32Window)Control.FromHandleInternal(ti.hwnd);
                } 

                if (win == null) { 
                    return; 
                }
 
                TipInfo tt = (TipInfo)tools[win];
                if (win == null || tt==null) {
                   return;
                } 

                // Treeview handles its own ToolTips. 
                TreeView treeView = win as TreeView; 
                if (treeView != null) {
                    if (treeView.ShowNodeToolTips) { 
                        return;
                    }
                }
 
                // Reposition the tooltip when its about to be shown.. since the tooltip can go out of screen workingarea bounds
                // Reposition would check the bounds for us. 
                if (tt.Position != Point.Empty) 
                {
                    Reposition(tt.Position, r.Size); 
                }
             }
        }
 

        ///  
        ///  
        ///     Handles the WM_MOUSEACTIVATE message.
        ///  
        /// 
        private void WmMouseActivate(ref Message msg) {

            NativeMethods.TOOLINFO_TOOLTIP ti = new NativeMethods.TOOLINFO_TOOLTIP(); 
            ti.cbSize = Marshal.SizeOf(typeof(NativeMethods.TOOLINFO_TOOLTIP));
            int ret = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TTM_GETCURRENTTOOL, 0, ti); 
 
            if (ret != 0) {
 
                IWin32Window win = (IWin32Window)owners[ti.hwnd];
                if (win == null) {
                    win = (IWin32Window)Control.FromHandleInternal(ti.hwnd);
                } 

                if (win == null) { 
                    return; 
                }
 
                NativeMethods.RECT r = new NativeMethods.RECT();
                UnsafeNativeMethods.GetWindowRect(new HandleRef(win, Control.GetSafeHandle(win)), ref r);
                Point cursorLocation = Cursor.Position;
 
                // Do not activate the mouse if its within the bounds of the
                // the associated tool 
                if (cursorLocation.X >= r.left && cursorLocation.X <= r.right && 
                    cursorLocation.Y >= r.top && cursorLocation.Y <= r.bottom) {
                    msg.Result = (IntPtr)NativeMethods.MA_NOACTIVATE; 
                }
            }
        }
 

 
        ///  
        /// 
        ///     Handles the WM_WINDOWFROMPOINT message. 
        /// 
        /// 
        private void WmWindowFromPoint(ref Message msg) {
            NativeMethods.POINT sc = (NativeMethods.POINT)msg.GetLParam(typeof(NativeMethods.POINT)); 
            Point screenCoords = new Point(sc.x, sc.y);
            bool result = false; 
            msg.Result = GetWindowFromPoint(screenCoords, ref result); 
        }
 


        /// 
        ///  
        ///     Handles the TTN_SHOW message.
        ///  
        ///  
        private void WmShow() {
 

            //Get the Bounds....
            NativeMethods.RECT r = new NativeMethods.RECT();
            UnsafeNativeMethods.GetWindowRect(new HandleRef(this, Handle), ref r); 

            NativeMethods.TOOLINFO_TOOLTIP ti = new NativeMethods.TOOLINFO_TOOLTIP(); 
            ti.cbSize = Marshal.SizeOf(typeof(NativeMethods.TOOLINFO_TOOLTIP)); 
            int ret = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TTM_GETCURRENTTOOL, 0, ti);
 
            if (ret != 0) {

                IWin32Window win = (IWin32Window)owners[ti.hwnd];
                if (win == null) { 
                    win = (IWin32Window)Control.FromHandleInternal(ti.hwnd);
                } 
 
                if (win == null) {
                    return; 
                }

                Control toolControl = win as Control;
 
                Size currentTooltipSize = r.Size;
                PopupEventArgs e = new PopupEventArgs(win, toolControl, IsBalloon, currentTooltipSize); 
                OnPopup(e); 

                DataGridView dataGridView = toolControl as DataGridView; 
                if (dataGridView != null && dataGridView.CancelToolTipPopup(this))
                {
                    // The dataGridView cancelled the tooltip.
                    e.Cancel = true; 
                }
 
                // We need to re-get the rectangle of the tooltip here because 
                // any of the tooltip attributes/properties could have been updated
                // during the popup event; in which case the size of the tooltip is 
                // affected. e.ToolTipSize is respected over r.Size
                UnsafeNativeMethods.GetWindowRect(new HandleRef(this, Handle), ref r);
                currentTooltipSize = (e.ToolTipSize == currentTooltipSize) ? r.Size:e.ToolTipSize;
 

                if (IsBalloon) { 
                  // Get the text display rectangle 
                   UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TTM_ADJUSTRECT, 1, ref r);
                   if (r.Size.Height > currentTooltipSize.Height) currentTooltipSize.Height = r.Size.Height; 
                }

                // Set the max possible size of the tooltip to the size we received.
                // This prevents the operating system from drawing incorrect rectangles 
                // when determing the correct display rectangle. VSWhidbey
 
                if (currentTooltipSize != r.Size) 
                {
                    Screen screen = Screen.FromPoint(Cursor.Position); 
                    int maxwidth = (IsBalloon) ?
                    Math.Min(currentTooltipSize.Width-2*XBALLOONOFFSET, screen.WorkingArea.Width):
                    Math.Min(currentTooltipSize.Width, screen.WorkingArea.Width);
                    UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TTM_SETMAXTIPWIDTH, 0, maxwidth); 
                }
 
                if (e.Cancel) { 
                    cancelled = true;
                    SafeNativeMethods.SetWindowPos(new HandleRef(this, this.Handle), 
                    NativeMethods.HWND_TOPMOST,
                    0, 0, 0, 0,
 					NativeMethods.SWP_NOACTIVATE | NativeMethods.SWP_NOOWNERZORDER);
 
                }
                else { 
                    cancelled = false; 
                    // Only width/height changes are respected, so set top,left to what we got earlier
                    SafeNativeMethods.SetWindowPos(new HandleRef(this, this.Handle), 
                    NativeMethods.HWND_TOPMOST,
                    r.left, r.top, currentTooltipSize.Width, currentTooltipSize.Height,
                    NativeMethods.SWP_NOACTIVATE | NativeMethods.SWP_NOOWNERZORDER);
                } 
            }
        } 
 
        /// 
        ///  
        ///     Handles the WM_WINDOWPOSCHANGED message.
        ///     We need to Hide the window since the native tooltip actually calls SetWindowPos in its TTN_SHOW even if we cancel showing the
        ///     tooltip : Hence we need to listen to the WindowPosChanged message can hide the window ourselves.
        ///     Refer to VsWhidbey : 490044 for more details. 
        /// 
        ///  
        private bool WmWindowPosChanged() { 
            if (cancelled)
            { 
               SafeNativeMethods.ShowWindow(new HandleRef(this, Handle), NativeMethods.SW_HIDE);
               return true;
            }
            return false; 
        }
 
 

        ///  
        /// 
        ///     Handles the WM_WINDOWPOSCHANGING message.
        /// 
        ///  
        private unsafe void WmWindowPosChanging(ref Message m) {
            if (cancelled) 
            { 
            	return;
            } 

            NativeMethods.WINDOWPOS* wp = (NativeMethods.WINDOWPOS *)m.LParam;

            Cursor currentCursor = Cursor.CurrentInternal; 
            Point cursorPos = Cursor.Position;
 
			 

            NativeMethods.TOOLINFO_TOOLTIP ti = new NativeMethods.TOOLINFO_TOOLTIP(); 
            ti.cbSize = Marshal.SizeOf(typeof(NativeMethods.TOOLINFO_TOOLTIP));
            int ret = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TTM_GETCURRENTTOOL, 0, ti);
            if (ret != 0) {
 
                IWin32Window win = (IWin32Window)owners[ti.hwnd];
                if (win == null) { 
                    win = (IWin32Window)Control.FromHandleInternal(ti.hwnd); 
                }
 
                if (win == null || !IsWindowActive(win)) {
                    return;
                }
 
                TipInfo tt = null;
                if (win != null) 
                { 
                    tt = (TipInfo)tools[win];
                    if (tt == null) { 
                       return;
                    }

                    // Treeview handles its own ToolTips. 
                    TreeView treeView = win as TreeView;
                    if (treeView != null) { 
                        if (treeView.ShowNodeToolTips) { 
                            return;
                        } 
                    }
                }

                if (IsBalloon) { 
                   wp->cx += 2*XBALLOONOFFSET;
                   return; 
                } 

                if ( (tt.TipType & TipInfo.Type.Auto) != 0) 
                {
                    window.DefWndProc(ref m);
                    return;
                } 

                if ( ((tt.TipType & TipInfo.Type.SemiAbsolute) != 0) && tt.Position == Point.Empty ) { 
 
                   Screen screen = Screen.FromPoint(cursorPos);
                   if (currentCursor != null) 
                   {
                        wp->x = cursorPos.X;
                        // Since HotSpot requires a security demand .. we assert this and revert Assert immediately
                        try { 
                            IntSecurity.ObjectFromWin32Handle.Assert();
 
                            wp->y = cursorPos.Y; 
                            if (wp->y + wp->cy + currentCursor.Size.Height - currentCursor.HotSpot.Y > screen.WorkingArea.Bottom) {
                               wp->y = cursorPos.Y - wp->cy; 
                            }
                            else {
                               wp->y = cursorPos.Y + currentCursor.Size.Height - currentCursor.HotSpot.Y;
                            } 
                        }
                        finally { 
                            CodeAccessPermission.RevertAssert(); 
                        }
                   } 
                   if (wp->x + wp->cx >screen.WorkingArea.Right) {
                      wp->x = screen.WorkingArea.Right - wp->cx;
                   }
 
                }
                else if ((tt.TipType & TipInfo.Type.SemiAbsolute) != 0 && tt.Position != Point.Empty) { 
 
                   Screen screen = Screen.FromPoint(tt.Position);
                   wp->x = tt.Position.X; 
                   if (wp->x + wp->cx >screen.WorkingArea.Right) {
                      wp->x = screen.WorkingArea.Right - wp->cx;
                   }
                   wp->y = tt.Position.Y; 

                   if (wp->y + wp->cy > screen.WorkingArea.Bottom) { 
                        wp->y = screen.WorkingArea.Bottom - wp->cy; 
                   }
                } 
            }

            m.Result = IntPtr.Zero;
        } 

        ///  
        ///  
        ///     Called just before the tooltip is hidden
        ///  
        /// 
        private void WmPop() {

            NativeMethods.TOOLINFO_TOOLTIP ti = new NativeMethods.TOOLINFO_TOOLTIP(); 
            ti.cbSize = Marshal.SizeOf(typeof(NativeMethods.TOOLINFO_TOOLTIP));
            int ret = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TTM_GETCURRENTTOOL, 0, ti); 
            if (ret != 0) { 

                IWin32Window win = (IWin32Window)owners[ti.hwnd]; 
                if (win == null) {
                    win = (IWin32Window)Control.FromHandleInternal(ti.hwnd);
                }
 
                if (win == null) {
                    return; 
                } 

                Control control = win as Control; 
                TipInfo tt = (TipInfo)tools[win];
                if (tt == null) {
                   return;
                } 

                // Must reset the maxwidth to the screen size. 
                // This is required to resolve VSWhidbey bug# 363408 
                if ((tt.TipType & TipInfo.Type.Auto) != 0 || (tt.TipType & TipInfo.Type.SemiAbsolute) != 0) {
                   Screen screen = Screen.FromPoint(Cursor.Position); 
                   UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TTM_SETMAXTIPWIDTH, 0, screen.WorkingArea.Width);
                }

                // For non-auto tips (those showned through 
                // the show(...) methods, we need to dissassociate
                // them from the tip control. 
                if ((tt.TipType & TipInfo.Type.Auto) == 0) { 

                     tools.Remove(control); 
                     owners.Remove(win.Handle);

                     control.HandleCreated -= new EventHandler(this.HandleCreated);
                     control.HandleDestroyed -= new EventHandler(this.HandleDestroyed); 
                     created.Remove(control);
 
                     if (originalPopupDelay != 0) { 
                        AutoPopDelay = originalPopupDelay;
                        originalPopupDelay = 0; 
                     }
                }
                else {
                     // Clear all other flags except for the 
                     // Auto flag to ensure automatic tips can still show
                     tt.TipType = TipInfo.Type.Auto; 
                     tt.Position = Point.Empty; 
                     tools[control] = tt;
                } 
            }
        }

        ///  
        /// 
        ///     WNDPROC 
        ///  
        /// 
        private void WndProc(ref Message msg) { 


            switch (msg.Msg) {
 
            case NativeMethods.WM_REFLECT + NativeMethods.WM_NOTIFY:
                 NativeMethods.NMHDR nmhdr = (NativeMethods.NMHDR) msg.GetLParam(typeof(NativeMethods.NMHDR)); 
                 if (nmhdr.code == NativeMethods.TTN_SHOW && !trackPosition) { 
                     WmShow();
                 } 
                 else if (nmhdr.code == NativeMethods.TTN_POP) {
                    WmPop();
                    window.DefWndProc(ref msg);
                 } 
                 break;
 
            case NativeMethods.WM_WINDOWPOSCHANGING: 
                 WmWindowPosChanging(ref msg);
                 break; 
			
            case NativeMethods.WM_WINDOWPOSCHANGED:
                 if (!WmWindowPosChanged())
                 { 
                    window.DefWndProc(ref msg);
                 } 
                 break; 
					
            case NativeMethods.WM_MOUSEACTIVATE: 
                 WmMouseActivate(ref msg);
                 break;

            case NativeMethods.WM_MOVE: 
                 WmMove();
                 break; 
 
            case NativeMethods.TTM_WINDOWFROMPOINT:
                WmWindowFromPoint(ref msg); 
                break;

            case NativeMethods.WM_PRINTCLIENT:
                goto case NativeMethods.WM_PAINT; 

            case NativeMethods.WM_PAINT: 
                if (ownerDraw && !isBalloon && !trackPosition) 
                {
                    NativeMethods.PAINTSTRUCT ps = new NativeMethods.PAINTSTRUCT(); 
                    IntPtr dc = UnsafeNativeMethods.BeginPaint(new HandleRef(this,Handle),ref ps);
                    Graphics g = Graphics.FromHdcInternal(dc);
                    Rectangle bounds = new Rectangle(ps.rcPaint_left,ps.rcPaint_top,
                    ps.rcPaint_right - ps.rcPaint_left, 
                    ps.rcPaint_bottom - ps.rcPaint_top);
                    if (bounds == Rectangle.Empty ) { 
                        return; 
                    }
                    NativeMethods.TOOLINFO_TOOLTIP ti = new NativeMethods.TOOLINFO_TOOLTIP(); 
                    ti.cbSize = Marshal.SizeOf(typeof(NativeMethods.TOOLINFO_TOOLTIP));
                    int ret = (int) UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TTM_GETCURRENTTOOL, 0, ti);
                    if (ret != 0) {
                        IWin32Window win = (IWin32Window)owners[ti.hwnd]; 
                        Control ac = Control.FromHandleInternal(ti.hwnd);
                        if (win == null) { 
                            win = (IWin32Window)ac; 
                        }
                        Font font; 
                        IntSecurity.ObjectFromWin32Handle.Assert();
                        try {
                            font = Font.FromHfont(UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.WM_GETFONT, 0, 0));
                        } 
                        catch (ArgumentException) {
                            // VSWhidbey 209345 - if the current default tooltip font is a non-TrueType font, then 
                            // Font.FromHfont throws this exception, so fall back to the default control font. 
                            font = Control.DefaultFont;
                        } 
                        finally {
                            CodeAccessPermission.RevertAssert();
                        }
 
                        try
                        { 
                            OnDraw(new DrawToolTipEventArgs(g, win, ac, bounds, GetToolTip(ac), 
                                                            BackColor, ForeColor, font));
                        } 
                        finally
                        {
                            g.Dispose();
                            UnsafeNativeMethods.EndPaint(new HandleRef(this,Handle),ref ps); 
                        }
 
                        break; 
                    }
                } 

                //If not OwnerDraw, fall through
                goto default;
            default: 
                window.DefWndProc(ref msg);
                break; 
            } 
        }
 
        /// 
        /// 
        /// 
        ///  
        private class ToolTipNativeWindow : NativeWindow {
            ToolTip control; 
 
            internal ToolTipNativeWindow(ToolTip control) {
                this.control = control; 
            }


        protected override void WndProc(ref Message m) { 
            if (control != null) {
            control.WndProc(ref m); 
                } 
            }
        } 

        private class ToolTipTimer : Timer {
            IWin32Window host;
 
            public ToolTipTimer(IWin32Window owner) : base(){
                this.host = owner; 
            } 

            public IWin32Window Host { 
                get {
                    return host;
                }
            } 
        }
 
 
        private class TipInfo {
 
           [Flags]
           public enum Type {
               None = 0x0000,
               Auto = 0x0001, 
               Absolute = 0x0002,
               SemiAbsolute = 0x0004 
           }; 

           public  Type     TipType = Type.Auto; 
           private string   caption;
           private string   designerText;
           public  Point    Position =  Point.Empty;
 
           public TipInfo(string caption, Type type) {
               this.caption = caption; 
               this.TipType = type; 
               if (type == Type.Auto) {
                   this.designerText = caption; 
               }
           }

           public string Caption { 
               get {
                   return ((this.TipType & (Type.Absolute | Type.SemiAbsolute)) != 0) ? caption:designerText; 
               } 
               set {
                   this.caption = value; 
               }
           }
        }
 
    }
} 

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