Reactos
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-2025 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#define ID_QUIT 999
22
23#define APPBAR_CALLBACK (WM_USER + 100)
24
25#define LEFT_DOWN() mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
26#define LEFT_UP() mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
27#define MOVE(x, y) SetCursorPos((x), (y))
28
29#define INTERVAL 250
30#define LONG_INTERVAL 2500
31
32static const TCHAR s_szName[] = TEXT("AppBarSample");
33static RECT s_rcPrimaryMonitor;
34static RECT s_rcWorkArea;
35static RECT s_rcTaskBar;
36static HWND s_hwnd1 = NULL;
37static HWND s_hwnd2 = NULL;
38
39#ifdef VERBOSE
40static LPCSTR MessageOfAppBar(DWORD dwMessage)
41{
42 static char s_buf[32];
43 switch (dwMessage)
44 {
45 case ABM_NEW: return "ABM_NEW";
46 case ABM_REMOVE: return "ABM_REMOVE";
47 case ABM_QUERYPOS: return "ABM_QUERYPOS";
48 case ABM_SETPOS: return "ABM_SETPOS";
49 case ABM_GETSTATE: return "ABM_GETSTATE";
50 case ABM_GETTASKBARPOS: return "ABM_GETTASKBARPOS";
51 case ABM_ACTIVATE: return "ABM_ACTIVATE";
52 case ABM_GETAUTOHIDEBAR: return "ABM_GETAUTOHIDEBAR";
53 case ABM_SETAUTOHIDEBAR: return "ABM_SETAUTOHIDEBAR";
54 case ABM_WINDOWPOSCHANGED: return "ABM_WINDOWPOSCHANGED";
55 }
56 wsprintfA(s_buf, "%lu", dwMessage);
57 return s_buf;
58}
59
60static UINT WINAPI
61SHAppBarMessageWrap(DWORD dwMessage, PAPPBARDATA pData)
62{
63 trace("SHAppBarMessage entered (dwMessage=%s, rc=(%ld, %ld, %ld, %ld))\n",
64 MessageOfAppBar(dwMessage),
65 pData->rc.left, pData->rc.top, pData->rc.right, pData->rc.bottom);
66 UINT ret = SHAppBarMessage(dwMessage, pData);
67 trace("SHAppBarMessage leaved (dwMessage=%s, rc=(%ld, %ld, %ld, %ld))\n",
68 MessageOfAppBar(dwMessage),
69 pData->rc.left, pData->rc.top, pData->rc.right, pData->rc.bottom);
70 return ret;
71}
72#define SHAppBarMessage SHAppBarMessageWrap
73
74#undef ARRAYSIZE
75#define ARRAYSIZE _countof
76
77void appbar_tprintf(const TCHAR *fmt, ...)
78{
79 TCHAR szText[512];
80 va_list va;
81 va_start(va, fmt);
82 wvsprintf(szText, fmt, va);
83#ifdef UNICODE
84 printf("%ls", szText);
85#else
86 printf("%s", szText);
87#endif
88 va_end(va);
89}
90
91#define MSGDUMP_TPRINTF appbar_tprintf
92#include "msgdump.h"
93
94#endif // def VERBOSE
95
96void SlideWindow(HWND hwnd, LPRECT prc)
97{
98#define SLIDE_HIDE 400
99#define SLIDE_SHOW 150
100 RECT rcOld, rcNew = *prc;
101 GetWindowRect(hwnd, &rcOld);
102
103 BOOL fShow = (rcNew.bottom - rcNew.top > rcOld.bottom - rcOld.top) ||
104 (rcNew.right - rcNew.left > rcOld.right - rcOld.left);
105
106 INT dx = (rcNew.right - rcOld.right) + (rcNew.left - rcOld.left);
107 INT dy = (rcNew.bottom - rcOld.bottom) + (rcNew.top - rcOld.top);
108
109 LONG dt = SLIDE_HIDE;
110 if (fShow)
111 {
112 dt = SLIDE_SHOW;
113 rcOld = rcNew;
114 OffsetRect(&rcOld, -dx, -dy);
115 SetWindowPos(hwnd, NULL, rcOld.left, rcOld.top,
116 rcOld.right - rcOld.left, rcOld.bottom - rcOld.top,
117 SWP_NOZORDER | SWP_NOACTIVATE | SWP_DRAWFRAME);
118 }
119
120 HANDLE hThread = GetCurrentThread();
121 INT priority = GetThreadPriority(hThread);
122 SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST);
123
124 LONG t, t0 = GetTickCount();
125 while ((t = GetTickCount()) < t0 + dt)
126 {
127 INT x = rcOld.left + dx * (t - t0) / dt;
128 INT y = rcOld.top + dy * (t - t0) / dt;
129 SetWindowPos(hwnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
130
131 UpdateWindow(hwnd);
132 UpdateWindow(GetDesktopWindow());
133 }
134
135 SetThreadPriority(hThread, priority);
136 SetWindowPos(hwnd, NULL, rcNew.left, rcNew.top,
137 rcNew.right - rcNew.left, rcNew.bottom - rcNew.top,
138 SWP_NOZORDER | SWP_NOACTIVATE | SWP_DRAWFRAME);
139#undef SLIDE_HIDE
140#undef SLIDE_SHOW
141}
142
143class Window
144{
145public:
146 Window(INT cx, INT cy, BOOL fAutoHide = FALSE)
147 : m_hwnd(NULL)
148 , m_fAutoHide(fAutoHide)
149 , m_cxWidth(cx)
150 , m_cyHeight(cy)
151 {
152 }
153
154 virtual ~Window() { }
155
156 static BOOL DoRegisterClass(HINSTANCE hInstance)
157 {
158 WNDCLASS wc;
159 ZeroMemory(&wc, sizeof(wc));
160 wc.lpfnWndProc = Window::WindowProc;
161 wc.hInstance = hInstance;
162 wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
163 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
164 wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
165 wc.lpszClassName = s_szName;
166 return !!RegisterClass(&wc);
167 }
168
169 static HWND DoCreateMainWnd(HINSTANCE hInstance, LPCTSTR pszText, INT cx, INT cy,
170 DWORD style = WS_POPUP | WS_THICKFRAME | WS_CLIPCHILDREN,
171 DWORD exstyle = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
172 BOOL fAutoHide = FALSE)
173 {
174 Window *this_ = new Window(cx, cy, fAutoHide);
175 HWND hwnd = CreateWindowEx(exstyle, s_szName, pszText, style,
176 CW_USEDEFAULT, CW_USEDEFAULT, 50, 50,
177 NULL, NULL, hInstance, this_);
178 ShowWindow(hwnd, SW_SHOWNORMAL);
179 UpdateWindow(hwnd);
180 return hwnd;
181 }
182
183 static Window *GetAppbarData(HWND hwnd)
184 {
185 return (Window *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
186 }
187
188 virtual LRESULT CALLBACK
189 WindowProcDx(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
190 {
191#ifdef VERBOSE
192 MD_msgdump(hwnd, uMsg, wParam, lParam);
193#endif
194 switch (uMsg)
195 {
196 HANDLE_MSG(hwnd, WM_CREATE, OnCreate);
197 HANDLE_MSG(hwnd, WM_COMMAND, OnCommand);
198 HANDLE_MSG(hwnd, WM_ACTIVATE, OnActivate);
199 HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGED, OnWindowPosChanged);
200 HANDLE_MSG(hwnd, WM_SIZE, OnSize);
201 HANDLE_MSG(hwnd, WM_MOVE, OnMove);
202 HANDLE_MSG(hwnd, WM_NCDESTROY, OnNCDestroy);
203 HANDLE_MSG(hwnd, WM_TIMER, OnTimer);
204 HANDLE_MSG(hwnd, WM_NCHITTEST, OnNCHitTest);
205 HANDLE_MSG(hwnd, WM_LBUTTONDOWN, OnLButtonDown);
206 HANDLE_MSG(hwnd, WM_MOUSEMOVE, OnMouseMove);
207 HANDLE_MSG(hwnd, WM_LBUTTONUP, OnLButtonUp);
208 HANDLE_MSG(hwnd, WM_RBUTTONDOWN, OnRButtonDown);
209 HANDLE_MSG(hwnd, WM_KEYDOWN, OnKey);
210 HANDLE_MSG(hwnd, WM_PAINT, OnPaint);
211
212 case APPBAR_CALLBACK:
213 OnAppBarCallback(hwnd, uMsg, wParam, lParam);
214 break;
215
216 default:
217 return DefWindowProc(hwnd, uMsg, wParam, lParam);
218 }
219 return 0;
220 }
221
222 static LRESULT CALLBACK
223 WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
224 {
225 Window *this_ = GetAppbarData(hwnd);
226 if (uMsg == WM_CREATE)
227 {
228 LPCREATESTRUCT pCS = (LPCREATESTRUCT)lParam;
229 this_ = (Window *)pCS->lpCreateParams;
230 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this_);
231 }
232 if (this_)
233 return this_->WindowProcDx(hwnd, uMsg, wParam, lParam);
234 return DefWindowProc(hwnd, uMsg, wParam, lParam);
235 }
236
237protected:
238 HWND m_hwnd;
239 BOOL m_fAutoHide;
240 BOOL m_fOnTop;
241 BOOL m_fHiding;
242 UINT m_uSide;
243 LONG m_cxWidth;
244 LONG m_cyHeight;
245 LONG m_cxSave;
246 LONG m_cySave;
247 BOOL m_fAppBarRegd;
248 BOOL m_fMoving;
249 BOOL m_bDragged;
250 POINT m_ptDragOn;
251 RECT m_rcAppBar;
252 RECT m_rcDrag;
253 BOOL m_bGotFullScreen;
254
255 void OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
256 {
257 HANDLE hThread;
258 switch (id)
259 {
260 case ID_ACTION:
261 PostMessageW(s_hwnd2, WM_COMMAND, ID_ACTION + 1, 0);
262 break;
263 case ID_ACTION + 1:
264 hThread = CreateThread(NULL, 0, ActionThreadFunc, this, 0, NULL);
265 if (!hThread)
266 {
267 skip("failed to create thread\n");
268 PostMessageW(s_hwnd1, WM_CLOSE, 0, 0);
269 PostMessageW(s_hwnd2, WM_CLOSE, 0, 0);
270 return;
271 }
272 CloseHandle(hThread);
273 break;
274 case ID_QUIT:
275 DestroyWindow(s_hwnd1);
276 DestroyWindow(s_hwnd2);
277 PostQuitMessage(0);
278 break;
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 m_bGotFullScreen = TRUE;
322 if (lParam)
323 {
324 s_hwndZOrder = GetWindow(hwnd, GW_HWNDPREV);
325 SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0,
326 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
327 }
328 else
329 {
330 SetWindowPos(hwnd, m_fOnTop ? HWND_TOPMOST : s_hwndZOrder,
331 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
332 s_hwndZOrder = NULL;
333 }
334 break;
335
336 case ABN_POSCHANGED:
337 {
338 APPBARDATA abd = { sizeof(abd), hwnd };
339 AppBar_PosChanged(&abd);
340 }
341 break;
342 }
343 }
344
345 BOOL AppBar_Register(HWND hwnd)
346 {
347 APPBARDATA abd = { sizeof(abd), hwnd, APPBAR_CALLBACK };
348 m_fAppBarRegd = (BOOL)SHAppBarMessage(ABM_NEW, &abd);
349 return m_fAppBarRegd;
350 }
351
352 BOOL AppBar_UnRegister(HWND hwnd)
353 {
354 APPBARDATA abd = { sizeof(abd), hwnd };
355 m_fAppBarRegd = !SHAppBarMessage(ABM_REMOVE, &abd);
356 return !m_fAppBarRegd;
357 }
358
359 BOOL AppBar_GetTaskBarPos(HWND hwnd, PRECT prc)
360 {
361 APPBARDATA abd = { sizeof(abd), hwnd };
362
363 if (!SHAppBarMessage(ABM_GETTASKBARPOS, &abd))
364 return FALSE;
365 *prc = abd.rc;
366 return TRUE;
367 }
368
369 HWND AppBar_GetAutoHideBar(HWND hwnd, UINT uSide)
370 {
371 APPBARDATA abd = { sizeof(abd), hwnd };
372 abd.uEdge = uSide;
373
374 return (HWND)SHAppBarMessage(ABM_GETAUTOHIDEBAR, &abd);
375 }
376
377 BOOL AppBar_SetAutoHide(HWND hwnd, BOOL fHide)
378 {
379 if (fHide)
380 return AppBar_AutoHide(hwnd);
381 else
382 return AppBar_NoAutoHide(hwnd);
383 }
384
385 BOOL AppBar_AutoHide(HWND hwnd)
386 {
387 APPBARDATA abd = { sizeof(abd), hwnd };
388 abd.uEdge = m_uSide;
389
390 HWND hwndAutoHide = (HWND)SHAppBarMessage(ABM_GETAUTOHIDEBAR, &abd);
391 if (hwndAutoHide)
392 return FALSE;
393
394 abd.lParam = TRUE;
395 if (!(BOOL)SHAppBarMessage(ABM_SETAUTOHIDEBAR, &abd))
396 return FALSE;
397
398 m_fAutoHide = TRUE;
399 m_cxSave = m_cxWidth;
400 m_cySave = m_cyHeight;
401
402 RECT rc = m_rcAppBar;
403 switch (m_uSide)
404 {
405 case ABE_TOP:
406 rc.bottom = rc.top + 2;
407 break;
408 case ABE_BOTTOM:
409 rc.top = rc.bottom - 2;
410 break;
411 case ABE_LEFT:
412 rc.right = rc.left + 2;
413 break;
414 case ABE_RIGHT:
415 rc.left = rc.right - 2;
416 break;
417 }
418
419 AppBar_QueryPos(hwnd, &rc);
420 abd.rc = rc;
421 SHAppBarMessage(ABM_SETPOS, &abd);
422 rc = abd.rc;
423
424 m_fHiding = TRUE;
425 SlideWindow(hwnd, &rc);
426
427 AppBar_SetAutoHideTimer(hwnd);
428 return TRUE;
429 }
430
431 BOOL AppBar_NoAutoHide(HWND hwnd)
432 {
433 APPBARDATA abd = { sizeof(abd), hwnd };
434 abd.uEdge = m_uSide;
435 HWND hwndAutoHide = (HWND)SHAppBarMessage(ABM_GETAUTOHIDEBAR, &abd);
436 if (hwndAutoHide != hwnd)
437 return FALSE;
438
439 abd.lParam = FALSE;
440 if (!(BOOL)SHAppBarMessage(ABM_SETAUTOHIDEBAR, &abd))
441 return FALSE;
442
443 m_fAutoHide = FALSE;
444 m_cxWidth = m_cxSave;
445 m_cyHeight = m_cySave;
446 AppBar_SetSide(hwnd, m_uSide);
447 return TRUE;
448 }
449
450 BOOL AppBar_SetSide(HWND hwnd, UINT uSide)
451 {
452 HMONITOR hMon = ::MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY);
453 MONITORINFO mi = { sizeof(mi) };
454 ::GetMonitorInfo(hMon, &mi);
455 RECT rc = mi.rcWork;
456
457 BOOL fAutoHide = FALSE;
458 if (m_fAutoHide)
459 {
460 fAutoHide = m_fAutoHide;
461 SetWindowRedraw(GetDesktopWindow(), FALSE);
462 AppBar_SetAutoHide(hwnd, FALSE);
463 m_fHiding = FALSE;
464 }
465
466 switch (uSide)
467 {
468 case ABE_TOP:
469 rc.bottom = rc.top + m_cyHeight;
470 break;
471 case ABE_BOTTOM:
472 rc.top = rc.bottom - m_cyHeight;
473 break;
474 case ABE_LEFT:
475 rc.right = rc.left + m_cxWidth;
476 break;
477 case ABE_RIGHT:
478 rc.left = rc.right - m_cxWidth;
479 break;
480 }
481
482 APPBARDATA abd = { sizeof(abd), hwnd };
483 AppBar_QuerySetPos(uSide, &rc, &abd, TRUE);
484
485 if (fAutoHide)
486 {
487 AppBar_SetAutoHide(hwnd, TRUE);
488 m_fHiding = TRUE;
489
490 SetWindowRedraw(GetDesktopWindow(), TRUE);
491 RedrawWindow(GetDesktopWindow(), NULL, NULL,
492 RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
493 }
494
495 return TRUE;
496 }
497
498 void AppBar_SetAlwaysOnTop(HWND hwnd, BOOL fOnTop)
499 {
500 SetWindowPos(hwnd, (fOnTop ? HWND_TOPMOST : HWND_NOTOPMOST),
501 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
502 m_fOnTop = fOnTop;
503 }
504
505 void AppBar_Hide(HWND hwnd)
506 {
507 if (!m_fAutoHide)
508 return;
509
510 RECT rc = m_rcAppBar;
511 switch (m_uSide)
512 {
513 case ABE_TOP:
514 rc.bottom = rc.top + 2;
515 break;
516 case ABE_BOTTOM:
517 rc.top = rc.bottom - 2;
518 break;
519 case ABE_LEFT:
520 rc.right = rc.left + 2;
521 break;
522 case ABE_RIGHT:
523 rc.left = rc.right - 2;
524 break;
525 }
526
527 m_fHiding = TRUE;
528 SlideWindow(hwnd, &rc);
529 }
530
531 void AppBar_UnHide(HWND hwnd)
532 {
533 SlideWindow(hwnd, &m_rcAppBar);
534 m_fHiding = FALSE;
535
536 AppBar_SetAutoHideTimer(hwnd);
537 }
538
539 void AppBar_SetAutoHideTimer(HWND hwnd)
540 {
541 if (m_fAutoHide)
542 {
543 SetTimer(hwnd, IDT_AUTOHIDE, 500, NULL);
544 }
545 }
546
547 void AppBar_SetAutoUnhideTimer(HWND hwnd)
548 {
549 if (m_fAutoHide && m_fHiding)
550 {
551 SetTimer(hwnd, IDT_AUTOUNHIDE, 50, NULL);
552 }
553 }
554
555 void AppBar_Size(HWND hwnd)
556 {
557 if (m_fAppBarRegd)
558 {
559 APPBARDATA abd = { sizeof(abd), hwnd };
560
561 RECT rc;
562 GetWindowRect(hwnd, &rc);
563 AppBar_QuerySetPos(m_uSide, &rc, &abd, TRUE);
564 }
565 }
566
567 void AppBar_QueryPos(HWND hwnd, LPRECT lprc)
568 {
569 APPBARDATA abd = { sizeof(abd), hwnd };
570 abd.rc = *lprc;
571 abd.uEdge = m_uSide;
572
573 INT cx = 0, cy = 0;
574 if (ABE_LEFT == abd.uEdge || ABE_RIGHT == abd.uEdge)
575 {
576 cx = abd.rc.right - abd.rc.left;
577 abd.rc.top = 0;
578 abd.rc.bottom = GetSystemMetrics(SM_CYSCREEN);
579 }
580 else
581 {
582 cy = abd.rc.bottom - abd.rc.top;
583 abd.rc.left = 0;
584 abd.rc.right = GetSystemMetrics(SM_CXSCREEN);
585 }
586
587 SHAppBarMessage(ABM_QUERYPOS, &abd);
588
589 switch (abd.uEdge)
590 {
591 case ABE_LEFT:
592 abd.rc.right = abd.rc.left + cx;
593 break;
594 case ABE_RIGHT:
595 abd.rc.left = abd.rc.right - cx;
596 break;
597 case ABE_TOP:
598 abd.rc.bottom = abd.rc.top + cy;
599 break;
600 case ABE_BOTTOM:
601 abd.rc.top = abd.rc.bottom - cy;
602 break;
603 }
604
605 *lprc = abd.rc;
606 }
607
608 void AppBar_QuerySetPos(UINT uEdge, LPRECT lprc, PAPPBARDATA pabd, BOOL fMove)
609 {
610 pabd->rc = *lprc;
611 pabd->uEdge = uEdge;
612 m_uSide = uEdge;
613
614 AppBar_QueryPos(pabd->hWnd, &pabd->rc);
615
616 SHAppBarMessage(ABM_SETPOS, pabd);
617
618 if (fMove)
619 {
620 RECT rc = pabd->rc;
621 MoveWindow(pabd->hWnd, rc.left, rc.top,
622 rc.right - rc.left, rc.bottom - rc.top, TRUE);
623 }
624
625 if (!m_fAutoHide)
626 {
627 m_rcAppBar = pabd->rc;
628 }
629 }
630
631 void AppBar_PosChanged(PAPPBARDATA pabd)
632 {
633 RECT rc;
634 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
635
636 if (m_fAutoHide)
637 {
638 m_rcAppBar = rc;
639 switch (m_uSide)
640 {
641 case ABE_TOP:
642 m_rcAppBar.bottom = m_rcAppBar.top + m_cySave;
643 break;
644 case ABE_BOTTOM:
645 m_rcAppBar.top = m_rcAppBar.bottom - m_cySave;
646 break;
647 case ABE_LEFT:
648 m_rcAppBar.right = m_rcAppBar.left + m_cxSave;
649 break;
650 case ABE_RIGHT:
651 m_rcAppBar.left = m_rcAppBar.right - m_cxSave;
652 break;
653 }
654 }
655
656 RECT rcWindow;
657 GetWindowRect(pabd->hWnd, &rcWindow);
658 INT cx = rcWindow.right - rcWindow.left;
659 INT cy = rcWindow.bottom - rcWindow.top;
660 switch (m_uSide)
661 {
662 case ABE_TOP:
663 rc.bottom = rc.top + cy;
664 break;
665 case ABE_BOTTOM:
666 rc.top = rc.bottom - cy;
667 break;
668 case ABE_LEFT:
669 rc.right = rc.left + cx;
670 break;
671 case ABE_RIGHT:
672 rc.left = rc.right - cx;
673 break;
674 }
675 AppBar_QuerySetPos(m_uSide, &rc, pabd, TRUE);
676 }
677
678 BOOL OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct)
679 {
680 m_hwnd = hwnd;
681 m_fOnTop = TRUE;
682 m_uSide = ABE_TOP;
683
684 m_fAppBarRegd = FALSE;
685 m_fMoving = FALSE;
686 m_cxSave = m_cxWidth;
687 m_cySave = m_cyHeight;
688 m_bDragged = FALSE;
689
690 AppBar_Register(hwnd);
691 AppBar_SetSide(hwnd, ABE_TOP);
692
693 trace("OnCreate(%p) done\n", hwnd);
694 return TRUE;
695 }
696
697 void OnActivate(HWND hwnd, UINT state, HWND hwndActDeact, BOOL fMinimized)
698 {
699 APPBARDATA abd = { sizeof(abd), hwnd };
700 SHAppBarMessage(ABM_ACTIVATE, &abd);
701
702 switch (state)
703 {
704 case WA_ACTIVE:
705 case WA_CLICKACTIVE:
706 AppBar_UnHide(hwnd);
707 KillTimer(hwnd, IDT_AUTOHIDE);
708 break;
709
710 case WA_INACTIVE:
711 AppBar_Hide(hwnd);
712 break;
713 }
714 }
715
716 void OnWindowPosChanged(HWND hwnd, const LPWINDOWPOS lpwpos)
717 {
718 APPBARDATA abd = { sizeof(abd), hwnd };
719 SHAppBarMessage(ABM_WINDOWPOSCHANGED, &abd);
720
721 FORWARD_WM_WINDOWPOSCHANGED(hwnd, lpwpos, DefWindowProc);
722 }
723
724 void OnSize(HWND hwnd, UINT state, int cx, int cy)
725 {
726 RECT rcWindow;
727
728 if (m_fMoving || (m_fAutoHide && m_fHiding))
729 return;
730
731 if (!m_fHiding)
732 {
733 if (!m_fAutoHide)
734 AppBar_Size(hwnd);
735
736 GetWindowRect(hwnd, &rcWindow);
737 m_rcAppBar = rcWindow;
738
739 if (m_uSide == ABE_TOP || m_uSide == ABE_BOTTOM)
740 m_cyHeight = m_cySave = rcWindow.bottom - rcWindow.top;
741 else
742 m_cxWidth = m_cxSave = rcWindow.right - rcWindow.left;
743 }
744
745 InvalidateRect(hwnd, NULL, TRUE);
746 }
747
748 void OnMove(HWND hwnd, int x, int y)
749 {
750 if (m_fMoving || m_fAutoHide)
751 return;
752
753 if (!m_fHiding)
754 AppBar_Size(hwnd);
755 }
756
757 void OnNCDestroy(HWND hwnd)
758 {
759 AppBar_UnRegister(hwnd);
760
761 m_hwnd = NULL;
762 SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
763 delete this;
764 }
765
766 void OnTimer(HWND hwnd, UINT id)
767 {
768 POINT pt;
769 RECT rc;
770 HWND hwndActive;
771
772 switch (id)
773 {
774 case IDT_AUTOHIDE:
775 if (m_fAutoHide && !m_fHiding && !m_fMoving)
776 {
777 GetCursorPos(&pt);
778 GetWindowRect(hwnd, &rc);
779 hwndActive = GetForegroundWindow();
780
781 if (!PtInRect(&rc, pt) &&
782 hwndActive != hwnd &&
783 hwndActive != NULL &&
784 GetWindowOwner(hwndActive) != hwnd)
785 {
786 KillTimer(hwnd, id);
787 AppBar_Hide(hwnd);
788 }
789 }
790 break;
791
792 case IDT_AUTOUNHIDE:
793 KillTimer(hwnd, id);
794
795 if (m_fAutoHide && m_fHiding)
796 {
797 GetCursorPos(&pt);
798 GetWindowRect(hwnd, &rc);
799 if (PtInRect(&rc, pt))
800 {
801 AppBar_UnHide(hwnd);
802 }
803 }
804 break;
805 }
806 }
807
808 UINT OnNCHitTest(HWND hwnd, int x, int y)
809 {
810 AppBar_SetAutoUnhideTimer(hwnd);
811
812 UINT uHitTest = FORWARD_WM_NCHITTEST(hwnd, x, y, DefWindowProc);
813
814 if (m_uSide == ABE_TOP && uHitTest == HTBOTTOM)
815 return HTBOTTOM;
816
817 if (m_uSide == ABE_BOTTOM && uHitTest == HTTOP)
818 return HTTOP;
819
820 if (m_uSide == ABE_LEFT && uHitTest == HTRIGHT)
821 return HTRIGHT;
822
823 if (m_uSide == ABE_RIGHT && uHitTest == HTLEFT)
824 return HTLEFT;
825
826 return HTCLIENT;
827 }
828
829 void OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
830 {
831 m_fMoving = TRUE;
832 m_bDragged = FALSE;
833 SetCapture(hwnd);
834 GetCursorPos(&m_ptDragOn);
835 }
836
837 void OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags)
838 {
839 if (!m_fMoving)
840 return;
841
842 POINT pt;
843 GetCursorPos(&pt);
844 if (labs(pt.x - m_ptDragOn.x) > GetSystemMetrics(SM_CXDRAG) ||
845 labs(pt.y - m_ptDragOn.y) > GetSystemMetrics(SM_CYDRAG))
846 {
847 m_bDragged = TRUE;
848 }
849
850 INT cxScreen = GetSystemMetrics(SM_CXSCREEN);
851 INT cyScreen = GetSystemMetrics(SM_CYSCREEN);
852
853 DWORD dx, dy;
854 UINT ix, iy;
855 if (pt.x < cxScreen / 2)
856 {
857 dx = pt.x;
858 ix = ABE_LEFT;
859 }
860 else
861 {
862 dx = cxScreen - pt.x;
863 ix = ABE_RIGHT;
864 }
865
866 if (pt.y < cyScreen / 2)
867 {
868 dy = pt.y;
869 iy = ABE_TOP;
870 }
871 else
872 {
873 dy = cyScreen - pt.y;
874 iy = ABE_BOTTOM;
875 }
876
877 if (cxScreen * dy > cyScreen * dx)
878 {
879 m_rcDrag.top = 0;
880 m_rcDrag.bottom = cyScreen;
881 if (ix == ABE_LEFT)
882 {
883 m_uSide = ABE_LEFT;
884 m_rcDrag.left = 0;
885 m_rcDrag.right = m_rcDrag.left + m_cxWidth;
886 }
887 else
888 {
889 m_uSide = ABE_RIGHT;
890 m_rcDrag.right = cxScreen;
891 m_rcDrag.left = m_rcDrag.right - m_cxWidth;
892 }
893 }
894 else
895 {
896 m_rcDrag.left = 0;
897 m_rcDrag.right = cxScreen;
898 if (iy == ABE_TOP)
899 {
900 m_uSide = ABE_TOP;
901 m_rcDrag.top = 0;
902 m_rcDrag.bottom = m_rcDrag.top + m_cyHeight;
903 }
904 else
905 {
906 m_uSide = ABE_BOTTOM;
907 m_rcDrag.bottom = cyScreen;
908 m_rcDrag.top = m_rcDrag.bottom - m_cyHeight;
909 }
910 }
911
912 AppBar_QueryPos(hwnd, &m_rcDrag);
913
914 if (m_bDragged)
915 {
916 MoveWindow(hwnd, m_rcDrag.left, m_rcDrag.top,
917 m_rcDrag.right - m_rcDrag.left,
918 m_rcDrag.bottom - m_rcDrag.top,
919 TRUE);
920 }
921 }
922
923 void OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags)
924 {
925 if (!m_fMoving)
926 return;
927
928 OnMouseMove(hwnd, x, y, keyFlags);
929
930 m_rcAppBar = m_rcDrag;
931
932 ReleaseCapture();
933
934 if (m_fAutoHide)
935 {
936 switch (m_uSide)
937 {
938 case ABE_TOP:
939 m_rcDrag.bottom = m_rcDrag.top + 2;
940 break;
941 case ABE_BOTTOM:
942 m_rcDrag.top = m_rcDrag.bottom - 2;
943 break;
944 case ABE_LEFT:
945 m_rcDrag.right = m_rcDrag.left + 2;
946 break;
947 case ABE_RIGHT:
948 m_rcDrag.left = m_rcDrag.right - 2;
949 break;
950 }
951 }
952
953 if (m_bDragged)
954 {
955 if (m_fAutoHide)
956 {
957 AppBar_AutoHide(hwnd);
958 }
959 else
960 {
961 APPBARDATA abd = { sizeof(abd), hwnd };
962 AppBar_QuerySetPos(m_uSide, &m_rcDrag, &abd, FALSE);
963 }
964 }
965
966 m_fMoving = FALSE;
967 }
968
969 void GetWorkArea(LPRECT prc) const
970 {
971 SystemParametersInfoW(SPI_GETWORKAREA, 0, prc, 0);
972 }
973
974 void Quit()
975 {
976 PostMessage(s_hwnd1, WM_COMMAND, ID_QUIT, 0);
977 PostMessage(s_hwnd2, WM_COMMAND, ID_QUIT, 0);
978 }
979
980public:
981 void DoAction()
982 {
983 trace("DoAction\n");
984
985 TEST_Main();
986 TEST_Dragging();
987 TEST_AutoHide();
988 TEST_FullScreen();
989
990 Quit();
991 }
992
993 void TEST_Main()
994 {
995 trace("TEST_Main\n");
996 Sleep(INTERVAL);
997
998 POINT pt;
999 RECT rc1, rc2, rcWork;
1000
1001 BOOL ret = AppBar_GetTaskBarPos(s_hwnd1, &rc1);
1002 ok_int(ret, TRUE);
1003 ok_int(EqualRect(&rc1, &s_rcTaskBar), TRUE);
1004
1005 GetWindowRect(s_hwnd1, &rc1);
1006 GetWindowRect(s_hwnd2, &rc2);
1007 GetWorkArea(&rcWork);
1008 ok_long(rc1.left, s_rcWorkArea.left);
1009 ok_long(rc1.top, s_rcWorkArea.top);
1010 ok_long(rc1.right, s_rcWorkArea.right);
1011 ok_long(rc1.bottom, s_rcWorkArea.top + 80);
1012 ok_long(rc2.left, s_rcWorkArea.left);
1013 ok_long(rc2.top, s_rcWorkArea.top + 80);
1014 ok_long(rc2.right, s_rcWorkArea.right);
1015 ok_long(rc2.bottom, s_rcWorkArea.top + 110);
1016 ok_long(rcWork.left, s_rcWorkArea.left);
1017 ok_long(rcWork.top, s_rcWorkArea.top + 110);
1018 ok_long(rcWork.right, s_rcWorkArea.right);
1019 ok_long(rcWork.bottom, s_rcWorkArea.bottom);
1020 PostMessageW(s_hwnd1, WM_CLOSE, 0, 0);
1021 Sleep(LONG_INTERVAL);
1022
1023 GetWindowRect(s_hwnd2, &rc2);
1024 GetWorkArea(&rcWork);
1025 ok_long(rc2.left, s_rcWorkArea.left);
1026 ok_long(rc2.top, s_rcWorkArea.top);
1027 ok_long(rc2.right, s_rcWorkArea.right);
1028 ok_long(rc2.bottom, s_rcWorkArea.top + 30);
1029 ok_long(rcWork.left, s_rcWorkArea.left);
1030 ok_long(rcWork.top, s_rcWorkArea.top + 30);
1031 ok_long(rcWork.right, s_rcWorkArea.right);
1032 ok_long(rcWork.bottom, s_rcWorkArea.bottom);
1033 AppBar_SetSide(s_hwnd2, ABE_LEFT);
1034 Sleep(INTERVAL);
1035
1036 GetWindowRect(s_hwnd2, &rc2);
1037 GetWorkArea(&rcWork);
1038 ok_long(rc2.left, s_rcWorkArea.left);
1039 ok_long(rc2.top, s_rcWorkArea.top);
1040 ok_long(rc2.right, s_rcWorkArea.left + 30);
1041 ok_long(rcWork.left, s_rcWorkArea.left + 30);
1042 ok_long(rcWork.top, s_rcWorkArea.top);
1043 ok_long(rcWork.right, s_rcWorkArea.right);
1044 ok_long(rcWork.bottom, s_rcWorkArea.bottom);
1045 AppBar_SetSide(s_hwnd2, ABE_TOP);
1046 Sleep(INTERVAL);
1047
1048 GetWindowRect(s_hwnd2, &rc2);
1049 GetWorkArea(&rcWork);
1050 ok_long(rc2.left, s_rcWorkArea.left);
1051 ok_long(rc2.top, s_rcWorkArea.top);
1052 ok_long(rc2.right, s_rcWorkArea.right);
1053 ok_long(rc2.bottom, s_rcWorkArea.top + 30);
1054 ok_long(rcWork.left, s_rcWorkArea.left);
1055 ok_long(rcWork.top, s_rcWorkArea.top + 30);
1056 ok_long(rcWork.right, s_rcWorkArea.right);
1057 ok_long(rcWork.bottom, s_rcWorkArea.bottom);
1058 AppBar_SetSide(s_hwnd2, ABE_RIGHT);
1059 Sleep(INTERVAL);
1060
1061 GetWindowRect(s_hwnd2, &rc2);
1062 GetWorkArea(&rcWork);
1063 ok_long(rc2.left, s_rcWorkArea.right - 30);
1064 ok_long(rc2.top, s_rcWorkArea.top);
1065 ok_long(rc2.right, s_rcWorkArea.right);
1066 ok_long(rcWork.left, s_rcWorkArea.left);
1067 ok_long(rcWork.top, s_rcWorkArea.top);
1068 ok_long(rcWork.right, s_rcWorkArea.right - 30);
1069 ok_long(rcWork.bottom, s_rcWorkArea.bottom);
1070 Sleep(INTERVAL);
1071
1072 GetWindowRect(s_hwnd2, &rc2);
1073 pt.x = (rc2.left + rc2.right) / 2;
1074 pt.y = (rc2.top + rc2.bottom) / 2;
1075 MOVE(pt.x, pt.y);
1076 LEFT_DOWN();
1077 MOVE(pt.x + 64, pt.y + 64);
1078 Sleep(INTERVAL);
1079
1080 pt.x = s_rcWorkArea.left + 80;
1081 pt.y = (s_rcWorkArea.top + s_rcWorkArea.bottom) / 2;
1082 MOVE(pt.x, pt.y);
1083 LEFT_UP();
1084 Sleep(INTERVAL);
1085
1086 GetWindowRect(s_hwnd2, &rc2);
1087 GetWorkArea(&rcWork);
1088 ok_long(rc2.left, s_rcWorkArea.left);
1089 ok_long(rc2.top, s_rcWorkArea.top);
1090 ok_long(rc2.right, s_rcWorkArea.left + 30);
1091 ok_long(rcWork.left, s_rcWorkArea.left + 30);
1092 ok_long(rcWork.top, s_rcWorkArea.top);
1093 ok_long(rcWork.right, s_rcWorkArea.right);
1094 ok_long(rcWork.bottom, s_rcWorkArea.bottom);
1095 Sleep(INTERVAL);
1096 }
1097
1098 void TEST_Dragging()
1099 {
1100 trace("TEST_Dragging\n");
1101
1102 RECT rc, rcWork;
1103 POINT pt;
1104
1105 GetWindowRect(s_hwnd2, &rc);
1106 pt.x = (rc.left + rc.right) / 2;
1107 pt.y = (rc.top + rc.bottom) / 2;
1108 MOVE(pt.x, pt.y);
1109 LEFT_DOWN();
1110 Sleep(INTERVAL);
1111
1112 pt.x = (s_rcWorkArea.left + s_rcWorkArea.right) / 2;
1113 pt.y = s_rcWorkArea.top;
1114 MOVE(pt.x, pt.y);
1115 Sleep(INTERVAL);
1116
1117 pt.x = s_rcWorkArea.right - 1;
1118 pt.y = (s_rcWorkArea.top + s_rcWorkArea.bottom) / 2;
1119 MOVE(pt.x, pt.y);
1120 LEFT_UP();
1121 Sleep(LONG_INTERVAL);
1122
1123 GetWindowRect(s_hwnd2, &rc);
1124 GetWorkArea(&rcWork);
1125 ok_long(rc.left, s_rcWorkArea.right - 30);
1126 ok_long(rc.top, s_rcWorkArea.top);
1127 ok_long(rc.right, s_rcWorkArea.right);
1128 ok_long(rcWork.left, s_rcWorkArea.left);
1129 ok_long(rcWork.top, s_rcWorkArea.top);
1130 ok_long(rcWork.right, s_rcWorkArea.right - 30);
1131 ok_long(rcWork.bottom, s_rcWorkArea.bottom);
1132 }
1133
1134 void TEST_AutoHide()
1135 {
1136 trace("TEST_AutoHide\n");
1137
1138 RECT rc;
1139
1140 m_cxWidth = 80;
1141 m_cyHeight = 40;
1142 AppBar_SetSide(s_hwnd2, ABE_TOP);
1143 AppBar_AutoHide(s_hwnd2);
1144 HWND hwndRet = AppBar_GetAutoHideBar(s_hwnd2, ABE_TOP);
1145 ok_ptr(hwndRet, s_hwnd2);
1146 Sleep(LONG_INTERVAL);
1147
1148 GetWindowRect(s_hwnd2, &rc);
1149 ok_long(rc.left, s_rcWorkArea.left);
1150 ok_long(rc.top, s_rcWorkArea.top);
1151 ok_long(rc.right, s_rcWorkArea.right);
1152 ok_long(rc.bottom, s_rcWorkArea.top + 2);
1153
1154 MOVE((s_rcWorkArea.left + s_rcWorkArea.right) / 2, s_rcWorkArea.top);
1155 LEFT_DOWN();
1156 LEFT_UP();
1157 Sleep(LONG_INTERVAL);
1158
1159 GetWindowRect(s_hwnd2, &rc);
1160 ok_long(rc.left, s_rcWorkArea.left);
1161 ok_long(rc.top, s_rcWorkArea.top);
1162 ok_long(rc.right, s_rcWorkArea.right);
1163 ok_long(rc.bottom, s_rcWorkArea.top + 40);
1164
1165 MOVE((s_rcWorkArea.left + s_rcWorkArea.right) / 2, s_rcWorkArea.bottom - 1);
1166 LEFT_DOWN();
1167 LEFT_UP();
1168 Sleep(LONG_INTERVAL);
1169
1170 GetWindowRect(s_hwnd2, &rc);
1171 ok_long(rc.left, s_rcWorkArea.left);
1172 ok_long(rc.top, s_rcWorkArea.top);
1173 ok_long(rc.right, s_rcWorkArea.right);
1174 ok_long(rc.bottom, s_rcWorkArea.top + 2);
1175
1176 SetForegroundWindow(s_hwnd2);
1177 Sleep(LONG_INTERVAL);
1178
1179 GetWindowRect(s_hwnd2, &rc);
1180 ok_long(rc.left, s_rcWorkArea.left);
1181 ok_long(rc.top, s_rcWorkArea.top);
1182 ok_long(rc.right, s_rcWorkArea.right);
1183 ok_long(rc.bottom, s_rcWorkArea.top + 40);
1184
1185 AppBar_SetSide(s_hwnd2, ABE_RIGHT);
1186 AppBar_AutoHide(s_hwnd2);
1187 SetForegroundWindow(s_hwnd2);
1188 hwndRet = AppBar_GetAutoHideBar(s_hwnd2, ABE_RIGHT);
1189 ok_ptr(hwndRet, s_hwnd2);
1190
1191 GetWindowRect(s_hwnd2, &rc);
1192 ok_long(rc.left, s_rcWorkArea.right - 2);
1193 ok_long(rc.top, s_rcWorkArea.top);
1194 ok_long(rc.right, s_rcWorkArea.right);
1195 ok_long(rc.bottom, s_rcWorkArea.bottom);
1196
1197 MOVE(s_rcWorkArea.left, (s_rcWorkArea.top + s_rcWorkArea.bottom) / 2);
1198 Sleep(LONG_INTERVAL);
1199
1200 GetWindowRect(s_hwnd2, &rc);
1201 ok_long(rc.left, s_rcWorkArea.right - 2);
1202 ok_long(rc.top, s_rcWorkArea.top);
1203 ok_long(rc.right, s_rcWorkArea.right);
1204 ok_long(rc.bottom, s_rcWorkArea.bottom);
1205 }
1206
1207 void TEST_FullScreen()
1208 {
1209 trace("TEST_FullScreen\n");
1210 RECT rc = s_rcPrimaryMonitor;
1211 m_bGotFullScreen = FALSE;
1212 MoveWindow(s_hwnd2, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);
1213 Sleep(LONG_INTERVAL);
1214 ok_int(m_bGotFullScreen, TRUE);
1215 MoveWindow(s_hwnd2, rc.left, rc.top, 100, 100, TRUE);
1216 }
1217
1218 static DWORD WINAPI ActionThreadFunc(LPVOID args)
1219 {
1220 Window *this_ = (Window *)args;
1221 this_->DoAction();
1222 return 0;
1223 }
1224};
1225
1226START_TEST(SHAppBarMessage)
1227{
1228 HINSTANCE hInstance = GetModuleHandle(NULL);
1229
1230 // Check Taskbar
1231 HWND hTrayWnd = FindWindowW(L"Shell_TrayWnd", NULL);
1232 if (!IsWindowVisible(hTrayWnd))
1233 {
1234 skip("Taskbar not found\n");
1235 return;
1236 }
1237
1238 // Taskbar
1239 RECT rc;
1240 GetWindowRect(hTrayWnd, &rc);
1241 s_rcTaskBar = rc;
1242 trace("s_rcTaskBar: %ld, %ld, %ld, %ld\n", rc.left, rc.top, rc.right, rc.bottom);
1243
1244 // Work area
1245 SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, FALSE);
1246 s_rcWorkArea = rc;
1247 trace("s_rcWorkArea: %ld, %ld, %ld, %ld\n", rc.left, rc.top, rc.right, rc.bottom);
1248
1249 // Primary monitor
1250 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
1251 s_rcPrimaryMonitor = rc;
1252 trace("s_rcPrimaryMonitor: %ld, %ld, %ld, %ld\n", rc.left, rc.top, rc.right, rc.bottom);
1253
1254 if (s_rcTaskBar.left > s_rcPrimaryMonitor.left ||
1255 s_rcTaskBar.right < s_rcPrimaryMonitor.right ||
1256 s_rcTaskBar.bottom < s_rcPrimaryMonitor.bottom)
1257 {
1258 // Taskbar must be bottom in this testcase
1259 skip("Taskbar was not bottom\n");
1260 return;
1261 }
1262
1263 if (!Window::DoRegisterClass(hInstance))
1264 {
1265 skip("Window::DoRegisterClass failed\n");
1266 return;
1267 }
1268
1269 trace("SM_CMONITORS: %d\n", GetSystemMetrics(SM_CMONITORS));
1270 if (GetSystemMetrics(SM_CMONITORS) != 1)
1271 {
1272 skip("Multi-monitor not supported yet\n");
1273 return;
1274 }
1275
1276 HWND hwnd1 = Window::DoCreateMainWnd(hInstance, TEXT("Test1"), 80, 80,
1277 WS_POPUP | WS_THICKFRAME | WS_CLIPCHILDREN);
1278 if (!hwnd1)
1279 {
1280 skip("CreateWindowExW failed\n");
1281 return;
1282 }
1283
1284 HWND hwnd2 = Window::DoCreateMainWnd(hInstance, TEXT("Test2"), 30, 30,
1285 WS_POPUP | WS_BORDER | WS_CLIPCHILDREN);
1286 if (!hwnd2)
1287 {
1288 skip("CreateWindowExW failed\n");
1289 return;
1290 }
1291
1292 s_hwnd1 = hwnd1;
1293 s_hwnd2 = hwnd2;
1294
1295 PostMessageW(hwnd1, WM_COMMAND, ID_ACTION, 0);
1296
1297 // message loop
1298 MSG msg;
1299 while (GetMessage(&msg, NULL, 0, 0))
1300 {
1301 TranslateMessage(&msg);
1302 DispatchMessage(&msg);
1303 }
1304}