首页  编辑  

实现应用程序桌面任务栏

Tags: /超级猛料/VCL/Control.控件使用开发和第三方控件/自定义控件/   Date Created:

//****************************************************************************

// 说明:

//  实现应用程序桌面任务栏。(参考J.Richters CAppBar MFC Class)

//版权:

//  版权 (c) 1997/98 Paolo Giacomuzzi

//EMail:

//  MailTo:paolo.giacomuzzi@usa.net

//主页:

//  http://www.geocities.com/SiliconValley/9486

//版本:

//  1.5

//修改时间:

//  杨军 于 2001.11.19

//****************************************************************************

unit AppBar;

interface

uses

 Windows, Messages, SysUtils, Classes, Forms, Dialogs, Controls, ExtCtrls,

 ShellApi, Registry,StrFuncs;

const

 // AppBars user notification message

 WM_APPBARNOTIFY = WM_USER + 100;

 // Timer interval

 SLIDE_DEF_TIMER_INTERVAL = 400; // milliseconds

 // Defaults

 AB_DEF_SIZE_INC = 1;

 AB_DEF_DOCK_SIZE = 32;

 AB_DEF_ROOT_KEY = HKEY_CURRENT_USER;

 AB_DEF_KEY_NAME = Software\IMISoIP;

type

 //应用程序工具栏异常处理类

 AppBarExcption = class(TonyException)

 end;

 //***********************************************************************

 //说明:

 // You can send to the Windows shell one of the following messages:

 // - Message             Description

 // * ABM_NEW             Register a new AppBar to the system

 // * ABM_REMOVE          Remove a previously created AppBar from the system

 // * ABM_QUERYPOS        Query the AppBar position

 // * ABM_SETPOS          Set the AppBar position

 // * ABM_GETSTATE        Get the edge the Appbar is docked to

 // * ABM_GETTASKBARPOS   Get the Explorer Taskbar position

 // * ABM_ACTIVATE        Activate the AppBar

 // * ABM_GETAUTOHIDEBAR  Query if AppBar has Auto-hide behavior

 // * ABM_SETAUTOHIDEBAR  Set the AppBars Auto-hide behavior

 // The ABM_message constants are defined in SHELLAPI.PAS as follows:

 // * ABM_NEW              = $00000000;

 // * ABM_REMOVE           = $00000001;

 // * ABM_QUERYPOS         = $00000002;

 // * ABM_SETPOS           = $00000003;

 // * ABM_GETSTATE         = $00000004;

 // * ABM_GETTASKBARPOS    = $00000005;

 // * ABM_ACTIVATE         = $00000006;

 // * ABM_GETAUTOHIDEBAR   = $00000007;

 // * ABM_SETAUTOHIDEBAR   = $00000008;

 // * ABM_WINDOWPOSCHANGED = $00000009;

 //概述:

 // 这个枚举类型定义了Windows Appbar Message的常量。

 TAppBarMessage = (abmNew, abmRemove, abmQueryPos, abmSetPos, abmGetState,

   abmGetTaskBarPos, abmActivate, abmGetAutoHideBar,

   abmSetAutoHideBar, abmWindowPosChanged);

 //说明:

 // An AppBar can be in one of 6 states shown in the table below:

 // - State          Description

 // * ABE_UNKNOWN    The Appbar is in an unknown state

 // *                (usually during construction/destruction)

 // * ABE_FLOAT      The AppBar is floating on the screen

 // * ABE_LEFT       The Appbar is docked on the left   edge of the screen

 // * ABE_TOP        The Appbar is docked on the top    edge of the screen

 // * ABE_RIGHT      The Appbar is docked on the right  edge of the screen

 // * ABE_BOTTOM     The Appbar is docked on the bottom edge of the screen

 // The ABE_edge state constants are defined in SHELLAPI.PAS as follows:

 // * ABE_LEFT    = 0;

 // * ABE_TOP     = 1;

 // * ABE_RIGHT   = 2;

 // * ABE_BOTTOM  = 3;

 // The ABE_UNKNOWN and ABE_FLOAT constants are defined here as follows:

 // * ABE_UNKNOWN = 4;

 // * ABE_FLOAT   = 5;

 //概述:

 // 该枚举类型定义了Appbar的6种状态,每种状态是互斥的。

 TAppBarEdge = (abeLeft, abeTop, abeRight, abeBottom, abeUnknown, abeFloat);

 //说明:

 // An AppBar can have several behavior flags as shown below:

 // - Flag                        Description

 // * ABF_ALLOWLEFT               Allow dock on left   of screen

 // * ABF_ALLOWRIGHT              Allow dock on right  of screen

 // * ABF_ALLOWTOP                Allow dock on top    of screen

 // * ABF_ALLOWBOTTOM             Allow dock on bottom of screen

 // * ABF_ALLOWFLOAT              Allow float in the middle of screen

 //概述:

 // 这个枚举类型定义了Appbar的行为标记。

 TAppBarFlag = (abfAllowLeft, abfAllowTop, abfAllowRight, abfAllowBottom,

   abfAllowFloat);

 //概述:

 //    Appbar的行为表积集合。

 TAppBarFlags = set of TAppBarFlag;

 //概述:

 // 这个枚举类型定义了Appbar在任务栏上的行为。

 TAppBarTaskEntry = (abtShow, abtHide, abtFloatDependent);

 //概述:

 // The record below contains all of the AppBar settings that

 // can be saved/loaded in/from the Registry

 TAppBarSettings = record

   Size: DWORD; // Size of this structure

   abEdge: TAppBarEdge; // ABE_UNKNOWN, ABE_FLOAT, or ABE_edge

   Flags: TAppBarFlags; // ABF_* flags

   Autohide: Boolean; // Should AppBar be auto-hidden when docked?

   AlwaysOnTop: Boolean; // Should AppBar always be on top?

   SlideEffect: Boolean; // Should AppBar slide?

   TimerInterval: Integer; // Slide Timer Interval (determines speed)

   SizeInc: TSize; // Discrete width/height size increments

   DockSize: TSize; // Width/Height for docked bar

   FloatRect: TRect; // Floating rectangle in screen coordinates

   MinWidth: Integer; // Min allowed width

   MinHeight: Integer; // Min allowed height

   MaxWidth: Integer; // Max allowed width

   MaxHeight: Integer; // Max allowed height

   MinDockSize: TSize; // Min Width/Height when docked

   MaxDockSize: TSize; // Max Width/Height when docked

   TaskEntry: TAppBarTaskEntry; // AppBar behavior in the Taskbar

 end;

 //概述

 // The record below contains the settings location in the registry

 TAppBarSettingsLocation = record

   RootKey: Cardinal; // HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE

   KeyName: string; // Key Name starting from root

 end;

 //概述:

 // TAppBar class 派生于TForm。

 TAppBar = class(TForm)

 private

   { Internal implementation state variables }

   // This AppBars settings info

   FABSetting: TAppBarSettings;

   // We need a member variable to store the settings location in the registry

   FSettingsLocation: TAppBarSettingsLocation;

   // We need a member variable which tracks the proposed edge of the

   // AppBar while the user is moving it, deciding where to position it.

   // While not moving, this member must contain ABE_UNKNOWN so that

   // GetEdge returns the current edge contained in 属性 Options.abEdge.

   // While moving the AppBar, FabEdgeProposedPrev contains the

   // proposed edge based on the position of the AppBar.  The proposed

   // edge becomes the new edge when the user stops moving the AppBar.

   FabEdgeProposedPrev: TAppBarEdge;

   // We need a member variable which tracks whether a full screen

   // application window is open

   FbFullScreenAppOpen: Boolean;

   // We need a member variable which tracks whether our autohide window

   // is visible or not

   FbAutoHideIsVisible: Boolean;

   // We need a timer to to determine when the AppBar should be re-hidden

   FTimer: TTimer;

   { Internal implementation functions }

     // Modifies window creation flags

   procedure CreateParams(var Params: TCreateParams); override;

   // These functions encapsulate the shells SHAppBarMessage function

   function AppBarMessage(abMessage: TAppBarMessage;

     abEdge: TAppBarEdge;

     lParam: LPARAM;

     bRect: Boolean;

     var rc: TRect): UINT;

   function AppBarMessage1(abMessage: TAppBarMessage): UINT;

   function AppBarMessage2(abMessage: TAppBarMessage;

     abEdge: TAppBarEdge): UINT;

   function AppBarMessage3(abMessage: TAppBarMessage;

     abEdge: TAppBarEdge;

     lParam: LPARAM): UINT;

   function AppBarMessage4(abMessage: TAppBarMessage;

     abEdge: TAppBarEdge;

     lParam: LPARAM;

     var rc: TRect): UINT;

   // Gets a edge (ABE_FLOAT or ABE_edge) from a point (screen coordinates)

   function CalcProposedState(var pt: TSmallPoint): TAppBarEdge;

   // Gets a retangle position (screen coordinates) from a proposed state

   procedure GetRect(abEdgeProposed: TAppBarEdge; var rcProposed: TRect);

   // Adjusts the AppBars location to account for autohide

   // Returns TRUE if rectangle was adjusted

   function AdjustLocationForAutohide(bShow: Boolean;

     var rc: TRect): Boolean;

   // If AppBar is Autohide and docked, shows/hides the AppBar

   procedure ShowHiddenAppBar(bShow: Boolean);

   // When Autohide AppBar is shown/hidden, slides in/out of view

   procedure SlideWindow(var rcEnd: TRect);

   // Returns which edge were autohidden on or ABE_UNKNOWN

   function GetAutohideEdge: TAppBarEdge;

   // Returns a TSmallPoint that gives the cursor position in screen coords

   function GetMessagePosition: TSmallPoint;

   // Changes the style of a window (translated from AfxModifyStyle)

   function ModifyStyle(hWnd: THandle;

     nStyleOffset: Integer;

     dwRemove: DWORD;

     dwAdd: DWORD;

     nFlags: UINT): Boolean;

 protected

   { Property selector functions }

   BarIndent: Integer;

   procedure AdjustClientRect(var Rect: TRect); override;

   function CheckBoundsRect(var rc: TRect): boolean; virtual;

   // Retrieves the AppBars edge.  If the AppBar is being positioned, its

   // proposed state is returned instead

   function GetEdge: TAppBarEdge;

   // Changes the AppBars edge to ABE_UNKNOWN, ABE_FLOAT or an ABE_edge

   procedure SetEdge(EdgeValue: TAppBarEdge);

   // Changes the slide time interval

   procedure SetSlideTime(nInterval: Integer);

   { Overridable functions }

   // Called when the AppBars proposed state changes

   procedure OnAppBarStateChange(bProposed: Boolean;

     abEdgeProposed: TAppBarEdge); virtual;

   // Called if user attempts to dock an Autohide AppBar on

   // an edge that already contains an Autohide AppBar

   procedure OnAppBarForcedToDocked; virtual;

   // Called when AppBar gets an ABN_FULLSCREENAPP notification

   procedure OnABNFullScreenApp(bOpen: Boolean); virtual;

   // Called when AppBar gets an ABN_POSCHANGED notification

   procedure OnABNPosChanged; virtual;

   // Called when AppBar gets an ABN_WINDOWARRANGE notification

   procedure OnABNWindowArrange(bBeginning: Boolean); virtual;

   { Message handlers }

   // Called when the AppBar receives a WM_APPBARNOTIFY window message

   procedure OnAppBarCallbackMsg(var Msg: TMessage); message WM_APPBARNOTIFY;

   // Called when the AppBar form is first created

   procedure OnCreate(var Msg: TWMCreate); message WM_CREATE;

   // Called when the AppBar form is about to be destroyed

   procedure OnDestroy(var Msg: TWMDestroy); message WM_DESTROY;

   // Called when the AppBar receives a WM_WINDOWPOSCHANGED message

   procedure OnWindowPosChanged(var Msg: TWMWindowPosChanged);

     message WM_WINDOWPOSCHANGED;

   // Called when the AppBar receives a WM_ACTIVATE message

   procedure OnActivate(var Msg: TWMActivate); message WM_ACTIVATE;

   // Called every timer tick

   procedure OnAppBarTimer(Sender: TObject);

   // Called when the AppBar receives a WM_NCMOUSEMOVE message

   procedure OnNcMouseMove(var Msg: TWMNCMouseMove); message WM_NCMOUSEMOVE;

   // Called when the AppBar receives a WM_NCHITTEST message

   procedure OnNcHitTest(var Msg: TWMNCHitTest); message WM_NCHITTEST;

   // Called when the AppBar receives a WM_ENTERSIZEMOVE message

   procedure OnEnterSizeMove(var Msg: TMessage); message WM_ENTERSIZEMOVE;

   // Called when the AppBar receives a WM_EXITSIZEMOVE message

   procedure OnExitSizeMove(var Msg: TMessage); message WM_EXITSIZEMOVE;

   // Called when the AppBar receives a WM_MOVING message

   procedure OnMoving(var Msg: TMessage); message WM_MOVING;

   // Called when the AppBar receives a WM_SIZING message

   procedure OnSizing(var Msg: TMessage); message WM_SIZING;

   // Called when the AppBar receives a WM_GETMINMAXINFO message

   procedure OnGetMinMaxInfo(var Msg: TWMGetMinMaxInfo);

     message WM_GETMINMAXINFO;

   { AppBar-specific helper functions }

   // Returns TRUE if abEdge is ABE_LEFT or ABE_RIGHT, else FALSE is returned

   function IsEdgeLeftOrRight(abEdge: TAppBarEdge): Boolean;

   // Returns TRUE if abEdge is ABE_TOP or ABE_BOTTOM, else FALSE is returned

   function IsEdgeTopOrBottom(abEdge: TAppBarEdge): Boolean;

   // Returns TRUE if abEdge is ABE_FLOAT, else FALSE is returned

   function IsFloating(abEdge: TAppBarEdge): Boolean;

   // Returns TRUE if abFlags contain an at least allowed edge to dock on

   function IsDockable(abFlags: TAppBarFlags): Boolean;

   // Returns TRUE if abFlags contain abfAllowLeft and abfAllowRight

   function IsDockableVertically(abFlags: TAppBarFlags): Boolean;

   // Returns TRUE if abFlags contain abfAllowTop and abfAllowBottom

   function IsDockableHorizontally(abFlags: TAppBarFlags): Boolean;

   // Forces the shell to update its AppBar list and the workspace area

   procedure ResetSystemKnowledge;

   // Returns a proposed edge or ABE_FLOAT based on ABF_* flags and a

   // point specified in screen coordinates

   function GetEdgeFromPoint(abFlags: TAppBarFlags;

     pt: TSmallPoint): TAppBarEdge;

 public

   { Public member functions }

     // Constructs an AppBar

   constructor Create(Owner: TComponent); override;

   // Destroys a previously created AppBar

   destructor Destroy; override;

   // Forces the AppBars visual appearance to match its internal state

   procedure UpdateBar; virtual;

   // Loads settings from the registry at RootKey and KeyName location.

   // Returns TRUE if the settings are available, else FALSE

   function LoadSettings: Boolean; virtual;

   // Saves settings into the registry at RootKey and KeyName location.

   // Returns TRUE if succeeded, else FALSE

   function SaveSettings: Boolean; virtual;

 published

   { Properties }

   //参数表

   property Options: TAppBarSettings read FABSetting write FABSetting;

   // store the settings location in the registry

   property LocationSetting: TAppBarSettingsLocation read FSettingsLocation

     write FSettingsLocation;

   // Edge to dock on

   property Edge: TAppBarEdge read GetEdge write SetEdge;

 end;

