问题提出:对于普通应用程序,我们很多时候会将窗口最小化到系统托盘。当我们点击这个托盘图标时,可能会弹出一些友好的提示界面,可以恰当的进行一些操作。
一般情况下,我们可能粗暴的将这个友好提示界面放置在桌面的右下角,对于XP,这是OK的,因为XP不允许我们将任务栏拖动到桌面的上、左、右三个方向,
只允许停靠下桌面的最下方,但是对于win7,我们便需要考虑到其它三个方向,再根据这个方向确定好提示界面放的位置。那么,如何获得任务栏的位置及相关信息?
windows提供了相关和API进行操作。
UINT_PTR SHAppBarMessage(
DWORD dwMessage,
PAPPBARDATA pData
);
其中
dwMessage为发送给system的消息。
pData为一个APPBARDATA结构体,用于存储发送或者返回的数据。
dwMessage只能为以下的其中一个值。
ABM_ACTIVATE:告知系统任务栏被激活。
ABM_GETAUTOHIDEBAR:查询任务栏是否是自动隐藏(前提是要给出任务栏停靠的位置)。
ABM_GETSTATE:查询任务栏自动隐藏和总是牌处于顶层的状态。
ABM_GETTASKBARPOS:获取任务栏的边界矩形位置。
ABM_QUERYPOS:请求任务栏的位置。(上、下、左、右)
其它状态略。
ABM_NEW、ABM_REMOVE、ABM_SETAUTOHIDEBAR、ABM_SETPOS、ABM_SETSTATE、ABM_WINDOWPOSCHANGED
typedef struct _AppBarData {
DWORD cbSize; // The size of the structure, in bytes.
HWND hWnd; // The handle to the appbar window.
UINT uCallbackMessage; // An application-defined message identifier.This member is used when sending the ABM_NEW message.
UINT uEdge; // 边界位置,有4种:ABE_BOTTOM、ABE_LEFT、ABE_RIGHT、ABE_TOP
RECT rc; // 任务栏的边界矩形位置。
LPARAM lParam; // This member is used with the ABM_SETAUTOHIDEBAR and ABM_SETSTATE messages.
} APPBARDATA, *PAPPBARDATA;
HWND hwnd = FindWindow(L"Shell_TrayWnd", L"");
if (hwnd != NULL)
{
APPBARDATA abd = { sizeof(APPBARDATA) };
abd.hWnd = hwnd;
BOOL bRt = SHAppBarMessage(ABM_GETTASKBARPOS, &abd); // 此处能够获取位置和矩形
UINT uState = (UINT) SHAppBarMessage(ABM_GETSTATE, &abd); // 此处也可以使用ABM_GETAUTOHIDEBAR来获取
if (0 == uState)
{
// 0: Taskbar is neither in the auto-hide nor always-on-top state.
// 1: ABS_AUTOHIDE The taskbar is in the auto-hide state.
// 2: ABS_ALWAYSONTOP The taskbar is in the always-on-top state.
}
...
}
功能:
1. 获取taskbar的位置
2. 计算出所放窗口的位置
首先需要引入API及相关宏和结构体:
[DllImport("shell32.dll")]
public static extern IntPtr SHAppBarMessage(uint dwMessage, ref APPBARDATA pData);
public enum AppBarMessages
{
New = 0x00000000,
Remove = 0x00000001,
QueryPos = 0x00000002,
SetPos = 0x00000003,
GetState = 0x00000004,
GetTaskBarPos = 0x00000005,
Activate = 0x00000006,
GetAutoHideBar = 0x00000007,
SetAutoHideBar = 0x00000008,
WindowPosChanged = 0x00000009,
SetState = 0x0000000a
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int _Left;
public int _Top;
public int _Right;
public int _Bottom;
}
[StructLayout(LayoutKind.Sequential)]
public struct APPBARDATA
{
public int cbSize;
public IntPtr hWnd;
public uint uCallbackMessage;
public uint uEdge;
public RECT rc;
public int lParam;
}
public enum AppBarStates
{
AutoHide = 0x00000001,
AlwaysOnTop = 0x00000002
}
public enum AppBarEdge
{
ABE_LEFT = 0,
ABE_TOP = 1,
ABE_RIGHT = 2,
ABE_BOTTOM = 3
}
///
/// Retrieve current task bar's position info.
///
/// Current task bar's rectangle.
/// Current task bar's edge.
/// Current task bar's state.
public void GetTaskbarPosInfo(
ref Rectangle taskbarRect,
ref Win32API.AppBarEdge eTaskbarEdge,
ref Win32API.AppBarStates eTaskbarState)
{
eTaskbarState = Win32API.AppBarStates.AlwaysOnTop; // Init default state
IntPtr hTaskBarWnd = Win32API.FindWindow("Shell_TrayWnd", "");
if (hTaskBarWnd != null)
{
Win32API.APPBARDATA abd = new Win32API.APPBARDATA();
abd.cbSize = Marshal.SizeOf(typeof(Win32API.APPBARDATA));
Win32API.SHAppBarMessage((uint)(Win32API.AppBarMessages.GetTaskBarPos), ref abd);
eTaskbarEdge = (Win32API.AppBarEdge)(abd.uEdge);
IntPtr hTmpWnd = Win32API.SHAppBarMessage((uint)(Win32API.AppBarMessages.GetAutoHideBar), ref abd);
if (0 != hTmpWnd.ToInt64())
{
eTaskbarState = Win32API.AppBarStates.AutoHide;
}
taskbarRect = Rectangle.FromLTRB(abd.rc._Left, abd.rc._Top, abd.rc._Right, abd.rc._Bottom);
}
}
///
/// Initialize the popup window's position.
///
///
private void InitialPosition()
{
Rectangle taskbarRect = new Rectangle();
Win32API.AppBarEdge eTaskbarEdge = new Win32API.AppBarEdge();
Win32API.AppBarStates eTaskbarState = new Win32API.AppBarStates();
Win32API.GetTaskbarPosInfo(ref taskbarRect, ref eTaskbarEdge, ref eTaskbarState);
int nSceenWidth = (int)Math.Ceiling(SystemParameters.VirtualScreenWidth);
int nSceenHeight = (int)Math.Ceiling(SystemParameters.VirtualScreenHeight);
// Whether current UI language is Middle East country language.
// Because the Middle East country' user is right handed, so the popup window's position
// is different with normal when task bar is in TOP and BOTTOM status.
bool isMiddleEastLanguage = IsMiddleEastLanguage();
bool isTaskBarHide = (Win32API.AppBarStates.AutoHide == eTaskbarState) ? true : false;
switch (eTaskbarEdge)
{
case Win32API.AppBarEdge.ABE_LEFT:
this.Left = isTaskBarHide ? taskbarRect.Left : (taskbarRect.Right);
this.Top = nSceenHeight - this.Height;
break;
case Win32API.AppBarEdge.ABE_TOP:
this.Left = !isMiddleEastLanguage ? (taskbarRect.Right - this.Width) : taskbarRect.Left;
this.Top = isTaskBarHide ? taskbarRect.Top : (taskbarRect.Bottom);
break;
case Win32API.AppBarEdge.ABE_RIGHT:
this.Left = isTaskBarHide ? (taskbarRect.Right - this.Width) : (taskbarRect.Left - this.Width);
this.Top = (nSceenHeight - this.Height)/*(1 == rightHanded) ? (nSceenHeight - this.Height) : (0)*/;
break;
default:
this.Left = !isMiddleEastLanguage ? (taskbarRect.Right - this.Width) : taskbarRect.Left;
this.Top = isTaskBarHide ? (taskbarRect.Bottom - this.Height) : (taskbarRect.Top - this.Height);
break;
}
}
///
/// Whether the current UI culture is middle country or not.
///
/// Return true or false.
private bool IsMiddleEastLanguage()
{
string cultureName = System.Globalization.CultureInfo.CurrentUICulture.Name;
string mainLanguage = cultureName.Substring(0, 2);
if (mainLanguage.Equals("ar") || mainLanguage.Equals("he"))
{
return true;
}
return false;
}