Click here to Skip to main content
Click here to Skip to main content

AppBar using C#

By , 18 Apr 2004
 

Using the Code

First we must declare the needed structures and constants.
(I combine constants in enums).

We declare the RECT WINAPI structure as follows:

[StructLayout(LayoutKind.Sequential)]
struct RECT
{
    public int left;
    public int top;
    public int right;
    public int bottom;
}

We declare the APPBARDATA SHELLAPI structure as follows:

[StructLayout(LayoutKind.Sequential)]
struct APPBARDATA
{
    public int cbSize;
    public IntPtr hWnd;
    public int uCallbackMessage;
    public int uEdge;
    public RECT rc;
    public IntPtr lParam;
}

Then, we declare the AppBar related constants enums as follows:

enum ABMsg : int
{
    ABM_NEW=0,
    ABM_REMOVE,
    ABM_QUERYPOS,
    ABM_SETPOS,
    ABM_GETSTATE,
    ABM_GETTASKBARPOS,
    ABM_ACTIVATE,
    ABM_GETAUTOHIDEBAR,
    ABM_SETAUTOHIDEBAR,
    ABM_WINDOWPOSCHANGED,
    ABM_SETSTATE
}
enum ABNotify : int
{
    ABN_STATECHANGE=0,
    ABN_POSCHANGED,
    ABN_FULLSCREENAPP,
    ABN_WINDOWARRANGE
}
enum ABEdge : int
{
    ABE_LEFT=0,
    ABE_TOP,
    ABE_RIGHT,
    ABE_BOTTOM
}

Next we declare the needed WIN32 and SHELL API functions import:

[DllImport("SHELL32", CallingConvention=CallingConvention.StdCall)]
static extern uint SHAppBarMessage(int dwMessage, ref APPBARDATA pData);
[DllImport("USER32")]
static extern int GetSystemMetrics(int Index);
[DllImport("User32.dll", ExactSpelling=true, 
    CharSet=System.Runtime.InteropServices.CharSet.Auto)]
private static extern bool MoveWindow
    (IntPtr hWnd, int x, int y, int cx, int cy, bool repaint);
[DllImport("User32.dll", CharSet=CharSet.Auto)]
private static extern int RegisterWindowMessage(string msg);

The next step is creating a function to register AppBar:

private void RegisterBar()
{
    APPBARDATA abd = new APPBARDATA();
    abd.cbSize = Marshal.SizeOf(abd);
    abd.hWnd = this.Handle;
    if (!fBarRegistered)
    {
        uCallBack = RegisterWindowMessage("AppBarMessage");
        abd.uCallbackMessage = uCallBack;

        uint ret = SHAppBarMessage((int)ABMsg.ABM_NEW, ref abd);
    fBarRegistered = true;

    ABSetPos();
    }
    else
    {
    SHAppBarMessage((int)ABMsg.ABM_REMOVE, ref abd);
    fBarRegistered = false;
    }
}

The last step is to create a function to position AppBar:

