Using the Code
First we must declare the needed structures and constants.
(I combine constants in enum
s).
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 enum
s 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
{
public class MainForm : System.Windows.Forms.Form
{
private System.ComponentModel.Container components = null;
public MainForm()
{
InitializeComponent();
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
private void InitializeComponent()
{
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;
}
}
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);
}
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);
cp.Style &= (~0x00800000);
cp.ExStyle = 0x00000080 | 0x00000008;
return cp;
}
}
#endregion
[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 AppBar
s, 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.