implementation

{ Internal implementation functions }

{TAppBar}

// TAppBar.CreateParams

procedure TAppBar.CreateParams(var Params: TCreateParams);

var

 dwAdd, dwRemove, dwAddEx, dwRemoveEx: DWORD;

begin

 // Call the inherited first

 inherited CreateParams(Params);

 // Styles to be added

 dwAdd := 0;

 dwAddEx := WS_EX_TOOLWINDOW;

 // Styles to be removed

 dwRemove := WS_SYSMENU or WS_MAXIMIZEBOX or WS_MINIMIZEBOX;

 dwRemoveEx := WS_EX_APPWINDOW;

 // Modify style flags

 with Params do

 begin

   Style := Style and (not dwRemove);

   Style := Style or dwAdd;

   ExStyle := ExStyle and (not dwRemoveEx);

   ExStyle := ExStyle or dwAddEx;

 end;

end;

// TAppBar.AppBarMessage

function TAppBar.AppBarMessage(abMessage: TAppBarMessage;

 abEdge: TAppBarEdge;

 lParam: LPARAM;

 bRect: Boolean;

 var rc: TRect): UINT;

var

 abd: TAppBarData;

begin

 // Initialize an APPBARDATA structure

 abd.cbSize := sizeof(abd);

 abd.hWnd := Handle;

 abd.uCallbackMessage := WM_APPBARNOTIFY;

 abd.uEdge := Ord(abEdge);

 if bRect then

   abd.rc := rc

 else

   abd.rc := Rect(0, 0, 0, 0);

 abd.lParam := lParam;

 Result := SHAppBarMessage(Ord(abMessage), abd);

 // If the caller passed a rectangle, return the updated rectangle

 if bRect then

   rc := abd.rc;

