1 /* 2 * PROJECT: ReactOS api tests 3 * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later) 4 * PURPOSE: Test for SHAppBarMessage 5 * COPYRIGHT: Copyright 2020 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) 6 */ 7 8 #include "shelltest.h" 9 #include <windowsx.h> 10 #include <shlwapi.h> 11 #include <stdio.h> 12 13 /* Based on https://github.com/katahiromz/AppBarSample */ 14 15 //#define VERBOSE 16 17 #define IDT_AUTOHIDE 1 18 #define IDT_AUTOUNHIDE 2 19 20 #define ID_ACTION 100 21 22 #define APPBAR_CALLBACK (WM_USER + 100) 23 24 #define LEFT_DOWN() mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0); 25 #define LEFT_UP() mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0); 26 #define MOVE(x, y) SetCursorPos((x), (y)) 27 28 static const TCHAR s_szName[] = TEXT("AppBarSample"); 29 static RECT s_rcWorkArea; 30 static HWND s_hwnd1 = NULL; 31 static HWND s_hwnd2 = NULL; 32 33 #ifdef VERBOSE 34 static LPCSTR MessageOfAppBar(DWORD dwMessage) 35 { 36 static char s_buf[32]; 37 switch (dwMessage) 38 { 39 case ABM_NEW: return "ABM_NEW"; 40 case ABM_REMOVE: return "ABM_REMOVE"; 41 case ABM_QUERYPOS: return "ABM_QUERYPOS"; 42 case ABM_SETPOS: return "ABM_SETPOS"; 43 case ABM_GETSTATE: return "ABM_GETSTATE"; 44 case ABM_GETTASKBARPOS: return "ABM_GETTASKBARPOS"; 45 case ABM_ACTIVATE: return "ABM_ACTIVATE"; 46 case ABM_GETAUTOHIDEBAR: return "ABM_GETAUTOHIDEBAR"; 47 case ABM_SETAUTOHIDEBAR: return "ABM_SETAUTOHIDEBAR"; 48 case ABM_WINDOWPOSCHANGED: return "ABM_WINDOWPOSCHANGED"; 49 } 50 wsprintfA(s_buf, "%lu", dwMessage); 51 return s_buf; 52 } 53 54 static UINT WINAPI 55 SHAppBarMessageWrap(DWORD dwMessage, PAPPBARDATA pData) 56 { 57 trace("SHAppBarMessage entered (dwMessage=%s, rc=(%ld, %ld, %ld, %ld))\n", 58 MessageOfAppBar(dwMessage), 59 pData->rc.left, pData->rc.top, pData->rc.right, pData->rc.bottom); 60 UINT ret = SHAppBarMessage(dwMessage, pData); 61 trace("SHAppBarMessage leaved (dwMessage=%s, rc=(%ld, %ld, %ld, %ld))\n", 62 MessageOfAppBar(dwMessage), 63 pData->rc.left, pData->rc.top, pData->rc.right, pData->rc.bottom); 64 return ret; 65 } 66 #define SHAppBarMessage SHAppBarMessageWrap 67 68 #undef ARRAYSIZE 69 #define ARRAYSIZE _countof 70 71 void appbar_tprintf(const TCHAR *fmt, ...) 72 { 73 TCHAR szText[512]; 74 va_list va; 75 va_start(va, fmt); 76 wvsprintf(szText, fmt, va); 77 #ifdef UNICODE 78 printf("%ls", szText); 79 #else 80 printf("%s", szText); 81 #endif 82 va_end(va); 83 } 84 85 #define MSGDUMP_TPRINTF appbar_tprintf 86 #include "msgdump.h" 87 88 #endif // def VERBOSE 89 90 void SlideWindow(HWND hwnd, LPRECT prc) 91 { 92 #define SLIDE_HIDE 400 93 #define SLIDE_SHOW 150 94 RECT rcOld, rcNew = *prc; 95 GetWindowRect(hwnd, &rcOld); 96 97 BOOL fShow = (rcNew.bottom - rcNew.top > rcOld.bottom - rcOld.top) || 98 (rcNew.right - rcNew.left > rcOld.right - rcOld.left); 99 100 INT dx = (rcNew.right - rcOld.right) + (rcNew.left - rcOld.left); 101 INT dy = (rcNew.bottom - rcOld.bottom) + (rcNew.top - rcOld.top); 102 103 LONG dt = SLIDE_HIDE; 104 if (fShow) 105 { 106 dt = SLIDE_SHOW; 107 rcOld = rcNew; 108 OffsetRect(&rcOld, -dx, -dy); 109 SetWindowPos(hwnd, NULL, rcOld.left, rcOld.top, 110 rcOld.right - rcOld.left, rcOld.bottom - rcOld.top, 111 SWP_NOZORDER | SWP_NOACTIVATE | SWP_DRAWFRAME); 112 } 113 114 HANDLE hThread = GetCurrentThread(); 115 INT priority = GetThreadPriority(hThread); 116 SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST); 117 118 LONG t, t0 = GetTickCount(); 119 while ((t = GetTickCount()) < t0 + dt) 120 { 121 INT x = rcOld.left + dx * (t - t0) / dt; 122 INT y = rcOld.top + dy * (t - t0) / dt; 123 SetWindowPos(hwnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); 124 125 UpdateWindow(hwnd); 126 UpdateWindow(GetDesktopWindow()); 127 } 128 129 SetThreadPriority(hThread, priority); 130 SetWindowPos(hwnd, NULL, rcNew.left, rcNew.top, 131 rcNew.right - rcNew.left, rcNew.bottom - rcNew.top, 132 SWP_NOZORDER | SWP_NOACTIVATE | SWP_DRAWFRAME); 133 #undef SLIDE_HIDE 134 #undef SLIDE_SHOW 135 } 136 137 class Window 138 { 139 public: 140 Window(INT cx, INT cy, BOOL fAutoHide = FALSE) 141 : m_hwnd(NULL) 142 , m_fAutoHide(fAutoHide) 143 , m_cxWidth(cx) 144 , m_cyHeight(cy) 145 { 146 } 147 148 virtual ~Window() 149 { 150 } 151 152 static BOOL DoRegisterClass(HINSTANCE hInstance) 153 { 154 WNDCLASS wc; 155 ZeroMemory(&wc, sizeof(wc)); 156 wc.lpfnWndProc = Window::WindowProc; 157 wc.hInstance = hInstance; 158 wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); 159 wc.hCursor = LoadCursor(NULL, IDC_ARROW); 160 wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); 161 wc.lpszClassName = s_szName; 162 return !!RegisterClass(&wc); 163 } 164 165 static HWND DoCreateMainWnd(HINSTANCE hInstance, LPCTSTR pszText, INT cx, INT cy, 166 DWORD style = WS_POPUP | WS_THICKFRAME | WS_CLIPCHILDREN, 167 DWORD exstyle = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST, 168 BOOL fAutoHide = FALSE) 169 { 170 Window *this_ = new Window(cx, cy, fAutoHide); 171 HWND hwnd = CreateWindowEx(exstyle, s_szName, pszText, style, 172 CW_USEDEFAULT, CW_USEDEFAULT, 50, 50, 173 NULL, NULL, hInstance, this_); 174 ShowWindow(hwnd, SW_SHOWNORMAL); 175 UpdateWindow(hwnd); 176 return hwnd; 177 } 178 179 static INT DoMainLoop() 180 { 181 MSG msg; 182 while (GetMessage(&msg, NULL, 0, 0)) 183 { 184 TranslateMessage(&msg); 185 DispatchMessage(&msg); 186 } 187 return (INT)msg.wParam; 188 } 189 190 static Window *GetAppbarData(HWND hwnd) 191 { 192 return (Window *)GetWindowLongPtr(hwnd, GWLP_USERDATA); 193 } 194 195 virtual LRESULT CALLBACK 196 WindowProcDx(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 197 { 198 #ifdef VERBOSE 199 MD_msgdump(hwnd, uMsg, wParam, lParam); 200 #endif 201 switch (uMsg) 202 { 203 HANDLE_MSG(hwnd, WM_CREATE, OnCreate); 204 HANDLE_MSG(hwnd, WM_COMMAND, OnCommand); 205 HANDLE_MSG(hwnd, WM_ACTIVATE, OnActivate); 206 HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGED, OnWindowPosChanged); 207 HANDLE_MSG(hwnd, WM_SIZE, OnSize); 208 HANDLE_MSG(hwnd, WM_MOVE, OnMove); 209 HANDLE_MSG(hwnd, WM_NCDESTROY, OnNCDestroy); 210 HANDLE_MSG(hwnd, WM_TIMER, OnTimer); 211 HANDLE_MSG(hwnd, WM_NCHITTEST, OnNCHitTest); 212 HANDLE_MSG(hwnd, WM_LBUTTONDOWN, OnLButtonDown); 213 HANDLE_MSG(hwnd, WM_MOUSEMOVE, OnMouseMove); 214 HANDLE_MSG(hwnd, WM_LBUTTONUP, OnLButtonUp); 215 HANDLE_MSG(hwnd, WM_RBUTTONDOWN, OnRButtonDown); 216 HANDLE_MSG(hwnd, WM_KEYDOWN, OnKey); 217 HANDLE_MSG(hwnd, WM_PAINT, OnPaint); 218 219 case APPBAR_CALLBACK: 220 OnAppBarCallback(hwnd, uMsg, wParam, lParam); 221 break; 222 223 default: 224 return DefWindowProc(hwnd, uMsg, wParam, lParam); 225 } 226 return 0; 227 } 228 229 static LRESULT CALLBACK 230 WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 231 { 232 Window *this_ = GetAppbarData(hwnd); 233 if (uMsg == WM_CREATE) 234 { 235 LPCREATESTRUCT pCS = (LPCREATESTRUCT)lParam; 236 this_ = (Window *)pCS->lpCreateParams; 237 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this_); 238 } 239 if (this_) 240 return this_->WindowProcDx(hwnd, uMsg, wParam, lParam); 241 return DefWindowProc(hwnd, uMsg, wParam, lParam); 242 } 243 244 protected: 245 HWND m_hwnd; 246 BOOL m_fAutoHide; 247 BOOL m_fOnTop; 248 BOOL m_fHiding; 249 UINT m_uSide; 250 LONG m_cxWidth; 251 LONG m_cyHeight; 252 LONG m_cxSave; 253 LONG m_cySave; 254 BOOL m_fAppBarRegd; 255 BOOL m_fMoving; 256 BOOL m_bDragged; 257 POINT m_ptDragOn; 258 RECT m_rcAppBar; 259 RECT m_rcDrag; 260 261 void OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) 262 { 263 HANDLE hThread; 264 switch (id) 265 { 266 case ID_ACTION: 267 PostMessage(s_hwnd2, WM_COMMAND, ID_ACTION + 1, 0); 268 break; 269 case ID_ACTION + 1: 270 hThread = CreateThread(NULL, 0, ActionThreadFunc, this, 0, NULL); 271 if (!hThread) 272 { 273 skip("failed to create thread\n"); 274 PostMessage(s_hwnd1, WM_CLOSE, 0, 0); 275 PostMessage(s_hwnd2, WM_CLOSE, 0, 0); 276 return; 277 } 278 CloseHandle(hThread); 279 } 280 } 281 282 void OnPaint(HWND hwnd) 283 { 284 PAINTSTRUCT ps; 285 286 TCHAR szText[64]; 287 GetWindowText(hwnd, szText, 64); 288 289 RECT rc; 290 GetClientRect(hwnd, &rc); 291 292 if (HDC hdc = BeginPaint(hwnd, &ps)) 293 { 294 DrawText(hdc, szText, -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER); 295 EndPaint(hwnd, &ps); 296 } 297 } 298 299 void OnRButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags) 300 { 301 m_fAutoHide = !m_fAutoHide; 302 AppBar_SetAutoHide(hwnd, m_fAutoHide); 303 } 304 305 void OnKey(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags) 306 { 307 if (vk == VK_ESCAPE) 308 DestroyWindow(hwnd); 309 } 310 311 void OnAppBarCallback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 312 { 313 static HWND s_hwndZOrder = NULL; 314 315 switch (wParam) 316 { 317 case ABN_STATECHANGE: 318 break; 319 320 case ABN_FULLSCREENAPP: 321 if (lParam) 322 { 323 s_hwndZOrder = GetWindow(hwnd, GW_HWNDPREV); 324 SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, 325 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); 326 } 327 else 328 { 329 SetWindowPos(hwnd, m_fOnTop ? HWND_TOPMOST : s_hwndZOrder, 330 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); 331 s_hwndZOrder = NULL; 332 } 333 break; 334 335 case ABN_POSCHANGED: 336 { 337 APPBARDATA abd = { sizeof(abd) }; 338 abd.hWnd = hwnd; 339 AppBar_PosChanged(&abd); 340 } 341 break; 342 } 343 } 344 345 BOOL AppBar_Register(HWND hwnd) 346 { 347 APPBARDATA abd = { sizeof(abd) }; 348 abd.hWnd = hwnd; 349 abd.uCallbackMessage = APPBAR_CALLBACK; 350 351 m_fAppBarRegd = (BOOL)SHAppBarMessage(ABM_NEW, &abd); 352 return m_fAppBarRegd; 353 } 354 355 BOOL AppBar_UnRegister(HWND hwnd) 356 { 357 APPBARDATA abd = { sizeof(abd) }; 358 abd.hWnd = hwnd; 359 360 m_fAppBarRegd = !SHAppBarMessage(ABM_REMOVE, &abd); 361 return !m_fAppBarRegd; 362 } 363 364 BOOL AppBar_SetAutoHide(HWND hwnd, BOOL fHide) 365 { 366 if (fHide) 367 return AppBar_AutoHide(hwnd); 368 else 369 return AppBar_NoAutoHide(hwnd); 370 } 371 372 BOOL AppBar_AutoHide(HWND hwnd) 373 { 374 APPBARDATA abd = { sizeof(abd) }; 375 abd.hWnd = hwnd; 376 abd.uEdge = m_uSide; 377 378 HWND hwndAutoHide = (HWND)SHAppBarMessage(ABM_GETAUTOHIDEBAR, &abd); 379 if (hwndAutoHide) 380 return FALSE; 381 382 abd.lParam = TRUE; 383 if (!(BOOL)SHAppBarMessage(ABM_SETAUTOHIDEBAR, &abd)) 384 return FALSE; 385 386 m_fAutoHide = TRUE; 387 m_cxSave = m_cxWidth; 388 m_cySave = m_cyHeight; 389 390 RECT rc = m_rcAppBar; 391 switch (m_uSide) 392 { 393 case ABE_TOP: 394 rc.bottom = rc.top + 2; 395 break; 396 case ABE_BOTTOM: 397 rc.top = rc.bottom - 2; 398 break; 399 case ABE_LEFT: 400 rc.right = rc.left + 2; 401 break; 402 case ABE_RIGHT: 403 rc.left = rc.right - 2; 404 break; 405 } 406 407 AppBar_QueryPos(hwnd, &rc); 408 abd.rc = rc; 409 SHAppBarMessage(ABM_SETPOS, &abd); 410 rc = abd.rc; 411 412 m_fHiding = TRUE; 413 SlideWindow(hwnd, &rc); 414 415 AppBar_SetAutoHideTimer(hwnd); 416 return TRUE; 417 } 418 419 BOOL AppBar_NoAutoHide(HWND hwnd) 420 { 421 APPBARDATA abd = { sizeof(abd) }; 422 abd.hWnd = hwnd; 423 abd.uEdge = m_uSide; 424 HWND hwndAutoHide = (HWND)SHAppBarMessage(ABM_GETAUTOHIDEBAR, &abd); 425 if (hwndAutoHide != hwnd) 426 return FALSE; 427 428 abd.lParam = FALSE; 429 if (!(BOOL)SHAppBarMessage(ABM_SETAUTOHIDEBAR, &abd)) 430 return FALSE; 431 432 m_fAutoHide = FALSE; 433 m_cxWidth = m_cxSave; 434 m_cyHeight = m_cySave; 435 AppBar_SetSide(hwnd, m_uSide); 436 return TRUE; 437 } 438 439 BOOL AppBar_SetSide(HWND hwnd, UINT uSide) 440 { 441 RECT rc; 442 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); 443 444 BOOL fAutoHide = FALSE; 445 if (m_fAutoHide) 446 { 447 fAutoHide = m_fAutoHide; 448 SetWindowRedraw(GetDesktopWindow(), FALSE); 449 AppBar_SetAutoHide(hwnd, FALSE); 450 m_fHiding = FALSE; 451 } 452 453 switch (uSide) 454 { 455 case ABE_TOP: 456 rc.bottom = rc.top + m_cyHeight; 457 break; 458 case ABE_BOTTOM: 459 rc.top = rc.bottom - m_cyHeight; 460 break; 461 case ABE_LEFT: 462 rc.right = rc.left + m_cxWidth; 463 break; 464 case ABE_RIGHT: 465 rc.left = rc.right - m_cxWidth; 466 break; 467 } 468 469 APPBARDATA abd = { sizeof(abd) }; 470 abd.hWnd = hwnd; 471 AppBar_QuerySetPos(uSide, &rc, &abd, TRUE); 472 473 if (fAutoHide) 474 { 475 AppBar_SetAutoHide(hwnd, TRUE); 476 m_fHiding = TRUE; 477 478 SetWindowRedraw(GetDesktopWindow(), TRUE); 479 RedrawWindow(GetDesktopWindow(), NULL, NULL, 480 RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); 481 } 482 483 return TRUE; 484 } 485 486 void AppBar_SetAlwaysOnTop(HWND hwnd, BOOL fOnTop) 487 { 488 SetWindowPos(hwnd, (fOnTop ? HWND_TOPMOST : HWND_NOTOPMOST), 489 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); 490 m_fOnTop = fOnTop; 491 } 492 493 void AppBar_Hide(HWND hwnd) 494 { 495 if (!m_fAutoHide) 496 return; 497 498 RECT rc = m_rcAppBar; 499 switch (m_uSide) 500 { 501 case ABE_TOP: 502 rc.bottom = rc.top + 2; 503 break; 504 case ABE_BOTTOM: 505 rc.top = rc.bottom - 2; 506 break; 507 case ABE_LEFT: 508 rc.right = rc.left + 2; 509 break; 510 case ABE_RIGHT: 511 rc.left = rc.right - 2; 512 break; 513 } 514 515 m_fHiding = TRUE; 516 SlideWindow(hwnd, &rc); 517 } 518 519 void AppBar_UnHide(HWND hwnd) 520 { 521 SlideWindow(hwnd, &m_rcAppBar); 522 m_fHiding = FALSE; 523 524 AppBar_SetAutoHideTimer(hwnd); 525 } 526 527 void AppBar_SetAutoHideTimer(HWND hwnd) 528 { 529 if (m_fAutoHide) 530 { 531 SetTimer(hwnd, IDT_AUTOHIDE, 500, NULL); 532 } 533 } 534 535 void AppBar_SetAutoUnhideTimer(HWND hwnd) 536 { 537 if (m_fAutoHide && m_fHiding) 538 { 539 SetTimer(hwnd, IDT_AUTOUNHIDE, 50, NULL); 540 } 541 } 542 543 void AppBar_Size(HWND hwnd) 544 { 545 if (m_fAppBarRegd) 546 { 547 APPBARDATA abd = { sizeof(abd) }; 548 abd.hWnd = hwnd; 549 550 RECT rc; 551 GetWindowRect(hwnd, &rc); 552 AppBar_QuerySetPos(m_uSide, &rc, &abd, TRUE); 553 } 554 } 555 556 void AppBar_QueryPos(HWND hwnd, LPRECT lprc) 557 { 558 APPBARDATA abd = { sizeof(abd) }; 559 abd.hWnd = hwnd; 560 abd.rc = *lprc; 561 abd.uEdge = m_uSide; 562 563 INT cx = 0, cy = 0; 564 if (ABE_LEFT == abd.uEdge || ABE_RIGHT == abd.uEdge) 565 { 566 cx = abd.rc.right - abd.rc.left; 567 abd.rc.top = 0; 568 abd.rc.bottom = GetSystemMetrics(SM_CYSCREEN); 569 } 570 else 571 { 572 cy = abd.rc.bottom - abd.rc.top; 573 abd.rc.left = 0; 574 abd.rc.right = GetSystemMetrics(SM_CXSCREEN); 575 } 576 577 SHAppBarMessage(ABM_QUERYPOS, &abd); 578 579 switch (abd.uEdge) 580 { 581 case ABE_LEFT: 582 abd.rc.right = abd.rc.left + cx; 583 break; 584 case ABE_RIGHT: 585 abd.rc.left = abd.rc.right - cx; 586 break; 587 case ABE_TOP: 588 abd.rc.bottom = abd.rc.top + cy; 589 break; 590 case ABE_BOTTOM: 591 abd.rc.top = abd.rc.bottom - cy; 592 break; 593 } 594 595 *lprc = abd.rc; 596 } 597 598 void AppBar_QuerySetPos(UINT uEdge, LPRECT lprc, PAPPBARDATA pabd, BOOL fMove) 599 { 600 pabd->rc = *lprc; 601 pabd->uEdge = uEdge; 602 m_uSide = uEdge; 603 604 AppBar_QueryPos(pabd->hWnd, &pabd->rc); 605 606 SHAppBarMessage(ABM_SETPOS, pabd); 607 608 if (fMove) 609 { 610 RECT rc = pabd->rc; 611 MoveWindow(pabd->hWnd, rc.left, rc.top, 612 rc.right - rc.left, rc.bottom - rc.top, TRUE); 613 } 614 615 if (!m_fAutoHide) 616 { 617 m_rcAppBar = pabd->rc; 618 } 619 } 620 621 void AppBar_PosChanged(PAPPBARDATA pabd) 622 { 623 RECT rc; 624 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); 625 626 if (m_fAutoHide) 627 { 628 m_rcAppBar = rc; 629 switch (m_uSide) 630 { 631 case ABE_TOP: 632 m_rcAppBar.bottom = m_rcAppBar.top + m_cySave; 633 break; 634 case ABE_BOTTOM: 635 m_rcAppBar.top = m_rcAppBar.bottom - m_cySave; 636 break; 637 case ABE_LEFT: 638 m_rcAppBar.right = m_rcAppBar.left + m_cxSave; 639 break; 640 case ABE_RIGHT: 641 m_rcAppBar.left = m_rcAppBar.right - m_cxSave; 642 break; 643 } 644 } 645 646 RECT rcWindow; 647 GetWindowRect(pabd->hWnd, &rcWindow); 648 INT cx = rcWindow.right - rcWindow.left; 649 INT cy = rcWindow.bottom - rcWindow.top; 650 switch (m_uSide) 651 { 652 case ABE_TOP: 653 rc.bottom = rc.top + cy; 654 break; 655 case ABE_BOTTOM: 656 rc.top = rc.bottom - cy; 657 break; 658 case ABE_LEFT: 659 rc.right = rc.left + cx; 660 break; 661 case ABE_RIGHT: 662 rc.left = rc.right - cx; 663 break; 664 } 665 AppBar_QuerySetPos(m_uSide, &rc, pabd, TRUE); 666 } 667 668 BOOL OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct) 669 { 670 m_hwnd = hwnd; 671 m_fOnTop = TRUE; 672 m_uSide = ABE_TOP; 673 674 m_fAppBarRegd = FALSE; 675 m_fMoving = FALSE; 676 m_cxSave = m_cxWidth; 677 m_cySave = m_cyHeight; 678 m_bDragged = FALSE; 679 680 AppBar_Register(hwnd); 681 AppBar_SetSide(hwnd, ABE_TOP); 682 683 return TRUE; 684 } 685 686 void OnActivate(HWND hwnd, UINT state, HWND hwndActDeact, BOOL fMinimized) 687 { 688 APPBARDATA abd = { sizeof(abd) }; 689 abd.hWnd = hwnd; 690 SHAppBarMessage(ABM_ACTIVATE, &abd); 691 692 switch (state) 693 { 694 case WA_ACTIVE: 695 case WA_CLICKACTIVE: 696 AppBar_UnHide(hwnd); 697 KillTimer(hwnd, IDT_AUTOHIDE); 698 break; 699 700 case WA_INACTIVE: 701 AppBar_Hide(hwnd); 702 break; 703 } 704 } 705 706 void OnWindowPosChanged(HWND hwnd, const LPWINDOWPOS lpwpos) 707 { 708 APPBARDATA abd = { sizeof(abd) }; 709 abd.hWnd = hwnd; 710 SHAppBarMessage(ABM_WINDOWPOSCHANGED, &abd); 711 712 FORWARD_WM_WINDOWPOSCHANGED(hwnd, lpwpos, DefWindowProc); 713 } 714 715 void OnSize(HWND hwnd, UINT state, int cx, int cy) 716 { 717 RECT rcWindow; 718 719 if (m_fMoving || (m_fAutoHide && m_fHiding)) 720 return; 721 722 if (!m_fHiding) 723 { 724 if (!m_fAutoHide) 725 AppBar_Size(hwnd); 726 727 GetWindowRect(hwnd, &rcWindow); 728 m_rcAppBar = rcWindow; 729 730 if (m_uSide == ABE_TOP || m_uSide == ABE_BOTTOM) 731 { 732 m_cyHeight = m_cySave = rcWindow.bottom - rcWindow.top; 733 } 734 else 735 { 736 m_cxWidth = m_cxSave = rcWindow.right - rcWindow.left; 737 } 738 } 739 740 InvalidateRect(hwnd, NULL, TRUE); 741 } 742 743 void OnMove(HWND hwnd, int x, int y) 744 { 745 if (m_fMoving || m_fAutoHide) 746 return; 747 748 if (!m_fHiding) 749 AppBar_Size(hwnd); 750 } 751 752 void OnNCDestroy(HWND hwnd) 753 { 754 AppBar_UnRegister(hwnd); 755 756 m_hwnd = NULL; 757 SetWindowLongPtr(hwnd, GWLP_USERDATA, 0); 758 delete this; 759 } 760 761 void OnTimer(HWND hwnd, UINT id) 762 { 763 POINT pt; 764 RECT rc; 765 HWND hwndActive; 766 767 switch (id) 768 { 769 case IDT_AUTOHIDE: 770 if (m_fAutoHide && !m_fHiding && !m_fMoving) 771 { 772 GetCursorPos(&pt); 773 GetWindowRect(hwnd, &rc); 774 hwndActive = GetForegroundWindow(); 775 776 if (!PtInRect(&rc, pt) && 777 hwndActive != hwnd && 778 hwndActive != NULL && 779 GetWindowOwner(hwndActive) != hwnd) 780 { 781 KillTimer(hwnd, id); 782 AppBar_Hide(hwnd); 783 } 784 } 785 break; 786 787 case IDT_AUTOUNHIDE: 788 KillTimer(hwnd, id); 789 790 if (m_fAutoHide && m_fHiding) 791 { 792 GetCursorPos(&pt); 793 GetWindowRect(hwnd, &rc); 794 if (PtInRect(&rc, pt)) 795 { 796 AppBar_UnHide(hwnd); 797 } 798 } 799 break; 800 } 801 } 802 803 UINT OnNCHitTest(HWND hwnd, int x, int y) 804 { 805 AppBar_SetAutoUnhideTimer(hwnd); 806 807 UINT uHitTest = FORWARD_WM_NCHITTEST(hwnd, x, y, DefWindowProc); 808 809 if (m_uSide == ABE_TOP && uHitTest == HTBOTTOM) 810 return HTBOTTOM; 811 812 if (m_uSide == ABE_BOTTOM && uHitTest == HTTOP) 813 return HTTOP; 814 815 if (m_uSide == ABE_LEFT && uHitTest == HTRIGHT) 816 return HTRIGHT; 817 818 if (m_uSide == ABE_RIGHT && uHitTest == HTLEFT) 819 return HTLEFT; 820 821 return HTCLIENT; 822 } 823 824 void OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags) 825 { 826 m_fMoving = TRUE; 827 m_bDragged = FALSE; 828 SetCapture(hwnd); 829 GetCursorPos(&m_ptDragOn); 830 } 831 832 void OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags) 833 { 834 if (!m_fMoving) 835 return; 836 837 POINT pt; 838 GetCursorPos(&pt); 839 if (labs(pt.x - m_ptDragOn.x) > GetSystemMetrics(SM_CXDRAG) || 840 labs(pt.y - m_ptDragOn.y) > GetSystemMetrics(SM_CYDRAG)) 841 { 842 m_bDragged = TRUE; 843 } 844 845 INT cxScreen = GetSystemMetrics(SM_CXSCREEN); 846 INT cyScreen = GetSystemMetrics(SM_CYSCREEN); 847 848 DWORD dx, dy; 849 UINT ix, iy; 850 if (pt.x < cxScreen / 2) 851 { 852 dx = pt.x; 853 ix = ABE_LEFT; 854 } 855 else 856 { 857 dx = cxScreen - pt.x; 858 ix = ABE_RIGHT; 859 } 860 861 if (pt.y < cyScreen / 2) 862 { 863 dy = pt.y; 864 iy = ABE_TOP; 865 } 866 else 867 { 868 dy = cyScreen - pt.y; 869 iy = ABE_BOTTOM; 870 } 871 872 if (cxScreen * dy > cyScreen * dx) 873 { 874 m_rcDrag.top = 0; 875 m_rcDrag.bottom = cyScreen; 876 if (ix == ABE_LEFT) 877 { 878 m_uSide = ABE_LEFT; 879 m_rcDrag.left = 0; 880 m_rcDrag.right = m_rcDrag.left + m_cxWidth; 881 } 882 else 883 { 884 m_uSide = ABE_RIGHT; 885 m_rcDrag.right = cxScreen; 886 m_rcDrag.left = m_rcDrag.right - m_cxWidth; 887 } 888 } 889 else 890 { 891 m_rcDrag.left = 0; 892 m_rcDrag.right = cxScreen; 893 if (iy == ABE_TOP) 894 { 895 m_uSide = ABE_TOP; 896 m_rcDrag.top = 0; 897 m_rcDrag.bottom = m_rcDrag.top + m_cyHeight; 898 } 899 else 900 { 901 m_uSide = ABE_BOTTOM; 902 m_rcDrag.bottom = cyScreen; 903 m_rcDrag.top = m_rcDrag.bottom - m_cyHeight; 904 } 905 } 906 907 AppBar_QueryPos(hwnd, &m_rcDrag); 908 909 if (m_bDragged) 910 { 911 MoveWindow(hwnd, m_rcDrag.left, m_rcDrag.top, 912 m_rcDrag.right - m_rcDrag.left, 913 m_rcDrag.bottom - m_rcDrag.top, 914 TRUE); 915 } 916 } 917 918 void OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags) 919 { 920 if (!m_fMoving) 921 return; 922 923 OnMouseMove(hwnd, x, y, keyFlags); 924 925 m_rcAppBar = m_rcDrag; 926 927 ReleaseCapture(); 928 929 if (m_fAutoHide) 930 { 931 switch (m_uSide) 932 { 933 case ABE_TOP: 934 m_rcDrag.bottom = m_rcDrag.top + 2; 935 break; 936 case ABE_BOTTOM: 937 m_rcDrag.top = m_rcDrag.bottom - 2; 938 break; 939 case ABE_LEFT: 940 m_rcDrag.right = m_rcDrag.left + 2; 941 break; 942 case ABE_RIGHT: 943 m_rcDrag.left = m_rcDrag.right - 2; 944 break; 945 } 946 } 947 948 if (m_bDragged) 949 { 950 if (m_fAutoHide) 951 { 952 AppBar_AutoHide(hwnd); 953 } 954 else 955 { 956 APPBARDATA abd = { sizeof(abd) }; 957 abd.hWnd = hwnd; 958 AppBar_QuerySetPos(m_uSide, &m_rcDrag, &abd, FALSE); 959 } 960 } 961 962 m_fMoving = FALSE; 963 } 964 965 public: 966 void DoAction() 967 { 968 #define INTERVAL 250 969 POINT pt; 970 RECT rc1, rc2; 971 DWORD dwTID = GetWindowThreadProcessId(s_hwnd1, NULL); 972 973 GetWindowRect(s_hwnd1, &rc1); 974 GetWindowRect(s_hwnd2, &rc2); 975 ok_long(rc1.left, s_rcWorkArea.left); 976 ok_long(rc1.top, s_rcWorkArea.top); 977 ok_long(rc1.right, s_rcWorkArea.right); 978 ok_long(rc1.bottom, s_rcWorkArea.top + 80); 979 ok_long(rc2.left, s_rcWorkArea.left); 980 ok_long(rc2.top, s_rcWorkArea.top + 80); 981 ok_long(rc2.right, s_rcWorkArea.right); 982 ok_long(rc2.bottom, s_rcWorkArea.top + 110); 983 PostMessage(s_hwnd1, WM_CLOSE, 0, 0); 984 Sleep(INTERVAL); 985 986 GetWindowRect(s_hwnd2, &rc2); 987 ok_long(rc2.left, s_rcWorkArea.left); 988 ok_long(rc2.top, s_rcWorkArea.top); 989 ok_long(rc2.right, s_rcWorkArea.right); 990 ok_long(rc2.bottom, s_rcWorkArea.top + 30); 991 AppBar_SetSide(s_hwnd2, ABE_LEFT); 992 Sleep(INTERVAL); 993 994 GetWindowRect(s_hwnd2, &rc2); 995 ok_long(rc2.left, s_rcWorkArea.left); 996 ok_long(rc2.top, s_rcWorkArea.top); 997 ok_long(rc2.right, s_rcWorkArea.left + 30); 998 AppBar_SetSide(s_hwnd2, ABE_TOP); 999 Sleep(INTERVAL); 1000 1001 GetWindowRect(s_hwnd2, &rc2); 1002 ok_long(rc2.left, s_rcWorkArea.left); 1003 ok_long(rc2.top, s_rcWorkArea.top); 1004 ok_long(rc2.right, s_rcWorkArea.right); 1005 ok_long(rc2.bottom, s_rcWorkArea.top + 30); 1006 AppBar_SetSide(s_hwnd2, ABE_RIGHT); 1007 Sleep(INTERVAL); 1008 1009 GetWindowRect(s_hwnd2, &rc2); 1010 ok_long(rc2.left, s_rcWorkArea.right - 30); 1011 ok_long(rc2.top, s_rcWorkArea.top); 1012 ok_long(rc2.right, s_rcWorkArea.right); 1013 Sleep(INTERVAL); 1014 1015 GetWindowRect(s_hwnd2, &rc2); 1016 pt.x = (rc2.left + rc2.right) / 2; 1017 pt.y = (rc2.top + rc2.bottom) / 2; 1018 MOVE(pt.x, pt.y); 1019 LEFT_DOWN(); 1020 MOVE(pt.x + 64, pt.y + 64); 1021 Sleep(INTERVAL); 1022 1023 pt.x = s_rcWorkArea.left + 80; 1024 pt.y = (s_rcWorkArea.top + s_rcWorkArea.bottom) / 2; 1025 MOVE(pt.x, pt.y); 1026 LEFT_UP(); 1027 Sleep(INTERVAL); 1028 1029 GetWindowRect(s_hwnd2, &rc2); 1030 ok_long(rc2.left, s_rcWorkArea.left); 1031 ok_long(rc2.top, s_rcWorkArea.top); 1032 ok_long(rc2.right, s_rcWorkArea.left + 30); 1033 Sleep(INTERVAL); 1034 1035 GetWindowRect(s_hwnd2, &rc2); 1036 pt.x = (rc2.left + rc2.right) / 2; 1037 pt.y = (rc2.top + rc2.bottom) / 2; 1038 MOVE(pt.x, pt.y); 1039 LEFT_DOWN(); 1040 MOVE(pt.x + 64, pt.y + 64); 1041 Sleep(INTERVAL); 1042 1043 pt.x = s_rcWorkArea.right - 80; 1044 pt.y = (s_rcWorkArea.top + s_rcWorkArea.bottom) / 2; 1045 MOVE(pt.x, pt.y); 1046 LEFT_UP(); 1047 Sleep(INTERVAL); 1048 1049 GetWindowRect(s_hwnd2, &rc2); 1050 ok_long(rc2.left, s_rcWorkArea.right - 30); 1051 ok_long(rc2.top, s_rcWorkArea.top); 1052 ok_long(rc2.right, s_rcWorkArea.right); 1053 Sleep(INTERVAL); 1054 1055 PostMessage(s_hwnd2, WM_CLOSE, 0, 0); 1056 PostMessage(s_hwnd2, WM_QUIT, 0, 0); 1057 PostThreadMessage(dwTID, WM_QUIT, 0, 0); 1058 #undef INTERVAL 1059 } 1060 1061 static DWORD WINAPI ActionThreadFunc(LPVOID args) 1062 { 1063 Window *this_ = (Window *)args; 1064 this_->DoAction(); 1065 return 0; 1066 } 1067 }; 1068 1069 START_TEST(SHAppBarMessage) 1070 { 1071 HINSTANCE hInstance = GetModuleHandle(NULL); 1072 1073 if (!Window::DoRegisterClass(hInstance)) 1074 { 1075 skip("Window::DoRegisterClass failed\n"); 1076 return; 1077 } 1078 1079 SystemParametersInfo(SPI_GETWORKAREA, 0, &s_rcWorkArea, FALSE); 1080 1081 HWND hwnd1 = Window::DoCreateMainWnd(hInstance, TEXT("Test1"), 80, 80, 1082 WS_POPUP | WS_THICKFRAME | WS_CLIPCHILDREN); 1083 if (!hwnd1) 1084 { 1085 skip("CreateWindowExW failed\n"); 1086 return; 1087 } 1088 1089 HWND hwnd2 = Window::DoCreateMainWnd(hInstance, TEXT("Test2"), 30, 30, 1090 WS_POPUP | WS_BORDER | WS_CLIPCHILDREN); 1091 if (!hwnd2) 1092 { 1093 skip("CreateWindowExW failed\n"); 1094 return; 1095 } 1096 1097 s_hwnd1 = hwnd1; 1098 s_hwnd2 = hwnd2; 1099 1100 PostMessage(hwnd1, WM_COMMAND, ID_ACTION, 0); 1101 1102 Window::DoMainLoop(); 1103 } 1104