reactos/modules/rostests/apitests/shell32/SHAppBarMessage.cpp
Katayama Hirofumi MZ 3aa9cae13e
[SHELL32_APITEST] Strengthen SHAppBarMessage testcase for workarea (#3041)
CORE-7237 - Add workarea checks.
2020-08-13 20:59:36 +09:00

1152 lines
31 KiB
C++

/*
* 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 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 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))
static const TCHAR s_szName[] = TEXT("AppBarSample");
static RECT s_rcWorkArea;
static HWND s_hwnd1 = NULL;
static HWND s_hwnd2 = NULL;
#ifdef VERBOSE
static 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 WINAPI
SHAppBarMessageWrap(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 INT DoMainLoop()
{
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (INT)msg.wParam;
}
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;
void OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
HANDLE hThread;
switch (id)
{
case ID_ACTION:
PostMessage(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");
PostMessage(s_hwnd1, WM_CLOSE, 0, 0);
PostMessage(s_hwnd2, WM_CLOSE, 0, 0);
return;
}
CloseHandle(hThread);
}
}
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:
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) };
abd.hWnd = hwnd;
AppBar_PosChanged(&abd);
}
break;
}
}
BOOL AppBar_Register(HWND hwnd)
{
APPBARDATA abd = { sizeof(abd) };
abd.hWnd = hwnd;
abd.uCallbackMessage = APPBAR_CALLBACK;
m_fAppBarRegd = (BOOL)SHAppBarMessage(ABM_NEW, &abd);
return m_fAppBarRegd;
}
BOOL AppBar_UnRegister(HWND hwnd)
{
APPBARDATA abd = { sizeof(abd) };
abd.hWnd = hwnd;
m_fAppBarRegd = !SHAppBarMessage(ABM_REMOVE, &abd);
return !m_fAppBarRegd;
}
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) };
abd.hWnd = 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) };
abd.hWnd = 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)
{
RECT rc;
SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
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) };
abd.hWnd = 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) };
abd.hWnd = hwnd;
RECT rc;
GetWindowRect(hwnd, &rc);
AppBar_QuerySetPos(m_uSide, &rc, &abd, TRUE);
}
}
void AppBar_QueryPos(HWND hwnd, LPRECT lprc)
{
APPBARDATA abd = { sizeof(abd) };
abd.hWnd = 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);
return TRUE;
}
void OnActivate(HWND hwnd, UINT state, HWND hwndActDeact, BOOL fMinimized)
{
APPBARDATA abd = { sizeof(abd) };
abd.hWnd = 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) };
abd.hWnd = 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) };
abd.hWnd = hwnd;
AppBar_QuerySetPos(m_uSide, &m_rcDrag, &abd, FALSE);
}
}
m_fMoving = FALSE;
}
void GetWorkArea(LPRECT prc) const
{
SystemParametersInfoW(SPI_GETWORKAREA, 0, prc, 0);
}
public:
void DoAction()
{
#define INTERVAL 250
POINT pt;
RECT rc1, rc2, rcWork;
DWORD dwTID = GetWindowThreadProcessId(s_hwnd1, NULL);
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);
PostMessage(s_hwnd1, WM_CLOSE, 0, 0);
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_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);
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.right - 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.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);
SendMessage(s_hwnd2, WM_CLOSE, 0, 0);
Sleep(INTERVAL);
GetWorkArea(&rcWork);
ok_long(rcWork.left, s_rcWorkArea.left);
ok_long(rcWork.top, s_rcWorkArea.top);
ok_long(rcWork.right, s_rcWorkArea.right);
ok_long(rcWork.bottom, s_rcWorkArea.bottom);
PostMessage(s_hwnd2, WM_QUIT, 0, 0);
PostThreadMessage(dwTID, WM_QUIT, 0, 0);
#undef INTERVAL
}
static DWORD WINAPI ActionThreadFunc(LPVOID args)
{
Window *this_ = (Window *)args;
this_->DoAction();
return 0;
}
};
START_TEST(SHAppBarMessage)
{
HINSTANCE hInstance = GetModuleHandle(NULL);
if (!Window::DoRegisterClass(hInstance))
{
skip("Window::DoRegisterClass failed\n");
return;
}
SystemParametersInfo(SPI_GETWORKAREA, 0, &s_rcWorkArea, FALSE);
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;
PostMessage(hwnd1, WM_COMMAND, ID_ACTION, 0);
Window::DoMainLoop();
}