Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305/* * PROJECT: ReactOS api tests * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later) * PURPOSE: Test for SHAppBarMessage * COPYRIGHT: Copyright 2020-2025 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) */
#include "shelltest.h"#include <windowsx.h>#include <shlwapi.h>#include <stdio.h>
/* Based on https://github.com/katahiromz/AppBarSample */
//#define VERBOSE
#define IDT_AUTOHIDE 1#define IDT_AUTOUNHIDE 2
#define ID_ACTION 100#define ID_QUIT 999
#define APPBAR_CALLBACK (WM_USER + 100)
#define LEFT_DOWN() mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);#define LEFT_UP() mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);#define MOVE(x, y) SetCursorPos((x), (y))
#define INTERVAL 250#define LONG_INTERVAL 2500
static const TCHAR s_szName[] = TEXT("AppBarSample");static RECT s_rcPrimaryMonitor;static RECT s_rcWorkArea;static RECT s_rcTaskBar;static HWND s_hwnd1 = NULL;static HWND s_hwnd2 = NULL;
#ifdef VERBOSEstatic LPCSTR MessageOfAppBar(DWORD dwMessage){ static char s_buf[32]; switch (dwMessage) { case ABM_NEW: return "ABM_NEW"; case ABM_REMOVE: return "ABM_REMOVE"; case ABM_QUERYPOS: return "ABM_QUERYPOS"; case ABM_SETPOS: return "ABM_SETPOS"; case ABM_GETSTATE: return "ABM_GETSTATE"; case ABM_GETTASKBARPOS: return "ABM_GETTASKBARPOS"; case ABM_ACTIVATE: return "ABM_ACTIVATE"; case ABM_GETAUTOHIDEBAR: return "ABM_GETAUTOHIDEBAR"; case ABM_SETAUTOHIDEBAR: return "ABM_SETAUTOHIDEBAR"; case ABM_WINDOWPOSCHANGED: return "ABM_WINDOWPOSCHANGED"; } wsprintfA(s_buf, "%lu", dwMessage); return s_buf;}
static UINT WINAPISHAppBarMessageWrap(DWORD dwMessage, PAPPBARDATA pData){ trace("SHAppBarMessage entered (dwMessage=%s, rc=(%ld, %ld, %ld, %ld))\n", MessageOfAppBar(dwMessage), pData->rc.left, pData->rc.top, pData->rc.right, pData->rc.bottom); UINT ret = SHAppBarMessage(dwMessage, pData); trace("SHAppBarMessage leaved (dwMessage=%s, rc=(%ld, %ld, %ld, %ld))\n", MessageOfAppBar(dwMessage), pData->rc.left, pData->rc.top, pData->rc.right, pData->rc.bottom); return ret;}#define SHAppBarMessage SHAppBarMessageWrap
#undef ARRAYSIZE#define ARRAYSIZE _countof
void appbar_tprintf(const TCHAR *fmt, ...){ TCHAR szText[512]; va_list va; va_start(va, fmt); wvsprintf(szText, fmt, va);#ifdef UNICODE printf("%ls", szText);#else printf("%s", szText);#endif va_end(va);}
#define MSGDUMP_TPRINTF appbar_tprintf#include "msgdump.h"
#endif // def VERBOSE
void SlideWindow(HWND hwnd, LPRECT prc){#define SLIDE_HIDE 400#define SLIDE_SHOW 150 RECT rcOld, rcNew = *prc; GetWindowRect(hwnd, &rcOld);
BOOL fShow = (rcNew.bottom - rcNew.top > rcOld.bottom - rcOld.top) || (rcNew.right - rcNew.left > rcOld.right - rcOld.left);
INT dx = (rcNew.right - rcOld.right) + (rcNew.left - rcOld.left); INT dy = (rcNew.bottom - rcOld.bottom) + (rcNew.top - rcOld.top);
LONG dt = SLIDE_HIDE; if (fShow) { dt = SLIDE_SHOW; rcOld = rcNew; OffsetRect(&rcOld, -dx, -dy); SetWindowPos(hwnd, NULL, rcOld.left, rcOld.top, rcOld.right - rcOld.left, rcOld.bottom - rcOld.top, SWP_NOZORDER | SWP_NOACTIVATE | SWP_DRAWFRAME); }
HANDLE hThread = GetCurrentThread(); INT priority = GetThreadPriority(hThread); SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST);
LONG t, t0 = GetTickCount(); while ((t = GetTickCount()) < t0 + dt) { INT x = rcOld.left + dx * (t - t0) / dt; INT y = rcOld.top + dy * (t - t0) / dt; SetWindowPos(hwnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
UpdateWindow(hwnd); UpdateWindow(GetDesktopWindow()); }
SetThreadPriority(hThread, priority); SetWindowPos(hwnd, NULL, rcNew.left, rcNew.top, rcNew.right - rcNew.left, rcNew.bottom - rcNew.top, SWP_NOZORDER | SWP_NOACTIVATE | SWP_DRAWFRAME);#undef SLIDE_HIDE#undef SLIDE_SHOW}
class Window{public: Window(INT cx, INT cy, BOOL fAutoHide = FALSE) : m_hwnd(NULL) , m_fAutoHide(fAutoHide) , m_cxWidth(cx) , m_cyHeight(cy) { }
virtual ~Window() { }
static BOOL DoRegisterClass(HINSTANCE hInstance) { WNDCLASS wc; ZeroMemory(&wc, sizeof(wc)); wc.lpfnWndProc = Window::WindowProc; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); wc.lpszClassName = s_szName; return !!RegisterClass(&wc); }
static HWND DoCreateMainWnd(HINSTANCE hInstance, LPCTSTR pszText, INT cx, INT cy, DWORD style = WS_POPUP | WS_THICKFRAME | WS_CLIPCHILDREN, DWORD exstyle = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST, BOOL fAutoHide = FALSE) { Window *this_ = new Window(cx, cy, fAutoHide); HWND hwnd = CreateWindowEx(exstyle, s_szName, pszText, style, CW_USEDEFAULT, CW_USEDEFAULT, 50, 50, NULL, NULL, hInstance, this_); ShowWindow(hwnd, SW_SHOWNORMAL); UpdateWindow(hwnd); return hwnd; }
static Window *GetAppbarData(HWND hwnd) { return (Window *)GetWindowLongPtr(hwnd, GWLP_USERDATA); }
virtual LRESULT CALLBACK WindowProcDx(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {#ifdef VERBOSE MD_msgdump(hwnd, uMsg, wParam, lParam);#endif switch (uMsg) { HANDLE_MSG(hwnd, WM_CREATE, OnCreate); HANDLE_MSG(hwnd, WM_COMMAND, OnCommand); HANDLE_MSG(hwnd, WM_ACTIVATE, OnActivate); HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGED, OnWindowPosChanged); HANDLE_MSG(hwnd, WM_SIZE, OnSize); HANDLE_MSG(hwnd, WM_MOVE, OnMove); HANDLE_MSG(hwnd, WM_NCDESTROY, OnNCDestroy); HANDLE_MSG(hwnd, WM_TIMER, OnTimer); HANDLE_MSG(hwnd, WM_NCHITTEST, OnNCHitTest); HANDLE_MSG(hwnd, WM_LBUTTONDOWN, OnLButtonDown); HANDLE_MSG(hwnd, WM_MOUSEMOVE, OnMouseMove); HANDLE_MSG(hwnd, WM_LBUTTONUP, OnLButtonUp); HANDLE_MSG(hwnd, WM_RBUTTONDOWN, OnRButtonDown); HANDLE_MSG(hwnd, WM_KEYDOWN, OnKey); HANDLE_MSG(hwnd, WM_PAINT, OnPaint);
case APPBAR_CALLBACK: OnAppBarCallback(hwnd, uMsg, wParam, lParam); break;
default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } return 0; }
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { Window *this_ = GetAppbarData(hwnd); if (uMsg == WM_CREATE) { LPCREATESTRUCT pCS = (LPCREATESTRUCT)lParam; this_ = (Window *)pCS->lpCreateParams; SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this_); } if (this_) return this_->WindowProcDx(hwnd, uMsg, wParam, lParam); return DefWindowProc(hwnd, uMsg, wParam, lParam); }
protected: HWND m_hwnd; BOOL m_fAutoHide; BOOL m_fOnTop; BOOL m_fHiding; UINT m_uSide; LONG m_cxWidth; LONG m_cyHeight; LONG m_cxSave; LONG m_cySave; BOOL m_fAppBarRegd; BOOL m_fMoving; BOOL m_bDragged; POINT m_ptDragOn; RECT m_rcAppBar; RECT m_rcDrag; BOOL m_bGotFullScreen;
void OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) { HANDLE hThread; switch (id) { case ID_ACTION: PostMessageW(s_hwnd2, WM_COMMAND, ID_ACTION + 1, 0); break; case ID_ACTION + 1: hThread = CreateThread(NULL, 0, ActionThreadFunc, this, 0, NULL); if (!hThread) { skip("failed to create thread\n"); PostMessageW(s_hwnd1, WM_CLOSE, 0, 0); PostMessageW(s_hwnd2, WM_CLOSE, 0, 0); return; } CloseHandle(hThread); break; case ID_QUIT: DestroyWindow(s_hwnd1); DestroyWindow(s_hwnd2); PostQuitMessage(0); break; } }
void OnPaint(HWND hwnd) { PAINTSTRUCT ps;
TCHAR szText[64]; GetWindowText(hwnd, szText, 64);
RECT rc; GetClientRect(hwnd, &rc);
if (HDC hdc = BeginPaint(hwnd, &ps)) { DrawText(hdc, szText, -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER); EndPaint(hwnd, &ps); } }
void OnRButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags) { m_fAutoHide = !m_fAutoHide; AppBar_SetAutoHide(hwnd, m_fAutoHide); }
void OnKey(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags) { if (vk == VK_ESCAPE) DestroyWindow(hwnd); }
void OnAppBarCallback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { static HWND s_hwndZOrder = NULL;
switch (wParam) { case ABN_STATECHANGE: break;
case ABN_FULLSCREENAPP: m_bGotFullScreen = TRUE; if (lParam) { s_hwndZOrder = GetWindow(hwnd, GW_HWNDPREV); SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); } else { SetWindowPos(hwnd, m_fOnTop ? HWND_TOPMOST : s_hwndZOrder, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); s_hwndZOrder = NULL; } break;
case ABN_POSCHANGED: { APPBARDATA abd = { sizeof(abd), hwnd }; AppBar_PosChanged(&abd); } break; } }
BOOL AppBar_Register(HWND hwnd) { APPBARDATA abd = { sizeof(abd), hwnd, APPBAR_CALLBACK }; m_fAppBarRegd = (BOOL)SHAppBarMessage(ABM_NEW, &abd); return m_fAppBarRegd; }
BOOL AppBar_UnRegister(HWND hwnd) { APPBARDATA abd = { sizeof(abd), hwnd }; m_fAppBarRegd = !SHAppBarMessage(ABM_REMOVE, &abd); return !m_fAppBarRegd; }
BOOL AppBar_GetTaskBarPos(HWND hwnd, PRECT prc) { APPBARDATA abd = { sizeof(abd), hwnd };
if (!SHAppBarMessage(ABM_GETTASKBARPOS, &abd)) return FALSE; *prc = abd.rc; return TRUE; }
HWND AppBar_GetAutoHideBar(HWND hwnd, UINT uSide) { APPBARDATA abd = { sizeof(abd), hwnd }; abd.uEdge = uSide;
return (HWND)SHAppBarMessage(ABM_GETAUTOHIDEBAR, &abd); }
BOOL AppBar_SetAutoHide(HWND hwnd, BOOL fHide) { if (fHide) return AppBar_AutoHide(hwnd); else return AppBar_NoAutoHide(hwnd); }
BOOL AppBar_AutoHide(HWND hwnd) { APPBARDATA abd = { sizeof(abd), hwnd }; abd.uEdge = m_uSide;
HWND hwndAutoHide = (HWND)SHAppBarMessage(ABM_GETAUTOHIDEBAR, &abd); if (hwndAutoHide) return FALSE;
abd.lParam = TRUE; if (!(BOOL)SHAppBarMessage(ABM_SETAUTOHIDEBAR, &abd)) return FALSE;
m_fAutoHide = TRUE; m_cxSave = m_cxWidth; m_cySave = m_cyHeight;
RECT rc = m_rcAppBar; switch (m_uSide) { case ABE_TOP: rc.bottom = rc.top + 2; break; case ABE_BOTTOM: rc.top = rc.bottom - 2; break; case ABE_LEFT: rc.right = rc.left + 2; break; case ABE_RIGHT: rc.left = rc.right - 2; break; }
AppBar_QueryPos(hwnd, &rc); abd.rc = rc; SHAppBarMessage(ABM_SETPOS, &abd); rc = abd.rc;
m_fHiding = TRUE; SlideWindow(hwnd, &rc);
AppBar_SetAutoHideTimer(hwnd); return TRUE; }
BOOL AppBar_NoAutoHide(HWND hwnd) { APPBARDATA abd = { sizeof(abd), hwnd }; abd.uEdge = m_uSide; HWND hwndAutoHide = (HWND)SHAppBarMessage(ABM_GETAUTOHIDEBAR, &abd); if (hwndAutoHide != hwnd) return FALSE;
abd.lParam = FALSE; if (!(BOOL)SHAppBarMessage(ABM_SETAUTOHIDEBAR, &abd)) return FALSE;
m_fAutoHide = FALSE; m_cxWidth = m_cxSave; m_cyHeight = m_cySave; AppBar_SetSide(hwnd, m_uSide); return TRUE; }
BOOL AppBar_SetSide(HWND hwnd, UINT uSide) { HMONITOR hMon = ::MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); MONITORINFO mi = { sizeof(mi) }; ::GetMonitorInfo(hMon, &mi); RECT rc = mi.rcWork;
BOOL fAutoHide = FALSE; if (m_fAutoHide) { fAutoHide = m_fAutoHide; SetWindowRedraw(GetDesktopWindow(), FALSE); AppBar_SetAutoHide(hwnd, FALSE); m_fHiding = FALSE; }
switch (uSide) { case ABE_TOP: rc.bottom = rc.top + m_cyHeight; break; case ABE_BOTTOM: rc.top = rc.bottom - m_cyHeight; break; case ABE_LEFT: rc.right = rc.left + m_cxWidth; break; case ABE_RIGHT: rc.left = rc.right - m_cxWidth; break; }
APPBARDATA abd = { sizeof(abd), hwnd }; AppBar_QuerySetPos(uSide, &rc, &abd, TRUE);
if (fAutoHide) { AppBar_SetAutoHide(hwnd, TRUE); m_fHiding = TRUE;
SetWindowRedraw(GetDesktopWindow(), TRUE); RedrawWindow(GetDesktopWindow(), NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); }
return TRUE; }
void AppBar_SetAlwaysOnTop(HWND hwnd, BOOL fOnTop) { SetWindowPos(hwnd, (fOnTop ? HWND_TOPMOST : HWND_NOTOPMOST), 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); m_fOnTop = fOnTop; }
void AppBar_Hide(HWND hwnd) { if (!m_fAutoHide) return;
RECT rc = m_rcAppBar; switch (m_uSide) { case ABE_TOP: rc.bottom = rc.top + 2; break; case ABE_BOTTOM: rc.top = rc.bottom - 2; break; case ABE_LEFT: rc.right = rc.left + 2; break; case ABE_RIGHT: rc.left = rc.right - 2; break; }
m_fHiding = TRUE; SlideWindow(hwnd, &rc); }
void AppBar_UnHide(HWND hwnd) { SlideWindow(hwnd, &m_rcAppBar); m_fHiding = FALSE;
AppBar_SetAutoHideTimer(hwnd); }
void AppBar_SetAutoHideTimer(HWND hwnd) { if (m_fAutoHide) { SetTimer(hwnd, IDT_AUTOHIDE, 500, NULL); } }
void AppBar_SetAutoUnhideTimer(HWND hwnd) { if (m_fAutoHide && m_fHiding) { SetTimer(hwnd, IDT_AUTOUNHIDE, 50, NULL); } }
void AppBar_Size(HWND hwnd) { if (m_fAppBarRegd) { APPBARDATA abd = { sizeof(abd), hwnd };
RECT rc; GetWindowRect(hwnd, &rc); AppBar_QuerySetPos(m_uSide, &rc, &abd, TRUE); } }
void AppBar_QueryPos(HWND hwnd, LPRECT lprc) { APPBARDATA abd = { sizeof(abd), hwnd }; abd.rc = *lprc; abd.uEdge = m_uSide;
INT cx = 0, cy = 0; if (ABE_LEFT == abd.uEdge || ABE_RIGHT == abd.uEdge) { cx = abd.rc.right - abd.rc.left; abd.rc.top = 0; abd.rc.bottom = GetSystemMetrics(SM_CYSCREEN); } else { cy = abd.rc.bottom - abd.rc.top; abd.rc.left = 0; abd.rc.right = GetSystemMetrics(SM_CXSCREEN); }
SHAppBarMessage(ABM_QUERYPOS, &abd);
switch (abd.uEdge) { case ABE_LEFT: abd.rc.right = abd.rc.left + cx; break; case ABE_RIGHT: abd.rc.left = abd.rc.right - cx; break; case ABE_TOP: abd.rc.bottom = abd.rc.top + cy; break; case ABE_BOTTOM: abd.rc.top = abd.rc.bottom - cy; break; }
*lprc = abd.rc; }
void AppBar_QuerySetPos(UINT uEdge, LPRECT lprc, PAPPBARDATA pabd, BOOL fMove) { pabd->rc = *lprc; pabd->uEdge = uEdge; m_uSide = uEdge;
AppBar_QueryPos(pabd->hWnd, &pabd->rc);
SHAppBarMessage(ABM_SETPOS, pabd);
if (fMove) { RECT rc = pabd->rc; MoveWindow(pabd->hWnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE); }
if (!m_fAutoHide) { m_rcAppBar = pabd->rc; } }
void AppBar_PosChanged(PAPPBARDATA pabd) { RECT rc; SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
if (m_fAutoHide) { m_rcAppBar = rc; switch (m_uSide) { case ABE_TOP: m_rcAppBar.bottom = m_rcAppBar.top + m_cySave; break; case ABE_BOTTOM: m_rcAppBar.top = m_rcAppBar.bottom - m_cySave; break; case ABE_LEFT: m_rcAppBar.right = m_rcAppBar.left + m_cxSave; break; case ABE_RIGHT: m_rcAppBar.left = m_rcAppBar.right - m_cxSave; break; } }
RECT rcWindow; GetWindowRect(pabd->hWnd, &rcWindow); INT cx = rcWindow.right - rcWindow.left; INT cy = rcWindow.bottom - rcWindow.top; switch (m_uSide) { case ABE_TOP: rc.bottom = rc.top + cy; break; case ABE_BOTTOM: rc.top = rc.bottom - cy; break; case ABE_LEFT: rc.right = rc.left + cx; break; case ABE_RIGHT: rc.left = rc.right - cx; break; } AppBar_QuerySetPos(m_uSide, &rc, pabd, TRUE); }
BOOL OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct) { m_hwnd = hwnd; m_fOnTop = TRUE; m_uSide = ABE_TOP;
m_fAppBarRegd = FALSE; m_fMoving = FALSE; m_cxSave = m_cxWidth; m_cySave = m_cyHeight; m_bDragged = FALSE;
AppBar_Register(hwnd); AppBar_SetSide(hwnd, ABE_TOP);
trace("OnCreate(%p) done\n", hwnd); return TRUE; }
void OnActivate(HWND hwnd, UINT state, HWND hwndActDeact, BOOL fMinimized) { APPBARDATA abd = { sizeof(abd), hwnd }; SHAppBarMessage(ABM_ACTIVATE, &abd);
switch (state) { case WA_ACTIVE: case WA_CLICKACTIVE: AppBar_UnHide(hwnd); KillTimer(hwnd, IDT_AUTOHIDE); break;
case WA_INACTIVE: AppBar_Hide(hwnd); break; } }
void OnWindowPosChanged(HWND hwnd, const LPWINDOWPOS lpwpos) { APPBARDATA abd = { sizeof(abd), hwnd }; SHAppBarMessage(ABM_WINDOWPOSCHANGED, &abd);
FORWARD_WM_WINDOWPOSCHANGED(hwnd, lpwpos, DefWindowProc); }
void OnSize(HWND hwnd, UINT state, int cx, int cy) { RECT rcWindow;
if (m_fMoving || (m_fAutoHide && m_fHiding)) return;
if (!m_fHiding) { if (!m_fAutoHide) AppBar_Size(hwnd);
GetWindowRect(hwnd, &rcWindow); m_rcAppBar = rcWindow;
if (m_uSide == ABE_TOP || m_uSide == ABE_BOTTOM) m_cyHeight = m_cySave = rcWindow.bottom - rcWindow.top; else m_cxWidth = m_cxSave = rcWindow.right - rcWindow.left; }
InvalidateRect(hwnd, NULL, TRUE); }
void OnMove(HWND hwnd, int x, int y) { if (m_fMoving || m_fAutoHide) return;
if (!m_fHiding) AppBar_Size(hwnd); }
void OnNCDestroy(HWND hwnd) { AppBar_UnRegister(hwnd);
m_hwnd = NULL; SetWindowLongPtr(hwnd, GWLP_USERDATA, 0); delete this; }
void OnTimer(HWND hwnd, UINT id) { POINT pt; RECT rc; HWND hwndActive;
switch (id) { case IDT_AUTOHIDE: if (m_fAutoHide && !m_fHiding && !m_fMoving) { GetCursorPos(&pt); GetWindowRect(hwnd, &rc); hwndActive = GetForegroundWindow();
if (!PtInRect(&rc, pt) && hwndActive != hwnd && hwndActive != NULL && GetWindowOwner(hwndActive) != hwnd) { KillTimer(hwnd, id); AppBar_Hide(hwnd); } } break;
case IDT_AUTOUNHIDE: KillTimer(hwnd, id);
if (m_fAutoHide && m_fHiding) { GetCursorPos(&pt); GetWindowRect(hwnd, &rc); if (PtInRect(&rc, pt)) { AppBar_UnHide(hwnd); } } break; } }
UINT OnNCHitTest(HWND hwnd, int x, int y) { AppBar_SetAutoUnhideTimer(hwnd);
UINT uHitTest = FORWARD_WM_NCHITTEST(hwnd, x, y, DefWindowProc);
if (m_uSide == ABE_TOP && uHitTest == HTBOTTOM) return HTBOTTOM;
if (m_uSide == ABE_BOTTOM && uHitTest == HTTOP) return HTTOP;
if (m_uSide == ABE_LEFT && uHitTest == HTRIGHT) return HTRIGHT;
if (m_uSide == ABE_RIGHT && uHitTest == HTLEFT) return HTLEFT;
return HTCLIENT; }
void OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags) { m_fMoving = TRUE; m_bDragged = FALSE; SetCapture(hwnd); GetCursorPos(&m_ptDragOn); }
void OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags) { if (!m_fMoving) return;
POINT pt; GetCursorPos(&pt); if (labs(pt.x - m_ptDragOn.x) > GetSystemMetrics(SM_CXDRAG) || labs(pt.y - m_ptDragOn.y) > GetSystemMetrics(SM_CYDRAG)) { m_bDragged = TRUE; }
INT cxScreen = GetSystemMetrics(SM_CXSCREEN); INT cyScreen = GetSystemMetrics(SM_CYSCREEN);
DWORD dx, dy; UINT ix, iy; if (pt.x < cxScreen / 2) { dx = pt.x; ix = ABE_LEFT; } else { dx = cxScreen - pt.x; ix = ABE_RIGHT; }
if (pt.y < cyScreen / 2) { dy = pt.y; iy = ABE_TOP; } else { dy = cyScreen - pt.y; iy = ABE_BOTTOM; }
if (cxScreen * dy > cyScreen * dx) { m_rcDrag.top = 0; m_rcDrag.bottom = cyScreen; if (ix == ABE_LEFT) { m_uSide = ABE_LEFT; m_rcDrag.left = 0; m_rcDrag.right = m_rcDrag.left + m_cxWidth; } else { m_uSide = ABE_RIGHT; m_rcDrag.right = cxScreen; m_rcDrag.left = m_rcDrag.right - m_cxWidth; } } else { m_rcDrag.left = 0; m_rcDrag.right = cxScreen; if (iy == ABE_TOP) { m_uSide = ABE_TOP; m_rcDrag.top = 0; m_rcDrag.bottom = m_rcDrag.top + m_cyHeight; } else { m_uSide = ABE_BOTTOM; m_rcDrag.bottom = cyScreen; m_rcDrag.top = m_rcDrag.bottom - m_cyHeight; } }
AppBar_QueryPos(hwnd, &m_rcDrag);
if (m_bDragged) { MoveWindow(hwnd, m_rcDrag.left, m_rcDrag.top, m_rcDrag.right - m_rcDrag.left, m_rcDrag.bottom - m_rcDrag.top, TRUE); } }
void OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags) { if (!m_fMoving) return;
OnMouseMove(hwnd, x, y, keyFlags);
m_rcAppBar = m_rcDrag;
ReleaseCapture();
if (m_fAutoHide) { switch (m_uSide) { case ABE_TOP: m_rcDrag.bottom = m_rcDrag.top + 2; break; case ABE_BOTTOM: m_rcDrag.top = m_rcDrag.bottom - 2; break; case ABE_LEFT: m_rcDrag.right = m_rcDrag.left + 2; break; case ABE_RIGHT: m_rcDrag.left = m_rcDrag.right - 2; break; } }
if (m_bDragged) { if (m_fAutoHide) { AppBar_AutoHide(hwnd); } else { APPBARDATA abd = { sizeof(abd), hwnd }; AppBar_QuerySetPos(m_uSide, &m_rcDrag, &abd, FALSE); } }
m_fMoving = FALSE; }
void GetWorkArea(LPRECT prc) const { SystemParametersInfoW(SPI_GETWORKAREA, 0, prc, 0); }
void Quit() { PostMessage(s_hwnd1, WM_COMMAND, ID_QUIT, 0); PostMessage(s_hwnd2, WM_COMMAND, ID_QUIT, 0); }
public: void DoAction() { trace("DoAction\n");
TEST_Main(); TEST_Dragging(); TEST_AutoHide(); TEST_FullScreen();
Quit(); }
void TEST_Main() { trace("TEST_Main\n"); Sleep(INTERVAL);
POINT pt; RECT rc1, rc2, rcWork;
BOOL ret = AppBar_GetTaskBarPos(s_hwnd1, &rc1); ok_int(ret, TRUE); ok_int(EqualRect(&rc1, &s_rcTaskBar), TRUE);
GetWindowRect(s_hwnd1, &rc1); GetWindowRect(s_hwnd2, &rc2); GetWorkArea(&rcWork); ok_long(rc1.left, s_rcWorkArea.left); ok_long(rc1.top, s_rcWorkArea.top); ok_long(rc1.right, s_rcWorkArea.right); ok_long(rc1.bottom, s_rcWorkArea.top + 80); ok_long(rc2.left, s_rcWorkArea.left); ok_long(rc2.top, s_rcWorkArea.top + 80); ok_long(rc2.right, s_rcWorkArea.right); ok_long(rc2.bottom, s_rcWorkArea.top + 110); ok_long(rcWork.left, s_rcWorkArea.left); ok_long(rcWork.top, s_rcWorkArea.top + 110); ok_long(rcWork.right, s_rcWorkArea.right); ok_long(rcWork.bottom, s_rcWorkArea.bottom); PostMessageW(s_hwnd1, WM_CLOSE, 0, 0); Sleep(LONG_INTERVAL);
GetWindowRect(s_hwnd2, &rc2); GetWorkArea(&rcWork); ok_long(rc2.left, s_rcWorkArea.left); ok_long(rc2.top, s_rcWorkArea.top); ok_long(rc2.right, s_rcWorkArea.right); ok_long(rc2.bottom, s_rcWorkArea.top + 30); ok_long(rcWork.left, s_rcWorkArea.left); ok_long(rcWork.top, s_rcWorkArea.top + 30); ok_long(rcWork.right, s_rcWorkArea.right); ok_long(rcWork.bottom, s_rcWorkArea.bottom); AppBar_SetSide(s_hwnd2, ABE_LEFT); Sleep(INTERVAL);
GetWindowRect(s_hwnd2, &rc2); GetWorkArea(&rcWork); ok_long(rc2.left, s_rcWorkArea.left); ok_long(rc2.top, s_rcWorkArea.top); ok_long(rc2.right, s_rcWorkArea.left + 30); ok_long(rcWork.left, s_rcWorkArea.left + 30); ok_long(rcWork.top, s_rcWorkArea.top); ok_long(rcWork.right, s_rcWorkArea.right); ok_long(rcWork.bottom, s_rcWorkArea.bottom); AppBar_SetSide(s_hwnd2, ABE_TOP); Sleep(INTERVAL);
GetWindowRect(s_hwnd2, &rc2); GetWorkArea(&rcWork); ok_long(rc2.left, s_rcWorkArea.left); ok_long(rc2.top, s_rcWorkArea.top); ok_long(rc2.right, s_rcWorkArea.right); ok_long(rc2.bottom, s_rcWorkArea.top + 30); ok_long(rcWork.left, s_rcWorkArea.left); ok_long(rcWork.top, s_rcWorkArea.top + 30); ok_long(rcWork.right, s_rcWorkArea.right); ok_long(rcWork.bottom, s_rcWorkArea.bottom); AppBar_SetSide(s_hwnd2, ABE_RIGHT); Sleep(INTERVAL);
GetWindowRect(s_hwnd2, &rc2); GetWorkArea(&rcWork); ok_long(rc2.left, s_rcWorkArea.right - 30); ok_long(rc2.top, s_rcWorkArea.top); ok_long(rc2.right, s_rcWorkArea.right); ok_long(rcWork.left, s_rcWorkArea.left); ok_long(rcWork.top, s_rcWorkArea.top); ok_long(rcWork.right, s_rcWorkArea.right - 30); ok_long(rcWork.bottom, s_rcWorkArea.bottom); Sleep(INTERVAL);
GetWindowRect(s_hwnd2, &rc2); pt.x = (rc2.left + rc2.right) / 2; pt.y = (rc2.top + rc2.bottom) / 2; MOVE(pt.x, pt.y); LEFT_DOWN(); MOVE(pt.x + 64, pt.y + 64); Sleep(INTERVAL);
pt.x = s_rcWorkArea.left + 80; pt.y = (s_rcWorkArea.top + s_rcWorkArea.bottom) / 2; MOVE(pt.x, pt.y); LEFT_UP(); Sleep(INTERVAL);
GetWindowRect(s_hwnd2, &rc2); GetWorkArea(&rcWork); ok_long(rc2.left, s_rcWorkArea.left); ok_long(rc2.top, s_rcWorkArea.top); ok_long(rc2.right, s_rcWorkArea.left + 30); ok_long(rcWork.left, s_rcWorkArea.left + 30); ok_long(rcWork.top, s_rcWorkArea.top); ok_long(rcWork.right, s_rcWorkArea.right); ok_long(rcWork.bottom, s_rcWorkArea.bottom); Sleep(INTERVAL); }
void TEST_Dragging() { trace("TEST_Dragging\n");
RECT rc, rcWork; POINT pt;
GetWindowRect(s_hwnd2, &rc); pt.x = (rc.left + rc.right) / 2; pt.y = (rc.top + rc.bottom) / 2; MOVE(pt.x, pt.y); LEFT_DOWN(); Sleep(INTERVAL);
pt.x = (s_rcWorkArea.left + s_rcWorkArea.right) / 2; pt.y = s_rcWorkArea.top; MOVE(pt.x, pt.y); Sleep(INTERVAL);
pt.x = s_rcWorkArea.right - 1; pt.y = (s_rcWorkArea.top + s_rcWorkArea.bottom) / 2; MOVE(pt.x, pt.y); LEFT_UP(); Sleep(LONG_INTERVAL);
GetWindowRect(s_hwnd2, &rc); GetWorkArea(&rcWork); ok_long(rc.left, s_rcWorkArea.right - 30); ok_long(rc.top, s_rcWorkArea.top); ok_long(rc.right, s_rcWorkArea.right); ok_long(rcWork.left, s_rcWorkArea.left); ok_long(rcWork.top, s_rcWorkArea.top); ok_long(rcWork.right, s_rcWorkArea.right - 30); ok_long(rcWork.bottom, s_rcWorkArea.bottom); }
void TEST_AutoHide() { trace("TEST_AutoHide\n");
RECT rc;
m_cxWidth = 80; m_cyHeight = 40; AppBar_SetSide(s_hwnd2, ABE_TOP); AppBar_AutoHide(s_hwnd2); HWND hwndRet = AppBar_GetAutoHideBar(s_hwnd2, ABE_TOP); ok_ptr(hwndRet, s_hwnd2); Sleep(LONG_INTERVAL);
GetWindowRect(s_hwnd2, &rc); ok_long(rc.left, s_rcWorkArea.left); ok_long(rc.top, s_rcWorkArea.top); ok_long(rc.right, s_rcWorkArea.right); ok_long(rc.bottom, s_rcWorkArea.top + 2);
MOVE((s_rcWorkArea.left + s_rcWorkArea.right) / 2, s_rcWorkArea.top); LEFT_DOWN(); LEFT_UP(); Sleep(LONG_INTERVAL);
GetWindowRect(s_hwnd2, &rc); ok_long(rc.left, s_rcWorkArea.left); ok_long(rc.top, s_rcWorkArea.top); ok_long(rc.right, s_rcWorkArea.right); ok_long(rc.bottom, s_rcWorkArea.top + 40);
MOVE((s_rcWorkArea.left + s_rcWorkArea.right) / 2, s_rcWorkArea.bottom - 1); LEFT_DOWN(); LEFT_UP(); Sleep(LONG_INTERVAL);
GetWindowRect(s_hwnd2, &rc); ok_long(rc.left, s_rcWorkArea.left); ok_long(rc.top, s_rcWorkArea.top); ok_long(rc.right, s_rcWorkArea.right); ok_long(rc.bottom, s_rcWorkArea.top + 2);
SetForegroundWindow(s_hwnd2); Sleep(LONG_INTERVAL);
GetWindowRect(s_hwnd2, &rc); ok_long(rc.left, s_rcWorkArea.left); ok_long(rc.top, s_rcWorkArea.top); ok_long(rc.right, s_rcWorkArea.right); ok_long(rc.bottom, s_rcWorkArea.top + 40);
AppBar_SetSide(s_hwnd2, ABE_RIGHT); AppBar_AutoHide(s_hwnd2); SetForegroundWindow(s_hwnd2); hwndRet = AppBar_GetAutoHideBar(s_hwnd2, ABE_RIGHT); ok_ptr(hwndRet, s_hwnd2);
GetWindowRect(s_hwnd2, &rc); ok_long(rc.left, s_rcWorkArea.right - 2); ok_long(rc.top, s_rcWorkArea.top); ok_long(rc.right, s_rcWorkArea.right); ok_long(rc.bottom, s_rcWorkArea.bottom);
MOVE(s_rcWorkArea.left, (s_rcWorkArea.top + s_rcWorkArea.bottom) / 2); Sleep(LONG_INTERVAL);
GetWindowRect(s_hwnd2, &rc); ok_long(rc.left, s_rcWorkArea.right - 2); ok_long(rc.top, s_rcWorkArea.top); ok_long(rc.right, s_rcWorkArea.right); ok_long(rc.bottom, s_rcWorkArea.bottom); }
void TEST_FullScreen() { trace("TEST_FullScreen\n"); RECT rc = s_rcPrimaryMonitor; m_bGotFullScreen = FALSE; MoveWindow(s_hwnd2, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE); Sleep(LONG_INTERVAL); ok_int(m_bGotFullScreen, TRUE); MoveWindow(s_hwnd2, rc.left, rc.top, 100, 100, TRUE); }
static DWORD WINAPI ActionThreadFunc(LPVOID args) { Window *this_ = (Window *)args; this_->DoAction(); return 0; }};
START_TEST(SHAppBarMessage){ HINSTANCE hInstance = GetModuleHandle(NULL);
// Check Taskbar HWND hTrayWnd = FindWindowW(L"Shell_TrayWnd", NULL); if (!IsWindowVisible(hTrayWnd)) { skip("Taskbar not found\n"); return; }
// Taskbar RECT rc; GetWindowRect(hTrayWnd, &rc); s_rcTaskBar = rc; trace("s_rcTaskBar: %ld, %ld, %ld, %ld\n", rc.left, rc.top, rc.right, rc.bottom);
// Work area SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, FALSE); s_rcWorkArea = rc; trace("s_rcWorkArea: %ld, %ld, %ld, %ld\n", rc.left, rc.top, rc.right, rc.bottom);
// Primary monitor SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); s_rcPrimaryMonitor = rc; trace("s_rcPrimaryMonitor: %ld, %ld, %ld, %ld\n", rc.left, rc.top, rc.right, rc.bottom);
if (s_rcTaskBar.left > s_rcPrimaryMonitor.left || s_rcTaskBar.right < s_rcPrimaryMonitor.right || s_rcTaskBar.bottom < s_rcPrimaryMonitor.bottom) { // Taskbar must be bottom in this testcase skip("Taskbar was not bottom\n"); return; }
if (!Window::DoRegisterClass(hInstance)) { skip("Window::DoRegisterClass failed\n"); return; }
trace("SM_CMONITORS: %d\n", GetSystemMetrics(SM_CMONITORS)); if (GetSystemMetrics(SM_CMONITORS) != 1) { skip("Multi-monitor not supported yet\n"); return; }
HWND hwnd1 = Window::DoCreateMainWnd(hInstance, TEXT("Test1"), 80, 80, WS_POPUP | WS_THICKFRAME | WS_CLIPCHILDREN); if (!hwnd1) { skip("CreateWindowExW failed\n"); return; }
HWND hwnd2 = Window::DoCreateMainWnd(hInstance, TEXT("Test2"), 30, 30, WS_POPUP | WS_BORDER | WS_CLIPCHILDREN); if (!hwnd2) { skip("CreateWindowExW failed\n"); return; }
s_hwnd1 = hwnd1; s_hwnd2 = hwnd2;
PostMessageW(hwnd1, WM_COMMAND, ID_ACTION, 0);
// message loop MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); }}