How can I show a systray tooltip longer than 63 chars?

后端 未结 5 735
不知归路
不知归路 2021-02-02 12:48

How can I show a systray tooltip longer than 63 chars? NotifyIcon.Text has a 63 chars limit, but I\'ve seen that VNC Server has a longer tooltip.

How can I do what VNC S

相关标签:
5条回答
  • 2021-02-02 12:59

    bk1e here says that the limit is 128 chars, now, if you use UTF-16, which is the native unicode format in windows and especially .NET, that means you are limited to 64 characters, including the NUL.

    I would believe that you're using a unicode API which limits tooltips to 64 16-bit characters (including the null), and that VNC Server uses ascii (or ANSI) api's instead, allowing the use of 128 8-bit characters (including the null).

    EDIT: This answer is wrong, here is a helpful comment by Cody Gray explaining why:

    This reasoning is compelling, but is not actually correct. When the MSDN documentation talks about "characters", it actually means the number of char or wchar_t items in the array (depending on whether you're targeting Unicode). So you get the full 128 characters promised when running on Windows 2000+. Windows 9x was limited to 64 characters. – Cody Gray Jun 19 at 4:11"

    0 讨论(0)
  • 2021-02-02 13:10

    Expanding on bk1e's correct answer.

    Under the hood, a system tray icon in WinForms is implemented as a Win32 Notify Icon. Therefore the winforms version has all of the limitations as the native one. The tooltip size limitation is just one example.

    0 讨论(0)
  • 2021-02-02 13:17

    Actually, it is a bug in the property setter for the Text property. The P/Invoke declaration for NOTIFYICONDATA inside Windows Forms uses the 128 char limit. You can hack around it with Reflection:

    using System;
    using System.Windows.Forms;
    using System.Reflection;
    
        public class Fixes {
          public static void SetNotifyIconText(NotifyIcon ni, string text) {
            if (text.Length >= 128) throw new ArgumentOutOfRangeException("Text limited to 127 characters");
            Type t = typeof(NotifyIcon);
            BindingFlags hidden = BindingFlags.NonPublic | BindingFlags.Instance;
            t.GetField("text", hidden).SetValue(ni, text);
            if ((bool)t.GetField("added", hidden).GetValue(ni))
              t.GetMethod("UpdateIcon", hidden).Invoke(ni, new object[] { true });
          }
        }
    
    0 讨论(0)
  • 2021-02-02 13:19

    From the MSDN documentation on the Win32 NOTIFYICONDATA structure:

    szTip

    A null-terminated string that specifies the text for a standard ToolTip. It can have a maximum of 64 characters, including the terminating null character.

    For Windows 2000 (Shell32.dll version 5.0) and later, szTip can have a maximum of 128 characters, including the terminating null character.

    It looks like the Windows Forms library supports the lowest common denominator here.

    0 讨论(0)
  • 2021-02-02 13:19

    I recently came across a similar problem. Rather than hacking the back-end, I implemented a work-around, which makes use of the BalloonTipText, which can accommodate quite a lot of characters.

    The tooltip is shown on the first MouseMove event over the tray icon and the tooltip is displayed for 2 seconds. Atter the tooltip is closed, it can be re-opened again by a new MouseMove event.

    The only downside with this solution is that is is not possible to close the balloon programatically, when a user, say, leaves the icon area, so it only disappears after a timeout or if the user clicks on the small X-button.

    Note that the title and the text can be set at any time elsewhere in the program. They are set here in the event for demonstration purpose only.

    EDIT: ShowBalloonTip() fires addition cascading MouseMove events, so it is necessary to disable this event until such time as the balloon tooltip is hidden. Additionally, BalloonTipClosed is (according to the documentation) only fired when the user actively clicks on 'X', though I observed it being fired when the tooltip closed after a timeout. I therefore added a helper timer to reset the sate, instead of relying on the BalloonTipClosed event. The revised and tested code is below:

        private bool balloonTipShown;
        private Timer balloonTimer;
        private void trayIcon_MouseMove(object sender, MouseEventArgs e)
        {
            if (balloonTipShown)
            {
                return;
            }
            balloonTipShown = true;
            trayIcon.MouseMove -= trayIcon_MouseMove;
            balloonTimer = new Timer();
            balloonTimer.Tick += balloonTimer_Tick;
            balloonTimer.Interval = 2005;
            balloonTimer.Start();
            trayIcon.ShowBalloonTip(2000);
        }
    
        void balloonTimer_Tick(object sender, EventArgs e)
        {
            balloonTipShown = false;
            balloonTimer.Stop();
            balloonTimer.Dispose();
            trayIcon.MouseMove += trayIcon_MouseMove;
        }
    

    EDIT 2: A screenshot of a balloon tooltip with quite a lot of text, that utilises this solution can be seen in by blog.

    0 讨论(0)
提交回复
热议问题