end;

// TAppBar.AppBarMessage1

function TAppBar.AppBarMessage1(abMessage: TAppBarMessage): UINT;

var

 rc: TRect;

begin

 Result := AppBarMessage(abMessage, abeFloat, 0, False, rc);

end;

// TAppBar.AppBarMessage2

function TAppBar.AppBarMessage2(abMessage: TAppBarMessage;

 abEdge: TAppBarEdge): UINT;

var

 rc: TRect;

begin

 Result := AppBarMessage(abMessage, abEdge, 0, False, rc);

end;

// TAppBar.AppBarMessage3

function TAppBar.AppBarMessage3(abMessage: TAppBarMessage;

 abEdge: TAppBarEdge;

 lParam: LPARAM): UINT;

var

 rc: TRect;

begin

 Result := AppBarMessage(abMessage, abEdge, lParam, False, rc);

end;

// TAppBar.AppBarMessage4

function TAppBar.AppBarMessage4(abMessage: TAppBarMessage;

 abEdge: TAppBarEdge;

 lParam: LPARAM;

 var rc: TRect): UINT;

begin

 Result := AppBarMessage(abMessage, abEdge, lParam, True, rc);

end;

// TAppBar.CalcProposedState

function TAppBar.CalcProposedState(var pt: TSmallPoint): TAppBarEdge;

var

 bForceFloat: Boolean;

begin

 // Force the AppBar to float if the user is holding down the Ctrl key

 // and the AppBars style allows floating

 bForceFloat := ((GetKeyState(VK_CONTROL) and $8000) <> 0) and

   (abfAllowFloat in Options.Flags);

 if bForceFloat then

   Result := abeFloat

 else

   Result := GetEdgeFromPoint(Options.Flags, pt);

end;

// TAppBar.GetRect

//修改时间:杨军 修改于2001.11.21

procedure TAppBar.GetRect(abEdgeProposed: TAppBarEdge;

 var rcProposed: TRect);

begin

 // This function finds the x, y, cx, cy of the AppBar window

 if abEdgeProposed = abeFloat then

 begin

   // The AppBar is floating, the proposed rectangle is correct

 end

 else

 begin

   // The AppBar is docked or auto-hide

   // Set dimensions to full screen

   with rcProposed do

   begin

     Left := 0;

     Top := 0;

     Right := GetSystemMetrics(SM_CXSCREEN);

     Bottom := GetSystemMetrics(SM_CYSCREEN);

   end;

   // Subtract off what we want from the full screen dimensions

   if not Options.Autohide then

     // Ask the shell where we can dock

     AppBarMessage4(abmQueryPos, abEdgeProposed, LPARAM(False), rcProposed);

   case abEdgeProposed of

     abeLeft:

       rcProposed.Right := rcProposed.Left + Options.DockSize.cx;

     abeTop:

       rcProposed.Bottom := rcProposed.Top + Options.DockSize.cy;

     abeRight:

       rcProposed.Left := rcProposed.Right - Options.DockSize.cx;

     abeBottom:

       rcProposed.Top := rcProposed.Bottom - Options.DockSize.cy;

   end; // end of case

 end; // end of else

 //在此检查Form 的大小

 CheckBoundsRect(rcProposed);

end;

//检查Form的尺寸

function TAppBar.CheckBoundsRect(var rc: TRect): boolean;

begin

 Result := (rc.Left <> BoundsRect.Left) or

   (rc.Right <> BoundsRect.Right) or

   (rc.Top <> BoundsRect.Top) or

   (rc.Bottom <> BoundsRect.Bottom);

end;

// TAppBar.AdjustLocationForAutohide

function TAppBar.AdjustLocationForAutohide(bShow: Boolean;

 var rc: TRect): Boolean;

var

 x, y: Integer;

 cxVisibleBorder, cyVisibleBorder: Integer;

begin

 if ((GetEdge = abeUnknown) or (GetEdge = abeFloat) or

   (not Options.Autohide)) then

 begin

   // If we are not docked on an edge OR we are not auto-hidden, there is

   // nothing for us to do; just return

   Result := False;

   Exit;

 end;

 // Showing/hiding doesnt change our size; only our position

 x := 0;

 y := 0; // Assume a position of (0, 0)

 if bShow then

   // If we are on the right or bottom, calculate our visible position

   case GetEdge of

     abeRight:

       x := GetSystemMetrics(SM_CXSCREEN) - (rc.Right - rc.Left);

     abeBottom:

       y := GetSystemMetrics(SM_CYSCREEN) - (rc.Bottom - rc.Top);

   end

 else

 begin

   // Keep a part of the AppBar visible at all times

   cxVisibleBorder := 2 * GetSystemMetrics(SM_CXBORDER);

   cyVisibleBorder := 2 * GetSystemMetrics(SM_CYBORDER);

   // Calculate our x or y coordinate so that only the border is visible

   case GetEdge of

     abeLeft:

       x := -((rc.Right - rc.Left) - cxVisibleBorder);

     abeRight:

       x := GetSystemMetrics(SM_CXSCREEN) - cxVisibleBorder;

     abeTop:

       y := -((rc.Bottom - rc.Top) - cyVisibleBorder);

     abeBottom:

       y := GetSystemMetrics(SM_CYSCREEN) - cyVisibleBorder;

   end;

 end;

 with rc do

 begin

   Right := x + (Right - Left);

   Bottom := y + (Bottom - Top);

   Left := x;

   Top := y;

 end;

 Result := True;

