问题提出:对于普通应用程序,我们很多时候会将窗口最小化到系统托盘。当我们点击这个托盘图标时,可能会弹出一些友好的提示界面,可以恰当的进行一些操作。
一般情况下,我们可能粗暴的将这个友好提示界面放置在桌面的右下角,对于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;
一个简单的C++代码:
- 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.
- }
- ...
- }
C#代码:
功能:
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
- }
- /// <summary>
- /// Retrieve current task bar's position info.
- /// </summary>
- /// <param name="taskbarRect">Current task bar's rectangle.</param>
- /// <param name="eTaskbarEdge">Current task bar's edge.</param>
- /// <param name="eTaskbarState">Current task bar's state.</param>
- 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);
- }
- }
- /// <summary>
- /// Initialize the popup window's position.
- /// </summary>
- /// <returns></returns>
- 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;
- }
- }
- /// <summary>
- /// Whether the current UI culture is middle country or not.
- /// </summary>
- /// <returns>Return true or false.</returns>
- 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;
- }