/// <summary> /// Closes the tooltip /// </summary> private void CloseToolTip() { WINAPI.TOOLINFO ti = new WINAPI.TOOLINFO(); ti.cbSize = Marshal.SizeOf(ti.GetType()); ti.hwnd = GetHandler(moNotifyIcon); WINAPI.SendMessage(moNativeWindow.Handle, WINAPI.TTM_DELTOOL, 0, ref ti); OnBalloonTipClosed(this, EventArgs.Empty); moNativeWindow = new NativeWindow(); }
/// <summary> /// Finds Systray toolbar /// </summary> /// <param name="hwnd">HWND of the window being enumerated</param> /// <param name="lParam"></param> /// <returns></returns> protected bool EnumChildWindowsFunc(IntPtr hwnd, IntPtr lParam) { StringBuilder sb = new StringBuilder(256); WINAPI.GetClassName(hwnd, sb, sb.Capacity); if (sb.ToString().StartsWith("ToolbarWindow32")) { mHWndNotify = hwnd; mFound = true; return false; } mFound = false; return true; }
/// <summary> /// Gets the NotifyIcon rectangle /// </summary> /// <param name="handle">Handle of the NotifyIcon</param> /// <returns></returns> private bool GetNotifyIconScreenRect(IntPtr handle) { WINAPI.RECT loNotifyIconRecr = new WINAPI.RECT(); if (handle == IntPtr.Zero) { return false; } // Find tray window IntPtr hWndTray = WINAPI.FindWindowEx(IntPtr.Zero, IntPtr.Zero, "Shell_TrayWnd", 0); if (hWndTray == IntPtr.Zero) return false; // Find SysTray toolbar WINAPI.EnumChildWindowsCallback callback = new WINAPI.EnumChildWindowsCallback(EnumChildWindowsFunc); WINAPI.EnumChildWindows(hWndTray, callback, 0); if (!mFound) return false; mFound = false; hWndTray = mHWndNotify; // Get a NotifyIcon rectangle and a tip position if (WINAPI.GetWindowRect(handle, ref loNotifyIconRecr) == 0) return false; if (WINAPI.MapWindowPoints(hWndTray, IntPtr.Zero, ref loNotifyIconRecr, 2) == 0) return false; // Here we should analyze where SysTray happens to be - up, left, right or bottom moPosition.X = loNotifyIconRecr.left; moPosition.Y = loNotifyIconRecr.top; return true; }
public static extern int GetTextExtentPoint32(IntPtr hDC, string String, int stringSize, ref WINAPI.SIZE size);
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, out WINAPI.RECT lParam);
/// <summary> /// Tooltip window proc /// </summary> /// <param name="hWnd"></param> /// <param name="iMsg"></param> /// <param name="wParam"></param> /// <param name="lParam"></param> /// <returns></returns> protected int WindowProc(IntPtr hWnd, UInt32 iMsg, IntPtr wParam, IntPtr lParam) { int height = 0; int width = 0; IntPtr nativeProc = WINAPI.GetProp(hWnd, "NATIVEPROC"); if (iMsg == WINAPI.WM_PAINT) { // Drow the original tooltip int liWinProcResult = WINAPI.CallWindowProc(nativeProc, hWnd, iMsg, wParam, lParam); WINAPI.TOOLINFO ti = new WINAPI.TOOLINFO(); ti.cbSize = Marshal.SizeOf(ti.GetType()); ti.hwnd = GetHandler(moNotifyIcon); if (ti.hwnd != IntPtr.Zero) { // Create graphics object for the tooltip Graphics loGraphics = Graphics.FromHwnd(hWnd); WINAPI.RECT rect = new WINAPI.RECT(); WINAPI.RECT rect1 = new WINAPI.RECT(); WINAPI.GetWindowRect(hWnd, ref rect); // In rect1 - tooltip rectangle // Calculate text display rectangle to rect rect1 = rect; WINAPI.SendMessage(hWnd, WINAPI.TTM_ADJUSTRECT, 0, out rect); // Width and heigth of the text area width = rect.right - rect.left; height = rect.bottom - rect.top; //Calculate iner rectangle of the text area rect.left = rect.left - rect1.left; rect.top = rect.top - rect1.top; rect.right = rect.left + width; rect.bottom = rect.top + height; //Clear text area: 16 pixs - header, 30 pixs from bottom loGraphics.FillRectangle(new SolidBrush(Color.LightYellow), new Rectangle(rect.left, rect.top + 16, width, height-30)); //Add close button and click handler // 16 pixs for the button control moCloseButton.Location = new System.Drawing.Point(rect.right - 16, rect.top); moCloseButton.AutoSize = false; moCloseButton.Click += CloseButtonClick; WINAPI.SetParent(moCloseButton.Handle, hWnd); //Adding panel to the tooltip below the header moPanel.Location = new Point(rect.left, rect.top + 16); WINAPI.SetParent(moPanel.Handle, hWnd); loGraphics = null; } return liWinProcResult; } return WINAPI.CallWindowProc(nativeProc, hWnd, iMsg, wParam, lParam); }
/// <summary> /// Shows the ballon tooltip /// </summary> /// <param name="timeout"></param> public void ShowBalloonTip(int timeout) { //Check if a balloon already is shown or no user control was defined if (moNativeWindow.Handle != IntPtr.Zero || moPanel == null) return; //Get a handle for the notify icon IntPtr loNotifyIconHandle = GetHandler(moNotifyIcon); if (loNotifyIconHandle == IntPtr.Zero) return; //Trying to find notify icon rectangle on a desktop if (!GetNotifyIconScreenRect(loNotifyIconHandle)) return; //Create parameters for a new tooltip window System.Windows.Forms.CreateParams moCreateParams = new System.Windows.Forms.CreateParams(); // New window is a tooltip and a balloon moCreateParams.ClassName = WINAPI.TOOLTIPS_CLASS; moCreateParams.Style = WINAPI.WS_POPUP | WINAPI.TTS_NOPREFIX | WINAPI.TTS_ALWAYSTIP | WINAPI.TTS_BALLOON; moCreateParams.Parent = loNotifyIconHandle; // Create the tooltip window moNativeWindow.CreateHandle(moCreateParams); //We save old window proc to be used later and replac it our own IntPtr loNativeProc = WINAPI.SetWindowLong(moNativeWindow.Handle, WINAPI.GWL_WNDPROC, wpcallback); if (loNativeProc == IntPtr.Zero) return; if (WINAPI.SetProp(moNativeWindow.Handle, "NATIVEPROC", loNativeProc) == 0) return; // Make tooltip the top level window if (!WINAPI.SetWindowPos(moNativeWindow.Handle, WINAPI.HWND_TOPMOST, 0, 0, 0, 0, WINAPI.SWP_NOACTIVATE | WINAPI.SWP_NOSIZE)) return; // Tool tip info. Set a TRACK flag to show it in specified position WINAPI.TOOLINFO ti = new WINAPI.TOOLINFO(); ti.cbSize = Marshal.SizeOf(ti); ti.uFlags = WINAPI.TTF_TRACK; ti.hwnd = loNotifyIconHandle; //Approximating window size by use of char size WINAPI.SIZE size = new WINAPI.SIZE(); IntPtr hDC = WINAPI.GetDC(moNativeWindow.Handle); if (hDC == IntPtr.Zero) return; if (WINAPI.GetTextExtentPoint32(hDC, ".", 1, ref size) == 0) return; int lines = 1 + moPanel.Height / size.cy; int cols = moPanel.Width / size.cx; ti.lpszText = "."; for (int i = 0; i < lines; i++) { for (int j = 0; j < cols; j++) ti.lpszText += "."; ti.lpszText += "\r\n"; } //Add tool to the notify icon if (WINAPI.SendMessage(moNativeWindow.Handle, WINAPI.TTM_ADDTOOL, 0, ref ti) == 0) return; WINAPI.SendMessage(moNativeWindow.Handle, WINAPI.TTM_SETTIPBKCOLOR, ColorTranslator.ToWin32(Color.LightYellow), ref ti); WINAPI.SendMessage(moNativeWindow.Handle, WINAPI.TTM_SETTIPTEXTCOLOR, ColorTranslator.ToWin32(Color.Black), ref ti); WINAPI.SendMessage(moNativeWindow.Handle, WINAPI.TTM_SETDELAYTIME, Duration.AutoPop, 1000); WINAPI.SendMessage(moNativeWindow.Handle, WINAPI.TTM_TRACKPOSITION, 0, (moPosition.Y << 16) + moPosition.X); WINAPI.SendMessage(moNativeWindow.Handle, WINAPI.TTM_SETTITLE, (int)BalloonTipIcon, BalloonTipTitle); WINAPI.SendMessage(moNativeWindow.Handle, WINAPI.TTM_TRACKACTIVATE, 1, ref ti); // Raise shown event OnBalloonTipShown(this, EventArgs.Empty); // Timeout for the tooltip moTimer.Interval = timeout; moTimer.Start(); }