Figure 5   AppBar


m_abs.m_rcFloat.Height(),SWP_NOZORDER|SWP_NOACTIVATE);
         break;

      default:
         if (IsBarAutohide() && !SHAppBarMessage(ABM_SETAUTOHIDEBAR, GetState(), 
TRUE)) { // We couldn't set the AppBar on a new edge, let's dock it instead. m_abs.m_fAutohide = FALSE; // Call a virtual function to let derived classes knowthattheAppBar // changed from auto-hide to docked. OnAppBarForcedToDocked(); } CRect rc; GetRect(GetState(), &rc); if (IsBarAutohide()) { SHAppBarMessage(ABM_SETPOS, ABE_LEFT, FALSE, &CRect(0, 0, 0, 0)); } else { // Tell the shell where the AppBar is. SHAppBarMessage(ABM_SETPOS, uState, FALSE, &rc); } AdjustLocationForAutohide(m_fAutoHideIsVisible, &rc); // Slide window in from or out to the edge SlideWindow(rc); break; } // Set the AppBar's z-order appropriately const CWnd* pwnd = &wndNoTopMost; // Assume normal Z-Order if (m_abs.m_fAlwaysOnTop) { // If we are supposed to be always-on-top, put us there. pwnd = &wndTopMost; if (m_fFullScreenAppOpen) { // But, if a full-screen window is opened, put ourself at the bottom // of the z-order so that we don't cover the full-screen window pwnd = &wndBottom; } } SetWindowPos(pwnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE|SWP_NOACTIVATE); // Make sure that any auto-hide appabrs stay on top of us after we move // even though our activation state has not changed. SHAppBarMessage(ABM_ACTIVATE); // Tell our derived class that there is a state change OnAppBarStateChange(FALSE, uState); } ///////////////////////////////////////////////////////////////////////////// void CAppBar::SetState (APPBARSTATE& abs) { // The AppBar window doesn't exist, just update the state variables CopyMemory(&m_abs, &abs, min(abs.m_cbSize, sizeof(m_abs))); m_abs.m_cbSize = sizeof(m_abs); // In case caller used an old version if (IsWindow(m_hWnd)) SetState(); } ///////////////////////////////////////////////////////////////////////////// // Internal implementation functions UINT CAppBar::SHAppBarMessage (DWORD dwMessage, UINT uEdge /*= ABE_FLOAT*/, LPARAM lParam /*= 0*/, CRect *rc /*= NULL*/) { // Initialize an APPBARDATA structure. APPBARDATA abd; abd.cbSize = sizeof(abd); abd.hWnd = m_hWnd; abd.uCallbackMessage = s_uAppBarNotifyMsg; abd.uEdge = uEdge; abd.rc = (rc == NULL) ? CRect(0, 0, 0, 0) : *rc; abd.lParam = lParam; UINT uRetVal = ::SHAppBarMessage(dwMessage, &abd); // If the caller passed a rectangle, return the updated rectangle. if (rc != NULL) *rc = abd.rc; return(uRetVal); } ///////////////////////////////////////////////////////////////////////////// UINT CAppBar::CalcProposedState (const CPoint& pt) { // Force the AppBar to float if the user is holding down the Ctrl key // and the AppBar's style allows floating. BOOL fForceFloat = ((GetKeyState(VK_CONTROL) & 0x8000) != 0) && ((m_fdwFlags & ABF_ALLOWFLOAT) != 0); return(fForceFloat ? ABE_FLOAT : GetEdgeFromPoint(m_fdwFlags, pt)); } ///////////////////////////////////////////////////////////////////////////// void CAppBar::GetRect (UINT uStateProposed, CRect* prcProposed) { // This function finds the x, y, cx, cy of the AppBar window if (ABE_FLOAT == uStateProposed) { // The AppBar is floating, the proposed rectangle is correct } else { // The AppBar is docked or auto-hide // Set dimensions to full screen. *prcProposed = CRect(0,0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); // Subtract off what we want from the full screen dimensions if (!IsBarAutohide()) { // Ask the shell where we can dock. SHAppBarMessage(ABM_QUERYPOS, uStateProposed, FALSE, prcProposed); } switch (uStateProposed) { case ABE_LEFT: prcProposed->right = prcProposed->left + m_abs.m_auDimsDock[uStateProposed]; break; case ABE_TOP: prcProposed->bottom = prcProposed->top + m_abs.m_auDimsDock[uStateProposed]; break; case ABE_RIGHT: prcProposed->left = prcProposed->right - m_abs.m_auDimsDock[uStateProposed]; break; case ABE_BOTTOM: prcProposed->top = prcProposed->bottom - m_abs.m_auDimsDock[uStateProposed]; break; } } } ///////////////////////////////////////////////////////////////////////////// BOOL CAppBar::AdjustLocationForAutohide (BOOL fShow, CRect* prc) { if ((GetState() == ABE_UNKNOWN) || (GetState() == ABE_FLOAT) || !IsBarAutohide()) { // If we are not docked on an edge OR we are not auto-hidden, there is // nothing for us to do; just return. return(FALSE); } // Showing/hiding doesn't change our size; only our position. int x = 0, y = 0; // Assume a position of (0, 0) if (fShow) { // If we are on the right or bottom, calculate our visible position switch (GetState()) { case ABE_RIGHT: x = GetSystemMetrics(SM_CXSCREEN) - prc->Width(); break; case ABE_BOTTOM: y = GetSystemMetrics(SM_CYSCREEN) - prc->Height(); break; } } else { // Keep a part of the AppBar visible at all times const int cxVisibleBorder = 2 * GetSystemMetrics(SM_CXBORDER); const int cyVisibleBorder = 2 * GetSystemMetrics(SM_CYBORDER); // Calculate our x or y coordinate so that only the border is visible switch (GetState()) { case ABE_LEFT: x = -(prc->Width() - cxVisibleBorder); break; case ABE_RIGHT: x = GetSystemMetrics(SM_CXSCREEN) - cxVisibleBorder; break; case ABE_TOP: y = -(prc->Height() - cyVisibleBorder); break; case ABE_BOTTOM: y = GetSystemMetrics(SM_CYSCREEN) - cyVisibleBorder; break; } } *prc = CRect(x, y, x + prc->Width(), y + prc->Height()); return(TRUE); } ///////////////////////////////////////////////////////////////////////////// void CAppBar::ShowHiddenAppBar (BOOL fShow /*= TRUE*/) { // Get our window location in screen coordinates. CRect rc; GetWindowRect(&rc); m_fAutoHideIsVisible = TRUE; // Assume that we are visible if (AdjustLocationForAutohide(fShow, &rc)) { // the rectangle was adjusted, we are an autohide bar // Rememebr whether we are visible or not. m_fAutoHideIsVisible = fShow; // Slide window in from or out to the edge SlideWindow(rc); } } ///////////////////////////////////////////////////////////////////////////// void CAppBar::SlideWindow (const CRect& rcEnd) { BOOL fFullDragOn; // Only slide the window if the user has FullDrag turned on ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &fFullDragOn, 0); // Get the current window position CRect rcStart; GetWindowRect(&rcStart); if (fFullDragOn && (rcStart != rcEnd)) { // Get our starting and ending time. DWORD dwTimeStart = GetTickCount(); DWORD dwTimeEnd = dwTimeStart + AUTOHIDETIMERINTERVAL; DWORD dwTime; while ((dwTime = ::GetTickCount()) < dwTimeEnd) { // While we are still sliding, calculate our new position int x = rcStart.left - (rcStart.left - rcEnd.left) * (int) (dwTime - dwTimeStart) / AUTOHIDETIMERINTERVAL; int y = rcStart.top - (rcStart.top - rcEnd.top) * (int) (dwTime - dwTimeStart) / AUTOHIDETIMERINTERVAL; int nWidth = rcStart.Width() - (rcStart.Width() - rcEnd.Width()) * (int) (dwTime - dwTimeStart) / AUTOHIDETIMERINTERVAL; int nHeight = rcStart.Height() - (rcStart.Height() - rcEnd.Height()) * (int) (dwTime - dwTimeStart) / AUTOHIDETIMERINTERVAL; // Show the window at its changed position SetWindowPos(NULL, x, y, nWidth, nHeight, SWP_NOZORDER | SWP_NOACTIVATE | SWP_DRAWFRAME); UpdateWindow(); } } // Make sure that the window is at its final position SetWindowPos(NULL, rcEnd.left, rcEnd.top, rcEnd.Width(), rcEnd.Height(), SWP_NOZORDER | SWP_NOACTIVATE | SWP_DRAWFRAME); UpdateWindow(); } ///////////////////////////////////////////////////////////////////////////// // Overridable functions void CAppBar::OnAppBarStateChange (BOOL fProposed, UINT uStateProposed) { // This function intentionally left blank. } ///////////////////////////////////////////////////////////////////////////// void CAppBar::OnAppBarForcedToDocked (void) { // Display the ppBar's caption text as the message box caption text. CString sz; GetWindowText(sz); ::MessageBox(NULL, __TEXT("There is already an auto hidden window on this edge.\n") __TEXT("Only one auto hidden window is allowed on each edge."), sz, MB_OK | MB_ICONSTOP); } ///////////////////////////////////////////////////////////////////////////// void CAppBar::OnABNFullScreenApp (BOOL fOpen) { // 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 window's client area. // If the AppBar is a topmost window when a FullScreen windiw is activated, // we need to change our window to a non-topmost window so that the AppBar // doesn't cover the FullScreen window's client area. // If the FullScreen window is closing, we need to set the AppBar's // Z-Order back to when the user wants it to be. m_fFullScreenAppOpen = fOpen; SetState(); } ///////////////////////////////////////////////////////////////////////////// void CAppBar::OnABNPosChanged (void) { // The TaskBar or another AppBar has changed its size or position. if ((GetState() != ABE_FLOAT) && !IsBarAutohide()) { // If we're not floating and we're not auto-hidden, we have to // reposition our window. SetState(); } } ///////////////////////////////////////////////////////////////////////////// void CAppBar::OnABNStateChange (DWORD fdwStateChangedMask, DWORD fdwState) { // Make our state mimic the taskbar's state. MimicState(fdwStateChangedMask, fdwState); } ///////////////////////////////////////////////////////////////////////////// void CAppBar::OnABNWindowArrange (BOOL fBeginning) { // This function intentionally left blank. } ///////////////////////////////////////////////////////////////////////////// void CAppBar::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CAppBar) // NOTE: the ClassWizard will add DDX and DDV calls here //}}AFX_DATA_MAP } ///////////////////////////////////////////////////////////////////////////// // Register a window message for the AppBar's callback notifications UINT CAppBar::s_uAppBarNotifyMsg = RegisterWindowMessage(__TEXT("AppBarNotify")); ///////////////////////////////////////////////////////////////////////////// // Called when the AppBar recieves a g_uAppBarNotifyMsg window message LRESULT CAppBar::OnAppBarCallbackMsg (WPARAM uNotifyMsg, LPARAM lParam) { switch (uNotifyMsg) { case ABN_FULLSCREENAPP: OnABNFullScreenApp((BOOL) lParam); break; case ABN_POSCHANGED: OnABNPosChanged(); break; case ABN_WINDOWARRANGE: OnABNWindowArrange((BOOL) lParam); break; case ABN_STATECHANGE: // The shell sends ABN_STATECHANGE notifications at inappropriate // times. So, we remember the TaskBar's current state and set // a mask indicating which states have actually changed. This mask // and the state information is passed to the derived class. // Get the state of the Taskbar DWORD fdwTaskBarState = SHAppBarMessage(ABM_GETSTATE); // Prepare a mask indicating which states have changed. The code in // the derived class should only act on the states that have changed. DWORD fdwStateChangedMask = 0; if ((fdwTaskBarState & ABS_ALWAYSONTOP) != (m_fdwTaskBarState & ABS_ALWAYSONTOP)) { fdwStateChangedMask |= ABS_ALWAYSONTOP; } if ((fdwTaskBarState & ABS_AUTOHIDE) != (m_fdwTaskBarState & ABS_AUTOHIDE)) { fdwStateChangedMask |= ABS_AUTOHIDE; } // Call the derived class OnABNStateChange(fdwStateChangedMask, fdwTaskBarState); // Save the TaskBar's state so that we can see exactly which states // change the next time be get an ABN_STATECHANGE notification. m_fdwTaskBarState = fdwTaskBarState; break; } return(0); } ///////////////////////////////////////////////////////////////////////////// BEGIN_MESSAGE_MAP(CAppBar, CDialog) ON_REGISTERED_MESSAGE(s_uAppBarNotifyMsg, OnAppBarCallbackMsg) ON_MESSAGE(WM_ENTERSIZEMOVE, OnEnterSizeMove) ON_MESSAGE(WM_SIZING, OnSizing) ON_MESSAGE(WM_MOVING, OnMoving) ON_MESSAGE(WM_EXITSIZEMOVE, OnExitSizeMove) //{{AFX_MSG_MAP(CAppBar) ON_WM_CREATE() ON_WM_DESTROY() ON_WM_WINDOWPOSCHANGED() ON_WM_ACTIVATE() ON_WM_NCMOUSEMOVE() ON_WM_NCHITTEST() ON_WM_TIMER() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CAppBar message handlers int CAppBar::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CDialog::OnCreate(lpCreateStruct) == -1) return(-1); // Associate a timer with the AppBar. The timer is used to determine // when a visible, inactive, auto-hide AppBar should be re-hidden. SetTimer(AUTOHIDETIMERID, AUTOHIDETIMERINTERVAL, NULL); // Register our AppBar window with the Shell SHAppBarMessage(ABM_NEW); // Force the AppBar to mimic the state of the TaskBar // Assume that all states have changed MimicState(ABS_ALWAYSONTOP | ABS_AUTOHIDE, m_fdwTaskBarState); return(0); } ///////////////////////////////////////////////////////////////////////////// void CAppBar::OnDestroy() { CDialog::OnDestroy(); // Kill the Autohide timer KillTimer(AUTOHIDETIMERID); // Unregister our AppBar window with the Shell SetState(ABE_UNKNOWN); } ///////////////////////////////////////////////////////////////////////////// void CAppBar::OnWindowPosChanged(WINDOWPOS FAR* lpwndpos) { CDialog::OnWindowPosChanged(lpwndpos); // 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. SHAppBarMessage(ABM_WINDOWPOSCHANGED); } ///////////////////////////////////////////////////////////////////////////// void CAppBar::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) { CDialog::OnActivate(nState, pWndOther, bMinimized); if (nState == WA_INACTIVE) { // 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. SHAppBarMessage(ABM_ACTIVATE); } ///////////////////////////////////////////////////////////////////////////// void CAppBar::OnTimer(UINT nIDEvent) { if (GetActiveWindow() != this) { // Possibly hide the AppBar if we are not the active window // Get the position of the mouse and the AppBar's position // Everything must be in screen coordinates. CPoint pt(::GetMessagePos()); CRect rc; GetWindowRect(&rc); // Add a little margin around the AppBar rc.InflateRect(2 * GetSystemMetrics(SM_CXDOUBLECLK), 2 * GetSystemMetrics(SM_CYDOUBLECLK)); if (!rc.PtInRect(pt)) { // If the mouse is NOT over the AppBar, hide the AppBar ShowHiddenAppBar(FALSE); } } CDialog::OnTimer(nIDEvent); } ///////////////////////////////////////////////////////////////////////////// void CAppBar::OnNcMouseMove(UINT nHitTest, CPoint point) { // If we are a docked, auto-hidden AppBar, shown us // when the user moves over our non-client area ShowHiddenAppBar(TRUE); CDialog::OnNcMouseMove(nHitTest, point); } ///////////////////////////////////////////////////////////////////////////// UINT CAppBar::OnNcHitTest(CPoint point) { // Find out what the system thinks is the hit test code UINT u = CDialog::OnNcHitTest(point); // 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 BOOL fPrimaryMouseBtnDown = (GetAsyncKeyState(GetSystemMetrics(SM_SWAPBUTTON) ? VK_RBUTTON : VK_LBUTTON) & 0x8000) != 0; if ((u == HTCLIENT) && fPrimaryMouseBtnDown) { // 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; } // 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 ((GetState() != ABE_FLOAT) && (GetState() != ABE_UNKNOWN) && (HTSIZEFIRST <= u) && (u <= HTSIZELAST)) { if (0 == (IsEdgeLeftOrRight(GetState()) ? m_szSizeInc.cx : m_szSizeInc.cy)) { // 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 } else { // Resizing IS allowed for the edge that the AppBar is docked on. // Get the location of the appbar's client area in screen coordinates. CRect rcClient; GetClientRect(&rcClient); ClientToScreen(rcClient); u = HTBORDER; // Assume that we can't resize switch (GetState()) { case ABE_LEFT: if (point.x > rcClient.right) u = HTRIGHT; break; case ABE_TOP: if (point.y > rcClient.bottom) u = HTBOTTOM; break; case ABE_RIGHT: if (point.x < rcClient.left) u = HTLEFT; break; case ABE_BOTTOM: if (point.y < rcClient.top) u = HTTOP; break; } } } return(u); // Return the hittest code } ///////////////////////////////////////////////////////////////////////////// LRESULT CAppBar::OnEnterSizeMove(WPARAM wParam, LPARAM lParam) { // The user started moving/resizing the AppBar, save its current state. m_uStateProposedPrev = GetState(); return(0); } ///////////////////////////////////////////////////////////////////////////// LRESULT CAppBar::OnExitSizeMove(WPARAM wParam, LPARAM lParam) { // The user stopped moving/resizing the AppBar, set the new state. // Save the new proposed state of the AppBar. UINT uStateProposedPrev = m_uStateProposedPrev; // Set the proposed state back to unknown. This causes GetState // to return the current state rather than the proposed state. m_uStateProposedPrev = ABE_UNKNOWN; // Get the location of the window in screen coordinates CRect rc; GetWindowRect(&rc); // If the AppBar's state has changed... if (GetState() == uStateProposedPrev) { switch (GetState()) { case ABE_UNKNOWN: break; case ABE_LEFT: case ABE_RIGHT: // Save the new width of the docked AppBar m_abs.m_auDimsDock[m_abs.m_uState] = rc.Width(); break; case ABE_TOP: case ABE_BOTTOM: // Save the new height of the docked AppBar m_abs.m_auDimsDock[m_abs.m_uState] = rc.Height(); break; } } // Always save the new position of the floating AppBar if (uStateProposedPrev == ABE_FLOAT) m_abs.m_rcFloat = rc; // After setting the dimensions, set the AppBar to the proposed state SetState(uStateProposedPrev); return(0); } ///////////////////////////////////////////////////////////////////////////// LRESULT CAppBar::OnMoving(WPARAM wParam, LPARAM lParam) { // 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 window's position proposed by the system CRect* prc = (CRect *) lParam; // Get the location of the mouse cursor CPoint pt(::GetMessagePos()); // Where should the AppBar be based on the mouse position? UINT uStateProposed = CalcProposedState(pt); if ((m_uStateProposedPrev != ABE_FLOAT) && (uStateProposed == ABE_FLOAT)) { // 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. GetFloatRect(prc); *prc = CRect(pt.x - prc->Width() / 2, pt.y, (pt.x - prc->Width() / 2) + prc->Width(), pt.y + prc->Height()); } // Remember the most-recently proposed state m_uStateProposedPrev = uStateProposed; // Tell the system where to move the window based on the proposed state GetRect(uStateProposed, prc); // Tell our derived class that there is a proposed state change OnAppBarStateChange(TRUE, uStateProposed); return(0); } ///////////////////////////////////////////////////////////////////////////// LRESULT CAppBar::OnSizing(WPARAM wParam, LPARAM lParam) { // We control the sizing of the AppBar. For example, if the user re-sizes // an edge, we want to change the size in descrete increments. // The lParam contains the window's position proposed by the system CRect* prc = (CRect *) lParam; // Get the minimum size of the window assuming it has no client area. // This is the width/height of the window that must always be present CRect rcBorder(0, 0, 0, 0); AdjustWindowRectEx(&rcBorder, GetStyle(), FALSE, GetExStyle()); // We force the window to resize in discrete units set by the m_szSizeInc // member. From the new, proposed window dimensions passed to us, round // the width/height to the nearest discrete unit. int nWidthNew = ((prc->Width() - rcBorder.Width()) + m_szSizeInc.cx / 2) / m_szSizeInc.cx * m_szSizeInc.cx + rcBorder.Width(); int nHeightNew = ((prc->Height() - rcBorder.Height()) + m_szSizeInc.cy / 2) / m_szSizeInc.cy * m_szSizeInc.cy + rcBorder.Height(); // Adjust the rectangle's dimensions switch (wParam) { case WMSZ_LEFT: prc->left = prc->right - nWidthNew; break; case WMSZ_TOP: prc->top = prc->bottom - nHeightNew; break; case WMSZ_RIGHT: prc->right = prc->left + nWidthNew; break; case WMSZ_BOTTOM: prc->bottom = prc->top + nHeightNew; break; case WMSZ_BOTTOMLEFT: prc->bottom = prc->top + nHeightNew; prc->left = prc->right - nWidthNew; break; case WMSZ_BOTTOMRIGHT: prc->bottom = prc->top + nHeightNew; prc->right = prc->left + nWidthNew; break; case WMSZ_TOPLEFT: prc->left = prc->right - nWidthNew; prc->top = prc->bottom - nHeightNew; break; case WMSZ_TOPRIGHT: prc->top = prc->bottom - nHeightNew; prc->right = prc->left + nWidthNew; break; } return(0); } //////////////////////////////// End of File /////////////////////////////////

Figure 6   M_fdwFlags Values

Flag

Description

ABF_ALLOWLEFTRIGHT

Allow the appbar to dock on the left or right edge of the screen.

ABF_ALLOWTOPBOTTOM

Allow the appbar to dock on the top or bottom of the screen.

ABF_ALLOWANYEDGE

Same as (ABF_ALLOWLEFTRIGHT | ABF_ALLOWTOPBOTTOM).

ABF_ALLOWFLOAT

Allow the appbar to float in the middle of the screen.

ABF_ALLOWANYWHERE

(ABF_ALLOWANYEDGE | ABF_ALLOWFLOAT)

ABF_MIMICTASKBARAUTOHIDE

The appbar should monitor ABN_STATECHANGE notifications and be autohide if the taskbar is autohide.

ABF_MIMICTASKBARALWAYSONTOP

The appbar should monitor ABN_STATECHANGE notifications and be always-on-top if the taskbar is always-on-top.

Figure 7   CAppBar Member Functions

Message Handler

Description

OnCreate

Sets a timer used to determine when to slide an autohide window.
Registers the appbar by sending an ABM_NEW message.
Calls MimicState.

OnDestroy

Kills the timer.

Unregisters the appbar by sending an ABM_REMOVE message.

OnWindowPosChanged

Brings autohide appbars to the top by sending an ABM_WINDOWPOSCHANGED message.

OnActivate

On de-activation, slides the appbar out if it's autohide.

Brings autohide appbars to the top by sending an ABM_ACTIVATE message.

OnTimer

Slides the appbar (if autohide) off the screen if it's not activated and the mouse is not over it.

OnNcMouseMove

Slides the appbar (if autohide) on to the screen.

OnNcHitTest

If the mouse is in the client area, return HTCAPTION so that the appbar can be moved.

Returns a value indicting whether the cursor is over an area of the window where resizing is allowed.

OnEnterSizeMove

Saves the current state of the appbar.

OnExitSizeMove

Saves the new state of the appbar and repositions it on the screen.

OnMoving

From the mouse position, CalcProposedState is called to get the proposed state of the appbar, then GetRect is called to get the location of the window in this state, then

OnAppBarStateChange is called to let the derived class know what the proposed state change is.

OnSizing

Ensures that the window's width or height always change in discrete increments.