end;

// TAppBar.ShowHiddenAppBar

procedure TAppBar.ShowHiddenAppBar(bShow: Boolean);

var

 rc: TRect;

begin

 // Get our window location in screen coordinates

 GetWindowRect(Handle, rc);

 // Assume  that we are visible

 FbAutoHideIsVisible := True;

 if AdjustLocationForAutohide(bShow, rc) then

 begin

   // the rectangle was adjusted, we are an autohide bar

   // Remember whether we are visible or not

   FbAutoHideIsVisible := bShow;

   // Slide window in from or out to the edge

   SlideWindow(rc);

 end;

end;

// TAppBar.SlideWindow

procedure TAppBar.SlideWindow(var rcEnd: TRect);

var

 bFullDragOn: LongBool;

 rcStart: TRect;

 dwTimeStart, dwTimeEnd, dwTime: DWORD;

 x, y, w, h: Integer;

begin

 // Only slide the window if the user has FullDrag turned on

 SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, @bFullDragOn, 0);

 // Get the current window position

 GetWindowRect(Handle, rcStart);

 if (Options.SlideEffect and bFullDragOn and

   ((rcStart.Left <> rcEnd.Left) or

   (rcStart.Top <> rcEnd.Top) or

   (rcStart.Right <> rcEnd.Right) or

   (rcStart.Bottom <> rcEnd.Bottom))) then

 begin

   // Get our starting and ending time

   dwTimeStart := GetTickCount;

   dwTimeEnd := dwTimeStart + Options.TimerInterval;

   dwTime := dwTimeStart;

   while (dwTime < dwTimeEnd) do

   begin

     // While we are still sliding, calculate our new position

     x := rcStart.Left - (rcStart.Left - rcEnd.Left)

       * Integer(dwTime - dwTimeStart) div Options.TimerInterval;

     y := rcStart.Top - (rcStart.Top - rcEnd.Top)

       * Integer(dwTime - dwTimeStart) div Options.TimerInterval;

     w := (rcStart.Right - rcStart.Left)

       - ((rcStart.Right - rcStart.Left) - (rcEnd.Right - rcEnd.Left))

       * Integer(dwTime - dwTimeStart) div Options.TimerInterval;

     h := (rcStart.Bottom - rcStart.Top)

       - ((rcStart.Bottom - rcStart.Top) - (rcEnd.Bottom - rcEnd.Top))

       * Integer(dwTime - dwTimeStart) div Options.TimerInterval;

     // Show the window at its changed position

     SetWindowPos(Handle, 0, x, y, w, h,

       SWP_NOZORDER or SWP_NOACTIVATE or SWP_DRAWFRAME);

     UpdateWindow(Handle);

     dwTime := GetTickCount;

   end;

 end;

 // Make sure that the window is at its final position

 Left := rcEnd.Left;

 Top := rcEnd.Top;

 Width := rcEnd.Right - rcEnd.Left;

 Height := rcEnd.Bottom - rcEnd.Top;

end;

// TAppBar.GetAutohideEdge /

function TAppBar.GetAutohideEdge: TAppBarEdge;

begin

 if Handle = AppBarMessage2(abmGetAutoHideBar, abeLeft) then

   Result := abeLeft

 else if Handle = AppBarMessage2(abmGetAutoHideBar, abeTop) then

   Result := abeTop

 else if Handle = AppBarMessage2(abmGetAutoHideBar, abeRight) then

   Result := abeRight

 else if Handle = AppBarMessage2(abmGetAutoHideBar, abeBottom) then

   Result := abeBottom

 else

   // NOTE: If AppBar is docked but not auto-hidden, we return ABE_UNKNOWN

   Result := abeUnknown;

end;

// TAppBar.GetMessagePosition /

function TAppBar.GetMessagePosition: TSmallPoint;

var

 pt: TSmallPoint;

 dw: DWORD;

begin

 dw := GetMessagePos;

 pt.X := SHORT(dw);

 pt.Y := SHORT((dw and $FFFF0000) shr 16);

 Result := pt;

end;

// TAppBar.ModifyStyle

function TAppBar.ModifyStyle(hWnd: THandle;

 nStyleOffset: Integer;

 dwRemove: DWORD;

 dwAdd: DWORD;

 nFlags: UINT): Boolean;

var

 dwStyle: DWORD;

 dwNewStyle: DWORD;

begin

 dwStyle := GetWindowLong(hWnd, nStyleOffset);

 dwNewStyle := (dwStyle and (not dwRemove)) or dwAdd;

 if dwStyle = dwNewStyle then

 begin

   Result := False;

   Exit;

 end;

 SetWindowLong(hWnd, nStyleOffset, dwNewStyle);

 if nFlags <> 0 then

   SetWindowPos(hWnd, 0, 0, 0, 0, 0,

     SWP_NOSIZE or SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or nFlags);

 Result := True;

end;

{ Property selector functions }

// TAppBar.GetEdge /

function TAppBar.GetEdge: TAppBarEdge;

begin

 if FabEdgeProposedPrev <> abeUnknown then

   Result := FabEdgeProposedPrev

 else

   Result := Options.abEdge;

end;

// TAppBar.SetEdge /

procedure TAppBar.SetEdge(EdgeValue: TAppBarEdge);

var

 abCurrentEdge: TAppBarEdge;

 currentRect: TRect;

 rc: TRect;

 hWnd: THandle;

begin

 // If the AppBar is registered as auto-hide, unregister it

 abCurrentEdge := GetAutohideEdge;

 // Our AppBar is auto-hidden, unregister it

 if abCurrentEdge <> abeUnknown then

   AppBarMessage3(abmSetAutoHideBar, abCurrentEdge, LPARAM(False));

 // Save the new requested state

 with Options do

   abEdge := EdgeValue;

 //

 case EdgeValue of

   abeUnknown:

     begin

       // We are being completely unregistered.

       // Probably, the AppBar window is being destroyed.

       // If the AppBar is registered as NOT auto-hide, unregister it

       AppBarMessage1(abmRemove);

     end;

   abeFloat:

     begin

       // We are floating and therefore are just a regular window.

       // Tell the shell that the docked AppBar should be of 0x0 dimensions

       // so that the workspace is not affected by the AppBar

       currentRect := Rect(0, 0, 0, 0);

       AppBarMessage4(abmSetPos, EdgeValue, LPARAM(False), currentRect);

       rc := Options.FloatRect;

       //SetBounds(rc.Left,rc.Top,rc.Right - rc.Left,rc.Bottom - rc.Top)

     end;

 else

   begin

     if Options.Autohide and

       (AppBarMessage3(abmSetAutoHideBar,

       GetEdge,

       LPARAM(True)) = 0) then

     begin

       // We couldnt set the AppBar on a new edge, lets dock it instead

       with Options do

         Autohide := False;

       // Call a virtual function to let derived classes know that the AppBar

       // changed from auto-hide to docked

       OnAppBarForcedToDocked;

     end;

     GetRect(GetEdge, rc);

     if Options.Autohide then

     begin

       currentRect := Rect(0, 0, 0,0);

       AppBarMessage4(abmSetPos, abeLeft, LPARAM(False), currentRect);

     end

     else

     begin

       // Tell the shell where the AppBar is

       AppBarMessage4(abmSetPos, EdgeValue, LPARAM(False), rc);

     end;

     if AdjustLocationForAutohide(FbAutoHideIsVisible, rc) then

       // Slide window in from or out to the edge

       SlideWindow(rc);

   end; // end of else

 end; // end of case

 // Set the AppBars z-order appropriately

 hWnd := HWND_NOTOPMOST; // Assume normal Z-Order

 if Options.AlwaysOnTop then

 begin

   // If we are supposed to be always-on-top, put us there

   hWnd := HWND_TOPMOST;

   if FbFullScreenAppOpen then

     // But, if a full-screen window is opened, put ourself at the bottom

     // of the z-order so that we dont cover the full-screen window

     hWnd := HWND_BOTTOM;

 end;

 SetWindowPos(Handle,

   hWnd,

   0, 0, 0, 0,

   SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE);

 // Make sure that any auto-hide appbars stay on top of us after we move

 // even though our activation state has not changed

 AppBarMessage1(abmActivate);

 // Tell our derived class that there is a state change

 OnAppBarStateChange(False, EdgeValue);

 if CheckBoundsRect(rc) then BoundsRect := rc;

 // Show or hide the taskbar entry depending on AppBar position

 case Options.TaskEntry of

   abtShow:

     ShowWindow(Application.Handle, SW_SHOW);

   abtHide:

     ShowWindow(Application.Handle, SW_HIDE);

   abtFloatDependent:

     case EdgeValue of

       abeFloat:

         ShowWindow(Application.Handle, SW_SHOW);

       abeLeft, abeTop, abeRight, abeBottom:

         ShowWindow(Application.Handle, SW_HIDE);

     end;

 end;