private void ABSetPos()
{
    APPBARDATA abd = new APPBARDATA();
    abd.cbSize = Marshal.SizeOf(abd);
    abd.hWnd = this.Handle;
    abd.uEdge = (int)ABEdge.ABE_TOP;

    if (abd.uEdge == (int)ABEdge.ABE_LEFT || abd.uEdge == (int)ABEdge.ABE_RIGHT) 
    {
    abd.rc.top = 0;
    abd.rc.bottom = SystemInformation.PrimaryMonitorSize.Height;
    if (abd.uEdge == (int)ABEdge.ABE_LEFT) 
    {
        abd.rc.left = 0;
        abd.rc.right = Size.Width;
    }
    else 
    {
        abd.rc.right = SystemInformation.PrimaryMonitorSize.Width;
        abd.rc.left = abd.rc.right - Size.Width;
    }

    }
    else 
    {
    abd.rc.left = 0;
    abd.rc.right = SystemInformation.PrimaryMonitorSize.Width;
    if (abd.uEdge == (int)ABEdge.ABE_TOP) 
    {
        abd.rc.top = 0;
        abd.rc.bottom = Size.Height;
    }
    else 
    {
        abd.rc.bottom = SystemInformation.PrimaryMonitorSize.Height;
        abd.rc.top = abd.rc.bottom - Size.Height;
    }
    }

    SHAppBarMessage((int)ABMsg.ABM_QUERYPOS, ref abd); 

    switch (abd.uEdge) 
    { 
    case (int)ABEdge.ABE_LEFT: 
        abd.rc.right = abd.rc.left + Size.Width;
        break; 
    case (int)ABEdge.ABE_RIGHT: 
        abd.rc.left= abd.rc.right - Size.Width;
        break; 
    case (int)ABEdge.ABE_TOP: 
        abd.rc.bottom = abd.rc.top + Size.Height;
        break; 
    case (int)ABEdge.ABE_BOTTOM: 
        abd.rc.top = abd.rc.bottom - Size.Height;
        break; 
    }

    SHAppBarMessage((int)ABMsg.ABM_SETPOS, ref abd); 
    MoveWindow(abd.hWnd, abd.rc.left, abd.rc.top, 
            abd.rc.right - abd.rc.left, abd.rc.bottom - abd.rc.top, true); 
}

This is a full listing of a sample AppBar form class:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Runtime.InteropServices;

namespace Sample.AppBar
{
    /// <summary>
    /// Summary description for Form1.
    /// </summary>
    public class MainForm : System.Windows.Forms.Form
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;

