Sourcecode - ApplicationDesktopToolbar
Download ApplicationDesktopToolbar.cs
//////////////////////////////////////////////// //// ApplicationDesktopToolbar //// //// Version 1.0.1 13.06.04 //// //////////////////////////////////////////////// // This class is based on http://www.codeproject.com/csharp/csdoesshell3.asp // The class was extended by Daniel Grunwald (www.danielgrunwald.de) // - fixed some bugs // - added multi-monitor support // - added Drag'n'Drop support // Known bugs: (send fixes to daniel@danielgrunwald.de!) // - The window isn't resizing back after it was undocked; I have no idea why... // - It flickers when dragging the window at the border of the screen // (so that it should stay docked) using System; using System.Runtime.InteropServices; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; namespace ShellLib { public class ApplicationDesktopToolbar : Form { #region Enums public enum AppBarMessages { /// <summary> /// Registers a new appbar and specifies the message identifier /// that the system should use to send notification messages to /// the appbar. /// </summary> New = 0x00000000, /// <summary> /// Unregisters an appbar, removing the bar from the system's /// internal list. /// </summary> Remove = 0x00000001, /// <summary> /// Requests a size and screen position for an appbar. /// </summary> QueryPos = 0x00000002, /// <summary> /// Sets the size and screen position of an appbar. /// </summary> SetPos = 0x00000003, /// <summary> /// Retrieves the autohide and always-on-top states of the /// Microsoft� Windows� taskbar. /// </summary> GetState = 0x00000004, /// <summary> /// Retrieves the bounding rectangle of the Windows taskbar. /// </summary> GetTaskBarPos = 0x00000005, /// <summary> /// Notifies the system that an appbar has been activated. /// </summary> Activate = 0x00000006, /// <summary> /// Retrieves the handle to the autohide appbar associated with /// a particular edge of the screen. /// </summary> GetAutoHideBar = 0x00000007, /// <summary> /// Registers or unregisters an autohide appbar for an edge of /// the screen. /// </summary> SetAutoHideBar = 0x00000008, /// <summary> /// Notifies the system when an appbar's position has changed. /// </summary> WindowPosChanged = 0x00000009, /// <summary> /// Sets the state of the appbar's autohide and always-on-top /// attributes. /// </summary> SetState = 0x0000000a } public enum AppBarNotifications { /// <summary> /// Notifies an appbar that the taskbar's autohide or /// always-on-top state has changed�that is, the user has selected /// or cleared the "Always on top" or "Auto hide" check box on the /// taskbar's property sheet. /// </summary> StateChange = 0x00000000, /// <summary> /// Notifies an appbar when an event has occurred that may affect /// the appbar's size and position. Events include changes in the /// taskbar's size, position, and visibility state, as well as the /// addition, removal, or resizing of another appbar on the same /// side of the screen. /// </summary> PosChanged = 0x00000001, /// <summary> /// Notifies an appbar when a full-screen application is opening or /// closing. This notification is sent in the form of an /// application-defined message that is set by the ABM_NEW message. /// </summary> FullScreenApp = 0x00000002, /// <summary> /// Notifies an appbar that the user has selected the Cascade, /// Tile Horizontally, or Tile Vertically command from the /// taskbar's shortcut menu. /// </summary> WindowArrange = 0x00000003 } [Flags] public enum AppBarStates { AutoHide = 0x00000001, AlwaysOnTop = 0x00000002 } public enum AppBarEdges { Left = 0, Top = 1, Right = 2, Bottom = 3, Float = 4 } // Window Messages public enum WM { ACTIVATE = 0x0006, WINDOWPOSCHANGED = 0x0047, NCHITTEST = 0x0084 } public enum MousePositionCodes { HTERROR = (-2), HTTRANSPARENT = (-1), HTNOWHERE = 0, HTCLIENT = 1, HTCAPTION = 2, HTSYSMENU = 3, HTGROWBOX = 4, HTSIZE = HTGROWBOX, HTMENU = 5, HTHSCROLL = 6, HTVSCROLL = 7, HTMINBUTTON = 8, HTMAXBUTTON = 9, HTLEFT = 10, HTRIGHT = 11, HTTOP = 12, HTTOPLEFT = 13, HTTOPRIGHT = 14, HTBOTTOM = 15, HTBOTTOMLEFT = 16, HTBOTTOMRIGHT = 17, HTBORDER = 18, HTREDUCE = HTMINBUTTON, HTZOOM = HTMAXBUTTON, HTSIZEFIRST = HTLEFT, HTSIZELAST = HTBOTTOMRIGHT, HTOBJECT = 19, HTCLOSE = 20, HTHELP = 21 } #endregion Enums #region AppBar Functions private Boolean AppbarNew() { if (CallbackMessageID == 0) throw new Exception("CallbackMessageID is 0"); if (IsAppbarMode) return true; m_PrevSize = Size; m_PrevLocation = Location; Console.WriteLine("Saving height {0}", m_PrevSize.Height); // prepare data structure of message ShellApi.APPBARDATA msgData = new ShellApi.APPBARDATA(); msgData.cbSize = (UInt32)Marshal.SizeOf(msgData); msgData.hWnd = Handle; msgData.uCallbackMessage = CallbackMessageID; // install new appbar UInt32 retVal = ShellApi.SHAppBarMessage((UInt32)AppBarMessages.New,ref msgData); IsAppbarMode = (retVal != 0); SizeAppBar(); return IsAppbarMode; } private Boolean AppbarRemove() { if (!IsAppbarMode) return true; // prepare data structure of message ShellApi.APPBARDATA msgData = new ShellApi.APPBARDATA(); msgData.cbSize = (UInt32)Marshal.SizeOf(msgData); msgData.hWnd = Handle; // remove appbar UInt32 retVal = ShellApi.SHAppBarMessage((UInt32)AppBarMessages.Remove,ref msgData); IsAppbarMode = false; DoResize(new Rectangle(m_PrevLocation, m_PrevSize)); Console.WriteLine("Restoring height {0}", m_PrevSize.Height); return (retVal!=0) ? true : false; } private void AppbarQueryPos(ref ShellApi.RECT appRect) { // prepare data structure of message ShellApi.APPBARDATA msgData = new ShellApi.APPBARDATA(); msgData.cbSize = (UInt32)Marshal.SizeOf(msgData); msgData.hWnd = Handle; msgData.uEdge = (UInt32)m_Edge; msgData.rc = appRect; // query postion for the appbar ShellApi.SHAppBarMessage((UInt32)AppBarMessages.QueryPos, ref msgData); appRect = msgData.rc; } private void AppbarSetPos(ref ShellApi.RECT appRect) { // prepare data structure of message ShellApi.APPBARDATA msgData = new ShellApi.APPBARDATA(); msgData.cbSize = (UInt32)Marshal.SizeOf(msgData); msgData.hWnd = Handle; msgData.uEdge = (UInt32)m_Edge; msgData.rc = appRect; // set postion for the appbar ShellApi.SHAppBarMessage((UInt32)AppBarMessages.SetPos, ref msgData); appRect = msgData.rc; } private void AppbarActivate() { // prepare data structure of message ShellApi.APPBARDATA msgData = new ShellApi.APPBARDATA(); msgData.cbSize = (UInt32)Marshal.SizeOf(msgData); msgData.hWnd = Handle; // send activate to the system ShellApi.SHAppBarMessage((UInt32)AppBarMessages.Activate, ref msgData); } private void AppbarWindowPosChanged() { // prepare data structure of message ShellApi.APPBARDATA msgData = new ShellApi.APPBARDATA(); msgData.cbSize = (UInt32)Marshal.SizeOf(msgData); msgData.hWnd = Handle; // send windowposchanged to the system ShellApi.SHAppBarMessage((UInt32)AppBarMessages.WindowPosChanged, ref msgData); } private Boolean AppbarSetAutoHideBar(Boolean hideValue) { // prepare data structure of message ShellApi.APPBARDATA msgData = new ShellApi.APPBARDATA(); msgData.cbSize = (UInt32)Marshal.SizeOf(msgData); msgData.hWnd = Handle; msgData.uEdge = (UInt32)m_Edge; msgData.lParam = (hideValue) ? 1 : 0; // set auto hide UInt32 retVal = ShellApi.SHAppBarMessage((UInt32)AppBarMessages.SetAutoHideBar,ref msgData); return (retVal!=0) ? true : false; } private IntPtr AppbarGetAutoHideBar(AppBarEdges edge) { // prepare data structure of message ShellApi.APPBARDATA msgData = new ShellApi.APPBARDATA(); msgData.cbSize = (UInt32)Marshal.SizeOf(msgData); msgData.uEdge = (UInt32)edge; // get auto hide IntPtr retVal = (IntPtr)ShellApi.SHAppBarMessage((UInt32)AppBarMessages.GetAutoHideBar,ref msgData); return retVal; } private AppBarStates AppbarGetTaskbarState() { // prepare data structure of message ShellApi.APPBARDATA msgData = new ShellApi.APPBARDATA(); msgData.cbSize = (UInt32)Marshal.SizeOf(msgData); // get taskbar state UInt32 retVal = ShellApi.SHAppBarMessage((UInt32)AppBarMessages.GetState, ref msgData); return (AppBarStates)retVal; } private void AppbarSetTaskbarState(AppBarStates state) { // prepare data structure of message ShellApi.APPBARDATA msgData = new ShellApi.APPBARDATA(); msgData.cbSize = (UInt32)Marshal.SizeOf(msgData); msgData.lParam = (Int32)state; // set taskbar state ShellApi.SHAppBarMessage((UInt32)AppBarMessages.SetState, ref msgData); } private void AppbarGetTaskbarPos(out ShellApi.RECT taskRect) { // prepare data structure of message ShellApi.APPBARDATA msgData = new ShellApi.APPBARDATA(); msgData.cbSize = (UInt32)Marshal.SizeOf(msgData); // get taskbar position ShellApi.SHAppBarMessage((UInt32)AppBarMessages.GetTaskBarPos, ref msgData); taskRect = msgData.rc; } #endregion AppBar Functions #region Private Variables // saves the current edge private AppBarEdges m_Edge = AppBarEdges.Float; // saves the callback message id private UInt32 CallbackMessageID = 0; // are we in dock mode? private Boolean IsAppbarMode = false; // save the floating size and location private Size m_PrevSize; private Point m_PrevLocation; #endregion Private Variables public ApplicationDesktopToolbar() { FormBorderStyle = FormBorderStyle.SizableToolWindow; // Register a unique message as our callback message CallbackMessageID = RegisterCallbackMessage(); if (CallbackMessageID == 0) throw new Exception("RegisterCallbackMessage failed"); } private UInt32 RegisterCallbackMessage() { String uniqueMessageString = Guid.NewGuid().ToString(); return ShellApi.RegisterWindowMessage(uniqueMessageString); } protected override void OnMove(EventArgs e) { if (!internalResizing) { Point mousePos = Control.MousePosition; Screen screen = Screen.FromPoint(mousePos); targetScreen = screen; if (mousePos.X >= screen.Bounds.X && mousePos.X < screen.Bounds.X + 15) Edge = AppBarEdges.Left; else if (mousePos.Y >= screen.Bounds.Y && mousePos.Y < screen.Bounds.Y + 15) Edge = AppBarEdges.Top; else if (mousePos.X <= screen.Bounds.Right && mousePos.X > screen.Bounds.Right - 15) Edge = AppBarEdges.Right; else if (mousePos.Y <= screen.Bounds.Bottom && mousePos.Y > screen.Bounds.Bottom - 15) Edge = AppBarEdges.Bottom; else Edge = AppBarEdges.Float; } if (IsAppbarMode && !internalResizing) { internalResizing = true; Location = viewLocation; internalResizing = false; } else { base.OnMove (e); } } private void SizeAppBar() { if (!IsAppbarMode) return; ShellApi.RECT rt = new ShellApi.RECT(); if ((m_Edge == AppBarEdges.Left) || (m_Edge == AppBarEdges.Right)) { rt.top = targetScreen.Bounds.Top; rt.bottom = targetScreen.Bounds.Bottom; if (m_Edge == AppBarEdges.Left) { rt.left = targetScreen.Bounds.Left; rt.right = m_PrevSize.Width + rt.left; } else { rt.right = targetScreen.Bounds.Right; rt.left = rt.right - m_PrevSize.Width; } } else { rt.left = targetScreen.Bounds.Left; rt.right = targetScreen.Bounds.Right; if (m_Edge == AppBarEdges.Top) { rt.top = targetScreen.Bounds.Top; rt.bottom = m_PrevSize.Height + targetScreen.Bounds.Top; } else { rt.bottom = targetScreen.Bounds.Bottom; rt.top = rt.bottom - m_PrevSize.Height; } } AppbarQueryPos(ref rt); switch (m_Edge) { case AppBarEdges.Left: rt.right = rt.left + m_PrevSize.Width; break; case AppBarEdges.Right: rt.left= rt.right - m_PrevSize.Width; break; case AppBarEdges.Top: rt.bottom = rt.top + m_PrevSize.Height; break; case AppBarEdges.Bottom: rt.top = rt.bottom - m_PrevSize.Height; break; } AppbarSetPos(ref rt); if (!IsAppbarMode) return; viewLocation = new Point(rt.left,rt.top); DoResize(new Rectangle(viewLocation, new Size(rt.right - rt.left, rt.bottom - rt.top))); Console.WriteLine("Setting size (AppbarMode = {0}, Edge = {1})", IsAppbarMode, m_Edge); } Point viewLocation; void DoResize(Rectangle bounds) { if (internalResizing) throw new Exception("Double call of DoResize!"); internalResizing = true; Bounds = bounds; internalResizing = false; } bool internalResizing; #region Message Handlers void OnAppbarNotification(ref Message msg) { AppBarStates state; AppBarNotifications msgType = (AppBarNotifications)(Int32)msg.WParam; switch (msgType) { case AppBarNotifications.PosChanged: SizeAppBar(); break; case AppBarNotifications.StateChange: state = AppbarGetTaskbarState(); if ((state & AppBarStates.AlwaysOnTop) !=0) { TopMost = true; BringToFront(); } else { TopMost = false; SendToBack(); } break; case AppBarNotifications.FullScreenApp: if ((int)msg.LParam !=0) { TopMost = false; SendToBack(); } else { state = AppbarGetTaskbarState(); if ((state & AppBarStates.AlwaysOnTop) !=0) { TopMost = true; BringToFront(); } else { TopMost = false; SendToBack(); } } break; case AppBarNotifications.WindowArrange: if ((int)msg.LParam != 0) // before Visible = false; else // after Visible = true; break; } } #endregion Message Handlers #region Window Procedure protected override void WndProc(ref Message msg) { if (IsAppbarMode) { if (msg.Msg == CallbackMessageID) { OnAppbarNotification(ref msg); } else if (msg.Msg == (int)WM.ACTIVATE) { AppbarActivate(); } else if (msg.Msg == (int)WM.WINDOWPOSCHANGED) { AppbarWindowPosChanged(); } else if (msg.Msg == (int)WM.NCHITTEST) { OnNcHitTest(ref msg); return; } } base.WndProc(ref msg); } #endregion Window Procedure void OnNcHitTest(ref Message msg) { DefWndProc(ref msg); if ((m_Edge == AppBarEdges.Top) && ((int)msg.Result == (int)MousePositionCodes.HTBOTTOM)) 0.ToString(); else if ((m_Edge == AppBarEdges.Bottom) && ((int)msg.Result == (int)MousePositionCodes.HTTOP)) 0.ToString(); else if ((m_Edge == AppBarEdges.Left) && ((int)msg.Result == (int)MousePositionCodes.HTRIGHT)) 0.ToString(); else if ((m_Edge == AppBarEdges.Right) && ((int)msg.Result == (int)MousePositionCodes.HTLEFT)) 0.ToString(); else if ((int)msg.Result == (int)MousePositionCodes.HTCLOSE) 0.ToString(); else if ((int)msg.Result == (int)MousePositionCodes.HTCAPTION) 0.ToString(); else { msg.Result = (IntPtr)MousePositionCodes.HTCLIENT; return; } base.WndProc(ref msg); } protected override void OnLoad(EventArgs e) { m_PrevSize = Size; m_PrevLocation = Location; base.OnLoad(e); } protected override void OnClosing(CancelEventArgs e) { AppbarRemove(); base.OnClosing(e); } protected override void OnSizeChanged(EventArgs e) { if (IsAppbarMode && !internalResizing) { if (m_Edge == AppBarEdges.Top || m_Edge == AppBarEdges.Bottom) m_PrevSize.Height = Size.Height; else m_PrevSize.Width = Size.Width; SizeAppBar(); } base.OnSizeChanged(e); } Screen targetScreen = Screen.PrimaryScreen; public AppBarEdges Edge { get { return m_Edge; } set { if (m_Edge == value) return; if (internalResizing) throw new Exception("Edge may not be changed while the Toolbar is resizing"); m_Edge = value; Console.WriteLine("Edge = {0}", value); if (value == AppBarEdges.Float) AppbarRemove(); else AppbarNew(); if (IsAppbarMode) SizeAppBar(); } } } }