end;

// TAppBar.SetSlideTime //

procedure TAppBar.SetSlideTime(nInterval: Integer);

begin

 with Options do

   TimerInterval := nInterval;

 FTimer.Interval := nInterval;

end;

{ Overridable functions }

// TAppBar.OnAppBarStateChange

procedure TAppBar.OnAppBarStateChange(bProposed: Boolean;

 abEdgeProposed: TAppBarEdge);

var

 bFullDragOn: LongBool;

begin

 // Find out if the user has FullDrag turned on

 SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, @bFullDragOn, 0);

 // If FullDrag is turned on OR the appbar has changed position

 if bFullDragOn or not bProposed then

 begin

   if abEdgeProposed = abeFloat then

     // Show the window adornments

     ModifyStyle(Handle,

       GWL_STYLE,

       0,

       WS_CAPTION or WS_SYSMENU,

       SWP_DRAWFRAME)

   else

     // Hide the window adornments

     ModifyStyle(Handle,

       GWL_STYLE,

       WS_CAPTION or WS_SYSMENU,

       0,

       SWP_DRAWFRAME);

 end;

end;

// TAppBar.OnAppBarForcedToDocked

procedure TAppBar.OnAppBarForcedToDocked;

const

 StrHaveAutoHiddenWindow = 屏幕的这一侧已经隐藏了一个工具栏。#13 +

   每一侧只能自动隐藏一个工具栏!;

begin

 // Display the application name as the message box caption text.

 //Raise AppBarExcption.Create(StrHaveAutoHiddenWindow);

 Application.MessageBox(StrHaveAutoHiddenWindow, PChar(Caption),

   MB_ICONINFORMATION or MB_OK);

end;

// TAppBar.OnABNFullScreenApp /

procedure TAppBar.OnABNFullScreenApp(bOpen: Boolean);

begin

 // This function is called when a FullScreen window is openning or

 // closing. A FullScreen window is a top-level window that has its caption

 // above the top of the screen allowing the entire screen to be occupied

 // by the windows client area.

 // If the AppBar is a topmost window when a FullScreen window is activated,

 // we need to change our window to a non-topmost window so that the AppBar

 // doesnt cover the FullScreen windows client area.

 // If the FullScreen window is closing, we need to set the AppBars

 // Z-Order back to when the user wants it to be.

 FbFullScreenAppOpen := bOpen;

 UpdateBar;

end;

// TAppBar.OnABNPosChanged /

procedure TAppBar.OnABNPosChanged;

begin

 // The TaskBar or another AppBar has changed its size or position

 if (GetEdge <> abeFloat) and (not Options.Autohide) then

   // If were not floating and were not auto-hidden, we have to

   // reposition our window

   UpdateBar;

end;

// TAppBar.OnABNWindowArrange

procedure TAppBar.OnABNWindowArrange(bBeginning: Boolean);

begin

 // This function intentionally left blank

end;

{ Message handlers }

// TAppBar.OnAppBarCallbackMsg

procedure TAppBar.OnAppBarCallbackMsg(var Msg: TMessage);

begin

 case Msg.WParam of

   ABN_FULLSCREENAPP:

     OnABNFullScreenApp(Msg.LParam <> 0);

   ABN_POSCHANGED:

     OnABNPosChanged;

   ABN_WINDOWARRANGE:

     OnABNWindowArrange(Msg.LParam <> 0);

 end;

end;

// TAppBar.OnCreate

procedure TAppBar.OnCreate(var Msg: TWMCreate);

var

 hMenu: THandle;

begin

 inherited;

 // Associate a timer with the AppBar.  The timer is used to determine

 // when a visible, inactive, auto-hide AppBar should be re-hidden

 FTimer := TTimer.Create(Self);

 with FTimer do

 begin

   Interval := Options.TimerInterval;

   OnTimer := OnAppBarTimer;

   Enabled := True;

 end;

 // Save the initial position of the floating AppBar

 with Options do

   FloatRect := BoundsRect;

 // Register our AppBar window with the Shell

 AppBarMessage1(abmNew);

 // Save the initial size of the floating AppBar

 PostMessage(Handle, WM_ENTERSIZEMOVE, 0, 0);

 PostMessage(Handle, WM_EXITSIZEMOVE, 0, 0);

 // Remove system menu

 hMenu := GetSystemMenu(Handle, False);

 DeleteMenu(hMenu, SC_RESTORE, MF_BYCOMMAND);

 DeleteMenu(hMenu, SC_MINIMIZE, MF_BYCOMMAND);

 DeleteMenu(hMenu, SC_MAXIMIZE, MF_BYCOMMAND);

end;

// TAppBar.OnDestroy

procedure TAppBar.OnDestroy(var Msg: TWMDestroy);

begin

 // Free the Autohide timer

 FTimer.Enabled := False;

 FTimer.Free;

 // Unregister our AppBar window with the Shell

 SetEdge(abeUnknown);

 inherited;

end;

// TAppBar.OnWindowPosChanged

procedure TAppBar.OnWindowPosChanged(var Msg: TWMWindowPosChanged);

begin

 inherited;

 // When our window changes position, tell the Shell so that any

 // auto-hidden AppBar on our edge stays on top of our window making it

 // always accessible to the user

 AppBarMessage1(abmWindowPosChanged);

end;

// TAppBar.OnActivate

procedure TAppBar.OnActivate(var Msg: TWMActivate);

begin

 inherited;

 if Msg.Active = WA_INACTIVE then

   // Hide the AppBar if we are docked and auto-hidden

   ShowHiddenAppBar(False);

 // When our window changes position, tell the Shell so that any

 // auto-hidden AppBar on our edge stays on top of our window making it

 // always accessible to the user.

 AppBarMessage1(abmActivate);

end;

// TAppBar.OnAppBarTimer

procedure TAppBar.OnAppBarTimer(Sender: TObject);

var

 pt: TSmallPoint;

 rc: TRect;