        public MainForm()
        {
            //
            // Required for Windows Form Designer support
            //
            InitializeComponent();

            //
            // TODO: Add any constructor code after InitializeComponent call
            //
        }

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
            if( disposing )
            {
                if (components != null) 
                {
                    components.Dispose();
                }
            }
            base.Dispose( disposing );
        }

        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            // 
            // MainForm
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(960, 50);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
            this.Name = "MainForm";
            this.Text = "AppBar";
            this.Closing += new System.ComponentModel.CancelEventHandler(this.OnClosing);
            this.Load += new System.EventHandler(this.OnLoad);
        }
        #endregion

        #region APPBAR

        [StructLayout(LayoutKind.Sequential)]
        struct RECT
        {
            public int left;
            public int top;
            public int right;
            public int bottom;
        }

        [StructLayout(LayoutKind.Sequential)]
        struct APPBARDATA
        {
            public int cbSize;
            public IntPtr hWnd;
            public int uCallbackMessage;
            public int uEdge;
            public RECT rc;
            public IntPtr lParam;
        }

        enum ABMsg : int
        {
            ABM_NEW=0,
            ABM_REMOVE=1,
            ABM_QUERYPOS=2,
            ABM_SETPOS=3,
            ABM_GETSTATE=4,
            ABM_GETTASKBARPOS=5,
            ABM_ACTIVATE=6,
            ABM_GETAUTOHIDEBAR=7,
            ABM_SETAUTOHIDEBAR=8,
            ABM_WINDOWPOSCHANGED=9,
            ABM_SETSTATE=10
        }

        enum ABNotify : int
        {
            ABN_STATECHANGE=0,
            ABN_POSCHANGED,
            ABN_FULLSCREENAPP,
            ABN_WINDOWARRANGE
        }

        enum ABEdge : int
        {
            ABE_LEFT=0,
            ABE_TOP,
            ABE_RIGHT,
            ABE_BOTTOM
        }

        private bool fBarRegistered = false;

        [DllImport("SHELL32", CallingConvention=CallingConvention.StdCall)]
        static extern uint SHAppBarMessage(int dwMessage, ref APPBARDATA pData);
        [DllImport("USER32")]
        static extern int GetSystemMetrics(int Index);
        [DllImport("User32.dll", ExactSpelling=true, 
            CharSet=System.Runtime.InteropServices.CharSet.Auto)]
        private static extern bool MoveWindow
            (IntPtr hWnd, int x, int y, int cx, int cy, bool repaint);
        [DllImport("User32.dll", CharSet=CharSet.Auto)]
        private static extern int RegisterWindowMessage(string msg);
        private int uCallBack;

        private void RegisterBar()
        {
            APPBARDATA abd = new APPBARDATA();
            abd.cbSize = Marshal.SizeOf(abd);
            abd.hWnd = this.Handle;
            if (!fBarRegistered)
            {
                uCallBack = RegisterWindowMessage("AppBarMessage");
                abd.uCallbackMessage = uCallBack;

                uint ret = SHAppBarMessage((int)ABMsg.ABM_NEW, ref abd);
                fBarRegistered = true;

                ABSetPos();
            }
            else
            {
                SHAppBarMessage((int)ABMsg.ABM_REMOVE, ref abd);
                fBarRegistered = false;
            }
        }

        private void ABSetPos()
        {
            APPBARDATA abd = new APPBARDATA();
            abd.cbSize = Marshal.SizeOf(abd);
            abd.hWnd = this.Handle;
            abd.uEdge = (int)ABEdge.ABE_TOP;

            if (abd.uEdge == (int)ABEdge.ABE_LEFT || abd.uEdge == (int)ABEdge.ABE_RIGHT) 
            {
                abd.rc.top = 0;
                abd.rc.bottom = SystemInformation.PrimaryMonitorSize.Height;
                if (abd.uEdge == (int)ABEdge.ABE_LEFT) 
                {
                    abd.rc.left = 0;
                    abd.rc.right = Size.Width;
                }
                else 
                {
                    abd.rc.right = SystemInformation.PrimaryMonitorSize.Width;
                    abd.rc.left = abd.rc.right - Size.Width;
                }

            }
            else 
            {
                abd.rc.left = 0;
                abd.rc.right = SystemInformation.PrimaryMonitorSize.Width;
                if (abd.uEdge == (int)ABEdge.ABE_TOP) 
                {
                    abd.rc.top = 0;
                    abd.rc.bottom = Size.Height;
                }
                else 
                {
                    abd.rc.bottom = SystemInformation.PrimaryMonitorSize.Height;
                    abd.rc.top = abd.rc.bottom - Size.Height;
                }
            }

            // Query the system for an approved size and position. 
            SHAppBarMessage((int)ABMsg.ABM_QUERYPOS, ref abd); 

            // Adjust the rectangle, depending on the edge to which the 
            // appbar is anchored. 
            switch (abd.uEdge) 
            { 
                case (int)ABEdge.ABE_LEFT: 
                    abd.rc.right = abd.rc.left + Size.Width;
                    break; 
                case (int)ABEdge.ABE_RIGHT: 
                    abd.rc.left= abd.rc.right - Size.Width;
                    break; 
                case (int)ABEdge.ABE_TOP: 
                    abd.rc.bottom = abd.rc.top + Size.Height;
                    break; 
                case (int)ABEdge.ABE_BOTTOM: 
                    abd.rc.top = abd.rc.bottom - Size.Height;
                    break; 
            }

            // Pass the final bounding rectangle to the system. 
            SHAppBarMessage((int)ABMsg.ABM_SETPOS, ref abd); 

            // Move and size the appbar so that it conforms to the 
            // bounding rectangle passed to the system. 
            MoveWindow(abd.hWnd, abd.rc.left, abd.rc.top, 
                abd.rc.right - abd.rc.left, abd.rc.bottom - abd.rc.top, true); 
        }

        protected override void WndProc(ref System.Windows.Forms.Message m)
        {
            if (m.Msg == uCallBack)
            {
                switch(m.WParam.ToInt32())
                {
                    case (int)ABNotify.ABN_POSCHANGED:
                        ABSetPos();
                        break;
                }
            }

            base.WndProc(ref m);
        }

        protected override System.Windows.Forms.CreateParams CreateParams
        {
            get
            {
                CreateParams cp = base.CreateParams;
                cp.Style &= (~0x00C00000); // WS_CAPTION
                cp.Style &= (~0x00800000); // WS_BORDER
                cp.ExStyle = 0x00000080 | 0x00000008; // WS_EX_TOOLWINDOW | WS_EX_TOPMOST
                return cp;
            }
        }

        #endregion

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main() 
        {
            Application.Run(new MainForm());
        }

        private void OnLoad(object sender, System.EventArgs e)
        {
            RegisterBar();
        }

        private void OnClosing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            RegisterBar();
        }
    }
}

