问题提出:对于普通应用程序,我们很多时候会将窗口最小化到系统托盘。当我们点击这个托盘图标时,可能会弹出一些友好的提示界面,可以恰当的进行一些操作。 一般情况下,我们可能粗暴的将这个友好提示界面放置在桌面的右下角,对于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; }