begin

 if GetActiveWindow <> Handle then

 begin

   // Possibly hide the AppBar if we are not the active window

   // Get the position of the mouse and the AppBars position

   // Everything must be in screen coordinates

   pt := GetMessagePosition;

   GetWindowRect(Handle, rc);

   // Add a little margin around the AppBar

   InflateRect(rc,

     2 * GetSystemMetrics(SM_CXDOUBLECLK),

     2 * GetSystemMetrics(SM_CYDOUBLECLK));

   if not PtInRect(rc, SmallPointToPoint(pt)) then

     // If the mouse is NOT over the AppBar, hide the AppBar

     ShowHiddenAppBar(False);

 end;

 inherited;

end;

// TAppBar.OnNcMouseMove

procedure TAppBar.OnNcMouseMove(var Msg: TWMNCMouseMove);

begin

 // If we are a docked, auto-hidden AppBar, shown us

 // when the user moves over our non-client area

 ShowHiddenAppBar(True);

 inherited;

end;

// TAppBar.OnNcHitTest

procedure TAppBar.OnNcHitTest(var Msg: TWMNCHitTest);

var

 u: UINT;

 bPrimaryMouseBtnDown: Boolean;

 rcClient: TRect;

 pt: TPoint;

 vKey: Integer;

begin

 // Find out what the system thinks is the hit test code

 inherited;

 u := Msg.Result;

 // NOTE: If the user presses the secondary mouse button, pretend that the

 // user clicked on the client area so that we get WM_CONTEXTMENU messages

 if GetSystemMetrics(SM_SWAPBUTTON) <> 0 then

   vKey := VK_RBUTTON

 else

   vKey := VK_LBUTTON;

 bPrimaryMouseBtnDown := ((GetAsyncKeyState(vKey) and $8000) <> 0);

 pt.X := Msg.XPos;

 pt.Y := Msg.YPos;

 pt := ScreenToClient(pt);

 if (u = HTCLIENT) and bPrimaryMouseBtnDown

   and (ControlAtPos(pt, False) = nil) then

   // User clicked in client area, allow AppBar to move.  We get this

   // behavior by pretending that the user clicked on the caption area

   u := HTCAPTION;

 // If the AppBar is floating and the hittest code is a resize code...

 if ((GetEdge = abeFloat) and

   (HTSIZEFIRST <= u) and (u <= HTSIZELAST)) then

 begin

   case u of

     HTLEFT, HTRIGHT:

       if Options.SizeInc.cx = 0 then

         u := HTBORDER;

     HTTOP, HTBOTTOM:

       if Options.SizeInc.cy = 0 then

         u := HTBORDER;

     HTTOPLEFT:

       if (Options.SizeInc.cx = 0) and (Options.SizeInc.cy = 0) then

         u := HTBORDER

       else if (Options.SizeInc.cx = 0) and (Options.SizeInc.cy <> 0) then

         u := HTTOP

       else if (Options.SizeInc.cx <> 0) and (Options.SizeInc.cy = 0) then

         u := HTLEFT;

     HTTOPRIGHT:

       if (Options.SizeInc.cx = 0) and (Options.SizeInc.cy = 0) then

         u := HTBORDER

       else if (Options.SizeInc.cx = 0) and (Options.SizeInc.cy <> 0) then

         u := HTTOP

       else if (Options.SizeInc.cx <> 0) and (Options.SizeInc.cy = 0) then

         u := HTRIGHT;

     HTBOTTOMLEFT:

       if (Options.SizeInc.cx = 0) and (Options.SizeInc.cy = 0) then

         u := HTBORDER

       else if (Options.SizeInc.cx = 0) and (Options.SizeInc.cy <> 0) then

         u := HTBOTTOM

       else if (Options.SizeInc.cx <> 0) and (Options.SizeInc.cy = 0) then

         u := HTLEFT;

     HTBOTTOMRIGHT:

       if (Options.SizeInc.cx = 0) and (Options.SizeInc.cy = 0) then

         u := HTBORDER

       else if (Options.SizeInc.cx = 0) and (Options.SizeInc.cy <> 0) then

         u := HTBOTTOM

       else if (Options.SizeInc.cx <> 0) and (Options.SizeInc.cy = 0) then

         u := HTRIGHT;

   end;

 end;

 // When the AppBar is docked, the user can resize only one edge.

 // This next section determines which edge the user can resize.

 // To allow resizing, the AppBar window must have the WS_THICKFRAME style

 // If the AppBar is docked and the hittest code is a resize code...

 if ((GetEdge <> abeFloat) and (GetEdge <> abeUnknown) and

   (HTSIZEFIRST <= u) and (u <= HTSIZELAST)) then

 begin

   if (IsEdgeLeftOrRight(GetEdge) and (Options.SizeInc.cx = 0)) or

     (not IsEdgeLeftOrRight(GetEdge) and (Options.SizeInc.cy = 0)) then

   begin

     // If the width/height size increment is zero, then resizing is NOT

     // allowed for the edge that the AppBar is docked on

     u := HTBORDER; // Pretend that the mouse is not on a resize border

   end

   else

   begin

     // Resizing IS allowed for the edge that the AppBar is docked on

     // Get the location of the appbars client area in screen coordinates

     rcClient := GetClientRect;

     pt.X := rcClient.Left;

     pt.Y := rcClient.Top;

     pt := ClientToScreen(pt);

     rcClient.Left := pt.X;

     rcClient.Top := pt.Y;

     pt.X := rcClient.Right;

     pt.Y := rcClient.Bottom;

     pt := ClientToScreen(pt);

     rcClient.Right := pt.X;

     rcClient.Bottom := pt.Y;

     u := HTBORDER; // Assume that we cant resize

     case GetEdge of

       abeLeft:

         if Msg.XPos > rcClient.Right then

           u := HTRIGHT;

       abeTop:

         if Msg.YPos > rcClient.Bottom then

           u := HTBOTTOM;

       abeRight:

         if Msg.XPos < rcClient.Left then

           u := HTLEFT;

       abeBottom:

         if Msg.YPos < rcClient.Top then

           u := HTTOP;

     end; // end of case

   end; // end of else

 end;

 // Return the hittest code

 Msg.Result := u;

end;

// TAppBar.OnEnterSizeMove

procedure TAppBar.OnEnterSizeMove(var Msg: TMessage);

begin

 // The user started moving/resizing the AppBar, save its current state

 FabEdgeProposedPrev := GetEdge;

end;

// TAppBar.OnExitSizeMove

procedure TAppBar.OnExitSizeMove(var Msg: TMessage);

var

 abEdgeProposedPrev: TAppBarEdge;

 rc, rcWorkArea: TRect;

 w, h: Integer;

begin

 // The user stopped moving/resizing the AppBar, set the new state

 // Save the new proposed state of the AppBar

 abEdgeProposedPrev := FabEdgeProposedPrev;

 // Set the proposed state back to unknown.  This causes GetState

 // to return the current state rather than the proposed state

 FabEdgeProposedPrev := abeUnknown;

 // Get the location of the window in screen coordinates

 GetWindowRect(Handle, rc);

 // If the AppBars state has changed...

 if GetEdge = abEdgeProposedPrev then

   case GetEdge of

     abeLeft, abeRight:

       // Save the new width of the docked AppBar

       with Options do

         DockSize.cx := rc.Right - rc.Left;

     abeTop, abeBottom:

       // Save the new height of the docked AppBar

       with Options do

         DockSize.cy := rc.Bottom - rc.Top;

     abeFloat:

       // If AppBar was floating and keeps floating...

       with Options do

         FloatRect := rc;

   end;

 // Always save the new position of the floating AppBar

 if abEdgeProposedPrev = abeFloat then

 begin

   // Propose width and height depending on the current window position

   w := rc.Right - rc.Left;

   h := rc.Bottom - rc.Top;

   // Adjust width and height

   SystemParametersInfo(SPI_GETWORKAREA, 0, @rcWorkArea, 0);

   if (w >= (rcWorkArea.Right - rcWorkArea.Left)) or

     (h >= (rcWorkArea.Bottom - rcWorkArea.Top)) then

   begin

     w := Options.FloatRect.Right - Options.FloatRect.Left;

     h := Options.FloatRect.Bottom - Options.FloatRect.Top;

   end;

   // Save new floating position

   with Options do

   begin

     FloatRect.Left := rc.Left;

     FloatRect.Top := rc.Top;

     FloatRect.Right := rc.Left + w;

     FloatRect.Bottom := rc.Top + h;

   end;

 end;

 // After setting the dimensions, set the AppBar to the proposed state

 SetEdge(abEdgeProposedPrev);