For more information about creating AppBars, refer to the MSDN.

P.S.

Post in comments and questions about code parts. I plan to update the article descriptions based on your questions.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Mad__
Web Developer
Ukraine Ukraine
Member
Developing software for Civilian aviation and Meteorogical offices.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionWhat is tha Best way to store data in mobile application.In Windows phone,android and nokia Mobilesgroupaamitsengar25 Apr '13 - 22:00 
I'm new here so suggest me some basics also
QuestionHow to make it Autohide?memberkilkenny9920 Dec '12 - 4:22 
This article really helped me out & I was able to make my appbar application. My question is to how to get my form to autohide?
 
I tried adding a call to SHAppBarMessage() in RegisterBar() after the ABM_NEW call but passing ABMsg.ABM_SETAUTOHIDEBAR instead, but it doesn't change any behaviour
GeneralWill this work without having explorer shelled?memberq2418130103p2 May '11 - 8:21 
Will this work without having explorer shelled?
 
Previous AppBar code I have found requires explorer to be shelled in order to make applications not maximize over the appbar.
GeneralRe: Will this work without having explorer shelled?memberVeldrik2 May '12 - 18:04 
just tried this, minimal changes as I'm sticking to a stock 2010 forms c# project.
Transparency and Translucency features for windows 7 don't work, but otherwise it all works fine. I topmost=true the form as someone else here said it helps for minimisation.
GeneralThanks...memberpuneetdhawan200019 Nov '10 - 23:28 
Thanks for the code, very useful Smile | :)
GeneralThanks, Exactly what I was looking for!memberjg00714 Jun '09 - 9:49 
this code was exactly what I wanted and combined with a scrolling text example from this site I have neerly finished the scrolling marquee project that I wanted.
Questionshould not be able to minimise AppBar when docked!memberWebermania8 Sep '08 - 3:01 
Hi Mad__,
 
First off I'd like to say thanks for this great article!
 
I noticed a problem when undocking then re-docking; The AppBar still behaves like an AppBar and reserves the working area of the screen but if you hide the desktop (by pressing the windows + D key) the AppBar minimises (disappears). If you show the desktop (by pressing the windows + D key again) it reappears. The AppBar should never be minimised when docked.
 
How can this be prevented?
 
THANKS,
Chris. W.
AnswerRe: should not be able to minimise AppBar when docked!memberRelair16 Feb '10 - 23:52 
Set TopMost to True, works for me.
Relair

GeneralExceptions encountered with .Net 2.0!memberirrdev23 Oct '07 - 0:55 
I copied the code into Visual C# 2008 Express Edition using .Net 2.0, and everything compiled fine. However, when I run my application, this function throws an exception:
 
protected override void WndProc(ref System.Windows.Forms.Message m)
{
if (m.Msg == uCallBack)
{
switch (m.WParam.ToInt32())
{
case (int)ABNotify.ABN_POSCHANGED:
ABSetPos();
break;
}
}
 
base.WndProc(ref m);
}

 
The second to last line is the problem:
base.WndProc(ref m);
It says that the parameter is incorrect. I checked the status of the variables, and "m" is correctly set to type System.Windows.Forms.Message. Also, .Net 2.0 still supports the function WndProc(ref Message m). I therefore am at a loss at where the problem is occuring. Does anyone have any ideas? Thanks!
 

GeneralRe: Exceptions encountered with .Net 2.0!memberYaroslav Trofimov22 Apr '08 - 3:03 
When got this problem, I made new project of Windows.Form and copy functional source code part. All work ideally.
GeneralThanks for the articlememberrayazax25 Apr '07 - 0:31 
It helped.
I have one problem.
I have a from that sometimes need to be a task bar and sometimes floating bar, according to what user chooses.
We need to define ExStyle as WS_EX_TOOLWINDOW in order this stuff make working, but then when my form is floating I can not do minimize to it and I don't see it at task bar.
What can I do in order to fix it?
Thanks
QuestionNot working with .NET Frame 2.0 ?memberHaggy21 Mar '06 - 0:56 
I tried to implement this code in an .NET Framework 2 Application but I got at "base.WndProc(ref m);" an InvalidArgument Exception
 