end;

// TAppBar.OnMoving

procedure TAppBar.OnMoving(var Msg: TMessage);

var

 prc: PRect;

 pt: TSmallPoint;

 abEdgeProposed: TAppBarEdge;

 w, h: Integer;

begin

 // We control the moving of the AppBar.  For example, if the mouse moves

 // close to an edge, we want to dock the AppBar

 // The lParam contains the windows position proposed by the system

 prc := PRect(Msg.LParam);

 // Get the location of the mouse cursor

 pt := GetMessagePosition;

 // Where should the AppBar be based on the mouse position?

 abEdgeProposed := CalcProposedState(pt);

 if ((FabEdgeProposedPrev <> abeFloat) and

   (abEdgeProposed = abeFloat)) then

 begin

   // While moving, the user took us from a docked/autohidden state to

   // the float state.  We have to calculate a rectangle location so that

   // the mouse cursor stays inside the window.

   prc^ := Options.FloatRect;

   w := prc^.Right - prc^.Left;

   h := prc^.Bottom - prc^.Top;

   with prc^ do

   begin

     Left := pt.X - w div 2;

     Top := pt.Y;

     Right := pt.X - w div 2 + w;

     Bottom := pt.Y + h;

   end;

 end;

 // Remember the most-recently proposed state

 FabEdgeProposedPrev := abEdgeProposed;

 // Tell the system where to move the window based on the proposed state

 GetRect(abEdgeProposed, prc^);

 // Tell our derived class that there is a proposed state change

 OnAppBarStateChange(True, abEdgeProposed);

end;

// TAppBar.OnSizing

procedure TAppBar.OnSizing(var Msg: TMessage);

var

 prc: PRect;

 rcBorder: TRect;

 nWidthNew, nHeightNew: Integer;

begin

 // We control the sizing of the AppBar.  For example, if the user re-sizes

 // an edge, we want to change the size in discrete increments.

 // The lParam contains the windows position proposed by the system

 prc := PRect(Msg.LParam);

 // Get the minimum allowed size of the window depending on current edge.

 // This is the width/height of the window that must always be present

 with Options do

   case abEdge of

     abeFloat:

       rcBorder := Rect(0, 0, MinWidth, MinHeight);

   else

     rcBorder := Rect(0, 0, MinDockSize.cx, MinDockSize.cy);

   end;

 // We force the window to resize in discrete units set by the Options.SizeInc

 // member.  From the new, proposed window dimensions passed to us, round

 // the width/height to the nearest discrete unit

 if Options.SizeInc.cx <> 0 then

   nWidthNew := ((prc^.Right - prc^.Left) - (rcBorder.Right - rcBorder.Left)

     + Options.SizeInc.cx div 2) div Options.SizeInc.cx

     * Options.SizeInc.cx + (rcBorder.Right - rcBorder.Left)

 else

   nWidthNew := prc^.Right - prc^.Left;

 if Options.SizeInc.cy <> 0 then

   nHeightNew := ((prc^.Bottom - prc^.Top) - (rcBorder.Bottom - rcBorder.Top)

     + Options.SizeInc.cy div 2) div Options.SizeInc.cy

     * Options.SizeInc.cy + (rcBorder.Bottom - rcBorder.Top)

 else

   nHeightNew := prc^.Bottom - prc^.Top;

 // Adjust the rectangles dimensions

 case Msg.wParam of

   WMSZ_LEFT:

     prc^.Left := prc^.Right - nWidthNew;

   WMSZ_TOP:

     prc^.Top := prc^.Bottom - nHeightNew;

   WMSZ_RIGHT:

     prc^.Right := prc^.Left + nWidthNew;

   WMSZ_BOTTOM:

     prc^.Bottom := prc^.Top + nHeightNew;

   WMSZ_BOTTOMLEFT:

     begin

       prc^.Bottom := prc^.Top + nHeightNew;

       prc^.Left := prc^.Right - nWidthNew;

     end;

   WMSZ_BOTTOMRIGHT:

     begin

       prc^.Bottom := prc^.Top + nHeightNew;

       prc^.Right := prc^.Left + nWidthNew;

     end;

   WMSZ_TOPLEFT:

     begin

       prc^.Left := prc^.Right - nWidthNew;

       prc^.Top := prc^.Bottom - nHeightNew;

     end;

   WMSZ_TOPRIGHT:

     begin

       prc^.Top := prc^.Bottom - nHeightNew;

       prc^.Right := prc^.Left + nWidthNew;

     end;

 end; // end of case

end;

// TAppBar.OnGetMinMaxInfo

procedure TAppBar.OnGetMinMaxInfo(var Msg: TWMGetMinMaxInfo);

begin

 if GetEdge = abeFloat then

   with Msg.MinMaxInfo^ do

   begin

     ptMinTrackSize.X := Options.MinWidth;

     ptMinTrackSize.Y := Options.MinHeight;

     ptMaxTrackSize.X := Options.MaxWidth;

     ptMaxTrackSize.Y := Options.MaxHeight;

   end

 else

   with Msg.MinMaxInfo^ do

   begin

     ptMinTrackSize.X := Options.MinDockSize.cx;

     ptMinTrackSize.Y := Options.MinDockSize.cy;

     ptMaxTrackSize.X := GetSystemMetrics(SM_CXSCREEN);

     ptMaxTrackSize.Y := GetSystemMetrics(SM_CYSCREEN);

     if not IsEdgeTopOrBottom(GetEdge) then

       ptMaxTrackSize.X := Options.MaxDockSize.cx;

     if not IsEdgeLeftOrRight(GetEdge) then

       ptMaxTrackSize.Y := Options.MaxDockSize.cy;

   end;

end;

{ AppBar-specific helper functions }

// TAppBar.IsEdgeLeftOrRight

function TAppBar.IsEdgeLeftOrRight(abEdge: TAppBarEdge): Boolean;

begin

 Result := (abEdge in [abeLeft, abeRight]);

end;

// TAppBar.IsEdgeTopOrBottom

function TAppBar.IsEdgeTopOrBottom(abEdge: TAppBarEdge): Boolean;

begin

 Result := (abEdge in [abeTop, abeBottom]);

end;

// TAppBar.IsFloating

function TAppBar.IsFloating(abEdge: TAppBarEdge): Boolean;

begin

 Result := (abEdge = abeFloat);

end;

// TAppBar.IsDockable

function TAppBar.IsDockable(abFlags: TAppBarFlags): Boolean;

begin

 Result := ((abFlags * [abfAllowLeft..abfAllowBottom]) <> []);

end;

// TAppBar.IsDockableVertically

function TAppBar.IsDockableVertically(abFlags: TAppBarFlags): Boolean;

begin

 Result := ((abFlags * [abfAllowLeft, abfAllowRight]) <> []);

end;

// TAppBar.IsDockableHorizontally

function TAppBar.IsDockableHorizontally(abFlags: TAppBarFlags): Boolean;

begin

 Result := ((abFlags * [abfAllowTop, abfAllowBottom]) <> []);

end;

// TAppBar.ResetSystemKnowledge

procedure TAppBar.ResetSystemKnowledge;

{$IFDEF DEBUG}

var

 abd: TAppBarData;

 {$ENDIF}

begin

 {$IFDEF DEBUG}

 abd.cbSize := sizeof(abd);

 abd.hWnd := 0;

 SHAppBarMessage(ABM_REMOVE, abd);

 {$ENDIF}

end;

// TAppBar.GetEdgeFromPoint

function TAppBar.GetEdgeFromPoint(abFlags: TAppBarFlags;

 pt: TSmallPoint): TAppBarEdge;

var

 rc: TRect;

 cxScreen: Integer;

 cyScreen: Integer;

 ptCenter: TSmallPoint;

 ptOffset: TSmallPoint;

 bIsLeftOrRight: Boolean;

 abSubstEdge: TAppBarEdge;

begin

 // Lets get floating out of the way first

 if abfAllowFloat in abFlags then

 begin

   // Get the rectangle that bounds the size of the screen

   // minus any docked (but not-autohidden) AppBars

   SystemParametersInfo(SPI_GETWORKAREA, 0, @rc, 0);

   // Leave a 1/2 width/height-of-a-scrollbar gutter around the workarea

   InflateRect(rc,

     -GetSystemMetrics(SM_CXVSCROLL),

     -GetSystemMetrics(SM_CYHSCROLL));

   // If the point is in the adjusted workarea OR no edges are allowed

   if PtInRect(rc, SmallPointToPoint(pt)) or

     not IsDockable(abFlags) then

   begin

     // The AppBar should float

     Result := abeFloat;

     Exit;

   end;

 end;

 // If we get here, the AppBar should be docked; determine the proper edge

 // Get the dimensions of the screen

 cxScreen := GetSystemMetrics(SM_CXSCREEN);

 cyScreen := GetSystemMetrics(SM_CYSCREEN);

 // Find the center of the screen

 ptCenter.X := cxScreen div 2;

 ptCenter.Y := cyScreen div 2;

 // Find the distance from the point to the center

 ptOffset.X := pt.X - ptCenter.X;

 ptOffset.Y := pt.Y - ptCenter.Y;

 // Determine if the point is farther from the left/right or top/bottom

 bIsLeftOrRight :=

   ((Abs(ptOffset.Y) * cxScreen) <= (Abs(ptOffset.X) * cyScreen));

 // Propose an edge

 if bIsLeftOrRight then

 begin

   if 0 <= ptOffset.X then

     Result := abeRight

   else

     Result := abeLeft;

 end

 else

 begin

   if 0 <= ptOffset.Y then

     Result := abeBottom

   else

     Result := abeTop;

 end;

 // Calculate an edge substitute

 if abfAllowFloat in abFlags then

   abSubstEdge := abeFloat

 else

   abSubstEdge := Options.abEdge;

 // Check if the proposed edge is allowed. If not, return the edge substitute

 case Result of

   abeLeft: if not (abfAllowLeft in abFlags) then

       Result := abSubstEdge;

   abeTop: if not (abfAllowTop in abFlags) then

       Result := abSubstEdge;

   abeRight: if not (abfAllowRight in abFlags) then

       Result := abSubstEdge;

   abeBottom: if not (abfAllowBottom in abFlags) then

       Result := abSubstEdge;

 end;

end;

{ Public member functions }

// TAppBar.Create

constructor TAppBar.Create(Owner: TComponent);

begin

 //留出工具栏托拽的位置

 BarIndent := 4;

 // Force the shell to update its list of AppBars and the workarea.

 // This is a precaution and is very useful when debugging.  If you create

 // an AppBar and then just terminate the application, the shell still

 // thinks that the AppBar exists and the users workarea is smaller than

 // it should be.  When a new AppBar is created, calling this function

 // fixes the users workarea.

 ResetSystemKnowledge;

 // Set default state of AppBar to float with no width & height

 with Options do

 begin

   Size := sizeof(TAppBarSettings);

   abEdge := abeFloat;

   Flags := [abfAllowLeft..abfAllowFloat];

   Autohide := False;

   AlwaysOnTop := True;

   SlideEffect := True;

   TimerInterval := SLIDE_DEF_TIMER_INTERVAL;

   SizeInc.cx := AB_DEF_SIZE_INC;

   SizeInc.cy := AB_DEF_SIZE_INC;

   DockSize.cy := AB_DEF_DOCK_SIZE;

   DockSize.cx := AB_DEF_DOCK_SIZE;

   FloatRect := Rect(0, 0, 200, 100);

   MinWidth := 0;

   MinHeight := 0;

   MaxWidth := GetSystemMetrics(SM_CXSCREEN);

   MaxHeight := GetSystemMetrics(SM_CYSCREEN);

   MinDockSize.cx := 0;

   MinDockSize.cy := 0;

   MaxDockSize.cx := GetSystemMetrics(SM_CXSCREEN) div 2;

   MaxDockSize.cy := GetSystemMetrics(SM_CYSCREEN) div 2;

   TaskEntry := abtFloatDependent;

 end;

 FabEdgeProposedPrev := abeUnknown;

 FbFullScreenAppOpen := False;

 FbAutoHideIsVisible := False;

 // Set default location of the settings in the registry

 with LocationSetting do

 begin

   RootKey := AB_DEF_ROOT_KEY;

   KeyName := AB_DEF_KEY_NAME;

 end;

 // Call base class

 inherited Create(Owner);

end;

// TAppBar.Destroy

destructor TAppBar.Destroy;

begin

 ResetSystemKnowledge;

 // Call base class

 inherited Destroy;

end;

// TAppBar.UpdateBar

procedure TAppBar.UpdateBar;

begin

 SetEdge(GetEdge);

end;

// TAppBar.LoadSettings

function TAppBar.LoadSettings: Boolean;

var

 reg: TRegistry;

 abs: TAppBarSettings;

begin

 Result := False;

 reg := TRegistry.Create;

 try

   // Set the RootKey

   reg.RootKey := LocationSetting.RootKey;

   // Open the KeyName

   if reg.OpenKey(LocationSetting.KeyName, False) then

     // Load the Options record from the default value

     if reg.ReadBinaryData(, abs, sizeof(abs)) = sizeof(abs) then

     begin

       Options := abs;

       Result := True;

     end;

 finally

   reg.Free;

 end;

end;

// TAppBar.SaveSettings

function TAppBar.SaveSettings: Boolean;

var

 reg: TRegistry;

begin

 Result := False;

 reg := TRegistry.Create;

 try

   // Set the RootKey

   reg.RootKey := LocationSetting.RootKey;

   // Open the KeyName, creating it if not exists

   if reg.OpenKey(LocationSetting.KeyName, True) then

   begin

     // Save the Options record in the default value

     reg.WriteBinaryData(, FABSetting, sizeof(FABSetting));

     Result := True;

   end;

 finally

   reg.Free;

 end;

end;

procedure TAppBar.AdjustClientRect(var Rect: TRect);

begin

 inherited AdjustClientRect(Rect);

 case Edge of

   abeTop, abeBottom:

     Rect.Left := Rect.Left + BarIndent;

   abeLeft, abeRight:

     Rect.Top := Rect.Top + BarIndent;

 end;

end;

end.