what do I have to change to got it work in .NET 2.0?
AnswerRe: Not working with .NET Frame 2.0 ?memberNeno123413 Jan '07 - 22:27 
For me it works with .NET Fx 2.0
QuestionWindows bug?membergrowse31 Oct '05 - 4:32 
I've a bug here where if my windows start bar is docked to the top, and I open a new window docked to the bottom, it moves up the window height + the height of the non-existant windows task bar at the bottom of the screen. Ie: it thinks the windows startbar is still at the bottom, so positions itself incorrectly.
 
This only happens on the primary monitor and only when the startbar is at the top.
 
Any reason for this, or is this a windows bug?
Generalgrumpfmembermofin16 Sep '05 - 3:27 
Unfortunately this AppBar can't cope with 3 monitors. It changes the user changable part of the screen from the top.
GeneralGreatsusschristos st.19 Oct '04 - 23:25 
Thanks for the great code. I have one problem: the appbar, when it appears, causes the desktop icons to shift position so that they remain visible. This has the effect of sometimes messing up the user's desktop. Icons that where close to the desktop's edge to begin with, seem to be repositioned randomly. Is it possible to not affect the position of the desktop icons so that all remain in their original place? This would mean that some icons would be hidden behind the appbar, but that's OK for me.
 
Thank you.
GeneralRe: GreatmemberMarcio Castilho25 Jan '05 - 18:52 

I guees if you don't include the flag WS_EX_TOPMOST. There might be also another flag that you can set to use the Auto-Hide feature, but I don't remember from the top of my head....
 
Thanks,
Marcio
GeneralRe: GreatmemberKeith Farmer27 Nov '05 - 10:47 
You may not understand what an appbar is, then, beyond something that docks at an edge. An appbar is a region which reduces the effective size of the desktop by removing a slice from the edge. The taskbar is an appbar -- try changing its size, and see what happens.
 
The shifting of icons is the behavior as enforced by the OS. If you don't like it, you shouldn't be using an appbar.

GeneralHmm....membermirano19 Apr '04 - 4:37 
I am not even going to bother to look into this article. No picture, no demo, not to talk about the source code...
 
.
GeneralRe: Hmm....sussAnonymous19 Apr '04 - 7:32 
No picture, no demo, no introduction, no explanation, no summary, no .... What is this article about?D'Oh! | :doh:
GeneralRe: Hmm....memberEllery19 Apr '04 - 17:58 
oh c'mon guys... he's just very... efficient.
 
intro: "how to make an appbar"
explanation: before every code block
code: ...code blocks.
pictures: ... 1x1 px somewhere Smile | :)
GeneralRe: Hmm....memberMad__19 Apr '04 - 21:12 
Dont simple say 'no picture, no demo', say what part of code you can't understand (or don't surf ADVANCED topics).
Based on this questions I planed update article whith more descriptionBig Grin | :-D
GeneralRe: Hmm....memberSirLestat20 Apr '04 - 10:39 
Could you just put a description and pic of what an AppBar is? I had to copy paste the thing and try it for myself to realize what it was. Oh and for everyone who tried the code and wonder how to close it, click on it to get the focus on it and hit Alt-F4 (if you hit stop you're stuck with a unaccesible area on your desktop)
GeneralRe: Hmm....memberRusskie22 Apr '04 - 16:06 
dude if you put smth here you could at least explain the purpose of it (or dont post it here if you are too cool to explain), or provide a downloadable demo to save us time.
GeneralRe: Hmm....memberSylfaen31 Jul '06 - 19:02 
Retards like you shouldn't put messages up on the board if they can't figure out wMad | :mad: hat something is.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130516.1 | Last Updated 19 Apr 2004
Article Copyright 2004 by Mad__
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid