mf/tests: Clobber the alignment and bytes per second, to test if the DMO fixes it.
[wine.git] / dlls / user32 / tests / msg.c
blob398bb0a69ed2a669e96bd75213d0b18a98f1e0e7
1 /*
2 * Unit tests for window message handling
4 * Copyright 1999 Ove Kaaven
5 * Copyright 2003 Dimitrie O. Paun
6 * Copyright 2004,2005,2016 Dmitry Timoshkov
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <limits.h>
24 #include <stdarg.h>
25 #include <stdbool.h>
26 #include <stdio.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "winuser.h"
32 #include "winnls.h"
33 #include "dbt.h"
34 #include "commctrl.h"
35 #include "imm.h"
37 #include "wine/test.h"
39 #define MDI_FIRST_CHILD_ID 2004
41 /* undocumented SWP flags - from SDK 3.1 */
42 #define SWP_NOCLIENTSIZE 0x0800
43 #define SWP_NOCLIENTMOVE 0x1000
44 #define SWP_STATECHANGED 0x8000
46 #define SW_NORMALNA 0xCC /* undoc. flag in MinMaximize */
48 #ifndef WM_KEYF1
49 #define WM_KEYF1 0x004d
50 #endif
52 #ifndef WM_SYSTIMER
53 #define WM_SYSTIMER 0x0118
54 #endif
56 #define WND_PARENT_ID 1
57 #define WND_POPUP_ID 2
58 #define WND_CHILD_ID 3
60 #ifndef WM_LBTRACKPOINT
61 #define WM_LBTRACKPOINT 0x0131
62 #endif
64 #ifdef __i386__
65 #define ARCH "x86"
66 #elif defined __aarch64__ || defined__arm64ec__
67 #define ARCH "arm64"
68 #elif defined __x86_64__
69 #define ARCH "amd64"
70 #elif defined __arm__
71 #define ARCH "arm"
72 #else
73 #define ARCH "none"
74 #endif
76 /* encoded DRAWITEMSTRUCT into an LPARAM */
77 typedef struct
79 union
81 struct
83 UINT type : 4; /* ODT_* flags */
84 UINT ctl_id : 4; /* Control ID */
85 UINT item_id : 4; /* Menu item ID */
86 UINT action : 4; /* ODA_* flags */
87 UINT state : 16; /* ODS_* flags */
88 } item;
89 LPARAM lp;
90 } u;
91 } DRAW_ITEM_STRUCT;
93 /* encoded MEASUREITEMSTRUCT into a WPARAM */
94 typedef struct
96 union
98 struct
100 UINT CtlType : 4;
101 UINT CtlID : 4;
102 UINT itemID : 4;
103 UINT wParam : 20;
104 } item;
105 WPARAM wp;
106 } u;
107 } MEASURE_ITEM_STRUCT;
109 static BOOL test_DestroyWindow_flag;
110 static BOOL test_context_menu;
111 static HWINEVENTHOOK hEvent_hook;
112 static HHOOK hKBD_hook;
113 static HHOOK hCBT_hook;
114 static DWORD cbt_hook_thread_id;
115 static DWORD winevent_hook_thread_id;
117 static const WCHAR testWindowClassW[] =
118 { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 };
120 static LRESULT WINAPI ParentMsgCheckProcA(HWND, UINT, WPARAM, LPARAM);
122 static void register_class(const WNDCLASSA *class)
124 BOOL ret = RegisterClassA(class);
125 ok(ret, "Failed to register class %s, error %lu.\n",
126 debugstr_a(class->lpszClassName), GetLastError());
130 FIXME: add tests for these
131 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
132 WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
133 WS_THICKFRAME: thick border
134 WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
135 WS_BORDER (default for overlapped windows): single black border
136 none (default for child (and popup?) windows): no border
139 typedef enum {
140 sent=0x1,
141 posted=0x2,
142 parent=0x4,
143 wparam=0x8,
144 lparam=0x10,
145 defwinproc=0x20,
146 beginpaint=0x40,
147 optional=0x80,
148 hook=0x100,
149 winevent_hook=0x200,
150 kbd_hook=0x400,
151 msg_todo=0x800,
152 wine_only=0x1000
153 } msg_flags_t;
155 struct message {
156 UINT message; /* the WM_* code */
157 msg_flags_t flags; /* message props */
158 WPARAM wParam; /* expected value of wParam */
159 LPARAM lParam; /* expected value of lParam */
160 WPARAM wp_mask; /* mask for wParam checks */
161 LPARAM lp_mask; /* mask for lParam checks */
164 struct recvd_message {
165 UINT message; /* the WM_* code */
166 msg_flags_t flags; /* message props */
167 HWND hwnd; /* window that received the message */
168 WPARAM wParam; /* expected value of wParam */
169 LPARAM lParam; /* expected value of lParam */
170 int line; /* source line where logged */
171 const char *descr; /* description for trace output */
172 char output[512]; /* trace output */
175 /* Empty message sequence */
176 static const struct message WmEmptySeq[] =
178 { 0 }
180 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
181 static const struct message WmCreateOverlappedSeq[] = {
182 { HCBT_CREATEWND, hook },
183 { WM_GETMINMAXINFO, sent },
184 { WM_NCCREATE, sent },
185 { WM_NCCALCSIZE, sent|wparam, 0 },
186 { 0x0093, sent|defwinproc|optional },
187 { 0x0094, sent|defwinproc|optional },
188 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on win10. */
189 { WM_CREATE, sent },
190 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
191 { 0 }
193 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
194 * for a not visible overlapped window.
196 static const struct message WmSWP_ShowOverlappedSeq[] = {
197 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
198 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
199 { WM_NCPAINT, sent|wparam|optional, 1 },
200 { WM_GETTEXT, sent|defwinproc|optional },
201 { WM_ERASEBKGND, sent|optional },
202 { HCBT_ACTIVATE, hook },
203 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
204 { WM_NOTIFYFORMAT, sent|optional },
205 { WM_QUERYUISTATE, sent|optional },
206 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
207 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
208 { WM_ACTIVATEAPP, sent|wparam, 1 },
209 { WM_NCACTIVATE, sent },
210 { WM_GETTEXT, sent|defwinproc|optional },
211 { WM_ACTIVATE, sent|wparam, 1 },
212 { HCBT_SETFOCUS, hook },
213 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
214 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
215 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
216 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
217 { WM_GETTEXT, sent|optional },
218 { WM_NCPAINT, sent|wparam|optional, 1 },
219 { WM_GETTEXT, sent|defwinproc|optional },
220 { WM_ERASEBKGND, sent|optional },
221 /* Win9x adds SWP_NOZORDER below */
222 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
223 { WM_GETTEXT, sent|optional },
224 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
225 { WM_NCPAINT, sent|wparam|optional, 1 },
226 { WM_ERASEBKGND, sent|optional },
227 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on win10 */
228 { WM_SYNCPAINT, sent|optional },
229 { WM_GETTITLEBARINFOEX, sent|optional },
230 { WM_PAINT, sent|optional },
231 { WM_NCPAINT, sent|beginpaint|optional },
232 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
233 { WM_ERASEBKGND, sent|beginpaint|optional },
234 { 0 }
236 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
237 * for a visible overlapped window.
239 static const struct message WmSWP_HideOverlappedSeq[] = {
240 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
241 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
242 { HCBT_ACTIVATE, hook|optional },
243 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
244 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
245 { WM_NCACTIVATE, sent|optional },
246 { WM_ACTIVATE, sent|optional },
247 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
248 { 0 }
251 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
252 * for a visible overlapped window.
254 static const struct message WmSWP_ResizeSeq[] = {
255 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
256 { WM_GETMINMAXINFO, sent|defwinproc },
257 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
258 { WM_NCPAINT, sent|optional },
259 { WM_GETTEXT, sent|defwinproc|optional },
260 { WM_ERASEBKGND, sent|optional },
261 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
262 { WM_SIZE, sent|defwinproc|optional },
263 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
264 { WM_NCPAINT, sent|optional },
265 { WM_GETTEXT, sent|defwinproc|optional },
266 { WM_ERASEBKGND, sent|optional },
267 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
268 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
269 { 0 }
272 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
273 * for a visible popup window.
275 static const struct message WmSWP_ResizePopupSeq[] = {
276 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
277 { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */
278 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
279 { WM_NCPAINT, sent|optional },
280 { WM_GETTEXT, sent|defwinproc|optional },
281 { WM_ERASEBKGND, sent|optional },
282 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
283 { WM_SIZE, sent|defwinproc|wparam|optional, SIZE_RESTORED },
284 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
285 { WM_NCPAINT, sent|optional },
286 { WM_GETTEXT, sent|defwinproc|optional },
287 { WM_ERASEBKGND, sent|optional },
288 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
289 { 0 }
292 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
293 * for a visible overlapped window.
295 static const struct message WmSWP_MoveSeq[] = {
296 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
297 { WM_NCPAINT, sent|optional },
298 { WM_GETTEXT, sent|defwinproc|optional },
299 { WM_ERASEBKGND, sent|optional },
300 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
301 { WM_MOVE, sent|defwinproc|wparam, 0 },
302 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
303 { 0 }
305 /* Resize with SetWindowPos(SWP_NOZORDER)
306 * for a visible overlapped window
307 * SWP_NOZORDER is stripped by the logging code
309 static const struct message WmSWP_ResizeNoZOrder[] = {
310 { WM_WINDOWPOSCHANGING, sent|wparam, /*SWP_NOZORDER|*/SWP_NOACTIVATE },
311 { WM_GETMINMAXINFO, sent|defwinproc },
312 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
313 { WM_NCPAINT, sent|optional },
314 { WM_GETTEXT, sent|defwinproc|optional },
315 { WM_ERASEBKGND, sent|optional },
316 { WM_WINDOWPOSCHANGED, sent|wparam|optional, /*SWP_NOZORDER|*/SWP_NOACTIVATE, 0,
317 SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
318 { WM_MOVE, sent|defwinproc|optional },
319 { WM_SIZE, sent|defwinproc|optional },
320 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
321 { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
322 { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */
323 { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */
324 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
325 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on win10. */
326 { 0 }
329 /* Switch visible mdi children */
330 static const struct message WmSwitchChild[] = {
331 /* Switch MDI child */
332 { WM_MDIACTIVATE, sent },/* in the MDI client */
333 { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 1st MDI child */
334 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
335 { WM_CHILDACTIVATE, sent },/* in the 1st MDI child */
336 /* Deactivate 2nd MDI child */
337 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
338 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
339 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
340 /* Preparing for maximize and maximize the 1st MDI child */
341 { WM_GETMINMAXINFO, sent|defwinproc }, /* in the 1st MDI child */
342 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED }, /* in the 1st MDI child */
343 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
344 { WM_CHILDACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
345 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 1st MDI child */
346 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, /* in the 1st MDI child */
347 /* Lock redraw 2nd MDI child */
348 { WM_SETREDRAW, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
349 { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
350 /* Restore 2nd MDI child */
351 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },/* in the 2nd MDI child */
352 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
353 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
354 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 2nd MDI child */
355 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, /* in the 2nd MDI child */
356 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
357 /* Redraw 2nd MDI child */
358 { WM_SETREDRAW, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
359 /* Redraw MDI frame */
360 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },/* in MDI frame */
361 { WM_NCCALCSIZE, sent|wparam, 1 },/* in MDI frame */
362 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in MDI frame */
363 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in MDI frame */
364 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
365 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
366 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
367 { HCBT_SETFOCUS, hook },
368 { WM_KILLFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
369 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },/* in the 1st MDI child */
370 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
371 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
372 { WM_SETFOCUS, sent },/* in the MDI client */
373 { HCBT_SETFOCUS, hook },
374 { WM_KILLFOCUS, sent },/* in the MDI client */
375 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
376 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, /* in the 1st MDI child */
377 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
378 { WM_SETFOCUS, sent|defwinproc }, /* in the 1st MDI child */
379 { WM_MDIACTIVATE, sent|defwinproc },/* in the 1st MDI child */
380 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* in the 1st MDI child */
381 { 0 }
384 /* Switch visible not maximized mdi children */
385 static const struct message WmSwitchNotMaximizedChild[] = {
386 /* Switch not maximized MDI child */
387 { WM_MDIACTIVATE, sent },/* in the MDI client */
388 { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 2nd MDI child */
389 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
390 { WM_CHILDACTIVATE, sent },/* in the 2nd MDI child */
391 /* Deactivate 1st MDI child */
392 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
393 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
394 /* Activate 2nd MDI child */
395 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE}, /* in the 2nd MDI child */
396 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 2nd MDI child */
397 { HCBT_SETFOCUS, hook }, /* in the 1st MDI child */
398 { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
399 { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
400 { WM_IME_SETCONTEXT, sent|optional }, /* in the MDI client */
401 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
402 { WM_SETFOCUS, sent, 0 }, /* in the MDI client */
403 { HCBT_SETFOCUS, hook },
404 { WM_KILLFOCUS, sent }, /* in the MDI client */
405 { WM_IME_SETCONTEXT, sent|optional }, /* in the MDI client */
406 { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
407 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
408 { WM_SETFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
409 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
410 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in the 2nd MDI child */
411 { 0 }
415 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
416 SWP_NOZORDER|SWP_FRAMECHANGED)
417 * for a visible overlapped window with WS_CLIPCHILDREN style set.
419 static const struct message WmSWP_FrameChanged_clip[] = {
420 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
421 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
422 { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
423 { WM_GETTEXT, sent|parent|defwinproc|optional },
424 { WM_ERASEBKGND, sent|parent|msg_todo },
425 { WM_NCPAINT, sent }, /* wparam != 1 */
426 { WM_ERASEBKGND, sent },
427 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
428 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
429 { WM_PAINT, sent },
430 { 0 }
432 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
433 SWP_NOZORDER|SWP_FRAMECHANGED)
434 * for a visible overlapped window.
436 static const struct message WmSWP_FrameChangedDeferErase[] = {
437 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
438 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
439 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
440 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
441 { WM_PAINT, sent|parent|optional },
442 { WM_NCPAINT, sent|beginpaint|parent|optional }, /* wparam != 1 */
443 { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
444 { WM_PAINT, sent },
445 { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
446 { WM_ERASEBKGND, sent|beginpaint|optional },
447 { 0 }
450 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
451 SWP_NOZORDER|SWP_FRAMECHANGED)
452 * for a visible overlapped window without WS_CLIPCHILDREN style set.
454 static const struct message WmSWP_FrameChanged_noclip[] = {
455 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
456 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
457 { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
458 { WM_GETTEXT, sent|parent|defwinproc|optional },
459 { WM_ERASEBKGND, sent|parent|optional },
460 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
461 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
462 { WM_PAINT, sent },
463 { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
464 { WM_ERASEBKGND, sent|beginpaint|optional },
465 { 0 }
468 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
469 static const struct message WmShowOverlappedSeq[] = {
470 { WM_SHOWWINDOW, sent|wparam, 1 },
471 { WM_NCPAINT, sent|wparam|optional, 1 },
472 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
473 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
474 { WM_NCPAINT, sent|wparam|optional, 1 },
475 { WM_GETTEXT, sent|defwinproc|optional },
476 { WM_ERASEBKGND, sent|optional },
477 { HCBT_ACTIVATE, hook|optional },
478 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|optional, 0, 0 },
479 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
480 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
481 { WM_NCPAINT, sent|wparam|optional, 1 },
482 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
483 { WM_NCACTIVATE, sent|wparam|optional, 1 },
484 { WM_GETTEXT, sent|defwinproc|optional },
485 { WM_ACTIVATE, sent|wparam|optional, 1 },
486 { HCBT_SETFOCUS, hook|optional },
487 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
488 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
489 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
490 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
491 { WM_GETTEXT, sent|optional },
492 { WM_NCPAINT, sent|wparam|optional, 1 },
493 { WM_GETTEXT, sent|defwinproc|optional },
494 { WM_ERASEBKGND, sent|optional },
495 /* Win9x adds SWP_NOZORDER below */
496 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
497 { WM_NCCALCSIZE, sent|optional },
498 { WM_GETTEXT, sent|optional },
499 { WM_NCPAINT, sent|optional },
500 { WM_ERASEBKGND, sent|optional },
501 { WM_SYNCPAINT, sent|optional },
502 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
503 * messages. Does that mean that CreateWindow doesn't set initial
504 * window dimensions for overlapped windows?
506 { WM_SIZE, sent },
507 { WM_MOVE, sent },
508 #endif
509 { WM_PAINT, sent|optional },
510 { WM_NCPAINT, sent|beginpaint|optional },
511 { 0 }
513 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
514 static const struct message WmShowMaxOverlappedSeq[] = {
515 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
516 { WM_GETMINMAXINFO, sent },
517 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
518 { WM_GETMINMAXINFO, sent|defwinproc },
519 { WM_NCCALCSIZE, sent|wparam, TRUE },
520 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
521 { HCBT_ACTIVATE, hook|optional },
522 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|optional, 0, 0 },
523 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
524 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
525 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
526 { WM_NCACTIVATE, sent|wparam|optional, 1 },
527 { WM_GETTEXT, sent|defwinproc|optional },
528 { WM_ACTIVATE, sent|wparam|optional, 1 },
529 { HCBT_SETFOCUS, hook|optional },
530 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
531 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
532 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
533 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
534 { WM_GETTEXT, sent|optional },
535 { WM_NCPAINT, sent|wparam|optional, 1 },
536 { WM_GETTEXT, sent|defwinproc|optional },
537 { WM_ERASEBKGND, sent|optional },
538 /* Win9x adds SWP_NOZORDER below */
539 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
540 { WM_MOVE, sent|defwinproc },
541 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
542 { WM_GETTEXT, sent|optional },
543 { WM_NCCALCSIZE, sent|optional },
544 { WM_NCPAINT, sent|optional },
545 { WM_ERASEBKGND, sent|optional },
546 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
547 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on win10. */
548 { WM_SYNCPAINT, sent|optional },
549 { WM_GETTITLEBARINFOEX, sent|optional },
550 { WM_PAINT, sent|optional },
551 { WM_NCPAINT, sent|beginpaint|optional },
552 { WM_ERASEBKGND, sent|beginpaint|optional },
553 { 0 }
555 /* ShowWindow(SW_RESTORE) for a not visible maximized overlapped window */
556 static const struct message WmShowRestoreMaxOverlappedSeq[] = {
557 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
558 { WM_GETTEXT, sent|optional },
559 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
560 { WM_GETMINMAXINFO, sent|defwinproc },
561 { WM_NCCALCSIZE, sent|wparam, TRUE },
562 { WM_NCPAINT, sent|optional },
563 { WM_GETTEXT, sent|defwinproc|optional },
564 { WM_ERASEBKGND, sent|optional },
565 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
566 { WM_MOVE, sent|defwinproc|optional },
567 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
568 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
569 { WM_NCPAINT, sent|optional },
570 { WM_ERASEBKGND, sent|optional },
571 { WM_PAINT, sent|optional },
572 { WM_GETTITLEBARINFOEX, sent|optional },
573 { WM_NCPAINT, sent|beginpaint|optional },
574 { WM_ERASEBKGND, sent|beginpaint|optional },
575 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
576 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
577 { WM_SYNCPAINT, sent|optional },
578 { 0 }
580 /* ShowWindow(SW_RESTORE) for a not visible minimized overlapped window */
581 static const struct message WmShowRestoreMinOverlappedSeq[] = {
582 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
583 { WM_QUERYOPEN, sent|optional },
584 { WM_GETTEXT, sent|optional },
585 { WM_NCACTIVATE, sent|wparam|optional, 1 },
586 { WM_WINDOWPOSCHANGING, sent|optional }, /* SWP_NOSIZE|SWP_NOMOVE */
587 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
588 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
589 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sent on Win7. */
590 { WM_MOVE, sent|optional },
591 { WM_SIZE, sent|wparam|optional, SIZE_RESTORED },
592 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sent on Win7. */
593 { WM_GETTEXT, sent|optional },
594 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED|SWP_NOCOPYBITS },
595 { WM_GETMINMAXINFO, sent|defwinproc|optional },
596 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
597 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sent on Win10. */
598 { HCBT_ACTIVATE, hook|optional },
599 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|optional, 0, 0 },
600 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
601 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
602 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
603 { WM_NCACTIVATE, sent|wparam|optional, 1 },
604 { WM_GETTEXT, sent|defwinproc|optional },
605 { WM_ACTIVATE, sent|wparam|optional, 1 },
606 { HCBT_SETFOCUS, hook|optional },
607 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
608 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
609 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
610 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
611 { WM_GETTEXT, sent|optional },
612 { WM_NCPAINT, sent|wparam|optional, 1 },
613 { WM_GETTEXT, sent|defwinproc|optional },
614 { WM_ERASEBKGND, sent },
615 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_STATECHANGED|SWP_FRAMECHANGED|SWP_NOCOPYBITS },
616 { WM_MOVE, sent|defwinproc },
617 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
618 { HCBT_SETFOCUS, hook|optional },
619 { WM_SETFOCUS, sent|wparam|optional, 0 },
620 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
621 { WM_NCPAINT, sent|wparam|optional, 1 },
622 { WM_ERASEBKGND, sent|optional },
623 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
624 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
625 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 },
626 { HCBT_SETFOCUS, hook|optional },
627 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
628 { WM_SETFOCUS, sent|wparam|optional, 0 },
629 { WM_ACTIVATE, sent|wparam, 1 },
630 { WM_GETTEXT, sent|optional },
631 { WM_PAINT, sent|optional },
632 { WM_GETTITLEBARINFOEX, sent|optional },
633 { WM_NCPAINT, sent|beginpaint|optional },
634 { WM_ERASEBKGND, sent|beginpaint|optional },
635 { 0 }
637 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
638 static const struct message WmShowMinOverlappedSeq[] = {
639 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
640 { HCBT_SETFOCUS, hook|optional },
641 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
642 { WM_KILLFOCUS, sent|optional },
643 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
644 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
645 { WM_GETTEXT, sent|optional },
646 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
647 { WM_GETMINMAXINFO, sent|defwinproc },
648 { WM_NCCALCSIZE, sent|wparam, TRUE },
649 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
650 { WM_NCPAINT, sent|optional },
651 { WM_GETTEXT, sent|defwinproc|optional },
652 { WM_WINDOWPOSCHANGED, sent },
653 { WM_MOVE, sent|defwinproc },
654 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
655 { WM_NCCALCSIZE, sent|optional },
656 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
657 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on win10. */
658 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
659 { WM_NCACTIVATE, sent|wparam|optional, 0 },
660 { WM_GETTEXT, sent|defwinproc|optional },
661 { WM_ACTIVATE, sent|optional },
662 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
664 /* Vista sometimes restores the window right away... */
665 { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
666 { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
667 { HCBT_MINMAX, hook|optional|lparam, 0, SW_RESTORE },
668 { WM_QUERYOPEN, sent|optional },
669 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
670 { WM_GETMINMAXINFO, sent|optional|defwinproc },
671 { WM_NCCALCSIZE, sent|optional|wparam, TRUE },
672 { HCBT_ACTIVATE, hook|optional },
673 { WM_ACTIVATEAPP, sent|optional|wparam, 1 },
674 { WM_NCACTIVATE, sent|optional },
675 { WM_GETTEXT, sent|optional },
676 { WM_ACTIVATE, sent|optional|wparam, 1 },
677 { HCBT_SETFOCUS, hook|optional },
678 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
679 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
680 { WM_SETFOCUS, sent|optional },
681 { WM_NCPAINT, sent|optional },
682 { WM_GETTEXT, sent|defwinproc|optional },
683 { WM_ERASEBKGND, sent|optional },
684 { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
685 { WM_MOVE, sent|defwinproc|optional },
686 { WM_SIZE, sent|defwinproc|optional|wparam, SIZE_RESTORED },
687 { WM_ACTIVATE, sent|optional|wparam, 1 },
688 { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
689 { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
691 { WM_PAINT, sent|optional },
692 { WM_NCPAINT, sent|beginpaint|optional },
693 { WM_ERASEBKGND, sent|beginpaint|optional },
694 { 0 }
696 /* ShowWindow(SW_HIDE) for a visible overlapped window */
697 static const struct message WmHideOverlappedSeq[] = {
698 { WM_SHOWWINDOW, sent|wparam, 0 },
699 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
700 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
701 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
702 { WM_SIZE, sent|optional }, /* XP doesn't send it */
703 { WM_MOVE, sent|optional }, /* XP doesn't send it */
704 { WM_NCACTIVATE, sent|wparam|optional, 0 },
705 { WM_ACTIVATE, sent|wparam|optional, 0 },
706 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
707 { HCBT_SETFOCUS, hook|optional },
708 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
709 { WM_KILLFOCUS, sent|wparam|optional, 0 },
710 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
711 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
712 { 0 }
714 /* DestroyWindow for a visible overlapped window */
715 static const struct message WmDestroyOverlappedSeq[] = {
716 { HCBT_DESTROYWND, hook },
717 { 0x0090, sent|optional },
718 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
719 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
720 { 0x0090, sent|optional },
721 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
722 { WM_NCACTIVATE, sent|optional|wparam, 0 },
723 { WM_ACTIVATE, sent|optional },
724 { WM_ACTIVATEAPP, sent|optional|wparam, 0 },
725 { WM_KILLFOCUS, sent|optional|wparam, 0 },
726 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
727 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
728 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
729 { WM_DESTROY, sent },
730 { WM_NCDESTROY, sent },
731 { 0 }
733 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
734 static const struct message WmCreateMaxPopupSeq[] = {
735 { HCBT_CREATEWND, hook },
736 { WM_NCCREATE, sent },
737 { WM_NCCALCSIZE, sent|wparam, 0 },
738 { WM_CREATE, sent },
739 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
740 { WM_SIZE, sent|wparam, SIZE_RESTORED },
741 { WM_MOVE, sent },
742 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
743 { WM_GETMINMAXINFO, sent },
744 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
745 { WM_NCCALCSIZE, sent|wparam, TRUE },
746 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
747 { WM_MOVE, sent|defwinproc },
748 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
749 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
750 { WM_SHOWWINDOW, sent|wparam, 1 },
751 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
752 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
753 { HCBT_ACTIVATE, hook },
754 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
755 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
756 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
757 { WM_NCPAINT, sent|wparam|optional, 1 },
758 { WM_ERASEBKGND, sent|optional },
759 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_NOMOVE|SWP_NOSIZE },
760 { WM_ACTIVATEAPP, sent|wparam, 1 },
761 { WM_NCACTIVATE, sent },
762 { WM_ACTIVATE, sent|wparam, 1 },
763 { HCBT_SETFOCUS, hook },
764 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
765 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
766 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
767 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
768 { WM_GETTEXT, sent|optional },
769 { WM_SYNCPAINT, sent|wparam|optional, 4 },
770 { WM_NCPAINT, sent|wparam|optional, 1 },
771 { WM_ERASEBKGND, sent|optional },
772 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
773 { WM_ERASEBKGND, sent|defwinproc|optional },
774 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
775 { 0 }
777 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
778 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
779 { HCBT_CREATEWND, hook },
780 { WM_NCCREATE, sent },
781 { WM_NCCALCSIZE, sent|wparam, 0 },
782 { WM_CREATE, sent },
783 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
784 { WM_SIZE, sent|wparam, SIZE_RESTORED },
785 { WM_MOVE, sent },
786 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
787 { WM_GETMINMAXINFO, sent },
788 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
789 { WM_NCCALCSIZE, sent|wparam, TRUE },
790 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
791 { WM_MOVE, sent|defwinproc },
792 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
793 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
794 { 0 }
796 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
797 static const struct message WmShowMaxPopupResizedSeq[] = {
798 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
799 { WM_GETMINMAXINFO, sent },
800 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED, 0, SWP_STATECHANGED /* w1064v1809 */ },
801 { WM_NCCALCSIZE, sent|wparam, TRUE },
802 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
803 { HCBT_ACTIVATE, hook },
804 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
805 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
806 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
807 { WM_NCPAINT, sent|wparam|optional, 1 },
808 { WM_ERASEBKGND, sent|optional },
809 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
810 { WM_ACTIVATEAPP, sent|wparam, 1 },
811 { WM_NCACTIVATE, sent },
812 { WM_ACTIVATE, sent|wparam, 1 },
813 { HCBT_SETFOCUS, hook },
814 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
815 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
816 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
817 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
818 { WM_GETTEXT, sent|optional },
819 { WM_NCPAINT, sent|wparam|optional, 1 },
820 { WM_ERASEBKGND, sent|optional },
821 { WM_WINDOWPOSCHANGED, sent },
822 /* WinNT4.0 sends WM_MOVE */
823 { WM_MOVE, sent|defwinproc|optional },
824 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
825 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
826 { 0 }
828 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
829 static const struct message WmShowMaxPopupSeq[] = {
830 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
831 { WM_GETMINMAXINFO, sent },
832 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED, 0, SWP_STATECHANGED /* w1064v1809 */ },
833 { WM_NCCALCSIZE, sent|wparam, TRUE },
834 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
835 { HCBT_ACTIVATE, hook },
836 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
837 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
838 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
839 { WM_NCPAINT, sent|wparam|optional, 1 },
840 { WM_ERASEBKGND, sent|optional },
841 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOMOVE|SWP_NOSIZE },
842 { WM_ACTIVATEAPP, sent|wparam, 1 },
843 { WM_NCACTIVATE, sent },
844 { WM_ACTIVATE, sent|wparam, 1 },
845 { HCBT_SETFOCUS, hook },
846 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
847 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
848 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
849 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
850 { WM_GETTEXT, sent|optional },
851 { WM_SYNCPAINT, sent|wparam|optional, 4 },
852 { WM_NCPAINT, sent|wparam|optional, 1 },
853 { WM_ERASEBKGND, sent|optional },
854 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
855 { WM_ERASEBKGND, sent|defwinproc|optional },
856 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE, 0, SWP_STATECHANGED /* w1064v1809 */ },
857 { WM_SIZE, sent|defwinproc|optional },
858 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
859 { 0 }
861 /* CreateWindow(WS_VISIBLE) for popup window */
862 static const struct message WmCreatePopupSeq[] = {
863 { HCBT_CREATEWND, hook },
864 { WM_NCCREATE, sent },
865 { WM_NCCALCSIZE, sent|wparam, 0 },
866 { WM_CREATE, sent },
867 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
868 { WM_SIZE, sent|wparam, SIZE_RESTORED },
869 { WM_MOVE, sent },
870 { WM_SHOWWINDOW, sent|wparam, 1 },
871 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
872 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
873 { HCBT_ACTIVATE, hook },
874 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
875 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
876 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
877 { WM_NCPAINT, sent|wparam|optional, 1 },
878 { WM_ERASEBKGND, sent|optional },
879 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
880 { WM_ACTIVATEAPP, sent|wparam, 1 },
881 { WM_NCACTIVATE, sent },
882 { WM_ACTIVATE, sent|wparam, 1 },
883 { HCBT_SETFOCUS, hook },
884 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
885 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
886 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
887 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
888 { WM_GETTEXT, sent|optional },
889 { WM_SYNCPAINT, sent|wparam|optional, 4 },
890 { WM_NCPAINT, sent|wparam|optional, 1 },
891 { WM_ERASEBKGND, sent|optional },
892 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
893 { 0 }
895 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
896 static const struct message WmShowVisMaxPopupSeq[] = {
897 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
898 { WM_GETMINMAXINFO, sent },
899 { WM_GETTEXT, sent|optional },
900 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
901 { WM_GETTEXT, sent|optional },
902 { WM_NCCALCSIZE, sent|wparam, TRUE },
903 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
904 { WM_NCPAINT, sent|wparam|optional, 1 },
905 { WM_ERASEBKGND, sent|optional },
906 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
907 { WM_MOVE, sent|defwinproc },
908 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
909 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
910 { 0 }
912 /* ShowWindow(hwnd, SW_RESTORE) to a minimized window */
913 static const struct message WmShowRestoreMinimizedOverlappedSeq[] =
915 { HCBT_MINMAX, hook },
916 { WM_QUERYOPEN, sent },
917 { WM_GETTEXT, sent|optional },
918 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
919 { WM_GETMINMAXINFO, sent|defwinproc },
920 { WM_NCCALCSIZE, sent },
921 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
922 { HCBT_ACTIVATE, hook },
923 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
924 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
925 { WM_NCACTIVATE, sent },
926 { WM_GETTEXT, sent|defwinproc|optional },
927 { WM_ACTIVATE, sent|wparam, WA_ACTIVE },
928 { HCBT_SETFOCUS, hook },
929 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
930 { WM_SETFOCUS, sent|defwinproc },
931 { WM_NCPAINT, sent },
932 { WM_GETTEXT, sent|defwinproc|optional },
933 { WM_GETTEXT, sent|defwinproc|optional },
934 { WM_ERASEBKGND, sent },
935 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
936 { WM_MOVE, sent|defwinproc },
937 { WM_SIZE, sent|defwinproc },
938 { WM_NCCALCSIZE, sent|optional },
939 { WM_NCPAINT, sent|optional },
940 { WM_ERASEBKGND, sent|optional },
941 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
942 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
943 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
944 /* Note this WM_ACTIVATE message even if the window is already active and focused */
945 { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, 0 },
946 { WM_SYNCPAINT, sent|optional },
947 { WM_PAINT, sent },
948 { WM_GETMINMAXINFO, sent|optional },
949 { 0 }
951 /* ShowWindow(hwnd, SW_SHOWNOACTIVATE) to a minimized window */
952 static const struct message WmShowNoActivateMinimizedOverlappedSeq[] =
954 { HCBT_MINMAX, hook },
955 { WM_QUERYOPEN, sent },
956 { WM_GETTEXT, sent|optional },
957 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
958 { WM_GETMINMAXINFO, sent|defwinproc },
959 { WM_NCCALCSIZE, sent },
960 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
961 { WM_NCPAINT, sent },
962 { WM_GETTEXT, sent|defwinproc|optional },
963 { WM_ERASEBKGND, sent },
964 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
965 { WM_MOVE, sent|defwinproc },
966 { WM_SIZE, sent|defwinproc },
967 /* Following optional messages are on XP/2003 */
968 { WM_NCCALCSIZE, sent|optional },
969 { WM_NCPAINT, sent|optional },
970 { WM_ERASEBKGND, sent|optional },
971 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
972 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
973 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
974 { HCBT_SETFOCUS, hook|optional },
975 { WM_SETFOCUS, sent|optional },
976 { HCBT_ACTIVATE, hook|optional },
977 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
978 { WM_NCACTIVATE, sent|optional },
979 { WM_GETTEXT, sent|defwinproc|optional },
980 { WM_ACTIVATE, sent|wparam|optional, WA_ACTIVE },
981 { HCBT_SETFOCUS, hook|optional },
982 { WM_SETFOCUS, sent|defwinproc|optional },
983 { WM_KILLFOCUS, sent|optional },
984 { WM_SETFOCUS, sent|optional },
985 /* Note this WM_ACTIVATE message on XP even if the window is already active and focused */
986 { WM_ACTIVATE, sent|wparam|lparam|optional, WA_ACTIVE, 0 },
987 { WM_SYNCPAINT, sent|optional },
988 { WM_PAINT, sent },
989 { WM_GETMINMAXINFO, sent|optional },
990 { 0 }
992 /* ShowWindow(hwnd, SW_RESTORE) to an active minimized window */
993 static const struct message WmShowRestoreActiveMinimizedOverlappedSeq[] =
995 { HCBT_MINMAX, hook },
996 { WM_QUERYOPEN, sent },
997 { WM_GETTEXT, sent|optional },
998 { WM_NCACTIVATE, sent },
999 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1000 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1001 { WM_NCCALCSIZE, sent|optional },
1002 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends this. */
1003 { WM_MOVE, sent|optional },
1004 { WM_SIZE, sent|optional },
1005 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends this. */
1006 { WM_GETTEXT, sent|optional },
1007 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1008 { WM_GETMINMAXINFO, sent|defwinproc },
1009 { WM_NCCALCSIZE, sent },
1010 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win8+ sends this. */
1011 { WM_NCPAINT, sent },
1012 { WM_GETTEXT, sent|defwinproc|optional },
1013 { WM_ERASEBKGND, sent },
1014 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1015 { WM_MOVE, sent|defwinproc },
1016 { WM_SIZE, sent|defwinproc },
1017 { WM_NCCALCSIZE, sent|optional },
1018 { WM_NCPAINT, sent|optional },
1019 { WM_ERASEBKGND, sent|optional },
1020 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
1021 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
1022 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
1023 { HCBT_SETFOCUS, hook },
1024 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1025 { WM_SETFOCUS, sent },
1026 /* Note this WM_ACTIVATE message even if the window is already active */
1027 { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, 0 },
1028 { WM_SYNCPAINT, sent|optional },
1029 { WM_PAINT, sent },
1030 { WM_GETMINMAXINFO, sent|optional },
1031 { 0 }
1033 /* ShowWindow(hwnd, SW_SHOWNOACTIVATE) to an active minimized window */
1034 static const struct message WmShowNoActivateActiveMinimizedOverlappedSeq[] =
1036 { HCBT_MINMAX, hook },
1037 { WM_QUERYOPEN, sent },
1038 { WM_GETTEXT, sent|optional },
1039 { WM_NCACTIVATE, sent },
1040 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1041 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1042 { WM_NCCALCSIZE, sent|optional },
1043 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends this. */
1044 { WM_MOVE, sent|optional },
1045 { WM_SIZE, sent|optional },
1046 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends this. */
1047 { WM_GETTEXT, sent|optional },
1048 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1049 { WM_GETMINMAXINFO, sent|defwinproc },
1050 { WM_NCCALCSIZE, sent },
1051 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win8+ sends this. */
1052 { WM_NCPAINT, sent },
1053 { WM_GETTEXT, sent|defwinproc|optional },
1054 { WM_ERASEBKGND, sent },
1055 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1056 { WM_MOVE, sent|defwinproc },
1057 { WM_SIZE, sent|defwinproc },
1058 { WM_NCCALCSIZE, sent|optional },
1059 { WM_NCPAINT, sent|optional },
1060 { WM_ERASEBKGND, sent|optional },
1061 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
1062 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
1063 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
1064 /* Following optional messages are present on XP */
1065 { HCBT_SETFOCUS, hook|optional },
1066 { WM_SETFOCUS, sent|optional },
1067 /* Note this WM_ACTIVATE message even if the window is already active and with flag SW_SHOWNOACTIVATE */
1068 { WM_ACTIVATE, sent|wparam|lparam|optional, WA_ACTIVE, 0 },
1069 { WM_SYNCPAINT, sent|optional },
1070 { WM_PAINT, sent },
1071 { WM_GETMINMAXINFO, sent|optional },
1072 { 0 }
1074 /* CreateWindow (for a child popup window, not initially visible) */
1075 static const struct message WmCreateChildPopupSeq[] = {
1076 { HCBT_CREATEWND, hook },
1077 { WM_NCCREATE, sent },
1078 { WM_NCCALCSIZE, sent|wparam, 0 },
1079 { WM_CREATE, sent },
1080 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1081 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1082 { WM_MOVE, sent },
1083 { 0 }
1085 /* CreateWindow (for a popup window, not initially visible,
1086 * which sets WS_VISIBLE in WM_CREATE handler)
1088 static const struct message WmCreateInvisiblePopupSeq[] = {
1089 { HCBT_CREATEWND, hook },
1090 { WM_NCCREATE, sent },
1091 { WM_NCCALCSIZE, sent|wparam, 0 },
1092 { WM_CREATE, sent },
1093 { WM_STYLECHANGING, sent },
1094 { WM_STYLECHANGED, sent },
1095 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1096 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1097 { WM_MOVE, sent },
1098 { 0 }
1100 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
1101 * for a popup window with WS_VISIBLE style set
1103 static const struct message WmShowVisiblePopupSeq_2[] = {
1104 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1105 { 0 }
1107 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1108 * for a popup window with WS_VISIBLE style set
1110 static const struct message WmShowVisiblePopupSeq_3[] = {
1111 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1112 { HCBT_ACTIVATE, hook },
1113 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1114 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1115 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1116 { WM_NCACTIVATE, sent },
1117 { WM_ACTIVATE, sent|wparam, 1 },
1118 { HCBT_SETFOCUS, hook },
1119 { WM_KILLFOCUS, sent|parent },
1120 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1121 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1122 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1123 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1124 { WM_SETFOCUS, sent|defwinproc },
1125 { WM_GETTEXT, sent|optional },
1126 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_SHOWWINDOW },
1127 { 0 }
1129 /* CreateWindow (for a popup window with WS_VISIBLE style set and extreme location)
1131 static const struct message WmShowPopupExtremeLocationSeq[] = {
1132 { HCBT_CREATEWND, hook },
1133 { WM_NCCREATE, sent },
1134 { WM_NCCALCSIZE, sent|wparam, 0 },
1135 { WM_CREATE, sent },
1136 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1137 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1138 { WM_MOVE, sent },
1139 { WM_SHOWWINDOW, sent|wparam, 1 },
1140 { WM_WINDOWPOSCHANGING, sent },
1141 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1142 { HCBT_ACTIVATE, hook },
1143 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1144 { WM_WINDOWPOSCHANGING, sent|optional },
1145 { WM_QUERYNEWPALETTE, sent|optional },
1147 /* occasionally received on test machines */
1148 { WM_NCPAINT, sent|optional },
1149 { WM_ERASEBKGND, sent|optional },
1150 { WM_WINDOWPOSCHANGED, sent|optional },
1152 { WM_ACTIVATEAPP, sent },
1153 { WM_NCACTIVATE, sent },
1154 { WM_ACTIVATE, sent },
1155 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1156 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1157 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1158 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Not sent on Win10. */
1159 { HCBT_SETFOCUS, hook },
1160 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1161 { WM_SETFOCUS, sent|defwinproc },
1162 { WM_NCPAINT, sent|wparam|optional, 1 }, /* Not always sent on Win8+ */
1163 { WM_ERASEBKGND, sent|optional }, /* Not always sent on Win8+ */
1164 { WM_WINDOWPOSCHANGED, sent },
1165 /* occasionally received on test machines */
1166 { WM_NCPAINT, sent|optional },
1167 { WM_ERASEBKGND, sent|optional },
1168 { 0 }
1170 /* CreateWindow (for a popup window with WS_VISIBLE style set)
1172 static const struct message WmShowPopupFirstDrawSeq_1[] = {
1173 { HCBT_CREATEWND, hook },
1174 { WM_NCCREATE, sent },
1175 { WM_NCCALCSIZE, sent|wparam, 0 },
1176 { WM_CREATE, sent },
1177 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1178 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1179 { WM_MOVE, sent },
1180 { WM_SHOWWINDOW, sent|wparam, 1 },
1181 { WM_WINDOWPOSCHANGING, sent },
1182 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1183 { HCBT_ACTIVATE, hook },
1184 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1185 { WM_WINDOWPOSCHANGING, sent|optional },
1186 { WM_QUERYNEWPALETTE, sent|optional },
1187 { WM_ACTIVATEAPP, sent },
1188 { WM_NCACTIVATE, sent },
1189 { WM_ACTIVATE, sent },
1190 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1191 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1192 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1193 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Not sent on Win10. */
1194 { HCBT_SETFOCUS, hook },
1195 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1196 { WM_SETFOCUS, sent|defwinproc },
1197 { WM_NCPAINT, sent|wparam, 1 },
1198 { WM_ERASEBKGND, sent },
1199 { WM_WINDOWPOSCHANGED, sent },
1200 { WM_PAINT, sent },
1201 /* occasionally received on test machines */
1202 { WM_NCPAINT, sent|beginpaint|optional },
1203 { WM_ERASEBKGND, sent|beginpaint|optional },
1204 { 0 }
1206 /* CreateWindow (for a popup window that is shown with ShowWindow(SW_SHOWMAXIMIZED))
1208 static const struct message WmShowPopupFirstDrawSeq_2[] = {
1209 { HCBT_CREATEWND, hook },
1210 { WM_NCCREATE, sent },
1211 { WM_NCCALCSIZE, sent|wparam, 0 },
1212 { WM_CREATE, sent },
1213 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1214 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1215 { WM_MOVE, sent },
1216 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1217 { WM_GETMINMAXINFO, sent },
1218 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_STATECHANGED|SWP_SHOWWINDOW|SWP_FRAMECHANGED },
1219 { WM_NCCALCSIZE, sent|wparam, TRUE },
1220 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1221 { HCBT_ACTIVATE, hook },
1222 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1223 { WM_WINDOWPOSCHANGING, sent|optional },
1224 { WM_NCPAINT, sent|optional|wparam, 1 },
1225 { WM_ERASEBKGND, sent|optional },
1226 { WM_WINDOWPOSCHANGED, sent|optional },
1227 { WM_QUERYNEWPALETTE, sent|optional },
1228 { WM_ACTIVATEAPP, sent },
1229 { WM_NCACTIVATE, sent },
1230 { WM_ACTIVATE, sent },
1231 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1232 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1233 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1234 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Not sent on Win10. */
1235 { HCBT_SETFOCUS, hook },
1236 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1237 { WM_SETFOCUS, sent|defwinproc },
1238 { WM_NCPAINT, sent|wparam, 1 },
1239 { WM_ERASEBKGND, sent },
1240 { WM_WINDOWPOSCHANGED, sent|optional },
1241 { WM_MOVE, sent|defwinproc },
1242 { WM_SIZE, sent|defwinproc, 0 },
1243 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1244 { WM_PAINT, sent},
1245 /* occasionally received on test machines */
1246 { WM_NCPAINT, sent|beginpaint|optional },
1247 { WM_ERASEBKGND, sent|beginpaint|optional },
1248 { 0 }
1250 static const struct message WmFirstDrawSetWindowPosSeq1[] = {
1251 { HCBT_CREATEWND, hook },
1252 { WM_NCCREATE, sent },
1253 { WM_NCCALCSIZE, sent|wparam, 0 },
1254 { WM_CREATE, sent },
1255 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1256 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1257 { WM_MOVE, sent },
1258 { WM_WINDOWPOSCHANGING, sent },
1259 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1260 { HCBT_ACTIVATE, hook },
1261 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1262 { WM_WINDOWPOSCHANGING, sent|optional },
1263 { WM_QUERYNEWPALETTE, sent|optional },
1264 { WM_ACTIVATEAPP, sent },
1265 { WM_NCACTIVATE, sent },
1266 { WM_ACTIVATE, sent },
1267 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1268 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1269 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1270 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Not sent on Win10. */
1271 { HCBT_SETFOCUS, hook },
1272 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1273 { WM_SETFOCUS, sent|defwinproc },
1274 { WM_NCPAINT, sent|wparam, 1 },
1275 { WM_ERASEBKGND, sent },
1276 { WM_WINDOWPOSCHANGED, sent },
1277 { WM_MOVE, sent|defwinproc },
1278 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1279 { 0 }
1281 static const struct message WmFirstDrawSetWindowPosSeq2[] = {
1282 { HCBT_CREATEWND, hook },
1283 { WM_NCCREATE, sent },
1284 { WM_NCCALCSIZE, sent|wparam, 0 },
1285 { WM_CREATE, sent },
1286 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1287 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1288 { WM_MOVE, sent },
1289 { WM_WINDOWPOSCHANGING, sent },
1290 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not always sent. */
1291 { HCBT_ACTIVATE, hook },
1292 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1293 { WM_QUERYNEWPALETTE, sent|optional },
1294 { WM_WINDOWPOSCHANGING, sent|optional },
1295 { WM_ACTIVATEAPP, sent },
1296 { WM_NCACTIVATE, sent },
1297 { WM_ACTIVATE, sent },
1298 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1299 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1300 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1301 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Not sent on Win10. */
1302 { HCBT_SETFOCUS, hook },
1303 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1304 { WM_SETFOCUS, sent|defwinproc },
1305 { WM_WINDOWPOSCHANGED, sent },
1306 { WM_MOVE, sent|defwinproc },
1307 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1308 { 0 }
1310 static const struct message WmFirstDrawSetWindowPosSeq3[] = {
1311 { HCBT_CREATEWND, hook },
1312 { WM_NCCREATE, sent },
1313 { WM_NCCALCSIZE, sent|wparam, 0 },
1314 { WM_CREATE, sent },
1315 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1316 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1317 { WM_MOVE, sent },
1318 { EVENT_OBJECT_SHOW, winevent_hook|wine_only },
1319 { HCBT_ACTIVATE, hook|wine_only },
1320 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|wine_only, 0, 0 },
1321 { WM_QUERYNEWPALETTE, sent|wine_only },
1322 { WM_ACTIVATEAPP, sent|wine_only },
1323 { WM_NCACTIVATE, sent|wine_only },
1324 { WM_ACTIVATE, sent|wine_only },
1325 { HCBT_SETFOCUS, hook|wine_only },
1326 { EVENT_OBJECT_FOCUS, winevent_hook|lparam|wparam|wine_only, OBJID_CLIENT, 0 },
1327 { WM_SETFOCUS, sent|defwinproc|wine_only },
1328 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|lparam|wparam|wine_only, 0, 0 },
1329 { 0 }
1331 static const struct message WmFirstDrawSetWindowPosSeq4[] = {
1332 { HCBT_CREATEWND, hook },
1333 { WM_NCCREATE, sent },
1334 { WM_NCCALCSIZE, sent|wparam, 0 },
1335 { WM_CREATE, sent },
1336 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1337 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1338 { WM_MOVE, sent },
1339 { WM_WINDOWPOSCHANGING, sent },
1340 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1341 { HCBT_ACTIVATE, hook },
1342 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1343 { WM_WINDOWPOSCHANGING, sent|optional },
1344 { WM_QUERYNEWPALETTE, sent|optional },
1345 { WM_ACTIVATEAPP, sent },
1346 { WM_NCACTIVATE, sent },
1347 { WM_ACTIVATE, sent },
1348 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1349 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1350 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1351 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Not sent on Win10. */
1352 { HCBT_SETFOCUS, hook },
1353 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1354 { WM_SETFOCUS, sent|defwinproc },
1355 { WM_NCPAINT, sent|wparam, 1 },
1356 { WM_ERASEBKGND, sent },
1357 { WM_WINDOWPOSCHANGED, sent },
1358 { 0 }
1360 static const struct message WmFirstDrawSetWindowPosSeq5[] = {
1361 { HCBT_CREATEWND, hook },
1362 { WM_NCCREATE, sent },
1363 { WM_NCCALCSIZE, sent|wparam, 0 },
1364 { WM_CREATE, sent },
1365 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1366 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1367 { WM_MOVE, sent },
1368 { WM_WINDOWPOSCHANGING, sent },
1369 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1370 { HCBT_ACTIVATE, hook },
1371 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1372 { WM_WINDOWPOSCHANGING, sent|optional },
1373 { WM_QUERYNEWPALETTE, sent|optional },
1374 { WM_ACTIVATEAPP, sent },
1375 { WM_NCACTIVATE, sent },
1376 { WM_ACTIVATE, sent },
1377 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1378 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1379 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1380 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Not sent on Win10. */
1381 { HCBT_SETFOCUS, hook },
1382 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1383 { WM_SETFOCUS, sent|defwinproc },
1384 { WM_WINDOWPOSCHANGED, sent },
1385 { 0 }
1387 static const struct message WmFirstDrawSetWindowPosSeq6[] = {
1388 { HCBT_CREATEWND, hook },
1389 { WM_NCCREATE, sent },
1390 { WM_NCCALCSIZE, sent|wparam, 0 },
1391 { WM_CREATE, sent },
1392 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1393 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1394 { WM_MOVE, sent },
1395 { EVENT_OBJECT_SHOW, winevent_hook|wine_only },
1396 { HCBT_ACTIVATE, hook|wine_only },
1397 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|wine_only, 0, 0 },
1398 { WM_QUERYNEWPALETTE, sent|wine_only },
1399 { WM_ACTIVATEAPP, sent|wine_only },
1400 { WM_NCACTIVATE, sent|wine_only },
1401 { WM_ACTIVATE, sent|wine_only },
1402 { HCBT_SETFOCUS, hook|wine_only },
1403 { EVENT_OBJECT_FOCUS, winevent_hook|lparam|wparam|wine_only, OBJID_CLIENT, 0 },
1404 { WM_SETFOCUS, sent|defwinproc|wine_only },
1405 { 0 }
1407 static const struct message WmFirstDrawChildSeq1[] = {
1408 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1409 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
1410 { 0 }
1412 static const struct message WmFirstDrawChildSeq2[] = {
1413 { WM_NCPAINT, sent|wparam, 1 },
1414 { WM_ERASEBKGND, sent },
1415 /* occasionally received on test machines */
1416 { WM_NCPAINT, sent|optional },
1417 { WM_ERASEBKGND, sent|optional },
1418 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1419 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
1420 { 0 }
1422 /* CreateWindow (for child window, not initially visible) */
1423 static const struct message WmCreateChildSeq[] = {
1424 { HCBT_CREATEWND, hook },
1425 { WM_NCCREATE, sent },
1426 /* child is inserted into parent's child list after WM_NCCREATE returns */
1427 { WM_NCCALCSIZE, sent|wparam, 0 },
1428 { WM_CREATE, sent },
1429 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1430 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1431 { WM_MOVE, sent },
1432 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1433 { 0 }
1435 /* CreateWindow (for maximized child window, not initially visible) */
1436 static const struct message WmCreateMaximizedChildSeq[] = {
1437 { HCBT_CREATEWND, hook },
1438 { WM_NCCREATE, sent },
1439 { WM_NCCALCSIZE, sent|wparam, 0 },
1440 { WM_CREATE, sent },
1441 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1442 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1443 { WM_MOVE, sent },
1444 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1445 { WM_GETMINMAXINFO, sent },
1446 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
1447 { WM_NCCALCSIZE, sent|wparam, 1 },
1448 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1449 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1450 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1451 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1452 { 0 }
1454 /* CreateWindow (for a child window, initially visible) */
1455 static const struct message WmCreateVisibleChildSeq[] = {
1456 { HCBT_CREATEWND, hook },
1457 { WM_NCCREATE, sent },
1458 /* child is inserted into parent's child list after WM_NCCREATE returns */
1459 { WM_NCCALCSIZE, sent|wparam, 0 },
1460 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win10. */
1461 { WM_CREATE, sent },
1462 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1463 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1464 { WM_MOVE, sent },
1465 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1466 { WM_SHOWWINDOW, sent|wparam, 1 },
1467 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1468 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1469 { WM_ERASEBKGND, sent|parent|optional },
1470 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1471 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
1472 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
1473 { 0 }
1475 /* ShowWindow(SW_SHOW) for a not visible child window */
1476 static const struct message WmShowChildSeq[] = {
1477 { WM_SHOWWINDOW, sent|wparam, 1 },
1478 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1479 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1480 { WM_ERASEBKGND, sent|parent|optional },
1481 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1482 { 0 }
1484 /* ShowWindow(SW_HIDE) for a visible child window */
1485 static const struct message WmHideChildSeq[] = {
1486 { WM_SHOWWINDOW, sent|wparam, 0 },
1487 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1488 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1489 { WM_ERASEBKGND, sent|parent|optional },
1490 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1491 { 0 }
1493 /* ShowWindow(SW_HIDE) for a visible child window checking all parent events*/
1494 static const struct message WmHideChildSeq2[] = {
1495 { WM_SHOWWINDOW, sent|wparam, 0 },
1496 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1497 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1498 { WM_ERASEBKGND, sent|parent|optional },
1499 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1500 { 0 }
1502 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1503 * for a not visible child window
1505 static const struct message WmShowChildSeq_2[] = {
1506 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1507 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1508 { WM_CHILDACTIVATE, sent },
1509 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1510 { 0 }
1512 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
1513 * for a not visible child window
1515 static const struct message WmShowChildSeq_3[] = {
1516 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1517 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1518 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1519 { 0 }
1521 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1522 * for a visible child window with a caption
1524 static const struct message WmShowChildSeq_4[] = {
1525 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1526 { WM_CHILDACTIVATE, sent },
1527 { 0 }
1529 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
1530 static const struct message WmShowChildInvisibleParentSeq_1[] = {
1531 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1532 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1533 { WM_NCCALCSIZE, sent|wparam, 1 },
1534 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1535 { WM_CHILDACTIVATE, sent|optional },
1536 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1537 { WM_MOVE, sent|defwinproc },
1538 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1539 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1540 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1541 { WM_GETTEXT, sent|optional },
1542 { 0 }
1544 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
1545 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
1546 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1547 { 0 }
1549 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1550 static const struct message WmShowChildInvisibleParentSeq_2[] = {
1551 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1552 { WM_GETMINMAXINFO, sent },
1553 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
1554 { WM_NCCALCSIZE, sent|wparam, 1 },
1555 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1556 { WM_CHILDACTIVATE, sent },
1557 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1558 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1559 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1560 { 0 }
1562 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1563 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
1564 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1565 { 0 }
1567 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1568 static const struct message WmShowChildInvisibleParentSeq_3[] = {
1569 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1570 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1571 { WM_NCCALCSIZE, sent|wparam, 1 },
1572 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1573 { WM_CHILDACTIVATE, sent },
1574 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1575 { WM_MOVE, sent|defwinproc },
1576 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1577 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1578 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1579 { WM_GETTEXT, sent|optional },
1580 { 0 }
1582 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1583 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
1584 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1585 { 0 }
1587 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1588 static const struct message WmShowChildInvisibleParentSeq_4[] = {
1589 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1590 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
1591 { WM_NCCALCSIZE, sent|wparam, 1 },
1592 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1593 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1594 { WM_MOVE, sent|defwinproc },
1595 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1596 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1597 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1598 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1599 { WM_GETTEXT, sent|optional },
1600 { 0 }
1602 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1603 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
1604 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1605 { 0 }
1607 /* ShowWindow(SW_SHOW) for child with invisible parent */
1608 static const struct message WmShowChildInvisibleParentSeq_5[] = {
1609 { WM_SHOWWINDOW, sent|wparam, 1 },
1610 { 0 }
1612 /* ShowWindow(SW_HIDE) for child with invisible parent */
1613 static const struct message WmHideChildInvisibleParentSeq[] = {
1614 { WM_SHOWWINDOW, sent|wparam, 0 },
1615 { 0 }
1617 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
1618 static const struct message WmShowChildInvisibleParentSeq_6[] = {
1619 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1620 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1621 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1622 { 0 }
1624 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
1625 static const struct message WmHideChildInvisibleParentSeq_2[] = {
1626 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1627 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1628 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1629 { 0 }
1631 /* DestroyWindow for a visible child window */
1632 static const struct message WmDestroyChildSeq[] = {
1633 { HCBT_DESTROYWND, hook },
1634 { 0x0090, sent|optional },
1635 { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1636 { WM_SHOWWINDOW, sent|wparam, 0 },
1637 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1638 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1639 { WM_ERASEBKGND, sent|parent|optional },
1640 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1641 { HCBT_SETFOCUS, hook }, /* set focus to a parent */
1642 { WM_KILLFOCUS, sent },
1643 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1644 { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
1645 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1646 { WM_SETFOCUS, sent|parent },
1647 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
1648 { WM_DESTROY, sent },
1649 { WM_DESTROY, sent|optional }, /* some other (IME?) window */
1650 { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
1651 { WM_NCDESTROY, sent },
1652 { 0 }
1654 /* visible child window destroyed by thread exit */
1655 static const struct message WmExitThreadSeq[] = {
1656 { WM_NCDESTROY, sent }, /* actually in grandchild */
1657 { WM_PAINT, sent|parent },
1658 { WM_ERASEBKGND, sent|parent|beginpaint },
1659 { 0 }
1661 /* DestroyWindow for a visible child window with invisible parent */
1662 static const struct message WmDestroyInvisibleChildSeq[] = {
1663 { HCBT_DESTROYWND, hook },
1664 { 0x0090, sent|optional },
1665 { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1666 { WM_SHOWWINDOW, sent|wparam, 0 },
1667 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
1668 { WM_DESTROY, sent },
1669 { WM_NCDESTROY, sent },
1670 { 0 }
1672 /* Resizing child window with MoveWindow (32) */
1673 static const struct message WmResizingChildWithMoveWindowSeq[] = {
1674 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
1675 { WM_NCCALCSIZE, sent|wparam, 1 },
1676 { WM_ERASEBKGND, sent|parent|optional },
1677 { WM_ERASEBKGND, sent|optional },
1678 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
1679 { WM_MOVE, sent|defwinproc },
1680 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1681 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1682 { 0 }
1684 /* Creation of a custom dialog (32) */
1685 static const struct message WmCreateCustomDialogSeq[] = {
1686 { HCBT_CREATEWND, hook },
1687 { WM_GETMINMAXINFO, sent },
1688 { WM_NCCREATE, sent },
1689 { WM_NCCALCSIZE, sent|wparam, 0 },
1690 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win10. */
1691 { WM_CREATE, sent },
1692 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
1693 { WM_NOTIFYFORMAT, sent|optional },
1694 { WM_QUERYUISTATE, sent|optional },
1695 { WM_WINDOWPOSCHANGING, sent|optional },
1696 { WM_GETMINMAXINFO, sent|optional },
1697 { WM_NCCALCSIZE, sent|optional },
1698 { WM_WINDOWPOSCHANGED, sent|optional },
1699 { WM_SHOWWINDOW, sent|wparam, 1 },
1700 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1701 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1702 { HCBT_ACTIVATE, hook },
1703 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
1706 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1708 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1710 { WM_NCACTIVATE, sent },
1711 { WM_GETTEXT, sent|optional|defwinproc },
1712 { WM_GETTEXT, sent|optional|defwinproc },
1713 { WM_GETTEXT, sent|optional|defwinproc },
1714 { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1715 { WM_ACTIVATE, sent|wparam, 1 },
1716 { WM_GETTEXT, sent|optional },
1717 { WM_KILLFOCUS, sent|parent },
1718 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1719 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1720 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1721 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1722 { WM_SETFOCUS, sent },
1723 { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1724 { WM_NCPAINT, sent|wparam, 1 },
1725 { WM_GETTEXT, sent|optional|defwinproc },
1726 { WM_GETTEXT, sent|optional|defwinproc },
1727 { WM_ERASEBKGND, sent },
1728 { WM_CTLCOLORDLG, sent|optional|defwinproc },
1729 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1730 { WM_GETTEXT, sent|optional },
1731 { WM_GETTEXT, sent|optional },
1732 { WM_NCCALCSIZE, sent|optional },
1733 { WM_NCPAINT, sent|optional },
1734 { WM_GETTEXT, sent|optional|defwinproc },
1735 { WM_GETTEXT, sent|optional|defwinproc },
1736 { WM_ERASEBKGND, sent|optional },
1737 { WM_CTLCOLORDLG, sent|optional|defwinproc },
1738 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win10. */
1739 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1740 { WM_MOVE, sent },
1741 { 0 }
1743 /* Calling EndDialog for a custom dialog (32) */
1744 static const struct message WmEndCustomDialogSeq[] = {
1745 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1746 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1747 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1748 { WM_GETTEXT, sent|optional },
1749 { HCBT_ACTIVATE, hook },
1750 { WM_NCACTIVATE, sent|wparam, 0 },
1751 { WM_GETTEXT, sent|optional|defwinproc },
1752 { WM_GETTEXT, sent|optional|defwinproc },
1753 { WM_ACTIVATE, sent|wparam, 0 },
1754 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1755 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1756 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1757 { WM_GETTEXT, sent|optional|defwinproc },
1758 { WM_GETTEXT, sent|optional|defwinproc },
1759 { HCBT_SETFOCUS, hook },
1760 { WM_KILLFOCUS, sent },
1761 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1762 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1763 { WM_IME_NOTIFY, sent|wparam|optional, 1 },
1764 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1765 { WM_SETFOCUS, sent|parent|defwinproc },
1766 { 0 }
1768 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
1769 static const struct message WmShowCustomDialogSeq[] = {
1770 { WM_SHOWWINDOW, sent|wparam, 1 },
1771 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1772 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1773 { HCBT_ACTIVATE, hook },
1774 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
1776 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1778 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1779 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1780 { WM_NCACTIVATE, sent },
1781 { WM_ACTIVATE, sent|wparam, 1 },
1782 { WM_GETTEXT, sent|optional },
1784 { WM_KILLFOCUS, sent|parent },
1785 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1786 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1787 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1788 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1789 { WM_SETFOCUS, sent },
1790 { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1791 { WM_NCPAINT, sent|wparam, 1 },
1792 { WM_ERASEBKGND, sent },
1793 { WM_CTLCOLORDLG, sent|defwinproc },
1794 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1795 { 0 }
1797 /* Creation and destruction of a modal dialog (32) */
1798 static const struct message WmModalDialogSeq[] = {
1799 { WM_CANCELMODE, sent|parent },
1800 { HCBT_SETFOCUS, hook },
1801 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1802 { WM_KILLFOCUS, sent|parent },
1803 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1804 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
1805 { WM_ENABLE, sent|parent|wparam, 0 },
1806 { HCBT_CREATEWND, hook },
1807 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win10. */
1808 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
1809 { WM_SETFONT, sent },
1810 { WM_INITDIALOG, sent },
1811 { WM_CHANGEUISTATE, sent|optional },
1812 { WM_UPDATEUISTATE, sent|optional },
1813 { WM_SHOWWINDOW, sent },
1814 { HCBT_ACTIVATE, hook },
1815 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
1816 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1817 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1818 { WM_NCACTIVATE, sent },
1819 { WM_GETTEXT, sent|optional },
1820 { WM_ACTIVATE, sent|wparam, 1 },
1821 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1822 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1823 { WM_NCPAINT, sent|optional },
1824 { WM_GETTEXT, sent|optional },
1825 { WM_ERASEBKGND, sent|optional },
1826 { WM_CTLCOLORDLG, sent|optional },
1827 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1828 { WM_GETTEXT, sent|optional },
1829 { WM_NCCALCSIZE, sent|optional },
1830 { WM_NCPAINT, sent|optional },
1831 { WM_GETTEXT, sent|optional },
1832 { WM_ERASEBKGND, sent|optional },
1833 { WM_CTLCOLORDLG, sent|optional },
1834 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win10. */
1835 { WM_PAINT, sent|optional },
1836 { WM_CTLCOLORBTN, sent|optional },
1837 { WM_GETTITLEBARINFOEX, sent|optional },
1838 { WM_ENTERIDLE, sent|parent|optional },
1839 { WM_ENTERIDLE, sent|parent|optional },
1840 { WM_ENTERIDLE, sent|parent|optional },
1841 { WM_ENTERIDLE, sent|parent|optional },
1842 { WM_ENTERIDLE, sent|parent|optional },
1843 { WM_ENTERIDLE, sent|parent|optional },
1844 { WM_ENTERIDLE, sent|parent|optional },
1845 { WM_ENTERIDLE, sent|parent|optional },
1846 { WM_ENTERIDLE, sent|parent|optional },
1847 { WM_ENTERIDLE, sent|parent|optional },
1848 { WM_ENTERIDLE, sent|parent|optional },
1849 { WM_ENTERIDLE, sent|parent|optional },
1850 { WM_ENTERIDLE, sent|parent|optional },
1851 { WM_ENTERIDLE, sent|parent|optional },
1852 { WM_ENTERIDLE, sent|parent|optional },
1853 { WM_ENTERIDLE, sent|parent|optional },
1854 { WM_ENTERIDLE, sent|parent|optional },
1855 { WM_ENTERIDLE, sent|parent|optional },
1856 { WM_ENTERIDLE, sent|parent|optional },
1857 { WM_ENTERIDLE, sent|parent|optional },
1858 { WM_TIMER, sent },
1859 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
1860 { WM_ENABLE, sent|parent|wparam, 1 },
1861 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1862 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1863 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1864 { WM_GETTEXT, sent|optional },
1865 { HCBT_ACTIVATE, hook },
1866 { WM_NCACTIVATE, sent|wparam, 0 },
1867 { WM_GETTEXT, sent|optional },
1868 { WM_ACTIVATE, sent|wparam, 0 },
1869 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
1870 { WM_WINDOWPOSCHANGING, sent|optional },
1871 { WM_WINDOWPOSCHANGED, sent|optional },
1872 { HCBT_SETFOCUS, hook },
1873 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1874 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1875 { WM_SETFOCUS, sent|parent|defwinproc },
1876 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
1877 { HCBT_DESTROYWND, hook },
1878 { 0x0090, sent|optional },
1879 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
1880 { WM_DESTROY, sent },
1881 { WM_NCDESTROY, sent },
1882 { 0 }
1884 static const struct message WmModalDialogSeq_2[] = {
1885 { WM_CANCELMODE, sent },
1886 { HCBT_SETFOCUS, hook },
1887 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1888 { WM_KILLFOCUS, sent },
1889 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1890 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
1891 { WM_ENABLE, sent|wparam, 0 },
1892 { HCBT_CREATEWND, hook },
1893 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
1894 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
1895 { WM_SETFONT, sent },
1896 { WM_INITDIALOG, sent },
1897 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
1898 { WM_CHANGEUISTATE, sent|optional },
1899 { WM_UPDATEUISTATE, sent|optional },
1900 { WM_ENABLE, sent|wparam, 1 },
1901 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1902 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 },
1903 { WM_CHANGEUISTATE, sent|optional },
1904 { WM_UPDATEUISTATE, sent|optional },
1905 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
1906 { HCBT_DESTROYWND, hook },
1907 { 0x0090, sent|optional },
1908 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
1909 { WM_DESTROY, sent },
1910 { WM_NCDESTROY, sent },
1911 { 0 }
1913 /* SetMenu for NonVisible windows with size change*/
1914 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1915 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1916 { WM_NCCALCSIZE, sent|wparam, 1 },
1917 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
1918 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1919 { WM_MOVE, sent|defwinproc },
1920 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1921 { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1922 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1923 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1924 { WM_GETTEXT, sent|optional },
1925 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1926 { 0 }
1928 /* SetMenu for NonVisible windows with no size change */
1929 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1930 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1931 { WM_NCCALCSIZE, sent|wparam, 1 },
1932 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1933 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1934 { 0 }
1936 /* SetMenu for Visible windows with size change */
1937 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1938 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1939 { WM_NCCALCSIZE, sent|wparam, 1 },
1940 { 0x0093, sent|defwinproc|optional },
1941 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
1942 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1943 { 0x0093, sent|defwinproc|optional },
1944 { 0x0093, sent|defwinproc|optional },
1945 { 0x0091, sent|defwinproc|optional },
1946 { 0x0092, sent|defwinproc|optional },
1947 { WM_GETTEXT, sent|defwinproc|optional },
1948 { WM_ERASEBKGND, sent|optional },
1949 { WM_ACTIVATE, sent|optional },
1950 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1951 { WM_MOVE, sent|defwinproc },
1952 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1953 { 0x0093, sent|optional },
1954 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1955 { 0x0093, sent|defwinproc|optional },
1956 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1957 { 0x0093, sent|defwinproc|optional },
1958 { 0x0093, sent|defwinproc|optional },
1959 { 0x0091, sent|defwinproc|optional },
1960 { 0x0092, sent|defwinproc|optional },
1961 { WM_ERASEBKGND, sent|optional },
1962 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1963 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1964 { 0 }
1966 /* SetMenu for Visible windows with no size change */
1967 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1968 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1969 { WM_NCCALCSIZE, sent|wparam, 1 },
1970 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1971 { WM_GETTEXT, sent|defwinproc|optional },
1972 { WM_ERASEBKGND, sent|optional },
1973 { WM_ACTIVATE, sent|optional },
1974 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1975 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1976 { 0 }
1978 /* DrawMenuBar for a visible window */
1979 static const struct message WmDrawMenuBarSeq[] =
1981 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1982 { WM_NCCALCSIZE, sent|wparam, 1 },
1983 { 0x0093, sent|defwinproc|optional },
1984 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1985 { 0x0093, sent|defwinproc|optional },
1986 { 0x0093, sent|defwinproc|optional },
1987 { 0x0091, sent|defwinproc|optional },
1988 { 0x0092, sent|defwinproc|optional },
1989 { WM_GETTEXT, sent|defwinproc|optional },
1990 { WM_ERASEBKGND, sent|optional },
1991 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1992 { 0x0093, sent|optional },
1993 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1994 { 0 }
1997 static const struct message WmSetRedrawFalseSeq[] =
1999 { WM_SETREDRAW, sent|wparam, 0 },
2000 { 0 }
2003 static const struct message WmSetRedrawTrueSeq[] =
2005 { WM_SETREDRAW, sent|wparam, 1 },
2006 { 0 }
2009 static const struct message WmEnableWindowSeq_1[] =
2011 { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
2012 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2013 { HCBT_SETFOCUS, hook|optional },
2014 { WM_KILLFOCUS, sent|optional },
2015 { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
2016 { 0 }
2019 static const struct message WmEnableWindowSeq_2[] =
2021 { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
2022 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win10. */
2023 { 0 }
2026 static const struct message WmEnableWindowSeq_3[] =
2028 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2029 { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
2030 { 0 }
2033 static const struct message WmEnableWindowSeq_4[] =
2035 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win10. */
2036 { 0 }
2039 static const struct message WmGetScrollRangeSeq[] =
2041 { SBM_GETRANGE, sent },
2042 { 0 }
2044 static const struct message WmGetScrollInfoSeq[] =
2046 { SBM_GETSCROLLINFO, sent },
2047 { 0 }
2049 static const struct message WmSetScrollRangeSeq[] =
2051 /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
2052 sends SBM_SETSCROLLINFO.
2054 { SBM_SETSCROLLINFO, sent },
2055 { 0 }
2057 /* SetScrollRange for a window without a non-client area */
2058 static const struct message WmSetScrollRangeHSeq_empty[] =
2060 { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_HSCROLL, 0 },
2061 { 0 }
2063 static const struct message WmSetScrollRangeVSeq_empty[] =
2065 { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_VSCROLL, 0 },
2066 { 0 }
2068 static const struct message WmSetScrollRangeHVSeq[] =
2070 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
2071 { WM_NCCALCSIZE, sent|wparam, 1 },
2072 { WM_GETTEXT, sent|defwinproc|optional },
2073 { WM_ERASEBKGND, sent|optional },
2074 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2075 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2076 { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
2077 { 0 }
2079 /* SetScrollRange for a window with a non-client area */
2080 static const struct message WmSetScrollRangeHV_NC_Seq[] =
2082 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
2083 { WM_NCCALCSIZE, sent|wparam, 1 },
2084 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2085 { WM_NCPAINT, sent|optional },
2086 { WM_STYLECHANGING, sent|defwinproc|optional },
2087 { WM_STYLECHANGED, sent|defwinproc|optional },
2088 { WM_STYLECHANGING, sent|defwinproc|optional },
2089 { WM_STYLECHANGED, sent|defwinproc|optional },
2090 { WM_STYLECHANGING, sent|defwinproc|optional },
2091 { WM_STYLECHANGED, sent|defwinproc|optional },
2092 { WM_STYLECHANGING, sent|defwinproc|optional },
2093 { WM_STYLECHANGED, sent|defwinproc|optional },
2094 { WM_GETTEXT, sent|defwinproc|optional },
2095 { WM_GETTEXT, sent|defwinproc|optional },
2096 { WM_ERASEBKGND, sent|optional },
2097 { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
2098 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOCLIENTSIZE },
2099 { WM_SIZE, sent|defwinproc|optional },
2100 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2101 { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
2102 { WM_GETTEXT, sent|optional },
2103 { WM_GETTEXT, sent|optional },
2104 { WM_GETTEXT, sent|optional },
2105 { WM_GETTEXT, sent|optional },
2106 { 0 }
2108 /* test if we receive the right sequence of messages */
2109 /* after calling ShowWindow( SW_SHOWNA) */
2110 static const struct message WmSHOWNAChildInvisParInvis[] = {
2111 { WM_SHOWWINDOW, sent|wparam, 1 },
2112 { 0 }
2114 static const struct message WmSHOWNAChildVisParInvis[] = {
2115 { WM_SHOWWINDOW, sent|wparam, 1 },
2116 { 0 }
2118 static const struct message WmSHOWNAChildVisParVis[] = {
2119 { WM_SHOWWINDOW, sent|wparam, 1 },
2120 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
2121 { 0 }
2123 static const struct message WmSHOWNAChildInvisParVis[] = {
2124 { WM_SHOWWINDOW, sent|wparam, 1 },
2125 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2126 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2127 { WM_ERASEBKGND, sent|optional },
2128 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
2129 { 0 }
2131 static const struct message WmSHOWNATopVisible[] = {
2132 { WM_SHOWWINDOW, sent|wparam, 1 },
2133 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
2134 { WM_NCPAINT, sent|wparam|optional, 1 },
2135 { WM_GETTEXT, sent|defwinproc|optional },
2136 { WM_ERASEBKGND, sent|optional },
2137 { WM_WINDOWPOSCHANGED, sent|optional },
2138 { 0 }
2140 static const struct message WmSHOWNATopInvisible[] = {
2141 { WM_NOTIFYFORMAT, sent|optional },
2142 { WM_QUERYUISTATE, sent|optional },
2143 { WM_WINDOWPOSCHANGING, sent|optional },
2144 { WM_GETMINMAXINFO, sent|optional },
2145 { WM_NCCALCSIZE, sent|optional },
2146 { WM_WINDOWPOSCHANGED, sent|optional },
2147 { WM_SHOWWINDOW, sent|wparam, 1 },
2148 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2149 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2150 { WM_NCPAINT, sent|wparam|optional, 1 },
2151 { WM_GETTEXT, sent|defwinproc|optional },
2152 { WM_ERASEBKGND, sent|optional },
2153 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2154 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2155 { WM_NCPAINT, sent|wparam|optional, 1 },
2156 { WM_ERASEBKGND, sent|optional },
2157 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends it, but Win8+ doesn't. */
2158 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2159 { WM_MOVE, sent },
2160 { 0 }
2163 static const struct message WmTrackPopupMenuMinimizeWindow[] = {
2164 { HCBT_CREATEWND, hook },
2165 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2166 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
2167 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2168 { WM_INITMENU, sent|lparam, 0, 0 },
2169 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2170 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
2171 { 0x0093, sent|optional },
2172 { 0x0094, sent|optional },
2173 { 0x0094, sent|optional },
2174 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2175 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2176 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
2177 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
2178 { WM_ENTERIDLE, sent|wparam, 2 },
2179 { HCBT_MINMAX, hook },
2180 { HCBT_SETFOCUS, hook },
2181 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2182 { WM_KILLFOCUS, sent|wparam, 0 },
2183 { WM_GETTEXT, sent|optional },
2184 { WM_WINDOWPOSCHANGING, sent },
2185 { WM_GETMINMAXINFO, sent|defwinproc },
2186 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2187 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2188 { WM_WINDOWPOSCHANGED, sent },
2189 { WM_MOVE, sent|defwinproc },
2190 { WM_SIZE, sent|defwinproc },
2191 { WM_GETTEXT, sent|optional },
2192 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2193 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2194 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
2195 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2196 { WM_CANCELMODE, sent },
2197 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2198 { WM_CAPTURECHANGED, sent|defwinproc },
2199 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
2200 { HCBT_DESTROYWND, hook },
2201 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2202 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2203 { WM_UNINITMENUPOPUP, sent|defwinproc|lparam, 0, 0 },
2204 { WM_MENUSELECT, sent|defwinproc|wparam|lparam, 0xffff0000, 0 },
2205 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2206 { WM_EXITMENULOOP, sent|defwinproc|wparam|lparam, 1, 0 },
2207 { WM_NCACTIVATE, sent },
2208 { WM_GETTEXT, sent|defwinproc|optional },
2209 { WM_GETTEXT, sent|defwinproc|optional },
2210 { WM_ACTIVATE, sent },
2211 { WM_ACTIVATEAPP, sent|wparam, 0 },
2212 { 0 }
2215 static const struct message WmTrackPopupMenu[] = {
2216 { HCBT_CREATEWND, hook },
2217 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2218 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
2219 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2220 { WM_INITMENU, sent|lparam, 0, 0 },
2221 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2222 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
2223 { 0x0093, sent|optional },
2224 { 0x0094, sent|optional },
2225 { 0x0094, sent|optional },
2226 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2227 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2228 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
2229 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
2230 { WM_ENTERIDLE, sent|wparam, 2 },
2231 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2232 { WM_CAPTURECHANGED, sent },
2233 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
2234 { HCBT_DESTROYWND, hook },
2235 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2236 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2237 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
2238 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
2239 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2240 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
2241 { 0 }
2244 static const struct message WmTrackPopupMenuEsc[] = {
2245 { 0 }
2248 static const struct message WmTrackPopupMenuCapture[] = {
2249 { HCBT_CREATEWND, hook },
2250 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2251 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
2252 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2253 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2254 { WM_CAPTURECHANGED, sent },
2255 { WM_INITMENU, sent|lparam, 0, 0 },
2256 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2257 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
2258 { 0x0093, sent|optional },
2259 { 0x0094, sent|optional },
2260 { 0x0094, sent|optional },
2261 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2262 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2263 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
2264 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
2265 { WM_ENTERIDLE, sent|wparam, 2 },
2266 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2267 { WM_CAPTURECHANGED, sent },
2268 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
2269 { HCBT_DESTROYWND, hook },
2270 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2271 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2272 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
2273 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
2274 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2275 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
2276 { 0 }
2279 static const struct message WmTrackPopupMenuEmpty[] = {
2280 { HCBT_CREATEWND, hook },
2281 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2282 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
2283 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2284 { WM_INITMENU, sent|lparam, 0, 0 },
2285 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2286 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
2287 { 0x0093, sent|optional },
2288 { 0x0094, sent|optional },
2289 { 0x0094, sent|optional },
2290 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2291 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2292 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2293 { WM_CAPTURECHANGED, sent },
2294 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
2295 { HCBT_DESTROYWND, hook },
2296 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2297 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
2298 { 0 }
2301 static const struct message WmTrackPopupMenuAbort[] = {
2302 { HCBT_CREATEWND, hook },
2303 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2304 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
2305 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2306 { WM_INITMENU, sent|lparam, 0, 0 },
2307 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2308 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
2309 { 0x0093, sent|optional },
2310 { 0x0094, sent|optional },
2311 { 0x0094, sent|optional },
2312 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2313 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2314 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
2315 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
2316 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2317 { WM_CAPTURECHANGED, sent },
2318 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
2319 { HCBT_DESTROYWND, hook },
2320 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2321 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2322 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
2323 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
2324 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
2325 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
2326 { 0 }
2329 static BOOL after_end_dialog, test_def_id, paint_loop_done;
2330 static int sequence_cnt, sequence_size;
2331 static struct recvd_message* sequence;
2332 static int log_all_parent_messages;
2333 static CRITICAL_SECTION sequence_cs;
2335 /* user32 functions */
2336 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
2337 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
2338 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
2339 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
2340 static BOOL (WINAPI *pUpdateLayeredWindow)(HWND,HDC,POINT*,SIZE*,HDC,POINT*,COLORREF,BLENDFUNCTION*,DWORD);
2341 static UINT_PTR (WINAPI *pSetSystemTimer)(HWND, UINT_PTR, UINT, TIMERPROC);
2342 static UINT_PTR (WINAPI *pKillSystemTimer)(HWND, UINT_PTR);
2343 static UINT_PTR (WINAPI *pSetCoalescableTimer)(HWND, UINT_PTR, UINT, TIMERPROC, ULONG);
2344 /* kernel32 functions */
2345 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
2347 static void init_procs(void)
2349 HMODULE user32 = GetModuleHandleA("user32.dll");
2350 HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
2352 #define GET_PROC(dll, func) \
2353 p ## func = (void*)GetProcAddress(dll, #func); \
2354 if(!p ## func) { \
2355 trace("GetProcAddress(%s) failed\n", #func); \
2358 GET_PROC(user32, NotifyWinEvent)
2359 GET_PROC(user32, SetWinEventHook)
2360 GET_PROC(user32, TrackMouseEvent)
2361 GET_PROC(user32, UnhookWinEvent)
2362 GET_PROC(user32, UpdateLayeredWindow)
2363 GET_PROC(user32, SetSystemTimer)
2364 GET_PROC(user32, KillSystemTimer)
2365 GET_PROC(user32, SetCoalescableTimer)
2367 GET_PROC(kernel32, GetCPInfoExA)
2369 #undef GET_PROC
2372 static const char *get_winpos_flags(UINT flags)
2374 static char buffer[300];
2376 buffer[0] = 0;
2377 #define DUMP(flag) do { if (flags & flag) { strcat( buffer, "|" #flag ); flags &= ~flag; } } while(0)
2378 DUMP( SWP_SHOWWINDOW );
2379 DUMP( SWP_HIDEWINDOW );
2380 DUMP( SWP_NOACTIVATE );
2381 DUMP( SWP_FRAMECHANGED );
2382 DUMP( SWP_NOCOPYBITS );
2383 DUMP( SWP_NOOWNERZORDER );
2384 DUMP( SWP_NOSENDCHANGING );
2385 DUMP( SWP_DEFERERASE );
2386 DUMP( SWP_ASYNCWINDOWPOS );
2387 DUMP( SWP_NOZORDER );
2388 DUMP( SWP_NOREDRAW );
2389 DUMP( SWP_NOSIZE );
2390 DUMP( SWP_NOMOVE );
2391 DUMP( SWP_NOCLIENTSIZE );
2392 DUMP( SWP_NOCLIENTMOVE );
2393 if (flags) sprintf(buffer + strlen(buffer),"|0x%04x", flags);
2394 return buffer + 1;
2395 #undef DUMP
2398 static BOOL ignore_message( UINT message )
2400 /* these are always ignored */
2401 return (message >= 0xc000 ||
2402 message == WM_GETICON ||
2403 message == WM_GETOBJECT ||
2404 message == WM_TIMECHANGE ||
2405 message == WM_DISPLAYCHANGE ||
2406 message == WM_DEVICECHANGE ||
2407 message == WM_DWMNCRENDERINGCHANGED ||
2408 message == WM_WININICHANGE);
2411 static unsigned hash_Ly_W(const WCHAR *str)
2413 unsigned hash = 0;
2415 for (; *str; str++)
2416 hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u;
2418 return hash;
2421 static unsigned hash_Ly(const char *str)
2423 unsigned hash = 0;
2425 for (; *str; str++)
2426 hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u;
2428 return hash;
2431 #define add_message(msg) add_message_(__LINE__,msg);
2432 static void add_message_(int line, const struct recvd_message *msg)
2434 struct recvd_message *seq;
2436 EnterCriticalSection( &sequence_cs );
2437 if (!sequence)
2439 sequence_size = 10;
2440 sequence = malloc( sequence_size * sizeof(*sequence) );
2442 if (sequence_cnt == sequence_size)
2444 sequence_size *= 2;
2445 sequence = realloc( sequence, sequence_size * sizeof(*sequence) );
2448 seq = &sequence[sequence_cnt++];
2449 seq->hwnd = msg->hwnd;
2450 seq->message = msg->message;
2451 seq->flags = msg->flags;
2452 seq->wParam = msg->wParam;
2453 seq->lParam = msg->lParam;
2454 seq->line = line;
2455 seq->descr = msg->descr;
2456 seq->output[0] = 0;
2457 LeaveCriticalSection( &sequence_cs );
2459 if (msg->descr)
2461 if (msg->flags & hook)
2463 static const char * const CBT_code_name[10] =
2465 "HCBT_MOVESIZE",
2466 "HCBT_MINMAX",
2467 "HCBT_QS",
2468 "HCBT_CREATEWND",
2469 "HCBT_DESTROYWND",
2470 "HCBT_ACTIVATE",
2471 "HCBT_CLICKSKIPPED",
2472 "HCBT_KEYSKIPPED",
2473 "HCBT_SYSCOMMAND",
2474 "HCBT_SETFOCUS"
2476 const char *code_name = (msg->message <= HCBT_SETFOCUS) ? CBT_code_name[msg->message] : "Unknown";
2478 sprintf( seq->output, "%s: hook %d (%s) wp %08Ix lp %08Ix",
2479 msg->descr, msg->message, code_name, msg->wParam, msg->lParam );
2481 else if (msg->flags & winevent_hook)
2483 sprintf( seq->output, "%s: winevent %p %08x %08Ix %08Ix",
2484 msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
2486 else
2488 switch (msg->message)
2490 case WM_WINDOWPOSCHANGING:
2491 case WM_WINDOWPOSCHANGED:
2493 WINDOWPOS *winpos = (WINDOWPOS *)msg->lParam;
2495 sprintf( seq->output, "%s: %p WM_WINDOWPOS%s wp %08Ix lp %08Ix after %p x %d y %d cx %d cy %d flags %s",
2496 msg->descr, msg->hwnd,
2497 (msg->message == WM_WINDOWPOSCHANGING) ? "CHANGING" : "CHANGED",
2498 msg->wParam, msg->lParam, winpos->hwndInsertAfter,
2499 winpos->x, winpos->y, winpos->cx, winpos->cy,
2500 get_winpos_flags(winpos->flags) );
2502 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2503 * in the high word for internal purposes
2505 seq->wParam = winpos->flags & 0xffff;
2506 /* We are not interested in the flags that don't match under XP and Win9x */
2507 seq->wParam &= ~SWP_NOZORDER;
2508 seq->lParam = (!!winpos->cx) | ((!!winpos->cy) << 1)
2509 | ((!!winpos->x) << 2) | ((!!winpos->y) << 3);
2510 break;
2513 case WM_NCCALCSIZE:
2514 if (msg->wParam)
2516 NCCALCSIZE_PARAMS *p = (NCCALCSIZE_PARAMS *)msg->lParam;
2517 WINDOWPOS *winpos = p->lppos;
2519 sprintf(seq->output, "%s: %p WM_NCCALCSIZE: winpos->cx %u, winpos->cy %u",
2520 msg->descr, msg->hwnd, winpos->cx, winpos->cy);
2521 seq->lParam = (!!winpos->cx) | ((!!winpos->cy) << 1)
2522 | ((!!winpos->x) << 2) | ((!!winpos->y) << 3);
2524 else
2526 RECT *rect = (RECT*)msg->lParam;
2528 sprintf(seq->output, "%s: %p WM_NCCALCSIZE: %s",
2529 msg->descr, msg->hwnd, wine_dbgstr_rect(rect));
2530 seq->lParam = 0;
2532 break;
2533 case WM_DRAWITEM:
2535 DRAW_ITEM_STRUCT di;
2536 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)msg->lParam;
2538 sprintf( seq->output, "%s: %p WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x",
2539 msg->descr, msg->hwnd, dis->CtlType, dis->CtlID,
2540 dis->itemID, dis->itemAction, dis->itemState);
2542 di.u.lp = 0;
2543 di.u.item.type = dis->CtlType;
2544 di.u.item.ctl_id = dis->CtlID;
2545 if (dis->CtlType == ODT_LISTBOX ||
2546 dis->CtlType == ODT_COMBOBOX ||
2547 dis->CtlType == ODT_MENU)
2548 di.u.item.item_id = dis->itemID;
2549 di.u.item.action = dis->itemAction;
2550 di.u.item.state = dis->itemState;
2552 seq->lParam = di.u.lp;
2553 break;
2556 case WM_MEASUREITEM:
2558 MEASURE_ITEM_STRUCT mi;
2559 MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)msg->lParam;
2560 BOOL is_unicode_data = TRUE;
2562 sprintf( seq->output, "%s: %p WM_MEASUREITEM: CtlType %#x, CtlID %#x, itemID %#x, itemData %#Ix",
2563 msg->descr, msg->hwnd, mis->CtlType, mis->CtlID,
2564 mis->itemID, mis->itemData);
2566 if (mis->CtlType == ODT_LISTBOX)
2568 HWND ctrl = GetDlgItem(msg->hwnd, mis->CtlID);
2569 is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
2572 mi.u.wp = 0;
2573 mi.u.item.CtlType = mis->CtlType;
2574 mi.u.item.CtlID = mis->CtlID;
2575 mi.u.item.itemID = mis->itemID;
2576 mi.u.item.wParam = msg->wParam;
2577 seq->wParam = mi.u.wp;
2578 if (is_unicode_data)
2579 seq->lParam = mis->itemData ? hash_Ly_W((const WCHAR *)mis->itemData) : 0;
2580 else
2581 seq->lParam = mis->itemData ? hash_Ly((const char *)mis->itemData) : 0;
2582 break;
2585 case WM_COMPAREITEM:
2587 COMPAREITEMSTRUCT *cis = (COMPAREITEMSTRUCT *)msg->lParam;
2588 HWND ctrl = GetDlgItem(msg->hwnd, cis->CtlID);
2589 BOOL is_unicode_data = TRUE;
2591 ok(msg->wParam == cis->CtlID, "expected %#x, got %#Ix\n", cis->CtlID, msg->wParam);
2592 ok(cis->hwndItem == ctrl, "expected %p, got %p\n", ctrl, cis->hwndItem);
2593 ok((int)cis->itemID1 >= 0, "expected >= 0, got %d\n", cis->itemID1);
2594 ok((int)cis->itemID2 == -1, "expected -1, got %d\n", cis->itemID2);
2596 sprintf( seq->output, "%s: %p WM_COMPAREITEM: CtlType %#x, CtlID %#x, itemID1 %#x, itemData1 %#Ix, itemID2 %#x, itemData2 %#Ix",
2597 msg->descr, msg->hwnd, cis->CtlType, cis->CtlID,
2598 cis->itemID1, cis->itemData1, cis->itemID2, cis->itemData2);
2600 if (cis->CtlType == ODT_LISTBOX)
2601 is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
2603 if (is_unicode_data)
2605 seq->wParam = cis->itemData1 ? hash_Ly_W((const WCHAR *)cis->itemData1) : 0;
2606 seq->lParam = cis->itemData2 ? hash_Ly_W((const WCHAR *)cis->itemData2) : 0;
2608 else
2610 seq->wParam = cis->itemData1 ? hash_Ly((const char *)cis->itemData1) : 0;
2611 seq->lParam = cis->itemData2 ? hash_Ly((const char *)cis->itemData2) : 0;
2613 break;
2616 default:
2617 if (msg->message >= 0xc000) return; /* ignore registered messages */
2618 sprintf( seq->output, "%s: %p %04x wp %08Ix lp %08Ix",
2619 msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
2621 if (msg->flags & (sent|posted|parent|defwinproc|beginpaint))
2622 sprintf( seq->output + strlen(seq->output), " (flags %x)", msg->flags );
2627 /* try to make sure pending X events have been processed before continuing */
2628 static void flush_events(void)
2630 MSG msg;
2631 int diff = 200;
2632 int min_timeout = 100;
2633 DWORD time = GetTickCount() + diff;
2635 while (diff > 0)
2637 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
2638 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
2639 diff = time - GetTickCount();
2643 static void flush_sequence(void)
2645 EnterCriticalSection( &sequence_cs );
2646 free( sequence );
2647 sequence = 0;
2648 sequence_cnt = sequence_size = 0;
2649 LeaveCriticalSection( &sequence_cs );
2652 static const char* message_type_name(int flags) {
2653 if (flags & hook) return "hook";
2654 if (flags & kbd_hook) return "kbd_hook";
2655 if (flags & winevent_hook) return "winevent_hook";
2656 return "msg";
2659 static BOOL can_skip_message(const struct message *expected)
2661 if (expected->flags & optional) return TRUE;
2663 if ((expected->flags & winevent_hook) && !hEvent_hook) return TRUE;
2664 if ((expected->flags & kbd_hook) && !hKBD_hook) return TRUE;
2665 if ((expected->flags & hook) && !hCBT_hook) return TRUE;
2667 if ((expected->flags & msg_todo) && !strcmp(winetest_platform, "wine")) return TRUE;
2669 if ((expected->flags & wine_only) && strcmp(winetest_platform, "wine")) return TRUE;
2671 return FALSE;
2674 static BOOL messages_equal(const struct message *expected, const struct recvd_message *actual,
2675 BOOL expect_equal, const char* file, int line)
2677 int todo = (expected->flags & msg_todo) != 0;
2678 int msg_wine_only = (expected->flags & wine_only) != 0;
2679 const int message_type_flags = hook|winevent_hook|kbd_hook;
2680 static int todo_reported;
2682 if (!todo && can_skip_message(expected))
2683 expect_equal = FALSE;
2685 if (msg_wine_only && strcmp(winetest_platform, "wine"))
2687 /* Ignore Wine-only message records on Windows. */
2688 return FALSE;
2691 if (!expected->message || !actual->message) {
2692 if (expect_equal && (!todo || !todo_reported++))
2693 todo_wine_if(todo || msg_wine_only)
2694 ok_( file, line) (msg_wine_only, "the msg sequence is not complete: expected %s %04x - actual %s %04x\n",
2695 message_type_name(expected->flags), expected->message, message_type_name(actual->flags), actual->message);
2696 return FALSE;
2699 if (expected->message != actual->message ||
2700 (expected->flags & message_type_flags) != (actual->flags & message_type_flags))
2702 if (expect_equal && (!todo || !todo_reported++))
2703 todo_wine_if(todo || msg_wine_only)
2704 ok_( file, line) (msg_wine_only, "the %s 0x%04x was expected, but got %s 0x%04x instead\n",
2705 message_type_name(expected->flags), expected->message, message_type_name(actual->flags), actual->message);
2706 return FALSE;
2709 if (expected->flags & optional)
2711 /* If a message can be sent in 2 different ways at the same time, we may need to treat
2712 * them as unequal so that the optional message can be properly skipped. */
2713 if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) {
2714 /* don't match messages if their defwinproc status differs */
2715 return FALSE;
2719 if (expect_equal)
2720 todo_wine_if(todo || msg_wine_only)
2721 ok_( file, line) (!msg_wine_only, "got %s 0x%04x as expected\n",
2722 message_type_name(expected->flags), expected->message);
2724 return TRUE;
2727 static BOOL sequence_contains_message(const struct message *expected, const struct recvd_message *actual)
2729 while (expected->message)
2731 if (messages_equal(expected, actual, FALSE, __FILE__, __LINE__))
2732 return TRUE;
2733 expected++;
2735 return FALSE;
2738 static void dump_sequence(const struct message *expected, const char *context, const char *file, int line)
2740 const struct recvd_message *actual = sequence;
2741 unsigned int count = 0;
2743 trace_(file, line)("Failed sequence %s:\n", context );
2744 while (expected->message && actual->message)
2746 if (actual->output[0])
2748 trace_(file, line)( " %u: expected: %s %04x - actual: %s\n",
2749 count, message_type_name(expected->flags), expected->message, actual->output );
2752 if (messages_equal(expected, actual, FALSE, file, line))
2754 expected++;
2755 actual++;
2756 count++;
2758 else if (can_skip_message(expected) || sequence_contains_message(expected, actual))
2760 expected++;
2761 count++;
2763 else
2765 actual++;
2769 /* optional trailing messages */
2770 while (can_skip_message(expected))
2772 trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2773 expected++;
2774 count++;
2777 if (expected->message)
2779 trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2780 return;
2783 while (actual->message && actual->output[0])
2785 trace_(file, line)( " %u: expected: nothing - actual: %s\n", count, actual->output );
2786 actual++;
2787 count++;
2791 #define ok_sequence( exp, contx, todo) \
2792 ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
2795 static void ok_sequence_(const struct message *expected_list, const char *context, BOOL todo,
2796 const char *file, int line)
2798 static const struct recvd_message end_of_sequence;
2799 const struct message *expected = expected_list;
2800 const struct recvd_message *actual;
2801 int failcount = 0, dump = 0;
2802 unsigned int count = 0;
2803 BOOL is_wine = !strcmp(winetest_platform, "wine");
2805 add_message(&end_of_sequence);
2807 actual = sequence;
2809 winetest_push_context("%s: %u", context, count);
2811 while (expected->message && actual->message)
2813 if (messages_equal(expected, actual, !todo, file, line))
2815 if (expected->flags & wparam)
2817 if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && todo)
2819 todo_wine {
2820 failcount ++;
2821 dump++;
2822 ok_( file, line) (FALSE,
2823 "in msg 0x%04x expecting wParam 0x%Ix got 0x%Ix\n",
2824 expected->message, expected->wParam, actual->wParam);
2826 if (is_wine) goto done;
2828 else
2830 ok_( file, line)( ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) == 0,
2831 "in msg 0x%04x expecting wParam 0x%Ix got 0x%Ix\n",
2832 expected->message, expected->wParam, actual->wParam);
2833 if ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) dump++;
2837 if (expected->flags & lparam)
2839 if (((expected->lParam ^ actual->lParam) & ~expected->lp_mask) && todo)
2841 todo_wine {
2842 failcount ++;
2843 dump++;
2844 ok_( file, line) (FALSE,
2845 "in msg 0x%04x expecting lParam 0x%Ix got 0x%Ix\n",
2846 expected->message, expected->lParam, actual->lParam);
2848 if (is_wine) goto done;
2850 else
2852 ok_( file, line)(((expected->lParam ^ actual->lParam) & ~expected->lp_mask) == 0,
2853 "in msg 0x%04x expecting lParam 0x%Ix got 0x%Ix\n",
2854 expected->message, expected->lParam, actual->lParam);
2855 if ((expected->lParam ^ actual->lParam) & ~expected->lp_mask) dump++;
2858 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
2860 todo_wine {
2861 failcount ++;
2862 dump++;
2863 ok_( file, line) (FALSE,
2864 "the msg 0x%04x should %shave been sent by DefWindowProc\n",
2865 expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2867 if (is_wine) goto done;
2869 else
2871 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
2872 "the msg 0x%04x should %shave been sent by DefWindowProc\n",
2873 expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2874 if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++;
2877 ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
2878 "the msg 0x%04x should %shave been sent by BeginPaint\n",
2879 expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
2880 if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++;
2882 ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
2883 "the msg 0x%04x should have been %s\n",
2884 expected->message, (expected->flags & posted) ? "posted" : "sent");
2885 if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++;
2887 ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
2888 "the msg 0x%04x was expected in %s\n",
2889 expected->message, (expected->flags & parent) ? "parent" : "child");
2890 if ((expected->flags & parent) != (actual->flags & parent)) dump++;
2892 expected++;
2893 count++;
2894 actual++;
2897 * silently drop hook messages if there is no support for them
2899 else if (can_skip_message(expected))
2901 expected++;
2902 count++;
2904 else if (todo)
2906 todo_wine messages_equal(expected, actual, TRUE, file, line);
2907 failcount++;
2908 dump++;
2909 goto done;
2911 else if (sequence_contains_message(expected, actual))
2913 dump++;
2914 expected++;
2915 count++;
2917 else
2919 dump++;
2920 actual++;
2923 winetest_pop_context();
2924 winetest_push_context("%s: %u", context, count);
2927 /* skip all optional trailing messages */
2928 while (can_skip_message(expected))
2930 messages_equal(expected, actual, TRUE, file, line); /* check for message todo's */
2931 expected++;
2934 if (todo)
2936 todo_wine {
2937 if (expected->message || actual->message) {
2938 failcount++;
2939 dump++;
2940 messages_equal(expected, actual, TRUE, file, line);
2943 if (is_wine && !failcount) /* succeeded yet marked todo */
2944 todo_wine {
2945 dump++;
2946 ok_( file, line)( TRUE, "marked \"todo_wine\" but succeeds\n");
2949 else
2951 if (expected->message || actual->message)
2953 dump++;
2954 messages_equal(expected, actual, TRUE, file, line);
2958 done:
2959 winetest_pop_context();
2960 if (dump && (!is_wine || winetest_debug > 1)) dump_sequence(expected_list, context, file, line);
2961 flush_sequence();
2964 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %ld\n", (EXPECTED), (GOT))
2966 /******************************** MDI test **********************************/
2968 /* CreateWindow for MDI frame window, initially visible */
2969 static const struct message WmCreateMDIframeSeq[] = {
2970 { HCBT_CREATEWND, hook },
2971 { WM_GETMINMAXINFO, sent },
2972 { WM_NCCREATE, sent },
2973 { WM_NCCALCSIZE, sent|wparam, 0 },
2974 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win8+. */
2975 { WM_CREATE, sent },
2976 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2977 { WM_NOTIFYFORMAT, sent|optional },
2978 { WM_QUERYUISTATE, sent|optional },
2979 { WM_WINDOWPOSCHANGING, sent|optional },
2980 { WM_GETMINMAXINFO, sent|optional },
2981 { WM_NCCALCSIZE, sent|optional },
2982 { WM_WINDOWPOSCHANGED, sent|optional },
2983 { WM_SHOWWINDOW, sent|wparam, 1 },
2984 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2985 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2986 { HCBT_ACTIVATE, hook },
2987 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
2988 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
2989 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
2990 { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
2991 { WM_NCACTIVATE, sent },
2992 { WM_GETTEXT, sent|defwinproc|optional },
2993 { WM_ACTIVATE, sent|wparam, 1 },
2994 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
2995 { HCBT_SETFOCUS, hook },
2996 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2997 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2998 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2999 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
3000 /* Win9x adds SWP_NOZORDER below */
3001 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3002 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
3003 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win8+. */
3004 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3005 { WM_MOVE, sent },
3006 { 0 }
3008 /* DestroyWindow for MDI frame window, initially visible */
3009 static const struct message WmDestroyMDIframeSeq[] = {
3010 { HCBT_DESTROYWND, hook },
3011 { 0x0090, sent|optional },
3012 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3013 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3014 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
3015 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3016 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
3017 { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
3018 { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
3019 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 },
3020 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
3021 { WM_DESTROY, sent },
3022 { WM_NCDESTROY, sent },
3023 { 0 }
3025 /* CreateWindow for MDI client window, initially visible */
3026 static const struct message WmCreateMDIclientSeq[] = {
3027 { HCBT_CREATEWND, hook },
3028 { WM_NCCREATE, sent },
3029 { WM_NCCALCSIZE, sent|wparam, 0 },
3030 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
3031 { WM_CREATE, sent },
3032 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
3033 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3034 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3035 { WM_MOVE, sent },
3036 { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
3037 { WM_SHOWWINDOW, sent|wparam, 1 },
3038 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3039 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3040 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3041 { 0 }
3043 /* ShowWindow(SW_SHOW) for MDI client window */
3044 static const struct message WmShowMDIclientSeq[] = {
3045 { WM_SHOWWINDOW, sent|wparam, 1 },
3046 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3047 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3048 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3049 { 0 }
3051 /* ShowWindow(SW_HIDE) for MDI client window */
3052 static const struct message WmHideMDIclientSeq[] = {
3053 { WM_SHOWWINDOW, sent|wparam, 0 },
3054 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3055 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
3056 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
3057 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3058 { 0 }
3060 /* DestroyWindow for MDI client window, initially visible */
3061 static const struct message WmDestroyMDIclientSeq[] = {
3062 { HCBT_DESTROYWND, hook },
3063 { 0x0090, sent|optional },
3064 { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
3065 { WM_SHOWWINDOW, sent|wparam, 0 },
3066 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3067 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3068 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3069 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
3070 { WM_DESTROY, sent },
3071 { WM_NCDESTROY, sent },
3072 { 0 }
3074 /* CreateWindow for MDI child window, initially visible */
3075 static const struct message WmCreateMDIchildVisibleSeq[] = {
3076 { HCBT_CREATEWND, hook },
3077 { WM_NCCREATE, sent },
3078 { WM_NCCALCSIZE, sent|wparam, 0 },
3079 { WM_CREATE, sent },
3080 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3081 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3082 { WM_MOVE, sent },
3083 /* Win2k sends wparam set to
3084 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3085 * while Win9x doesn't bother to set child window id according to
3086 * CLIENTCREATESTRUCT.idFirstChild
3088 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3089 { WM_SHOWWINDOW, sent|wparam, 1 },
3090 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3091 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3092 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3093 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
3094 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3095 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3096 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3098 /* Win9x: message sequence terminates here. */
3100 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3101 { HCBT_SETFOCUS, hook }, /* in MDI client */
3102 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3103 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
3104 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3105 { WM_SETFOCUS, sent }, /* in MDI client */
3106 { HCBT_SETFOCUS, hook },
3107 { WM_KILLFOCUS, sent }, /* in MDI client */
3108 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3109 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3110 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3111 { WM_SETFOCUS, sent|defwinproc },
3112 { WM_MDIACTIVATE, sent|defwinproc },
3113 { 0 }
3115 /* WM_CHILDACTIVATE sent to disabled window */
3116 static const struct message WmChildActivateDisabledWindowSeq[] = {
3117 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3118 { 0 }
3120 /* WM_CHILDACTIVATE sent to enabled window */
3121 static const struct message WmChildActivateWindowSeq[] = {
3122 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3123 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 },
3124 { WM_MDIACTIVATE, sent|defwinproc },
3125 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3126 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
3127 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3128 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3129 { HCBT_SETFOCUS, hook },
3130 { WM_KILLFOCUS, sent|defwinproc },
3131 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3132 { WM_SETFOCUS, sent },
3133 { HCBT_SETFOCUS, hook },
3134 { WM_KILLFOCUS, sent },
3135 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3136 { WM_SETFOCUS, sent|defwinproc },
3137 { WM_MDIACTIVATE, sent|defwinproc },
3138 { 0 }
3140 /* CreateWindow for MDI child window with invisible parent */
3141 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
3142 { HCBT_CREATEWND, hook },
3143 { WM_GETMINMAXINFO, sent },
3144 { WM_NCCREATE, sent },
3145 { WM_NCCALCSIZE, sent|wparam, 0 },
3146 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
3147 { WM_CREATE, sent },
3148 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3149 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3150 { WM_MOVE, sent },
3151 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3152 { WM_SHOWWINDOW, sent|wparam, 1 },
3153 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
3154 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3155 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3156 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3158 /* Win9x: message sequence terminates here. */
3160 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3161 { HCBT_SETFOCUS, hook }, /* in MDI client */
3162 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3163 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
3164 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3165 { WM_SETFOCUS, sent }, /* in MDI client */
3166 { HCBT_SETFOCUS, hook },
3167 { WM_KILLFOCUS, sent }, /* in MDI client */
3168 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3169 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3170 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3171 { WM_SETFOCUS, sent|defwinproc },
3172 { WM_MDIACTIVATE, sent|defwinproc },
3173 { 0 }
3175 /* DestroyWindow for MDI child window, initially visible */
3176 static const struct message WmDestroyMDIchildVisibleSeq[] = {
3177 { HCBT_DESTROYWND, hook },
3178 /* Win2k sends wparam set to
3179 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3180 * while Win9x doesn't bother to set child window id according to
3181 * CLIENTCREATESTRUCT.idFirstChild
3183 { 0x0090, sent|optional },
3184 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3185 { WM_SHOWWINDOW, sent|wparam, 0 },
3186 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3187 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3188 { WM_ERASEBKGND, sent|parent|optional },
3189 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3191 /* { WM_DESTROY, sent }
3192 * Win9x: message sequence terminates here.
3195 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
3196 { WM_KILLFOCUS, sent },
3197 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3198 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3199 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3200 { WM_SETFOCUS, sent }, /* in MDI client */
3202 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
3203 { WM_KILLFOCUS, sent }, /* in MDI client */
3204 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3205 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3206 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3207 { WM_SETFOCUS, sent }, /* in MDI client */
3209 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
3211 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
3212 { WM_KILLFOCUS, sent },
3213 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3214 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3215 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3216 { WM_SETFOCUS, sent }, /* in MDI client */
3218 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
3219 { WM_KILLFOCUS, sent }, /* in MDI client */
3220 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3221 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3222 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3223 { WM_SETFOCUS, sent }, /* in MDI client */
3225 { WM_DESTROY, sent },
3227 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
3228 { WM_KILLFOCUS, sent },
3229 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3230 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3231 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3232 { WM_SETFOCUS, sent }, /* in MDI client */
3234 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
3235 { WM_KILLFOCUS, sent }, /* in MDI client */
3236 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3237 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3238 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3239 { WM_SETFOCUS, sent }, /* in MDI client */
3241 { WM_NCDESTROY, sent },
3242 { 0 }
3244 /* CreateWindow for MDI child window, initially invisible */
3245 static const struct message WmCreateMDIchildInvisibleSeq[] = {
3246 { HCBT_CREATEWND, hook },
3247 { WM_NCCREATE, sent },
3248 { WM_NCCALCSIZE, sent|wparam, 0 },
3249 { WM_CREATE, sent },
3250 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3251 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3252 { WM_MOVE, sent },
3253 /* Win2k sends wparam set to
3254 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3255 * while Win9x doesn't bother to set child window id according to
3256 * CLIENTCREATESTRUCT.idFirstChild
3258 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3259 { 0 }
3261 /* DestroyWindow for MDI child window, initially invisible */
3262 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
3263 { HCBT_DESTROYWND, hook },
3264 /* Win2k sends wparam set to
3265 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3266 * while Win9x doesn't bother to set child window id according to
3267 * CLIENTCREATESTRUCT.idFirstChild
3269 { 0x0090, sent|optional },
3270 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3271 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
3272 { WM_DESTROY, sent },
3273 { WM_NCDESTROY, sent },
3274 { 0 }
3276 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
3277 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
3278 { HCBT_CREATEWND, hook },
3279 { WM_NCCREATE, sent },
3280 { WM_NCCALCSIZE, sent|wparam, 0 },
3281 { WM_CREATE, sent },
3282 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
3283 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3284 { WM_MOVE, sent },
3285 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3286 { WM_GETMINMAXINFO, sent },
3287 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3288 { WM_NCCALCSIZE, sent|wparam, 1 },
3289 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3290 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3291 /* in MDI frame */
3292 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3293 { WM_NCCALCSIZE, sent|wparam, 1 },
3294 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3295 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI frame */
3296 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI child */
3297 /* Win2k sends wparam set to
3298 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3299 * while Win9x doesn't bother to set child window id according to
3300 * CLIENTCREATESTRUCT.idFirstChild
3302 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3303 { WM_SHOWWINDOW, sent|wparam, 1 },
3304 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3305 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3306 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3307 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
3308 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3309 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3310 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_FRAMECHANGED },
3312 /* Win9x: message sequence terminates here. */
3314 { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
3315 { HCBT_SETFOCUS, hook|optional }, /* in MDI client */
3316 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3317 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
3318 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3319 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3320 { HCBT_SETFOCUS, hook|optional },
3321 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3322 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3323 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3324 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3325 { WM_SETFOCUS, sent|defwinproc|optional },
3326 { WM_MDIACTIVATE, sent|defwinproc|optional },
3327 /* in MDI frame */
3328 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3329 { WM_NCCALCSIZE, sent|wparam, 1 },
3330 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3331 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI frame */
3332 { 0 }
3334 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
3335 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
3336 /* restore the 1st MDI child */
3337 { WM_SETREDRAW, sent|wparam, 0 },
3338 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
3339 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3340 { WM_NCCALCSIZE, sent|wparam, 1 },
3341 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3342 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3343 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3344 /* in MDI frame */
3345 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3346 { WM_NCCALCSIZE, sent|wparam, 1 },
3347 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3348 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI frame */
3349 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI child */
3350 { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
3351 /* create the 2nd MDI child */
3352 { HCBT_CREATEWND, hook },
3353 { WM_NCCREATE, sent },
3354 { WM_NCCALCSIZE, sent|wparam, 0 },
3355 { WM_CREATE, sent },
3356 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
3357 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3358 { WM_MOVE, sent },
3359 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3360 { WM_GETMINMAXINFO, sent },
3361 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3362 { WM_NCCALCSIZE, sent|wparam, 1 },
3363 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
3364 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3365 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3366 /* in MDI frame */
3367 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3368 { WM_NCCALCSIZE, sent|wparam, 1 },
3369 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3370 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI frame */
3371 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI child */
3372 /* Win2k sends wparam set to
3373 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3374 * while Win9x doesn't bother to set child window id according to
3375 * CLIENTCREATESTRUCT.idFirstChild
3377 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3378 { WM_SHOWWINDOW, sent|wparam, 1 },
3379 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3380 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3381 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3382 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
3383 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3384 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3386 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
3387 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
3389 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3391 /* Win9x: message sequence terminates here. */
3393 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3394 { HCBT_SETFOCUS, hook },
3395 { WM_KILLFOCUS, sent|defwinproc|optional }, /* in the 1st MDI child */
3396 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
3397 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3398 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3399 { WM_SETFOCUS, sent }, /* in MDI client */
3400 { HCBT_SETFOCUS, hook },
3401 { WM_KILLFOCUS, sent }, /* in MDI client */
3402 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3403 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3404 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3405 { WM_SETFOCUS, sent|defwinproc },
3407 { WM_MDIACTIVATE, sent|defwinproc },
3408 /* in MDI frame */
3409 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3410 { WM_NCCALCSIZE, sent|wparam, 1 },
3411 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3412 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI frame */
3413 { 0 }
3415 /* WM_MDICREATE MDI child window, initially visible and maximized */
3416 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
3417 { WM_MDICREATE, sent },
3418 { HCBT_CREATEWND, hook },
3419 { WM_NCCREATE, sent },
3420 { WM_NCCALCSIZE, sent|wparam, 0 },
3421 { WM_CREATE, sent },
3422 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
3423 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3424 { WM_MOVE, sent },
3425 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3426 { WM_GETMINMAXINFO, sent },
3427 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3428 { WM_NCCALCSIZE, sent|wparam, 1 },
3429 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3430 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3432 /* in MDI frame */
3433 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3434 { WM_NCCALCSIZE, sent|wparam, 1 },
3435 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3436 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI frame */
3437 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI child */
3439 /* Win2k sends wparam set to
3440 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3441 * while Win9x doesn't bother to set child window id according to
3442 * CLIENTCREATESTRUCT.idFirstChild
3444 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3445 { WM_SHOWWINDOW, sent|wparam, 1 },
3446 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3448 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3450 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3451 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
3452 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3454 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3455 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3457 /* Win9x: message sequence terminates here. */
3459 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3460 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3461 { HCBT_SETFOCUS, hook }, /* in MDI client */
3462 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3463 { WM_IME_NOTIFY, sent|wparam|optional, 2 },
3464 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
3465 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3466 { HCBT_SETFOCUS, hook|optional },
3467 { WM_KILLFOCUS, sent }, /* in MDI client */
3468 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3469 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3470 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3471 { WM_SETFOCUS, sent|defwinproc },
3473 { WM_MDIACTIVATE, sent|defwinproc },
3475 /* in MDI child */
3476 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3477 { WM_NCCALCSIZE, sent|wparam, 1 },
3478 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3479 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
3481 /* in MDI frame */
3482 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3483 { WM_NCCALCSIZE, sent|wparam, 1 },
3484 { 0x0093, sent|defwinproc|optional },
3485 { 0x0093, sent|defwinproc|optional },
3486 { 0x0093, sent|defwinproc|optional },
3487 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3488 { WM_MOVE, sent|defwinproc },
3489 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3491 /* in MDI client */
3492 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3493 { WM_NCCALCSIZE, sent|wparam, 1 },
3494 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3495 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3497 /* in MDI child */
3498 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3499 { WM_NCCALCSIZE, sent|wparam, 1 },
3500 { 0x0093, sent|optional },
3501 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3502 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3504 { 0x0093, sent|optional },
3505 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI child */
3506 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client, not sent on Win7. */
3507 { 0x0093, sent|optional }, /* Win8+ sends an extra. */
3508 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
3509 { 0x0093, sent|defwinproc|optional },
3510 { 0x0093, sent|defwinproc|optional },
3511 { 0x0093, sent|defwinproc|optional },
3512 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI frame */
3513 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
3515 { 0 }
3517 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
3518 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
3519 { HCBT_CREATEWND, hook },
3520 { WM_GETMINMAXINFO, sent },
3521 { WM_NCCREATE, sent },
3522 { WM_NCCALCSIZE, sent|wparam, 0 },
3523 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win8+. */
3524 { WM_CREATE, sent },
3525 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3526 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3527 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOZORDER }, /* MDI frame */
3528 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI frame */
3529 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOZORDER }, /* MDI frame */
3530 { WM_MOVE, sent },
3531 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3532 { WM_GETMINMAXINFO, sent },
3533 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3534 { WM_GETMINMAXINFO, sent|defwinproc },
3535 { WM_NCCALCSIZE, sent|wparam, 1 },
3536 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_STATECHANGED },
3537 { WM_MOVE, sent|defwinproc },
3538 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3539 /* in MDI frame */
3540 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3541 { WM_NCCALCSIZE, sent|wparam, 1 },
3542 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3543 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3544 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
3545 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3546 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI child */
3547 /* Win2k sends wparam set to
3548 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3549 * while Win9x doesn't bother to set child window id according to
3550 * CLIENTCREATESTRUCT.idFirstChild
3552 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3553 { 0 }
3555 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
3556 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
3557 { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
3558 { HCBT_SYSCOMMAND, hook },
3559 { WM_CLOSE, sent|defwinproc },
3560 { WM_MDIDESTROY, sent }, /* in MDI client */
3562 /* bring the 1st MDI child to top */
3563 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
3564 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
3566 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
3568 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
3569 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
3570 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
3572 /* maximize the 1st MDI child */
3573 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3574 { WM_GETMINMAXINFO, sent|defwinproc },
3575 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED },
3576 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
3577 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
3578 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3579 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3581 /* restore the 2nd MDI child */
3582 { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
3583 { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
3584 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
3585 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
3587 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3589 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3590 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3592 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI frame */
3594 { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
3595 /* in MDI frame */
3596 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3597 { WM_NCCALCSIZE, sent|wparam, 1 },
3598 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3599 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI frame */
3600 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI child */
3602 /* bring the 1st MDI child to top */
3603 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3604 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3605 { HCBT_SETFOCUS, hook },
3606 { WM_KILLFOCUS, sent|defwinproc },
3607 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
3608 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3609 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3610 { WM_SETFOCUS, sent }, /* in MDI client */
3611 { HCBT_SETFOCUS, hook },
3612 { WM_KILLFOCUS, sent }, /* in MDI client */
3613 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3614 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3615 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3616 { WM_SETFOCUS, sent|defwinproc },
3617 { WM_MDIACTIVATE, sent|defwinproc },
3618 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3620 /* apparently ShowWindow(SW_SHOW) on an MDI client */
3621 { WM_SHOWWINDOW, sent|wparam, 1 },
3622 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3623 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3624 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3625 { WM_MDIREFRESHMENU, sent },
3627 { HCBT_DESTROYWND, hook },
3628 /* Win2k sends wparam set to
3629 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3630 * while Win9x doesn't bother to set child window id according to
3631 * CLIENTCREATESTRUCT.idFirstChild
3633 { 0x0090, sent|defwinproc|optional },
3634 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3635 { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
3636 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3637 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3638 { WM_ERASEBKGND, sent|parent|optional },
3639 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3641 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
3642 { WM_DESTROY, sent|defwinproc },
3643 { WM_NCDESTROY, sent|defwinproc },
3644 { 0 }
3646 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
3647 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
3648 { WM_MDIDESTROY, sent }, /* in MDI client */
3649 { WM_SHOWWINDOW, sent|wparam, 0 },
3650 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3651 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3652 { WM_ERASEBKGND, sent|parent|optional },
3653 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3655 { HCBT_SETFOCUS, hook },
3656 { WM_KILLFOCUS, sent },
3657 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3658 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3659 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3660 { WM_SETFOCUS, sent }, /* in MDI client */
3661 { HCBT_SETFOCUS, hook },
3662 { WM_KILLFOCUS, sent }, /* in MDI client */
3663 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3664 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3665 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3666 { WM_SETFOCUS, sent },
3668 /* in MDI child */
3669 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3670 { WM_NCCALCSIZE, sent|wparam, 1 },
3671 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3672 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI child */
3674 /* in MDI frame */
3675 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3676 { WM_NCCALCSIZE, sent|wparam, 1 },
3677 { 0x0093, sent|defwinproc|optional },
3678 { 0x0093, sent|defwinproc|optional },
3679 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3680 { WM_MOVE, sent|defwinproc },
3681 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3683 /* in MDI client */
3684 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3685 { WM_NCCALCSIZE, sent|wparam, 1 },
3686 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3687 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3689 /* in MDI child */
3690 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3691 { WM_NCCALCSIZE, sent|wparam, 1 },
3692 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3693 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3695 /* in MDI child */
3696 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3697 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3698 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3699 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI child */
3701 /* in MDI frame */
3702 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3703 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3704 { 0x0093, sent|defwinproc|optional },
3705 { 0x0093, sent|defwinproc|optional },
3706 { 0x0093, sent|defwinproc|optional },
3707 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3708 { WM_MOVE, sent|defwinproc },
3709 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3711 /* in MDI client */
3712 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3713 { WM_NCCALCSIZE, sent|wparam, 1 },
3714 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3715 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3717 /* in MDI child */
3718 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3719 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3720 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3721 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3722 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI child */
3723 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI client */
3725 { 0x0093, sent|defwinproc|optional },
3726 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
3727 { 0x0093, sent|defwinproc|optional },
3728 { 0x0093, sent|defwinproc|optional },
3729 { 0x0093, sent|defwinproc|optional },
3730 { 0x0093, sent|optional },
3732 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI frame */
3733 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI child */
3734 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI client */
3735 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame */
3736 { 0x0093, sent|optional }, /* Win8+ sends an extra. */
3737 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
3739 /* in MDI frame */
3740 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3741 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3742 { 0x0093, sent|defwinproc|optional },
3743 { 0x0093, sent|defwinproc|optional },
3744 { 0x0093, sent|defwinproc|optional },
3745 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3746 { 0x0093, sent|optional }, /* Win8+ sends an extra. */
3747 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI frame */
3748 { 0x0093, sent|optional },
3750 { WM_NCACTIVATE, sent|wparam, 0 },
3751 { WM_MDIACTIVATE, sent },
3753 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
3754 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
3755 { WM_NCCALCSIZE, sent|wparam, 1 },
3757 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3759 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3760 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3761 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3763 /* in MDI child */
3764 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3765 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3766 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3767 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI child */
3769 /* in MDI frame */
3770 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3771 { WM_NCCALCSIZE, sent|wparam, 1 },
3772 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3773 { WM_MOVE, sent|defwinproc },
3774 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3776 /* in MDI client */
3777 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3778 { WM_NCCALCSIZE, sent|wparam, 1 },
3779 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3780 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3781 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI child */
3782 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
3783 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI client */
3784 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI frame */
3785 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
3787 { HCBT_SETFOCUS, hook },
3788 { WM_KILLFOCUS, sent },
3789 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3790 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3791 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3792 { WM_SETFOCUS, sent }, /* in MDI client */
3794 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
3796 { HCBT_DESTROYWND, hook },
3797 /* Win2k sends wparam set to
3798 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3799 * while Win9x doesn't bother to set child window id according to
3800 * CLIENTCREATESTRUCT.idFirstChild
3802 { 0x0090, sent|optional },
3803 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3805 { WM_SHOWWINDOW, sent|wparam, 0 },
3806 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3807 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3808 { WM_ERASEBKGND, sent|parent|optional },
3809 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3811 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
3812 { WM_DESTROY, sent },
3813 { WM_NCDESTROY, sent },
3814 { 0 }
3816 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
3817 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
3818 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3819 { WM_GETMINMAXINFO, sent },
3820 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3821 { WM_NCCALCSIZE, sent|wparam, 1 },
3822 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3823 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3825 { WM_WINDOWPOSCHANGING, sent|wparam|optional|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3826 { WM_NCACTIVATE, sent|wparam|optional|defwinproc, 1 },
3827 { HCBT_SETFOCUS, hook|optional },
3828 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3829 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3830 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3831 { HCBT_SETFOCUS, hook|optional },
3832 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3833 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3834 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3835 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3836 { WM_SETFOCUS, sent|optional|defwinproc },
3837 { WM_MDIACTIVATE, sent|optional|defwinproc },
3838 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3839 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3840 /* in MDI frame */
3841 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3842 { WM_NCCALCSIZE, sent|wparam, 1 },
3843 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3844 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3845 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3846 { 0 }
3848 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
3849 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
3850 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3851 { WM_GETMINMAXINFO, sent },
3852 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED, 0, SWP_STATECHANGED /* w1064v1809 */ },
3853 { WM_GETMINMAXINFO, sent|defwinproc },
3854 { WM_NCCALCSIZE, sent|wparam, 1 },
3855 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3856 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3858 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3859 { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
3860 { HCBT_SETFOCUS, hook|optional },
3861 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3862 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3863 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3864 { HCBT_SETFOCUS, hook|optional },
3865 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3866 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3867 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3868 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3869 { WM_SETFOCUS, sent|defwinproc|optional },
3870 { WM_MDIACTIVATE, sent|defwinproc|optional },
3871 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_STATECHANGED /* w1064v1809 */ },
3872 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child, not sent on Win8+. */
3873 { WM_SIZE, sent|defwinproc|optional },
3874 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* w1064v1809. */
3875 { 0 }
3877 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
3878 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
3879 { WM_MDIMAXIMIZE, sent }, /* in MDI client */
3880 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3881 { WM_GETMINMAXINFO, sent },
3882 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3883 { WM_GETMINMAXINFO, sent|defwinproc },
3884 { WM_NCCALCSIZE, sent|wparam, 1 },
3885 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
3886 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3887 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
3888 { WM_MOVE, sent|defwinproc },
3889 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3891 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3892 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3893 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3894 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3895 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3896 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3897 /* in MDI frame */
3898 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3899 { WM_NCCALCSIZE, sent|wparam, 1 },
3900 { 0x0093, sent|defwinproc|optional },
3901 { 0x0094, sent|defwinproc|optional },
3902 { 0x0094, sent|defwinproc|optional },
3903 { 0x0094, sent|defwinproc|optional },
3904 { 0x0094, sent|defwinproc|optional },
3905 { 0x0093, sent|defwinproc|optional },
3906 { 0x0093, sent|defwinproc|optional },
3907 { 0x0091, sent|defwinproc|optional },
3908 { 0x0092, sent|defwinproc|optional },
3909 { 0x0092, sent|defwinproc|optional },
3910 { 0x0092, sent|defwinproc|optional },
3911 { 0x0092, sent|defwinproc|optional },
3912 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3913 { WM_MOVE, sent|defwinproc },
3914 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3915 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
3916 /* in MDI client */
3917 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3918 { WM_NCCALCSIZE, sent|wparam, 1 },
3919 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3920 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3921 /* in MDI child */
3922 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3923 { WM_GETMINMAXINFO, sent|defwinproc },
3924 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3925 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3926 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3927 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
3928 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3929 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3930 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3931 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3932 /* in MDI frame */
3933 { 0x0093, sent|optional },
3934 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3935 { 0x0093, sent|defwinproc|optional },
3936 { 0x0093, sent|defwinproc|optional },
3937 { 0x0093, sent|defwinproc|optional },
3938 { 0x0091, sent|defwinproc|optional },
3939 { 0x0092, sent|defwinproc|optional },
3940 { 0x0092, sent|defwinproc|optional },
3941 { 0x0092, sent|defwinproc|optional },
3942 { 0x0092, sent|defwinproc|optional },
3943 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3944 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3945 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3946 { 0 }
3948 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
3949 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
3950 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3951 { WM_GETMINMAXINFO, sent },
3952 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3953 { WM_NCCALCSIZE, sent|wparam, 1 },
3954 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3955 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3956 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3957 /* in MDI frame */
3958 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3959 { WM_NCCALCSIZE, sent|wparam, 1 },
3960 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3961 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3962 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3963 { 0 }
3965 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
3966 static const struct message WmRestoreMDIchildVisibleSeq[] = {
3967 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3968 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3969 { WM_NCCALCSIZE, sent|wparam, 1 },
3970 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3971 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3972 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3973 /* in MDI frame */
3974 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3975 { WM_NCCALCSIZE, sent|wparam, 1 },
3976 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3977 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3978 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3979 { 0 }
3981 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
3982 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
3983 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3984 { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
3985 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3986 { WM_NCCALCSIZE, sent|wparam, 1 },
3987 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3988 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3989 { WM_MOVE, sent|defwinproc },
3990 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3991 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3992 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3993 { HCBT_SETFOCUS, hook },
3994 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3995 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
3996 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3997 { WM_SETFOCUS, sent },
3998 { 0 }
4000 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
4001 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
4002 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
4003 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
4004 { WM_NCCALCSIZE, sent|wparam, 1 },
4005 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
4006 { WM_MOVE, sent|defwinproc },
4007 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
4008 { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
4009 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
4010 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
4011 { 0 }
4013 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
4014 static const struct message WmRestoreMDIchildInvisibleSeq[] = {
4015 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
4016 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
4017 { WM_NCCALCSIZE, sent|wparam, 1 },
4018 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
4019 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
4020 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
4021 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
4022 /* in MDI frame */
4023 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
4024 { WM_NCCALCSIZE, sent|wparam, 1 },
4025 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
4026 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
4027 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
4028 { 0 }
4031 static HWND mdi_client;
4032 static WNDPROC old_mdi_client_proc;
4034 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4036 struct recvd_message msg;
4038 /* do not log painting messages */
4039 if (message != WM_PAINT &&
4040 message != WM_NCPAINT &&
4041 message != WM_SYNCPAINT &&
4042 message != WM_ERASEBKGND &&
4043 message != WM_NCHITTEST &&
4044 message != WM_GETTEXT &&
4045 message != WM_MDIGETACTIVE &&
4046 !ignore_message( message ))
4048 msg.hwnd = hwnd;
4049 msg.message = message;
4050 msg.flags = sent|wparam|lparam;
4051 msg.wParam = wParam;
4052 msg.lParam = lParam;
4053 msg.descr = "mdi client";
4054 add_message(&msg);
4057 return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
4060 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4062 static LONG defwndproc_counter = 0;
4063 LRESULT ret;
4064 struct recvd_message msg;
4066 /* do not log painting messages */
4067 if (message != WM_PAINT &&
4068 message != WM_NCPAINT &&
4069 message != WM_SYNCPAINT &&
4070 message != WM_ERASEBKGND &&
4071 message != WM_NCHITTEST &&
4072 message != WM_GETTEXT &&
4073 !ignore_message( message ))
4075 switch (message)
4077 case WM_MDIACTIVATE:
4079 HWND active, client = GetParent(hwnd);
4081 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
4083 if (hwnd == (HWND)lParam) /* if we are being activated */
4084 ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
4085 else
4086 ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
4087 break;
4091 msg.hwnd = hwnd;
4092 msg.message = message;
4093 msg.flags = sent|wparam|lparam;
4094 if (defwndproc_counter) msg.flags |= defwinproc;
4095 msg.wParam = wParam;
4096 msg.lParam = lParam;
4097 msg.descr = "mdi child";
4098 add_message(&msg);
4101 defwndproc_counter++;
4102 ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
4103 defwndproc_counter--;
4105 return ret;
4108 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4110 static LONG defwndproc_counter = 0;
4111 LRESULT ret;
4112 struct recvd_message msg;
4114 /* do not log painting messages */
4115 if (message != WM_PAINT &&
4116 message != WM_NCPAINT &&
4117 message != WM_SYNCPAINT &&
4118 message != WM_ERASEBKGND &&
4119 message != WM_NCHITTEST &&
4120 message != WM_GETTEXT &&
4121 !ignore_message( message ))
4123 msg.hwnd = hwnd;
4124 msg.message = message;
4125 msg.flags = sent|wparam|lparam;
4126 if (defwndproc_counter) msg.flags |= defwinproc;
4127 msg.wParam = wParam;
4128 msg.lParam = lParam;
4129 msg.descr = "mdi frame";
4130 add_message(&msg);
4133 defwndproc_counter++;
4134 ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
4135 defwndproc_counter--;
4137 return ret;
4140 static void mdi_register_classes(void)
4142 WNDCLASSA cls;
4143 BOOL ret;
4145 cls.style = 0;
4146 cls.lpfnWndProc = mdi_frame_wnd_proc;
4147 cls.cbClsExtra = 0;
4148 cls.cbWndExtra = 0;
4149 cls.hInstance = GetModuleHandleA(0);
4150 cls.hIcon = 0;
4151 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
4152 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
4153 cls.lpszMenuName = NULL;
4154 cls.lpszClassName = "MDI_frame_class";
4155 register_class(&cls);
4157 cls.lpfnWndProc = mdi_child_wnd_proc;
4158 cls.lpszClassName = "MDI_child_class";
4159 register_class(&cls);
4161 ret = GetClassInfoA(0, "MDIClient", &cls);
4162 ok(ret, "Failed to get class info, error %lu.\n", GetLastError());
4163 old_mdi_client_proc = cls.lpfnWndProc;
4164 cls.hInstance = GetModuleHandleA(0);
4165 cls.lpfnWndProc = mdi_client_hook_proc;
4166 cls.lpszClassName = "MDI_client_class";
4167 register_class(&cls);
4170 static void test_mdi_messages(void)
4172 MDICREATESTRUCTA mdi_cs;
4173 CLIENTCREATESTRUCT client_cs;
4174 HWND mdi_frame, mdi_child, mdi_child2, active_child;
4175 BOOL zoomed;
4176 RECT rc;
4177 HMENU hMenu = CreateMenu();
4178 LONG val;
4180 mdi_register_classes();
4182 flush_sequence();
4184 if (winetest_debug > 1) trace("creating MDI frame window\n");
4185 mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
4186 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
4187 WS_MAXIMIZEBOX | WS_VISIBLE,
4188 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
4189 GetDesktopWindow(), hMenu,
4190 GetModuleHandleA(0), NULL);
4191 ok(!!mdi_frame, "Failed to create window, error %lu.\n", GetLastError());
4192 ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
4194 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4195 ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
4197 if (winetest_debug > 1) trace("creating MDI client window\n");
4198 GetClientRect(mdi_frame, &rc);
4199 client_cs.hWindowMenu = 0;
4200 client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
4201 mdi_client = CreateWindowExA(0, "MDI_client_class",
4202 NULL,
4203 WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
4204 rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
4205 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
4206 ok(!!mdi_client, "Failed to create window, error %lu.\n", GetLastError());
4207 SetWindowLongA(mdi_client, 0, 0xdeadbeef);
4209 ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
4210 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4211 ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
4213 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4214 ok(!active_child, "wrong active MDI child %p\n", active_child);
4215 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4217 SetFocus(0);
4218 flush_sequence();
4220 if (winetest_debug > 1) trace("creating invisible MDI child window\n");
4221 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4222 WS_CHILD,
4223 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4224 mdi_client, 0, GetModuleHandleA(0), NULL);
4225 ok(!!mdi_child, "Failed to create window, error %lu.\n", GetLastError());
4227 flush_sequence();
4228 ShowWindow(mdi_child, SW_SHOWNORMAL);
4229 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
4231 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4232 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
4234 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4235 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4237 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4238 ok(!active_child, "wrong active MDI child %p\n", active_child);
4239 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4241 ShowWindow(mdi_child, SW_HIDE);
4242 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
4243 flush_sequence();
4245 ShowWindow(mdi_child, SW_SHOW);
4246 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
4248 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4249 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
4251 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4252 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4254 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4255 ok(!active_child, "wrong active MDI child %p\n", active_child);
4256 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4258 DestroyWindow(mdi_child);
4259 flush_sequence();
4261 if (winetest_debug > 1) trace("creating visible MDI child window\n");
4262 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4263 WS_CHILD | WS_VISIBLE,
4264 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4265 mdi_client, 0, GetModuleHandleA(0), NULL);
4266 ok(!!mdi_child, "Failed to create window, error %lu.\n", GetLastError());
4267 ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
4269 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4270 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
4272 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4273 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4275 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4276 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4277 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4278 flush_sequence();
4280 DestroyWindow(mdi_child);
4281 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4283 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4284 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4286 /* Win2k: MDI client still returns a just destroyed child as active
4287 * Win9x: MDI client returns 0
4289 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4290 ok(active_child == mdi_child || /* win2k */
4291 !active_child, /* win9x */
4292 "wrong active MDI child %p\n", active_child);
4293 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4295 flush_sequence();
4297 if (winetest_debug > 1) trace("creating invisible MDI child window\n");
4298 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4299 WS_CHILD,
4300 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4301 mdi_client, 0, GetModuleHandleA(0), NULL);
4302 ok(!!mdi_child2, "Failed to create window, error %lu.\n", GetLastError());
4303 ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
4305 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
4306 ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
4308 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4309 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4311 /* Win2k: MDI client still returns a just destroyed child as active
4312 * Win9x: MDI client returns mdi_child2
4314 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4315 ok(active_child == mdi_child || /* win2k */
4316 active_child == mdi_child2, /* win9x */
4317 "wrong active MDI child %p\n", active_child);
4318 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4319 flush_sequence();
4321 ShowWindow(mdi_child2, SW_MAXIMIZE);
4322 ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
4324 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4325 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
4327 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4328 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4329 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4330 flush_sequence();
4332 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4333 ok(GetFocus() == mdi_child2 || /* win2k */
4334 GetFocus() == 0, /* win9x */
4335 "wrong focus window %p\n", GetFocus());
4337 SetFocus(0);
4338 flush_sequence();
4340 ShowWindow(mdi_child2, SW_HIDE);
4341 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
4343 ShowWindow(mdi_child2, SW_RESTORE);
4344 ok_sequence(WmRestoreMDIchildInvisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
4345 flush_sequence();
4347 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4348 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
4350 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4351 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4352 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4353 flush_sequence();
4355 SetFocus(0);
4356 flush_sequence();
4358 ShowWindow(mdi_child2, SW_HIDE);
4359 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
4361 ShowWindow(mdi_child2, SW_SHOW);
4362 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
4364 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4365 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4367 ShowWindow(mdi_child2, SW_MAXIMIZE);
4368 ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
4370 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4371 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4373 ShowWindow(mdi_child2, SW_RESTORE);
4374 ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
4376 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4377 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4379 ShowWindow(mdi_child2, SW_MINIMIZE);
4380 ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", FALSE);
4382 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4383 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4385 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4386 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4387 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4388 flush_sequence();
4390 ShowWindow(mdi_child2, SW_RESTORE);
4391 ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", FALSE);
4393 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4394 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4396 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4397 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4398 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4399 flush_sequence();
4401 SetFocus(0);
4402 flush_sequence();
4404 ShowWindow(mdi_child2, SW_HIDE);
4405 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
4407 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4408 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4410 DestroyWindow(mdi_child2);
4411 ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
4413 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4414 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4416 if (winetest_debug > 1) trace("Testing WM_CHILDACTIVATE\n");
4418 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4419 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_DISABLED,
4420 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4421 mdi_client, 0, GetModuleHandleA(0), NULL);
4423 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4424 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX,
4425 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4426 mdi_client, 0, GetModuleHandleA(0), NULL);
4428 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4429 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4430 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4432 flush_sequence();
4433 SendMessageW(mdi_child, WM_CHILDACTIVATE, 0, 0);
4434 ok_sequence(WmChildActivateDisabledWindowSeq, "WM_CHILDACTIVATE sent to disabled window", FALSE);
4436 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4437 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4438 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4439 flush_sequence();
4441 EnableWindow(mdi_child, TRUE);
4443 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4444 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4445 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4447 flush_sequence();
4448 SendMessageW(mdi_child, WM_CHILDACTIVATE, 0, 0);
4449 ok_sequence(WmChildActivateWindowSeq, "WM_CHILDACTIVATE sent to enabled window", FALSE);
4451 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4452 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4453 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4454 flush_sequence();
4456 DestroyWindow(mdi_child);
4457 DestroyWindow(mdi_child2);
4458 flush_sequence();
4460 /* test for maximized MDI children */
4461 if (winetest_debug > 1) trace("creating maximized visible MDI child window 1\n");
4462 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4463 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4464 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4465 mdi_client, 0, GetModuleHandleA(0), NULL);
4466 ok(!!mdi_child, "Failed to create window, error %lu.\n", GetLastError());
4467 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
4468 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4470 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4471 ok(GetFocus() == mdi_child || /* win2k */
4472 GetFocus() == 0, /* win9x */
4473 "wrong focus window %p\n", GetFocus());
4475 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4476 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4477 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4478 flush_sequence();
4480 if (winetest_debug > 1) trace("creating maximized visible MDI child window 2\n");
4481 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4482 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4483 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4484 mdi_client, 0, GetModuleHandleA(0), NULL);
4485 ok(!!mdi_child2, "Failed to create window, error %lu.\n", GetLastError());
4486 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
4487 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
4488 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4490 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4491 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4493 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4494 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4495 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4496 flush_sequence();
4498 if (winetest_debug > 1) trace("destroying maximized visible MDI child window 2\n");
4499 DestroyWindow(mdi_child2);
4500 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4502 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4504 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4505 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4507 /* Win2k: MDI client still returns a just destroyed child as active
4508 * Win9x: MDI client returns 0
4510 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4511 ok(active_child == mdi_child2 || /* win2k */
4512 !active_child, /* win9x */
4513 "wrong active MDI child %p\n", active_child);
4514 flush_sequence();
4516 ShowWindow(mdi_child, SW_MAXIMIZE);
4517 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4518 flush_sequence();
4520 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4521 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4523 if (winetest_debug > 1) trace("re-creating maximized visible MDI child window 2\n");
4524 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4525 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4526 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4527 mdi_client, 0, GetModuleHandleA(0), NULL);
4528 ok(!!mdi_child2, "Failed to create window, error %lu.\n", GetLastError());
4529 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
4530 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
4531 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4533 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4534 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4536 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4537 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4538 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4539 flush_sequence();
4541 SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
4542 ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
4543 ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
4545 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4546 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4547 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4549 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4550 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4551 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4552 flush_sequence();
4554 DestroyWindow(mdi_child);
4555 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4557 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4558 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4560 /* Win2k: MDI client still returns a just destroyed child as active
4561 * Win9x: MDI client returns 0
4563 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4564 ok(active_child == mdi_child || /* win2k */
4565 !active_child, /* win9x */
4566 "wrong active MDI child %p\n", active_child);
4567 flush_sequence();
4569 if (winetest_debug > 1) trace("creating maximized invisible MDI child window\n");
4570 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4571 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
4572 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4573 mdi_client, 0, GetModuleHandleA(0), NULL);
4574 ok(!!mdi_child2, "Failed to create window, error %lu.\n", GetLastError());
4575 ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE);
4576 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
4577 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
4578 ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
4580 /* Win2k: MDI client still returns a just destroyed child as active
4581 * Win9x: MDI client returns 0
4583 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4584 ok(active_child == mdi_child || /* win2k */
4585 !active_child || active_child == mdi_child2, /* win9x */
4586 "wrong active MDI child %p\n", active_child);
4587 flush_sequence();
4589 if (winetest_debug > 1) trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
4590 ShowWindow(mdi_child2, SW_MAXIMIZE);
4591 ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
4592 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
4593 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4594 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
4596 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4597 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4598 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4599 flush_sequence();
4601 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
4602 flush_sequence();
4604 /* end of test for maximized MDI children */
4605 SetFocus(0);
4606 flush_sequence();
4607 if (winetest_debug > 1) trace("creating maximized visible MDI child window 1(Switch test)\n");
4608 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4609 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4610 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4611 mdi_client, 0, GetModuleHandleA(0), NULL);
4612 ok(!!mdi_child, "Failed to create window, error %lu.\n", GetLastError());
4613 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
4614 ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
4616 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
4617 ok(GetFocus() == mdi_child || /* win2k */
4618 GetFocus() == 0, /* win9x */
4619 "wrong focus window %p(Switch test)\n", GetFocus());
4621 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4622 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
4623 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
4624 flush_sequence();
4626 if (winetest_debug > 1) trace("creating maximized visible MDI child window 2(Switch test)\n");
4627 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4628 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4629 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4630 mdi_client, 0, GetModuleHandleA(0), NULL);
4631 ok(!!mdi_child2, "Failed to create window, error %lu.\n", GetLastError());
4632 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
4634 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
4635 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
4637 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
4638 ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
4640 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4641 ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
4642 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
4643 flush_sequence();
4645 if (winetest_debug > 1) trace("Switch child window.\n");
4646 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
4647 ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
4648 if (winetest_debug > 1) trace("end of test for switch maximized MDI children\n");
4649 flush_sequence();
4651 /* Prepare for switching test of not maximized MDI children */
4652 ShowWindow( mdi_child, SW_NORMAL );
4653 ok(!IsZoomed(mdi_child), "wrong zoomed state for %p(Switch test)\n", mdi_child);
4654 ok(!IsZoomed(mdi_child2), "wrong zoomed state for %p(Switch test)\n", mdi_child2);
4655 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
4656 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
4657 flush_sequence();
4659 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0);
4660 ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE);
4661 if (winetest_debug > 1) trace("end of test for switch not maximized MDI children\n");
4662 flush_sequence();
4664 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
4665 flush_sequence();
4667 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
4668 flush_sequence();
4670 SetFocus(0);
4671 flush_sequence();
4672 /* end of tests for switch maximized/not maximized MDI children */
4674 mdi_cs.szClass = "MDI_child_Class";
4675 mdi_cs.szTitle = "MDI child";
4676 mdi_cs.hOwner = GetModuleHandleA(0);
4677 mdi_cs.x = 0;
4678 mdi_cs.y = 0;
4679 mdi_cs.cx = CW_USEDEFAULT;
4680 mdi_cs.cy = CW_USEDEFAULT;
4681 mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
4682 mdi_cs.lParam = 0;
4683 mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
4684 ok(mdi_child != 0, "MDI child creation failed\n");
4685 ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
4687 ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
4689 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4690 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4692 ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
4693 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4694 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4696 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4697 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4698 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4699 flush_sequence();
4701 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
4702 ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
4704 ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
4705 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4706 ok(!active_child, "wrong active MDI child %p\n", active_child);
4708 SetFocus(0);
4709 flush_sequence();
4711 val = GetWindowLongA(mdi_client, 0);
4712 ok(val == 0xdeadbeef || broken(val == 0) /* >= Win Vista */, "Expected 0xdeadbeef, got 0x%lx\n", val);
4713 DestroyWindow(mdi_client);
4714 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
4716 /* test maximization of MDI child with invisible parent */
4717 client_cs.hWindowMenu = 0;
4718 mdi_client = CreateWindowA("MDI_client_class",
4719 NULL,
4720 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
4721 0, 0, 660, 430,
4722 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
4723 ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
4725 ShowWindow(mdi_client, SW_HIDE);
4726 ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
4728 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4729 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
4730 0, 0, 650, 440,
4731 mdi_client, 0, GetModuleHandleA(0), NULL);
4732 ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
4734 SendMessageA(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
4735 ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
4736 zoomed = IsZoomed(mdi_child);
4737 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4739 ShowWindow(mdi_client, SW_SHOW);
4740 ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
4742 DestroyWindow(mdi_child);
4743 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
4745 /* end of test for maximization of MDI child with invisible parent */
4747 DestroyWindow(mdi_client);
4748 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
4750 DestroyWindow(mdi_frame);
4751 ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
4753 /************************* End of MDI test **********************************/
4755 static void test_WM_SETREDRAW(HWND hwnd)
4757 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
4759 flush_events();
4760 flush_sequence();
4762 SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
4763 ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
4765 ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
4766 ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
4768 flush_sequence();
4769 SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
4770 ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
4772 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4773 ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
4775 /* restore original WS_VISIBLE state */
4776 SetWindowLongA(hwnd, GWL_STYLE, style);
4778 flush_events();
4779 flush_sequence();
4782 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4784 struct recvd_message msg;
4786 if (ignore_message( message )) return 0;
4788 switch (message)
4790 /* ignore */
4791 case WM_MOUSEMOVE:
4792 case WM_NCMOUSEMOVE:
4793 case WM_NCMOUSELEAVE:
4794 case WM_SETCURSOR:
4795 return 0;
4796 case WM_NCHITTEST:
4797 return HTCLIENT;
4800 msg.hwnd = hwnd;
4801 msg.message = message;
4802 msg.flags = sent|wparam|lparam;
4803 msg.wParam = wParam;
4804 msg.lParam = lParam;
4805 msg.descr = "dialog";
4806 add_message(&msg);
4808 if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
4809 if (message == WM_TIMER) EndDialog( hwnd, 0 );
4810 return 0;
4813 static INT_PTR CALLBACK TestModalDlgProc2(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4815 struct recvd_message msg;
4817 if (ignore_message( message )) return 0;
4819 switch (message)
4821 /* ignore */
4822 case WM_MOUSEMOVE:
4823 case WM_NCMOUSEMOVE:
4824 case WM_NCMOUSELEAVE:
4825 case WM_SETCURSOR:
4826 return 0;
4827 case WM_NCHITTEST:
4828 return HTCLIENT;
4831 msg.hwnd = hwnd;
4832 msg.message = message;
4833 msg.flags = sent|wparam|lparam;
4834 msg.wParam = wParam;
4835 msg.lParam = lParam;
4836 msg.descr = "dialog";
4837 add_message(&msg);
4839 if (message == WM_INITDIALOG) EndDialog( hwnd, 0 );
4840 return 0;
4843 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4845 DWORD style, exstyle;
4846 INT xmin, xmax;
4847 BOOL ret;
4849 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4850 style = GetWindowLongA(hwnd, GWL_STYLE);
4851 /* do not be confused by WS_DLGFRAME set */
4852 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4854 if (clear) ok(style & clear, "style %08lx should be set\n", clear);
4855 if (set) ok(!(style & set), "style %08lx should not be set\n", set);
4857 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4858 ok( ret, "SetScrollRange(%d) error %ld\n", ctl, GetLastError());
4859 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4860 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
4861 else
4862 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
4864 style = GetWindowLongA(hwnd, GWL_STYLE);
4865 if (set) ok(style & set, "style %08lx should be set\n", set);
4866 if (clear) ok(!(style & clear), "style %08lx should not be set\n", clear);
4868 /* a subsequent call should do nothing */
4869 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4870 ok( ret, "SetScrollRange(%d) error %ld\n", ctl, GetLastError());
4871 ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4873 xmin = 0xdeadbeef;
4874 xmax = 0xdeadbeef;
4875 ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
4876 ok( ret, "GetScrollRange(%d) error %ld\n", ctl, GetLastError());
4877 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4878 ok(xmin == min, "unexpected min scroll value %d\n", xmin);
4879 ok(xmax == max, "unexpected max scroll value %d\n", xmax);
4882 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4884 DWORD style, exstyle;
4885 SCROLLINFO si;
4886 BOOL ret;
4888 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4889 style = GetWindowLongA(hwnd, GWL_STYLE);
4890 /* do not be confused by WS_DLGFRAME set */
4891 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4893 if (clear) ok(style & clear, "style %08lx should be set\n", clear);
4894 if (set) ok(!(style & set), "style %08lx should not be set\n", set);
4896 si.cbSize = sizeof(si);
4897 si.fMask = SIF_RANGE;
4898 si.nMin = min;
4899 si.nMax = max;
4900 SetScrollInfo(hwnd, ctl, &si, TRUE);
4901 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4902 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
4903 else
4904 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
4906 style = GetWindowLongA(hwnd, GWL_STYLE);
4907 if (set) ok(style & set, "style %08lx should be set\n", set);
4908 if (clear) ok(!(style & clear), "style %08lx should not be set\n", clear);
4910 /* a subsequent call should do nothing */
4911 SetScrollInfo(hwnd, ctl, &si, TRUE);
4912 if (style & WS_HSCROLL)
4913 ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4914 else if (style & WS_VSCROLL)
4915 ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4916 else
4917 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4919 si.fMask = SIF_PAGE;
4920 si.nPage = 5;
4921 SetScrollInfo(hwnd, ctl, &si, FALSE);
4922 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4924 si.fMask = SIF_POS;
4925 si.nPos = max - 1;
4926 SetScrollInfo(hwnd, ctl, &si, FALSE);
4927 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4929 si.fMask = SIF_RANGE;
4930 si.nMin = 0xdeadbeef;
4931 si.nMax = 0xdeadbeef;
4932 ret = GetScrollInfo(hwnd, ctl, &si);
4933 ok( ret, "GetScrollInfo error %ld\n", GetLastError());
4934 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4935 ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
4936 ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
4939 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
4940 static void test_scroll_messages(HWND hwnd)
4942 SCROLLINFO si;
4943 INT min, max;
4944 BOOL ret;
4946 flush_events();
4947 flush_sequence();
4949 min = 0xdeadbeef;
4950 max = 0xdeadbeef;
4951 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4952 ok( ret, "GetScrollRange error %ld\n", GetLastError());
4953 if (sequence->message != WmGetScrollRangeSeq[0].message)
4954 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4955 /* values of min and max are undefined */
4956 flush_sequence();
4958 ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
4959 ok( ret, "SetScrollRange error %ld\n", GetLastError());
4960 if (sequence->message != WmSetScrollRangeSeq[0].message)
4961 trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4962 flush_sequence();
4964 min = 0xdeadbeef;
4965 max = 0xdeadbeef;
4966 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4967 ok( ret, "GetScrollRange error %ld\n", GetLastError());
4968 if (sequence->message != WmGetScrollRangeSeq[0].message)
4969 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4970 /* values of min and max are undefined */
4971 flush_sequence();
4973 si.cbSize = sizeof(si);
4974 si.fMask = SIF_RANGE;
4975 si.nMin = 20;
4976 si.nMax = 160;
4977 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4978 if (sequence->message != WmSetScrollRangeSeq[0].message)
4979 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4980 flush_sequence();
4982 si.fMask = SIF_PAGE;
4983 si.nPage = 10;
4984 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4985 if (sequence->message != WmSetScrollRangeSeq[0].message)
4986 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4987 flush_sequence();
4989 si.fMask = SIF_POS;
4990 si.nPos = 20;
4991 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4992 if (sequence->message != WmSetScrollRangeSeq[0].message)
4993 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4994 flush_sequence();
4996 si.fMask = SIF_RANGE;
4997 si.nMin = 0xdeadbeef;
4998 si.nMax = 0xdeadbeef;
4999 ret = GetScrollInfo(hwnd, SB_CTL, &si);
5000 ok( ret, "GetScrollInfo error %ld\n", GetLastError());
5001 if (sequence->message != WmGetScrollInfoSeq[0].message)
5002 trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
5003 /* values of min and max are undefined */
5004 flush_sequence();
5006 /* set WS_HSCROLL */
5007 test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
5008 /* clear WS_HSCROLL */
5009 test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
5011 /* set WS_HSCROLL */
5012 test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
5013 /* clear WS_HSCROLL */
5014 test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
5016 /* set WS_VSCROLL */
5017 test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
5018 /* clear WS_VSCROLL */
5019 test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
5021 /* set WS_VSCROLL */
5022 test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
5023 /* clear WS_VSCROLL */
5024 test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
5027 static void test_showwindow(void)
5029 HWND hwnd, hwnd2, hchild;
5030 RECT rc;
5032 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5033 100, 100, 200, 200, 0, 0, 0, NULL);
5034 ok (hwnd != 0, "Failed to create overlapped window\n");
5035 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5036 0, 0, 10, 10, hwnd, 0, 0, NULL);
5037 ok (hchild != 0, "Failed to create child\n");
5038 flush_sequence();
5040 /* ShowWindow( SW_SHOWNA) for invisible top level window */
5041 if (winetest_debug > 1) trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
5042 ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
5043 ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", FALSE);
5045 /* ShowWindow( SW_SHOWNA) for now visible top level window */
5046 if (winetest_debug > 1) trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
5047 ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
5048 ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
5049 /* back to invisible */
5050 ShowWindow(hchild, SW_HIDE);
5051 ShowWindow(hwnd, SW_HIDE);
5052 flush_sequence();
5053 /* ShowWindow(SW_SHOWNA) with child and parent invisible */
5054 if (winetest_debug > 1) trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
5055 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
5056 ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
5057 /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */
5058 ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
5059 flush_sequence();
5060 if (winetest_debug > 1) trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
5061 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
5062 ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
5063 /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
5064 ShowWindow( hwnd, SW_SHOW);
5065 flush_sequence();
5066 if (winetest_debug > 1) trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
5067 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
5068 ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
5070 /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
5071 ShowWindow( hchild, SW_HIDE);
5072 flush_sequence();
5073 if (winetest_debug > 1) trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
5074 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
5075 ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
5077 SetCapture(hchild);
5078 ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
5079 DestroyWindow(hchild);
5080 ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
5082 DestroyWindow(hwnd);
5083 flush_sequence();
5085 /* Popup windows */
5086 /* Test 1:
5087 * 1. Create invisible maximized popup window.
5088 * 2. Move and resize it.
5089 * 3. Show it maximized.
5091 if (winetest_debug > 1) trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
5092 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
5093 100, 100, 200, 200, 0, 0, 0, NULL);
5094 ok (hwnd != 0, "Failed to create popup window\n");
5095 ok(IsZoomed(hwnd), "window should be maximized\n");
5096 ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
5098 GetWindowRect(hwnd, &rc);
5099 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
5100 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
5101 "Invalid maximized size before ShowWindow %s\n", wine_dbgstr_rect( &rc ));
5102 /* Reset window's size & position */
5103 SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
5104 ok(IsZoomed(hwnd), "window should be maximized\n");
5105 flush_sequence();
5107 if (winetest_debug > 1) trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
5108 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5109 ok(IsZoomed(hwnd), "window should be maximized\n");
5110 ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
5112 GetWindowRect(hwnd, &rc);
5113 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
5114 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
5115 "Invalid maximized size after ShowWindow %s\n", wine_dbgstr_rect( &rc ));
5116 DestroyWindow(hwnd);
5117 flush_sequence();
5119 /* Test 2:
5120 * 1. Create invisible maximized popup window.
5121 * 2. Show it maximized.
5123 if (winetest_debug > 1) trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
5124 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
5125 100, 100, 200, 200, 0, 0, 0, NULL);
5126 ok (hwnd != 0, "Failed to create popup window\n");
5127 ok(IsZoomed(hwnd), "window should be maximized\n");
5128 ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
5130 if (winetest_debug > 1) trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
5131 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5132 ok(IsZoomed(hwnd), "window should be maximized\n");
5133 ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
5134 DestroyWindow(hwnd);
5135 flush_sequence();
5137 /* Test 3:
5138 * 1. Create visible maximized popup window.
5140 if (winetest_debug > 1) trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
5141 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
5142 100, 100, 200, 200, 0, 0, 0, NULL);
5143 ok (hwnd != 0, "Failed to create popup window\n");
5144 ok(IsZoomed(hwnd), "window should be maximized\n");
5145 ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
5146 DestroyWindow(hwnd);
5147 flush_sequence();
5149 /* Test 4:
5150 * 1. Create visible popup window.
5151 * 2. Maximize it.
5153 if (winetest_debug > 1) trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
5154 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
5155 100, 100, 200, 200, 0, 0, 0, NULL);
5156 ok (hwnd != 0, "Failed to create popup window\n");
5157 ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
5158 ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
5160 if (winetest_debug > 1) trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
5161 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5162 ok(IsZoomed(hwnd), "window should be maximized\n");
5163 ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
5164 DestroyWindow(hwnd);
5165 flush_sequence();
5167 /* Test 5:
5168 * 1. Restoring a minimized window.
5170 hwnd = CreateWindowA("TestWindowClass", "window1", WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 0, 0, 0, 0);
5171 ok(hwnd != NULL, "Failed to create window\n");
5173 hwnd2 = CreateWindowA("static", "window2", WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 0, 0, 0, 0);
5174 ok(hwnd2 != NULL, "Failed to create window\n");
5176 ShowWindow(hwnd, SW_MINIMIZE);
5177 SetActiveWindow(hwnd2);
5178 ok(GetActiveWindow() == hwnd2, "Unexpected active window\n");
5179 flush_events();
5180 flush_sequence();
5181 ShowWindow(hwnd, SW_RESTORE);
5182 flush_events();
5183 ok_sequence(WmShowRestoreMinimizedOverlappedSeq,
5184 "ShowWindow(hwnd, SW_RESTORE): minimized overlapped", TRUE);
5186 ShowWindow(hwnd, SW_MINIMIZE);
5187 SetActiveWindow(hwnd2);
5188 ok(GetActiveWindow() == hwnd2, "Unexpected active window\n");
5189 flush_events();
5190 flush_sequence();
5191 ShowWindow(hwnd, SW_SHOWNOACTIVATE);
5192 flush_events();
5193 ok_sequence(WmShowNoActivateMinimizedOverlappedSeq,
5194 "ShowWindow(hwnd, SW_SHOWNOACTIVATE): minimized overlapped", TRUE);
5196 DestroyWindow(hwnd2);
5197 DestroyWindow(hwnd);
5198 flush_sequence();
5200 /* Test 6:
5201 * 1. Restoring a minimized but active window.
5203 hwnd = CreateWindowA("TestWindowClass", "parent", WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 0, 0, 0, 0);
5204 ok(hwnd != NULL, "Failed to create window\n");
5206 ShowWindow(hwnd, SW_MINIMIZE);
5207 SetActiveWindow(hwnd);
5208 ok(GetActiveWindow() == hwnd, "Unexpected active window\n");
5209 flush_events();
5210 flush_sequence();
5211 ShowWindow(hwnd, SW_RESTORE);
5212 flush_events();
5213 ok_sequence(WmShowRestoreActiveMinimizedOverlappedSeq,
5214 "ShowWindow(hwnd, SW_RESTORE): active minimized overlapped", TRUE);
5216 ShowWindow(hwnd, SW_MINIMIZE);
5217 SetActiveWindow(hwnd);
5218 ok(GetActiveWindow() == hwnd, "Unexpected active window\n");
5219 flush_events();
5220 flush_sequence();
5221 ShowWindow(hwnd, SW_SHOWNOACTIVATE);
5222 flush_events();
5223 ok_sequence(WmShowNoActivateActiveMinimizedOverlappedSeq,
5224 "ShowWindow(hwnd, SW_SHOWNOACTIVATE): active minimized overlapped", TRUE);
5226 DestroyWindow(hwnd);
5227 flush_sequence();
5230 static void test_sys_menu(void)
5232 HWND hwnd;
5233 HMENU hmenu;
5234 UINT state;
5236 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
5237 100, 100, 200, 200, 0, 0, 0, NULL);
5238 ok (hwnd != 0, "Failed to create overlapped window\n");
5240 flush_sequence();
5242 /* test existing window without CS_NOCLOSE style */
5243 hmenu = GetSystemMenu(hwnd, FALSE);
5244 ok(hmenu != 0, "GetSystemMenu error %ld\n", GetLastError());
5246 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
5247 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
5248 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
5250 EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
5251 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
5253 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
5254 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
5255 ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
5257 EnableMenuItem(hmenu, SC_CLOSE, 0);
5258 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
5260 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
5261 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
5262 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
5264 /* test whether removing WS_SYSMENU destroys a system menu */
5265 SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
5266 SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
5267 flush_sequence();
5268 hmenu = GetSystemMenu(hwnd, FALSE);
5269 ok(hmenu != 0, "GetSystemMenu error %ld\n", GetLastError());
5271 DestroyWindow(hwnd);
5273 /* test new window with CS_NOCLOSE style */
5274 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
5275 100, 100, 200, 200, 0, 0, 0, NULL);
5276 ok (hwnd != 0, "Failed to create overlapped window\n");
5278 hmenu = GetSystemMenu(hwnd, FALSE);
5279 ok(hmenu != 0, "GetSystemMenu error %ld\n", GetLastError());
5281 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
5282 ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
5284 DestroyWindow(hwnd);
5286 /* test new window without WS_SYSMENU style */
5287 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
5288 100, 100, 200, 200, 0, 0, 0, NULL);
5289 ok(hwnd != 0, "Failed to create overlapped window\n");
5291 hmenu = GetSystemMenu(hwnd, FALSE);
5292 ok(!hmenu, "GetSystemMenu error %ld\n", GetLastError());
5294 DestroyWindow(hwnd);
5297 /* For shown WS_OVERLAPPEDWINDOW */
5298 static const struct message WmSetIcon_1[] = {
5299 { WM_SETICON, sent },
5300 { 0x00AE, sent|defwinproc|optional }, /* XP */
5301 { WM_GETTEXT, sent|defwinproc|optional },
5302 { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
5303 { 0 }
5306 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
5307 static const struct message WmSetIcon_2[] = {
5308 { WM_SETICON, sent },
5309 { 0 }
5312 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
5313 static const struct message WmInitEndSession[] = {
5314 { 0x003B, sent },
5315 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
5316 { 0 }
5319 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
5320 static const struct message WmInitEndSession_2[] = {
5321 { 0x003B, sent },
5322 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
5323 { 0 }
5326 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
5327 static const struct message WmInitEndSession_3[] = {
5328 { 0x003B, sent },
5329 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
5330 { 0 }
5333 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
5334 static const struct message WmInitEndSession_4[] = {
5335 { 0x003B, sent },
5336 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
5337 { 0 }
5340 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
5341 static const struct message WmInitEndSession_5[] = {
5342 { 0x003B, sent },
5343 { WM_ENDSESSION, sent|defwinproc/*|wparam*/|lparam, 1, ENDSESSION_LOGOFF },
5344 { 0 }
5347 static const struct message WmOptionalPaint[] = {
5348 { WM_PAINT, sent|optional },
5349 { WM_NCPAINT, sent|beginpaint|optional },
5350 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5351 { WM_ERASEBKGND, sent|beginpaint|optional },
5352 { 0 }
5355 static const struct message WmZOrder[] = {
5356 { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 },
5357 { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 },
5358 { HCBT_ACTIVATE, hook },
5359 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
5360 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
5361 { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 },
5362 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 },
5363 { WM_GETTEXT, sent|optional },
5364 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
5365 { WM_ACTIVATEAPP, sent|wparam, 1, 0 },
5366 { WM_NCACTIVATE, sent|lparam, 1, 0 },
5367 { WM_GETTEXT, sent|defwinproc|optional },
5368 { WM_GETTEXT, sent|defwinproc|optional },
5369 { WM_ACTIVATE, sent|wparam|lparam, 1, 0 },
5370 { HCBT_SETFOCUS, hook },
5371 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5372 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5373 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5374 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
5375 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
5376 { WM_GETTEXT, sent|optional },
5377 { WM_NCCALCSIZE, sent|optional },
5378 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends it, but Win8+ doesn't. */
5379 { 0 }
5382 static void CALLBACK apc_test_proc(ULONG_PTR param)
5384 /* nothing */
5387 static void test_MsgWaitForMultipleObjects(HWND hwnd)
5389 DWORD ret;
5390 MSG msg;
5392 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5393 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %lx\n", ret);
5395 PostMessageA(hwnd, WM_USER, 0, 0);
5397 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5398 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %lx\n", ret);
5400 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5401 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5403 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5404 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %lx\n", ret);
5406 PostMessageA(hwnd, WM_USER, 0, 0);
5408 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5409 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %lx\n", ret);
5411 ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
5412 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5414 /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
5415 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5416 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %lx\n", ret);
5418 PostMessageA(hwnd, WM_USER, 0, 0);
5420 /* new incoming message causes it to become signaled again */
5421 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5422 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %lx\n", ret);
5424 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5425 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5426 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5427 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5429 /* MWMO_INPUTAVAILABLE should succeed even if the message was already seen */
5430 PostMessageA( hwnd, WM_USER, 0, 0 );
5431 ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
5432 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5434 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_INPUTAVAILABLE );
5435 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %lx\n", ret);
5437 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5438 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5440 /* without MWMO_ALERTABLE the result is never WAIT_IO_COMPLETION */
5441 ret = QueueUserAPC( apc_test_proc, GetCurrentThread(), 0 );
5442 ok(ret, "QueueUserAPC failed %lu\n", GetLastError());
5444 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, 0 );
5445 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjectsEx returned %lx\n", ret);
5447 /* but even with MWMO_ALERTABLE window events are preferred */
5448 PostMessageA( hwnd, WM_USER, 0, 0 );
5450 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_ALERTABLE );
5451 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %lx\n", ret);
5453 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5454 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5456 /* the APC call is still queued */
5457 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_ALERTABLE );
5458 ok(ret == WAIT_IO_COMPLETION, "MsgWaitForMultipleObjectsEx returned %lx\n", ret);
5461 static void test_WM_DEVICECHANGE(HWND hwnd)
5463 DWORD ret;
5464 MSG msg;
5465 int i;
5466 static const WPARAM wparams[] = {0,
5467 DBT_DEVNODES_CHANGED,
5468 DBT_QUERYCHANGECONFIG,
5469 DBT_CONFIGCHANGED,
5470 DBT_CONFIGCHANGECANCELED,
5471 DBT_NO_DISK_SPACE,
5472 DBT_LOW_DISK_SPACE,
5473 DBT_CONFIGMGPRIVATE, /* 0x7fff */
5474 DBT_DEVICEARRIVAL, /* 0x8000 */
5475 DBT_DEVICEQUERYREMOVE,
5476 DBT_DEVICEQUERYREMOVEFAILED,
5477 DBT_DEVICEREMOVEPENDING,
5478 DBT_DEVICEREMOVECOMPLETE,
5479 DBT_DEVICETYPESPECIFIC,
5480 DBT_CUSTOMEVENT};
5482 for (i = 0; i < ARRAY_SIZE(wparams); i++)
5484 SetLastError(0xdeadbeef);
5485 ret = PostMessageA(hwnd, WM_DEVICECHANGE, wparams[i], 0);
5486 if (wparams[i] & 0x8000)
5488 ok(ret == FALSE, "PostMessage returned %ld\n", ret);
5489 ok(GetLastError() == ERROR_MESSAGE_SYNC_ONLY, "PostMessage error %08lx\n", GetLastError());
5491 else
5493 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5494 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %lx\n", ret);
5495 memset(&msg, 0, sizeof(msg));
5496 ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should succeed\n");
5497 ok(msg.message == WM_DEVICECHANGE, "got %04x instead of WM_DEVICECHANGE\n", msg.message);
5502 static DWORD CALLBACK hide_window_thread( LPVOID arg )
5504 HWND hwnd = arg;
5506 /* function will not return if ShowWindow(SW_HIDE) calls SendMessage() */
5507 ok(ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow(SW_HIDE) expected FALSE\n");
5509 return 0;
5512 static DWORD CALLBACK show_window_thread( LPVOID arg )
5514 HWND hwnd = arg;
5516 /* function will not return if ShowWindow(SW_SHOW) calls SendMessage() */
5517 ok( ShowWindow( hwnd, SW_SHOW ), "ShowWindow(SW_SHOW) expected TRUE\n" ); /* actually it's 24... */
5519 return 0;
5522 /* Helper function to easier test SetWindowPos messages */
5523 #define test_msg_setpos( expected_list, flags, todo ) \
5524 test_msg_setpos_( (expected_list), (flags), (todo), __FILE__, __LINE__)
5525 static void test_msg_setpos_(const struct message *expected_list, UINT flags, BOOL todo, const char *file, int line)
5527 HWND hwnd;
5529 flush_events();
5530 flush_sequence();
5531 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5532 10, 10, 100, 100, NULL, 0, 0, NULL );
5533 ok (hwnd != 0, "Failed to create popup window\n");
5534 SetWindowPos(hwnd, NULL, 0, 0, 100, 100, flags);
5535 ok_sequence_(expected_list, "SetWindowPos:show_popup_first_show_window", todo, file, line);
5536 DestroyWindow(hwnd);
5539 /* test if we receive the right sequence of messages */
5540 static void test_messages(void)
5542 DWORD tid;
5543 HANDLE hthread;
5544 HWND hwnd, hparent, hchild;
5545 HWND hchild2, hbutton;
5546 HMENU hmenu;
5547 MSG msg;
5548 LRESULT res;
5549 POINT pos;
5550 BOOL ret;
5552 flush_sequence();
5554 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5555 100, 100, 200, 200, 0, 0, 0, NULL);
5556 ok (hwnd != 0, "Failed to create overlapped window\n");
5557 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
5559 /* test ShowWindow(SW_HIDE) on a newly created invisible window */
5560 ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
5561 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
5563 /* test WM_SETREDRAW on a not visible top level window */
5564 test_WM_SETREDRAW(hwnd);
5566 SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5567 flush_events();
5568 ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
5569 ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
5571 ok(GetActiveWindow() == hwnd, "window should be active\n");
5572 ok(GetFocus() == hwnd, "window should have input focus\n");
5573 ShowWindow(hwnd, SW_HIDE);
5574 flush_events();
5575 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5577 /* test ShowWindow(SW_HIDE) on a hidden window - single threaded */
5578 ok(ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow(SW_HIDE) expected FALSE\n");
5579 flush_events();
5580 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5582 /* test ShowWindow(SW_HIDE) on a hidden window - multi-threaded */
5583 hthread = CreateThread( NULL, 0, hide_window_thread, hwnd, 0, &tid );
5584 ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError());
5585 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5586 CloseHandle(hthread);
5587 flush_events();
5588 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5590 ShowWindow(hwnd, SW_SHOW);
5591 flush_events();
5592 ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
5594 /* test ShowWindow(SW_SHOW) on a visible window - multi-threaded */
5595 hthread = CreateThread( NULL, 0, show_window_thread, hwnd, 0, &tid );
5596 ok( hthread != NULL, "CreateThread failed, error %ld\n", GetLastError() );
5597 ok( WaitForSingleObject( hthread, INFINITE ) == WAIT_OBJECT_0, "WaitForSingleObject failed\n" );
5598 CloseHandle( hthread );
5599 flush_events();
5600 ok_sequence( WmEmptySeq, "ShowWindow(SW_SHOW):overlapped", FALSE );
5602 ShowWindow(hwnd, SW_HIDE);
5603 flush_events();
5604 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5606 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5607 flush_events();
5608 ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
5609 flush_sequence();
5611 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZE)
5613 ShowWindow(hwnd, SW_RESTORE);
5614 flush_events();
5615 ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
5616 flush_sequence();
5619 ShowWindow(hwnd, SW_MINIMIZE);
5620 flush_events();
5621 ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", FALSE);
5622 flush_sequence();
5624 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)
5626 ShowWindow(hwnd, SW_RESTORE);
5627 flush_events();
5628 ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", FALSE);
5629 flush_sequence();
5632 ShowWindow(hwnd, SW_SHOW);
5633 flush_events();
5634 ok_sequence(WmOptionalPaint, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
5636 SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5637 ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
5638 ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
5639 ok(GetActiveWindow() == hwnd, "window should still be active\n");
5641 /* test WM_SETREDRAW on a visible top level window */
5642 ShowWindow(hwnd, SW_SHOW);
5643 flush_events();
5644 test_WM_SETREDRAW(hwnd);
5646 if (winetest_debug > 1) trace("testing scroll APIs on a visible top level window %p\n", hwnd);
5647 test_scroll_messages(hwnd);
5649 /* test resizing and moving */
5650 SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
5651 ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
5652 flush_events();
5653 flush_sequence();
5654 SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
5655 ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
5656 flush_events();
5657 flush_sequence();
5658 SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER|SWP_NOACTIVATE );
5659 ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
5660 flush_events();
5661 flush_sequence();
5663 /* popups don't get WM_GETMINMAXINFO */
5664 SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
5665 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
5666 flush_sequence();
5667 SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
5668 ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
5670 DestroyWindow(hwnd);
5671 ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
5673 /* Test if windows are correctly drawn when first shown */
5675 /* Visible, redraw */
5676 flush_events();
5677 flush_sequence();
5678 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5679 10, 10, 100, 100, NULL, 0, 0, NULL );
5680 ok (hwnd != 0, "Failed to create popup window\n");
5681 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
5682 ok_sequence(WmShowPopupFirstDrawSeq_1, "RedrawWindow:show_popup_first_draw_visible", FALSE);
5683 DestroyWindow(hwnd);
5685 /* Invisible, show, message */
5686 flush_events();
5687 flush_sequence();
5688 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5689 10, 10, 100, 100, NULL, 0, 0, NULL );
5690 ok (hwnd != 0, "Failed to create popup window\n");
5691 ShowWindow(hwnd, SW_SHOW);
5692 SendMessageW(hwnd, WM_PAINT, 0, 0);
5693 ok_sequence(WmShowPopupFirstDrawSeq_1, "RedrawWindow:show_popup_first_draw_show", FALSE);
5694 DestroyWindow(hwnd);
5696 /* Invisible, show maximized, redraw */
5697 flush_events();
5698 flush_sequence();
5699 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5700 10, 10, 100, 100, NULL, 0, 0, NULL );
5701 ok (hwnd != 0, "Failed to create popup window\n");
5702 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5703 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
5704 ok_sequence(WmShowPopupFirstDrawSeq_2, "RedrawWindow:show_popup_first_draw_show_maximized", FALSE);
5705 DestroyWindow(hwnd);
5707 /* Test SetWindowPos */
5708 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW, FALSE);
5709 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, 0, FALSE);
5710 test_msg_setpos(WmFirstDrawSetWindowPosSeq6,
5711 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER, FALSE);
5713 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOSIZE, FALSE);
5714 test_msg_setpos(WmFirstDrawSetWindowPosSeq4, SWP_SHOWWINDOW | SWP_NOMOVE, FALSE);
5715 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCLIENTSIZE, FALSE);
5716 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCLIENTMOVE, FALSE);
5717 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOZORDER, FALSE);
5719 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE, FALSE);
5720 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOCLIENTMOVE, FALSE);
5721 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOCLIENTSIZE, FALSE);
5722 test_msg_setpos(WmFirstDrawSetWindowPosSeq5, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOMOVE, FALSE);
5723 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOSIZE, FALSE);
5724 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOZORDER, FALSE);
5726 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS, FALSE);
5727 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOCLIENTMOVE, FALSE);
5728 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOCLIENTSIZE, FALSE);
5729 test_msg_setpos(WmFirstDrawSetWindowPosSeq4, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOMOVE, FALSE);
5730 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOSIZE, FALSE);
5731 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOZORDER, FALSE);
5733 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW, FALSE);
5734 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCLIENTMOVE, FALSE);
5735 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCLIENTSIZE, FALSE);
5736 test_msg_setpos(WmFirstDrawSetWindowPosSeq5, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOMOVE, FALSE);
5737 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOSIZE, FALSE);
5738 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOZORDER, FALSE);
5740 /* Test SetWindowPos with child windows */
5741 flush_events();
5742 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5743 100, 100, 200, 200, 0, 0, 0, NULL);
5744 ok (hparent != 0, "Failed to create parent window\n");
5746 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5747 0, 0, 10, 10, hparent, 0, 0, NULL);
5748 ok (hchild != 0, "Failed to create child window\n");
5749 flush_sequence();
5750 SetWindowPos(hparent, NULL, 0, 0, 100, 100, SWP_SHOWWINDOW);
5751 ok_sequence(WmFirstDrawChildSeq1, /* Expect no messages for the child */
5752 "SetWindowPos:show_popup_first_show_window_child1", FALSE);
5753 DestroyWindow(hchild);
5754 DestroyWindow(hparent);
5756 flush_events();
5757 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN,
5758 100, 100, 200, 200, 0, 0, 0, NULL);
5759 ok (hparent != 0, "Failed to create parent window\n");
5761 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5762 0, 0, 10, 10, hparent, 0, 0, NULL);
5763 ok (hchild != 0, "Failed to create child window\n");
5764 flush_sequence();
5765 SetWindowPos(hparent, NULL, 0, 0, 100, 100, SWP_SHOWWINDOW);
5766 ok_sequence(WmFirstDrawChildSeq2, /* Expect child to be redrawn */
5767 "SetWindowPos:show_popup_first_show_window_child2", FALSE);
5768 DestroyWindow(hchild);
5769 DestroyWindow(hparent);
5771 /* Test message sequence for extreme position and size */
5773 flush_sequence();
5774 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5775 -10, -10, 10000, 10000, NULL, 0, 0, NULL );
5776 ok (hwnd != 0, "Failed to create popup window\n");
5777 ok_sequence(WmShowPopupExtremeLocationSeq, "RedrawWindow:show_popup_extreme_location", FALSE);
5778 DestroyWindow(hwnd);
5781 /* Test child windows */
5783 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5784 100, 100, 200, 200, 0, 0, 0, NULL);
5785 ok (hparent != 0, "Failed to create parent window\n");
5786 flush_sequence();
5788 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
5789 0, 0, 10, 10, hparent, 0, 0, NULL);
5790 ok (hchild != 0, "Failed to create child window\n");
5791 ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
5792 DestroyWindow(hchild);
5793 flush_sequence();
5795 /* visible child window with a caption */
5796 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
5797 WS_CHILD | WS_VISIBLE | WS_CAPTION,
5798 0, 0, 10, 10, hparent, 0, 0, NULL);
5799 ok (hchild != 0, "Failed to create child window\n");
5800 ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
5802 if (winetest_debug > 1) trace("testing scroll APIs on a visible child window %p\n", hchild);
5803 test_scroll_messages(hchild);
5805 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5806 ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
5808 DestroyWindow(hchild);
5809 flush_sequence();
5811 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5812 0, 0, 10, 10, hparent, 0, 0, NULL);
5813 ok (hchild != 0, "Failed to create child window\n");
5814 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
5816 hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
5817 100, 100, 50, 50, hparent, 0, 0, NULL);
5818 ok (hchild2 != 0, "Failed to create child2 window\n");
5819 flush_sequence();
5821 hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
5822 0, 100, 50, 50, hchild, 0, 0, NULL);
5823 ok (hbutton != 0, "Failed to create button window\n");
5825 /* test WM_SETREDRAW on a not visible child window */
5826 test_WM_SETREDRAW(hchild);
5828 ShowWindow(hchild, SW_SHOW);
5829 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5831 /* check parent messages too */
5832 log_all_parent_messages++;
5833 ShowWindow(hchild, SW_HIDE);
5834 ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
5835 log_all_parent_messages--;
5837 ShowWindow(hchild, SW_SHOW);
5838 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5840 ShowWindow(hchild, SW_HIDE);
5841 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
5843 ShowWindow(hchild, SW_SHOW);
5844 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5846 /* test WM_SETREDRAW on a visible child window */
5847 test_WM_SETREDRAW(hchild);
5849 log_all_parent_messages++;
5850 MoveWindow(hchild, 10, 10, 20, 20, TRUE);
5851 ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
5852 log_all_parent_messages--;
5854 ShowWindow(hchild, SW_HIDE);
5855 flush_sequence();
5856 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5857 ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
5859 ShowWindow(hchild, SW_HIDE);
5860 flush_sequence();
5861 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
5862 ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
5864 /* DestroyWindow sequence below expects that a child has focus */
5865 SetFocus(hchild);
5866 flush_sequence();
5868 DestroyWindow(hchild);
5869 ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
5870 DestroyWindow(hchild2);
5871 DestroyWindow(hbutton);
5873 flush_sequence();
5874 hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
5875 0, 0, 100, 100, hparent, 0, 0, NULL);
5876 ok (hchild != 0, "Failed to create child popup window\n");
5877 ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
5878 DestroyWindow(hchild);
5880 /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
5881 flush_sequence();
5882 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
5883 0, 0, 100, 100, hparent, 0, 0, NULL);
5884 ok (hchild != 0, "Failed to create popup window\n");
5885 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
5886 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5887 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
5888 flush_sequence();
5889 ShowWindow(hchild, SW_SHOW);
5890 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
5891 flush_sequence();
5892 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5893 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
5894 flush_sequence();
5895 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5896 ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
5897 DestroyWindow(hchild);
5899 /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
5900 * changes nothing in message sequences.
5902 flush_sequence();
5903 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5904 0, 0, 100, 100, hparent, 0, 0, NULL);
5905 ok (hchild != 0, "Failed to create popup window\n");
5906 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
5907 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5908 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
5909 flush_sequence();
5910 ShowWindow(hchild, SW_SHOW);
5911 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
5912 flush_sequence();
5913 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5914 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
5915 DestroyWindow(hchild);
5917 flush_sequence();
5918 hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
5919 0, 0, 100, 100, hparent, 0, 0, NULL);
5920 ok(hwnd != 0, "Failed to create custom dialog window\n");
5921 ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
5923 if(0) {
5924 if (winetest_debug > 1) trace("testing scroll APIs on a visible dialog %p\n", hwnd);
5925 test_scroll_messages(hwnd);
5928 flush_sequence();
5930 test_def_id = TRUE;
5931 SendMessageA(hwnd, WM_NULL, 0, 0);
5933 flush_sequence();
5934 after_end_dialog = TRUE;
5935 EndDialog( hwnd, 0 );
5936 ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
5938 DestroyWindow(hwnd);
5939 after_end_dialog = FALSE;
5940 test_def_id = FALSE;
5942 ok(GetCursorPos(&pos), "GetCursorPos failed\n");
5943 ok(SetCursorPos(109, 109), "SetCursorPos failed\n");
5945 hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP|WS_CHILD,
5946 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
5947 ok(hwnd != 0, "Failed to create custom dialog window\n");
5948 flush_sequence();
5949 if (winetest_debug > 1) trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
5950 ShowWindow(hwnd, SW_SHOW);
5951 ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
5953 flush_events();
5954 flush_sequence();
5955 ret = DrawMenuBar(hwnd);
5956 ok(ret, "DrawMenuBar failed: %ld\n", GetLastError());
5957 flush_events();
5958 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
5959 ok(SetCursorPos(pos.x, pos.y), "SetCursorPos failed\n");
5961 DestroyWindow(hwnd);
5963 hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_CHILD|WS_VISIBLE,
5964 0, 0, 100, 100, hparent, 0, GetModuleHandleA(0), NULL);
5965 ok(hwnd != 0, "Failed to create custom dialog window\n");
5966 flush_events();
5967 flush_sequence();
5968 ret = DrawMenuBar(hwnd);
5969 ok(ret, "DrawMenuBar failed: %ld\n", GetLastError());
5970 flush_events();
5971 ok_sequence(WmEmptySeq, "DrawMenuBar for a child window", FALSE);
5973 DestroyWindow(hwnd);
5975 flush_sequence();
5976 DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
5977 ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
5979 DestroyWindow(hparent);
5980 flush_sequence();
5982 /* Message sequence for SetMenu */
5983 ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a destroyed window\n");
5984 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "last error is %ld\n", GetLastError());
5985 ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
5987 hmenu = CreateMenu();
5988 ok (hmenu != 0, "Failed to create menu\n");
5989 ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
5990 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5991 100, 100, 200, 200, 0, hmenu, 0, NULL);
5992 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
5993 ok (SetMenu(hwnd, 0), "SetMenu\n");
5994 ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
5995 ok (SetMenu(hwnd, 0), "SetMenu\n");
5996 ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
5997 ShowWindow(hwnd, SW_SHOW);
5998 UpdateWindow( hwnd );
5999 flush_events();
6000 flush_sequence();
6001 ok (SetMenu(hwnd, 0), "SetMenu\n");
6002 ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
6003 ok (SetMenu(hwnd, hmenu), "SetMenu\n");
6004 ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
6006 UpdateWindow( hwnd );
6007 flush_events();
6008 flush_sequence();
6009 ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
6010 flush_events();
6011 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
6013 DestroyWindow(hwnd);
6014 flush_sequence();
6016 /* Message sequence for EnableWindow */
6017 hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6018 100, 100, 200, 200, 0, 0, 0, NULL);
6019 ok (hparent != 0, "Failed to create parent window\n");
6020 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
6021 0, 0, 10, 10, hparent, 0, 0, NULL);
6022 ok (hchild != 0, "Failed to create child window\n");
6024 SetFocus(hchild);
6025 flush_events();
6026 flush_sequence();
6028 EnableWindow(hparent, FALSE);
6029 ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
6031 EnableWindow(hparent, FALSE);
6032 ok_sequence(WmEnableWindowSeq_2, "EnableWindow(FALSE)", FALSE);
6034 EnableWindow(hparent, TRUE);
6035 ok_sequence(WmEnableWindowSeq_3, "EnableWindow(TRUE)", FALSE);
6037 EnableWindow(hparent, TRUE);
6038 ok_sequence(WmEnableWindowSeq_4, "EnableWindow(TRUE)", FALSE);
6040 flush_events();
6041 flush_sequence();
6043 test_MsgWaitForMultipleObjects(hparent);
6044 test_WM_DEVICECHANGE(hparent);
6046 /* the following test causes an exception in user.exe under win9x */
6047 if (!PostMessageW( hparent, WM_USER, 0, 0 ))
6049 DestroyWindow(hparent);
6050 flush_sequence();
6051 return;
6053 PostMessageW( hparent, WM_USER+1, 0, 0 );
6054 /* PeekMessage(NULL) fails, but still removes the message */
6055 SetLastError(0xdeadbeef);
6056 ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
6057 ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
6058 GetLastError() == 0xdeadbeef, /* NT4 */
6059 "last error is %ld\n", GetLastError() );
6060 ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
6061 ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
6063 DestroyWindow(hchild);
6064 DestroyWindow(hparent);
6065 flush_sequence();
6067 /* Message sequences for WM_SETICON */
6068 if (winetest_debug > 1) trace("testing WM_SETICON\n");
6069 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
6070 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
6071 NULL, NULL, 0);
6072 ShowWindow(hwnd, SW_SHOW);
6073 UpdateWindow(hwnd);
6074 flush_events();
6075 flush_sequence();
6076 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
6077 ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
6079 ShowWindow(hwnd, SW_HIDE);
6080 flush_events();
6081 flush_sequence();
6082 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
6083 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
6084 DestroyWindow(hwnd);
6085 flush_sequence();
6087 hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
6088 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
6089 NULL, NULL, 0);
6090 ShowWindow(hwnd, SW_SHOW);
6091 UpdateWindow(hwnd);
6092 flush_events();
6093 flush_sequence();
6094 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
6095 ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
6097 ShowWindow(hwnd, SW_HIDE);
6098 flush_events();
6099 flush_sequence();
6100 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
6101 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
6103 flush_sequence();
6104 res = SendMessageA(hwnd, 0x3B, 0x8000000b, 0);
6105 if (!res)
6107 todo_wine win_skip( "Message 0x3b not supported\n" );
6108 goto done;
6110 ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
6111 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %Id\n", res);
6112 res = SendMessageA(hwnd, 0x3B, 0x0000000b, 0);
6113 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
6114 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %Id\n", res);
6115 res = SendMessageA(hwnd, 0x3B, 0x0000000f, 0);
6116 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
6117 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %Id\n", res);
6119 flush_sequence();
6120 res = SendMessageA(hwnd, 0x3B, 0x80000008, 0);
6121 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
6122 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %Id\n", res);
6123 res = SendMessageA(hwnd, 0x3B, 0x00000008, 0);
6124 ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
6125 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %Id\n", res);
6127 res = SendMessageA(hwnd, 0x3B, 0x80000004, 0);
6128 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
6129 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %Id\n", res);
6131 res = SendMessageA(hwnd, 0x3B, 0x80000001, 0);
6132 ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
6133 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %Id\n", res);
6135 done:
6136 DestroyWindow(hwnd);
6137 flush_sequence();
6140 static const struct message WmFrameChanged[] = {
6141 { WM_WINDOWPOSCHANGING, sent|wparam|lparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE, 0 },
6142 { WM_NCCALCSIZE, sent|wparam|lparam, 1, 0xf },
6143 { WM_WINDOWPOSCHANGED, sent|wparam|lparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW
6144 |SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0xf },
6145 { WM_GETTEXT, sent|optional },
6146 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
6147 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
6148 { 0 }
6151 static const struct message WmFrameChanged_move[] = {
6152 { WM_WINDOWPOSCHANGING, sent|wparam|lparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE, 0 },
6153 { WM_NCCALCSIZE, sent|wparam|lparam, 1, 0x3 },
6154 { WM_WINDOWPOSCHANGED, sent|wparam|lparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW
6155 |SWP_NOSIZE|SWP_NOCLIENTSIZE, 0x3 },
6156 { WM_MOVE, sent|defwinproc, 0 },
6157 { WM_GETTEXT, sent|optional },
6158 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
6159 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
6160 { 0 }
6163 static void test_setwindowpos(void)
6165 HWND hwnd;
6166 RECT rc;
6167 LRESULT res;
6168 const INT X = 50;
6169 const INT Y = 50;
6170 const INT winX = 100;
6171 const INT winY = 100;
6172 const INT sysX = GetSystemMetrics(SM_CXMINTRACK);
6174 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
6175 X, Y, winX, winY, 0,
6176 NULL, NULL, 0);
6178 GetWindowRect(hwnd, &rc);
6179 expect(sysX + X, rc.right);
6180 expect(winY + Y, rc.bottom);
6182 flush_events();
6183 flush_sequence();
6184 res = SetWindowPos(hwnd, HWND_TOPMOST, 50, 50, winX, winY, 0);
6185 ok_sequence(WmZOrder, "Z-Order", TRUE);
6186 ok(res == TRUE, "SetWindowPos expected TRUE, got %Id\n", res);
6188 GetWindowRect(hwnd, &rc);
6189 expect(sysX + X, rc.right);
6190 expect(winY + Y, rc.bottom);
6192 res = SetWindowPos( hwnd, 0, 0, 0, 0, 0,
6193 SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
6194 ok_sequence(WmFrameChanged, "FrameChanged", FALSE);
6195 ok(res == TRUE, "SetWindowPos expected TRUE, got %Id.\n", res);
6197 GetWindowRect(hwnd, &rc);
6198 expect(sysX + X, rc.right);
6199 expect(winY + Y, rc.bottom);
6201 res = SetWindowPos( hwnd, 0, 0, 0, 0, 0,
6202 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
6203 ok_sequence(WmFrameChanged_move, "FrameChanged", FALSE);
6204 ok(res == TRUE, "SetWindowPos expected TRUE, got %Id.\n", res);
6206 GetWindowRect(hwnd, &rc);
6207 expect(sysX, rc.right);
6208 expect(winY, rc.bottom);
6210 DestroyWindow(hwnd);
6213 static void invisible_parent_tests(void)
6215 HWND hparent, hchild;
6217 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
6218 100, 100, 200, 200, 0, 0, 0, NULL);
6219 ok (hparent != 0, "Failed to create parent window\n");
6220 flush_sequence();
6222 /* test showing child with hidden parent */
6224 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6225 0, 0, 10, 10, hparent, 0, 0, NULL);
6226 ok (hchild != 0, "Failed to create child window\n");
6227 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
6229 ShowWindow( hchild, SW_MINIMIZE );
6230 ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
6231 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6232 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6234 /* repeat */
6235 flush_events();
6236 flush_sequence();
6237 ShowWindow( hchild, SW_MINIMIZE );
6238 ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
6240 DestroyWindow(hchild);
6241 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6242 0, 0, 10, 10, hparent, 0, 0, NULL);
6243 flush_sequence();
6245 ShowWindow( hchild, SW_MAXIMIZE );
6246 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
6247 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6248 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6250 /* repeat */
6251 flush_events();
6252 flush_sequence();
6253 ShowWindow( hchild, SW_MAXIMIZE );
6254 ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
6256 DestroyWindow(hchild);
6257 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6258 0, 0, 10, 10, hparent, 0, 0, NULL);
6259 flush_sequence();
6261 ShowWindow( hchild, SW_RESTORE );
6262 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
6263 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6264 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6266 DestroyWindow(hchild);
6267 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6268 0, 0, 10, 10, hparent, 0, 0, NULL);
6269 flush_sequence();
6271 ShowWindow( hchild, SW_SHOWMINIMIZED );
6272 ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
6273 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6274 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6276 /* repeat */
6277 flush_events();
6278 flush_sequence();
6279 ShowWindow( hchild, SW_SHOWMINIMIZED );
6280 ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
6282 DestroyWindow(hchild);
6283 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6284 0, 0, 10, 10, hparent, 0, 0, NULL);
6285 flush_sequence();
6287 /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
6288 ShowWindow( hchild, SW_SHOWMAXIMIZED );
6289 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
6290 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6291 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6293 DestroyWindow(hchild);
6294 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6295 0, 0, 10, 10, hparent, 0, 0, NULL);
6296 flush_sequence();
6298 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
6299 ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
6300 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6301 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6303 /* repeat */
6304 flush_events();
6305 flush_sequence();
6306 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
6307 ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
6309 DestroyWindow(hchild);
6310 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6311 0, 0, 10, 10, hparent, 0, 0, NULL);
6312 flush_sequence();
6314 /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
6315 ShowWindow( hchild, SW_FORCEMINIMIZE );
6316 ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
6317 todo_wine {
6318 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
6320 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6322 DestroyWindow(hchild);
6323 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6324 0, 0, 10, 10, hparent, 0, 0, NULL);
6325 flush_sequence();
6327 ShowWindow( hchild, SW_SHOWNA );
6328 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
6329 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6330 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6332 /* repeat */
6333 flush_events();
6334 flush_sequence();
6335 ShowWindow( hchild, SW_SHOWNA );
6336 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
6338 DestroyWindow(hchild);
6339 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6340 0, 0, 10, 10, hparent, 0, 0, NULL);
6341 flush_sequence();
6343 ShowWindow( hchild, SW_SHOW );
6344 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
6345 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6346 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6348 /* repeat */
6349 flush_events();
6350 flush_sequence();
6351 ShowWindow( hchild, SW_SHOW );
6352 ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
6354 ShowWindow( hchild, SW_HIDE );
6355 ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
6356 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
6357 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6359 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
6360 ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
6361 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6362 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6364 SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
6365 ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
6366 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
6367 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6369 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
6370 flush_sequence();
6371 DestroyWindow(hchild);
6372 ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
6374 DestroyWindow(hparent);
6375 flush_sequence();
6378 /****************** button message test *************************/
6379 #define ID_BUTTON 0x000e
6381 static const struct message WmSetFocusButtonSeq[] =
6383 { HCBT_SETFOCUS, hook },
6384 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
6385 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
6386 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6387 { WM_SETFOCUS, sent|wparam, 0 },
6388 { WM_CTLCOLORBTN, sent|parent },
6389 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
6390 { WM_APP, sent|wparam|lparam, 0, 0 },
6391 { 0 }
6393 static const struct message WmKillFocusButtonSeq[] =
6395 { HCBT_SETFOCUS, hook },
6396 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
6397 { WM_KILLFOCUS, sent|wparam, 0 },
6398 { WM_CTLCOLORBTN, sent|parent },
6399 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
6400 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
6401 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
6402 { WM_APP, sent|wparam|lparam, 0, 0 },
6403 { WM_PAINT, sent },
6404 { WM_CTLCOLORBTN, sent|parent },
6405 { 0 }
6407 static const struct message WmSetFocusStaticSeq[] =
6409 { HCBT_SETFOCUS, hook },
6410 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
6411 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
6412 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6413 { WM_SETFOCUS, sent|wparam, 0 },
6414 { WM_CTLCOLORSTATIC, sent|parent },
6415 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
6416 { WM_COMMAND, sent|wparam|parent|optional, MAKEWPARAM(ID_BUTTON, BN_CLICKED) }, /* radio button */
6417 { WM_APP, sent|wparam|lparam, 0, 0 },
6418 { 0 }
6420 static const struct message WmKillFocusStaticSeq[] =
6422 { HCBT_SETFOCUS, hook },
6423 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
6424 { WM_KILLFOCUS, sent|wparam, 0 },
6425 { WM_CTLCOLORSTATIC, sent|parent },
6426 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
6427 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
6428 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
6429 { WM_APP, sent|wparam|lparam, 0, 0 },
6430 { WM_PAINT, sent },
6431 { WM_CTLCOLORSTATIC, sent|parent },
6432 { 0 }
6434 static const struct message WmSetFocusOwnerdrawSeq[] =
6436 { HCBT_SETFOCUS, hook },
6437 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
6438 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
6439 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6440 { WM_SETFOCUS, sent|wparam, 0 },
6441 { WM_CTLCOLORBTN, sent|parent },
6442 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x001040e4 },
6443 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
6444 { WM_APP, sent|wparam|lparam, 0, 0 },
6445 { 0 }
6447 static const struct message WmKillFocusOwnerdrawSeq[] =
6449 { HCBT_SETFOCUS, hook },
6450 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
6451 { WM_KILLFOCUS, sent|wparam, 0 },
6452 { WM_CTLCOLORBTN, sent|parent },
6453 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000040e4 },
6454 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
6455 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
6456 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
6457 { WM_APP, sent|wparam|lparam, 0, 0 },
6458 { WM_PAINT, sent },
6459 { WM_CTLCOLORBTN, sent|parent },
6460 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
6461 { 0 }
6463 static const struct message WmLButtonDownSeq[] =
6465 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
6466 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
6467 { HCBT_SETFOCUS, hook },
6468 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
6469 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
6470 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6471 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
6472 { WM_CTLCOLORBTN, sent|defwinproc },
6473 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
6474 { WM_CTLCOLORBTN, sent|defwinproc },
6475 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
6476 { 0 }
6478 static const struct message WmLButtonDownStaticSeq[] =
6480 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
6481 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
6482 { HCBT_SETFOCUS, hook },
6483 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
6484 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
6485 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6486 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
6487 { WM_CTLCOLORSTATIC, sent|defwinproc },
6488 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
6489 { WM_CTLCOLORSTATIC, sent|defwinproc },
6490 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
6491 { 0 }
6493 static const struct message WmLButtonUpSeq[] =
6495 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6496 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6497 { WM_CTLCOLORBTN, sent|defwinproc },
6498 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
6499 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
6500 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6501 { 0 }
6503 static const struct message WmLButtonUpStaticSeq[] =
6505 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6506 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6507 { WM_CTLCOLORSTATIC, sent|defwinproc },
6508 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
6509 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
6510 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6511 { 0 }
6513 static const struct message WmLButtonUpAutoSeq[] =
6515 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6516 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6517 { WM_CTLCOLORSTATIC, sent|defwinproc },
6518 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
6519 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|optional, 0, 0 },
6520 { BM_SETCHECK, sent|defwinproc },
6521 { WM_CTLCOLORSTATIC, sent|defwinproc|optional, 0, 0 }, /* Sent here on Win7. */
6522 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
6523 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
6524 { WM_CTLCOLORSTATIC, sent|defwinproc|optional, 0, 0 }, /* Sent here on Win8+. */
6525 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6526 { 0 }
6528 static const struct message WmLButtonUpBrokenSeq[] =
6530 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6531 { 0 }
6533 static const struct message WmSetFontButtonSeq[] =
6535 { WM_SETFONT, sent },
6536 { WM_PAINT, sent },
6537 { WM_ERASEBKGND, sent|defwinproc|optional },
6538 { WM_CTLCOLORBTN, sent|defwinproc },
6539 { 0 }
6541 static const struct message WmSetFontOwnerdrawSeq[] =
6543 { WM_SETFONT, sent },
6544 { WM_PAINT, sent },
6545 { WM_ERASEBKGND, sent|defwinproc|optional },
6546 { WM_CTLCOLORBTN, sent|defwinproc },
6547 { WM_CTLCOLORBTN, sent|defwinproc|wine_only }, /* FIXME: Wine sends it twice for BS_OWNERDRAW */
6548 { 0 }
6550 static const struct message WmSetFontStaticSeq[] =
6552 { WM_SETFONT, sent },
6553 { WM_PAINT, sent },
6554 { WM_ERASEBKGND, sent|defwinproc|optional },
6555 { WM_CTLCOLORSTATIC, sent|defwinproc },
6556 { 0 }
6558 static const struct message WmSetTextButtonSeq[] =
6560 { WM_SETTEXT, sent },
6561 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
6562 { WM_CTLCOLORBTN, sent|parent },
6563 { WM_CTLCOLORBTN, sent|parent },
6564 { WM_COMMAND, sent|parent|optional },
6565 { WM_DRAWITEM, sent|parent|optional },
6566 { 0 }
6568 static const struct message WmSetTextStaticSeq[] =
6570 { WM_SETTEXT, sent },
6571 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
6572 { WM_CTLCOLORSTATIC, sent|parent },
6573 { WM_CTLCOLORSTATIC, sent|parent },
6574 { 0 }
6576 static const struct message WmSetTextGroupSeq[] =
6578 { WM_SETTEXT, sent },
6579 { WM_CTLCOLORSTATIC, sent|parent },
6580 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
6581 { WM_CTLCOLORSTATIC, sent|parent|msg_todo }, /* FIXME: Missing in Wine */
6582 { WM_CTLCOLORSTATIC, sent|parent|msg_todo }, /* FIXME: Missing in Wine */
6583 { 0 }
6585 static const struct message WmSetTextInvisibleSeq[] =
6587 { WM_SETTEXT, sent },
6588 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
6589 { 0 }
6591 static const struct message WmSetStyleButtonSeq[] =
6593 { BM_SETSTYLE, sent },
6594 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
6595 { WM_APP, sent|wparam|lparam, 0, 0 },
6596 { WM_PAINT, sent },
6597 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6598 { WM_CTLCOLORBTN, sent|parent },
6599 { 0 }
6601 static const struct message WmSetStyleStaticSeq[] =
6603 { BM_SETSTYLE, sent },
6604 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
6605 { WM_APP, sent|wparam|lparam, 0, 0 },
6606 { WM_PAINT, sent },
6607 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6608 { WM_CTLCOLORSTATIC, sent|parent },
6609 { 0 }
6611 static const struct message WmSetStyleUserSeq[] =
6613 { BM_SETSTYLE, sent },
6614 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
6615 { WM_APP, sent|wparam|lparam, 0, 0 },
6616 { WM_PAINT, sent },
6617 { WM_NCPAINT, sent|defwinproc|wine_only }, /* FIXME: Wine sends it */
6618 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6619 { WM_CTLCOLORBTN, sent|parent },
6620 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_PAINT) },
6621 { 0 }
6623 static const struct message WmSetStyleOwnerdrawSeq[] =
6625 { BM_SETSTYLE, sent },
6626 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
6627 { WM_APP, sent|wparam|lparam, 0, 0 },
6628 { WM_PAINT, sent },
6629 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6630 { WM_CTLCOLORBTN, sent|parent },
6631 { WM_CTLCOLORBTN, sent|parent|optional }, /* Win9x doesn't send it */
6632 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
6633 { 0 }
6635 static const struct message WmSetStateButtonSeq[] =
6637 { BM_SETSTATE, sent },
6638 { WM_CTLCOLORBTN, sent|parent },
6639 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
6640 { WM_APP, sent|wparam|lparam, 0, 0 },
6641 { 0 }
6643 static const struct message WmSetStateStaticSeq[] =
6645 { BM_SETSTATE, sent },
6646 { WM_CTLCOLORSTATIC, sent|parent },
6647 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
6648 { WM_APP, sent|wparam|lparam, 0, 0 },
6649 { 0 }
6651 static const struct message WmSetStateUserSeq[] =
6653 { BM_SETSTATE, sent },
6654 { WM_CTLCOLORBTN, sent|parent },
6655 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_HILITE) },
6656 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
6657 { WM_APP, sent|wparam|lparam, 0, 0 },
6658 { 0 }
6660 static const struct message WmSetStateOwnerdrawSeq[] =
6662 { BM_SETSTATE, sent },
6663 { WM_CTLCOLORBTN, sent|parent },
6664 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000120e4 },
6665 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
6666 { WM_APP, sent|wparam|lparam, 0, 0 },
6667 { 0 }
6669 static const struct message WmClearStateButtonSeq[] =
6671 { BM_SETSTATE, sent },
6672 { WM_CTLCOLORBTN, sent|parent },
6673 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_UNHILITE) },
6674 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
6675 { WM_APP, sent|wparam|lparam, 0, 0 },
6676 { 0 }
6678 static const struct message WmDisableButtonSeq[] =
6680 { WM_LBUTTONDOWN, sent },
6681 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
6682 { BM_SETSTATE, sent|defwinproc },
6683 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6684 { WM_CTLCOLORBTN, sent|optional },
6685 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
6686 { WM_LBUTTONUP, sent },
6687 { BM_SETSTATE, sent|defwinproc },
6688 { WM_CTLCOLORBTN, sent|defwinproc|optional },
6689 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6690 { BM_SETCHECK, sent|defwinproc|optional },
6691 { WM_CTLCOLORBTN, sent|optional },
6692 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
6693 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
6694 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6695 { WM_CAPTURECHANGED, sent|defwinproc },
6696 { WM_COMMAND, sent },
6697 { 0 }
6699 static const struct message WmClearStateOwnerdrawSeq[] =
6701 { BM_SETSTATE, sent },
6702 { WM_CTLCOLORBTN, sent|parent },
6703 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000020e4 },
6704 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
6705 { WM_APP, sent|wparam|lparam, 0, 0 },
6706 { 0 }
6708 static const struct message WmSetCheckIgnoredSeq[] =
6710 { BM_SETCHECK, sent },
6711 { WM_APP, sent|wparam|lparam, 0, 0 },
6712 { 0 }
6714 static const struct message WmSetCheckStaticSeq[] =
6716 { BM_SETCHECK, sent },
6717 { WM_CTLCOLORSTATIC, sent|parent },
6718 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
6719 { WM_APP, sent|wparam|lparam, 0, 0 },
6720 { 0 }
6723 static WNDPROC old_button_proc;
6725 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6727 static LONG defwndproc_counter = 0;
6728 LRESULT ret;
6729 struct recvd_message msg;
6731 if (ignore_message( message )) return 0;
6733 switch (message)
6735 case WM_SYNCPAINT:
6736 break;
6737 case BM_SETSTATE:
6738 if (GetCapture())
6739 ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
6741 lParam = (ULONG_PTR)GetMenu(hwnd);
6742 goto log_it;
6744 case WM_GETDLGCODE:
6745 if (lParam)
6747 MSG *msg = (MSG *)lParam;
6748 lParam = MAKELPARAM(msg->message, msg->wParam);
6750 wParam = (ULONG_PTR)GetMenu(hwnd);
6751 goto log_it;
6753 case BM_SETCHECK:
6754 case BM_GETCHECK:
6755 lParam = (ULONG_PTR)GetMenu(hwnd);
6756 /* fall through */
6757 log_it:
6758 default:
6759 msg.hwnd = hwnd;
6760 msg.message = message;
6761 msg.flags = sent|wparam|lparam;
6762 if (defwndproc_counter) msg.flags |= defwinproc;
6763 msg.wParam = wParam;
6764 msg.lParam = lParam;
6765 msg.descr = "button";
6766 add_message(&msg);
6769 defwndproc_counter++;
6770 ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
6771 defwndproc_counter--;
6773 return ret;
6776 static void subclass_button(void)
6778 WNDCLASSA cls;
6779 BOOL ret;
6781 ret = GetClassInfoA(0, "button", &cls);
6782 ok(ret, "Failed to get class info, error %lu.\n", GetLastError());
6784 old_button_proc = cls.lpfnWndProc;
6786 cls.hInstance = GetModuleHandleA(NULL);
6787 cls.lpfnWndProc = button_hook_proc;
6788 cls.lpszClassName = "my_button_class";
6789 UnregisterClassA(cls.lpszClassName, cls.hInstance);
6790 register_class(&cls);
6793 static void test_button_messages(void)
6795 static const struct
6797 DWORD style;
6798 DWORD dlg_code;
6799 const struct message *setfocus;
6800 const struct message *killfocus;
6801 const struct message *setstyle;
6802 const struct message *setstate;
6803 const struct message *clearstate;
6804 const struct message *setcheck;
6805 const struct message *lbuttondown;
6806 const struct message *lbuttonup;
6807 const struct message *setfont;
6808 const struct message *settext;
6809 } button[] = {
6810 { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
6811 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
6812 WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq,
6813 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6814 WmSetTextButtonSeq },
6815 { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
6816 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
6817 WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq,
6818 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6819 WmSetTextButtonSeq },
6820 { BS_CHECKBOX, DLGC_BUTTON,
6821 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6822 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6823 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6824 WmSetTextStaticSeq },
6825 { BS_AUTOCHECKBOX, DLGC_BUTTON,
6826 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6827 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6828 WmLButtonDownStaticSeq, WmLButtonUpAutoSeq, WmSetFontStaticSeq,
6829 WmSetTextStaticSeq },
6830 { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
6831 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6832 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6833 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6834 WmSetTextStaticSeq },
6835 { BS_3STATE, DLGC_BUTTON,
6836 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6837 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6838 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6839 WmSetTextStaticSeq },
6840 { BS_AUTO3STATE, DLGC_BUTTON,
6841 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6842 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6843 WmLButtonDownStaticSeq, WmLButtonUpAutoSeq, WmSetFontStaticSeq,
6844 WmSetTextStaticSeq },
6845 { BS_GROUPBOX, DLGC_STATIC,
6846 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6847 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckIgnoredSeq,
6848 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6849 WmSetTextGroupSeq },
6850 { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
6851 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleUserSeq,
6852 WmSetStateUserSeq, WmClearStateButtonSeq, WmSetCheckIgnoredSeq,
6853 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6854 WmSetTextButtonSeq },
6855 { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
6856 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6857 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6858 NULL /* avoid infinite loop */, WmLButtonUpBrokenSeq, WmSetFontStaticSeq,
6859 WmSetTextStaticSeq },
6860 { BS_OWNERDRAW, DLGC_BUTTON,
6861 WmSetFocusOwnerdrawSeq, WmKillFocusOwnerdrawSeq, WmSetStyleOwnerdrawSeq,
6862 WmSetStateOwnerdrawSeq, WmClearStateOwnerdrawSeq, WmSetCheckIgnoredSeq,
6863 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontOwnerdrawSeq,
6864 WmSetTextButtonSeq },
6866 LOGFONTA logfont = { 0 };
6867 HFONT zfont, hfont2;
6868 unsigned int i;
6869 HWND hwnd, parent;
6870 DWORD dlg_code;
6872 /* selection with VK_SPACE should capture button window */
6873 hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
6874 0, 0, 50, 14, 0, 0, 0, NULL);
6875 ok(hwnd != 0, "Failed to create button window\n");
6876 ReleaseCapture();
6877 SetFocus(hwnd);
6878 SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
6879 ok(GetCapture() == hwnd, "Should be captured on VK_SPACE WM_KEYDOWN\n");
6880 SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
6881 DestroyWindow(hwnd);
6883 subclass_button();
6885 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6886 100, 100, 200, 200, 0, 0, 0, NULL);
6887 ok(parent != 0, "Failed to create parent window\n");
6889 memset(&logfont, 0, sizeof(logfont));
6890 logfont.lfHeight = -12;
6891 logfont.lfWeight = FW_NORMAL;
6892 strcpy(logfont.lfFaceName, "Tahoma");
6894 hfont2 = CreateFontIndirectA(&logfont);
6895 ok(hfont2 != NULL, "Failed to create Tahoma font\n");
6897 for (i = 0; i < ARRAY_SIZE(button); i++)
6899 MSG msg;
6900 DWORD style, state;
6901 HFONT prevfont;
6902 char desc[64];
6903 HDC hdc;
6905 if (winetest_debug > 1) trace("button style %08lx\n", button[i].style);
6907 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_CHILD | BS_NOTIFY,
6908 0, 0, 50, 14, parent, (HMENU)ID_BUTTON, 0, NULL);
6909 ok(hwnd != 0, "Failed to create button window\n");
6911 style = GetWindowLongA(hwnd, GWL_STYLE);
6912 style &= ~(WS_CHILD | BS_NOTIFY);
6913 /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
6914 if (button[i].style == BS_USERBUTTON)
6915 ok(style == BS_PUSHBUTTON, "expected style BS_PUSHBUTTON got %lx\n", style);
6916 else
6917 ok(style == button[i].style, "expected style %lx got %lx\n", button[i].style, style);
6919 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
6920 ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08lx\n", i, dlg_code);
6922 ShowWindow(hwnd, SW_SHOW);
6923 UpdateWindow(hwnd);
6924 SetFocus(0);
6925 flush_events();
6926 SetFocus(0);
6927 flush_sequence();
6929 log_all_parent_messages++;
6931 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
6932 SetFocus(hwnd);
6933 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6934 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6935 ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
6937 SetFocus(0);
6938 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6939 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6940 ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
6942 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
6944 SendMessageA(hwnd, BM_SETSTYLE, button[i].style | BS_BOTTOM, TRUE);
6945 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6946 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6947 ok_sequence(button[i].setstyle, "BM_SETSTYLE on a button", FALSE);
6949 style = GetWindowLongA(hwnd, GWL_STYLE);
6950 style &= ~(WS_VISIBLE | WS_CHILD | BS_NOTIFY);
6951 /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */
6952 ok(style == button[i].style, "expected style %04lx got %04lx\n", button[i].style, style);
6954 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6955 ok(state == 0, "expected state 0, got %04lx\n", state);
6957 flush_sequence();
6959 SendMessageA(hwnd, BM_SETSTATE, TRUE, 0);
6960 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6961 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6962 ok_sequence(button[i].setstate, "BM_SETSTATE/TRUE on a button", FALSE);
6964 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6965 ok(state == 0x0004, "expected state 0x0004, got %04lx\n", state);
6967 style = GetWindowLongA(hwnd, GWL_STYLE);
6968 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6969 ok(style == button[i].style, "expected style %04lx got %04lx\n", button[i].style, style);
6971 flush_sequence();
6973 SendMessageA(hwnd, BM_SETSTATE, FALSE, 0);
6974 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6975 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6976 ok_sequence(button[i].clearstate, "BM_SETSTATE/FALSE on a button", FALSE);
6978 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6979 ok(state == 0, "expected state 0, got %04lx\n", state);
6981 style = GetWindowLongA(hwnd, GWL_STYLE);
6982 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6983 ok(style == button[i].style, "expected style %04lx got %04lx\n", button[i].style, style);
6985 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6986 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04lx\n", state);
6988 flush_sequence();
6990 SendMessageA(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
6991 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6992 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6993 ok_sequence(WmSetCheckIgnoredSeq, "BM_SETCHECK on a button", FALSE);
6995 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6996 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04lx\n", state);
6998 style = GetWindowLongA(hwnd, GWL_STYLE);
6999 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
7000 ok(style == button[i].style, "expected style %04lx got %04lx\n", button[i].style, style);
7002 flush_sequence();
7004 SendMessageA(hwnd, BM_SETCHECK, BST_CHECKED, 0);
7005 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
7006 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7007 ok_sequence(button[i].setcheck, "BM_SETCHECK on a button", FALSE);
7009 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 1");
7010 sprintf(desc, "button[%i]: WM_SETTEXT on a visible button", i);
7011 ok_sequence(button[i].settext, desc, FALSE);
7013 ShowWindow(hwnd, SW_HIDE);
7014 flush_events();
7015 flush_sequence();
7017 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 2");
7018 sprintf(desc, "button[%i]: WM_SETTEXT on an invisible button", i);
7019 ok_sequence(WmSetTextInvisibleSeq, desc, FALSE);
7021 ShowWindow(hwnd, SW_SHOW);
7022 ShowWindow(parent, SW_HIDE);
7023 flush_events();
7024 flush_sequence();
7026 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 3");
7027 sprintf(desc, "button[%i]: WM_SETTEXT on an invisible button", i);
7028 ok_sequence(WmSetTextInvisibleSeq, desc, FALSE);
7030 ShowWindow(parent, SW_SHOW);
7031 flush_events();
7033 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
7034 if (button[i].style == BS_PUSHBUTTON ||
7035 button[i].style == BS_DEFPUSHBUTTON ||
7036 button[i].style == BS_GROUPBOX ||
7037 button[i].style == BS_USERBUTTON ||
7038 button[i].style == BS_OWNERDRAW)
7039 ok(state == BST_UNCHECKED, "expected check 0, got %04lx\n", state);
7040 else
7041 ok(state == BST_CHECKED, "expected check 1, got %04lx\n", state);
7043 style = GetWindowLongA(hwnd, GWL_STYLE);
7044 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
7045 if (button[i].style == BS_RADIOBUTTON ||
7046 button[i].style == BS_AUTORADIOBUTTON)
7047 ok(style == (button[i].style | WS_TABSTOP), "expected style %04lx | WS_TABSTOP got %04lx\n", button[i].style, style);
7048 else
7049 ok(style == button[i].style, "expected style %04lx got %04lx\n", button[i].style, style);
7051 log_all_parent_messages--;
7053 DestroyWindow(hwnd);
7055 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP | WS_VISIBLE,
7056 0, 0, 50, 14, 0, 0, 0, NULL);
7057 ok(hwnd != 0, "Failed to create button window\n");
7059 SetForegroundWindow(hwnd);
7060 flush_events();
7062 SetActiveWindow(hwnd);
7063 SetFocus(0);
7064 flush_sequence();
7066 if (button[i].lbuttondown)
7068 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
7069 sprintf(desc, "button[%i]: WM_LBUTTONDOWN on a button", i);
7070 ok_sequence(button[i].lbuttondown, desc, FALSE);
7073 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
7074 sprintf(desc, "button[%i]: WM_LBUTTONUP on a button", i);
7075 ok_sequence(button[i].lbuttonup, desc, FALSE);
7077 flush_sequence();
7078 zfont = GetStockObject(DEFAULT_GUI_FONT);
7079 SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
7080 UpdateWindow(hwnd);
7081 sprintf(desc, "button[%i]: WM_SETFONT on a button", i);
7082 ok_sequence(button[i].setfont, desc, FALSE);
7084 /* Test that original font is not selected back after painting */
7085 hdc = CreateCompatibleDC(0);
7087 prevfont = SelectObject(hdc, hfont2);
7088 ok(prevfont == GetStockObject(SYSTEM_FONT), "Unexpected default font\n");
7089 SendMessageA(hwnd, WM_PRINTCLIENT, (WPARAM)hdc, 0);
7090 ok(hfont2 != GetCurrentObject(hdc, OBJ_FONT), "button[%u]: unexpected font selected after WM_PRINTCLIENT\n", i);
7091 SelectObject(hdc, prevfont);
7093 prevfont = SelectObject(hdc, hfont2);
7094 ok(prevfont == GetStockObject(SYSTEM_FONT), "Unexpected default font\n");
7095 SendMessageA(hwnd, WM_PAINT, (WPARAM)hdc, 0);
7096 ok(hfont2 != GetCurrentObject(hdc, OBJ_FONT), "button[%u]: unexpected font selected after WM_PAINT\n", i);
7097 SelectObject(hdc, prevfont);
7099 DeleteDC(hdc);
7101 DestroyWindow(hwnd);
7104 DeleteObject(hfont2);
7105 DestroyWindow(parent);
7107 /* Test if WM_LBUTTONDOWN and WM_LBUTTONUP to a disabled button leads to a WM_COMMAND for the parent */
7109 parent = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7110 100, 100, 200, 200, 0, 0, 0, NULL);
7111 ok (hwnd != 0, "Failed to create overlapped window\n");
7113 hwnd = CreateWindowExA(0, "my_button_class", "test", BS_DEFPUSHBUTTON | WS_VISIBLE | WS_CHILD,
7114 0, 0, 50, 14, parent, 0, 0, NULL);
7116 EnableWindow(hwnd, FALSE);
7117 flush_sequence();
7118 SendMessageA(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, 0);
7119 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
7120 ok_sequence(WmDisableButtonSeq, "Mouseclick on a disabled button", FALSE);
7122 DestroyWindow(hwnd);
7123 DestroyWindow(parent);
7126 static void test_button_bm_get_set_image(void)
7128 HWND hwnd;
7129 HDC hdc;
7130 HBITMAP hbmp1x1;
7131 HBITMAP hbmp2x2;
7132 HBITMAP hmask2x2;
7133 ICONINFO icon_info2x2;
7134 HICON hicon2x2;
7135 HBITMAP hbmp;
7136 HICON hicon;
7137 ICONINFO icon_info;
7138 BITMAP bm;
7139 DWORD default_style = BS_PUSHBUTTON | WS_TABSTOP | WS_POPUP | WS_VISIBLE;
7140 LRESULT ret;
7142 hdc = GetDC(0);
7143 hbmp1x1 = CreateCompatibleBitmap(hdc, 1, 1);
7144 hbmp2x2 = CreateCompatibleBitmap(hdc, 2, 2);
7145 ZeroMemory(&bm, sizeof(bm));
7146 ok(GetObjectW(hbmp1x1, sizeof(bm), &bm), "Expect GetObjectW() success\n");
7147 ok(bm.bmWidth == 1 && bm.bmHeight == 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
7148 bm.bmWidth, bm.bmHeight);
7149 ZeroMemory(&bm, sizeof(bm));
7150 ok(GetObjectW(hbmp2x2, sizeof(bm), &bm), "Expect GetObjectW() success\n");
7151 ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
7152 bm.bmWidth, bm.bmHeight);
7154 hmask2x2 = CreateCompatibleBitmap(hdc, 2, 2);
7155 ZeroMemory(&icon_info2x2, sizeof(icon_info2x2));
7156 icon_info2x2.fIcon = TRUE;
7157 icon_info2x2.hbmMask = hmask2x2;
7158 icon_info2x2.hbmColor = hbmp2x2;
7159 hicon2x2 = CreateIconIndirect(&icon_info2x2);
7161 ZeroMemory(&icon_info, sizeof(icon_info));
7162 ok(GetIconInfo(hicon2x2, &icon_info), "Expect GetIconInfo() success\n");
7163 ZeroMemory(&bm, sizeof(bm));
7164 ok(GetObjectW(icon_info.hbmColor, sizeof(bm), &bm), "Expect GetObjectW() success\n");
7165 ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
7166 bm.bmWidth, bm.bmHeight);
7167 DeleteObject(icon_info.hbmColor);
7168 DeleteObject(icon_info.hbmMask);
7170 /* Set bitmap with BS_BITMAP */
7171 hwnd = CreateWindowA("Button", "test", default_style | BS_BITMAP, 0, 0, 100, 100, 0, 0, 0, 0);
7172 ok(hwnd != NULL, "Expect hwnd not NULL\n");
7173 SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp1x1);
7174 hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_BITMAP, 0);
7175 ok(hbmp != 0, "Expect hbmp not 0\n");
7176 ZeroMemory(&bm, sizeof(bm));
7177 ok(GetObjectW(hbmp, sizeof(bm), &bm), "Expect GetObjectW() success\n");
7178 ok(bm.bmWidth == 1 && bm.bmHeight == 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
7179 bm.bmWidth, bm.bmHeight);
7180 DestroyWindow(hwnd);
7182 /* Set bitmap without BS_BITMAP */
7183 hwnd = CreateWindowA("Button", "test", default_style, 0, 0, 100, 100, 0, 0, 0, 0);
7184 ok(hwnd != NULL, "Expect hwnd not NULL\n");
7185 ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp1x1);
7186 ok(ret == 0, "Expect ret to be 0\n");
7187 hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_BITMAP, 0);
7188 ok(hbmp == NULL, "Expect hbmp to be NULL\n");
7189 DestroyWindow(hwnd);
7191 /* Set icon with BS_ICON */
7192 hwnd = CreateWindowA("Button", "test", default_style | BS_ICON, 0, 0, 100, 100, 0, 0, 0, 0);
7193 ok(hwnd != NULL, "Expect hwnd not NULL\n");
7194 SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicon2x2);
7195 hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_ICON, 0);
7196 ok(hicon != NULL, "Expect hicon not NULL\n");
7197 ZeroMemory(&icon_info, sizeof(icon_info));
7198 ok(GetIconInfo(hicon, &icon_info), "Expect GetIconInfo() success\n");
7199 ZeroMemory(&bm, sizeof(bm));
7200 ok(GetObjectW(icon_info.hbmColor, sizeof(bm), &bm), "Expect GetObjectW() success\n");
7201 ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
7202 bm.bmWidth, bm.bmHeight);
7203 DeleteObject(icon_info.hbmColor);
7204 DeleteObject(icon_info.hbmMask);
7205 DestroyWindow(hwnd);
7207 /* Set icon without BS_ICON */
7208 hwnd = CreateWindowA("Button", "test", default_style, 0, 0, 100, 100, 0, 0, 0, 0);
7209 ok(hwnd != NULL, "Expect hwnd not NULL\n");
7210 ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicon2x2);
7211 ok(ret == 0, "Expect ret to be 0\n");
7212 hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_ICON, 0);
7213 ok(hicon == NULL, "Expect hicon to be NULL\n");
7214 DestroyWindow(hwnd);
7216 /* Set icon with BS_BITMAP */
7217 hwnd = CreateWindowA("Button", "test", default_style | BS_BITMAP, 0, 0, 100, 100, 0, 0, 0, 0);
7218 ok(hwnd != NULL, "Expect hwnd to be not NULL\n");
7219 ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicon2x2);
7220 ok(ret == 0, "Expect ret to be 0\n");
7221 hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_ICON, 0);
7222 ok(hicon == NULL, "Expect hicon to be NULL\n");
7223 DestroyWindow(hwnd);
7225 /* Set bitmap with BS_ICON */
7226 hwnd = CreateWindowA("Button", "test", default_style | BS_ICON, 0, 0, 100, 100, 0, 0, 0, 0);
7227 ok(hwnd != NULL, "Expect hwnd to be not NULL\n");
7228 ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp1x1);
7229 ok(ret == 0, "Expect ret to be 0\n");
7230 hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_BITMAP, 0);
7231 ok(hbmp == NULL, "Expect hbmp to be NULL\n");
7232 DestroyWindow(hwnd);
7234 DestroyIcon(hicon2x2);
7235 DeleteObject(hmask2x2);
7236 DeleteObject(hbmp2x2);
7237 DeleteObject(hbmp1x1);
7238 ReleaseDC(0, hdc);
7241 #define ID_RADIO1 501
7242 #define ID_RADIO2 502
7243 #define ID_RADIO3 503
7244 #define ID_TEXT 504
7246 static const struct message auto_radio_button_BM_CLICK[] =
7248 { BM_CLICK, sent|wparam|lparam, 0, 0 },
7249 { WM_LBUTTONDOWN, sent|wparam|lparam|defwinproc, 0, 0 },
7250 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
7251 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO2 },
7252 { WM_CTLCOLORSTATIC, sent|parent },
7253 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
7254 { WM_LBUTTONUP, sent|wparam|lparam|defwinproc, 0, 0 },
7255 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO2 },
7256 { WM_CTLCOLORSTATIC, sent|parent },
7257 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
7258 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO2, 0 },
7259 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO2 },
7260 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO1, 0 },
7261 { BM_SETCHECK, sent|wparam|lparam|defwinproc, 0, ID_RADIO1 },
7262 { WM_CTLCOLORSTATIC, sent|parent },
7263 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
7264 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO3, 0 },
7265 { BM_SETCHECK, sent|wparam|lparam|defwinproc, 0, ID_RADIO3 },
7266 { WM_CTLCOLORSTATIC, sent|parent },
7267 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
7268 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_TEXT, 0 },
7269 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
7270 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
7271 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO2, BN_CLICKED) },
7272 { WM_NCHITTEST, sent|optional, 0, 0 },
7273 { WM_SETCURSOR, sent|optional, 0, 0 },
7274 { WM_MOUSEMOVE, sent|optional, 0, 0 },
7275 { 0 }
7278 static const struct message auto_radio_button_VK_UP_child[] =
7280 { WM_KEYDOWN, sent|wparam|lparam, VK_UP, 0 },
7281 { WM_KEYUP, sent|wparam|lparam, VK_UP, 0 },
7282 { 0 }
7285 static const struct message auto_radio_button_VK_UP_parent[] =
7287 { WM_KEYDOWN, sent|wparam|lparam|parent, VK_UP, 0 },
7288 { WM_KEYUP, sent|wparam|lparam|parent, VK_UP, 0 },
7289 { 0 }
7292 static const struct message auto_radio_button_VK_UP_dialog[] =
7294 { WM_GETDLGCODE, sent|parent, 0, 0 },
7296 /* optional trailer seen on some windows setups */
7297 { WM_CHANGEUISTATE, sent|optional },
7298 { WM_UPDATEUISTATE, sent|optional },
7299 { WM_UPDATEUISTATE, sent|optional },
7300 { WM_UPDATEUISTATE, sent|optional },
7301 { WM_UPDATEUISTATE, sent|optional },
7302 { WM_UPDATEUISTATE, sent|optional },
7303 { WM_UPDATEUISTATE, sent|optional },
7304 { WM_UPDATEUISTATE, sent|optional },
7305 { WM_UPDATEUISTATE, sent|optional },
7306 { WM_UPDATEUISTATE, sent|optional },
7307 { WM_UPDATEUISTATE, sent|optional },
7308 { WM_UPDATEUISTATE, sent|optional },
7309 { WM_UPDATEUISTATE, sent|optional },
7310 { WM_UPDATEUISTATE, sent|optional },
7311 { WM_UPDATEUISTATE, sent|optional },
7312 { WM_UPDATEUISTATE, sent|optional },
7313 { WM_UPDATEUISTATE, sent|optional },
7314 { WM_UPDATEUISTATE, sent|optional },
7315 { WM_UPDATEUISTATE, sent|optional },
7316 { WM_CTLCOLORSTATIC, sent|parent|optional },
7317 { WM_CTLCOLORSTATIC, sent|parent|optional },
7318 { WM_CTLCOLORSTATIC, sent|parent|optional },
7319 { WM_UPDATEUISTATE, sent|optional },
7320 { WM_CTLCOLORSTATIC, sent|parent|optional },
7321 { WM_CTLCOLORSTATIC, sent|parent|optional },
7322 { WM_UPDATEUISTATE, sent|optional },
7323 { WM_CTLCOLORBTN, sent|parent|optional },
7324 { WM_CTLCOLORBTN, sent|parent|optional },
7325 { WM_UPDATEUISTATE, sent|optional },
7326 { WM_CTLCOLORSTATIC, sent|parent|optional },
7327 { WM_CTLCOLORSTATIC, sent|parent|optional },
7328 { 0 }
7331 static const struct message auto_radio_button_VK_DOWN_dialog[] =
7333 { WM_GETDLGCODE, sent|parent, 0, 0 },
7334 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, MAKELPARAM(WM_KEYDOWN, VK_DOWN) },
7335 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
7336 { HCBT_SETFOCUS, hook },
7337 { WM_KILLFOCUS, sent, 0, 0 },
7338 { WM_CTLCOLORSTATIC, sent|parent },
7339 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO3, BN_KILLFOCUS) },
7340 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7341 { WM_SETFOCUS, sent, 0, 0 },
7342 { WM_CTLCOLORSTATIC, sent|parent },
7343 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_SETFOCUS) },
7344 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_CLICKED) },
7345 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
7346 { WM_GETDLGCODE, sent|parent, 0, 0 },
7347 { DM_GETDEFID, sent|parent, 0, 0 },
7348 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
7349 { BM_CLICK, sent|wparam|lparam, 1, 0 },
7350 { WM_LBUTTONDOWN, sent|wparam|lparam|defwinproc, 0, 0 },
7351 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
7352 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO1 },
7353 { WM_CTLCOLORSTATIC, sent|parent },
7354 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
7355 { WM_LBUTTONUP, sent|wparam|lparam|defwinproc, 0, 0 },
7356 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO1 },
7357 { WM_CTLCOLORSTATIC, sent|parent },
7358 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
7359 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO1, 0 },
7360 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO1 },
7361 { WM_CTLCOLORSTATIC, sent|parent },
7362 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
7363 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO3, 0 },
7364 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO3 },
7365 { WM_CTLCOLORSTATIC, sent|parent },
7366 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
7367 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_TEXT, 0 },
7368 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO2, 0 },
7369 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO2 },
7370 { WM_CTLCOLORSTATIC, sent|parent },
7371 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
7372 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
7373 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
7374 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_CLICKED) },
7375 { WM_NCHITTEST, sent|optional, 0, 0 },
7376 { WM_SETCURSOR, sent|optional, 0, 0 },
7377 { WM_MOUSEMOVE, sent|optional, 0, 0 },
7378 { WM_PAINT, sent },
7379 { WM_CTLCOLORSTATIC, sent|parent },
7380 { 0 }
7383 static const struct message auto_radio_button_VK_DOWN_radio3[] =
7385 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
7386 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO2 },
7387 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO3 },
7388 { WM_GETDLGCODE, sent|parent, 0, 0 },
7389 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, MAKELPARAM(WM_KEYDOWN, VK_DOWN) },
7390 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
7391 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
7392 { WM_GETDLGCODE, sent|wparam|lparam|parent, 0, 0 },
7393 { WM_USER, sent|parent, 0, 0 },
7394 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
7395 { 0 }
7398 static const struct message auto_radio_button_VK_UP_radio1[] =
7400 { WM_GETDLGCODE, sent|parent, 0, 0 },
7401 { 0 }
7404 static INT_PTR WINAPI radio_test_dlg_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
7406 ParentMsgCheckProcA(hwnd, msg, wp, lp);
7407 return 1;
7410 static void test_autoradio_BM_CLICK(void)
7412 HWND parent, radio1, radio2, radio3;
7413 RECT rc;
7414 MSG msg;
7415 DWORD ret;
7417 subclass_button();
7419 parent = CreateDialogParamA(0, "AUTORADIO_TEST_DIALOG_1", 0, radio_test_dlg_proc, 0);
7420 ok(parent != 0, "failed to create parent window\n");
7422 radio1 = GetDlgItem(parent, ID_RADIO1);
7423 radio2 = GetDlgItem(parent, ID_RADIO2);
7424 radio3 = GetDlgItem(parent, ID_RADIO3);
7426 /* this avoids focus messages in the generated sequence */
7427 SetFocus(radio2);
7429 flush_events();
7430 flush_sequence();
7432 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
7433 ok(ret == BST_UNCHECKED, "got %08lx\n", ret);
7434 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
7435 ok(ret == BST_UNCHECKED, "got %08lx\n", ret);
7436 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
7437 ok(ret == BST_UNCHECKED, "got %08lx\n", ret);
7439 SendMessageA(radio1, BM_SETCHECK, BST_CHECKED, 0);
7441 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
7442 ok(ret == BST_CHECKED, "got %08lx\n", ret);
7443 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
7444 ok(ret == BST_UNCHECKED, "got %08lx\n", ret);
7445 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
7446 ok(ret == BST_UNCHECKED, "got %08lx\n", ret);
7448 SendMessageA(radio2, BM_SETCHECK, BST_CHECKED, 0);
7450 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
7451 ok(ret == BST_CHECKED, "got %08lx\n", ret);
7452 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
7453 ok(ret == BST_CHECKED, "got %08lx\n", ret);
7454 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
7455 ok(ret == BST_UNCHECKED, "got %08lx\n", ret);
7457 SendMessageA(radio3, BM_SETCHECK, BST_CHECKED, 0);
7459 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
7460 ok(ret == BST_CHECKED, "got %08lx\n", ret);
7461 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
7462 ok(ret == BST_CHECKED, "got %08lx\n", ret);
7463 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
7464 ok(ret == BST_CHECKED, "got %08lx\n", ret);
7466 GetWindowRect(radio2, &rc);
7467 SetCursorPos(rc.left+1, rc.top+1);
7469 flush_events();
7470 flush_sequence();
7472 log_all_parent_messages++;
7474 SendMessageA(radio2, BM_CLICK, 0, 0);
7475 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7476 ok_sequence(auto_radio_button_BM_CLICK, "BM_CLICK on auto-radio button", FALSE);
7478 log_all_parent_messages--;
7480 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
7481 ok(ret == BST_UNCHECKED, "got %08lx\n", ret);
7482 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
7483 ok(ret == BST_CHECKED, "got %08lx\n", ret);
7484 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
7485 ok(ret == BST_UNCHECKED, "got %08lx\n", ret);
7487 DestroyWindow(parent);
7490 #define test_radio(r1, s1, r2, s2, r3, s3) test_radio_dbg(r1, s1, r2, s2, r3, s3, __LINE__)
7491 static void test_radio_dbg(HWND radio1, int state1, HWND radio2, int state2, HWND radio3, int state3, int line)
7493 DWORD ret;
7495 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
7496 ok_(__FILE__,line)(ret == state1 ? BST_CHECKED : BST_UNCHECKED, "got %08lx\n", ret);
7497 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
7498 ok_(__FILE__,line)(ret == state2 ? BST_CHECKED : BST_UNCHECKED, "got %08lx\n", ret);
7499 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
7500 ok_(__FILE__,line)(ret == state3 ? BST_CHECKED : BST_UNCHECKED, "got %08lx\n", ret);
7503 static void set_radio(HWND radio1, int state1, HWND radio2, int state2, HWND radio3, int state3)
7505 SendMessageA(radio1, BM_SETCHECK, state1 ? BST_CHECKED : BST_UNCHECKED, 0);
7506 SendMessageA(radio2, BM_SETCHECK, state2 ? BST_CHECKED : BST_UNCHECKED, 0);
7507 SendMessageA(radio3, BM_SETCHECK, state3 ? BST_CHECKED : BST_UNCHECKED, 0);
7510 static void test_autoradio_kbd_move(void)
7512 HWND parent, radio1, radio2, radio3, hwnd;
7513 RECT rc;
7514 MSG msg;
7515 DWORD ret;
7517 subclass_button();
7519 parent = CreateDialogParamA(0, "AUTORADIO_TEST_DIALOG_2", 0, radio_test_dlg_proc, 0);
7520 ok(parent != 0, "failed to create parent window\n");
7522 radio1 = GetDlgItem(parent, ID_RADIO1);
7523 radio2 = GetDlgItem(parent, ID_RADIO2);
7524 radio3 = GetDlgItem(parent, ID_RADIO3);
7526 flush_events();
7527 flush_sequence();
7529 test_radio(radio1, 0, radio2, 0, radio3, 0);
7530 set_radio(radio1, 1, radio2, 1, radio3, 1);
7531 test_radio(radio1, 1, radio2, 1, radio3, 1);
7533 SetFocus(radio3);
7535 flush_events();
7536 flush_sequence();
7538 log_all_parent_messages++;
7540 SendMessageA(radio3, WM_KEYDOWN, VK_UP, 0);
7541 SendMessageA(radio3, WM_KEYUP, VK_UP, 0);
7542 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7543 ok_sequence(auto_radio_button_VK_UP_child, "press/release VK_UP on auto-radio button", FALSE);
7545 test_radio(radio1, 1, radio2, 1, radio3, 1);
7547 flush_events();
7548 flush_sequence();
7550 DefDlgProcA(parent, WM_KEYDOWN, VK_UP, 0);
7551 DefDlgProcA(parent, WM_KEYUP, VK_UP, 0);
7552 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7553 ok_sequence(auto_radio_button_VK_UP_parent, "press/release VK_UP on dialog", FALSE);
7555 test_radio(radio1, 1, radio2, 1, radio3, 1);
7557 SetFocus(radio3);
7558 GetWindowRect(radio3, &rc);
7560 flush_events();
7561 flush_sequence();
7563 msg.hwnd = parent;
7564 msg.message = WM_KEYDOWN;
7565 msg.wParam = VK_UP;
7566 msg.lParam = 0;
7567 msg.pt.x = rc.left + 1;
7568 msg.pt.y = rc.top + 1;
7569 ret = IsDialogMessageA(parent, &msg);
7570 ok(ret, "IsDialogMessage should return TRUE\n");
7571 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7572 if (0) /* actual message sequence is different on every run in some Windows setups */
7573 ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #1", FALSE);
7574 /* what really matters is that nothing has changed */
7575 test_radio(radio1, 1, radio2, 1, radio3, 1);
7577 set_radio(radio1, 0, radio2, 1, radio3, 1);
7578 test_radio(radio1, 0, radio2, 1, radio3, 1);
7580 flush_events();
7581 flush_sequence();
7583 ret = IsDialogMessageA(parent, &msg);
7584 ok(ret, "IsDialogMessage should return TRUE\n");
7585 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7586 if (0) /* actual message sequence is different on every run in some Windows setups */
7587 ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #2", FALSE);
7588 /* what really matters is that nothing has changed */
7589 test_radio(radio1, 0, radio2, 1, radio3, 1);
7591 /* switch from radio3 ro radio1 */
7592 SetFocus(radio3);
7593 GetWindowRect(radio3, &rc);
7595 flush_events();
7596 flush_sequence();
7598 msg.hwnd = parent;
7599 msg.message = WM_KEYDOWN;
7600 msg.wParam = VK_DOWN;
7601 msg.lParam = 0;
7602 msg.pt.x = rc.left + 1;
7603 msg.pt.y = rc.top + 1;
7604 ret = IsDialogMessageA(parent, &msg);
7605 ok(ret, "IsDialogMessage should return TRUE\n");
7606 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7607 ok_sequence(auto_radio_button_VK_DOWN_dialog, "IsDialogMessage(VK_DOWN)", TRUE);
7609 test_radio(radio1, 1, radio2, 0, radio3, 0);
7611 hwnd = GetFocus();
7612 ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
7613 GetWindowRect(radio1, &rc);
7615 msg.hwnd = parent;
7616 msg.message = WM_KEYDOWN;
7617 msg.wParam = VK_DOWN;
7618 msg.lParam = 0;
7619 msg.pt.x = rc.left + 1;
7620 msg.pt.y = rc.top + 1;
7621 ret = IsDialogMessageA(parent, &msg);
7622 ok(ret, "IsDialogMessage should return TRUE\n");
7623 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7624 ok_sequence(auto_radio_button_VK_DOWN_radio3, "down to radio3", TRUE);
7626 test_radio(radio1, 1, radio2, 0, radio3, 0);
7628 hwnd = GetFocus();
7629 ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
7631 flush_events();
7632 flush_sequence();
7634 msg.hwnd = parent;
7635 msg.message = WM_KEYDOWN;
7636 msg.wParam = VK_UP;
7637 msg.lParam = 0;
7638 msg.pt.x = rc.left + 1;
7639 msg.pt.y = rc.top + 1;
7640 ret = IsDialogMessageA(parent, &msg);
7641 ok(ret, "IsDialogMessage should return TRUE\n");
7642 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7643 ok_sequence(auto_radio_button_VK_UP_radio1, "up to radio1", TRUE);
7645 test_radio(radio1, 1, radio2, 0, radio3, 0);
7647 hwnd = GetFocus();
7648 ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
7650 flush_events();
7651 flush_sequence();
7653 msg.hwnd = parent;
7654 msg.message = WM_KEYDOWN;
7655 msg.wParam = VK_UP;
7656 msg.lParam = 0;
7657 msg.pt.x = rc.left + 1;
7658 msg.pt.y = rc.top + 1;
7659 ret = IsDialogMessageA(parent, &msg);
7660 ok(ret, "IsDialogMessage should return TRUE\n");
7661 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7662 if (0) /* actual message sequence is different on every run in some Windows setups */
7663 ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #3", FALSE);
7664 /* what really matters is that nothing has changed */
7665 test_radio(radio1, 1, radio2, 0, radio3, 0);
7667 log_all_parent_messages--;
7669 DestroyWindow(parent);
7672 /****************** static message test *************************/
7673 static const struct message WmSetFontStaticSeq2[] =
7675 { WM_SETFONT, sent },
7676 { WM_PAINT, sent|defwinproc|optional },
7677 { WM_ERASEBKGND, sent|defwinproc|optional },
7678 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
7679 { 0 }
7682 static WNDPROC old_static_proc;
7684 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7686 static LONG defwndproc_counter = 0;
7687 LRESULT ret;
7688 struct recvd_message msg;
7690 if (ignore_message( message )) return 0;
7692 msg.hwnd = hwnd;
7693 msg.message = message;
7694 msg.flags = sent|wparam|lparam;
7695 if (defwndproc_counter) msg.flags |= defwinproc;
7696 msg.wParam = wParam;
7697 msg.lParam = lParam;
7698 msg.descr = "static";
7699 add_message(&msg);
7701 defwndproc_counter++;
7702 ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
7703 defwndproc_counter--;
7705 return ret;
7708 static void subclass_static(void)
7710 WNDCLASSA cls;
7711 BOOL ret;
7713 ret = GetClassInfoA(0, "static", &cls);
7714 ok(ret, "Failed to get class info, error %lu.\n", GetLastError());
7716 old_static_proc = cls.lpfnWndProc;
7718 cls.hInstance = GetModuleHandleA(NULL);
7719 cls.lpfnWndProc = static_hook_proc;
7720 cls.lpszClassName = "my_static_class";
7721 UnregisterClassA(cls.lpszClassName, cls.hInstance);
7722 register_class(&cls);
7725 static void test_static_messages(void)
7727 /* FIXME: make as comprehensive as the button message test */
7728 static const struct
7730 DWORD style;
7731 DWORD dlg_code;
7732 const struct message *setfont;
7733 } static_ctrl[] = {
7734 { SS_LEFT, DLGC_STATIC,
7735 WmSetFontStaticSeq2 }
7737 unsigned int i;
7738 HWND hwnd;
7739 DWORD dlg_code;
7741 subclass_static();
7743 for (i = 0; i < ARRAY_SIZE(static_ctrl); i++)
7745 hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
7746 0, 0, 50, 14, 0, 0, 0, NULL);
7747 ok(hwnd != 0, "Failed to create static window\n");
7749 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
7750 ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08lx\n", i, dlg_code);
7752 ShowWindow(hwnd, SW_SHOW);
7753 UpdateWindow(hwnd);
7754 SetFocus(0);
7755 flush_sequence();
7757 if (winetest_debug > 1) trace("static style %08lx\n", static_ctrl[i].style);
7758 SendMessageA(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
7759 ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
7761 DestroyWindow(hwnd);
7765 /****************** ComboBox message test *************************/
7766 #define ID_COMBOBOX 0x000f
7768 static const struct message SetCurSelComboSeq[] =
7770 { CB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7771 { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7772 { LB_SETTOPINDEX, sent|wparam|lparam, 0, 0 },
7773 { LB_GETCURSEL, sent|wparam|lparam, 0, 0 },
7774 { LB_GETTEXTLEN, sent|wparam|lparam, 0, 0 },
7775 { LB_GETTEXTLEN, sent|wparam|lparam|optional, 0, 0 }, /* TODO: it's sent on all Windows versions */
7776 { LB_GETTEXT, sent|wparam, 0 },
7777 { WM_CTLCOLOREDIT, sent|parent },
7778 { LB_GETITEMDATA, sent|wparam|lparam, 0, 0 },
7779 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_COMBOBOX, 0x100010f3 },
7780 { 0 }
7783 static const struct message SetCurSelComboSeq2[] =
7785 { CB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7786 { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7787 { LB_SETTOPINDEX, sent|wparam|lparam, 0, 0 },
7788 { LB_GETCURSEL, sent|wparam|lparam, 0, 0 },
7789 { LB_GETTEXTLEN, sent|wparam|lparam, 0, 0 },
7790 { LB_GETTEXTLEN, sent|wparam|lparam|optional, 0, 0 }, /* TODO: it's sent on all Windows versions */
7791 { LB_GETTEXT, sent|wparam, 0 },
7792 { 0 }
7795 static const struct message SetCurSelComboSeq_edit[] =
7797 { CB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7798 { WM_SETTEXT, sent|wparam, 0 },
7799 { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
7800 { 0 }
7803 static const struct message WmKeyDownComboSeq[] =
7805 { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
7806 { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
7807 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
7808 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
7809 { WM_CTLCOLOREDIT, sent|parent },
7810 { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
7811 { 0 }
7814 static const struct message WmSetPosComboSeq[] =
7816 { WM_WINDOWPOSCHANGING, sent },
7817 { WM_NCCALCSIZE, sent|wparam, TRUE },
7818 { WM_CHILDACTIVATE, sent },
7819 { WM_WINDOWPOSCHANGED, sent },
7820 { WM_MOVE, sent|defwinproc },
7821 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
7822 { WM_WINDOWPOSCHANGING, sent|defwinproc },
7823 { WM_NCCALCSIZE, sent|defwinproc|wparam, TRUE },
7824 { WM_WINDOWPOSCHANGED, sent|defwinproc },
7825 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
7826 { 0 }
7829 static const struct message WMSetFocusComboBoxSeq[] =
7831 { WM_SETFOCUS, sent },
7832 { WM_KILLFOCUS, sent|parent },
7833 { WM_SETFOCUS, sent },
7834 { WM_COMMAND, sent|defwinproc|wparam, MAKEWPARAM(1001, EN_SETFOCUS) },
7835 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, INT_MAX },
7836 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7837 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7838 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SETFOCUS) },
7839 { 0 }
7842 static const struct message SetFocusButtonSeq[] =
7844 { WM_KILLFOCUS, sent },
7845 { CB_GETCOMBOBOXINFO, sent|optional },/* Windows 2000 */
7846 { 0x0167, sent|optional },/* Undocumented message. Sent on all versions except Windows 2000 */
7847 { WM_LBUTTONUP, sent|defwinproc },
7848 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDCANCEL) },
7849 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, 0 },
7850 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7851 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7852 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_KILLFOCUS) },
7853 { WM_CTLCOLORBTN, sent|parent },
7854 { 0 }
7857 static const struct message SetFocusComboBoxSeq[] =
7859 { WM_CTLCOLORBTN, sent|parent },
7860 { WM_SETFOCUS, sent },
7861 { WM_KILLFOCUS, sent|defwinproc },
7862 { EM_GETPASSWORDCHAR, sent|optional }, /* Sent on some Win10 machines */
7863 { WM_SETFOCUS, sent },
7864 { WM_COMMAND, sent|defwinproc|wparam, MAKEWPARAM(1001, EN_SETFOCUS) },
7865 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, INT_MAX },
7866 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7867 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7868 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SETFOCUS) },
7869 { 0 }
7872 static const struct message SetFocusButtonSeq2[] =
7874 { WM_KILLFOCUS, sent },
7875 { CB_GETCOMBOBOXINFO, sent|optional },/* Windows 2000 */
7876 { 0x0167, sent|optional },/* Undocumented message. Sent on all versions except Windows 2000 */
7877 { WM_LBUTTONUP, sent|defwinproc },
7878 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDCANCEL) },
7879 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, 0 },
7880 { WM_CTLCOLOREDIT, sent|defwinproc },
7881 { WM_CTLCOLOREDIT, sent|parent },
7882 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_KILLFOCUS) },
7883 { WM_CTLCOLORBTN, sent|parent },
7884 { 0 }
7887 static WNDPROC old_combobox_proc, edit_window_proc, lbox_window_proc;
7889 static LRESULT CALLBACK combobox_edit_subclass_proc(HWND hwnd, UINT message,
7890 WPARAM wParam, LPARAM lParam)
7892 static LONG defwndproc_counter = 0;
7893 LRESULT ret;
7894 struct recvd_message msg;
7896 /* do not log painting messages */
7897 if (message != WM_PAINT &&
7898 message != WM_NCPAINT &&
7899 message != WM_SYNCPAINT &&
7900 message != WM_ERASEBKGND &&
7901 message != WM_NCHITTEST &&
7902 message != WM_GETTEXT &&
7903 !ignore_message( message ))
7905 msg.hwnd = hwnd;
7906 msg.message = message;
7907 msg.flags = sent|wparam|lparam;
7908 if (defwndproc_counter) msg.flags |= defwinproc;
7909 msg.wParam = wParam;
7910 msg.lParam = lParam;
7911 msg.descr = "combo edit";
7912 add_message(&msg);
7915 defwndproc_counter++;
7916 ret = CallWindowProcA(edit_window_proc, hwnd, message, wParam, lParam);
7917 defwndproc_counter--;
7919 return ret;
7922 static LRESULT CALLBACK combobox_lbox_subclass_proc(HWND hwnd, UINT message,
7923 WPARAM wParam, LPARAM lParam)
7925 static LONG defwndproc_counter = 0;
7926 LRESULT ret;
7927 struct recvd_message msg;
7929 /* do not log painting messages */
7930 if (message != WM_PAINT &&
7931 message != WM_NCPAINT &&
7932 message != WM_SYNCPAINT &&
7933 message != WM_ERASEBKGND &&
7934 message != WM_NCHITTEST &&
7935 !ignore_message( message ))
7937 msg.hwnd = hwnd;
7938 msg.message = message;
7939 msg.flags = sent|wparam|lparam;
7940 if (defwndproc_counter) msg.flags |= defwinproc;
7941 msg.wParam = wParam;
7942 msg.lParam = lParam;
7943 msg.descr = "combo lbox";
7944 add_message(&msg);
7947 defwndproc_counter++;
7948 ret = CallWindowProcA(lbox_window_proc, hwnd, message, wParam, lParam);
7949 defwndproc_counter--;
7951 return ret;
7954 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7956 static LONG defwndproc_counter = 0;
7957 LRESULT ret;
7958 struct recvd_message msg;
7960 /* do not log painting messages */
7961 if (message != WM_PAINT &&
7962 message != WM_NCPAINT &&
7963 message != WM_SYNCPAINT &&
7964 message != WM_ERASEBKGND &&
7965 message != WM_NCHITTEST &&
7966 message != WM_GETTEXT &&
7967 !ignore_message( message ))
7969 msg.hwnd = hwnd;
7970 msg.message = message;
7971 msg.flags = sent|wparam|lparam;
7972 if (defwndproc_counter) msg.flags |= defwinproc;
7973 msg.wParam = wParam;
7974 msg.lParam = lParam;
7975 msg.descr = "combo";
7976 add_message(&msg);
7979 defwndproc_counter++;
7980 ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
7981 defwndproc_counter--;
7983 return ret;
7986 static void subclass_combobox(void)
7988 WNDCLASSA cls;
7989 BOOL ret;
7991 ret = GetClassInfoA(0, "ComboBox", &cls);
7992 ok(ret, "Failed to get class info, error %lu.\n", GetLastError());
7994 old_combobox_proc = cls.lpfnWndProc;
7996 cls.hInstance = GetModuleHandleA(NULL);
7997 cls.lpfnWndProc = combobox_hook_proc;
7998 cls.lpszClassName = "my_combobox_class";
7999 UnregisterClassA(cls.lpszClassName, cls.hInstance);
8000 register_class(&cls);
8003 static void test_combobox_messages(void)
8005 HWND parent, combo, button, edit, lbox;
8006 LRESULT ret;
8007 COMBOBOXINFO cbInfo;
8008 BOOL res;
8010 subclass_combobox();
8012 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8013 100, 100, 200, 200, 0, 0, 0, NULL);
8014 ok(parent != 0, "Failed to create parent window\n");
8015 flush_sequence();
8017 combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
8018 0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
8019 ok(combo != 0, "Failed to create combobox window\n");
8021 UpdateWindow(combo);
8023 ret = SendMessageA(combo, WM_GETDLGCODE, 0, 0);
8024 ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08Ix\n", ret);
8026 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
8027 ok(ret == 0, "expected 0, got %Id\n", ret);
8028 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
8029 ok(ret == 1, "expected 1, got %Id\n", ret);
8030 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
8031 ok(ret == 2, "expected 2, got %Id\n", ret);
8033 SendMessageA(combo, CB_SETCURSEL, 0, 0);
8034 SetFocus(combo);
8035 flush_sequence();
8037 log_all_parent_messages++;
8038 SendMessageA(combo, WM_KEYDOWN, VK_DOWN, 0);
8039 SendMessageA(combo, WM_KEYUP, VK_DOWN, 0);
8040 log_all_parent_messages--;
8041 ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
8043 flush_sequence();
8044 SetWindowPos(combo, 0, 10, 10, 120, 130, SWP_NOZORDER);
8045 ok_sequence(WmSetPosComboSeq, "repositioning messages on a ComboBox", FALSE);
8047 DestroyWindow(combo);
8048 DestroyWindow(parent);
8050 /* Start again. Test combobox text selection when getting and losing focus */
8051 parent = CreateWindowExA(0, "TestParentClass", "Parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8052 10, 10, 300, 300, NULL, NULL, NULL, NULL);
8053 ok(parent != 0, "Failed to create parent window\n");
8055 combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWN,
8056 5, 5, 100, 100, parent, (HMENU)ID_COMBOBOX, NULL, NULL);
8057 ok(combo != 0, "Failed to create combobox window\n");
8059 cbInfo.cbSize = sizeof(COMBOBOXINFO);
8060 SetLastError(0xdeadbeef);
8061 res = GetComboBoxInfo(combo, &cbInfo);
8062 ok(res, "Failed to get COMBOBOXINFO structure; LastError: %lu\n", GetLastError());
8063 edit = cbInfo.hwndItem;
8065 edit_window_proc = (WNDPROC)SetWindowLongPtrA(edit, GWLP_WNDPROC,
8066 (ULONG_PTR)combobox_edit_subclass_proc);
8068 button = CreateWindowExA(0, "Button", "OK", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
8069 5, 50, 100, 20, parent, NULL,
8070 (HINSTANCE)GetWindowLongPtrA(parent, GWLP_HINSTANCE), NULL);
8071 ok(button != 0, "Failed to create button window\n");
8073 flush_sequence();
8074 log_all_parent_messages++;
8075 SendMessageA(combo, WM_SETFOCUS, 0, (LPARAM)edit);
8076 log_all_parent_messages--;
8077 ok_sequence(WMSetFocusComboBoxSeq, "WM_SETFOCUS on a ComboBox", TRUE);
8079 flush_sequence();
8080 log_all_parent_messages++;
8081 SetFocus(button);
8082 log_all_parent_messages--;
8083 ok_sequence(SetFocusButtonSeq, "SetFocus on a Button", TRUE);
8085 SendMessageA(combo, WM_SETTEXT, 0, (LPARAM)"Wine Test");
8087 flush_sequence();
8088 log_all_parent_messages++;
8089 SetFocus(combo);
8090 log_all_parent_messages--;
8091 ok_sequence(SetFocusComboBoxSeq, "SetFocus on a ComboBox", TRUE);
8093 flush_sequence();
8094 log_all_parent_messages++;
8095 SetFocus(button);
8096 log_all_parent_messages--;
8097 ok_sequence(SetFocusButtonSeq2, "SetFocus on a Button (2)", TRUE);
8099 SetFocus(combo);
8100 SendMessageA(combo, WM_SETREDRAW, FALSE, 0);
8101 flush_sequence();
8102 log_all_parent_messages++;
8103 SendMessageA(combo, CB_SETCURSEL, 0, 0);
8104 log_all_parent_messages--;
8105 ok_sequence(SetCurSelComboSeq_edit, "CB_SETCURSEL on a ComboBox with edit control", FALSE);
8107 DestroyWindow(button);
8108 DestroyWindow(combo);
8110 combo = CreateWindowExA(0, "my_combobox_class", "test",
8111 WS_CHILD | WS_VISIBLE | CBS_OWNERDRAWFIXED | CBS_DROPDOWNLIST,
8112 5, 5, 100, 100, parent, (HMENU)ID_COMBOBOX, NULL, NULL);
8113 ok(combo != 0, "Failed to create combobox window\n");
8115 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
8116 ok(ret == 0, "expected 0, got %Id\n", ret);
8118 cbInfo.cbSize = sizeof(COMBOBOXINFO);
8119 SetLastError(0xdeadbeef);
8120 res = GetComboBoxInfo(combo, &cbInfo);
8121 ok(res, "Failed to get COMBOBOXINFO structure; LastError: %lu\n", GetLastError());
8122 lbox = cbInfo.hwndList;
8123 lbox_window_proc = (WNDPROC)SetWindowLongPtrA(lbox, GWLP_WNDPROC,
8124 (ULONG_PTR)combobox_lbox_subclass_proc);
8125 flush_sequence();
8127 log_all_parent_messages++;
8128 SendMessageA(combo, CB_SETCURSEL, 0, 0);
8129 log_all_parent_messages--;
8130 ok_sequence(SetCurSelComboSeq, "CB_SETCURSEL on a ComboBox", FALSE);
8132 ShowWindow(combo, SW_HIDE);
8133 flush_sequence();
8134 log_all_parent_messages++;
8135 SendMessageA(combo, CB_SETCURSEL, 0, 0);
8136 log_all_parent_messages--;
8137 ok_sequence(SetCurSelComboSeq2, "CB_SETCURSEL on a ComboBox", FALSE);
8139 DestroyWindow(combo);
8140 DestroyWindow(parent);
8143 /****************** WM_IME_KEYDOWN message test *******************/
8145 static const struct message WmImeKeydownMsgSeq_0[] =
8147 { WM_IME_KEYDOWN, wparam, VK_RETURN },
8148 { WM_CHAR, wparam, 'A' },
8149 { 0 }
8152 static const struct message WmImeKeydownMsgSeq_1[] =
8154 { WM_KEYDOWN, optional|wparam, VK_RETURN },
8155 { WM_CHAR, optional|wparam, VK_RETURN },
8156 { 0 }
8159 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8161 struct recvd_message msg;
8163 msg.hwnd = hwnd;
8164 msg.message = message;
8165 msg.flags = wparam|lparam;
8166 msg.wParam = wParam;
8167 msg.lParam = lParam;
8168 msg.descr = "wmime_keydown";
8169 add_message(&msg);
8171 return DefWindowProcA(hwnd, message, wParam, lParam);
8174 static void register_wmime_keydown_class(void)
8176 WNDCLASSA cls;
8178 ZeroMemory(&cls, sizeof(WNDCLASSA));
8179 cls.lpfnWndProc = wmime_keydown_procA;
8180 cls.hInstance = GetModuleHandleA(0);
8181 cls.lpszClassName = "wmime_keydown_class";
8182 register_class(&cls);
8185 static void test_wmime_keydown_message(void)
8187 HWND hwnd;
8188 MSG msg;
8190 if (winetest_debug > 1) trace("Message sequences by WM_IME_KEYDOWN\n");
8192 register_wmime_keydown_class();
8193 hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
8194 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
8195 NULL, NULL, 0);
8196 flush_events();
8197 flush_sequence();
8199 SendMessageA(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
8200 SendMessageA(hwnd, WM_CHAR, 'A', 1);
8201 ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
8203 while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
8205 TranslateMessage(&msg);
8206 DispatchMessageA(&msg);
8208 ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
8210 DestroyWindow(hwnd);
8213 /************* painting message test ********************/
8215 void dump_region(HRGN hrgn)
8217 DWORD i, size;
8218 RGNDATA *data = NULL;
8219 RECT *rect;
8221 if (!hrgn)
8223 printf( "null region\n" );
8224 return;
8226 if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
8227 if (!(data = malloc( size ))) return;
8228 GetRegionData( hrgn, size, data );
8229 printf("%ld rects:", data->rdh.nCount );
8230 for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
8231 printf( " %s", wine_dbgstr_rect( rect ));
8232 printf("\n");
8233 free( data );
8236 #define check_update_rgn( hwnd, hrgn ) check_update_rgn_( __LINE__, hwnd, hrgn )
8237 static void check_update_rgn_( int line, HWND hwnd, HRGN hrgn )
8239 INT ret;
8240 RECT r1, r2;
8241 HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
8242 HRGN update = CreateRectRgn( 0, 0, 0, 0 );
8244 ret = GetUpdateRgn( hwnd, update, FALSE );
8245 ok( ret != ERROR, "GetUpdateRgn failed\n" );
8246 if (ret == NULLREGION)
8248 ok_(__FILE__,line)( !hrgn, "Update region shouldn't be empty\n" );
8250 else
8252 if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
8254 ok_(__FILE__,line)( 0, "Regions are different\n" );
8255 if (winetest_debug > 0)
8257 printf( "Update region: " );
8258 dump_region( update );
8259 printf( "Wanted region: " );
8260 dump_region( hrgn );
8264 GetRgnBox( update, &r1 );
8265 GetUpdateRect( hwnd, &r2, FALSE );
8266 ok_(__FILE__,line)( EqualRect( &r1, &r2 ), "Rectangles are different: %s / %s\n",
8267 wine_dbgstr_rect( &r1 ), wine_dbgstr_rect( &r2 ));
8269 DeleteObject( tmp );
8270 DeleteObject( update );
8273 static const struct message WmInvalidateRgn[] = {
8274 { WM_NCPAINT, sent },
8275 { WM_GETTEXT, sent|defwinproc|optional },
8276 { 0 }
8279 static const struct message WmGetUpdateRect[] = {
8280 { WM_NCPAINT, sent },
8281 { WM_GETTEXT, sent|defwinproc|optional },
8282 { WM_PAINT, sent },
8283 { 0 }
8286 static const struct message WmInvalidateFull[] = {
8287 { WM_NCPAINT, sent|wparam, 1 },
8288 { WM_GETTEXT, sent|defwinproc|optional },
8289 { 0 }
8292 static const struct message WmInvalidateErase[] = {
8293 { WM_NCPAINT, sent|wparam, 1 },
8294 { WM_GETTEXT, sent|defwinproc|optional },
8295 { WM_ERASEBKGND, sent },
8296 { 0 }
8299 static const struct message WmInvalidatePaint[] = {
8300 { WM_PAINT, sent },
8301 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
8302 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8303 { 0 }
8306 static const struct message WmInvalidateErasePaint[] = {
8307 { WM_PAINT, sent },
8308 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
8309 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8310 { WM_ERASEBKGND, sent|beginpaint|optional },
8311 { 0 }
8314 static const struct message WmInvalidateErasePaint2[] = {
8315 { WM_PAINT, sent },
8316 { WM_NCPAINT, sent|beginpaint },
8317 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8318 { WM_ERASEBKGND, sent|beginpaint|optional },
8319 { 0 }
8322 static const struct message WmErase[] = {
8323 { WM_ERASEBKGND, sent },
8324 { 0 }
8327 static const struct message WmPaint[] = {
8328 { WM_PAINT, sent },
8329 { 0 }
8332 static const struct message WmParentOnlyPaint[] = {
8333 { WM_PAINT, sent|parent },
8334 { 0 }
8337 static const struct message WmInvalidateParent[] = {
8338 { WM_NCPAINT, sent|parent },
8339 { WM_GETTEXT, sent|defwinproc|parent|optional },
8340 { WM_ERASEBKGND, sent|parent },
8341 { 0 }
8344 static const struct message WmInvalidateParentChild[] = {
8345 { WM_NCPAINT, sent|parent },
8346 { WM_GETTEXT, sent|defwinproc|parent|optional },
8347 { WM_ERASEBKGND, sent|parent },
8348 { WM_NCPAINT, sent },
8349 { WM_GETTEXT, sent|defwinproc|optional },
8350 { WM_ERASEBKGND, sent },
8351 { 0 }
8354 static const struct message WmInvalidateParentChild2[] = {
8355 { WM_ERASEBKGND, sent|parent },
8356 { WM_NCPAINT, sent },
8357 { WM_GETTEXT, sent|defwinproc|optional },
8358 { WM_ERASEBKGND, sent },
8359 { 0 }
8362 static const struct message WmParentPaint[] = {
8363 { WM_PAINT, sent|parent },
8364 { WM_PAINT, sent },
8365 { 0 }
8368 static const struct message WmParentPaintNc[] = {
8369 { WM_PAINT, sent|parent },
8370 { WM_PAINT, sent },
8371 { WM_NCPAINT, sent|beginpaint },
8372 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8373 { WM_ERASEBKGND, sent|beginpaint|optional },
8374 { WM_GETMINMAXINFO, sent|optional },
8375 { 0 }
8378 static const struct message WmChildPaintNc[] = {
8379 { WM_PAINT, sent },
8380 { WM_NCPAINT, sent|beginpaint },
8381 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8382 { WM_ERASEBKGND, sent|beginpaint|optional },
8383 { 0 }
8386 static const struct message WmParentErasePaint[] = {
8387 { WM_PAINT, sent|parent },
8388 { WM_NCPAINT, sent|parent|beginpaint },
8389 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
8390 { WM_ERASEBKGND, sent|parent|beginpaint|optional },
8391 { WM_PAINT, sent },
8392 { WM_NCPAINT, sent|beginpaint },
8393 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8394 { WM_ERASEBKGND, sent|beginpaint|optional },
8395 { 0 }
8398 static const struct message WmParentOnlyNcPaint[] = {
8399 { WM_PAINT, sent|parent },
8400 { WM_NCPAINT, sent|parent|beginpaint },
8401 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
8402 { 0 }
8405 static const struct message WmSetParentStyle[] = {
8406 { WM_STYLECHANGING, sent|parent },
8407 { WM_STYLECHANGED, sent|parent },
8408 { 0 }
8411 static void test_paint_messages(void)
8413 BOOL ret;
8414 RECT rect, rect2;
8415 DWORD style;
8416 POINT pt;
8417 MSG msg;
8418 HWND hparent, hchild;
8419 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
8420 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
8421 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
8422 100, 100, 200, 200, 0, 0, 0, NULL);
8423 ok (hwnd != 0, "Failed to create overlapped window\n");
8425 ShowWindow( hwnd, SW_SHOW );
8426 UpdateWindow( hwnd );
8427 flush_events();
8428 flush_sequence();
8430 check_update_rgn( hwnd, 0 );
8431 SetRectRgn( hrgn, 10, 10, 20, 20 );
8432 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
8433 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8434 check_update_rgn( hwnd, hrgn );
8435 SetRectRgn( hrgn2, 20, 20, 30, 30 );
8436 ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
8437 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8438 CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
8439 check_update_rgn( hwnd, hrgn );
8440 /* validate everything */
8441 ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8442 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8443 check_update_rgn( hwnd, 0 );
8445 /* test empty region */
8446 SetRectRgn( hrgn, 10, 10, 10, 15 );
8447 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
8448 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8449 check_update_rgn( hwnd, 0 );
8450 /* test empty rect */
8451 SetRect( &rect, 10, 10, 10, 15 );
8452 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
8453 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8454 check_update_rgn( hwnd, 0 );
8456 /* test a zeroed rectangle */
8457 RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
8458 SetRect( &rect, 0, 0, 0, 0 );
8459 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
8460 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8461 check_update_rgn( hwnd, 0 );
8463 /* a well ordered rectangle */
8464 RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
8465 SetRect( &rect, 10, 5, 17, 21 );
8466 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
8467 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8468 SetRectRgn( hrgn, 10, 5, 17, 21 );
8469 check_update_rgn( hwnd, hrgn );
8471 /* empty rectangle, top and bottom are swapped but left and right have
8472 the same value */
8473 RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
8474 SetRect( &rect, 5, 30, 5, 10 );
8475 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
8476 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8477 check_update_rgn( hwnd, 0 );
8479 /* empty rectangle, left and right are swapped but top and bottom have
8480 the same value */
8481 RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
8482 SetRect( &rect, 17, 10, 5, 10 );
8483 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
8484 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8485 check_update_rgn( hwnd, 0 );
8487 /* Left and right are swapped */
8488 RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
8489 SetRect( &rect, 21, 12, 7, 30 );
8490 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
8491 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8492 SetRectRgn( hrgn, 7, 12, 21, 30 );
8493 check_update_rgn( hwnd, hrgn );
8495 /* Top and bottom are swapped */
8496 RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
8497 SetRect( &rect, 7, 30, 21, 12 );
8498 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
8499 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8500 SetRectRgn( hrgn, 7, 12, 21, 30 );
8501 check_update_rgn( hwnd, hrgn );
8503 /* both reference points are swapped */
8504 RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
8505 SetRect( &rect, 21, 30, 7, 12 );
8506 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
8507 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8508 SetRectRgn( hrgn, 7, 12, 21, 30 );
8509 check_update_rgn( hwnd, hrgn );
8511 /* flush pending messages */
8512 flush_events();
8513 flush_sequence();
8515 GetClientRect( hwnd, &rect );
8516 SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
8517 /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
8518 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
8520 SetRectEmpty( &rect );
8521 ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) failed\n");
8522 check_update_rgn( hwnd, hrgn );
8523 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8524 flush_events();
8525 ok_sequence( WmPaint, "Paint", FALSE );
8526 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8527 check_update_rgn( hwnd, 0 );
8529 SetRectEmpty( &rect );
8530 ok(RedrawWindow(0, &rect, 0, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
8531 "RedrawWindow failed\n");
8532 check_update_rgn( hwnd, 0 );
8534 SetRectEmpty( &rect );
8535 ok(RedrawWindow(0, &rect, 0, RDW_ALLCHILDREN | RDW_VALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
8536 "RedrawWindow failed\n");
8537 check_update_rgn( hwnd, 0 );
8539 GetWindowRect( hwnd, &rect );
8540 ok(RedrawWindow(0, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
8541 "RedrawWindow failed\n");
8542 check_update_rgn( hwnd, 0 );
8544 flush_events();
8545 ok(RedrawWindow(0, &rect, 0, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
8546 "RedrawWindow failed\n");
8547 check_update_rgn( hwnd, hrgn );
8548 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8549 flush_events();
8550 ok_sequence( WmPaint, "Paint", FALSE );
8551 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8552 check_update_rgn( hwnd, 0 );
8554 ok(RedrawWindow(GetDesktopWindow(), &rect, 0,
8555 RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
8556 "RedrawWindow failed\n");
8557 ret = GetUpdateRgn( hwnd, hrgn2, FALSE );
8558 ok( ret == NULLREGION || broken(ret == SIMPLEREGION), /* <= win7 */
8559 "region should be null (%d)\n", ret );
8560 if (ret == SIMPLEREGION) ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8561 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8562 flush_events();
8564 ok(RedrawWindow(GetDesktopWindow(), NULL, 0,
8565 RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
8566 "RedrawWindow failed\n");
8567 ret = GetUpdateRgn( hwnd, hrgn2, FALSE );
8568 ok( ret == NULLREGION || broken(ret == SIMPLEREGION), /* <= win7 */
8569 "region should be null (%d)\n", ret );
8570 if (ret == SIMPLEREGION) ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8571 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8572 flush_events();
8574 SetRectRgn( hrgn2, rect.left, rect.top, rect.right, rect.bottom );
8575 ok(RedrawWindow(0, NULL, hrgn2, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
8576 "RedrawWindow failed\n");
8577 check_update_rgn( hwnd, hrgn );
8578 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8579 flush_events();
8580 ok_sequence( WmPaint, "Paint", FALSE );
8581 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8582 check_update_rgn( hwnd, 0 );
8584 ok(RedrawWindow(0, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW ),
8585 "RedrawWindow failed\n");
8586 check_update_rgn( hwnd, 0 );
8588 ok(RedrawWindow(0, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW ),
8589 "RedrawWindow failed\n");
8590 check_update_rgn( hwnd, hrgn );
8591 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8592 flush_events();
8593 ok_sequence( WmPaint, "Paint", FALSE );
8594 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8595 check_update_rgn( hwnd, 0 );
8597 /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
8598 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
8600 SetRectEmpty( &rect );
8601 if (ValidateRect(0, &rect) && /* not supported on Win9x */
8602 GetUpdateRect(hwnd, NULL, FALSE)) /* or >= Win 8 */
8604 check_update_rgn( hwnd, hrgn );
8605 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8606 flush_events();
8607 ok_sequence( WmPaint, "Paint", FALSE );
8608 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8609 check_update_rgn( hwnd, 0 );
8612 SetLastError(0xdeadbeef);
8613 ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
8614 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
8615 "wrong error code %ld\n", GetLastError());
8616 check_update_rgn( hwnd, 0 );
8617 flush_events();
8618 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8620 SetLastError(0xdeadbeef);
8621 ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
8622 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
8623 broken( GetLastError() == 0xdeadbeef ) /* win9x */,
8624 "wrong error code %ld\n", GetLastError());
8625 check_update_rgn( hwnd, 0 );
8626 flush_events();
8627 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8629 SetLastError(0xdeadbeef);
8630 ok(!UpdateWindow(NULL), "UpdateWindow(NULL) should fail\n");
8631 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
8632 broken( GetLastError() == 0xdeadbeef ) /* win9x */,
8633 "wrong error code %ld\n", GetLastError());
8634 check_update_rgn( hwnd, 0 );
8635 flush_events();
8636 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8638 /* now with frame */
8639 SetRectRgn( hrgn, -5, -5, 20, 20 );
8641 /* flush pending messages */
8642 flush_events();
8643 flush_sequence();
8644 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8645 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
8647 SetRectRgn( hrgn, 0, 0, 20, 20 ); /* GetUpdateRgn clips to client area */
8648 check_update_rgn( hwnd, hrgn );
8650 flush_sequence();
8651 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
8652 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
8654 flush_sequence();
8655 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
8656 ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
8658 GetClientRect( hwnd, &rect );
8659 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8660 check_update_rgn( hwnd, hrgn );
8662 flush_sequence();
8663 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
8664 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8666 flush_sequence();
8667 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
8668 ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
8669 check_update_rgn( hwnd, 0 );
8671 flush_sequence();
8672 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
8673 ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
8674 check_update_rgn( hwnd, 0 );
8676 flush_sequence();
8677 SetRectRgn( hrgn, 0, 0, 100, 100 );
8678 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
8679 SetRectRgn( hrgn, 0, 0, 50, 100 );
8680 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
8681 SetRectRgn( hrgn, 50, 0, 100, 100 );
8682 check_update_rgn( hwnd, hrgn );
8683 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
8684 ok_sequence( WmEmptySeq, "EmptySeq", FALSE ); /* must not generate messages, everything is valid */
8685 check_update_rgn( hwnd, 0 );
8687 flush_sequence();
8688 SetRectRgn( hrgn, 0, 0, 100, 100 );
8689 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
8690 SetRectRgn( hrgn, 0, 0, 100, 50 );
8691 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
8692 ok_sequence( WmErase, "Erase", FALSE );
8693 SetRectRgn( hrgn, 0, 50, 100, 100 );
8694 check_update_rgn( hwnd, hrgn );
8696 flush_sequence();
8697 SetRectRgn( hrgn, 0, 0, 100, 100 );
8698 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
8699 SetRectRgn( hrgn, 0, 0, 50, 50 );
8700 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
8701 ok_sequence( WmPaint, "Paint", FALSE );
8703 flush_sequence();
8704 SetRectRgn( hrgn, -4, -4, -2, -2 );
8705 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8706 SetRectRgn( hrgn, -200, -200, -198, -198 );
8707 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
8708 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
8710 flush_sequence();
8711 SetRectRgn( hrgn, -4, -4, -2, -2 );
8712 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8713 SetRectRgn( hrgn, -4, -4, -3, -3 );
8714 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
8715 SetRectRgn( hrgn, 0, 0, 1, 1 );
8716 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
8717 ok_sequence( WmPaint, "Paint", FALSE );
8719 flush_sequence();
8720 SetRectRgn( hrgn, -4, -4, -1, -1 );
8721 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8722 RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
8723 /* make sure no WM_PAINT was generated */
8724 flush_events();
8725 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
8727 flush_sequence();
8728 SetRectRgn( hrgn, -4, -4, -1, -1 );
8729 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8730 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
8732 if (msg.hwnd == hwnd && msg.message == WM_PAINT)
8734 /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
8735 INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
8736 ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
8737 ret = GetUpdateRect( hwnd, &rect, FALSE );
8738 ok( ret, "Invalid GetUpdateRect result %d\n", ret );
8739 /* this will send WM_NCPAINT and validate the non client area */
8740 ret = GetUpdateRect( hwnd, &rect, TRUE );
8741 ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
8743 DispatchMessageA( &msg );
8745 ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
8747 DestroyWindow( hwnd );
8749 /* now test with a child window */
8751 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
8752 100, 100, 200, 200, 0, 0, 0, NULL);
8753 ok (hparent != 0, "Failed to create parent window\n");
8755 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
8756 10, 10, 100, 100, hparent, 0, 0, NULL);
8757 ok (hchild != 0, "Failed to create child window\n");
8759 ShowWindow( hparent, SW_SHOW );
8760 UpdateWindow( hparent );
8761 UpdateWindow( hchild );
8762 flush_events();
8763 flush_sequence();
8764 log_all_parent_messages++;
8766 SetRect( &rect, 0, 0, 50, 50 );
8767 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8768 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
8769 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
8771 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8772 pt.x = pt.y = 0;
8773 MapWindowPoints( hchild, hparent, &pt, 1 );
8774 SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
8775 check_update_rgn( hchild, hrgn );
8776 SetRectRgn( hrgn, 0, 0, 50, 50 );
8777 check_update_rgn( hparent, hrgn );
8778 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8779 ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
8780 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
8781 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
8783 flush_events();
8784 ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
8786 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
8787 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8788 ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
8789 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
8790 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
8792 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
8793 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
8794 ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
8796 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
8797 flush_sequence();
8798 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
8799 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8800 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
8802 /* flush all paint messages */
8803 flush_events();
8804 flush_sequence();
8806 /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
8807 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
8808 SetRectRgn( hrgn, 0, 0, 50, 50 );
8809 check_update_rgn( hparent, hrgn );
8810 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
8811 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8812 SetRectRgn( hrgn, 0, 0, 50, 50 );
8813 check_update_rgn( hparent, hrgn );
8815 /* flush all paint messages */
8816 flush_events();
8817 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
8818 flush_sequence();
8820 /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
8821 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8822 SetRectRgn( hrgn, 0, 0, 50, 50 );
8823 check_update_rgn( hparent, hrgn );
8824 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
8825 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8826 SetRectRgn( hrgn2, 10, 10, 50, 50 );
8827 CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
8828 check_update_rgn( hparent, hrgn );
8829 /* flush all paint messages */
8830 flush_events();
8831 flush_sequence();
8833 /* same as above but parent gets completely validated */
8834 SetRect( &rect, 20, 20, 30, 30 );
8835 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8836 SetRectRgn( hrgn, 20, 20, 30, 30 );
8837 check_update_rgn( hparent, hrgn );
8838 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
8839 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8840 check_update_rgn( hparent, 0 ); /* no update region */
8841 flush_events();
8842 ok_sequence( WmEmptySeq, "WmEmpty", FALSE ); /* and no paint messages */
8844 /* make sure RDW_VALIDATE on child doesn't have the same effect */
8845 flush_sequence();
8846 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8847 SetRectRgn( hrgn, 20, 20, 30, 30 );
8848 check_update_rgn( hparent, hrgn );
8849 RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
8850 SetRectRgn( hrgn, 20, 20, 30, 30 );
8851 check_update_rgn( hparent, hrgn );
8853 /* same as above but normal WM_PAINT doesn't validate parent */
8854 flush_sequence();
8855 SetRect( &rect, 20, 20, 30, 30 );
8856 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8857 SetRectRgn( hrgn, 20, 20, 30, 30 );
8858 check_update_rgn( hparent, hrgn );
8859 /* no WM_PAINT in child while parent still pending */
8860 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8861 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8862 while (PeekMessageA( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8863 ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
8865 flush_sequence();
8866 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8867 /* no WM_PAINT in child while parent still pending */
8868 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8869 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8870 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
8871 /* now that parent is valid child should get WM_PAINT */
8872 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8873 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8874 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8875 ok_sequence( WmEmptySeq, "No other message", FALSE );
8877 /* same thing with WS_CLIPCHILDREN in parent */
8878 flush_sequence();
8879 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
8880 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
8881 /* changing style invalidates non client area, but we need to invalidate something else to see it */
8882 RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
8883 ok_sequence( WmEmptySeq, "No message", FALSE );
8884 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
8885 ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
8887 flush_sequence();
8888 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
8889 SetRectRgn( hrgn, 20, 20, 30, 30 );
8890 check_update_rgn( hparent, hrgn );
8891 /* no WM_PAINT in child while parent still pending */
8892 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8893 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8894 /* WM_PAINT in parent first */
8895 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8896 ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
8898 /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
8899 flush_sequence();
8900 SetRect( &rect, 0, 0, 30, 30 );
8901 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
8902 SetRectRgn( hrgn, 0, 0, 30, 30 );
8903 check_update_rgn( hparent, hrgn );
8904 flush_events();
8905 ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
8907 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
8908 flush_sequence();
8909 SetRect( &rect, -10, 0, 30, 30 );
8910 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
8911 SetRect( &rect, 0, 0, 20, 20 );
8912 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
8913 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
8914 ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
8916 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
8917 flush_sequence();
8918 SetRect( &rect, -10, 0, 30, 30 );
8919 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
8920 SetRect( &rect, 0, 0, 100, 100 );
8921 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
8922 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
8923 ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
8924 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8925 ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
8927 /* WS_CLIPCHILDREN doesn't exclude children from update region */
8928 flush_sequence();
8929 RedrawWindow( hparent, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
8930 GetClientRect( hparent, &rect );
8931 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8932 check_update_rgn( hparent, hrgn );
8933 flush_events();
8935 RedrawWindow( hparent, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
8936 GetClientRect( hparent, &rect );
8937 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8938 check_update_rgn( hparent, hrgn );
8939 flush_events();
8941 /* test RDW_INTERNALPAINT behavior */
8943 flush_sequence();
8944 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
8945 flush_events();
8946 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
8948 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
8949 flush_events();
8950 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
8952 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
8953 flush_events();
8954 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
8956 style = GetWindowLongA(hparent, GWL_STYLE);
8957 ok(style & WS_CLIPCHILDREN, "Got unexpected style %#lx.\n", style);
8958 UpdateWindow( hparent );
8959 flush_events();
8960 flush_sequence();
8961 if (winetest_debug > 1) trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
8962 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8963 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
8964 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8965 flush_events();
8966 ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
8968 UpdateWindow( hparent );
8969 flush_events();
8970 flush_sequence();
8971 if (winetest_debug > 1) trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
8972 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8973 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
8974 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8975 flush_events();
8976 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
8978 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
8979 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
8980 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
8981 flush_events();
8982 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
8984 style = GetWindowLongA(hparent, GWL_STYLE);
8985 ok(!(style & WS_CLIPCHILDREN), "Got unexpected style %#lx.\n", style);
8986 UpdateWindow( hparent );
8987 flush_events();
8988 flush_sequence();
8989 if (winetest_debug > 1) trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
8990 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8991 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
8992 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8993 flush_events();
8994 ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
8996 UpdateWindow( hparent );
8997 flush_events();
8998 flush_sequence();
8999 if (winetest_debug > 1) trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
9000 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
9001 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
9002 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
9003 flush_events();
9004 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
9006 ok(GetWindowLongA( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
9007 ok(GetWindowLongA( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
9009 UpdateWindow( hparent );
9010 flush_events();
9011 flush_sequence();
9012 if (winetest_debug > 1) trace("testing SetWindowPos(-10000, -10000) on child\n");
9013 SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
9014 check_update_rgn( hchild, 0 );
9015 flush_events();
9017 #if 0 /* this one doesn't pass under Wine yet */
9018 UpdateWindow( hparent );
9019 flush_events();
9020 flush_sequence();
9021 if (winetest_debug > 1) trace("testing ShowWindow(SW_MINIMIZE) on child\n");
9022 ShowWindow( hchild, SW_MINIMIZE );
9023 check_update_rgn( hchild, 0 );
9024 flush_events();
9025 #endif
9027 UpdateWindow( hparent );
9028 flush_events();
9029 flush_sequence();
9030 if (winetest_debug > 1) trace("testing SetWindowPos(-10000, -10000) on parent\n");
9031 SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
9032 check_update_rgn( hparent, 0 );
9033 flush_events();
9035 log_all_parent_messages--;
9036 DestroyWindow( hparent );
9037 ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
9039 /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
9041 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
9042 100, 100, 200, 200, 0, 0, 0, NULL);
9043 ok (hparent != 0, "Failed to create parent window\n");
9045 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
9046 10, 10, 100, 100, hparent, 0, 0, NULL);
9047 ok (hchild != 0, "Failed to create child window\n");
9049 ShowWindow( hparent, SW_SHOW );
9050 UpdateWindow( hparent );
9051 UpdateWindow( hchild );
9052 flush_events();
9053 flush_sequence();
9055 /* moving child outside of parent boundaries changes update region */
9056 SetRect( &rect, 0, 0, 40, 40 );
9057 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
9058 SetRectRgn( hrgn, 0, 0, 40, 40 );
9059 check_update_rgn( hchild, hrgn );
9060 MoveWindow( hchild, -10, 10, 100, 100, FALSE );
9061 SetRectRgn( hrgn, 10, 0, 40, 40 );
9062 check_update_rgn( hchild, hrgn );
9063 MoveWindow( hchild, -10, -10, 100, 100, FALSE );
9064 SetRectRgn( hrgn, 10, 10, 40, 40 );
9065 check_update_rgn( hchild, hrgn );
9067 /* moving parent off-screen does too */
9068 SetRect( &rect, 0, 0, 100, 100 );
9069 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
9070 SetRectRgn( hrgn, 0, 0, 100, 100 );
9071 check_update_rgn( hparent, hrgn );
9072 SetRectRgn( hrgn, 10, 10, 40, 40 );
9073 check_update_rgn( hchild, hrgn );
9074 MoveWindow( hparent, -20, -20, 200, 200, FALSE );
9075 GetUpdateRect( hparent, &rect2, FALSE );
9076 if (!EqualRect( &rect2, &rect )) /* Win 8 and later don't crop update to screen */
9078 rect.left += 20;
9079 rect.top += 20;
9081 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
9082 check_update_rgn( hparent, hrgn );
9083 SetRectRgn( hrgn, rect.left + 10, rect.top + 10, 40, 40 );
9084 check_update_rgn( hchild, hrgn );
9086 /* invalidated region is cropped by the parent rects */
9087 SetRect( &rect, 0, 0, 50, 50 );
9088 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
9089 SetRectRgn( hrgn, rect2.left + 10, rect2.top + 10, 50, 50 );
9090 check_update_rgn( hchild, hrgn );
9092 DestroyWindow( hparent );
9093 ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
9094 flush_sequence();
9096 DeleteObject( hrgn );
9097 DeleteObject( hrgn2 );
9100 static void visualize_region_differences( HWND hwnd, HWND hother, HRGN hrgn_expect, HRGN hrgn_actual )
9102 HBRUSH b_expectonly, b_actualonly, b_intersect;
9103 HRGN hrgn_intersect;
9104 HWND hstatic, hshow, hhide;
9105 HDC hdc, hdctmp;
9106 HBITMAP hbitmap;
9107 MSG msg;
9108 RECT rect;
9109 DWORD start_time, elapsed, timeout = 60 * 1000;
9110 BOOL toggle = TRUE, stop = FALSE;
9112 start_time = GetTickCount();
9114 b_expectonly = CreateSolidBrush( RGB( 64, 64, 255 ));
9115 b_actualonly = CreateSolidBrush( RGB( 255, 64, 64 ));
9116 b_intersect = CreateSolidBrush( RGB( 159, 64, 159 ));
9118 hrgn_intersect = CreateRectRgn( 0, 0, 0, 0 );
9119 CombineRgn( hrgn_intersect, hrgn_expect, hrgn_actual, RGN_AND );
9121 GetClientRect( hwnd, &rect );
9122 hdc = GetDC( hwnd );
9123 hbitmap = CreateCompatibleBitmap( hdc, rect.right, rect.bottom );
9124 hdctmp = CreateCompatibleDC( hdc );
9125 ReleaseDC( hwnd, hdc );
9127 SelectObject( hdctmp, hbitmap );
9128 FillRgn( hdctmp, hrgn_expect, b_expectonly );
9129 FillRgn( hdctmp, hrgn_actual, b_actualonly );
9130 FillRgn( hdctmp, hrgn_intersect, b_intersect );
9132 DeleteObject( hdctmp );
9133 DeleteObject( hrgn_intersect );
9134 DeleteObject( b_intersect );
9135 DeleteObject( b_actualonly );
9136 DeleteObject( b_expectonly );
9138 hstatic = CreateWindowExA( 0, WC_STATICA, "", WS_CHILD | SS_BITMAP,
9139 0, 0, rect.right, rect.bottom, hwnd, 0, 0, NULL );
9140 SendMessageA( hstatic, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbitmap );
9142 hshow = hstatic;
9143 hhide = hother;
9145 for (;;)
9147 if (stop) toggle = hshow == hother;
9148 if (toggle)
9150 HWND htmp;
9151 HDWP hdwp;
9153 hdwp = BeginDeferWindowPos( !!hhide + !!hshow );
9154 if (hhide)
9156 DeferWindowPos( hdwp, hhide, NULL, 0, 0, 0, 0,
9157 SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER );
9159 if (hshow)
9161 DeferWindowPos( hdwp, hshow, HWND_TOP, 0, 0, 0, 0,
9162 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE );
9164 EndDeferWindowPos( hdwp );
9166 htmp = hshow;
9167 hshow = hhide;
9168 hhide = htmp;
9169 toggle = FALSE;
9171 if (stop) break;
9172 if ((elapsed = GetTickCount() - start_time) >= timeout)
9174 stop = TRUE;
9175 continue;
9177 MsgWaitForMultipleObjects( 0, NULL, FALSE, timeout - elapsed, QS_ALLINPUT );
9178 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
9180 TranslateMessage( &msg );
9181 DispatchMessageA( &msg );
9182 if (msg.message == WM_MOUSEMOVE)
9184 start_time = GetTickCount();
9186 else if (msg.message == WM_LBUTTONUP || (msg.message == WM_CHAR && msg.wParam == VK_SPACE))
9188 toggle = !toggle;
9190 else if (msg.message == WM_RBUTTONUP || (msg.message == WM_CHAR && msg.wParam == VK_RETURN))
9192 stop = TRUE;
9197 DestroyWindow( hstatic );
9198 DeleteObject( hbitmap );
9201 #define subtest_swp_paint_regions(w,p,c) subtest_swp_paint_regions_(__LINE__,w,p,c)
9203 static void subtest_swp_paint_regions_( int line, int wrap_toplevel, LPCSTR parent_class, LPCSTR child_class )
9205 static const struct exposure_test {
9206 int ex_style, style;
9207 BOOL shuffle_zorder;
9208 } exposure_tests[] = {
9209 { 0, WS_CLIPCHILDREN, FALSE },
9210 { 0, 0, FALSE },
9211 { WS_EX_COMPOSITED, WS_CLIPCHILDREN, TRUE },
9212 { WS_EX_COMPOSITED, 0, FALSE },
9213 { WS_EX_COMPOSITED, 0, TRUE },
9215 size_t i;
9216 HWND htoplevel = NULL, hparent, hchild, hauxchild;
9217 const RECT rect_old = { 10, 10, 100, 100 };
9218 HRGN hrgn_old_vis = CreateRectRgn( 0, 0, 0, 0 );
9219 HRGN hrgn_new_vis = CreateRectRgn( 0, 0, 0, 0 );
9220 HRGN hrgn_expect = CreateRectRgn( 0, 0, 0, 0 );
9221 HRGN hrgn_actual = CreateRectRgn( 0, 0, 0, 0 );
9222 HRGN hrgn_old_vis_child = CreateRectRgn( 0, 0, 0, 0 );
9223 HRGN hrgn_new_vis_child = CreateRectRgn( 0, 0, 0, 0 );
9224 HRGN hrgn_expect_child = CreateRectRgn( 0, 0, 0, 0 );
9225 HRGN hrgn_actual_child = CreateRectRgn( 0, 0, 0, 0 );
9226 int base_style;
9227 BOOL is_composition_possible, has_parentdc_anomaly;
9228 WNDCLASSA parent_wc;
9230 if (wrap_toplevel)
9232 htoplevel = CreateWindowExA( 0, "SimpleWindowClass", "Test toplevel", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9233 100, 100, 400, 400, 0, 0, 0, NULL );
9234 ok( htoplevel != 0, "Failed to create top-level window: %lu\n", GetLastError() );
9235 base_style = WS_CHILD | WS_VISIBLE;
9237 else
9239 base_style = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
9242 ok( GetClassInfoA( GetModuleHandleA( NULL ), parent_class, &parent_wc ),
9243 "GetClassInfoA failed\n" );
9245 is_composition_possible = (base_style & (WS_POPUP|WS_CHILD)) != WS_CHILD ||
9246 (parent_wc.style & CS_PARENTDC) == 0;
9248 has_parentdc_anomaly = (base_style & (WS_POPUP|WS_CHILD)) != WS_CHILD &&
9249 (parent_wc.style & CS_PARENTDC) != 0;
9251 hparent = CreateWindowExA( 0, parent_class, "Test parent", base_style,
9252 80, 80, 200, 200, htoplevel, 0, 0, NULL );
9253 ok( hparent != 0, "Creating parent window (%s) returned error %lu\n",
9254 debugstr_a( parent_class ), GetLastError() );
9256 hchild = CreateWindowExA( 0, child_class, "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
9257 rect_old.left, rect_old.top,
9258 rect_old.right - rect_old.left, rect_old.bottom - rect_old.top,
9259 hparent, 0, 0, NULL );
9260 ok( hchild != 0, "Creating child window (%s) returned error %lu\n",
9261 debugstr_a( child_class ), GetLastError() );
9263 hauxchild = CreateWindowExA( 0, child_class, "Auxiliary child for z order test", WS_CHILD | WS_VISIBLE,
9264 110, 0, 0, 0, hparent, 0, 0, NULL );
9265 ok( hauxchild != 0, "Creating child window (%s) returned error %lu\n",
9266 debugstr_a( child_class ), GetLastError() );
9268 for (i = 0; i < ARRAY_SIZE(exposure_tests); i++)
9270 const struct exposure_test *extest = &exposure_tests[i];
9271 BOOL has_ws_ex_composited = (extest->ex_style & WS_EX_COMPOSITED) != 0;
9272 BOOL is_composited = is_composition_possible && has_ws_ex_composited;
9273 BOOL is_zorder_redraw = is_composited && extest->shuffle_zorder;
9274 int delta;
9276 winetest_push_context( "%d: SetWindowPos redraw #%Id (ex_style = %#x, style = %#x, shuffle_zorder = %d)",
9277 line, i, extest->ex_style, extest->style, extest->shuffle_zorder );
9279 SetWindowLongA( hparent, GWL_EXSTYLE, extest->ex_style );
9280 SetWindowLongA( hparent, GWL_STYLE, base_style | extest->style );
9281 RedrawWindow( hparent, NULL, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
9283 for (delta = -20; delta <= 0; delta += 20)
9285 RECT rect_old_vis, rect_new, rect_new_vis;
9286 RECT rect_parent_clip, rect_child_clip;
9287 RECT rect_old_vis_child, rect_new_vis_child;
9288 BOOL rgn_ok;
9290 winetest_push_context( "delta = %+d", delta );
9292 SetWindowPos( hchild, HWND_TOP,
9293 rect_old.left,
9294 rect_old.top,
9295 rect_old.right - rect_old.left,
9296 rect_old.bottom - rect_old.top,
9297 SWP_NOACTIVATE );
9299 rect_new = rect_old;
9300 OffsetRect( &rect_new, delta, delta );
9302 rect_old_vis_child = rect_old;
9303 MapWindowPoints( hparent, hchild, (POINT *)&rect_old_vis_child, 2 );
9305 SetRectRgn( hrgn_actual, 0, 0, 0, 0 );
9306 SetRectRgn( hrgn_actual_child, 0, 0, 0, 0 );
9308 UpdateWindow( hparent );
9309 flush_events();
9311 if (extest->shuffle_zorder)
9313 /* bring sibling to top/bottom first so we can trigger z-order change */
9314 SetWindowPos( hauxchild, HWND_TOP, 0, 0, 0, 0,
9315 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
9318 SetWindowPos( hchild, HWND_TOP,
9319 rect_new.left,
9320 rect_new.top,
9321 rect_new.right - rect_new.left,
9322 rect_new.bottom - rect_new.top,
9323 SWP_NOACTIVATE |
9324 (extest->shuffle_zorder ? 0 : SWP_NOZORDER) );
9326 ok( GetUpdateRgn( hparent, hrgn_actual, FALSE ) != ERROR,
9327 "GetUpdateRgn on parentshall succeed\n" );
9328 ok( GetUpdateRgn( hchild, hrgn_actual_child, FALSE ) != ERROR,
9329 "GetUpdateRgn on child shall succeed\n" );
9331 /* Compute parent window expose region */
9332 GetClientRect( hparent, &rect_parent_clip );
9333 IntersectRect( &rect_old_vis, &rect_old, &rect_parent_clip );
9334 SetRectRgn( hrgn_old_vis, rect_old_vis.left, rect_old_vis.top, rect_old_vis.right, rect_old_vis.bottom );
9335 IntersectRect( &rect_new_vis, &rect_new, &rect_parent_clip );
9336 SetRectRgn( hrgn_new_vis, rect_new_vis.left, rect_new_vis.top, rect_new_vis.right, rect_new_vis.bottom );
9338 if (!EqualRect( &rect_old, &rect_new ) || is_zorder_redraw)
9340 CombineRgn( hrgn_expect, hrgn_old_vis, hrgn_new_vis, is_composited ? RGN_OR : RGN_DIFF );
9342 else
9344 SetRectRgn( hrgn_expect, 0, 0, 0, 0 );
9347 rgn_ok = EqualRgn( hrgn_expect, hrgn_actual );
9348 if (!rgn_ok && broken( has_parentdc_anomaly && is_composited /* Win7 */ ))
9350 if (winetest_debug > 1)
9352 trace( "Forcing non-composited update region (broken)\n" );
9354 rgn_ok = 1;
9356 else
9358 ok( !!rgn_ok, "Parent update region shall match expected region\n" );
9361 if (!rgn_ok)
9363 trace( "Expected parent update region: " );
9364 dump_region( hrgn_expect );
9365 trace( "Actual parent update region: " );
9366 dump_region( hrgn_actual );
9367 trace( "Old child window visible area: %s\n", wine_dbgstr_rect( &rect_old_vis ) );
9368 trace( "New child window visible area: %s\n", wine_dbgstr_rect( &rect_new_vis ) );
9371 if (winetest_interactive)
9373 if (!rgn_ok)
9375 visualize_region_differences( hparent, hchild, hrgn_expect, hrgn_actual );
9378 /* Let the position change be visible to the user */
9379 flush_events();
9382 rect_new_vis_child = rect_new;
9383 MapWindowPoints( hparent, hchild, (POINT *)&rect_new_vis_child, 2 );
9385 /* Compute child window expose region */
9386 GetClientRect( hchild, &rect_child_clip );
9387 if (is_composited)
9389 RECT rect_outer_clip;
9390 GetClientRect( hparent, &rect_outer_clip );
9391 MapWindowPoints( hparent, hchild, (POINT *)&rect_outer_clip, 2 );
9392 IntersectRect( &rect_child_clip, &rect_child_clip, &rect_outer_clip );
9394 IntersectRect( &rect_old_vis_child, &rect_old_vis_child, &rect_child_clip );
9395 SetRectRgn( hrgn_old_vis_child, rect_old_vis_child.left, rect_old_vis_child.top, rect_old_vis_child.right, rect_old_vis_child.bottom );
9396 IntersectRect( &rect_new_vis_child, &rect_new_vis_child, &rect_child_clip );
9397 SetRectRgn( hrgn_new_vis_child, rect_new_vis_child.left, rect_new_vis_child.top, rect_new_vis_child.right, rect_new_vis_child.bottom );
9399 if (!EqualRect( &rect_old, &rect_new ) || is_zorder_redraw)
9401 CombineRgn( hrgn_expect_child, hrgn_new_vis_child, hrgn_old_vis_child, is_composited ? RGN_OR : RGN_DIFF );
9403 else
9405 SetRectRgn( hrgn_expect_child, 0, 0, 0, 0 );
9408 rgn_ok = EqualRgn( hrgn_expect_child, hrgn_actual_child );
9409 if (!rgn_ok && broken( has_parentdc_anomaly && is_composited /* Win7 */ ))
9411 if (winetest_debug > 1)
9413 trace( "Forcing non-composited update region (broken)\n" );
9415 rgn_ok = 1;
9417 else
9419 ok( !!rgn_ok, "Child update region shall match expected region\n" );
9422 if (!rgn_ok)
9424 trace( "Expected child update region: " );
9425 dump_region( hrgn_expect_child );
9426 trace( "Actual child update region: " );
9427 dump_region( hrgn_actual_child );
9428 trace( "Old child window client visible area: %s\n", wine_dbgstr_rect( &rect_old_vis_child ) );
9429 trace( "New child window client visible area: %s\n", wine_dbgstr_rect( &rect_new_vis_child ) );
9432 if (winetest_interactive)
9434 if (!rgn_ok)
9436 visualize_region_differences( hchild, NULL, hrgn_expect_child, hrgn_actual_child );
9439 /* Let the position change be visible to the user */
9440 flush_events();
9443 winetest_pop_context();
9446 winetest_pop_context();
9449 DestroyWindow( hauxchild );
9450 DestroyWindow( hchild );
9451 DestroyWindow( hparent );
9452 if (htoplevel) DestroyWindow( htoplevel );
9454 DeleteObject( hrgn_actual_child );
9455 DeleteObject( hrgn_expect_child );
9456 DeleteObject( hrgn_new_vis_child );
9457 DeleteObject( hrgn_old_vis_child );
9458 DeleteObject( hrgn_actual );
9459 DeleteObject( hrgn_expect );
9460 DeleteObject( hrgn_new_vis );
9461 DeleteObject( hrgn_old_vis );
9464 static void test_swp_paint_regions(void)
9466 subtest_swp_paint_regions( 1, "SimpleWindowClass", "SimpleWindowClass" );
9467 subtest_swp_paint_regions( 0, "SimpleWindowClass", "SimpleWindowClass" );
9468 subtest_swp_paint_regions( 0, "SimpleWindowClass", "SimpleWindowClassWithParentDC" );
9469 subtest_swp_paint_regions( 0, "SimpleWindowClassWithParentDC", "SimpleWindowClass" );
9472 static void test_swp_paint_region_on_show(void)
9474 HRGN hrgn_actual_child = CreateRectRgn( 0, 0, 0, 0 );
9475 HRGN hrgn_actual = CreateRectRgn( 0, 0, 0, 0 );
9476 const RECT rect_1 = { 10, 10, 100, 100 };
9477 const RECT rect_2 = { 20, 20, 120, 120 };
9478 RECT rect_expect_child, rect_expect;
9479 RECT rect_actual_child, rect_actual;
9480 HWND hparent, hchild;
9481 int result;
9483 hparent = CreateWindowExA( 0, "SimpleWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9484 80, 80, 200, 200, NULL, 0, 0, NULL );
9485 ok( hparent != 0, "Creating parent window returned error %lu\n", GetLastError() );
9487 hchild = CreateWindowExA( 0, "SimpleWindowClass", "Test child", WS_CHILD | WS_BORDER,
9488 0, 0, 100, 100, hparent, 0, 0, NULL );
9489 ok( hchild != 0, "Creating child window returned error %lu\n", GetLastError() );
9491 if (winetest_debug > 1) trace("testing show window (no move / size)\n");
9493 SetWindowPos( hchild, HWND_TOP,
9494 rect_1.left, rect_1.top, rect_1.right - rect_1.left, rect_1.bottom - rect_1.top,
9495 SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOZORDER );
9497 UpdateWindow( hparent );
9498 flush_events();
9500 SetWindowPos( hchild, HWND_TOP, 0, 0, 0, 0,
9501 SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE );
9503 ok( GetUpdateRgn( hparent, hrgn_actual, FALSE ) != ERROR,
9504 "GetUpdateRgn on parent shall succeed\n" );
9505 ok( GetUpdateRgn( hchild, hrgn_actual_child, FALSE ) != ERROR,
9506 "GetUpdateRgn on child shall succeed\n" );
9508 result = GetRgnBox( hrgn_actual, &rect_actual );
9509 ok( result == SIMPLEREGION, "GetRgnBox (on parent) returned %d\n", result );
9510 if (result == COMPLEXREGION) dump_region( hrgn_actual );
9512 rect_expect = rect_1;
9513 ok( EqualRect( &rect_actual, &rect_expect ), "parent update region: got %s, expected %s\n",
9514 wine_dbgstr_rect( &rect_actual ), wine_dbgstr_rect( &rect_expect ) );
9516 result = GetRgnBox( hrgn_actual_child, &rect_actual_child );
9517 ok( result == SIMPLEREGION, "GetRgnBox (on child) returned %d\n", result );
9518 if (result == COMPLEXREGION) dump_region( hrgn_actual_child );
9520 ok( GetClientRect( hchild, &rect_expect_child ), "GetClientRect failed\n" );
9521 ok( EqualRect( &rect_actual_child, &rect_expect_child ), "child update region: got %s, expected %s\n",
9522 wine_dbgstr_rect( &rect_actual_child ), wine_dbgstr_rect( &rect_expect_child ) );
9524 if (winetest_debug > 1) trace("testing show window (with move / resize)\n");
9526 SetWindowPos( hchild, HWND_TOP,
9527 rect_1.left, rect_1.top, rect_1.right - rect_1.left, rect_1.bottom - rect_1.top,
9528 SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOZORDER );
9530 UpdateWindow( hparent );
9531 flush_events();
9533 SetWindowPos( hchild, HWND_TOP,
9534 rect_2.left,
9535 rect_2.top,
9536 rect_2.right - rect_2.left,
9537 rect_2.bottom - rect_2.top,
9538 SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER );
9540 ok( GetUpdateRgn( hparent, hrgn_actual, FALSE ) != ERROR,
9541 "GetUpdateRgn on parent shall succeed\n" );
9542 ok( GetUpdateRgn( hchild, hrgn_actual_child, FALSE ) != ERROR,
9543 "GetUpdateRgn on child shall succeed\n" );
9545 result = GetRgnBox( hrgn_actual, &rect_actual );
9546 ok( result == SIMPLEREGION, "GetRgnBox (on parent) returned %d\n", result );
9547 if (result == COMPLEXREGION) dump_region( hrgn_actual );
9549 rect_expect = rect_2;
9550 ok( EqualRect( &rect_actual, &rect_expect ), "parent update region: got %s, expected %s\n",
9551 wine_dbgstr_rect( &rect_actual ), wine_dbgstr_rect( &rect_expect ) );
9553 result = GetRgnBox( hrgn_actual_child, &rect_actual_child );
9554 ok( result == SIMPLEREGION, "GetRgnBox (on child) returned %d\n", result );
9555 if (result == COMPLEXREGION) dump_region( hrgn_actual_child );
9557 ok( GetClientRect( hchild, &rect_expect_child ), "GetClientRect failed\n" );
9558 ok( EqualRect( &rect_actual_child, &rect_expect_child ), "child update region: got %s, expected %s\n",
9559 wine_dbgstr_rect( &rect_actual_child ), wine_dbgstr_rect( &rect_expect_child ) );
9561 DestroyWindow( hchild );
9562 DestroyWindow( hparent );
9563 DeleteObject( hrgn_actual_child );
9564 DeleteObject( hrgn_actual );
9567 static void test_swp_paint_region_on_extend_zerosize(void)
9569 HRGN hrgn_actual_child = CreateRectRgn( 0, 0, 0, 0 );
9570 HRGN hrgn_actual = CreateRectRgn( 0, 0, 0, 0 );
9571 const RECT rect_1 = { 10, 10, 100, 100 };
9572 RECT rect_expect_child, rect_expect;
9573 RECT rect_actual_child, rect_actual;
9574 HWND hparent, hchild;
9575 int result;
9577 hparent = CreateWindowExA( 0, "SimpleWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9578 80, 80, 200, 200, NULL, 0, 0, NULL );
9579 ok( hparent != 0, "Creating parent window returned error %lu\n", GetLastError() );
9581 hchild = CreateWindowExA( 0, "SimpleWindowClass", "Test child (no border)", WS_CHILD | WS_VISIBLE,
9582 10, 10, 0, 0, hparent, 0, 0, NULL );
9583 ok( hchild != 0, "Creating child window returned error %lu\n", GetLastError() );
9585 if (winetest_debug > 1) trace("testing extending zero-size window\n");
9587 UpdateWindow( hparent );
9588 flush_events();
9590 SetWindowPos( hchild, HWND_TOP,
9591 rect_1.left,
9592 rect_1.top,
9593 rect_1.right - rect_1.left,
9594 rect_1.bottom - rect_1.top,
9595 SWP_NOACTIVATE | SWP_NOZORDER );
9597 ok( GetUpdateRgn( hparent, hrgn_actual, FALSE ) != ERROR,
9598 "GetUpdateRgn on parent shall succeed\n" );
9599 ok( GetUpdateRgn( hchild, hrgn_actual_child, FALSE ) != ERROR,
9600 "GetUpdateRgn on child shall succeed\n" );
9602 result = GetRgnBox( hrgn_actual, &rect_actual );
9603 ok( result == SIMPLEREGION, "GetRgnBox (on parent) returned %d\n", result );
9604 if (result == COMPLEXREGION) dump_region( hrgn_actual );
9606 rect_expect = rect_1;
9607 ok( EqualRect( &rect_actual, &rect_expect ), "parent update region: got %s, expected %s\n",
9608 wine_dbgstr_rect( &rect_actual ), wine_dbgstr_rect( &rect_expect ) );
9610 result = GetRgnBox( hrgn_actual_child, &rect_actual_child );
9611 ok( result == SIMPLEREGION, "GetRgnBox (on child) returned %d\n", result );
9612 if (result == COMPLEXREGION) dump_region( hrgn_actual_child );
9614 ok( GetClientRect( hchild, &rect_expect_child ), "GetClientRect failed\n" );
9615 ok( EqualRect( &rect_actual_child, &rect_expect_child ), "child update region: got %s, expected %s\n",
9616 wine_dbgstr_rect( &rect_actual_child ), wine_dbgstr_rect( &rect_expect_child ) );
9618 DestroyWindow( hchild );
9619 DestroyWindow( hparent );
9620 DeleteObject( hrgn_actual_child );
9621 DeleteObject( hrgn_actual );
9624 static void subtest_hvredraw(HWND hparent, UINT class_style, DWORD style)
9626 static const struct movesize_test {
9627 int dx, dy, dw, dh;
9628 } movesize_tests[] = {
9629 { 0, 0, 0, 5 },
9630 { 0, 0, 5, 0 },
9631 { 0, 0, 5, 5 },
9632 { 0, 0, -5, -5 },
9633 { -5, -5, 0, 5 },
9634 { -5, -5, 5, 0 },
9635 { -5, -5, 5, 5 },
9637 HRGN hrgn_old_vis = CreateRectRgn( 0, 0, 0, 0 );
9638 HRGN hrgn_new_vis = CreateRectRgn( 0, 0, 0, 0 );
9639 HRGN hrgn_expect = CreateRectRgn( 0, 0, 0, 0 );
9640 HRGN hrgn_actual = CreateRectRgn( 0, 0, 0, 0 );
9641 const int x0 = 100, y0 = 100, w0 = 150, h0 = 150;
9642 size_t i;
9643 HWND hwnd;
9644 WNDCLASSA cls = {
9645 .style = class_style,
9646 .lpfnWndProc = DefWindowProcA,
9647 .hInstance = GetModuleHandleA(0),
9648 .hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW),
9649 .hbrBackground = GetStockObject(WHITE_BRUSH),
9650 .lpszClassName = "TestHVRedrawClass"
9653 register_class(&cls);
9655 hwnd = CreateWindowExA( 0, cls.lpszClassName, "Test window", style, x0, y0, w0, h0, hparent, 0, 0, NULL );
9656 ok(hwnd != NULL, "Failed to create the window\n");
9658 ShowWindow( hwnd, SW_SHOW );
9659 UpdateWindow( hwnd );
9661 for (i = 0; i < ARRAY_SIZE(movesize_tests); i++)
9663 const struct movesize_test *test = &movesize_tests[i];
9664 int is_redraw = (test->dw != 0 && (class_style & CS_HREDRAW)) ||
9665 (test->dh != 0 && (class_style & CS_VREDRAW));
9666 RECT rect_old_vis, rect_new_vis;
9667 BOOL rgn_ok;
9669 winetest_push_context( "%x %08lx SetWindowPos redraw #%Id (%d, %d, %d, %d)",
9670 class_style, style, i, test->dx, test->dy, test->dw, test->dh );
9672 SetWindowPos( hwnd, HWND_TOP, x0, y0, w0, h0, SWP_NOACTIVATE );
9674 GetClientRect( hwnd, &rect_old_vis );
9675 SetRectRgn( hrgn_old_vis, rect_old_vis.left, rect_old_vis.top, rect_old_vis.right, rect_old_vis.bottom );
9677 UpdateWindow( hparent );
9678 flush_events();
9680 SetWindowPos( hwnd, HWND_TOP,
9681 x0 + test->dx, y0 + test->dy,
9682 w0 + test->dw, h0 + test->dh, SWP_NOACTIVATE );
9683 ok( GetUpdateRgn( hwnd, hrgn_actual, FALSE ) != ERROR, "GetUpdateRgn shall succeed\n" );
9685 GetClientRect( hwnd, &rect_new_vis );
9686 SetRectRgn( hrgn_new_vis, rect_new_vis.left, rect_new_vis.top, rect_new_vis.right, rect_new_vis.bottom );
9687 CombineRgn( hrgn_expect, hrgn_new_vis, hrgn_old_vis, is_redraw ? RGN_COPY : RGN_DIFF );
9689 rgn_ok = EqualRgn( hrgn_expect, hrgn_actual );
9690 ok( !!rgn_ok, "Update region shall match expected region\n" );
9692 if (!rgn_ok)
9694 trace( "Expected update region: " );
9695 dump_region( hrgn_expect );
9696 trace( "Actual update region: " );
9697 dump_region( hrgn_actual );
9698 trace( "Old window visible area: %s\n", wine_dbgstr_rect( &rect_old_vis ) );
9699 trace( "New window visible area: %s\n", wine_dbgstr_rect( &rect_new_vis ) );
9702 if (winetest_interactive)
9704 if (!rgn_ok)
9706 visualize_region_differences( hwnd, NULL, hrgn_expect, hrgn_actual );
9709 /* Let the position change be visible to the user */
9710 flush_events();
9713 winetest_pop_context();
9716 DestroyWindow( hwnd );
9717 DeleteObject( hrgn_actual );
9718 DeleteObject( hrgn_expect );
9719 DeleteObject( hrgn_new_vis );
9720 DeleteObject( hrgn_old_vis );
9721 UnregisterClassA( cls.lpszClassName, cls.hInstance );
9725 static void test_hvredraw(void)
9727 HWND htoplevel;
9729 subtest_hvredraw( NULL, CS_HREDRAW, WS_OVERLAPPEDWINDOW );
9730 subtest_hvredraw( NULL, CS_VREDRAW, WS_OVERLAPPEDWINDOW );
9731 subtest_hvredraw( NULL, CS_HREDRAW|CS_VREDRAW, WS_OVERLAPPEDWINDOW );
9733 htoplevel = CreateWindowExA( 0, "SimpleWindowClass", "Test toplevel",
9734 WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_VISIBLE,
9735 100, 100, 400, 400, 0, 0, 0, NULL );
9736 ok( htoplevel != 0, "Failed to create top-level window: %lu\n", GetLastError() );
9738 subtest_hvredraw( htoplevel, CS_HREDRAW, WS_CHILD | WS_BORDER );
9739 subtest_hvredraw( htoplevel, CS_VREDRAW, WS_CHILD | WS_BORDER );
9740 subtest_hvredraw( htoplevel, CS_HREDRAW|CS_VREDRAW, WS_CHILD | WS_BORDER );
9742 DestroyWindow( htoplevel );
9745 struct run_in_temp_desktop_args
9747 const char *file;
9748 int line;
9749 const char *name;
9750 void (*test_func)(void);
9753 static DWORD WINAPI run_in_temp_desktop_thread_func(LPVOID param)
9755 HDESK prev_thr_desktop, prev_inp_desktop, post_inp_desktop, temp_desktop;
9756 char temp_desktop_name[1024], curr_desktop_name[1024];
9757 struct run_in_temp_desktop_args *args = param;
9758 const char *file = args->file;
9759 int line = args->line;
9760 LARGE_INTEGER qpc;
9761 DWORD length;
9762 int result;
9764 result = QueryPerformanceCounter( &qpc );
9765 ok_(file, line)( result, "QueryPerformanceCounter error %lu\n", GetLastError() );
9768 * Temporary desktops from previous runs may leak due to a Windows bug.
9769 * Generate a unique name that is unlikely to collide with previous runs.
9771 result = snprintf( temp_desktop_name, ARRAY_SIZE(temp_desktop_name),
9772 "WineTest-%08lX-%08lX-%08lX%08lX-%s",
9773 GetCurrentProcessId(), GetCurrentThreadId(),
9774 qpc.HighPart, qpc.LowPart, args->name );
9775 ok_(file, line)( result > 0 && result < ARRAY_SIZE(temp_desktop_name),
9776 "sprintf returned %d (out of memory, or name too long?)\n", result );
9778 if (winetest_debug > 1)
9779 trace_(file, line)( "creating desktop: %s\n", debugstr_a( temp_desktop_name ) );
9781 temp_desktop = CreateDesktopA( temp_desktop_name, NULL, NULL, 0, GENERIC_ALL, NULL );
9782 ok_(file, line)( temp_desktop != NULL, "CreateDesktopA(%s, ..) error %lu\n",
9783 debugstr_a( temp_desktop_name ), GetLastError() );
9785 prev_inp_desktop = OpenInputDesktop( 0, FALSE, DESKTOP_SWITCHDESKTOP );
9786 ok_(file, line)( prev_inp_desktop != NULL, "OpenInputDesktop [prev] error %lu\n", GetLastError() );
9788 if (winetest_debug > 1)
9789 trace_(file, line)( "sanity check: no concurrent WineTest desktop\n" );
9792 * Check if the desktop has not been properly restored. This is done to
9793 * avoid any possible hard-to-debug failures due to unexpected desktop.
9795 result = GetUserObjectInformationA( prev_inp_desktop, UOI_NAME,
9796 curr_desktop_name, sizeof(curr_desktop_name), &length );
9797 ok_(file, line)( result, "GetUserObjectInformationA error %lu [rl = %lu]\n",
9798 GetLastError(), length );
9799 ok_(file, line)( _strnicmp( curr_desktop_name, temp_desktop_name, 8 ) != 0,
9800 "unexpected input desktop name %s (concurrent WineTest run?)\n",
9801 debugstr_a( curr_desktop_name ) );
9803 if (winetest_debug > 1)
9804 trace_(file, line)( "switching desktop to: %s (%p)\n", debugstr_a( temp_desktop_name ), temp_desktop );
9806 result = SwitchDesktop( temp_desktop );
9807 ok_(file, line)( result, "SwitchDesktop(temp_desktop=%p) error %lu\n",
9808 temp_desktop, GetLastError() );
9810 prev_thr_desktop = GetThreadDesktop( GetCurrentThreadId() );
9811 ok_(file, line)( prev_thr_desktop != NULL, "GetThreadDesktop error %lu\n", GetLastError() );
9813 result = SetThreadDesktop( temp_desktop );
9814 ok_(file, line)( result, "SetThreadDesktop(temp_desktop=%p) error %lu\n",
9815 temp_desktop, GetLastError() );
9817 if (winetest_debug > 1)
9818 trace_(file, line)( "running test function %s()\n", args->name );
9820 args->test_func();
9822 if (winetest_debug > 1)
9823 trace_(file, line)( "sanity check: input desktop has not been changed\n" );
9826 * Check if the input desktop has been tampered with. This is done to
9827 * avoid any possible hard-to-debug failures due to unexpected desktop.
9829 post_inp_desktop = OpenInputDesktop( 0, FALSE, DESKTOP_ENUMERATE );
9830 ok_(file, line)( post_inp_desktop != NULL, "OpenInputDesktop [post] error %lu\n", GetLastError() );
9832 result = GetUserObjectInformationA( post_inp_desktop, UOI_NAME,
9833 curr_desktop_name, sizeof(curr_desktop_name), &length );
9834 ok_(file, line)( result, "GetUserObjectInformationA(post_inp_desktop=%p) error %lu [rl = %lu]\n",
9835 post_inp_desktop, GetLastError(), length );
9836 ok_(file, line)( strcmp( curr_desktop_name, temp_desktop_name ) == 0,
9837 "different desktop name: %s != %s (no switch or concurrent WineTest run?)\n",
9838 debugstr_a( curr_desktop_name ), debugstr_a( temp_desktop_name ) );
9840 result = CloseDesktop( post_inp_desktop );
9841 ok_(file, line)( result, "CloseDesktop(post_inp_desktop=%p) error %lu\n",
9842 post_inp_desktop, GetLastError() );
9844 if (winetest_debug > 1)
9845 trace_(file, line)( "restoring previous desktop\n" );
9847 result = SetThreadDesktop( prev_thr_desktop );
9848 ok_(file, line)( result || broken( GetLastError() == ERROR_BUSY ) /* == W10 */,
9849 "SetThreadDesktop(prev_thr_desktop=%p) error %lu\n",
9850 prev_thr_desktop, GetLastError() );
9852 result = SwitchDesktop( prev_inp_desktop );
9853 ok_(file, line)( result, "SwitchDesktop(prev_inp_desktop=%p) error %lu\n",
9854 prev_inp_desktop, GetLastError() );
9856 result = CloseDesktop( prev_inp_desktop );
9857 ok_(file, line)( result, "CloseDesktop(prev_inp_desktop=%p) error %lu\n",
9858 prev_inp_desktop, GetLastError() );
9860 if (winetest_debug > 1)
9861 trace_(file, line)( "closing desktop: %s (%p)\n", debugstr_a( temp_desktop_name ), temp_desktop );
9863 result = CloseDesktop( temp_desktop );
9864 ok_(file, line)( result || broken( GetLastError() == ERROR_BUSY ) /* == W10 */,
9865 "CloseDesktop(temp_desktop=%p) error %lu\n",
9866 temp_desktop, GetLastError() );
9868 return 0;
9871 #define run_in_temp_desktop(f) run_in_temp_desktop_(__FILE__, __LINE__, #f, f)
9872 static void run_in_temp_desktop_(const char *file, int line, const char *name, void (*test_func)(void))
9874 struct run_in_temp_desktop_args args;
9875 HANDLE thread;
9876 DWORD result;
9878 args.file = file;
9879 args.line = line;
9880 args.name = name;
9881 args.test_func = test_func;
9883 thread = CreateThread( NULL, 0, run_in_temp_desktop_thread_func, &args, 0, NULL );
9884 ok_(file, line)( thread != NULL, "CreateThread error %lu\n", GetLastError() );
9886 result = WaitForSingleObject( thread, INFINITE );
9887 ok_(file, line)( result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu, error %lu\n",
9888 result, GetLastError() );
9890 CloseHandle( thread );
9893 struct wnd_event
9895 HWND hwnd;
9896 HANDLE grand_child;
9897 HANDLE start_event;
9898 HANDLE stop_event;
9899 HANDLE getmessage_complete;
9902 static DWORD WINAPI thread_proc(void *param)
9904 MSG msg;
9905 struct wnd_event *wnd_event = param;
9907 wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
9908 100, 100, 200, 200, 0, 0, 0, NULL);
9909 ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
9911 SetEvent(wnd_event->start_event);
9913 while (GetMessageA(&msg, 0, 0, 0))
9915 TranslateMessage(&msg);
9916 DispatchMessageA(&msg);
9919 ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
9921 return 0;
9924 static DWORD CALLBACK create_grand_child_thread( void *param )
9926 struct wnd_event *wnd_event = param;
9927 HWND hchild;
9928 MSG msg;
9930 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
9931 WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
9932 ok (hchild != 0, "Failed to create child window\n");
9933 flush_events();
9934 flush_sequence();
9935 SetEvent( wnd_event->start_event );
9937 for (;;)
9939 MsgWaitForMultipleObjects(0, NULL, FALSE, 1000, QS_ALLINPUT);
9940 if (!IsWindow( hchild )) break; /* will be destroyed when parent thread exits */
9941 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
9943 return 0;
9946 static DWORD CALLBACK create_child_thread( void *param )
9948 struct wnd_event *wnd_event = param;
9949 struct wnd_event child_event;
9950 DWORD ret, tid;
9951 MSG msg;
9953 child_event.hwnd = CreateWindowExA(0, "TestWindowClass", "Test child",
9954 WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
9955 ok (child_event.hwnd != 0, "Failed to create child window\n");
9956 SetFocus( child_event.hwnd );
9957 flush_events();
9958 flush_sequence();
9959 child_event.start_event = wnd_event->start_event;
9960 wnd_event->grand_child = CreateThread(NULL, 0, create_grand_child_thread, &child_event, 0, &tid);
9961 for (;;)
9963 DWORD ret = MsgWaitForMultipleObjects(1, &child_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
9964 if (ret != 1) break;
9965 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
9967 ret = WaitForSingleObject( wnd_event->stop_event, 5000 );
9968 ok( !ret, "WaitForSingleObject failed %lx\n", ret );
9969 return 0;
9972 static const char manifest_dep[] =
9973 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
9974 "<assemblyIdentity version=\"1.2.3.4\" name=\"testdep1\" type=\"win32\" processorArchitecture=\"" ARCH "\"/>"
9975 " <file name=\"testdep.dll\" />"
9976 "</assembly>";
9978 static const char manifest_main[] =
9979 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
9980 "<assemblyIdentity version=\"1.2.3.4\" name=\"Wine.Test\" type=\"win32\" />"
9981 "<dependency>"
9982 " <dependentAssembly>"
9983 " <assemblyIdentity type=\"win32\" name=\"testdep1\" version=\"1.2.3.4\" processorArchitecture=\"" ARCH "\" />"
9984 " </dependentAssembly>"
9985 "</dependency>"
9986 "</assembly>";
9988 static void create_manifest_file(const char *filename, const char *manifest)
9990 WCHAR path[MAX_PATH];
9991 HANDLE file;
9992 DWORD size;
9994 MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH );
9995 file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
9996 ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %lu\n", GetLastError());
9997 WriteFile(file, manifest, strlen(manifest), &size, NULL);
9998 CloseHandle(file);
10001 static HANDLE test_create(const char *file)
10003 WCHAR path[MAX_PATH];
10004 ACTCTXW actctx;
10005 HANDLE handle;
10007 MultiByteToWideChar(CP_ACP, 0, file, -1, path, MAX_PATH);
10008 memset(&actctx, 0, sizeof(ACTCTXW));
10009 actctx.cbSize = sizeof(ACTCTXW);
10010 actctx.lpSource = path;
10012 handle = CreateActCtxW(&actctx);
10013 ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %lu\n", GetLastError());
10015 ok(actctx.cbSize == sizeof(actctx), "cbSize=%ld\n", actctx.cbSize);
10016 ok(actctx.dwFlags == 0, "dwFlags=%ld\n", actctx.dwFlags);
10017 ok(actctx.lpSource == path, "lpSource=%p\n", actctx.lpSource);
10018 ok(actctx.wProcessorArchitecture == 0, "wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture);
10019 ok(actctx.wLangId == 0, "wLangId=%d\n", actctx.wLangId);
10020 ok(actctx.lpAssemblyDirectory == NULL, "lpAssemblyDirectory=%p\n", actctx.lpAssemblyDirectory);
10021 ok(actctx.lpResourceName == NULL, "lpResourceName=%p\n", actctx.lpResourceName);
10022 ok(actctx.lpApplicationName == NULL, "lpApplicationName=%p\n", actctx.lpApplicationName);
10023 ok(actctx.hModule == NULL, "hModule=%p\n", actctx.hModule);
10025 return handle;
10028 static void test_interthread_messages(void)
10030 HANDLE hThread, context, handle, event;
10031 ULONG_PTR cookie;
10032 DWORD tid;
10033 WNDPROC proc;
10034 MSG msg;
10035 char buf[256];
10036 int len, expected_len;
10037 struct wnd_event wnd_event;
10038 BOOL ret;
10040 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
10041 if (!wnd_event.start_event)
10043 win_skip("skipping interthread message test under win9x\n");
10044 return;
10047 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
10048 ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError());
10050 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10052 CloseHandle(wnd_event.start_event);
10054 SetLastError(0xdeadbeef);
10055 ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeeded\n");
10056 ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
10057 "wrong error code %ld\n", GetLastError());
10059 proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
10060 ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %ld\n", GetLastError());
10062 expected_len = lstrlenA("window caption text");
10063 memset(buf, 0, sizeof(buf));
10064 SetLastError(0xdeadbeef);
10065 len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
10066 ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %ld, len %d, expected len %d\n", GetLastError(), len, expected_len);
10067 ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
10069 msg.hwnd = wnd_event.hwnd;
10070 msg.message = WM_GETTEXT;
10071 msg.wParam = sizeof(buf);
10072 msg.lParam = (LPARAM)buf;
10073 memset(buf, 0, sizeof(buf));
10074 SetLastError(0xdeadbeef);
10075 len = DispatchMessageA(&msg);
10076 ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */
10077 "DispatchMessageA(WM_GETTEXT) succeeded on another thread window: ret %d, error %ld\n", len, GetLastError());
10079 /* the following test causes an exception in user.exe under win9x */
10080 msg.hwnd = wnd_event.hwnd;
10081 msg.message = WM_TIMER;
10082 msg.wParam = 0;
10083 msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
10084 SetLastError(0xdeadbeef);
10085 len = DispatchMessageA(&msg);
10086 ok(!len && GetLastError() == 0xdeadbeef,
10087 "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %ld\n", len, GetLastError());
10089 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
10090 ok( ret, "PostMessageA(WM_QUIT) error %ld\n", GetLastError());
10092 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10093 CloseHandle(hThread);
10095 ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
10097 wnd_event.hwnd = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10098 100, 100, 200, 200, 0, 0, 0, NULL);
10099 ok (wnd_event.hwnd != 0, "Failed to create parent window\n");
10100 flush_events();
10101 flush_sequence();
10102 log_all_parent_messages++;
10103 wnd_event.start_event = CreateEventA( NULL, TRUE, FALSE, NULL );
10104 wnd_event.stop_event = CreateEventA( NULL, TRUE, FALSE, NULL );
10105 hThread = CreateThread( NULL, 0, create_child_thread, &wnd_event, 0, &tid );
10106 for (;;)
10108 ret = MsgWaitForMultipleObjects(1, &wnd_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
10109 if (ret != 1) break;
10110 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10112 ok( !ret, "MsgWaitForMultipleObjects failed %x\n", ret );
10113 /* now wait for the thread without processing messages; this shouldn't deadlock */
10114 SetEvent( wnd_event.stop_event );
10115 ret = WaitForSingleObject( hThread, 5000 );
10116 ok( !ret, "WaitForSingleObject failed %x\n", ret );
10117 CloseHandle( hThread );
10119 ret = WaitForSingleObject( wnd_event.grand_child, 5000 );
10120 ok( !ret, "WaitForSingleObject failed %x\n", ret );
10121 CloseHandle( wnd_event.grand_child );
10123 CloseHandle( wnd_event.start_event );
10124 CloseHandle( wnd_event.stop_event );
10125 flush_events();
10126 ok_sequence(WmExitThreadSeq, "destroy child on thread exit", FALSE);
10127 log_all_parent_messages--;
10128 DestroyWindow( wnd_event.hwnd );
10130 /* Activation context tests */
10131 create_manifest_file("testdep1.manifest", manifest_dep);
10132 create_manifest_file("main.manifest", manifest_main);
10134 context = test_create("main.manifest");
10135 DeleteFileA("testdep1.manifest");
10136 DeleteFileA("main.manifest");
10138 handle = (void*)0xdeadbeef;
10139 ret = GetCurrentActCtx(&handle);
10140 ok(ret, "GetCurrentActCtx failed: %lu\n", GetLastError());
10141 ok(handle == 0, "active context %p\n", handle);
10143 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
10144 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
10145 ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError());
10146 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10147 CloseHandle(wnd_event.start_event);
10149 /* context is activated after thread creation, so it doesn't inherit it by default */
10150 ret = ActivateActCtx(context, &cookie);
10151 ok(ret, "activation failed: %lu\n", GetLastError());
10153 handle = 0;
10154 ret = GetCurrentActCtx(&handle);
10155 ok(ret, "GetCurrentActCtx failed: %lu\n", GetLastError());
10156 ok(handle != 0, "active context %p\n", handle);
10157 ReleaseActCtx(handle);
10159 /* destination window will test for active context */
10160 ret = SendMessageA(wnd_event.hwnd, WM_USER+10, 0, 0);
10161 ok(ret, "thread window returned %d\n", ret);
10163 event = CreateEventW(NULL, 0, 0, NULL);
10164 ret = PostMessageA(wnd_event.hwnd, WM_USER+10, 0, (LPARAM)event);
10165 ok(ret, "thread window returned %d\n", ret);
10166 ok(WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10167 CloseHandle(event);
10169 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
10170 ok(ret, "PostMessageA(WM_QUIT) error %ld\n", GetLastError());
10172 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10173 CloseHandle(hThread);
10175 ret = DeactivateActCtx(0, cookie);
10176 ok(ret, "DeactivateActCtx failed: %lu\n", GetLastError());
10177 ReleaseActCtx(context);
10181 static const struct message WmVkN[] = {
10182 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
10183 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
10184 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
10185 { WM_CHAR, wparam|lparam, 'n', 1 },
10186 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
10187 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
10188 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
10189 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
10190 { 0 }
10192 static const struct message WmShiftVkN[] = {
10193 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
10194 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
10195 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
10196 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
10197 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
10198 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
10199 { WM_CHAR, wparam|lparam, 'N', 1 },
10200 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
10201 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
10202 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
10203 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
10204 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
10205 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
10206 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
10207 { 0 }
10209 static const struct message WmCtrlVkN[] = {
10210 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
10211 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
10212 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
10213 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
10214 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
10215 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
10216 { WM_CHAR, wparam|lparam, 0x000e, 1 },
10217 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
10218 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
10219 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
10220 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
10221 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
10222 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
10223 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
10224 { 0 }
10226 static const struct message WmCtrlVkN_2[] = {
10227 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
10228 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
10229 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
10230 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
10231 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
10232 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
10233 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
10234 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
10235 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
10236 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
10237 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
10238 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
10239 { 0 }
10241 static const struct message WmAltVkN[] = {
10242 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
10243 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
10244 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
10245 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
10246 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
10247 { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
10248 { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
10249 { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
10250 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
10251 { HCBT_SYSCOMMAND, hook },
10252 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
10253 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
10254 { 0x00AE, sent|defwinproc|optional }, /* XP */
10255 { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
10256 { WM_INITMENU, sent|defwinproc },
10257 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|msg_todo, OBJID_SYSMENU, 0 },
10258 { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
10259 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
10260 { WM_CAPTURECHANGED, sent|defwinproc },
10261 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
10262 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|msg_todo, OBJID_SYSMENU, 0 },
10263 { WM_EXITMENULOOP, sent|defwinproc },
10264 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
10265 { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
10266 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
10267 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
10268 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
10269 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
10270 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
10271 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
10272 { 0 }
10274 static const struct message WmAltVkN_2[] = {
10275 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
10276 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
10277 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
10278 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
10279 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
10280 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
10281 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
10282 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
10283 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
10284 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
10285 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
10286 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
10287 { 0 }
10289 static const struct message WmCtrlAltVkN[] = {
10290 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
10291 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
10292 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
10293 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
10294 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
10295 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
10296 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
10297 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
10298 { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
10299 { WM_CHAR, optional },
10300 { WM_CHAR, sent|optional },
10301 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
10302 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
10303 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
10304 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
10305 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
10306 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
10307 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
10308 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
10309 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
10310 { 0 }
10312 static const struct message WmCtrlShiftVkN[] = {
10313 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
10314 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
10315 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
10316 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
10317 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
10318 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
10319 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
10320 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
10321 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
10322 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
10323 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
10324 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
10325 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
10326 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
10327 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
10328 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
10329 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
10330 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
10331 { 0 }
10333 static const struct message WmCtrlAltShiftVkN[] = {
10334 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
10335 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
10336 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
10337 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
10338 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
10339 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
10340 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
10341 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
10342 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
10343 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
10344 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
10345 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
10346 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
10347 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
10348 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
10349 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
10350 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
10351 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
10352 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
10353 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
10354 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
10355 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
10356 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
10357 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
10358 { 0 }
10360 static const struct message WmAltPressRelease[] = {
10361 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
10362 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
10363 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
10364 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
10365 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
10366 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
10367 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
10368 { HCBT_SYSCOMMAND, hook },
10369 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
10370 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
10371 { WM_INITMENU, sent|defwinproc },
10372 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|msg_todo, OBJID_SYSMENU, 0 },
10373 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
10374 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_SYSMENU, 1 },
10376 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
10378 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_SYSMENU, 0 },
10379 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0, },
10380 { WM_CAPTURECHANGED, sent|defwinproc },
10381 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
10382 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|msg_todo, OBJID_SYSMENU, 0 },
10383 { WM_EXITMENULOOP, sent|defwinproc },
10384 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
10385 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
10386 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
10387 { 0 }
10389 static const struct message WmShiftMouseButton[] = {
10390 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
10391 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
10392 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
10393 { WM_MOUSEMOVE, wparam|optional, 0, 0 },
10394 { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
10395 { WM_LBUTTONDOWN, wparam, MK_LBUTTON|MK_SHIFT, 0 },
10396 { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON|MK_SHIFT, 0 },
10397 { WM_LBUTTONUP, wparam|optional, MK_SHIFT, 0 }, /* < w1064v1809 */
10398 { WM_LBUTTONUP, sent|wparam|optional, MK_SHIFT, 0 }, /* < w1064v1809 */
10399 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
10400 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
10401 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
10402 { WM_LBUTTONUP, optional, 0, 0 }, /* >= w1064v1809 */
10403 { WM_LBUTTONUP, sent|optional, 0, 0 }, /* >= w1064v1809 */
10404 { 0 }
10406 static const struct message WmF1Seq[] = {
10407 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
10408 { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
10409 { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
10410 { WM_KEYF1, wparam|lparam, 0, 0 },
10411 { WM_KEYF1, sent|wparam|lparam, 0, 0 },
10412 { WM_HELP, sent|defwinproc },
10413 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
10414 { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
10415 { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
10416 { 0 }
10418 static const struct message WmVkAppsSeq[] = {
10419 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
10420 { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
10421 { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
10422 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
10423 { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
10424 { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
10425 { WM_CONTEXTMENU, lparam, /*hwnd*/0, -1 },
10426 { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, -1 },
10427 { 0 }
10429 static const struct message WmVkF10Seq[] = {
10430 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
10431 { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
10432 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
10433 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
10434 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
10435 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
10436 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
10437 { HCBT_SYSCOMMAND, hook },
10438 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
10439 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
10440 { WM_INITMENU, sent|defwinproc },
10441 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|msg_todo, OBJID_SYSMENU, 0 },
10442 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
10443 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_SYSMENU, 1 },
10445 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0x10000001 }, /* XP */
10447 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
10448 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_SYSMENU, 0 },
10449 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0, },
10450 { WM_CAPTURECHANGED, sent|defwinproc },
10451 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
10452 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|msg_todo, OBJID_SYSMENU, 0 },
10453 { WM_EXITMENULOOP, sent|defwinproc },
10454 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
10455 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
10456 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
10457 { 0 }
10459 static const struct message WmShiftF10Seq[] = {
10460 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
10461 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
10462 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x00000001 },
10463 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
10464 { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
10465 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
10466 { WM_CONTEXTMENU, sent|defwinproc|lparam, /*hwnd*/0, -1 },
10467 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
10468 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
10469 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
10470 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
10471 { HCBT_SYSCOMMAND, hook },
10472 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
10473 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
10474 { WM_INITMENU, sent|defwinproc },
10475 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|msg_todo, OBJID_SYSMENU, 0 },
10476 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
10477 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_SYSMENU, 1 },
10478 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xd0000001 }, /* XP */
10479 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0x10000001 }, /* XP */
10480 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_SYSMENU, 0 },
10481 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
10482 { WM_CAPTURECHANGED, sent|defwinproc|wparam|lparam, 0, 0 },
10483 { WM_MENUSELECT, sent|defwinproc|wparam|lparam, 0xffff0000, 0 },
10484 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|msg_todo, OBJID_SYSMENU, 0 },
10485 { WM_EXITMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
10486 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 }, /* XP */
10487 { WM_KEYUP, wparam|lparam, VK_ESCAPE, 0xc0000001 },
10488 { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
10489 { 0 }
10492 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
10494 MSG msg;
10496 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
10498 struct recvd_message log_msg;
10500 /* ignore some unwanted messages */
10501 if (msg.message == WM_MOUSEMOVE ||
10502 msg.message == WM_TIMER ||
10503 ignore_message( msg.message ))
10504 continue;
10506 log_msg.hwnd = msg.hwnd;
10507 log_msg.message = msg.message;
10508 log_msg.flags = wparam|lparam;
10509 log_msg.wParam = msg.wParam;
10510 log_msg.lParam = msg.lParam;
10511 log_msg.descr = "accel";
10512 add_message(&log_msg);
10514 if (!hAccel || !TranslateAcceleratorA(hwnd, hAccel, &msg))
10516 TranslateMessage(&msg);
10517 DispatchMessageA(&msg);
10522 static void test_accelerators(void)
10524 RECT rc;
10525 POINT pt;
10526 SHORT state;
10527 HACCEL hAccel;
10528 HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10529 100, 100, 200, 200, 0, 0, 0, NULL);
10530 BOOL us_kbd = (GetKeyboardLayout(0) == (HKL)(ULONG_PTR)0x04090409);
10531 BOOL ret;
10533 ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError());
10534 UpdateWindow(hwnd);
10535 flush_events();
10536 flush_sequence();
10538 SetFocus(hwnd);
10539 ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
10541 state = GetKeyState(VK_SHIFT);
10542 ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
10543 state = GetKeyState(VK_CAPITAL);
10544 ok(state == 0, "wrong CapsLock state %04x\n", state);
10546 hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
10547 ok(!!hAccel, "Failed to load accelerators, error %lu.\n", GetLastError());
10549 flush_events();
10550 pump_msg_loop(hwnd, 0);
10551 flush_sequence();
10553 if (!us_kbd)
10555 skip("skipping ascii VK events on non-us keyboard\n");
10556 goto done;
10559 if (winetest_debug > 1) trace("testing VK_N press/release\n");
10560 flush_sequence();
10561 keybd_event('N', 0, 0, 0);
10562 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
10563 pump_msg_loop(hwnd, hAccel);
10564 if (!sequence_cnt) /* we didn't get any message */
10566 skip( "queuing key events not supported\n" );
10567 goto done;
10569 ok_sequence(WmVkN, "VK_N press/release", FALSE);
10571 if (winetest_debug > 1) trace("testing Shift+VK_N press/release\n");
10572 flush_sequence();
10573 keybd_event(VK_SHIFT, 0, 0, 0);
10574 keybd_event('N', 0, 0, 0);
10575 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
10576 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
10577 pump_msg_loop(hwnd, hAccel);
10578 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
10580 if (winetest_debug > 1) trace("testing Ctrl+VK_N press/release\n");
10581 flush_sequence();
10582 keybd_event(VK_CONTROL, 0, 0, 0);
10583 keybd_event('N', 0, 0, 0);
10584 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
10585 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
10586 pump_msg_loop(hwnd, hAccel);
10587 ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
10589 if (winetest_debug > 1) trace("testing Alt+VK_N press/release\n");
10590 flush_sequence();
10591 keybd_event(VK_MENU, 0, 0, 0);
10592 keybd_event('N', 0, 0, 0);
10593 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
10594 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
10595 pump_msg_loop(hwnd, hAccel);
10596 ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
10598 if (winetest_debug > 1) trace("testing Ctrl+Alt+VK_N press/release 1\n");
10599 flush_sequence();
10600 keybd_event(VK_CONTROL, 0, 0, 0);
10601 keybd_event(VK_MENU, 0, 0, 0);
10602 keybd_event('N', 0, 0, 0);
10603 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
10604 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
10605 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
10606 pump_msg_loop(hwnd, hAccel);
10607 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
10609 ret = DestroyAcceleratorTable(hAccel);
10610 ok( ret, "DestroyAcceleratorTable error %ld\n", GetLastError());
10612 hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(2));
10613 ok(!!hAccel, "Failed to load accelerators, error %lu.\n", GetLastError());
10615 if (winetest_debug > 1) trace("testing VK_N press/release\n");
10616 flush_sequence();
10617 keybd_event('N', 0, 0, 0);
10618 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
10619 pump_msg_loop(hwnd, hAccel);
10620 ok_sequence(WmVkN, "VK_N press/release", FALSE);
10622 if (winetest_debug > 1) trace("testing Shift+VK_N press/release\n");
10623 flush_sequence();
10624 keybd_event(VK_SHIFT, 0, 0, 0);
10625 keybd_event('N', 0, 0, 0);
10626 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
10627 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
10628 pump_msg_loop(hwnd, hAccel);
10629 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
10631 if (winetest_debug > 1) trace("testing Ctrl+VK_N press/release 2\n");
10632 flush_sequence();
10633 keybd_event(VK_CONTROL, 0, 0, 0);
10634 keybd_event('N', 0, 0, 0);
10635 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
10636 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
10637 pump_msg_loop(hwnd, hAccel);
10638 ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
10640 if (winetest_debug > 1) trace("testing Alt+VK_N press/release 2\n");
10641 flush_sequence();
10642 keybd_event(VK_MENU, 0, 0, 0);
10643 keybd_event('N', 0, 0, 0);
10644 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
10645 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
10646 pump_msg_loop(hwnd, hAccel);
10647 ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
10649 if (winetest_debug > 1) trace("testing Ctrl+Alt+VK_N press/release 2\n");
10650 flush_sequence();
10651 keybd_event(VK_CONTROL, 0, 0, 0);
10652 keybd_event(VK_MENU, 0, 0, 0);
10653 keybd_event('N', 0, 0, 0);
10654 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
10655 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
10656 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
10657 pump_msg_loop(hwnd, hAccel);
10658 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
10660 if (winetest_debug > 1) trace("testing Ctrl+Shift+VK_N press/release\n");
10661 flush_sequence();
10662 keybd_event(VK_CONTROL, 0, 0, 0);
10663 keybd_event(VK_SHIFT, 0, 0, 0);
10664 keybd_event('N', 0, 0, 0);
10665 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
10666 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
10667 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
10668 pump_msg_loop(hwnd, hAccel);
10669 ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
10671 if (winetest_debug > 1) trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
10672 flush_sequence();
10673 keybd_event(VK_CONTROL, 0, 0, 0);
10674 keybd_event(VK_MENU, 0, 0, 0);
10675 keybd_event(VK_SHIFT, 0, 0, 0);
10676 keybd_event('N', 0, 0, 0);
10677 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
10678 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
10679 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
10680 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
10681 pump_msg_loop(hwnd, hAccel);
10682 ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
10684 ret = DestroyAcceleratorTable(hAccel);
10685 ok( ret, "DestroyAcceleratorTable error %ld\n", GetLastError());
10686 hAccel = 0;
10688 if (winetest_debug > 1) trace("testing Alt press/release\n");
10689 flush_sequence();
10690 keybd_event(VK_MENU, 0, 0, 0);
10691 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
10692 keybd_event(VK_MENU, 0, 0, 0);
10693 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
10694 pump_msg_loop(hwnd, 0);
10695 /* this test doesn't pass in Wine for managed windows */
10696 ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
10698 if (winetest_debug > 1) trace("testing VK_F1 press/release\n");
10699 keybd_event(VK_F1, 0, 0, 0);
10700 keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
10701 pump_msg_loop(hwnd, 0);
10702 ok_sequence(WmF1Seq, "F1 press/release", FALSE);
10704 if (winetest_debug > 1) trace("testing VK_APPS press/release\n");
10705 keybd_event(VK_APPS, 0, 0, 0);
10706 keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
10707 pump_msg_loop(hwnd, 0);
10708 ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
10710 if (winetest_debug > 1) trace("testing VK_F10 press/release\n");
10711 keybd_event(VK_F10, 0, 0, 0);
10712 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
10713 keybd_event(VK_F10, 0, 0, 0);
10714 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
10715 pump_msg_loop(hwnd, 0);
10716 ok_sequence(WmVkF10Seq, "VK_F10 press/release", TRUE);
10718 if (winetest_debug > 1) trace("testing SHIFT+F10 press/release\n");
10719 keybd_event(VK_SHIFT, 0, 0, 0);
10720 keybd_event(VK_F10, 0, 0, 0);
10721 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
10722 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
10723 keybd_event(VK_ESCAPE, 0, 0, 0);
10724 keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
10725 pump_msg_loop(hwnd, 0);
10726 ok_sequence(WmShiftF10Seq, "SHIFT+F10 press/release", TRUE);
10728 if (winetest_debug > 1) trace("testing Shift+MouseButton press/release\n");
10729 /* first, move mouse pointer inside of the window client area */
10730 GetClientRect(hwnd, &rc);
10731 MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
10732 rc.left += (rc.right - rc.left)/2;
10733 rc.top += (rc.bottom - rc.top)/2;
10734 SetCursorPos(rc.left, rc.top);
10735 SetActiveWindow(hwnd);
10737 flush_events();
10738 flush_sequence();
10739 GetCursorPos(&pt);
10740 if (pt.x == rc.left && pt.y == rc.top)
10742 int i;
10743 keybd_event(VK_SHIFT, 0, 0, 0);
10744 mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
10745 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
10746 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
10747 pump_msg_loop(hwnd, 0);
10748 for (i = 0; i < sequence_cnt; i++) if (sequence[i].message == WM_LBUTTONDOWN) break;
10749 if (i < sequence_cnt)
10750 ok_sequence(WmShiftMouseButton, "Shift+MouseButton press/release", FALSE);
10751 else
10752 skip( "Shift+MouseButton event didn't get to the window\n" );
10755 done:
10756 if (hAccel) DestroyAcceleratorTable(hAccel);
10757 DestroyWindow(hwnd);
10760 /************* window procedures ********************/
10762 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message,
10763 WPARAM wParam, LPARAM lParam)
10765 static LONG defwndproc_counter = 0;
10766 static LONG beginpaint_counter = 0;
10767 LRESULT ret;
10768 struct recvd_message msg;
10770 if (ignore_message( message )) return 0;
10772 switch (message)
10774 case WM_ENABLE:
10776 LONG style = GetWindowLongA(hwnd, GWL_STYLE);
10777 ok((BOOL)wParam == !(style & WS_DISABLED),
10778 "wrong WS_DISABLED state: %Id != %d\n", wParam, !(style & WS_DISABLED));
10779 break;
10782 case WM_CAPTURECHANGED:
10783 if (test_DestroyWindow_flag)
10785 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
10786 if (style & WS_CHILD)
10787 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
10788 else if (style & WS_POPUP)
10789 lParam = WND_POPUP_ID;
10790 else
10791 lParam = WND_PARENT_ID;
10793 break;
10795 case WM_NCDESTROY:
10797 HWND capture;
10799 ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
10800 capture = GetCapture();
10801 if (capture)
10803 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
10804 if (winetest_debug > 1) trace("current capture %p, releasing...\n", capture);
10805 ReleaseCapture();
10808 /* fall through */
10809 case WM_DESTROY:
10810 ok(GetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
10811 if (test_DestroyWindow_flag)
10813 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
10814 if (style & WS_CHILD)
10815 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
10816 else if (style & WS_POPUP)
10817 lParam = WND_POPUP_ID;
10818 else
10819 lParam = WND_PARENT_ID;
10821 break;
10823 /* test_accelerators() depends on this */
10824 case WM_NCHITTEST:
10825 return HTCLIENT;
10827 case WM_USER+10:
10829 ACTIVATION_CONTEXT_BASIC_INFORMATION basicinfo;
10830 HANDLE handle, event = (HANDLE)lParam;
10831 BOOL ret;
10833 handle = (void*)0xdeadbeef;
10834 ret = GetCurrentActCtx(&handle);
10835 ok(ret, "failed to get current context, %lu\n", GetLastError());
10836 ok(handle == 0, "got active context %p\n", handle);
10838 memset(&basicinfo, 0xff, sizeof(basicinfo));
10839 ret = QueryActCtxW(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX, handle, 0, ActivationContextBasicInformation,
10840 &basicinfo, sizeof(basicinfo), NULL);
10841 ok(ret, "got %d, error %ld\n", ret, GetLastError());
10842 ok(basicinfo.hActCtx == NULL, "got %p\n", basicinfo.hActCtx);
10843 ok(basicinfo.dwFlags == 0, "got %lx\n", basicinfo.dwFlags);
10845 if (event) SetEvent(event);
10846 return 1;
10849 /* ignore */
10850 case WM_MOUSEMOVE:
10851 case WM_MOUSEACTIVATE:
10852 case WM_NCMOUSEMOVE:
10853 case WM_SETCURSOR:
10854 case WM_IME_SELECT:
10855 return 0;
10858 msg.hwnd = hwnd;
10859 msg.message = message;
10860 msg.flags = sent|wparam|lparam;
10861 if (defwndproc_counter) msg.flags |= defwinproc;
10862 if (beginpaint_counter) msg.flags |= beginpaint;
10863 msg.wParam = wParam;
10864 msg.lParam = lParam;
10865 msg.descr = "MsgCheckProc";
10866 add_message(&msg);
10868 if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
10870 HWND parent = GetParent(hwnd);
10871 RECT rc;
10872 MINMAXINFO *minmax = (MINMAXINFO *)lParam;
10874 GetClientRect(parent, &rc);
10875 if (winetest_debug > 1)
10877 trace("parent %p client size = (%ld x %ld)\n", parent, rc.right, rc.bottom);
10878 trace("Reserved=%ld,%ld MaxSize=%ld,%ld MaxPos=%ld,%ld MinTrack=%ld,%ld MaxTrack=%ld,%ld\n",
10879 minmax->ptReserved.x, minmax->ptReserved.y,
10880 minmax->ptMaxSize.x, minmax->ptMaxSize.y,
10881 minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
10882 minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
10883 minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
10885 ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %ld != %ld\n",
10886 minmax->ptMaxSize.x, rc.right);
10887 ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %ld != %ld\n",
10888 minmax->ptMaxSize.y, rc.bottom);
10891 if (message == WM_PAINT)
10893 PAINTSTRUCT ps;
10894 beginpaint_counter++;
10895 BeginPaint( hwnd, &ps );
10896 beginpaint_counter--;
10897 EndPaint( hwnd, &ps );
10898 return 0;
10901 if (!test_context_menu && message == WM_CONTEXTMENU)
10903 /* don't create context menu */
10904 return 0;
10907 defwndproc_counter++;
10908 ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam)
10909 : DefWindowProcA(hwnd, message, wParam, lParam);
10910 defwndproc_counter--;
10912 return ret;
10915 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10917 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
10920 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10922 return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
10925 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10927 static LONG defwndproc_counter = 0;
10928 LRESULT ret;
10929 struct recvd_message msg;
10931 if (ignore_message( message )) return 0;
10933 switch (message)
10935 case WM_QUERYENDSESSION:
10936 case WM_ENDSESSION:
10937 lParam &= ~0x01; /* Vista adds a 0x01 flag */
10938 break;
10941 msg.hwnd = hwnd;
10942 msg.message = message;
10943 msg.flags = sent|wparam|lparam;
10944 if (defwndproc_counter) msg.flags |= defwinproc;
10945 msg.wParam = wParam;
10946 msg.lParam = lParam;
10947 msg.descr = "popup";
10948 add_message(&msg);
10950 if (message == WM_CREATE)
10952 DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
10953 SetWindowLongA(hwnd, GWL_STYLE, style);
10956 defwndproc_counter++;
10957 ret = DefWindowProcA(hwnd, message, wParam, lParam);
10958 defwndproc_counter--;
10960 return ret;
10963 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10965 static LONG defwndproc_counter = 0;
10966 static LONG beginpaint_counter = 0;
10967 LRESULT ret;
10968 struct recvd_message msg;
10970 if (ignore_message( message )) return 0;
10972 if (log_all_parent_messages ||
10973 message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
10974 message == WM_SETFOCUS || message == WM_KILLFOCUS ||
10975 message == WM_ENABLE || message == WM_ENTERIDLE ||
10976 message == WM_DRAWITEM || message == WM_MEASUREITEM || message == WM_COMPAREITEM ||
10977 message == WM_COMMAND || message == WM_IME_SETCONTEXT)
10979 switch (message)
10981 /* ignore */
10982 case WM_NCHITTEST:
10983 return HTCLIENT;
10984 case WM_SETCURSOR:
10985 case WM_MOUSEMOVE:
10986 case WM_NCMOUSEMOVE:
10987 return 0;
10990 msg.hwnd = hwnd;
10991 msg.message = message;
10992 msg.flags = sent|parent|wparam|lparam;
10993 if (defwndproc_counter) msg.flags |= defwinproc;
10994 if (beginpaint_counter) msg.flags |= beginpaint;
10995 msg.wParam = wParam;
10996 msg.lParam = lParam;
10997 msg.descr = "parent";
10998 add_message(&msg);
11001 if (message == WM_PAINT)
11003 PAINTSTRUCT ps;
11004 beginpaint_counter++;
11005 BeginPaint( hwnd, &ps );
11006 beginpaint_counter--;
11007 EndPaint( hwnd, &ps );
11008 return 0;
11011 defwndproc_counter++;
11012 ret = DefWindowProcA(hwnd, message, wParam, lParam);
11013 defwndproc_counter--;
11015 return message == WM_COMPAREITEM ? -1 : ret;
11018 static LRESULT CALLBACK StopQuitMsgCheckProcA(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
11020 if (message == WM_CREATE)
11021 PostMessageA(hwnd, WM_CLOSE, 0, 0);
11022 else if (message == WM_CLOSE)
11024 /* Only the first WM_QUIT will survive the window destruction */
11025 PostMessageA(hwnd, WM_USER, 0x1234, 0x5678);
11026 PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
11027 PostMessageA(hwnd, WM_QUIT, 0x4321, 0x8765);
11030 return DefWindowProcA(hwnd, message, wp, lp);
11033 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11035 static LONG defwndproc_counter = 0;
11036 LRESULT ret;
11037 struct recvd_message msg;
11039 if (ignore_message( message )) return 0;
11041 if (test_def_id)
11043 DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
11044 ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
11045 if (after_end_dialog)
11046 ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %Ix\n", ret );
11047 else
11048 ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %Ix\n", ret);
11051 msg.hwnd = hwnd;
11052 msg.message = message;
11053 msg.flags = sent|wparam|lparam;
11054 if (defwndproc_counter) msg.flags |= defwinproc;
11055 msg.wParam = wParam;
11056 msg.lParam = lParam;
11057 msg.descr = "dialog";
11058 add_message(&msg);
11060 defwndproc_counter++;
11061 ret = DefDlgProcA(hwnd, message, wParam, lParam);
11062 defwndproc_counter--;
11064 return ret;
11067 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11069 static LONG defwndproc_counter = 0;
11070 LRESULT ret;
11071 struct recvd_message msg;
11073 /* log only specific messages we are interested in */
11074 switch (message)
11076 #if 0 /* probably log these as well */
11077 case WM_ACTIVATE:
11078 case WM_SETFOCUS:
11079 case WM_KILLFOCUS:
11080 #endif
11081 case WM_SHOWWINDOW:
11082 case WM_SIZE:
11083 case WM_MOVE:
11084 case WM_GETMINMAXINFO:
11085 case WM_WINDOWPOSCHANGING:
11086 case WM_WINDOWPOSCHANGED:
11087 break;
11089 default: /* ignore */
11090 /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
11091 return DefWindowProcA(hwnd, message, wParam, lParam);
11094 msg.hwnd = hwnd;
11095 msg.message = message;
11096 msg.flags = sent|wparam|lparam;
11097 if (defwndproc_counter) msg.flags |= defwinproc;
11098 msg.wParam = wParam;
11099 msg.lParam = lParam;
11100 msg.descr = "show";
11101 add_message(&msg);
11103 defwndproc_counter++;
11104 ret = DefWindowProcA(hwnd, message, wParam, lParam);
11105 defwndproc_counter--;
11107 return ret;
11110 static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
11112 switch (msg)
11114 case WM_CREATE: return 0;
11115 case WM_PAINT:
11117 MSG msg2;
11118 static int i = 0;
11120 if (i < 256)
11122 i++;
11123 if (PeekMessageA(&msg2, 0, 0, 0, 1))
11125 TranslateMessage(&msg2);
11126 DispatchMessageA(&msg2);
11128 i--;
11130 else ok(broken(1), "infinite loop\n");
11131 if ( i == 0)
11132 paint_loop_done = TRUE;
11133 return DefWindowProcA(hWnd,msg,wParam,lParam);
11136 return DefWindowProcA(hWnd,msg,wParam,lParam);
11139 static LRESULT WINAPI HotkeyMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11141 static LONG defwndproc_counter = 0;
11142 LRESULT ret;
11143 struct recvd_message msg;
11144 DWORD queue_status;
11146 if (ignore_message( message )) return 0;
11148 if ((message >= WM_KEYFIRST && message <= WM_KEYLAST) ||
11149 message == WM_HOTKEY || message >= WM_APP)
11151 msg.hwnd = hwnd;
11152 msg.message = message;
11153 msg.flags = sent|wparam|lparam;
11154 if (defwndproc_counter) msg.flags |= defwinproc;
11155 msg.wParam = wParam;
11156 msg.lParam = lParam;
11157 msg.descr = "HotkeyMsgCheckProcA";
11158 add_message(&msg);
11161 defwndproc_counter++;
11162 ret = DefWindowProcA(hwnd, message, wParam, lParam);
11163 defwndproc_counter--;
11165 if (message == WM_APP)
11167 queue_status = GetQueueStatus(QS_HOTKEY);
11168 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %lx\n", queue_status);
11169 queue_status = GetQueueStatus(QS_POSTMESSAGE);
11170 ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %lx\n", queue_status);
11171 PostMessageA(hwnd, WM_APP+1, 0, 0);
11173 else if (message == WM_APP+1)
11175 queue_status = GetQueueStatus(QS_HOTKEY);
11176 ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %lx\n", queue_status);
11179 return ret;
11182 static void register_classes(void)
11184 WNDCLASSA cls;
11185 WNDCLASSW clsW;
11187 cls.style = 0;
11188 cls.lpfnWndProc = MsgCheckProcA;
11189 cls.cbClsExtra = 0;
11190 cls.cbWndExtra = 0;
11191 cls.hInstance = GetModuleHandleA(0);
11192 cls.hIcon = 0;
11193 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
11194 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
11195 cls.lpszMenuName = NULL;
11196 cls.lpszClassName = "TestWindowClass";
11197 register_class(&cls);
11199 cls.lpfnWndProc = HotkeyMsgCheckProcA;
11200 cls.lpszClassName = "HotkeyWindowClass";
11201 register_class(&cls);
11203 cls.lpfnWndProc = ShowWindowProcA;
11204 cls.lpszClassName = "ShowWindowClass";
11205 register_class(&cls);
11207 cls.lpfnWndProc = PopupMsgCheckProcA;
11208 cls.lpszClassName = "TestPopupClass";
11209 register_class(&cls);
11211 cls.lpfnWndProc = ParentMsgCheckProcA;
11212 cls.lpszClassName = "TestParentClass";
11213 register_class(&cls);
11215 cls.lpfnWndProc = StopQuitMsgCheckProcA;
11216 cls.lpszClassName = "StopQuitClass";
11217 register_class(&cls);
11219 cls.lpfnWndProc = DefWindowProcA;
11220 cls.lpszClassName = "SimpleWindowClass";
11221 register_class(&cls);
11223 cls.lpfnWndProc = PaintLoopProcA;
11224 cls.lpszClassName = "PaintLoopWindowClass";
11225 register_class(&cls);
11227 cls.style = CS_NOCLOSE;
11228 cls.lpszClassName = "NoCloseWindowClass";
11229 register_class(&cls);
11231 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
11232 cls.style = 0;
11233 cls.hInstance = GetModuleHandleA(0);
11234 cls.hbrBackground = 0;
11235 cls.lpfnWndProc = TestDlgProcA;
11236 cls.lpszClassName = "TestDialogClass";
11237 register_class(&cls);
11239 cls.lpfnWndProc = DefWindowProcA;
11240 cls.style = CS_PARENTDC;
11241 cls.lpszClassName = "SimpleWindowClassWithParentDC";
11242 register_class(&cls);
11244 clsW.style = 0;
11245 clsW.lpfnWndProc = MsgCheckProcW;
11246 clsW.cbClsExtra = 0;
11247 clsW.cbWndExtra = 0;
11248 clsW.hInstance = GetModuleHandleW(0);
11249 clsW.hIcon = 0;
11250 clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
11251 clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
11252 clsW.lpszMenuName = NULL;
11253 clsW.lpszClassName = testWindowClassW;
11254 RegisterClassW(&clsW); /* ignore error, this fails on Win9x */
11257 static BOOL is_our_logged_class(HWND hwnd)
11259 char buf[256];
11261 if (GetClassNameA(hwnd, buf, sizeof(buf)))
11263 if (!lstrcmpiA(buf, "TestWindowClass") ||
11264 !lstrcmpiA(buf, "ShowWindowClass") ||
11265 !lstrcmpiA(buf, "TestParentClass") ||
11266 !lstrcmpiA(buf, "TestPopupClass") ||
11267 !lstrcmpiA(buf, "SimpleWindowClass") ||
11268 !lstrcmpiA(buf, "TestDialogClass") ||
11269 !lstrcmpiA(buf, "MDI_frame_class") ||
11270 !lstrcmpiA(buf, "MDI_client_class") ||
11271 !lstrcmpiA(buf, "MDI_child_class") ||
11272 !lstrcmpiA(buf, "my_button_class") ||
11273 !lstrcmpiA(buf, "my_edit_class") ||
11274 !lstrcmpiA(buf, "static") ||
11275 !lstrcmpiA(buf, "ListBox") ||
11276 !lstrcmpiA(buf, "ComboBox") ||
11277 !lstrcmpiA(buf, "MyDialogClass") ||
11278 !lstrcmpiA(buf, "#32770") ||
11279 !lstrcmpiA(buf, "#32768"))
11280 return TRUE;
11282 return FALSE;
11285 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
11287 HWND hwnd;
11289 ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
11291 if (nCode == HCBT_CLICKSKIPPED)
11293 /* ignore this event, XP sends it a lot when switching focus between windows */
11294 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
11297 if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
11299 struct recvd_message msg;
11301 msg.hwnd = 0;
11302 msg.message = nCode;
11303 msg.flags = hook|wparam|lparam;
11304 msg.wParam = wParam;
11305 msg.lParam = lParam;
11306 msg.descr = "CBT";
11307 add_message(&msg);
11309 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
11312 if (nCode == HCBT_DESTROYWND)
11314 if (test_DestroyWindow_flag)
11316 DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
11317 if (style & WS_CHILD)
11318 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
11319 else if (style & WS_POPUP)
11320 lParam = WND_POPUP_ID;
11321 else
11322 lParam = WND_PARENT_ID;
11326 /* Log also SetFocus(0) calls */
11327 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
11329 if (is_our_logged_class(hwnd))
11331 struct recvd_message msg;
11333 msg.hwnd = hwnd;
11334 msg.message = nCode;
11335 msg.flags = hook|wparam|lparam;
11336 msg.wParam = wParam;
11337 msg.lParam = lParam;
11338 msg.descr = "CBT";
11339 add_message(&msg);
11341 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
11344 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
11345 DWORD event,
11346 HWND hwnd,
11347 LONG object_id,
11348 LONG child_id,
11349 DWORD thread_id,
11350 DWORD event_time)
11352 ok(thread_id == winevent_hook_thread_id, "we didn't ask for events from other threads\n");
11354 /* ignore mouse cursor events */
11355 if (object_id == OBJID_CURSOR) return;
11357 if (!hwnd || is_our_logged_class(hwnd))
11359 struct recvd_message msg;
11361 msg.hwnd = hwnd;
11362 msg.message = event;
11363 msg.flags = winevent_hook|wparam|lparam;
11364 msg.wParam = object_id;
11365 msg.lParam = child_id;
11366 msg.descr = "WEH";
11367 add_message(&msg);
11371 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
11372 static const WCHAR wszAnsi[] = {'U',0};
11374 static const GUID iface_guid = {0x66666666};
11376 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
11378 const DEV_BROADCAST_DEVICEINTERFACE_A *ifaceA = (const void *)lParam;
11380 switch (uMsg)
11382 case CB_FINDSTRINGEXACT:
11383 if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
11384 return 1;
11385 if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
11386 return 0;
11387 return -1;
11389 case WM_DEVICECHANGE:
11390 if (wParam == DBT_DEVICEARRIVAL && IsEqualGUID(&ifaceA->dbcc_classguid, &iface_guid))
11392 DWORD expect_size = offsetof(DEV_BROADCAST_DEVICEINTERFACE_A, dbcc_name[strlen(ifaceA->dbcc_name)]);
11394 ok(ifaceA->dbcc_size == expect_size, "Expected %lu, got %lu.\n", expect_size, ifaceA->dbcc_size);
11395 ok(ifaceA->dbcc_devicetype == DBT_DEVTYP_DEVICEINTERFACE,
11396 "Got notification type %#lx.\n", ifaceA->dbcc_devicetype);
11397 ok(!ifaceA->dbcc_reserved, "Got reserved %#lx.\n", ifaceA->dbcc_reserved);
11398 ok(!strcmp(ifaceA->dbcc_name, "test name"), "Got name %s.\n", debugstr_a(ifaceA->dbcc_name));
11399 return 2;
11402 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
11405 static const struct message WmGetTextLengthAfromW[] = {
11406 { WM_GETTEXTLENGTH, sent },
11407 { WM_GETTEXT, sent|optional },
11408 { 0 }
11411 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
11413 /* dummy window proc for WM_GETTEXTLENGTH test */
11414 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
11416 switch(msg)
11418 case WM_GETTEXTLENGTH:
11419 return lstrlenW(dummy_window_text) + 37; /* some random length */
11420 case WM_GETTEXT:
11421 lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
11422 return lstrlenW( (LPWSTR)lp );
11423 default:
11424 return DefWindowProcW( hwnd, msg, wp, lp );
11428 static void test_message_conversion(void)
11430 static const WCHAR wszMsgConversionClass[] =
11431 {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
11432 char buffer[200];
11433 DEV_BROADCAST_DEVICEINTERFACE_A *dev_interface = (void *)buffer;
11434 WNDCLASSW cls;
11435 LRESULT lRes;
11436 HWND hwnd;
11437 WNDPROC wndproc, newproc;
11438 BOOL ret;
11440 cls.style = 0;
11441 cls.lpfnWndProc = MsgConversionProcW;
11442 cls.cbClsExtra = 0;
11443 cls.cbWndExtra = 0;
11444 cls.hInstance = GetModuleHandleW(NULL);
11445 cls.hIcon = NULL;
11446 cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
11447 cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
11448 cls.lpszMenuName = NULL;
11449 cls.lpszClassName = wszMsgConversionClass;
11450 /* this call will fail on Win9x, but that doesn't matter as this test is
11451 * meaningless on those platforms */
11452 if(!RegisterClassW(&cls)) return;
11454 hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
11455 100, 100, 200, 200, 0, 0, 0, NULL);
11456 ok(hwnd != NULL, "Window creation failed\n");
11458 /* {W, A} -> A */
11460 wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
11461 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
11462 ok(lRes == 0, "String should have been converted\n");
11463 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
11464 ok(lRes == 1, "String shouldn't have been converted\n");
11466 /* {W, A} -> W */
11468 wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
11469 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
11470 ok(lRes == 1, "String shouldn't have been converted\n");
11471 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
11472 ok(lRes == 1, "String shouldn't have been converted\n");
11474 /* Synchronous messages */
11476 lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
11477 ok(lRes == 0, "String should have been converted\n");
11478 lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
11479 ok(lRes == 1, "String shouldn't have been converted\n");
11481 /* Asynchronous messages */
11483 SetLastError(0);
11484 lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
11485 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
11486 "PostMessage on sync only message returned %Id, last error %ld\n", lRes, GetLastError());
11487 SetLastError(0);
11488 lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
11489 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
11490 "PostMessage on sync only message returned %Id, last error %ld\n", lRes, GetLastError());
11491 SetLastError(0);
11492 lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
11493 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
11494 "PosThreadtMessage on sync only message returned %Id, last error %ld\n", lRes, GetLastError());
11495 SetLastError(0);
11496 lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
11497 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
11498 "PosThreadtMessage on sync only message returned %Id, last error %ld\n", lRes, GetLastError());
11499 SetLastError(0);
11500 lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
11501 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
11502 "SendNotifyMessage on sync only message returned %Id, last error %ld\n", lRes, GetLastError());
11503 SetLastError(0);
11504 lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
11505 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
11506 "SendNotifyMessage on sync only message returned %Id, last error %ld\n", lRes, GetLastError());
11507 SetLastError(0);
11508 lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
11509 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
11510 "SendMessageCallback on sync only message returned %Id, last error %ld\n", lRes, GetLastError());
11511 SetLastError(0);
11512 lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
11513 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
11514 "SendMessageCallback on sync only message returned %Id, last error %ld\n", lRes, GetLastError());
11516 /* Test WM_DEVICECHANGE. */
11518 dev_interface->dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
11519 dev_interface->dbcc_reserved = 0;
11520 dev_interface->dbcc_classguid = iface_guid;
11521 strcpy(dev_interface->dbcc_name, "test name");
11522 dev_interface->dbcc_size = offsetof(DEV_BROADCAST_DEVICEINTERFACE_A,
11523 dbcc_name[strlen(dev_interface->dbcc_name)]);
11524 lRes = SendMessageA(hwnd, WM_DEVICECHANGE, DBT_DEVICEARRIVAL, (LPARAM)dev_interface);
11525 ok(lRes == 2, "Got %Id, error %lu.\n", lRes, GetLastError());
11527 DestroyWindow(hwnd);
11529 /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
11531 hwnd = CreateWindowW (testWindowClassW, wszUnicode,
11532 WS_OVERLAPPEDWINDOW,
11533 100, 100, 200, 200, 0, 0, 0, NULL);
11534 ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError());
11535 flush_sequence();
11536 lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
11537 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
11538 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
11539 "got bad length %Id\n", lRes );
11541 flush_sequence();
11542 lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
11543 hwnd, WM_GETTEXTLENGTH, 0, 0);
11544 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
11545 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
11546 "got bad length %Id\n", lRes );
11548 wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
11549 newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
11550 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
11551 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
11552 NULL, 0, NULL, NULL ) ||
11553 broken(lRes == lstrlenW(dummy_window_text) + 37),
11554 "got bad length %Id\n", lRes );
11556 SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc ); /* restore old wnd proc */
11557 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
11558 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
11559 NULL, 0, NULL, NULL ) ||
11560 broken(lRes == lstrlenW(dummy_window_text) + 37),
11561 "got bad length %Id\n", lRes );
11563 ret = DestroyWindow(hwnd);
11564 ok( ret, "DestroyWindow() error %ld\n", GetLastError());
11567 struct timer_info
11569 HWND hWnd;
11570 HANDLE handles[2];
11571 DWORD id;
11574 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
11578 #define TIMER_ID 0x19
11579 #define TIMER_COUNT 500 /* 499 samples */
11580 #define TIMER_DURATION_EXPECTED 10000 /* 10 ms */
11581 #define TIMER_DURATION_ALT 15600 /* 15.6 ms */
11582 #define TIMER_DURATION_TOLERANCE 1000 /* 1 ms */
11584 static int count = 0;
11585 static ULONGLONG timer_ticks[TIMER_COUNT];
11586 static int timer_duration = 0;
11588 static int compare_ulonglong(const void *a, const void *b)
11590 ULONGLONG la, lb;
11591 la = *(ULONGLONG*)a;
11592 lb = *(ULONGLONG*)b;
11593 return (la > lb) - (la < lb);
11596 static void timer_fired(void)
11598 if (count < TIMER_COUNT)
11600 LARGE_INTEGER performance_counter;
11601 BOOL ret;
11603 ret = QueryPerformanceCounter(&performance_counter);
11604 ok(ret, "QueryPerformanceCounter failed\n");
11606 timer_ticks[count] = performance_counter.QuadPart;
11609 count++;
11611 if (count == TIMER_COUNT)
11613 LARGE_INTEGER performance_frequency;
11614 BOOL ret;
11616 /* calculate durations */
11617 for (int i=0; i < TIMER_COUNT-1; i++)
11618 timer_ticks[i] = timer_ticks[i+1] - timer_ticks[i];
11620 qsort(timer_ticks, TIMER_COUNT - 1, sizeof(timer_ticks[0]), compare_ulonglong);
11622 ret = QueryPerformanceFrequency(&performance_frequency);
11623 ok(ret, "QueryPerformanceFrequency failed\n");
11625 /* median duration, converted to microseconds */
11626 timer_duration = (int)(timer_ticks[(TIMER_COUNT - 1) / 2] * 1000000 / performance_frequency.QuadPart);
11630 static void CALLBACK callback_count(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
11632 timer_fired();
11635 static DWORD exception;
11636 static void CALLBACK callback_exception(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
11638 timer_fired();
11639 RaiseException(exception, 0, 0, NULL);
11642 static DWORD WINAPI timer_thread_proc(LPVOID x)
11644 struct timer_info *info = x;
11645 DWORD r;
11647 r = KillTimer(info->hWnd, 0x19);
11648 ok(r,"KillTimer failed in thread\n");
11649 r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
11650 ok(r,"SetTimer failed in thread\n");
11651 ok(r==TIMER_ID,"SetTimer id different\n");
11652 r = SetEvent(info->handles[0]);
11653 ok(r,"SetEvent failed in thread\n");
11654 return 0;
11657 static void test_timers(void)
11659 struct timer_info info;
11660 DWORD id;
11661 MSG msg;
11663 info.hWnd = CreateWindowA("TestWindowClass", NULL,
11664 WS_OVERLAPPEDWINDOW ,
11665 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
11666 NULL, NULL, 0);
11668 info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
11669 ok(info.id, "SetTimer failed\n");
11670 ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
11671 info.handles[0] = CreateEventW(NULL,0,0,NULL);
11672 info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
11674 WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
11676 WaitForSingleObject(info.handles[1], INFINITE);
11678 CloseHandle(info.handles[0]);
11679 CloseHandle(info.handles[1]);
11681 ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
11683 /* Check the minimum allowed timeout for a timer. MSDN indicates that it should be 10.0 ms,
11684 * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to
11685 * 15.6 ms.
11687 count = 0;
11688 id = SetTimer(info.hWnd, TIMER_ID, 0, callback_count);
11689 ok(id != 0, "did not get id from SetTimer.\n");
11690 ok(id==TIMER_ID, "SetTimer timer ID different\n");
11691 while (count < TIMER_COUNT && GetMessageA(&msg, info.hWnd, 0, 0))
11692 DispatchMessageA(&msg);
11693 ok(abs(timer_duration-TIMER_DURATION_EXPECTED) < TIMER_DURATION_TOLERANCE /* xp, win7 */
11694 || broken(abs(timer_duration - TIMER_DURATION_ALT) < TIMER_DURATION_TOLERANCE) /* most common */,
11695 "did not get expected median timeout (%d != ~%d).\n",
11696 timer_duration, TIMER_DURATION_EXPECTED);
11697 ok(KillTimer(info.hWnd, id), "KillTimer failed\n");
11698 /* Perform the same check on SetSystemTimer (only available on w2k3 and older) */
11699 if (pSetSystemTimer)
11701 count = 0;
11702 id = pSetSystemTimer(info.hWnd, TIMER_ID, 0, callback_count);
11703 ok(id != 0, "did not get id from SetSystemTimer.\n");
11704 ok(id==TIMER_ID, "SetTimer timer ID different\n");
11705 while (count < TIMER_COUNT && GetMessageA(&msg, info.hWnd, 0, 0))
11707 if (msg.message == WM_SYSTIMER)
11708 timer_fired();
11709 ok(msg.message != WM_TIMER, "unexpected WM_TIMER\n");
11710 DispatchMessageA(&msg);
11712 ok(abs(timer_duration-TIMER_DURATION_EXPECTED) < TIMER_DURATION_TOLERANCE
11713 || broken(abs(timer_duration - TIMER_DURATION_ALT) < TIMER_DURATION_TOLERANCE) /* most common */,
11714 "did not get expected median timeout (%d != ~%d).\n",
11715 timer_duration, TIMER_DURATION_EXPECTED);
11716 ok(pKillSystemTimer(info.hWnd, id), "KillSystemTimer failed\n");
11719 ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
11722 static void test_timers_no_wnd(void)
11724 static UINT_PTR ids[0xffff];
11725 UINT_PTR id, id2;
11726 DWORD start;
11727 MSG msg;
11728 int i;
11730 count = 0;
11731 id = SetTimer(NULL, 0, 100, callback_count);
11732 ok(id != 0, "did not get id from SetTimer.\n");
11733 id2 = SetTimer(NULL, id, 200, callback_count);
11734 ok(id2 == id, "did not get same id from SetTimer when replacing (%Ii expected %Ii).\n", id2, id);
11735 Sleep(150);
11736 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
11737 ok(count == 0, "did not get zero count as expected (%i).\n", count);
11738 Sleep(150);
11739 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
11740 ok(count == 1, "did not get one count as expected (%i).\n", count);
11741 KillTimer(NULL, id);
11742 Sleep(250);
11743 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
11744 ok(count == 1, "killing replaced timer did not work (%i).\n", count);
11746 /* Check the minimum allowed timeout for a timer. MSDN indicates that it should be 10.0 ms,
11747 * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to
11748 * 15.6 ms.
11750 count = 0;
11751 id = SetTimer(NULL, 0, 0, callback_count);
11752 ok(id != 0, "did not get id from SetTimer.\n");
11753 while (count < TIMER_COUNT && GetMessageA(&msg, NULL, 0, 0))
11754 DispatchMessageA(&msg);
11755 ok(abs(timer_duration-TIMER_DURATION_EXPECTED) < TIMER_DURATION_TOLERANCE /* xp */
11756 || broken(abs(timer_duration - TIMER_DURATION_ALT) < TIMER_DURATION_TOLERANCE) /* most common */,
11757 "did not get expected median timeout (%d != ~%d).\n",
11758 timer_duration, TIMER_DURATION_EXPECTED);
11759 KillTimer(NULL, id);
11760 /* Note: SetSystemTimer doesn't support a NULL window, see test_timers */
11762 if (pSetCoalescableTimer)
11764 count = 0;
11765 id = pSetCoalescableTimer(NULL, 0, 0, callback_count, 0);
11766 ok(id != 0, "SetCoalescableTimer failed with %lu.\n", GetLastError());
11767 start = GetTickCount();
11768 while (GetTickCount()-start < 100 && GetMessageA(&msg, NULL, 0, 0))
11769 DispatchMessageA(&msg);
11770 ok(count > 1, "expected count > 1, got %d.\n", count);
11771 KillTimer(NULL, id);
11773 else
11774 win_skip("SetCoalescableTimer not available.\n");
11776 /* Check what happens when we're running out of timers */
11777 for (i = 0; i < ARRAY_SIZE(ids); i++)
11779 SetLastError(0xdeadbeef);
11780 ids[i] = SetTimer(NULL, 0, USER_TIMER_MAXIMUM, tfunc);
11781 if (!ids[i]) break;
11783 ok(i != ARRAY_SIZE(ids), "all timers were created successfully\n");
11784 ok(GetLastError()==ERROR_NO_MORE_USER_HANDLES || broken(GetLastError()==0xdeadbeef),
11785 "GetLastError() = %ld\n", GetLastError());
11786 while (i > 0) KillTimer(NULL, ids[--i]);
11789 static void test_timers_exception(DWORD code)
11791 UINT_PTR id;
11792 MSG msg;
11794 exception = code;
11795 id = SetTimer(NULL, 0, 1000, callback_exception);
11796 ok(id != 0, "did not get id from SetTimer.\n");
11798 memset(&msg, 0, sizeof(msg));
11799 msg.message = WM_TIMER;
11800 msg.wParam = id;
11801 msg.lParam = (LPARAM)callback_exception;
11803 count = 0;
11804 DispatchMessageA(&msg);
11805 ok(count == 1, "did not get one count as expected (%i).\n", count);
11807 KillTimer(NULL, id);
11810 static void test_timers_exceptions(void)
11812 test_timers_exception(EXCEPTION_ACCESS_VIOLATION);
11813 test_timers_exception(EXCEPTION_DATATYPE_MISALIGNMENT);
11814 test_timers_exception(EXCEPTION_BREAKPOINT);
11815 test_timers_exception(EXCEPTION_SINGLE_STEP);
11816 test_timers_exception(EXCEPTION_ARRAY_BOUNDS_EXCEEDED);
11817 test_timers_exception(EXCEPTION_FLT_DENORMAL_OPERAND);
11818 test_timers_exception(EXCEPTION_FLT_DIVIDE_BY_ZERO);
11819 test_timers_exception(EXCEPTION_FLT_INEXACT_RESULT);
11820 test_timers_exception(EXCEPTION_ILLEGAL_INSTRUCTION);
11821 test_timers_exception(0xE000BEEF); /* customer exception */
11824 /* Various win events with arbitrary parameters */
11825 static const struct message WmWinEventsSeq[] = {
11826 { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
11827 { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
11828 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
11829 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
11830 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
11831 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
11832 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
11833 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
11834 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
11835 /* our win event hook ignores OBJID_CURSOR events */
11836 /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
11837 { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
11838 { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
11839 { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
11840 { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
11841 { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
11842 { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
11843 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
11844 { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
11845 { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
11846 { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
11847 { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
11848 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
11849 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
11850 { 0 }
11852 static const struct message WmWinEventCaretSeq[] = {
11853 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
11854 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
11855 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
11856 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
11857 { 0 }
11859 static const struct message WmWinEventCaretSeq_2[] = {
11860 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
11861 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
11862 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
11863 { 0 }
11865 static const struct message WmWinEventAlertSeq[] = {
11866 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
11867 { 0 }
11869 static const struct message WmWinEventAlertSeq_2[] = {
11870 /* create window in the thread proc */
11871 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
11872 /* our test event */
11873 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
11874 { 0 }
11876 static const struct message WmGlobalHookSeq_1[] = {
11877 /* create window in the thread proc */
11878 { HCBT_CREATEWND, hook|lparam, 0, 2 },
11879 /* our test events */
11880 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
11881 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
11882 { 0 }
11884 static const struct message WmGlobalHookSeq_2[] = {
11885 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
11886 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
11887 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
11888 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
11889 { 0 }
11892 static const struct message WmMouseLLHookSeq[] = {
11893 { WM_MOUSEMOVE, hook },
11894 { WM_LBUTTONUP, hook },
11895 { WM_MOUSEMOVE, hook },
11896 { 0 }
11899 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
11900 DWORD event,
11901 HWND hwnd,
11902 LONG object_id,
11903 LONG child_id,
11904 DWORD thread_id,
11905 DWORD event_time)
11907 char buf[256];
11909 if (GetClassNameA(hwnd, buf, sizeof(buf)))
11911 if (!lstrcmpiA(buf, "TestWindowClass") ||
11912 !lstrcmpiA(buf, "static"))
11914 struct recvd_message msg;
11916 msg.hwnd = hwnd;
11917 msg.message = event;
11918 msg.flags = winevent_hook|wparam|lparam;
11919 msg.wParam = object_id;
11920 msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
11921 msg.descr = "WEH_2";
11922 add_message(&msg);
11927 static HHOOK hCBT_global_hook;
11928 static DWORD cbt_global_hook_thread_id;
11930 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
11932 HWND hwnd;
11933 char buf[256];
11935 if (nCode == HCBT_SYSCOMMAND)
11937 struct recvd_message msg;
11939 msg.hwnd = 0;
11940 msg.message = nCode;
11941 msg.flags = hook|wparam|lparam;
11942 msg.wParam = wParam;
11943 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
11944 msg.descr = "CBT_2";
11945 add_message(&msg);
11947 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
11949 /* WH_MOUSE_LL hook */
11950 if (nCode == HC_ACTION)
11952 MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
11954 /* we can't test for real mouse events */
11955 if (mhll->flags & LLMHF_INJECTED)
11957 struct recvd_message msg;
11959 memset (&msg, 0, sizeof (msg));
11960 msg.message = wParam;
11961 msg.flags = hook;
11962 msg.descr = "CBT_2";
11963 add_message(&msg);
11965 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
11968 /* Log also SetFocus(0) calls */
11969 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
11971 if (GetClassNameA(hwnd, buf, sizeof(buf)))
11973 if (!lstrcmpiA(buf, "TestWindowClass") ||
11974 !lstrcmpiA(buf, "static"))
11976 struct recvd_message msg;
11978 msg.hwnd = hwnd;
11979 msg.message = nCode;
11980 msg.flags = hook|wparam|lparam;
11981 msg.wParam = wParam;
11982 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
11983 msg.descr = "CBT_2";
11984 add_message(&msg);
11987 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
11990 static DWORD WINAPI win_event_global_thread_proc(void *param)
11992 HWND hwnd;
11993 MSG msg;
11994 HANDLE hevent = *(HANDLE *)param;
11996 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
11997 ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError());
11998 if (winetest_debug > 1) trace("created thread window %p\n", hwnd);
12000 *(HWND *)param = hwnd;
12002 flush_sequence();
12003 /* this event should be received only by our new hook proc,
12004 * an old one does not expect an event from another thread.
12006 pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
12007 SetEvent(hevent);
12009 while (GetMessageA(&msg, 0, 0, 0))
12011 TranslateMessage(&msg);
12012 DispatchMessageA(&msg);
12014 return 0;
12017 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
12019 HWND hwnd;
12020 MSG msg;
12021 HANDLE hevent = *(HANDLE *)param;
12023 flush_sequence();
12024 /* these events should be received only by our new hook proc,
12025 * an old one does not expect an event from another thread.
12028 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
12029 ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError());
12030 if (winetest_debug > 1) trace("created thread window %p\n", hwnd);
12032 *(HWND *)param = hwnd;
12034 /* Windows doesn't like when a thread plays games with the focus,
12035 that leads to all kinds of misbehaviours and failures to activate
12036 a window. So, better keep next lines commented out.
12037 SetFocus(0);
12038 SetFocus(hwnd);*/
12040 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
12041 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
12043 SetEvent(hevent);
12045 while (GetMessageA(&msg, 0, 0, 0))
12047 TranslateMessage(&msg);
12048 DispatchMessageA(&msg);
12050 return 0;
12053 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
12055 HWND hwnd;
12056 MSG msg;
12057 HANDLE hevent = *(HANDLE *)param;
12059 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
12060 ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError());
12061 if (winetest_debug > 1) trace("created thread window %p\n", hwnd);
12063 *(HWND *)param = hwnd;
12065 flush_sequence();
12067 /* Windows doesn't like when a thread plays games with the focus,
12068 * that leads to all kinds of misbehaviours and failures to activate
12069 * a window. So, better don't generate a mouse click message below.
12071 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
12072 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
12073 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
12075 SetEvent(hevent);
12076 while (GetMessageA(&msg, 0, 0, 0))
12078 TranslateMessage(&msg);
12079 DispatchMessageA(&msg);
12081 return 0;
12084 static void test_winevents(void)
12086 BOOL ret;
12087 MSG msg;
12088 HWND hwnd, hwnd2;
12089 UINT i;
12090 HANDLE hthread, hevent;
12091 DWORD tid;
12092 HWINEVENTHOOK hhook;
12093 const struct message *events = WmWinEventsSeq;
12095 hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
12096 WS_OVERLAPPEDWINDOW,
12097 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
12098 NULL, NULL, 0);
12099 ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError());
12101 /****** start of global hook test *************/
12102 hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
12103 if (!hCBT_global_hook)
12105 ok(DestroyWindow(hwnd), "failed to destroy window\n");
12106 skip( "cannot set global hook\n" );
12107 return;
12110 hevent = CreateEventA(NULL, 0, 0, NULL);
12111 ok(!!hevent, "Failed to create event, error %lu.\n", GetLastError());
12112 hwnd2 = hevent;
12114 hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
12115 ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError());
12117 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
12119 ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
12121 flush_sequence();
12122 /* this one should be received only by old hook proc */
12123 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
12124 /* this one should be received only by old hook proc */
12125 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
12127 ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
12129 ret = UnhookWindowsHookEx(hCBT_global_hook);
12130 ok( ret, "UnhookWindowsHookEx error %ld\n", GetLastError());
12132 PostThreadMessageA(tid, WM_QUIT, 0, 0);
12133 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
12134 CloseHandle(hthread);
12135 CloseHandle(hevent);
12136 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
12137 /****** end of global hook test *************/
12139 if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
12141 ok(DestroyWindow(hwnd), "failed to destroy window\n");
12142 return;
12145 flush_sequence();
12147 if (0)
12149 /* this test doesn't pass under Win9x */
12150 /* win2k ignores events with hwnd == 0 */
12151 SetLastError(0xdeadbeef);
12152 pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
12153 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
12154 GetLastError() == 0xdeadbeef, /* Win9x */
12155 "unexpected error %ld\n", GetLastError());
12156 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
12159 for (i = 0; i < ARRAY_SIZE(WmWinEventsSeq); i++)
12160 pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
12162 ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
12164 /****** start of event filtering test *************/
12165 hhook = pSetWinEventHook(
12166 EVENT_OBJECT_SHOW, /* 0x8002 */
12167 EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
12168 GetModuleHandleA(0), win_event_global_hook_proc,
12169 GetCurrentProcessId(), 0,
12170 WINEVENT_INCONTEXT);
12171 ok(hhook != 0, "SetWinEventHook error %ld\n", GetLastError());
12173 hevent = CreateEventA(NULL, 0, 0, NULL);
12174 ok(!!hevent, "Failed to create event, error %lu.\n", GetLastError());
12175 hwnd2 = hevent;
12177 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
12178 ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError());
12180 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
12182 ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
12184 flush_sequence();
12185 /* this one should be received only by old hook proc */
12186 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
12187 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
12188 /* this one should be received only by old hook proc */
12189 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
12191 ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
12193 ret = pUnhookWinEvent(hhook);
12194 ok( ret, "UnhookWinEvent error %ld\n", GetLastError());
12196 PostThreadMessageA(tid, WM_QUIT, 0, 0);
12197 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
12198 CloseHandle(hthread);
12199 CloseHandle(hevent);
12200 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
12201 /****** end of event filtering test *************/
12203 /****** start of out of context event test *************/
12204 hhook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0,
12205 win_event_global_hook_proc, GetCurrentProcessId(), 0,
12206 WINEVENT_OUTOFCONTEXT);
12207 ok(hhook != 0, "SetWinEventHook error %ld\n", GetLastError());
12209 hevent = CreateEventA(NULL, 0, 0, NULL);
12210 ok(!!hevent, "Failed to create event, error %lu.\n", GetLastError());
12211 hwnd2 = hevent;
12213 flush_sequence();
12215 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
12216 ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError());
12218 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
12220 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
12221 /* process pending winevent messages */
12222 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
12223 ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
12225 flush_sequence();
12226 /* this one should be received only by old hook proc */
12227 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
12228 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
12229 /* this one should be received only by old hook proc */
12230 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
12232 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
12233 /* process pending winevent messages */
12234 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
12235 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
12237 ret = pUnhookWinEvent(hhook);
12238 ok( ret, "UnhookWinEvent error %ld\n", GetLastError());
12240 PostThreadMessageA(tid, WM_QUIT, 0, 0);
12241 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
12242 CloseHandle(hthread);
12243 CloseHandle(hevent);
12244 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
12245 /****** end of out of context event test *************/
12247 /****** start of MOUSE_LL hook test *************/
12248 hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
12249 /* WH_MOUSE_LL is not supported on Win9x platforms */
12250 if (!hCBT_global_hook)
12252 win_skip("Skipping WH_MOUSE_LL test on this platform\n");
12253 goto skip_mouse_ll_hook_test;
12256 hevent = CreateEventA(NULL, 0, 0, NULL);
12257 ok(!!hevent, "Failed to create event, error %lu.\n", GetLastError());
12258 hwnd2 = hevent;
12260 hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
12261 ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError());
12263 while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
12264 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
12266 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
12267 flush_sequence();
12269 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
12270 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
12271 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
12273 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
12275 ret = UnhookWindowsHookEx(hCBT_global_hook);
12276 ok( ret, "UnhookWindowsHookEx error %ld\n", GetLastError());
12278 PostThreadMessageA(tid, WM_QUIT, 0, 0);
12279 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
12280 CloseHandle(hthread);
12281 CloseHandle(hevent);
12282 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
12283 /****** end of MOUSE_LL hook test *************/
12284 skip_mouse_ll_hook_test:
12286 ok(DestroyWindow(hwnd), "failed to destroy window\n");
12289 static char *get_test_dll_path(void)
12291 static const char *dll_name = "testdll.dll";
12292 static char path[MAX_PATH];
12293 DWORD written;
12294 HANDLE file;
12295 HRSRC res;
12296 void *ptr;
12298 GetTempPathA(ARRAY_SIZE(path), path);
12299 strcat(path, dll_name);
12301 file = CreateFileA(path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
12302 ok(file != INVALID_HANDLE_VALUE, "Failed to create file %s: %lu.\n", debugstr_a(path), GetLastError());
12304 res = FindResourceA(NULL, dll_name, "TESTDLL");
12305 ok(!!res, "Failed to load resource: %lu\n", GetLastError());
12306 ptr = LockResource(LoadResource(GetModuleHandleA(NULL), res));
12307 WriteFile(file, ptr, SizeofResource(GetModuleHandleA(NULL), res), &written, NULL);
12308 ok(written == SizeofResource(GetModuleHandleA(NULL), res), "Failed to write resource\n");
12309 CloseHandle(file);
12311 return path;
12314 static void test_set_hook(void)
12316 LRESULT (CALLBACK *p_dummy_hook_proc)(int code, WPARAM wp, LPARAM lp);
12317 HMODULE test_dll_module;
12318 char *test_dll_path;
12319 DWORD error;
12320 BOOL ret;
12321 HHOOK hhook;
12322 HWINEVENTHOOK hwinevent_hook;
12323 int i;
12325 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
12326 ok(hhook != 0, "local hook does not require hModule set to 0\n");
12327 UnhookWindowsHookEx(hhook);
12329 SetLastError(0xdeadbeef);
12330 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
12331 ok(!hhook, "global hook requires hModule != 0\n");
12332 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %ld\n", GetLastError());
12334 SetLastError(0xdeadbeef);
12335 hhook = SetWindowsHookExA(WH_JOURNALRECORD, cbt_hook_proc, 0, 0);
12336 ok(!hhook, "global hook requires hModule != 0\n");
12337 ok(GetLastError() == ERROR_ACCESS_DENIED, "unexpected error %ld\n", GetLastError());
12339 SetLastError(0xdeadbeef);
12340 hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
12341 ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
12342 ok(GetLastError() == ERROR_INVALID_FILTER_PROC, "unexpected error %ld\n", GetLastError());
12344 SetLastError(0xdeadbeef);
12345 ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
12346 ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE, "unexpected error %ld\n", GetLastError());
12348 test_dll_path = get_test_dll_path();
12349 test_dll_module = LoadLibraryA(test_dll_path);
12350 p_dummy_hook_proc = (void *)GetProcAddress(test_dll_module, "dummy_hook_proc");
12351 for (i = WH_MIN; i <= WH_MAX; i++)
12353 winetest_push_context("ID %d", i);
12355 /* Test that setting hooks should succeed for hook procs in a library. But for WH_JOURNALRECORD
12356 * and WH_JOURNALPLAYBACK, ERROR_ACCESS_DENIED is returned, even with administrator rights */
12357 SetLastError(0xdeadbeef);
12358 hhook = SetWindowsHookExA(i, p_dummy_hook_proc, test_dll_module, 0);
12359 error = GetLastError();
12360 if (i == WH_JOURNALRECORD || i == WH_JOURNALPLAYBACK)
12362 ok(!hhook, "SetWinEventHook succeeded.\n");
12363 ok(error == ERROR_ACCESS_DENIED, "Got unexpected error %ld.\n", GetLastError());
12365 else
12367 ok(!!hhook, "SetWinEventHook failed.\n");
12368 ok(error == NO_ERROR, "Got unexpected error %ld.\n", GetLastError());
12370 if (hhook)
12371 UnhookWindowsHookEx(hhook);
12373 /* Test settings global hooks with a thread ID */
12374 SetLastError(0xdeadbeef);
12375 hhook = SetWindowsHookExA(i, p_dummy_hook_proc, test_dll_module, GetCurrentThreadId());
12376 error = GetLastError();
12377 if (i == WH_JOURNALRECORD || i == WH_JOURNALPLAYBACK || i == WH_SYSMSGFILTER
12378 || i == WH_KEYBOARD_LL || i == WH_MOUSE_LL)
12380 ok(!hhook, "SetWinEventHook succeeded.\n");
12381 ok(error == ERROR_GLOBAL_ONLY_HOOK, "Got unexpected error %ld.\n", GetLastError());
12383 else
12385 ok(!!hhook, "SetWinEventHook failed.\n");
12386 ok(error == NO_ERROR, "Got unexpected error %ld.\n", GetLastError());
12388 if (hhook)
12389 UnhookWindowsHookEx(hhook);
12391 winetest_pop_context();
12393 FreeLibrary(test_dll_module);
12394 ret = DeleteFileA(test_dll_path);
12395 ok(ret, "Failed to remove the test dll, error %ld.\n", GetLastError());
12397 if (!pSetWinEventHook || !pUnhookWinEvent) return;
12399 /* even process local incontext hooks require hmodule */
12400 SetLastError(0xdeadbeef);
12401 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
12402 GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
12403 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
12404 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %ld\n", GetLastError());
12406 /* even thread local incontext hooks require hmodule */
12407 SetLastError(0xdeadbeef);
12408 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
12409 GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
12410 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
12411 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %ld\n", GetLastError());
12413 SetLastError(0xdeadbeef);
12414 hwinevent_hook = pSetWinEventHook(1, 0, 0, win_event_proc,
12415 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
12416 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
12417 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %ld\n", GetLastError());
12419 SetLastError(0xdeadbeef);
12420 hwinevent_hook = pSetWinEventHook(-1, 1, 0, win_event_proc,
12421 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
12422 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
12423 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %ld\n", GetLastError());
12425 SetLastError(0xdeadbeef);
12426 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
12427 0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
12428 ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
12429 todo_wine
12430 ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %ld\n", GetLastError());
12432 SetLastError(0xdeadbeef);
12433 hwinevent_hook = pSetWinEventHook(0, 0, 0, win_event_proc,
12434 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
12435 ok(hwinevent_hook != 0, "SetWinEventHook error %ld\n", GetLastError());
12436 ok(GetLastError() == 0xdeadbeef, "unexpected error %ld\n", GetLastError());
12437 ret = pUnhookWinEvent(hwinevent_hook);
12438 ok( ret, "UnhookWinEvent error %ld\n", GetLastError());
12440 todo_wine {
12441 /* This call succeeds under win2k SP4, but fails under Wine.
12442 Does win2k test/use passed process id? */
12443 SetLastError(0xdeadbeef);
12444 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
12445 0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
12446 ok(hwinevent_hook != 0, "SetWinEventHook error %ld\n", GetLastError());
12447 ok(GetLastError() == 0xdeadbeef, "unexpected error %ld\n", GetLastError());
12448 ret = pUnhookWinEvent(hwinevent_hook);
12449 ok( ret, "UnhookWinEvent error %ld\n", GetLastError());
12452 SetLastError(0xdeadbeef);
12453 ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
12454 ok(GetLastError() == ERROR_INVALID_HANDLE, "unexpected error %ld\n", GetLastError());
12457 static HWND hook_hwnd;
12458 static HHOOK recursive_hook;
12459 static int hook_depth, max_hook_depth;
12460 static BOOL skip_WH_KEYBOARD_hook, skip_WH_MOUSE_hook;
12462 static void simulate_click(BOOL left, int x, int y)
12464 POINT old_pt;
12465 INPUT input[2];
12466 UINT events_no;
12468 GetCursorPos(&old_pt);
12469 SetCursorPos(x, y);
12470 memset(input, 0, sizeof(input));
12471 input[0].type = INPUT_MOUSE;
12472 input[0].mi.dx = x;
12473 input[0].mi.dy = y;
12474 input[0].mi.dwFlags = left ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_RIGHTDOWN;
12475 input[1].type = INPUT_MOUSE;
12476 input[1].mi.dx = x;
12477 input[1].mi.dy = y;
12478 input[1].mi.dwFlags = left ? MOUSEEVENTF_LEFTUP : MOUSEEVENTF_RIGHTUP;
12479 events_no = SendInput(2, input, sizeof(input[0]));
12480 ok(events_no == 2, "SendInput returned %d\n", events_no);
12481 SetCursorPos(old_pt.x, old_pt.y);
12484 static LRESULT WINAPI rec_get_message_hook(int code, WPARAM w, LPARAM l)
12486 LRESULT res;
12487 MSG msg;
12488 BOOL b;
12490 hook_depth++;
12491 if(hook_depth > max_hook_depth)
12492 max_hook_depth = hook_depth;
12494 b = PeekMessageW(&msg, hook_hwnd, 0, 0, PM_NOREMOVE);
12495 ok(b, "PeekMessage failed\n");
12497 res = CallNextHookEx(recursive_hook, code, w, l);
12499 hook_depth--;
12500 return res;
12503 static LRESULT CALLBACK keyboard_recursive_hook_proc(int code, WPARAM wp, LPARAM lp)
12505 MSG msg;
12507 if (code < 0)
12508 return CallNextHookEx(0, code, wp, lp);
12510 if (skip_WH_KEYBOARD_hook)
12511 return 1;
12513 hook_depth++;
12514 max_hook_depth = max(max_hook_depth, hook_depth);
12515 PeekMessageW(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE);
12516 hook_depth--;
12517 return CallNextHookEx(0, code, wp, lp);
12520 static LRESULT CALLBACK mouse_recursive_hook_proc(int code, WPARAM wp, LPARAM lp)
12522 MSG msg;
12524 if (code < 0)
12525 return CallNextHookEx(0, code, wp, lp);
12527 if (skip_WH_MOUSE_hook)
12528 return 1;
12530 hook_depth++;
12531 max_hook_depth = max(max_hook_depth, hook_depth);
12532 PeekMessageW(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE);
12533 hook_depth--;
12534 return CallNextHookEx(0, code, wp, lp);
12537 static LRESULT CALLBACK keyboard_recursive_cbt_hook_proc(int code, WPARAM wp, LPARAM lp)
12539 MSG msg;
12541 if (code < 0)
12542 return CallNextHookEx(0, code, wp, lp);
12544 if (code == HCBT_KEYSKIPPED)
12546 hook_depth++;
12547 max_hook_depth = max(max_hook_depth, hook_depth);
12548 PeekMessageW(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE);
12549 hook_depth--;
12552 return CallNextHookEx(0, code, wp, lp);
12555 static LRESULT CALLBACK mouse_recursive_cbt_hook_proc(int code, WPARAM wp, LPARAM lp)
12557 MSG msg;
12559 if (code < 0)
12560 return CallNextHookEx(0, code, wp, lp);
12562 if (code == HCBT_CLICKSKIPPED)
12564 hook_depth++;
12565 max_hook_depth = max(max_hook_depth, hook_depth);
12566 PeekMessageW(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE);
12567 hook_depth--;
12570 return CallNextHookEx(0, code, wp, lp);
12573 static void test_recursive_hook(void)
12575 HHOOK hook, cbt_hook;
12576 INPUT input = {0};
12577 MSG msg;
12578 BOOL b;
12580 hook_hwnd = CreateWindowExA(WS_EX_TOPMOST, "Static", NULL, WS_POPUP | WS_VISIBLE, 0, 0, 200, 60,
12581 NULL, NULL, NULL, NULL);
12582 ok(hook_hwnd != NULL, "CreateWindow failed\n");
12584 recursive_hook = SetWindowsHookExW(WH_GETMESSAGE, rec_get_message_hook, NULL, GetCurrentThreadId());
12585 ok(recursive_hook != NULL, "SetWindowsHookEx failed\n");
12587 PostMessageW(hook_hwnd, WM_USER, 0, 0);
12588 PostMessageW(hook_hwnd, WM_USER+1, 0, 0);
12590 hook_depth = 0;
12591 GetMessageW(&msg, hook_hwnd, 0, 0);
12592 ok(15 <= max_hook_depth && max_hook_depth < 45, "max_hook_depth = %d\n", max_hook_depth);
12593 if (winetest_debug > 1) trace("max_hook_depth = %d\n", max_hook_depth);
12595 b = UnhookWindowsHookEx(recursive_hook);
12596 ok(b, "UnhokWindowsHookEx failed\n");
12598 /* Test possible recursive hook conditions */
12599 b = SetForegroundWindow(hook_hwnd);
12600 ok(b, "SetForegroundWindow failed, error %ld.\n", GetLastError());
12602 /* Test a possible recursive WH_KEYBOARD hook condition */
12603 max_hook_depth = 0;
12604 hook = SetWindowsHookExA(WH_KEYBOARD, keyboard_recursive_hook_proc, NULL, GetCurrentThreadId());
12605 ok(!!hook, "SetWindowsHookExA failed, error %ld.\n", GetLastError());
12607 flush_events();
12608 input.type = INPUT_KEYBOARD;
12609 input.ki.wVk = VK_F3;
12610 SendInput(1, &input, sizeof(INPUT));
12611 flush_events();
12613 /* Expect the WH_KEYBOARD hook not gets called recursively */
12614 ok(max_hook_depth == 1, "Got expected %d.\n", max_hook_depth);
12616 /* Test a possible recursive WH_CBT HCBT_KEYSKIPPED hook condition */
12617 max_hook_depth = 0;
12618 skip_WH_KEYBOARD_hook = 1;
12619 cbt_hook = SetWindowsHookExA(WH_CBT, keyboard_recursive_cbt_hook_proc, NULL, GetCurrentThreadId());
12620 ok(!!cbt_hook, "SetWindowsHookExA failed, error %ld.\n", GetLastError());
12622 flush_events();
12623 input.type = INPUT_KEYBOARD;
12624 input.ki.wVk = VK_F3;
12625 SendInput(1, &input, sizeof(INPUT));
12626 while (PeekMessageA(&msg, hook_hwnd, WM_KEYFIRST, WM_KEYLAST, 0)) DispatchMessageA(&msg);
12628 /* Expect the WH_CBT HCBT_KEYSKIPPED hook not gets called recursively */
12629 ok(max_hook_depth == 1, "Got expected %d.\n", max_hook_depth);
12631 UnhookWindowsHookEx(cbt_hook);
12632 UnhookWindowsHookEx(hook);
12634 /* Test a recursive WH_MOUSE hook condition */
12635 SetCapture(hook_hwnd);
12637 max_hook_depth = 0;
12638 hook = SetWindowsHookExA(WH_MOUSE, mouse_recursive_hook_proc, NULL, GetCurrentThreadId());
12639 ok(!!hook, "SetWindowsHookExA failed, error %ld.\n", GetLastError());
12641 flush_events();
12642 simulate_click(FALSE, 50, 50);
12643 flush_events();
12645 /* Expect the WH_MOUSE hook gets called recursively */
12646 ok(max_hook_depth > 10, "Got expected %d.\n", max_hook_depth);
12648 /* Test a possible recursive WH_CBT HCBT_CLICKSKIPPED hook condition */
12649 max_hook_depth = 0;
12650 skip_WH_MOUSE_hook = 1;
12651 cbt_hook = SetWindowsHookExA(WH_CBT, mouse_recursive_cbt_hook_proc, NULL, GetCurrentThreadId());
12652 ok(!!cbt_hook, "SetWindowsHookExA failed, error %ld.\n", GetLastError());
12654 flush_events();
12655 simulate_click(FALSE, 50, 50);
12656 flush_events();
12658 /* Expect the WH_CBT HCBT_CLICKSKIPPED hook not gets called recursively */
12659 ok(max_hook_depth <= 10, "Got expected %d.\n", max_hook_depth);
12661 UnhookWindowsHookEx(cbt_hook);
12662 UnhookWindowsHookEx(hook);
12663 ReleaseCapture();
12664 DestroyWindow(hook_hwnd);
12667 static int max_msg_depth;
12669 static LRESULT WINAPI recursive_messages_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
12671 static int msg_depth;
12672 MSG msg;
12674 if (message == WM_SETCURSOR && max_msg_depth < 15)
12676 msg_depth++;
12677 max_msg_depth = max(max_msg_depth, msg_depth);
12678 PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE);
12679 msg_depth--;
12681 return DefWindowProcA(hwnd, message, wp, lp);
12684 static void test_recursive_messages(void)
12686 WNDCLASSA cls = {0};
12687 HWND hwnd;
12689 cls.lpfnWndProc = recursive_messages_proc;
12690 cls.hInstance = GetModuleHandleA(0);
12691 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
12692 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
12693 cls.lpszClassName = "TestRecursiveMsgClass";
12694 register_class(&cls);
12696 hwnd = CreateWindowExA(WS_EX_TOPMOST, "TestRecursiveMsgClass", NULL, WS_POPUP | WS_DISABLED | WS_VISIBLE, 0, 0,
12697 100, 100, NULL, NULL, NULL, NULL);
12698 ok(hwnd != NULL, "CreateWindowExA failed, error %ld.\n", GetLastError());
12699 SetForegroundWindow(hwnd);
12700 flush_events();
12702 max_msg_depth = 0;
12703 simulate_click(FALSE, 50, 50);
12704 flush_events();
12706 /* Expect recursive_messages_proc() gets called recursively for WM_SETCURSOR */
12707 ok(max_msg_depth == 15, "Got expected %d.\n", max_msg_depth);
12709 DestroyWindow(hwnd);
12710 UnregisterClassA(cls.lpszClassName, cls.hInstance);
12713 static const struct message ScrollWindowPaint1[] = {
12714 { WM_PAINT, sent },
12715 { WM_ERASEBKGND, sent|beginpaint },
12716 { WM_GETTEXTLENGTH, sent|optional },
12717 { WM_PAINT, sent|optional },
12718 { WM_NCPAINT, sent|beginpaint|optional },
12719 { WM_GETTEXT, sent|beginpaint|optional },
12720 { WM_GETTEXT, sent|beginpaint|optional },
12721 { WM_GETTEXT, sent|beginpaint|optional },
12722 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
12723 { WM_ERASEBKGND, sent|beginpaint|optional },
12724 { 0 }
12727 static const struct message ScrollWindowPaint2[] = {
12728 { WM_PAINT, sent },
12729 { 0 }
12732 static void test_scrollwindowex(void)
12734 HWND hwnd, hchild;
12735 RECT rect={0,0,130,130};
12737 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
12738 WS_VISIBLE|WS_OVERLAPPEDWINDOW,
12739 100, 100, 200, 200, 0, 0, 0, NULL);
12740 ok (hwnd != 0, "Failed to create overlapped window\n");
12741 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
12742 WS_VISIBLE|WS_CAPTION|WS_CHILD,
12743 10, 10, 150, 150, hwnd, 0, 0, NULL);
12744 ok (hchild != 0, "Failed to create child\n");
12745 UpdateWindow(hwnd);
12746 flush_events();
12747 flush_sequence();
12749 /* scroll without the child window */
12750 if (winetest_debug > 1) trace("start scroll\n");
12751 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
12752 SW_ERASE|SW_INVALIDATE);
12753 ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
12754 if (winetest_debug > 1) trace("end scroll\n");
12755 flush_sequence();
12756 flush_events();
12757 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
12758 flush_events();
12759 flush_sequence();
12761 /* Now without the SW_ERASE flag */
12762 if (winetest_debug > 1) trace("start scroll\n");
12763 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
12764 ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
12765 if (winetest_debug > 1) trace("end scroll\n");
12766 flush_sequence();
12767 flush_events();
12768 ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", FALSE);
12769 flush_events();
12770 flush_sequence();
12772 /* now scroll the child window as well */
12773 if (winetest_debug > 1) trace("start scroll\n");
12774 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
12775 SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
12776 /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
12777 /* windows sometimes a WM_MOVE */
12778 ok_sequence(WmEmptySeq, "ScrollWindowEx", TRUE);
12779 if (winetest_debug > 1) trace("end scroll\n");
12780 flush_sequence();
12781 flush_events();
12782 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
12783 flush_events();
12784 flush_sequence();
12786 /* now scroll with ScrollWindow() */
12787 if (winetest_debug > 1) trace("start scroll with ScrollWindow\n");
12788 ScrollWindow( hwnd, 5, 5, NULL, NULL);
12789 if (winetest_debug > 1) trace("end scroll\n");
12790 flush_sequence();
12791 flush_events();
12792 ok_sequence(ScrollWindowPaint1, "ScrollWindow", FALSE);
12794 ok(DestroyWindow(hchild), "failed to destroy window\n");
12795 ok(DestroyWindow(hwnd), "failed to destroy window\n");
12796 flush_sequence();
12799 static const struct message destroy_window_with_children[] = {
12800 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* popup */
12801 { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
12802 { 0x0090, sent|optional },
12803 { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
12804 { 0x0090, sent|optional },
12805 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* popup */
12806 { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
12807 { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
12808 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
12809 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* parent */
12810 { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
12811 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
12812 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
12813 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
12814 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
12815 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
12816 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
12817 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
12818 { 0 }
12821 static void test_DestroyWindow(void)
12823 BOOL ret;
12824 HWND parent, child1, child2, child3, child4, test;
12825 UINT_PTR child_id = WND_CHILD_ID + 1;
12827 parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
12828 100, 100, 200, 200, 0, 0, 0, NULL);
12829 ok(!!parent, "Failed to create window, error %lu.\n", GetLastError());
12830 child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
12831 0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
12832 ok(!!child1, "Failed to create window, error %lu.\n", GetLastError());
12833 child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
12834 0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
12835 ok(!!child2, "Failed to create window, error %lu.\n", GetLastError());
12836 child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
12837 0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
12838 ok(!!child3, "Failed to create window, error %lu.\n", GetLastError());
12839 child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
12840 0, 0, 50, 50, parent, 0, 0, NULL);
12841 ok(!!child4, "Failed to create window, error %lu.\n", GetLastError());
12843 /* test owner/parent of child2 */
12844 test = GetParent(child2);
12845 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
12846 ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
12847 test = GetAncestor(child2, GA_PARENT);
12848 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
12849 test = GetWindow(child2, GW_OWNER);
12850 ok(!test, "wrong owner %p\n", test);
12852 test = SetParent(child2, parent);
12853 ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
12855 /* test owner/parent of the parent */
12856 test = GetParent(parent);
12857 ok(!test, "wrong parent %p\n", test);
12858 ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
12859 test = GetAncestor(parent, GA_PARENT);
12860 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
12861 test = GetWindow(parent, GW_OWNER);
12862 ok(!test, "wrong owner %p\n", test);
12864 /* test owner/parent of child1 */
12865 test = GetParent(child1);
12866 ok(test == parent, "wrong parent %p\n", test);
12867 ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
12868 test = GetAncestor(child1, GA_PARENT);
12869 ok(test == parent, "wrong parent %p\n", test);
12870 test = GetWindow(child1, GW_OWNER);
12871 ok(!test, "wrong owner %p\n", test);
12873 /* test owner/parent of child2 */
12874 test = GetParent(child2);
12875 ok(test == parent, "wrong parent %p\n", test);
12876 ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
12877 test = GetAncestor(child2, GA_PARENT);
12878 ok(test == parent, "wrong parent %p\n", test);
12879 test = GetWindow(child2, GW_OWNER);
12880 ok(!test, "wrong owner %p\n", test);
12882 /* test owner/parent of child3 */
12883 test = GetParent(child3);
12884 ok(test == child1, "wrong parent %p\n", test);
12885 ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
12886 test = GetAncestor(child3, GA_PARENT);
12887 ok(test == child1, "wrong parent %p\n", test);
12888 test = GetWindow(child3, GW_OWNER);
12889 ok(!test, "wrong owner %p\n", test);
12891 /* test owner/parent of child4 */
12892 test = GetParent(child4);
12893 ok(test == parent, "wrong parent %p\n", test);
12894 ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
12895 test = GetAncestor(child4, GA_PARENT);
12896 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
12897 test = GetWindow(child4, GW_OWNER);
12898 ok(test == parent, "wrong owner %p\n", test);
12900 flush_sequence();
12902 if (winetest_debug > 1) trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
12903 parent, child1, child2, child3, child4);
12905 SetCapture(child4);
12906 test = GetCapture();
12907 ok(test == child4, "wrong capture window %p\n", test);
12909 test_DestroyWindow_flag = TRUE;
12910 ret = DestroyWindow(parent);
12911 ok( ret, "DestroyWindow() error %ld\n", GetLastError());
12912 test_DestroyWindow_flag = FALSE;
12913 ok_sequence(destroy_window_with_children, "destroy window with children", FALSE);
12915 ok(!IsWindow(parent), "parent still exists\n");
12916 ok(!IsWindow(child1), "child1 still exists\n");
12917 ok(!IsWindow(child2), "child2 still exists\n");
12918 ok(!IsWindow(child3), "child3 still exists\n");
12919 ok(!IsWindow(child4), "child4 still exists\n");
12921 test = GetCapture();
12922 ok(!test, "wrong capture window %p\n", test);
12926 static const struct message WmDispatchPaint[] = {
12927 { WM_NCPAINT, sent },
12928 { WM_GETTEXT, sent|defwinproc|optional },
12929 { WM_GETTEXT, sent|defwinproc|optional },
12930 { WM_ERASEBKGND, sent },
12931 { 0 }
12934 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
12936 if (message == WM_PAINT) return 0;
12937 return MsgCheckProcA( hwnd, message, wParam, lParam );
12940 static void test_DispatchMessage(void)
12942 RECT rect;
12943 MSG msg;
12944 int count;
12945 HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
12946 100, 100, 200, 200, 0, 0, 0, NULL);
12947 ShowWindow( hwnd, SW_SHOW );
12948 UpdateWindow( hwnd );
12949 flush_events();
12950 flush_sequence();
12951 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
12953 SetRect( &rect, -5, -5, 5, 5 );
12954 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
12955 count = 0;
12956 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
12958 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
12959 else
12961 flush_sequence();
12962 DispatchMessageA( &msg );
12963 /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
12964 if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
12965 else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
12966 if (++count > 10) break;
12969 ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
12971 if (winetest_debug > 1) trace("now without DispatchMessage\n");
12972 flush_sequence();
12973 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
12974 count = 0;
12975 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
12977 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
12978 else
12980 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
12981 flush_sequence();
12982 /* this will send WM_NCCPAINT just like DispatchMessage does */
12983 GetUpdateRgn( hwnd, hrgn, TRUE );
12984 ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
12985 DeleteObject( hrgn );
12986 GetClientRect( hwnd, &rect );
12987 ValidateRect( hwnd, &rect ); /* this will stop WM_PAINTs */
12988 ok( !count, "Got multiple WM_PAINTs\n" );
12989 if (++count > 10) break;
12993 flush_sequence();
12994 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
12995 count = 0;
12996 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
12998 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
12999 else
13001 HDC hdc;
13003 flush_sequence();
13004 hdc = BeginPaint( hwnd, NULL );
13005 ok( !hdc, "got valid hdc %p from BeginPaint\n", hdc );
13006 ok( !EndPaint( hwnd, NULL ), "EndPaint succeeded\n" );
13007 ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
13008 ok( !count, "Got multiple WM_PAINTs\n" );
13009 if (++count > 10) break;
13012 DestroyWindow(hwnd);
13016 static const struct message WmUser[] = {
13017 { WM_USER, sent },
13018 { 0 }
13021 struct sendmsg_info
13023 HWND hwnd;
13024 DWORD timeout;
13025 DWORD ret;
13026 HANDLE ready;
13029 static DWORD CALLBACK send_msg_thread( LPVOID arg )
13031 struct sendmsg_info *info = arg;
13032 SetLastError( 0xdeadbeef );
13033 SetEvent( info->ready );
13034 info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
13035 if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT ||
13036 broken(GetLastError() == 0), /* win9x */
13037 "unexpected error %ld\n", GetLastError());
13038 return 0;
13041 static void wait_for_thread( HANDLE thread )
13043 while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
13045 MSG msg;
13046 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA(&msg);
13050 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13052 if (message == WM_USER) Sleep(200);
13053 return MsgCheckProcA( hwnd, message, wParam, lParam );
13056 static void test_SendMessageTimeout(void)
13058 HANDLE thread;
13059 struct sendmsg_info info;
13060 DWORD tid;
13061 BOOL is_win9x;
13063 info.ready = CreateEventA( NULL, 0, 0, NULL );
13064 info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
13065 100, 100, 200, 200, 0, 0, 0, NULL);
13066 flush_events();
13067 flush_sequence();
13069 info.timeout = 1000;
13070 info.ret = 0xdeadbeef;
13071 ResetEvent( info.ready );
13072 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
13073 WaitForSingleObject( info.ready, INFINITE );
13074 wait_for_thread( thread );
13075 CloseHandle( thread );
13076 ok( info.ret == 1, "SendMessageTimeout failed\n" );
13077 ok_sequence( WmUser, "WmUser", FALSE );
13079 info.timeout = 1;
13080 info.ret = 0xdeadbeef;
13081 ResetEvent( info.ready );
13082 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
13083 WaitForSingleObject( info.ready, INFINITE );
13084 Sleep(100); /* SendMessageTimeout should time out here */
13085 wait_for_thread( thread );
13086 CloseHandle( thread );
13087 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
13088 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
13090 /* 0 means infinite timeout (but not on win9x) */
13091 info.timeout = 0;
13092 info.ret = 0xdeadbeef;
13093 ResetEvent( info.ready );
13094 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
13095 WaitForSingleObject( info.ready, INFINITE );
13096 Sleep(100);
13097 wait_for_thread( thread );
13098 CloseHandle( thread );
13099 is_win9x = !info.ret;
13100 if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
13101 else ok_sequence( WmUser, "WmUser", FALSE );
13103 /* timeout is treated as signed despite the prototype (but not on win9x) */
13104 info.timeout = 0x7fffffff;
13105 info.ret = 0xdeadbeef;
13106 ResetEvent( info.ready );
13107 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
13108 WaitForSingleObject( info.ready, INFINITE );
13109 Sleep(100);
13110 wait_for_thread( thread );
13111 CloseHandle( thread );
13112 ok( info.ret == 1, "SendMessageTimeout failed\n" );
13113 ok_sequence( WmUser, "WmUser", FALSE );
13115 info.timeout = 0x80000000;
13116 info.ret = 0xdeadbeef;
13117 ResetEvent( info.ready );
13118 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
13119 WaitForSingleObject( info.ready, INFINITE );
13120 Sleep(100);
13121 wait_for_thread( thread );
13122 CloseHandle( thread );
13123 if (is_win9x)
13125 ok( info.ret == 1, "SendMessageTimeout failed\n" );
13126 ok_sequence( WmUser, "WmUser", FALSE );
13128 else
13130 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
13131 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
13134 /* now check for timeout during message processing */
13135 SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
13136 info.timeout = 100;
13137 info.ret = 0xdeadbeef;
13138 ResetEvent( info.ready );
13139 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
13140 WaitForSingleObject( info.ready, INFINITE );
13141 wait_for_thread( thread );
13142 CloseHandle( thread );
13143 /* we should time out but still get the message */
13144 ok( info.ret == 0, "SendMessageTimeout failed\n" );
13145 ok_sequence( WmUser, "WmUser", FALSE );
13147 DestroyWindow( info.hwnd );
13148 CloseHandle( info.ready );
13152 /****************** edit message test *************************/
13153 #define ID_EDIT 0x1234
13154 static const struct message sl_edit_setfocus[] =
13156 { HCBT_SETFOCUS, hook },
13157 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
13158 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13159 { EM_GETPASSWORDCHAR, sent|optional }, /* Sent on some Win10 machines */
13160 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
13161 { WM_SETFOCUS, sent|wparam, 0 },
13162 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
13163 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
13164 { WM_CTLCOLOREDIT, sent|parent },
13165 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
13166 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 },
13167 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 },
13168 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
13169 { 0 }
13171 static const struct message sl_edit_invisible[] =
13173 { HCBT_SETFOCUS, hook },
13174 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
13175 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13176 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Sent for IME. */
13177 { WM_KILLFOCUS, sent|parent },
13178 { EM_GETPASSWORDCHAR, sent|optional }, /* Sent on some Win10 machines */
13179 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
13180 { WM_SETFOCUS, sent },
13181 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 },
13182 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 },
13183 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
13184 { 0 }
13186 static const struct message ml_edit_setfocus[] =
13188 { HCBT_SETFOCUS, hook },
13189 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
13190 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13191 { EM_GETPASSWORDCHAR, sent|optional }, /* Sent on some Win10 machines */
13192 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
13193 { WM_SETFOCUS, sent|wparam, 0 },
13194 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
13195 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
13196 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 },
13197 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 },
13198 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CARET, 0 },
13199 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
13200 { 0 }
13202 static const struct message sl_edit_killfocus[] =
13204 { HCBT_SETFOCUS, hook },
13205 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
13206 { WM_KILLFOCUS, sent|wparam, 0 },
13207 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 },
13208 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 },
13209 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
13210 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
13211 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
13212 { 0 }
13214 static const struct message sl_edit_lbutton_dblclk[] =
13216 { WM_LBUTTONDBLCLK, sent },
13217 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
13218 { 0 }
13220 static const struct message sl_edit_lbutton_down[] =
13222 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
13223 { HCBT_SETFOCUS, hook },
13224 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
13225 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13226 { EM_GETPASSWORDCHAR, sent|defwinproc|optional }, /* Sent on some Win10 machines */
13227 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
13228 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
13229 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
13230 { WM_CTLCOLOREDIT, sent|parent },
13231 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
13232 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 },
13233 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CARET, 0 },
13234 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 },
13235 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
13236 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
13237 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 },
13238 { WM_CTLCOLOREDIT, sent|parent|optional },
13239 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
13240 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CARET, 0 },
13241 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 },
13242 { 0 }
13244 static const struct message ml_edit_lbutton_down[] =
13246 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
13247 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
13248 { HCBT_SETFOCUS, hook },
13249 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
13250 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13251 { EM_GETPASSWORDCHAR, sent|defwinproc|optional }, /* Sent on some Win10 machines */
13252 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
13253 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
13254 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
13255 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
13256 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 },
13257 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 },
13258 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
13259 { 0 }
13261 static const struct message sl_edit_lbutton_up[] =
13263 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
13264 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 },
13265 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
13266 { WM_CAPTURECHANGED, sent|defwinproc },
13267 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 },
13268 { 0 }
13270 static const struct message ml_edit_lbutton_up[] =
13272 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
13273 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
13274 { WM_CAPTURECHANGED, sent|defwinproc },
13275 { 0 }
13278 static WNDPROC old_edit_proc;
13280 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13282 static LONG defwndproc_counter = 0;
13283 LRESULT ret;
13284 struct recvd_message msg;
13286 if (ignore_message( message )) return 0;
13288 msg.hwnd = hwnd;
13289 msg.message = message;
13290 msg.flags = sent|wparam|lparam;
13291 if (defwndproc_counter) msg.flags |= defwinproc;
13292 msg.wParam = wParam;
13293 msg.lParam = lParam;
13294 msg.descr = "edit";
13295 add_message(&msg);
13297 defwndproc_counter++;
13298 ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
13299 defwndproc_counter--;
13301 return ret;
13304 static const struct message edit_wm_ime_composition_seq[] =
13306 {WM_IME_STARTCOMPOSITION, sent},
13307 {WM_IME_COMPOSITION, sent | wparam, 'W'},
13308 {WM_IME_CHAR, sent | wparam | defwinproc, 'W'},
13309 {WM_IME_CHAR, sent | wparam | defwinproc, 'i'},
13310 {WM_IME_CHAR, sent | wparam | defwinproc, 'n'},
13311 {WM_IME_CHAR, sent | wparam | defwinproc, 'e'},
13312 {WM_IME_ENDCOMPOSITION, sent},
13313 {WM_CHAR, sent | wparam, 'W'},
13314 {WM_CHAR, sent | wparam, 'i'},
13315 {WM_CHAR, sent | wparam, 'n'},
13316 {WM_CHAR, sent | wparam, 'e'},
13320 static const struct message edit_wm_ime_composition_korean_seq[] =
13322 {WM_IME_ENDCOMPOSITION, sent},
13323 {WM_IME_COMPOSITION, sent | wparam, 'W'},
13324 {WM_IME_CHAR, sent | wparam | defwinproc, 'W'},
13325 {WM_IME_CHAR, sent | wparam | defwinproc, 'i'},
13326 {WM_IME_CHAR, sent | wparam | defwinproc, 'n'},
13327 {WM_IME_CHAR, sent | wparam | defwinproc, 'e'},
13328 {WM_CHAR, sent | wparam, 'W'},
13329 {WM_CHAR, sent | wparam, 'i'},
13330 {WM_CHAR, sent | wparam, 'n'},
13331 {WM_CHAR, sent | wparam, 'e'},
13335 static const struct message edit_wm_ime_char_seq[] =
13337 {WM_IME_CHAR, sent | wparam, '0'},
13338 {WM_CHAR, sent | wparam, '0'},
13342 static const struct message edit_eimes_getcompstratonce_seq[] =
13344 {WM_IME_STARTCOMPOSITION, sent},
13345 {WM_IME_COMPOSITION, sent | wparam, 'W'},
13346 {WM_IME_ENDCOMPOSITION, sent},
13350 static const struct message edit_eimes_getcompstratonce_korean_seq[] =
13352 {WM_IME_ENDCOMPOSITION, sent},
13353 {WM_IME_COMPOSITION, sent | wparam, 'W'},
13357 static LRESULT CALLBACK edit_ime_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13359 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
13360 static LONG defwndproc_counter = 0;
13361 struct recvd_message msg = {0};
13362 LRESULT ret;
13364 msg.message = message;
13365 msg.flags = sent | wparam;
13366 if (defwndproc_counter)
13367 msg.flags |= defwinproc;
13368 msg.wParam = wParam;
13370 if (message < 0xc000 &&
13371 message != WM_GETTEXTLENGTH &&
13372 message != WM_GETTEXT &&
13373 message != WM_GETFONT &&
13374 message != WM_GETICON &&
13375 message != WM_IME_SETCONTEXT &&
13376 message != WM_IME_NOTIFY &&
13377 message != WM_CTLCOLOREDIT &&
13378 message != WM_PAINT &&
13379 message != WM_ERASEBKGND &&
13380 message != WM_NCHITTEST &&
13381 message != WM_SETCURSOR &&
13382 message != WM_MOUSEMOVE &&
13383 message != WM_MOUSEACTIVATE &&
13384 message != WM_KEYUP &&
13385 (message < EM_GETSEL || message > EM_GETIMESTATUS))
13387 add_message(&msg);
13390 defwndproc_counter++;
13391 if (IsWindowUnicode(hwnd))
13392 ret = CallWindowProcW(oldproc, hwnd, message, wParam, lParam);
13393 else
13394 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
13395 defwndproc_counter--;
13397 return ret;
13400 static DWORD WINAPI test_edit_ime_messages(void *unused_arg)
13402 static const HKL korean_hkl = (HKL)0x04120412;
13403 WNDPROC old_proc;
13404 LRESULT lr;
13405 HIMC himc;
13406 HWND hwnd;
13407 BOOL ret;
13408 HKL hkl;
13409 MSG msg;
13411 hkl = GetKeyboardLayout(0);
13413 hwnd = CreateWindowA(WC_EDITA, "Test", WS_POPUP | WS_VISIBLE, 10, 10, 300, 300, NULL, NULL,
13414 NULL, NULL);
13415 ok(hwnd != NULL, "CreateWindowA failed.\n");
13417 /* Test EM_{GET|SET}IMESTATUS */
13418 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
13419 ok(lr == 0, "Got unexpected lr %#Ix.\n", lr);
13421 /* Note that EM_SETIMESTATUS always return 1, which is contrary to what MSDN says about
13422 * returning the previous LPARAM value */
13423 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_GETCOMPSTRATONCE);
13424 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
13425 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
13426 ok(lr == EIMES_GETCOMPSTRATONCE, "Got unexpected lr %#Ix.\n", lr);
13428 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_CANCELCOMPSTRINFOCUS);
13429 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
13430 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
13431 ok(lr == EIMES_CANCELCOMPSTRINFOCUS, "Got unexpected lr %#Ix.\n", lr);
13433 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_COMPLETECOMPSTRKILLFOCUS);
13434 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
13435 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
13436 ok(lr == EIMES_COMPLETECOMPSTRKILLFOCUS, "Got unexpected lr %#Ix.\n", lr);
13438 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_GETCOMPSTRATONCE
13439 | EIMES_CANCELCOMPSTRINFOCUS | EIMES_COMPLETECOMPSTRKILLFOCUS);
13440 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
13441 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
13442 ok(lr == (EIMES_GETCOMPSTRATONCE | EIMES_CANCELCOMPSTRINFOCUS | EIMES_COMPLETECOMPSTRKILLFOCUS),
13443 "Got unexpected lr %#Ix.\n", lr);
13445 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
13446 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
13447 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
13448 ok(lr == 0, "Got unexpected lr %#Ix.\n", lr);
13450 /* Invalid EM_{GET|SET}IMESTATUS status types and flags */
13451 lr = SendMessageA(hwnd, EM_GETIMESTATUS, 0, 0);
13452 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
13454 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING + 1, 0);
13455 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
13457 lr = SendMessageA(hwnd, EM_SETIMESTATUS, 0, EIMES_GETCOMPSTRATONCE);
13458 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
13459 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
13460 ok(lr == 0, "Got unexpected lr %#Ix.\n", lr);
13462 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING + 1, EIMES_GETCOMPSTRATONCE);
13463 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
13464 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
13465 ok(lr == 0, "Got unexpected lr %#Ix.\n", lr);
13467 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0xFFFFFFFF);
13468 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
13469 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
13470 ok(lr == 0xFFFF, "Got unexpected lr %#Ix.\n", lr);
13472 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
13473 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
13474 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
13475 ok(lr == 0, "Got unexpected lr %#Ix.\n", lr);
13477 /* Test IME messages when EIMES_GETCOMPSTRATONCE is not set */
13478 old_proc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)edit_ime_subclass_proc);
13479 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)old_proc);
13481 himc = ImmGetContext(hwnd);
13482 ret = ImmSetCompositionStringA(himc, SCS_SETSTR, "Wine", 4, NULL, 0);
13483 ok(ret, "ImmSetCompositionStringA failed.\n");
13484 flush_sequence();
13485 ret = ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
13486 ok(ret, "ImmNotifyIME failed.\n");
13487 /* Note that the following message loop is necessary to get the WM_CHAR messages because they
13488 * are posted. Same for the later message loops in this function. */
13489 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
13490 if (hkl == korean_hkl)
13491 ok_sequence(edit_wm_ime_composition_korean_seq,
13492 "korean WM_IME_COMPOSITION", TRUE);
13493 else
13494 ok_sequence(edit_wm_ime_composition_seq, "WM_IME_COMPOSITION", TRUE);
13496 /* Test that WM_IME_CHAR is passed to DefWindowProc() to get WM_CHAR */
13497 flush_sequence();
13498 SendMessageA(hwnd, WM_IME_CHAR, '0', 1);
13499 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
13500 ok_sequence(edit_wm_ime_char_seq, "WM_IME_CHAR", FALSE);
13502 /* Test IME messages when EIMES_GETCOMPSTRATONCE is set */
13503 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_GETCOMPSTRATONCE);
13504 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
13505 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
13506 ok(lr == EIMES_GETCOMPSTRATONCE, "Got unexpected lr %#Ix.\n", lr);
13508 ret = ImmSetCompositionStringA(himc, SCS_SETSTR, "Wine", 4, NULL, 0);
13509 ok(ret, "ImmSetCompositionStringA failed.\n");
13510 flush_sequence();
13511 ret = ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
13512 ok(ret, "ImmNotifyIME failed.\n");
13513 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
13514 if (hkl == korean_hkl)
13515 ok_sequence(edit_eimes_getcompstratonce_korean_seq,
13516 "korean WM_IME_COMPOSITION with EIMES_GETCOMPSTRATONCE", TRUE);
13517 else
13518 ok_sequence(edit_eimes_getcompstratonce_seq,
13519 "WM_IME_COMPOSITION with EIMES_GETCOMPSTRATONCE", TRUE);
13521 /* Test that WM_IME_CHAR is passed to DefWindowProc() to get WM_CHAR with EIMES_GETCOMPSTRATONCE */
13522 flush_sequence();
13523 SendMessageA(hwnd, WM_IME_CHAR, '0', 1);
13524 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
13525 ok_sequence(edit_wm_ime_char_seq, "WM_IME_CHAR", FALSE);
13527 ImmReleaseContext(hwnd, himc);
13528 DestroyWindow(hwnd);
13529 return 0;
13532 static void subclass_edit(void)
13534 WNDCLASSA cls;
13535 BOOL ret;
13537 ret = GetClassInfoA(0, "edit", &cls);
13538 ok(ret, "Failed to get class info, error %lu.\n", GetLastError());
13540 old_edit_proc = cls.lpfnWndProc;
13542 cls.hInstance = GetModuleHandleA(NULL);
13543 cls.lpfnWndProc = edit_hook_proc;
13544 cls.lpszClassName = "my_edit_class";
13545 UnregisterClassA(cls.lpszClassName, cls.hInstance);
13546 register_class(&cls);
13549 static void test_edit_messages(void)
13551 HWND hwnd, parent;
13552 DWORD dlg_code;
13553 HANDLE thread;
13555 subclass_edit();
13556 log_all_parent_messages++;
13558 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13559 100, 100, 200, 200, 0, 0, 0, NULL);
13560 ok (parent != 0, "Failed to create parent window\n");
13562 /* test single line edit */
13563 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
13564 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
13565 ok(hwnd != 0, "Failed to create edit window\n");
13567 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
13568 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08lx\n", dlg_code);
13570 flush_sequence();
13571 SetFocus(hwnd);
13572 ok_sequence(sl_edit_invisible, "SetFocus(hwnd) on an invisible edit", FALSE);
13574 ShowWindow(hwnd, SW_SHOW);
13575 UpdateWindow(hwnd);
13576 SetFocus(0);
13577 flush_sequence();
13579 SetFocus(hwnd);
13580 ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
13582 SetFocus(0);
13583 ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
13585 SetFocus(0);
13586 ReleaseCapture();
13587 flush_sequence();
13589 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
13590 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
13592 SetFocus(0);
13593 ReleaseCapture();
13594 flush_sequence();
13596 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
13597 ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
13599 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
13600 ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
13602 DestroyWindow(hwnd);
13604 /* test multiline edit */
13605 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
13606 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
13607 ok(hwnd != 0, "Failed to create edit window\n");
13609 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
13610 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
13611 "wrong dlg_code %08lx\n", dlg_code);
13613 ShowWindow(hwnd, SW_SHOW);
13614 UpdateWindow(hwnd);
13615 SetFocus(0);
13616 flush_sequence();
13618 SetFocus(hwnd);
13619 ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
13621 SetFocus(0);
13622 ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
13624 SetFocus(0);
13625 ReleaseCapture();
13626 flush_sequence();
13628 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
13629 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
13631 SetFocus(0);
13632 ReleaseCapture();
13633 flush_sequence();
13635 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
13636 ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
13638 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
13639 ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
13641 DestroyWindow(hwnd);
13642 DestroyWindow(parent);
13644 log_all_parent_messages--;
13646 /* Test IME messages in another thread because IME is disabled in the current thread */
13647 thread = CreateThread(NULL, 0, test_edit_ime_messages, NULL, 0, NULL);
13648 WaitForSingleObject(thread, INFINITE);
13649 CloseHandle(thread);
13652 /**************************** End of Edit test ******************************/
13654 static const struct message WmKeyDownSkippedSeq[] =
13656 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
13657 { 0 }
13659 static const struct message WmKeyDownWasDownSkippedSeq[] =
13661 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x40000001 }, /* XP */
13662 { 0 }
13664 static const struct message WmKeyUpSkippedSeq[] =
13666 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
13667 { 0 }
13669 static const struct message WmUserKeyUpSkippedSeq[] =
13671 { WM_USER, sent },
13672 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
13673 { 0 }
13676 #define EV_STOP 0
13677 #define EV_SENDMSG 1
13678 #define EV_ACK 2
13680 struct peekmsg_info
13682 HWND hwnd;
13683 HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
13686 static DWORD CALLBACK send_msg_thread_2(void *param)
13688 DWORD ret;
13689 struct peekmsg_info *info = param;
13691 if (winetest_debug > 1) trace("thread: looping\n");
13692 SetEvent(info->hevent[EV_ACK]);
13694 while (1)
13696 ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
13698 switch (ret)
13700 case WAIT_OBJECT_0 + EV_STOP:
13701 if (winetest_debug > 1) trace("thread: exiting\n");
13702 return 0;
13704 case WAIT_OBJECT_0 + EV_SENDMSG:
13705 if (winetest_debug > 1) trace("thread: sending message\n");
13706 ret = SendNotifyMessageA(info->hwnd, WM_USER, 0, 0);
13707 ok(ret, "SendNotifyMessageA failed error %lu\n", GetLastError());
13708 SetEvent(info->hevent[EV_ACK]);
13709 break;
13711 default:
13712 ok(0, "Unexpected return %#lx.\n", ret);
13713 break;
13716 return 0;
13719 static void test_PeekMessage(void)
13721 MSG msg;
13722 HANDLE hthread;
13723 DWORD tid, qstatus;
13724 UINT qs_all_input = QS_ALLINPUT;
13725 UINT qs_input = QS_INPUT;
13726 BOOL ret, broken_flags = FALSE;
13727 struct peekmsg_info info;
13729 info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
13730 100, 100, 200, 200, 0, 0, 0, NULL);
13731 ok(!!info.hwnd, "Failed to create window, error %lu.\n", GetLastError());
13732 ShowWindow(info.hwnd, SW_SHOW);
13733 UpdateWindow(info.hwnd);
13734 SetFocus(info.hwnd);
13736 info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
13737 info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
13738 info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
13740 hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
13741 WaitForSingleObject(info.hevent[EV_ACK], 10000);
13743 flush_events();
13744 flush_sequence();
13746 SetLastError(0xdeadbeef);
13747 qstatus = GetQueueStatus(qs_all_input);
13748 if (GetLastError() == ERROR_INVALID_FLAGS)
13750 trace("QS_RAWINPUT not supported on this platform\n");
13751 qs_all_input &= ~QS_RAWINPUT;
13752 qs_input &= ~QS_RAWINPUT;
13754 SetLastError(0xdeadbeef);
13755 qstatus = GetQueueStatus(qs_all_input);
13756 if (GetLastError() == ERROR_INVALID_FLAGS)
13757 broken_flags = TRUE;
13758 ok(GetLastError() == 0xdeadbeef || broken(GetLastError() == ERROR_INVALID_FLAGS) /* win7 */,
13759 "wrong error %ld\n", GetLastError());
13761 if (qstatus & QS_POSTMESSAGE)
13763 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) /* nothing */ ;
13764 qstatus = GetQueueStatus(qs_all_input);
13766 ok(qstatus == 0, "wrong qstatus %08lx\n", qstatus);
13768 if (winetest_debug > 1) trace("signalling to send message\n");
13769 SetEvent(info.hevent[EV_SENDMSG]);
13770 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
13772 /* pass invalid QS_xxxx flags */
13773 SetLastError(0xdeadbeef);
13774 qstatus = GetQueueStatus(0xffffffff);
13775 ok(qstatus == 0 || broken(qstatus) /* win9x */, "GetQueueStatus should fail: %08lx\n", qstatus);
13776 if (!qstatus)
13778 ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %ld\n", GetLastError());
13779 SetLastError(0xdeadbeef);
13780 qstatus = GetQueueStatus(qs_all_input);
13781 ok(GetLastError() == 0xdeadbeef || broken(broken_flags && GetLastError() == ERROR_INVALID_FLAGS),
13782 "wrong error %ld\n", GetLastError());
13784 qstatus &= ~MAKELONG( 0x4000, 0x4000 ); /* sometimes set on Win95 */
13785 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE) ||
13786 broken(broken_flags && qstatus == 0),
13787 "wrong qstatus %08lx\n", qstatus);
13789 msg.message = 0;
13790 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
13791 ok(!ret,
13792 "PeekMessageA should have returned FALSE instead of msg %04x\n",
13793 msg.message);
13794 ok_sequence(WmUser, "WmUser", FALSE);
13796 qstatus = GetQueueStatus(qs_all_input);
13797 ok(qstatus == 0, "wrong qstatus %08lx\n", qstatus);
13799 keybd_event('N', 0, 0, 0);
13800 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
13801 qstatus = GetQueueStatus(qs_all_input);
13802 if (!(qstatus & MAKELONG(QS_KEY, QS_KEY)))
13804 skip( "queuing key events not supported\n" );
13805 goto done;
13807 ok(qstatus == MAKELONG(QS_KEY, QS_KEY) ||
13808 /* keybd_event seems to trigger a sent message on NT4 */
13809 qstatus == MAKELONG(QS_KEY|QS_SENDMESSAGE, QS_KEY|QS_SENDMESSAGE),
13810 "wrong qstatus %08lx\n", qstatus);
13812 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
13813 qstatus = GetQueueStatus(qs_all_input);
13814 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY) ||
13815 qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
13816 "wrong qstatus %08lx\n", qstatus);
13818 InvalidateRect(info.hwnd, NULL, FALSE);
13819 qstatus = GetQueueStatus(qs_all_input);
13820 ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY) ||
13821 qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
13822 "wrong qstatus %08lx\n", qstatus);
13824 if (winetest_debug > 1) trace("signalling to send message\n");
13825 SetEvent(info.hevent[EV_SENDMSG]);
13826 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
13828 qstatus = GetQueueStatus(qs_all_input);
13829 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
13830 "wrong qstatus %08lx\n", qstatus);
13832 msg.message = 0;
13833 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
13834 if (ret && msg.message == WM_CHAR)
13836 win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
13837 goto done;
13839 ok(!ret,
13840 "PeekMessageA should have returned FALSE instead of msg %04x\n",
13841 msg.message);
13842 if (!sequence_cnt) /* nt4 doesn't fetch anything with PM_QS_* flags */
13844 win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
13845 goto done;
13847 ok_sequence(WmUser, "WmUser", FALSE);
13849 qstatus = GetQueueStatus(qs_all_input);
13850 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
13851 "wrong qstatus %08lx\n", qstatus);
13853 if (winetest_debug > 1) trace("signalling to send message\n");
13854 SetEvent(info.hevent[EV_SENDMSG]);
13855 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
13857 qstatus = GetQueueStatus(qs_all_input);
13858 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
13859 "wrong qstatus %08lx\n", qstatus);
13861 msg.message = 0;
13862 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE );
13863 ok(!ret,
13864 "PeekMessageA should have returned FALSE instead of msg %04x\n",
13865 msg.message);
13866 ok_sequence(WmUser, "WmUser", FALSE);
13868 qstatus = GetQueueStatus(qs_all_input);
13869 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
13870 "wrong qstatus %08lx\n", qstatus);
13872 msg.message = 0;
13873 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
13874 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
13875 "got %d and %04x wParam %08Ix instead of TRUE and WM_CHAR wParam 'z'\n",
13876 ret, msg.message, msg.wParam);
13877 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
13879 qstatus = GetQueueStatus(qs_all_input);
13880 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
13881 "wrong qstatus %08lx\n", qstatus);
13883 msg.message = 0;
13884 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
13885 ok(!ret,
13886 "PeekMessageA should have returned FALSE instead of msg %04x\n",
13887 msg.message);
13888 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
13890 qstatus = GetQueueStatus(qs_all_input);
13891 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
13892 "wrong qstatus %08lx\n", qstatus);
13894 msg.message = 0;
13895 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
13896 ok(ret && msg.message == WM_PAINT,
13897 "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
13898 DispatchMessageA(&msg);
13899 ok_sequence(WmPaint, "WmPaint", FALSE);
13901 qstatus = GetQueueStatus(qs_all_input);
13902 ok(qstatus == MAKELONG(0, QS_KEY),
13903 "wrong qstatus %08lx\n", qstatus);
13905 msg.message = 0;
13906 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
13907 ok(!ret,
13908 "PeekMessageA should have returned FALSE instead of msg %04x\n",
13909 msg.message);
13910 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
13912 qstatus = GetQueueStatus(qs_all_input);
13913 ok(qstatus == MAKELONG(0, QS_KEY),
13914 "wrong qstatus %08lx\n", qstatus);
13916 if (winetest_debug > 1) trace("signalling to send message\n");
13917 SetEvent(info.hevent[EV_SENDMSG]);
13918 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
13920 qstatus = GetQueueStatus(qs_all_input);
13921 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
13922 "wrong qstatus %08lx\n", qstatus);
13924 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
13926 qstatus = GetQueueStatus(qs_all_input);
13927 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
13928 "wrong qstatus %08lx\n", qstatus);
13930 msg.message = 0;
13931 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
13932 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
13933 "got %d and %04x wParam %08Ix instead of TRUE and WM_CHAR wParam 'z'\n",
13934 ret, msg.message, msg.wParam);
13935 ok_sequence(WmUser, "WmUser", FALSE);
13937 qstatus = GetQueueStatus(qs_all_input);
13938 ok(qstatus == MAKELONG(0, QS_KEY),
13939 "wrong qstatus %08lx\n", qstatus);
13941 msg.message = 0;
13942 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
13943 ok(!ret,
13944 "PeekMessageA should have returned FALSE instead of msg %04x\n",
13945 msg.message);
13946 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
13948 qstatus = GetQueueStatus(qs_all_input);
13949 ok(qstatus == MAKELONG(0, QS_KEY),
13950 "wrong qstatus %08lx\n", qstatus);
13952 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
13954 qstatus = GetQueueStatus(qs_all_input);
13955 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
13956 "wrong qstatus %08lx\n", qstatus);
13958 if (winetest_debug > 1) trace("signalling to send message\n");
13959 SetEvent(info.hevent[EV_SENDMSG]);
13960 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
13962 qstatus = GetQueueStatus(qs_all_input);
13963 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
13964 "wrong qstatus %08lx\n", qstatus);
13966 msg.message = 0;
13967 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
13968 ok(!ret,
13969 "PeekMessageA should have returned FALSE instead of msg %04x\n",
13970 msg.message);
13971 ok_sequence(WmUser, "WmUser", FALSE);
13973 qstatus = GetQueueStatus(qs_all_input);
13974 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
13975 "wrong qstatus %08lx\n", qstatus);
13977 msg.message = 0;
13978 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
13979 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
13980 else /* workaround for a missing QS_RAWINPUT support */
13981 ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
13982 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
13983 "got %d and %04x wParam %08Ix instead of TRUE and WM_KEYDOWN wParam 'N'\n",
13984 ret, msg.message, msg.wParam);
13985 ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
13987 qstatus = GetQueueStatus(qs_all_input);
13988 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
13989 "wrong qstatus %08lx\n", qstatus);
13991 msg.message = 0;
13992 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
13993 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
13994 else /* workaround for a missing QS_RAWINPUT support */
13995 ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
13996 ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
13997 "got %d and %04x wParam %08Ix instead of TRUE and WM_KEYUP wParam 'N'\n",
13998 ret, msg.message, msg.wParam);
13999 ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
14001 qstatus = GetQueueStatus(qs_all_input);
14002 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
14003 "wrong qstatus %08lx\n", qstatus);
14005 msg.message = 0;
14006 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
14007 ok(!ret,
14008 "PeekMessageA should have returned FALSE instead of msg %04x\n",
14009 msg.message);
14010 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
14012 qstatus = GetQueueStatus(qs_all_input);
14013 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
14014 "wrong qstatus %08lx\n", qstatus);
14016 msg.message = 0;
14017 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
14018 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
14019 "got %d and %04x wParam %08Ix instead of TRUE and WM_CHAR wParam 'z'\n",
14020 ret, msg.message, msg.wParam);
14021 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
14023 qstatus = GetQueueStatus(qs_all_input);
14024 ok(qstatus == 0,
14025 "wrong qstatus %08lx\n", qstatus);
14027 msg.message = 0;
14028 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
14029 ok(!ret,
14030 "PeekMessageA should have returned FALSE instead of msg %04x\n",
14031 msg.message);
14032 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
14034 qstatus = GetQueueStatus(qs_all_input);
14035 ok(qstatus == 0,
14036 "wrong qstatus %08lx\n", qstatus);
14038 /* test whether presence of the quit flag in the queue affects
14039 * the queue state
14041 PostQuitMessage(0x1234abcd);
14043 qstatus = GetQueueStatus(qs_all_input);
14044 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
14045 "wrong qstatus %08lx\n", qstatus);
14047 PostMessageA(info.hwnd, WM_USER, 0, 0);
14049 qstatus = GetQueueStatus(qs_all_input);
14050 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
14051 "wrong qstatus %08lx\n", qstatus);
14053 msg.message = 0;
14054 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
14055 ok(ret && msg.message == WM_USER,
14056 "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
14057 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
14059 qstatus = GetQueueStatus(qs_all_input);
14060 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
14061 "wrong qstatus %08lx\n", qstatus);
14063 msg.message = 0;
14064 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
14065 ok(ret && msg.message == WM_QUIT,
14066 "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
14067 ok(msg.wParam == 0x1234abcd, "got wParam %08Ix instead of 0x1234abcd\n", msg.wParam);
14068 ok(msg.lParam == 0, "got lParam %08Ix instead of 0\n", msg.lParam);
14069 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
14071 qstatus = GetQueueStatus(qs_all_input);
14072 todo_wine {
14073 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
14074 "wrong qstatus %08lx\n", qstatus);
14077 msg.message = 0;
14078 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
14079 ok(!ret,
14080 "PeekMessageA should have returned FALSE instead of msg %04x\n",
14081 msg.message);
14082 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
14084 qstatus = GetQueueStatus(qs_all_input);
14085 ok(qstatus == 0,
14086 "wrong qstatus %08lx\n", qstatus);
14088 /* some GetMessage tests */
14090 keybd_event('N', 0, 0, 0);
14091 qstatus = GetQueueStatus(qs_all_input);
14092 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08lx\n", qstatus);
14094 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
14095 qstatus = GetQueueStatus(qs_all_input);
14096 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08lx\n", qstatus);
14098 if (qstatus)
14100 ret = GetMessageA( &msg, 0, 0, 0 );
14101 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
14102 "got %d and %04x wParam %08Ix instead of TRUE and WM_CHAR wParam 'z'\n",
14103 ret, msg.message, msg.wParam);
14104 qstatus = GetQueueStatus(qs_all_input);
14105 ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08lx\n", qstatus);
14108 if (qstatus)
14110 ret = GetMessageA( &msg, 0, 0, 0 );
14111 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
14112 "got %d and %04x wParam %08Ix instead of TRUE and WM_KEYDOWN wParam 'N'\n",
14113 ret, msg.message, msg.wParam);
14114 ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
14115 qstatus = GetQueueStatus(qs_all_input);
14116 ok(qstatus == 0, "wrong qstatus %08lx\n", qstatus);
14119 keybd_event('N', 0, 0, 0);
14120 qstatus = GetQueueStatus(qs_all_input);
14121 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08lx\n", qstatus);
14123 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
14124 qstatus = GetQueueStatus(qs_all_input);
14125 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08lx\n", qstatus);
14127 if (qstatus & (QS_KEY << 16))
14129 ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
14130 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
14131 "got %d and %04x wParam %08Ix instead of TRUE and WM_KEYDOWN wParam 'N'\n",
14132 ret, msg.message, msg.wParam);
14133 ok_sequence(WmKeyDownWasDownSkippedSeq, "WmKeyDownWasDownSkippedSeq", FALSE);
14134 qstatus = GetQueueStatus(qs_all_input);
14135 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08lx\n", qstatus);
14138 if (qstatus)
14140 ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
14141 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
14142 "got %d and %04x wParam %08Ix instead of TRUE and WM_CHAR wParam 'z'\n",
14143 ret, msg.message, msg.wParam);
14144 qstatus = GetQueueStatus(qs_all_input);
14145 ok(qstatus == 0, "wrong qstatus %08lx\n", qstatus);
14148 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
14149 qstatus = GetQueueStatus(qs_all_input);
14150 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08lx\n", qstatus);
14152 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
14153 qstatus = GetQueueStatus(qs_all_input);
14154 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08lx\n", qstatus);
14156 if (winetest_debug > 1) trace("signalling to send message\n");
14157 SetEvent(info.hevent[EV_SENDMSG]);
14158 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
14159 qstatus = GetQueueStatus(qs_all_input);
14160 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
14161 "wrong qstatus %08lx\n", qstatus);
14163 if (qstatus & (QS_KEY << 16))
14165 ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
14166 ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
14167 "got %d and %04x wParam %08Ix instead of TRUE and WM_KEYDOWN wParam 'N'\n",
14168 ret, msg.message, msg.wParam);
14169 ok_sequence(WmUserKeyUpSkippedSeq, "WmUserKeyUpSkippedSeq", FALSE);
14170 qstatus = GetQueueStatus(qs_all_input);
14171 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08lx\n", qstatus);
14174 if (qstatus)
14176 ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
14177 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
14178 "got %d and %04x wParam %08Ix instead of TRUE and WM_CHAR wParam 'z'\n",
14179 ret, msg.message, msg.wParam);
14180 qstatus = GetQueueStatus(qs_all_input);
14181 ok(qstatus == 0, "wrong qstatus %08lx\n", qstatus);
14184 PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
14185 ret = PeekMessageA(&msg, (HWND)-1, 0, 0, PM_NOREMOVE);
14186 ok(ret == TRUE, "wrong ret %d\n", ret);
14187 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
14188 ret = GetMessageA(&msg, (HWND)-1, 0, 0);
14189 ok(ret == TRUE, "wrong ret %d\n", ret);
14190 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
14192 PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
14193 ret = PeekMessageA(&msg, (HWND)1, 0, 0, PM_NOREMOVE);
14194 ok(ret == TRUE, "wrong ret %d\n", ret);
14195 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
14196 ret = GetMessageA(&msg, (HWND)1, 0, 0);
14197 ok(ret == TRUE, "wrong ret %d\n", ret);
14198 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
14200 PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
14201 ret = PeekMessageA(&msg, (HWND)0xffff, 0, 0, PM_NOREMOVE);
14202 ok(ret == TRUE, "wrong ret %d\n", ret);
14203 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
14204 ret = GetMessageA(&msg, (HWND)0xffff, 0, 0);
14205 ok(ret == TRUE, "wrong ret %d\n", ret);
14206 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
14208 done:
14209 if (winetest_debug > 1) trace("signalling to exit\n");
14210 SetEvent(info.hevent[EV_STOP]);
14212 WaitForSingleObject(hthread, INFINITE);
14214 CloseHandle(hthread);
14215 CloseHandle(info.hevent[0]);
14216 CloseHandle(info.hevent[1]);
14217 CloseHandle(info.hevent[2]);
14219 DestroyWindow(info.hwnd);
14222 static void wait_move_event(HWND hwnd, int x, int y)
14224 MSG msg;
14225 DWORD timeout = GetTickCount() + 500;
14226 BOOL ret;
14227 int delay;
14229 while ((delay = timeout - GetTickCount()) > 0)
14231 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
14232 if (ret && msg.pt.x > x && msg.pt.y > y) break;
14233 if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, delay, QS_ALLINPUT );
14234 else Sleep( delay );
14238 #define STEP 5
14239 static void test_PeekMessage2(void)
14241 HWND hwnd;
14242 BOOL ret;
14243 MSG msg;
14244 UINT message;
14245 DWORD time1, time2, time3;
14246 int x1, y1, x2, y2, x3, y3;
14247 POINT pos;
14249 time1 = time2 = time3 = 0;
14250 x1 = y1 = x2 = y2 = x3 = y3 = 0;
14252 /* Initialise window and make sure it is ready for events */
14253 hwnd = CreateWindowA("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
14254 10, 10, 800, 800, NULL, NULL, NULL, NULL);
14255 ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError());
14256 if (winetest_debug > 1) trace("Window for test_PeekMessage2 %p\n", hwnd);
14257 ShowWindow(hwnd, SW_SHOW);
14258 UpdateWindow(hwnd);
14259 SetFocus(hwnd);
14260 GetCursorPos(&pos);
14261 SetCursorPos(100, 100);
14262 mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
14263 flush_events();
14265 /* Do initial mousemove, wait until we can see it
14266 and then do our test peek with PM_NOREMOVE. */
14267 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
14268 wait_move_event(hwnd, 100-STEP, 100-STEP);
14270 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
14271 if (!ret)
14273 skip( "queuing mouse events not supported\n" );
14274 goto done;
14276 else
14278 if (winetest_debug > 1) trace("1st move event: %04x %lx %ld %ld\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
14279 message = msg.message;
14280 time1 = msg.time;
14281 x1 = msg.pt.x;
14282 y1 = msg.pt.y;
14283 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
14286 /* Allow time to advance a bit, and then simulate the user moving their
14287 * mouse around. After that we peek again with PM_NOREMOVE.
14288 * Although the previous mousemove message was never removed, the
14289 * mousemove we now peek should reflect the recent mouse movements
14290 * because the input queue will merge the move events. */
14291 Sleep(100);
14292 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
14293 wait_move_event(hwnd, x1, y1);
14295 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
14296 ok(ret, "no message available\n");
14297 if (ret) {
14298 if (winetest_debug > 1) trace("2nd move event: %04x %lx %ld %ld\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
14299 message = msg.message;
14300 time2 = msg.time;
14301 x2 = msg.pt.x;
14302 y2 = msg.pt.y;
14303 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
14304 ok(time2 > time1, "message time not advanced: %lx %lx\n", time1, time2);
14305 ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
14308 /* Have another go, to drive the point home */
14309 Sleep(100);
14310 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
14311 wait_move_event(hwnd, x2, y2);
14313 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
14314 ok(ret, "no message available\n");
14315 if (ret) {
14316 if (winetest_debug > 1) trace("3rd move event: %04x %lx %ld %ld\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
14317 message = msg.message;
14318 time3 = msg.time;
14319 x3 = msg.pt.x;
14320 y3 = msg.pt.y;
14321 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
14322 ok(time3 > time2, "message time not advanced: %lx %lx\n", time2, time3);
14323 ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
14326 done:
14327 DestroyWindow(hwnd);
14328 SetCursorPos(pos.x, pos.y);
14329 flush_events();
14332 static void test_PeekMessage3(void)
14334 HWND parent_hwnd, hwnd;
14335 BOOL ret;
14336 MSG msg;
14338 parent_hwnd = CreateWindowA("SimpleWindowClass", "PeekMessage3", WS_OVERLAPPEDWINDOW,
14339 10, 10, 800, 800, NULL, NULL, NULL, NULL);
14340 ok(parent_hwnd != NULL, "expected parent_hwnd != NULL\n");
14342 hwnd = CreateWindowA("TestWindowClass", "PeekMessage3", WS_CHILD, 0, 0, 1, 1,
14343 parent_hwnd, NULL, NULL, NULL);
14344 ok(hwnd != NULL, "expected hwnd != NULL\n");
14346 flush_events();
14348 /* GetMessage() and PeekMessage(..., PM_REMOVE) should prefer messages which
14349 * were already seen. */
14351 SetTimer(hwnd, 1, 100, NULL);
14352 while (!PeekMessageA(&msg, hwnd, 0, 0, PM_NOREMOVE));
14353 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14354 PostMessageA(hwnd, WM_USER, 0, 0);
14355 ret = PeekMessageA(&msg, hwnd, 0, 0, PM_NOREMOVE);
14356 todo_wine
14357 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14358 ret = GetMessageA(&msg, hwnd, 0, 0);
14359 todo_wine
14360 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14361 ret = GetMessageA(&msg, hwnd, 0, 0);
14362 todo_wine
14363 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
14364 ret = PeekMessageA(&msg, hwnd, 0, 0, 0);
14365 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
14367 SetTimer(hwnd, 1, 100, NULL);
14368 while (!PeekMessageA(&msg, hwnd, 0, 0, PM_NOREMOVE));
14369 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14370 PostMessageA(hwnd, WM_USER, 0, 0);
14371 ret = PeekMessageA(&msg, hwnd, 0, 0, PM_REMOVE);
14372 todo_wine
14373 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14374 ret = PeekMessageA(&msg, hwnd, 0, 0, PM_REMOVE);
14375 todo_wine
14376 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
14377 ret = PeekMessageA(&msg, hwnd, 0, 0, 0);
14378 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
14380 /* It doesn't matter if a message range is specified or not. */
14382 SetTimer(hwnd, 1, 100, NULL);
14383 while (!PeekMessageA(&msg, hwnd, WM_TIMER, WM_TIMER, PM_NOREMOVE));
14384 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14385 PostMessageA(hwnd, WM_USER, 0, 0);
14386 ret = GetMessageA(&msg, hwnd, 0, 0);
14387 todo_wine
14388 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14389 ret = GetMessageA(&msg, hwnd, 0, 0);
14390 todo_wine
14391 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
14392 ret = PeekMessageA(&msg, hwnd, 0, 0, 0);
14393 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
14395 /* But not if the post messages were added before the PeekMessage() call. */
14397 PostMessageA(hwnd, WM_USER, 0, 0);
14398 SetTimer(hwnd, 1, 100, NULL);
14399 while (!PeekMessageA(&msg, hwnd, WM_TIMER, WM_TIMER, PM_NOREMOVE));
14400 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14401 ret = GetMessageA(&msg, hwnd, 0, 0);
14402 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
14403 ret = GetMessageA(&msg, hwnd, 0, 0);
14404 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14405 ret = PeekMessageA(&msg, hwnd, 0, 0, 0);
14406 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
14408 /* More complicated test with multiple messages. */
14410 PostMessageA(hwnd, WM_USER, 0, 0);
14411 SetTimer(hwnd, 1, 100, NULL);
14412 while (!PeekMessageA(&msg, hwnd, WM_TIMER, WM_TIMER, PM_NOREMOVE));
14413 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14414 PostMessageA(hwnd, WM_USER + 1, 0, 0);
14415 ret = GetMessageA(&msg, hwnd, 0, 0);
14416 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
14417 ret = GetMessageA(&msg, hwnd, 0, 0);
14418 todo_wine
14419 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14420 ret = GetMessageA(&msg, hwnd, 0, 0);
14421 todo_wine
14422 ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message);
14423 ret = PeekMessageA(&msg, hwnd, 0, 0, 0);
14424 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
14426 /* Also works for posted messages, but the situation is a bit different,
14427 * because both messages are in the same queue. */
14429 PostMessageA(hwnd, WM_TIMER, 0, 0);
14430 while (!PeekMessageA(&msg, hwnd, WM_TIMER, WM_TIMER, PM_NOREMOVE));
14431 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14432 PostMessageA(hwnd, WM_USER, 0, 0);
14433 ret = GetMessageA(&msg, hwnd, 0, 0);
14434 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14435 ret = GetMessageA(&msg, hwnd, 0, 0);
14436 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
14437 ret = PeekMessageA(&msg, hwnd, 0, 0, 0);
14438 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
14440 PostMessageA(hwnd, WM_USER, 0, 0);
14441 PostMessageA(hwnd, WM_TIMER, 0, 0);
14442 while (!PeekMessageA(&msg, hwnd, WM_TIMER, WM_TIMER, PM_NOREMOVE));
14443 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14444 ret = GetMessageA(&msg, hwnd, 0, 0);
14445 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
14446 ret = GetMessageA(&msg, hwnd, 0, 0);
14447 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14448 ret = PeekMessageA(&msg, hwnd, 0, 0, 0);
14449 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
14451 DestroyWindow(parent_hwnd);
14452 flush_events();
14455 static INT_PTR CALLBACK wm_quit_dlg_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
14457 struct recvd_message msg;
14459 if (ignore_message( message )) return 0;
14461 msg.hwnd = hwnd;
14462 msg.message = message;
14463 msg.flags = sent|wparam|lparam;
14464 msg.wParam = wp;
14465 msg.lParam = lp;
14466 msg.descr = "dialog";
14467 add_message(&msg);
14469 switch (message)
14471 case WM_INITDIALOG:
14472 PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
14473 PostMessageA(hwnd, WM_USER, 0xdead, 0xbeef);
14474 return 0;
14476 case WM_GETDLGCODE:
14477 return 0;
14479 case WM_USER:
14480 EndDialog(hwnd, 0);
14481 break;
14484 return 1;
14487 static const struct message WmQuitDialogSeq[] = {
14488 { HCBT_CREATEWND, hook },
14489 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
14490 { WM_SETFONT, sent },
14491 { WM_INITDIALOG, sent },
14492 { WM_CHANGEUISTATE, sent|optional },
14493 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
14494 { HCBT_DESTROYWND, hook },
14495 { 0x0090, sent|optional }, /* Vista */
14496 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
14497 { WM_DESTROY, sent },
14498 { WM_NCDESTROY, sent },
14499 { 0 }
14502 static const struct message WmStopQuitSeq[] = {
14503 { WM_DWMNCRENDERINGCHANGED, posted|optional },
14504 { WM_CLOSE, posted },
14505 { WM_QUIT, posted|wparam|lparam, 0x1234, 0 },
14506 { 0 }
14509 static void test_quit_message(void)
14511 MSG msg;
14512 BOOL ret;
14514 /* test using PostQuitMessage */
14515 flush_events();
14516 PostQuitMessage(0xbeef);
14518 msg.message = 0;
14519 ret = PeekMessageA(&msg, 0, 0, 0, PM_QS_SENDMESSAGE);
14520 ok(!ret, "got %x message\n", msg.message);
14522 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
14523 ok(ret, "PeekMessage failed with error %ld\n", GetLastError());
14524 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
14525 ok(msg.wParam == 0xbeef, "wParam was 0x%Ix instead of 0xbeef\n", msg.wParam);
14527 ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
14528 ok(ret, "PostMessage failed with error %ld\n", GetLastError());
14530 ret = GetMessageA(&msg, NULL, 0, 0);
14531 ok(ret > 0, "GetMessage failed with error %ld\n", GetLastError());
14532 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
14534 /* note: WM_QUIT message received after WM_USER message */
14535 ret = GetMessageA(&msg, NULL, 0, 0);
14536 ok(!ret, "GetMessage return %d with error %ld instead of FALSE\n", ret, GetLastError());
14537 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
14538 ok(msg.wParam == 0xbeef, "wParam was 0x%Ix instead of 0xbeef\n", msg.wParam);
14540 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
14541 ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
14543 /* now test with PostThreadMessage - different behaviour! */
14544 PostThreadMessageA(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
14546 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
14547 ok(ret, "PeekMessage failed with error %ld\n", GetLastError());
14548 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
14549 ok(msg.wParam == 0xdead, "wParam was 0x%Ix instead of 0xdead\n", msg.wParam);
14551 ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
14552 ok(ret, "PostMessage failed with error %ld\n", GetLastError());
14554 /* note: we receive the WM_QUIT message first this time */
14555 ret = GetMessageA(&msg, NULL, 0, 0);
14556 ok(!ret, "GetMessage return %d with error %ld instead of FALSE\n", ret, GetLastError());
14557 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
14558 ok(msg.wParam == 0xdead, "wParam was 0x%Ix instead of 0xdead\n", msg.wParam);
14560 ret = GetMessageA(&msg, NULL, 0, 0);
14561 ok(ret > 0, "GetMessage failed with error %ld\n", GetLastError());
14562 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
14564 flush_events();
14565 flush_sequence();
14566 ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, wm_quit_dlg_proc, 0);
14567 ok(ret == 1, "expected 1, got %d\n", ret);
14568 ok_sequence(WmQuitDialogSeq, "WmQuitDialogSeq", FALSE);
14569 memset(&msg, 0xab, sizeof(msg));
14570 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
14571 ok(ret, "PeekMessage failed\n");
14572 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
14573 ok(msg.wParam == 0x1234, "wParam was 0x%Ix instead of 0x1234\n", msg.wParam);
14574 ok(msg.lParam == 0, "lParam was 0x%Ix instead of 0\n", msg.lParam);
14576 /* Check what happens to a WM_QUIT message posted to a window that gets
14577 * destroyed.
14579 CreateWindowExA(0, "StopQuitClass", "Stop Quit Test", WS_OVERLAPPEDWINDOW,
14580 0, 0, 100, 100, NULL, NULL, NULL, NULL);
14581 flush_sequence();
14582 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
14584 struct recvd_message rmsg;
14585 rmsg.hwnd = msg.hwnd;
14586 rmsg.message = msg.message;
14587 rmsg.flags = posted|wparam|lparam;
14588 rmsg.wParam = msg.wParam;
14589 rmsg.lParam = msg.lParam;
14590 rmsg.descr = "stop/quit";
14591 if (msg.message == WM_QUIT)
14592 /* The hwnd can only be checked here */
14593 ok(!msg.hwnd, "The WM_QUIT hwnd was %p instead of NULL\n", msg.hwnd);
14594 add_message(&rmsg);
14595 DispatchMessageA(&msg);
14597 ok_sequence(WmStopQuitSeq, "WmStopQuitSeq", FALSE);
14600 static const struct message WmNotifySeq[] = {
14601 { WM_NOTIFY, sent|wparam|lparam, 0x1234, 0xdeadbeef },
14602 { 0 }
14605 static void test_notify_message(void)
14607 HWND hwnd;
14608 BOOL ret;
14609 MSG msg;
14611 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
14612 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0, NULL, NULL, 0);
14613 ok(hwnd != 0, "Failed to create window\n");
14614 flush_events();
14615 flush_sequence();
14617 ret = SendNotifyMessageA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
14618 ok(ret == TRUE, "SendNotifyMessageA failed with error %lu\n", GetLastError());
14619 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
14621 ret = SendNotifyMessageW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
14622 ok(ret == TRUE, "SendNotifyMessageW failed with error %lu\n", GetLastError());
14623 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
14625 ret = SendMessageCallbackA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef, NULL, 0);
14626 ok(ret == TRUE, "SendMessageCallbackA failed with error %lu\n", GetLastError());
14627 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
14629 ret = SendMessageCallbackW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef, NULL, 0);
14630 ok(ret == TRUE, "SendMessageCallbackW failed with error %lu\n", GetLastError());
14631 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
14633 ret = PostMessageA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
14634 ok(ret == TRUE, "PostMessageA failed with error %lu\n", GetLastError());
14635 flush_events();
14636 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
14638 ret = PostMessageW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
14639 ok(ret == TRUE, "PostMessageW failed with error %lu\n", GetLastError());
14640 flush_events();
14641 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
14643 ret = PostThreadMessageA(GetCurrentThreadId(), WM_NOTIFY, 0x1234, 0xdeadbeef);
14644 ok(ret == TRUE, "PostThreadMessageA failed with error %lu\n", GetLastError());
14645 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
14647 msg.hwnd = hwnd;
14648 DispatchMessageA(&msg);
14650 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
14652 ret = PostThreadMessageW(GetCurrentThreadId(), WM_NOTIFY, 0x1234, 0xdeadbeef);
14653 ok(ret == TRUE, "PostThreadMessageW failed with error %lu\n", GetLastError());
14654 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
14656 msg.hwnd = hwnd;
14657 DispatchMessageA(&msg);
14659 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
14661 DestroyWindow(hwnd);
14664 static const struct message WmMouseHoverSeq[] = {
14665 { WM_GETMINMAXINFO, sent|optional }, /* sometimes seen on w1064v1809 */
14666 { WM_MOUSEACTIVATE, sent|optional }, /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
14667 { WM_MOUSEACTIVATE, sent|optional },
14668 { WM_TIMER, sent|optional }, /* XP sends it */
14669 { WM_SYSTIMER, sent },
14670 { WM_MOUSEHOVER, sent|wparam, 0 },
14671 { 0 }
14674 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
14676 MSG msg;
14677 DWORD start_ticks, end_ticks;
14679 start_ticks = GetTickCount();
14680 /* add some deviation (50%) to cover not expected delays */
14681 start_ticks += timeout / 2;
14685 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
14687 /* Timer proc messages are not dispatched to the window proc,
14688 * and therefore not logged.
14690 if ((msg.message == WM_TIMER || msg.message == WM_SYSTIMER) && msg.hwnd)
14692 struct recvd_message s_msg;
14694 s_msg.hwnd = msg.hwnd;
14695 s_msg.message = msg.message;
14696 s_msg.flags = sent|wparam|lparam;
14697 s_msg.wParam = msg.wParam;
14698 s_msg.lParam = msg.lParam;
14699 s_msg.descr = "msg_loop";
14700 add_message(&s_msg);
14702 DispatchMessageA(&msg);
14705 end_ticks = GetTickCount();
14707 /* inject WM_MOUSEMOVE to see how it changes tracking */
14708 if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
14710 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
14711 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
14713 inject_mouse_move = FALSE;
14715 } while (start_ticks + timeout >= end_ticks);
14718 static void test_TrackMouseEvent(void)
14720 TRACKMOUSEEVENT tme;
14721 BOOL ret;
14722 HWND hwnd, hchild;
14723 RECT rc_parent, rc_child;
14724 UINT default_hover_time, hover_width = 0, hover_height = 0;
14726 #define track_hover(track_hwnd, track_hover_time) \
14727 tme.cbSize = sizeof(tme); \
14728 tme.dwFlags = TME_HOVER; \
14729 tme.hwndTrack = track_hwnd; \
14730 tme.dwHoverTime = track_hover_time; \
14731 SetLastError(0xdeadbeef); \
14732 ret = pTrackMouseEvent(&tme); \
14733 ok(ret, "TrackMouseEvent(TME_HOVER) error %ld\n", GetLastError())
14735 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
14736 tme.cbSize = sizeof(tme); \
14737 tme.dwFlags = TME_QUERY; \
14738 tme.hwndTrack = (HWND)0xdeadbeef; \
14739 tme.dwHoverTime = 0xdeadbeef; \
14740 SetLastError(0xdeadbeef); \
14741 ret = pTrackMouseEvent(&tme); \
14742 ok(ret, "TrackMouseEvent(TME_QUERY) error %ld\n", GetLastError());\
14743 ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %lu\n", tme.cbSize); \
14744 ok(tme.dwFlags == (expected_track_flags), \
14745 "wrong tme.dwFlags %08lx, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
14746 ok(tme.hwndTrack == (expected_track_hwnd), \
14747 "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
14748 ok(tme.dwHoverTime == (expected_hover_time), \
14749 "wrong tme.dwHoverTime %lu, expected %u\n", tme.dwHoverTime, (expected_hover_time))
14751 #define track_hover_cancel(track_hwnd) \
14752 tme.cbSize = sizeof(tme); \
14753 tme.dwFlags = TME_HOVER | TME_CANCEL; \
14754 tme.hwndTrack = track_hwnd; \
14755 tme.dwHoverTime = 0xdeadbeef; \
14756 SetLastError(0xdeadbeef); \
14757 ret = pTrackMouseEvent(&tme); \
14758 ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %ld\n", GetLastError())
14760 default_hover_time = 0xdeadbeef;
14761 SetLastError(0xdeadbeef);
14762 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
14763 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
14764 "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %lu\n", GetLastError());
14765 if (!ret) default_hover_time = 400;
14766 if (winetest_debug > 1) trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
14768 SetLastError(0xdeadbeef);
14769 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
14770 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
14771 "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %lu\n", GetLastError());
14772 if (!ret) hover_width = 4;
14773 SetLastError(0xdeadbeef);
14774 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
14775 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
14776 "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %lu\n", GetLastError());
14777 if (!ret) hover_height = 4;
14778 if (winetest_debug > 1) trace("hover rect is %u x %d\n", hover_width, hover_height);
14780 hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
14781 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14782 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
14783 NULL, NULL, 0);
14784 ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError());
14786 hchild = CreateWindowExA(0, "TestWindowClass", NULL,
14787 WS_CHILD | WS_BORDER | WS_VISIBLE,
14788 50, 50, 200, 200, hwnd,
14789 NULL, NULL, 0);
14790 ok(!!hchild, "Failed to create window, error %lu.\n", GetLastError());
14792 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
14793 flush_events();
14794 flush_sequence();
14796 tme.cbSize = 0;
14797 tme.dwFlags = TME_QUERY;
14798 tme.hwndTrack = (HWND)0xdeadbeef;
14799 tme.dwHoverTime = 0xdeadbeef;
14800 SetLastError(0xdeadbeef);
14801 ret = pTrackMouseEvent(&tme);
14802 ok(!ret, "TrackMouseEvent should fail\n");
14803 ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
14804 "not expected error %lu\n", GetLastError());
14806 tme.cbSize = sizeof(tme);
14807 tme.dwFlags = TME_HOVER;
14808 tme.hwndTrack = (HWND)0xdeadbeef;
14809 tme.dwHoverTime = 0xdeadbeef;
14810 SetLastError(0xdeadbeef);
14811 ret = pTrackMouseEvent(&tme);
14812 ok(!ret, "TrackMouseEvent should fail\n");
14813 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
14814 "not expected error %lu\n", GetLastError());
14816 tme.cbSize = sizeof(tme);
14817 tme.dwFlags = TME_HOVER | TME_CANCEL;
14818 tme.hwndTrack = (HWND)0xdeadbeef;
14819 tme.dwHoverTime = 0xdeadbeef;
14820 SetLastError(0xdeadbeef);
14821 ret = pTrackMouseEvent(&tme);
14822 ok(!ret, "TrackMouseEvent should fail\n");
14823 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
14824 "not expected error %lu\n", GetLastError());
14826 GetWindowRect(hwnd, &rc_parent);
14827 GetWindowRect(hchild, &rc_child);
14828 SetCursorPos(rc_child.left - 10, rc_child.top - 10);
14830 /* Process messages so that the system updates its internal current
14831 * window and hittest, otherwise TrackMouseEvent calls don't have any
14832 * effect.
14834 flush_events();
14835 flush_sequence();
14837 track_query(0, NULL, 0);
14838 track_hover(hchild, 0);
14839 track_query(0, NULL, 0);
14841 flush_events();
14842 flush_sequence();
14844 track_hover(hwnd, 0);
14845 tme.cbSize = sizeof(tme);
14846 tme.dwFlags = TME_QUERY;
14847 tme.hwndTrack = (HWND)0xdeadbeef;
14848 tme.dwHoverTime = 0xdeadbeef;
14849 SetLastError(0xdeadbeef);
14850 ret = pTrackMouseEvent(&tme);
14851 ok(ret, "TrackMouseEvent(TME_QUERY) error %ld\n", GetLastError());
14852 ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %lu\n", tme.cbSize);
14853 if (!tme.dwFlags)
14855 skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" );
14856 DestroyWindow( hwnd );
14857 return;
14859 ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08lx, expected TME_HOVER\n", tme.dwFlags);
14860 ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd);
14861 ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %lu, expected %u\n",
14862 tme.dwHoverTime, default_hover_time);
14864 pump_msg_loop_timeout(default_hover_time, FALSE);
14865 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
14867 track_query(0, NULL, 0);
14869 track_hover(hwnd, HOVER_DEFAULT);
14870 track_query(TME_HOVER, hwnd, default_hover_time);
14872 Sleep(default_hover_time / 2);
14873 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
14874 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
14876 track_query(TME_HOVER, hwnd, default_hover_time);
14878 pump_msg_loop_timeout(default_hover_time, FALSE);
14879 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
14881 track_query(0, NULL, 0);
14883 track_hover(hwnd, HOVER_DEFAULT);
14884 track_query(TME_HOVER, hwnd, default_hover_time);
14886 pump_msg_loop_timeout(default_hover_time, TRUE);
14887 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
14889 track_query(0, NULL, 0);
14891 track_hover(hwnd, HOVER_DEFAULT);
14892 track_query(TME_HOVER, hwnd, default_hover_time);
14893 track_hover_cancel(hwnd);
14895 DestroyWindow(hwnd);
14897 #undef track_hover
14898 #undef track_query
14899 #undef track_hover_cancel
14903 static const struct message WmSetWindowRgn[] = {
14904 { WM_WINDOWPOSCHANGING, sent|wparam|lparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE
14905 |SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE, 0 },
14906 { WM_NCCALCSIZE, sent|wparam, 1 },
14907 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
14908 { WM_GETTEXT, sent|defwinproc|optional },
14909 { WM_ERASEBKGND, sent|optional },
14910 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
14911 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
14912 { 0 }
14915 static const struct message WmSetWindowRgn_no_redraw[] = {
14916 { WM_WINDOWPOSCHANGING, sent|wparam|lparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE
14917 |SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW, 0 },
14918 { WM_NCCALCSIZE, sent|wparam, 1 },
14919 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
14920 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
14921 { 0 }
14924 static const struct message WmSetWindowRgn_clear[] = {
14925 { WM_WINDOWPOSCHANGING, sent/*|wparam|lparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED
14926 |SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */
14927 /* Some newer Windows versions set window coordinates instead of zeros in WINDOWPOS structure */},
14928 { WM_NCCALCSIZE, sent|wparam, 1 },
14929 { WM_NCPAINT, sent|optional },
14930 { WM_GETTEXT, sent|defwinproc|optional },
14931 { WM_ERASEBKGND, sent },
14932 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
14933 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
14934 { WM_NCPAINT, sent|optional },
14935 { WM_GETTEXT, sent|defwinproc|optional },
14936 { WM_ERASEBKGND, sent|optional },
14937 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
14938 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
14939 { WM_WINDOWPOSCHANGING, sent|optional },
14940 { WM_NCCALCSIZE, sent|optional|wparam, 1 },
14941 { WM_NCPAINT, sent|optional },
14942 { WM_GETTEXT, sent|defwinproc|optional },
14943 { WM_ERASEBKGND, sent|optional },
14944 { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
14945 { WM_NCCALCSIZE, sent|optional|wparam, 1 },
14946 { WM_NCPAINT, sent|optional },
14947 { WM_GETTEXT, sent|defwinproc|optional },
14948 { WM_ERASEBKGND, sent|optional },
14949 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
14950 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not always sent. */
14951 { 0 }
14954 static void test_SetWindowRgn(void)
14956 HRGN hrgn;
14957 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
14958 100, 100, 200, 200, 0, 0, 0, NULL);
14959 ok( hwnd != 0, "Failed to create overlapped window\n" );
14961 ShowWindow( hwnd, SW_SHOW );
14962 UpdateWindow( hwnd );
14963 flush_events();
14964 flush_sequence();
14966 if (winetest_debug > 1) trace("testing SetWindowRgn\n");
14967 hrgn = CreateRectRgn( 0, 0, 150, 150 );
14968 SetWindowRgn( hwnd, hrgn, TRUE );
14969 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
14971 hrgn = CreateRectRgn( 30, 30, 160, 160 );
14972 SetWindowRgn( hwnd, hrgn, FALSE );
14973 ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
14975 hrgn = CreateRectRgn( 0, 0, 180, 180 );
14976 SetWindowRgn( hwnd, hrgn, TRUE );
14977 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
14979 SetWindowRgn( hwnd, 0, TRUE );
14980 ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
14982 DestroyWindow( hwnd );
14985 /*************************** ShowWindow() test ******************************/
14986 static const struct message WmShowNormal[] = {
14987 { WM_SHOWWINDOW, sent|wparam, 1 },
14988 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
14989 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
14990 { HCBT_ACTIVATE, hook },
14991 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
14992 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
14993 { HCBT_SETFOCUS, hook },
14994 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
14995 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14996 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends it, but Win8+ doesn't. */
14997 { 0 }
14999 static const struct message WmShow[] = {
15000 { WM_SHOWWINDOW, sent|wparam, 1 },
15001 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
15002 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
15003 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
15004 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|wine_only, 0, 0 },
15005 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
15006 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
15007 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|wine_only, OBJID_CLIENT, 0 },
15008 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15009 { 0 }
15011 static const struct message WmShowNoActivate_1[] = {
15012 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
15013 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
15014 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
15015 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
15016 { WM_MOVE, sent|defwinproc|optional },
15017 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
15018 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15019 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
15020 { 0 }
15022 static const struct message WmShowNoActivate_2[] = {
15023 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
15024 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
15025 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
15026 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
15027 { HCBT_ACTIVATE, hook|optional },
15028 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends this. */
15029 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
15030 { WM_WINDOWPOSCHANGED, sent|optional }, /* Sometimes sent on Win8+. */
15031 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
15032 { HCBT_SETFOCUS, hook|optional },
15033 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Win7 sends this. */
15034 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
15035 { WM_MOVE, sent|defwinproc },
15036 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
15037 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|wine_only, 0, 0 },
15038 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|wine_only, 0, 0 },
15039 { HCBT_SETFOCUS, hook|optional },
15040 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
15041 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|wine_only, 0, 0 },
15042 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
15043 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15044 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
15045 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
15046 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
15047 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|wine_only, OBJID_CLIENT, 0 },
15048 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
15049 { 0 }
15051 static const struct message WmShowNA_1[] = {
15052 { WM_SHOWWINDOW, sent|wparam, 1 },
15053 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
15054 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
15055 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15056 { 0 }
15058 static const struct message WmShowNA_2[] = {
15059 { WM_SHOWWINDOW, sent|wparam, 1 },
15060 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
15061 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15062 { 0 }
15064 static const struct message WmRestore_1[] = {
15065 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
15066 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
15067 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
15068 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
15069 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
15070 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|wine_only, 0, 0 },
15071 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
15072 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
15073 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|wine_only, OBJID_CLIENT, 0 },
15074 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
15075 { WM_MOVE, sent|defwinproc },
15076 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
15077 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15078 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
15079 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 },
15080 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
15081 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
15082 { 0 }
15084 static const struct message WmRestore_2[] = {
15085 { WM_SHOWWINDOW, sent|wparam, 1 },
15086 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
15087 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
15088 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
15089 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|wine_only, 0, 0 },
15090 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
15091 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
15092 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|wine_only, OBJID_CLIENT, 0 },
15093 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15094 { 0 }
15096 static const struct message WmRestore_3[] = {
15097 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
15098 { WM_GETMINMAXINFO, sent },
15099 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
15100 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
15101 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
15102 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
15103 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
15104 { WM_WINDOWPOSCHANGED, sent|optional }, /* Win8+ sometimes sends this. */
15105 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
15106 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
15107 { WM_WINDOWPOSCHANGED, sent|optional },
15108 { WM_MOVE, sent|defwinproc },
15109 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
15110 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15111 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
15112 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 },
15113 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
15114 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|wine_only, OBJID_CLIENT, 0 },
15115 { 0 }
15117 static const struct message WmRestore_4[] = {
15118 { HCBT_MINMAX, hook|lparam|optional, 0, SW_RESTORE },
15119 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
15120 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
15121 { WM_MOVE, sent|defwinproc|optional },
15122 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
15123 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15124 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
15125 { 0 }
15127 static const struct message WmRestore_5[] = {
15128 { HCBT_MINMAX, hook|lparam|optional, 0, SW_SHOWNORMAL },
15129 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
15130 { HCBT_ACTIVATE, hook|optional },
15131 { HCBT_SETFOCUS, hook|optional },
15132 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
15133 { WM_MOVE, sent|defwinproc|optional },
15134 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
15135 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
15136 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
15137 { 0 }
15139 static const struct message WmHide_1[] = {
15140 { WM_SHOWWINDOW, sent|wparam, 0 },
15141 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOACTIVATE },
15142 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
15143 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOACTIVATE },
15144 { HCBT_ACTIVATE, hook|optional },
15145 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
15146 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
15147 { 0 }
15149 static const struct message WmHide_2[] = {
15150 { WM_SHOWWINDOW, sent|wparam, 0 },
15151 { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
15152 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
15153 { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
15154 { HCBT_ACTIVATE, hook|optional },
15155 { 0 }
15157 static const struct message WmHide_3[] = {
15158 { WM_SHOWWINDOW, sent|wparam, 0 },
15159 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
15160 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
15161 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15162 { HCBT_SETFOCUS, hook|optional },
15163 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
15164 { 0 }
15166 static const struct message WmShowMinimized_1[] = {
15167 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
15168 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
15169 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
15170 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
15171 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
15172 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|wine_only, 0, 0 },
15173 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
15174 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|wine_only, OBJID_CLIENT, 0 },
15175 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
15176 { WM_MOVE, sent|defwinproc },
15177 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
15178 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15179 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
15180 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
15181 { 0 }
15183 static const struct message WmMinimize_1[] = {
15184 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
15185 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
15186 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
15187 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
15188 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
15189 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
15190 { WM_MOVE, sent|defwinproc },
15191 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
15192 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15193 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
15194 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
15195 { 0 }
15197 static const struct message WmMinimize_2[] = {
15198 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
15199 { HCBT_SETFOCUS, hook|optional },
15200 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
15201 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
15202 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
15203 { WM_MOVE, sent|defwinproc },
15204 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
15205 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15206 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
15207 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
15208 { 0 }
15210 static const struct message WmMinimize_3[] = {
15211 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
15212 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
15213 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
15214 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
15215 { HCBT_ACTIVATE, hook|optional },
15216 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sometimes sent on Win8/10. */
15217 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
15218 { WM_WINDOWPOSCHANGED, sent|optional },
15219 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sometimes sent on Win7. */
15220 { WM_WINDOWPOSCHANGED, sent|optional },
15221 { WM_MOVE, sent|defwinproc },
15222 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
15223 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15224 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
15225 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
15226 { 0 }
15228 static const struct message WmShowMinNoActivate[] = {
15229 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
15230 { WM_WINDOWPOSCHANGING, sent },
15231 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
15232 { WM_WINDOWPOSCHANGED, sent },
15233 { WM_MOVE, sent|defwinproc|optional },
15234 { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
15235 { 0 }
15237 static const struct message WmMinMax_1[] = {
15238 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
15239 { 0 }
15241 static const struct message WmMinMax_2[] = {
15242 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
15243 { WM_GETMINMAXINFO, sent|optional },
15244 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED },
15245 { HCBT_ACTIVATE, hook|optional },
15246 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
15247 { HCBT_SETFOCUS, hook|optional },
15248 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15249 { WM_MOVE, sent|defwinproc|optional },
15250 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MAXIMIZED },
15251 { HCBT_SETFOCUS, hook|optional },
15252 { 0 }
15254 static const struct message WmMinMax_3[] = {
15255 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
15256 { HCBT_SETFOCUS, hook|optional },
15257 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
15258 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
15259 { WM_MOVE, sent|defwinproc|optional },
15260 { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
15261 { 0 }
15263 static const struct message WmMinMax_4[] = {
15264 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
15265 { 0 }
15267 static const struct message WmShowMaximized_1[] = {
15268 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
15269 { WM_GETMINMAXINFO, sent },
15270 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
15271 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
15272 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
15273 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
15274 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|wine_only, 0, 0 },
15275 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
15276 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
15277 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|wine_only, OBJID_CLIENT, 0 },
15278 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
15279 { WM_MOVE, sent|defwinproc },
15280 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
15281 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15282 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
15283 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 },
15284 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
15285 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
15286 { 0 }
15288 static const struct message WmShowMaximized_2[] = {
15289 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
15290 { WM_GETMINMAXINFO, sent },
15291 { WM_WINDOWPOSCHANGING, sent|optional },
15292 { HCBT_ACTIVATE, hook|optional },
15293 { WM_WINDOWPOSCHANGED, sent|optional },
15294 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
15295 { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
15296 { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
15297 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends this. */
15298 { WM_WINDOWPOSCHANGING, sent|optional },
15299 { HCBT_SETFOCUS, hook|optional },
15300 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
15301 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
15302 { WM_MOVE, sent|defwinproc },
15303 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
15304 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15305 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
15306 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 },
15307 { HCBT_SETFOCUS, hook|optional },
15308 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
15309 { 0 }
15311 static const struct message WmShowMaximized_3[] = {
15312 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
15313 { WM_GETMINMAXINFO, sent|optional },
15314 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
15315 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
15316 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
15317 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
15318 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
15319 { WM_MOVE, sent|defwinproc|optional },
15320 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
15321 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15322 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
15323 { 0 }
15326 static void test_ShowWindow(void)
15328 /* ShowWindow commands in random order */
15329 static const struct
15331 INT cmd; /* ShowWindow command */
15332 LPARAM ret; /* ShowWindow return value */
15333 DWORD style; /* window style after the command */
15334 const struct message *msg; /* message sequence the command produces */
15335 INT wp_cmd, wp_flags; /* window placement after the command */
15336 POINT wp_min, wp_max; /* window placement after the command */
15337 BOOL todo_msg; /* message sequence doesn't match what Wine does */
15338 } sw[] =
15340 /* 1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal,
15341 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
15342 /* 2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq,
15343 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
15344 /* 3 */ { SW_HIDE, TRUE, 0, WmHide_1,
15345 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
15346 /* 4 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
15347 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
15348 /* 5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1,
15349 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15350 /* 6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1,
15351 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15352 /* 7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1,
15353 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15354 /* 8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
15355 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15356 /* 9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1,
15357 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15358 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
15359 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15360 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1,
15361 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15362 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq,
15363 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15364 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1,
15365 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15366 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
15367 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15368 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2,
15369 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15370 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
15371 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15372 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow,
15373 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15374 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
15375 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15376 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
15377 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15378 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
15379 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15380 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
15381 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15382 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate,
15383 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, TRUE },
15384 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4,
15385 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15386 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
15387 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15388 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
15389 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15390 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1,
15391 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15392 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2,
15393 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15394 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
15395 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15396 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
15397 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15398 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1,
15399 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15400 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
15401 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15402 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3,
15403 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15404 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
15405 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15406 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, /* what does this mean?! */
15407 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15408 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq,
15409 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15410 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
15411 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15412 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2,
15413 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15414 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
15415 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15416 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
15417 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15418 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2,
15419 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15420 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
15421 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15422 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2,
15423 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15424 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
15425 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15426 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
15427 SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15428 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
15429 SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15430 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3,
15431 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15432 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4,
15433 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15434 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3,
15435 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15436 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq,
15437 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15438 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
15439 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15440 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
15441 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15442 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1,
15443 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15444 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
15445 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15446 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3,
15447 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15448 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
15449 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15450 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2,
15451 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15452 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
15453 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE }
15455 HWND hwnd;
15456 DWORD style;
15457 LPARAM ret;
15458 INT i;
15459 WINDOWPLACEMENT wp;
15460 RECT win_rc, work_rc = {0, 0, 0, 0};
15461 HMONITOR hmon;
15462 MONITORINFO mi;
15463 POINT pt = {0, 0};
15465 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
15466 hwnd = CreateWindowExA(0, "ShowWindowClass", NULL, WS_BASE,
15467 120, 120, 90, 90,
15468 0, 0, 0, NULL);
15469 ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError());
15471 style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
15472 ok(style == 0, "expected style 0, got %08lx\n", style);
15474 flush_events();
15475 flush_sequence();
15477 SetLastError(0xdeadbeef);
15478 hmon = MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
15479 ok(hmon != 0, "MonitorFromPoint error %lu\n", GetLastError());
15481 mi.cbSize = sizeof(mi);
15482 SetLastError(0xdeadbeef);
15483 ret = GetMonitorInfoA(hmon, &mi);
15484 ok(ret, "GetMonitorInfo error %lu\n", GetLastError());
15485 if (winetest_debug > 1) trace("monitor %s, work %s\n", wine_dbgstr_rect(&mi.rcMonitor),
15486 wine_dbgstr_rect(&mi.rcWork));
15487 work_rc = mi.rcWork;
15489 GetWindowRect(hwnd, &win_rc);
15490 OffsetRect(&win_rc, -work_rc.left, -work_rc.top);
15492 wp.length = sizeof(wp);
15493 SetLastError(0xdeadbeaf);
15494 ret = GetWindowPlacement(hwnd, &wp);
15495 ok(ret, "GetWindowPlacement error %lu\n", GetLastError());
15496 ok(wp.flags == 0, "expected 0, got %#x\n", wp.flags);
15497 ok(wp.showCmd == SW_SHOWNORMAL, "expected SW_SHOWNORMAL, got %d\n", wp.showCmd);
15498 ok(wp.ptMinPosition.x == -1 && wp.ptMinPosition.y == -1,
15499 "expected -1,-1 got %ld,%ld\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
15500 ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
15501 "expected -1,-1 got %ld,%ld\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
15502 todo_wine_if (work_rc.left || work_rc.top) /* FIXME: remove once Wine is fixed */
15503 ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n", wine_dbgstr_rect(&win_rc),
15504 wine_dbgstr_rect(&wp.rcNormalPosition));
15506 for (i = 0; i < ARRAY_SIZE(sw); i++)
15508 static const char * const sw_cmd_name[13] =
15510 "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
15511 "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
15512 "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
15513 "SW_NORMALNA" /* 0xCC */
15515 char comment[64];
15516 INT idx; /* index into the above array of names */
15518 idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
15520 style = GetWindowLongA(hwnd, GWL_STYLE);
15521 if (winetest_debug > 1) trace("%d: sending %s, current window style %08lx\n", i+1, sw_cmd_name[idx], style);
15522 ret = ShowWindow(hwnd, sw[i].cmd);
15523 ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %Iu, got %Iu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
15524 style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
15525 ok(style == sw[i].style, "%d: expected style %08lx, got %08lx\n", i+1, sw[i].style, style);
15527 sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
15528 ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
15530 wp.length = sizeof(wp);
15531 SetLastError(0xdeadbeaf);
15532 ret = GetWindowPlacement(hwnd, &wp);
15533 ok(ret, "GetWindowPlacement error %lu\n", GetLastError());
15534 ok(wp.flags == sw[i].wp_flags, "expected %#x, got %#x\n", sw[i].wp_flags, wp.flags);
15535 ok(wp.showCmd == sw[i].wp_cmd, "expected %d, got %d\n", sw[i].wp_cmd, wp.showCmd);
15537 /* NT moves the minimized window to -32000,-32000, win9x to 3000,3000 */
15538 if ((wp.ptMinPosition.x + work_rc.left == -32000 && wp.ptMinPosition.y + work_rc.top == -32000) ||
15539 (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000))
15541 ok((wp.ptMinPosition.x + work_rc.left == sw[i].wp_min.x && wp.ptMinPosition.y + work_rc.top == sw[i].wp_min.y) ||
15542 (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000),
15543 "expected %ld,%ld got %ld,%ld\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
15545 else
15547 ok(wp.ptMinPosition.x == sw[i].wp_min.x && wp.ptMinPosition.y == sw[i].wp_min.y,
15548 "expected %ld,%ld got %ld,%ld\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
15551 todo_wine_if(wp.ptMaxPosition.x != sw[i].wp_max.x || wp.ptMaxPosition.y != sw[i].wp_max.y)
15552 ok(wp.ptMaxPosition.x == sw[i].wp_max.x && wp.ptMaxPosition.y == sw[i].wp_max.y,
15553 "expected %ld,%ld got %ld,%ld\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y);
15555 if (0) /* FIXME: Wine behaves completely different here */
15556 ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n",
15557 wine_dbgstr_rect(&win_rc), wine_dbgstr_rect(&wp.rcNormalPosition));
15559 DestroyWindow(hwnd);
15560 flush_events();
15563 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
15565 struct recvd_message msg;
15567 if (ignore_message( message )) return 0;
15569 msg.hwnd = hwnd;
15570 msg.message = message;
15571 msg.flags = sent|wparam|lparam;
15572 msg.wParam = wParam;
15573 msg.lParam = lParam;
15574 msg.descr = "dialog";
15575 add_message(&msg);
15577 /* calling DefDlgProc leads to a recursion under XP */
15579 switch (message)
15581 case WM_INITDIALOG:
15582 return lParam;
15584 case WM_GETDLGCODE:
15585 return 0;
15587 return 1;
15590 static WNDPROC orig_edit_proc;
15591 static LRESULT WINAPI dlg_creation_edit_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
15593 struct recvd_message msg;
15595 if (ignore_message( message )) return 0;
15597 msg.hwnd = hwnd;
15598 msg.message = message;
15599 msg.flags = sent|wparam|lparam;
15600 msg.wParam = wp;
15601 msg.lParam = lp;
15602 msg.descr = "edit";
15603 add_message(&msg);
15605 return CallWindowProcW(orig_edit_proc, hwnd, message, wp, lp);
15608 static INT_PTR WINAPI test_dlg_proc2(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
15610 struct recvd_message msg;
15612 if (ignore_message( message )) return 0;
15614 msg.hwnd = hwnd;
15615 msg.message = message;
15616 msg.flags = sent|wparam|lparam|parent;
15617 msg.wParam = wParam;
15618 msg.lParam = lParam;
15619 msg.descr = "dialog";
15620 add_message(&msg);
15622 if (message == WM_INITDIALOG)
15624 orig_edit_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwnd, 200),
15625 GWLP_WNDPROC, (LONG_PTR)dlg_creation_edit_proc);
15628 return 1;
15631 static INT_PTR WINAPI test_dlg_proc3(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
15633 ok( 0, "should not be called since DefDlgProc is not used\n" );
15634 return 0;
15637 static LRESULT WINAPI test_dlg_proc4(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
15639 struct recvd_message msg;
15641 if (!ignore_message( message ))
15643 msg.hwnd = hwnd;
15644 msg.message = message;
15645 msg.flags = sent|wparam|lparam|parent;
15646 msg.wParam = wParam;
15647 msg.lParam = lParam;
15648 msg.descr = "dialog";
15649 add_message(&msg);
15651 if (message == WM_INITDIALOG)
15653 orig_edit_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwnd, 200),
15654 GWLP_WNDPROC, (LONG_PTR)dlg_creation_edit_proc);
15655 return 1;
15657 return DefWindowProcW( hwnd, message, wParam, lParam );
15660 static const struct message WmDefDlgSetFocus_1[] = {
15661 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
15662 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
15663 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
15664 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
15665 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
15666 { HCBT_SETFOCUS, hook },
15667 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
15668 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
15669 { EM_GETPASSWORDCHAR, sent|optional }, /* Sent on some Win10 machines */
15670 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
15671 { WM_SETFOCUS, sent|wparam, 0 },
15672 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
15673 { WM_CTLCOLOREDIT, sent },
15674 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
15675 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 },
15676 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 },
15677 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 },
15678 { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
15679 { 0 }
15681 static const struct message WmDefDlgSetFocus_2[] = {
15682 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
15683 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
15684 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
15685 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
15686 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
15687 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 },
15688 { WM_CTLCOLOREDIT, sent|optional }, /* XP */
15689 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 },
15690 { 0 }
15692 /* Creation of a dialog */
15693 static const struct message WmCreateDialogParamSeq_0[] = {
15694 { HCBT_CREATEWND, hook },
15695 { WM_NCCREATE, sent },
15696 { WM_NCCALCSIZE, sent|wparam, 0 },
15697 { WM_CREATE, sent },
15698 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
15699 { WM_SIZE, sent|wparam, SIZE_RESTORED },
15700 { WM_MOVE, sent },
15701 { WM_SETFONT, sent },
15702 { WM_INITDIALOG, sent },
15703 { WM_CHANGEUISTATE, sent|optional },
15704 { 0 }
15706 /* Creation of a dialog */
15707 static const struct message WmCreateDialogParamSeq_1[] = {
15708 { HCBT_CREATEWND, hook },
15709 { WM_NCCREATE, sent },
15710 { WM_NCCALCSIZE, sent|wparam, 0 },
15711 { WM_CREATE, sent },
15712 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
15713 { WM_SIZE, sent|wparam, SIZE_RESTORED },
15714 { WM_MOVE, sent },
15715 { WM_SETFONT, sent },
15716 { WM_INITDIALOG, sent },
15717 { WM_GETDLGCODE, sent|wparam|lparam|msg_todo, 0, 0 }, /* FIXME: Wine doesn't send it */
15718 { HCBT_SETFOCUS, hook },
15719 { HCBT_ACTIVATE, hook },
15720 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
15721 { WM_QUERYNEWPALETTE, sent|optional },
15722 { WM_PALETTEISCHANGING, sent|optional },
15723 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
15724 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOREDRAW },
15725 { WM_GETTEXT, sent|optional }, /* win7 */
15726 { WM_NCCALCSIZE, sent|optional }, /* win7 */
15727 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win7 */
15728 { WM_ACTIVATEAPP, sent|wparam, 1 },
15729 { WM_NCACTIVATE, sent },
15730 { WM_ACTIVATE, sent|wparam, 1 },
15731 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
15732 { WM_SETFOCUS, sent },
15733 { WM_CHANGEUISTATE, sent|optional },
15734 { 0 }
15736 /* Creation of a dialog */
15737 static const struct message WmCreateDialogParamSeq_2[] = {
15738 { HCBT_CREATEWND, hook },
15739 { WM_NCCREATE, sent },
15740 { WM_NCCALCSIZE, sent|wparam, 0 },
15741 { WM_CREATE, sent },
15742 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
15743 { WM_SIZE, sent|wparam, SIZE_RESTORED },
15744 { WM_MOVE, sent },
15745 { WM_CHANGEUISTATE, sent|optional },
15746 { 0 }
15749 static const struct message WmCreateDialogParamSeq_3[] = {
15750 { HCBT_CREATEWND, hook },
15751 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
15752 { WM_SETFONT, sent|parent },
15753 { WM_INITDIALOG, sent|parent },
15754 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
15755 { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
15756 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
15757 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
15758 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
15759 { HCBT_ACTIVATE, hook },
15760 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
15761 { WM_QUERYNEWPALETTE, sent|parent|optional }, /* TODO: this message should not be sent */
15762 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
15763 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
15764 { WM_WINDOWPOSCHANGED, sent|parent|wparam|optional, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15765 { WM_WINDOWPOSCHANGED, sent|parent|wparam|optional, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15766 { WM_NCCALCSIZE, sent|parent|optional, 0 },
15767 { WM_MOVE, sent|parent|optional },
15768 { WM_SIZE, sent|parent|optional },
15769 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
15770 { WM_ACTIVATEAPP, sent|parent|wparam, 1 },
15771 { WM_NCACTIVATE, sent|parent },
15772 { WM_ACTIVATE, sent|parent|wparam, 1 },
15773 { EM_GETPASSWORDCHAR, sent|optional }, /* Sent on some Win10 machines */
15774 { WM_SETFOCUS, sent },
15775 { WM_COMMAND, sent|parent|wparam, MAKELONG(200, EN_SETFOCUS) },
15776 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
15777 { WM_USER, sent|parent },
15778 { WM_CHANGEUISTATE, sent|parent|optional },
15779 { 0 }
15782 static const struct message WmCreateDialogParamSeq_4[] = {
15783 { HCBT_CREATEWND, hook },
15784 { WM_NCCREATE, sent|parent },
15785 { WM_NCCALCSIZE, sent|parent|wparam, 0 },
15786 { WM_CREATE, sent|parent },
15787 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
15788 { WM_SIZE, sent|parent|wparam, SIZE_RESTORED },
15789 { WM_MOVE, sent|parent },
15790 { WM_SETFONT, sent|parent },
15791 { WM_INITDIALOG, sent|parent },
15792 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
15793 { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
15794 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
15795 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
15796 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
15797 { HCBT_ACTIVATE, hook },
15798 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
15799 { WM_QUERYNEWPALETTE, sent|parent|optional }, /* TODO: this message should not be sent */
15800 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
15801 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
15802 { WM_WINDOWPOSCHANGED, sent|parent|wparam|optional, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15803 { WM_NCCALCSIZE, sent|parent|optional, 0 },
15804 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
15805 { WM_ACTIVATEAPP, sent|parent|wparam, 1 },
15806 { WM_NCACTIVATE, sent|parent },
15807 { WM_ACTIVATE, sent|parent|wparam, 1 },
15808 { HCBT_SETFOCUS, hook },
15809 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
15810 { WM_SETFOCUS, sent|parent },
15811 { WM_KILLFOCUS, sent|parent },
15812 { EM_GETPASSWORDCHAR, sent|optional }, /* Sent on some Win10 machines */
15813 { WM_SETFOCUS, sent },
15814 { WM_COMMAND, sent|parent|wparam, MAKELONG(200, EN_SETFOCUS) },
15815 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
15816 { WM_USER, sent|parent },
15817 { WM_CHANGEUISTATE, sent|parent|optional },
15818 { WM_UPDATEUISTATE, sent|parent|optional },
15819 { WM_UPDATEUISTATE, sent|optional },
15820 { 0 }
15823 static void test_dialog_messages(void)
15825 WNDCLASSA cls;
15826 HWND hdlg, hedit1, hedit2, hfocus, parent, child, child2;
15827 LRESULT ret;
15829 #define set_selection(hctl, start, end) \
15830 ret = SendMessageA(hctl, EM_SETSEL, start, end); \
15831 ok(ret == 1, "EM_SETSEL returned %Id\n", ret);
15833 #define check_selection(hctl, start, end) \
15834 ret = SendMessageA(hctl, EM_GETSEL, 0, 0); \
15835 ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
15837 subclass_edit();
15839 hdlg = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
15840 WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
15841 0, 0, 100, 100, 0, 0, 0, NULL);
15842 ok(hdlg != 0, "Failed to create custom dialog window\n");
15844 hedit1 = CreateWindowExA(0, "my_edit_class", NULL,
15845 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
15846 0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
15847 ok(hedit1 != 0, "Failed to create edit control\n");
15848 hedit2 = CreateWindowExA(0, "my_edit_class", NULL,
15849 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
15850 0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
15851 ok(hedit2 != 0, "Failed to create edit control\n");
15853 SendMessageA(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
15854 SendMessageA(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
15856 hfocus = GetFocus();
15857 ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
15859 SetFocus(hedit2);
15860 hfocus = GetFocus();
15861 ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
15863 check_selection(hedit1, 0, 0);
15864 check_selection(hedit2, 0, 0);
15866 set_selection(hedit2, 0, -1);
15867 check_selection(hedit2, 0, 3);
15869 SetFocus(0);
15870 hfocus = GetFocus();
15871 ok(hfocus == 0, "wrong focus %p\n", hfocus);
15873 flush_sequence();
15874 ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
15875 ok(ret == 0, "WM_SETFOCUS returned %Id\n", ret);
15876 ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
15878 hfocus = GetFocus();
15879 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
15881 check_selection(hedit1, 0, 5);
15882 check_selection(hedit2, 0, 3);
15884 flush_sequence();
15885 ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
15886 ok(ret == 0, "WM_SETFOCUS returned %Id\n", ret);
15887 ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
15889 hfocus = GetFocus();
15890 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
15892 check_selection(hedit1, 0, 5);
15893 check_selection(hedit2, 0, 3);
15895 EndDialog(hdlg, 0);
15896 DestroyWindow(hedit1);
15897 DestroyWindow(hedit2);
15898 DestroyWindow(hdlg);
15899 flush_sequence();
15901 #undef set_selection
15902 #undef check_selection
15904 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
15905 cls.lpszClassName = "MyDialogClass";
15906 cls.hInstance = GetModuleHandleA(NULL);
15907 /* need a cast since a dlgproc is used as a wndproc */
15908 cls.lpfnWndProc = (WNDPROC)test_dlg_proc;
15909 register_class(&cls);
15911 SetFocus(0);
15912 flush_sequence();
15913 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
15914 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
15915 ok_sequence(WmCreateDialogParamSeq_0, "CreateDialogParam_0", FALSE);
15916 hfocus = GetFocus();
15917 ok(hfocus == 0, "wrong focus %p\n", hfocus);
15918 EndDialog(hdlg, 0);
15919 DestroyWindow(hdlg);
15920 flush_sequence();
15922 SetFocus(0);
15923 flush_sequence();
15924 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 1);
15925 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
15926 ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
15927 hfocus = GetFocus();
15928 ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
15929 EndDialog(hdlg, 0);
15930 DestroyWindow(hdlg);
15931 flush_sequence();
15933 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
15934 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
15935 ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
15936 EndDialog(hdlg, 0);
15937 DestroyWindow(hdlg);
15938 flush_sequence();
15940 hdlg = CreateDialogParamA(0, "FOCUS_TEST_DIALOG_3", 0, test_dlg_proc2, 0);
15941 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
15942 ok_sequence(WmCreateDialogParamSeq_3, "CreateDialogParam_3", TRUE);
15943 EndDialog(hdlg, 0);
15944 DestroyWindow(hdlg);
15945 flush_sequence();
15947 UnregisterClassA( cls.lpszClassName, cls.hInstance );
15948 cls.lpfnWndProc = test_dlg_proc4;
15949 register_class(&cls);
15950 hdlg = CreateDialogParamA(0, "FOCUS_TEST_DIALOG_4", 0, test_dlg_proc3, 0);
15951 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
15952 ok_sequence(WmCreateDialogParamSeq_4, "CreateDialogParam_4", TRUE);
15953 EndDialog(hdlg, 0);
15954 DestroyWindow(hdlg);
15955 flush_sequence();
15957 UnregisterClassA(cls.lpszClassName, cls.hInstance);
15959 parent = CreateWindowExA(0, "TestParentClass", "Test parent",
15960 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
15961 100, 100, 200, 200, 0, 0, 0, NULL);
15962 ok (parent != 0, "Failed to create parent window\n");
15964 /* This child has no parent set. We will later call SetParent on it,
15965 * so that it will have a parent set, but no WS_CHILD style. */
15966 child = CreateWindowExA(0, "TestWindowClass", "Test child",
15967 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
15968 100, 100, 200, 200, 0, 0, 0, NULL);
15969 ok (child != 0, "Failed to create child window\n");
15971 /* This is a regular child window. When used as an owner, the other
15972 * child window will be used. */
15973 child2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2",
15974 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CHILD,
15975 100, 100, 200, 200, child, 0, 0, NULL);
15976 ok (child2 != 0, "Failed to create child window\n");
15978 SetParent(child, parent);
15979 SetFocus(child);
15981 flush_sequence();
15982 DialogBoxA( 0, "TEST_DIALOG", child2, TestModalDlgProc2 );
15983 ok_sequence(WmModalDialogSeq_2, "ModalDialog2", TRUE);
15985 DestroyWindow(child2);
15986 DestroyWindow(child);
15987 DestroyWindow(parent);
15988 flush_sequence();
15991 static void test_enddialog_seq(HWND dialog, HWND owner)
15993 const struct message seq[] = {
15994 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
15995 { WM_ENABLE, sent },
15996 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
15997 { HCBT_ACTIVATE, hook|wparam, (WPARAM)owner },
15998 { WM_NCACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
15999 { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
16000 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
16001 /* FIXME: Following two are optional because Wine sends WM_QUERYNEWPALETTE instead of WM_WINDOWPOSCHANGING */
16002 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
16003 { WM_QUERYNEWPALETTE, sent|optional },
16004 { WM_NCACTIVATE, sent|wparam|lparam, WA_ACTIVE, (LPARAM)dialog },
16005 { WM_GETTEXT, sent|optional|defwinproc },
16006 { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, (LPARAM)dialog },
16007 { HCBT_SETFOCUS, hook|wparam, (WPARAM)owner },
16008 { WM_KILLFOCUS, sent|wparam, (WPARAM)owner },
16009 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
16010 { WM_SETFOCUS, sent|defwinproc|wparam, (WPARAM)dialog },
16011 { 0 }
16014 flush_sequence();
16015 EndDialog(dialog, 0);
16016 ok_sequence(seq, "EndDialog", FALSE);
16019 static void test_enddialog_seq2(HWND dialog, HWND owner)
16021 const struct message seq[] = {
16022 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
16023 { WM_ENABLE, parent|sent },
16024 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
16025 { HCBT_ACTIVATE, hook|wparam, (WPARAM)owner },
16026 { WM_NCACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
16027 { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
16028 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
16029 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
16030 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
16031 { HCBT_SETFOCUS, hook|wparam, (WPARAM)owner },
16032 { WM_KILLFOCUS, sent|wparam, (WPARAM)owner },
16033 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
16034 { WM_SETFOCUS, sent|parent|defwinproc|wparam, (WPARAM)dialog },
16035 { 0 }
16038 flush_sequence();
16039 EndDialog(dialog, 0);
16040 ok_sequence(seq, "EndDialog2", FALSE);
16043 static void test_EndDialog(void)
16045 HWND hparent, hother, hactive, hdlg, hchild;
16046 WNDCLASSA cls;
16048 hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
16049 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
16050 100, 100, 200, 200, 0, 0, 0, NULL);
16051 ok (hparent != 0, "Failed to create parent window\n");
16053 hother = CreateWindowExA(0, "TestParentClass", "Test parent 2",
16054 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
16055 200, 100, 200, 200, 0, 0, 0, NULL);
16056 ok (hother != 0, "Failed to create parent window\n");
16058 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
16059 cls.lpszClassName = "MyDialogClass";
16060 cls.hInstance = GetModuleHandleA(NULL);
16061 cls.lpfnWndProc = (WNDPROC)test_dlg_proc;
16062 register_class(&cls);
16064 flush_sequence();
16065 SetForegroundWindow(hother);
16066 hactive = GetForegroundWindow();
16067 ok(hother == hactive, "Wrong window has focus (%p != %p)\n", hother, hactive);
16069 /* create a dialog where the parent is disabled, this parent should be
16070 * enabled and receive focus when dialog exits */
16071 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hparent, test_dlg_proc, 0);
16072 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
16073 SetForegroundWindow(hdlg);
16074 hactive = GetForegroundWindow();
16075 ok(hdlg == hactive, "Wrong window has focus (%p != %p)\n", hdlg, hactive);
16076 EndDialog(hdlg, 0);
16077 ok(IsWindowEnabled(hparent), "parent is not enabled\n");
16078 hactive = GetForegroundWindow();
16079 ok(hparent == hactive, "Wrong window has focus (parent != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
16080 DestroyWindow(hdlg);
16081 flush_sequence();
16083 /* create a dialog where the parent is disabled and set active window to other window before calling EndDialog */
16084 EnableWindow(hparent, FALSE);
16085 hdlg = CreateWindowExA(0, "TestDialogClass", NULL,
16086 WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
16087 0, 0, 100, 100, hparent, 0, 0, NULL);
16088 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
16089 flush_sequence();
16090 SetForegroundWindow(hother);
16091 flush_sequence();
16092 hactive = GetForegroundWindow();
16093 ok(hactive == hother, "Wrong foreground (%p != %p)\n", hactive, hother);
16094 hactive = GetActiveWindow();
16095 ok(hactive == hother, "Wrong active window (%p != %p)\n", hactive, hother);
16096 EndDialog(hdlg, 0);
16097 ok(IsWindowEnabled(hparent), "parent is not enabled\n");
16098 hactive = GetForegroundWindow();
16099 ok(hother == hactive, "Wrong window has focus (other != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
16100 DestroyWindow(hdlg);
16101 flush_sequence();
16103 DestroyWindow( hparent );
16105 hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
16106 WS_POPUP | WS_VISIBLE | WS_DISABLED,
16107 100, 100, 200, 200, 0, 0, 0, NULL);
16108 ok (hparent != 0, "Failed to create parent window\n");
16110 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
16111 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
16112 0, 0, 0, 0, 0, 0, 0, NULL);
16113 ok (hchild != 0, "Failed to create child window\n");
16115 SetParent(hchild, hparent);
16117 flush_sequence();
16118 SetForegroundWindow(hother);
16119 hactive = GetForegroundWindow();
16120 ok(hother == hactive, "Wrong foreground window (%p != %p)\n", hother, hactive);
16122 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hchild, test_dlg_proc, 0);
16123 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
16125 SetForegroundWindow(hdlg);
16126 test_enddialog_seq(hdlg, hchild);
16128 hactive = GetForegroundWindow();
16129 ok(hactive == hchild, "Wrong foreground window (active: %p, parent: %p, dlg: %p, other: %p child: %p)\n", hactive, hparent, hdlg, hother, hchild);
16131 DestroyWindow(hdlg);
16133 /* Now set WS_CHILD style flag so that it's a real child and its parent will be dialog's owner. */
16134 SetWindowLongW(hchild, GWL_STYLE, GetWindowLongW(hchild, GWL_STYLE) | WS_CHILD);
16136 SetForegroundWindow(hother);
16137 hactive = GetForegroundWindow();
16138 ok(hother == hactive, "Wrong foreground window (%p != %p)\n", hother, hactive);
16140 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hchild, test_dlg_proc, 0);
16141 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
16143 SetForegroundWindow(hdlg);
16144 test_enddialog_seq2(hdlg, hparent);
16146 hactive = GetForegroundWindow();
16147 ok(hactive == hparent, "Wrong foreground window (active: %p, parent: %p, dlg: %p, other: %p child: %p)\n", hactive, hparent, hdlg, hother, hchild);
16148 DestroyWindow(hdlg);
16149 DestroyWindow(hchild);
16150 DestroyWindow(hparent);
16151 DestroyWindow(hother);
16152 flush_sequence();
16154 UnregisterClassA(cls.lpszClassName, cls.hInstance);
16157 static void test_nullCallback(void)
16159 HWND hwnd;
16161 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
16162 100, 100, 200, 200, 0, 0, 0, NULL);
16163 ok (hwnd != 0, "Failed to create overlapped window\n");
16165 SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
16166 flush_events();
16167 DestroyWindow(hwnd);
16170 /* SetActiveWindow( 0 ) hwnd visible */
16171 static const struct message SetActiveWindowSeq0[] =
16173 { HCBT_ACTIVATE, hook|optional },
16174 { WM_NCACTIVATE, sent|wparam, 0 },
16175 { WM_GETTEXT, sent|defwinproc|optional },
16176 { WM_ACTIVATE, sent|wparam, 0 },
16177 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
16178 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
16179 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
16180 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
16181 { WM_KILLFOCUS, sent|optional },
16182 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
16183 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
16184 { WM_NCACTIVATE, sent|wparam|optional, 1 },
16185 { WM_GETTEXT, sent|defwinproc|optional },
16186 { WM_ACTIVATE, sent|wparam|optional, 1 },
16187 { HCBT_SETFOCUS, hook|optional },
16188 { WM_KILLFOCUS, sent|defwinproc|optional },
16189 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
16190 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
16191 { WM_IME_SETCONTEXT, sent|optional },
16192 { WM_IME_SETCONTEXT, sent|optional },
16193 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
16194 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
16195 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
16196 { WM_SETFOCUS, sent|defwinproc|optional },
16197 { WM_GETTEXT, sent|optional },
16198 { 0 }
16200 /* SetActiveWindow( hwnd ) hwnd visible */
16201 static const struct message SetActiveWindowSeq1[] =
16203 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
16204 { 0 }
16206 /* SetActiveWindow( popup ) hwnd visible, popup visible */
16207 static const struct message SetActiveWindowSeq2[] =
16209 { HCBT_ACTIVATE, hook },
16210 { WM_NCACTIVATE, sent|wparam, 0 },
16211 { WM_GETTEXT, sent|defwinproc|optional },
16212 { WM_ACTIVATE, sent|wparam, 0 },
16213 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
16214 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
16215 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
16216 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
16217 { WM_NCPAINT, sent|optional },
16218 { WM_GETTEXT, sent|defwinproc|optional },
16219 { WM_ERASEBKGND, sent|optional },
16220 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
16221 { WM_NCACTIVATE, sent|wparam, 1 },
16222 { WM_GETTEXT, sent|defwinproc|optional },
16223 { WM_ACTIVATE, sent|wparam, 1 },
16224 { HCBT_SETFOCUS, hook },
16225 { WM_KILLFOCUS, sent|defwinproc },
16226 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
16227 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
16228 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
16229 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
16230 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
16231 { WM_SETFOCUS, sent|defwinproc },
16232 { WM_GETTEXT, sent|optional },
16233 { 0 }
16236 /* SetActiveWindow( hwnd ) hwnd not visible */
16237 static const struct message SetActiveWindowSeq3[] =
16239 { HCBT_ACTIVATE, hook },
16240 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
16241 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
16242 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
16243 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
16244 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
16245 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
16246 { WM_ACTIVATEAPP, sent|wparam, 1 },
16247 { WM_ACTIVATEAPP, sent|wparam, 1 },
16248 { WM_NCACTIVATE, sent|wparam, 1 },
16249 { WM_ACTIVATE, sent|wparam, 1 },
16250 { HCBT_SETFOCUS, hook },
16251 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
16252 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
16253 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
16254 { WM_SETFOCUS, sent|defwinproc },
16255 { 0 }
16257 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
16258 static const struct message SetActiveWindowSeq4[] =
16260 { HCBT_ACTIVATE, hook },
16261 { WM_NCACTIVATE, sent|wparam, 0 },
16262 { WM_GETTEXT, sent|defwinproc|optional },
16263 { WM_ACTIVATE, sent|wparam, 0 },
16264 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
16265 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
16266 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
16267 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
16268 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
16269 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
16270 { WM_NCACTIVATE, sent|wparam, 1 },
16271 { WM_GETTEXT, sent|defwinproc|optional },
16272 { WM_ACTIVATE, sent|wparam, 1 },
16273 { HCBT_SETFOCUS, hook },
16274 { WM_KILLFOCUS, sent|defwinproc },
16275 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
16276 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
16277 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
16278 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
16279 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
16280 { WM_SETFOCUS, sent|defwinproc },
16281 { 0 }
16285 static void test_SetActiveWindow(void)
16287 HWND hwnd, popup, ret;
16289 hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
16290 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
16291 100, 100, 200, 200, 0, 0, 0, NULL);
16293 popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
16294 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
16295 100, 100, 200, 200, hwnd, 0, 0, NULL);
16297 ok(hwnd != 0, "Failed to create overlapped window\n");
16298 ok(popup != 0, "Failed to create popup window\n");
16299 SetForegroundWindow( popup );
16300 flush_sequence();
16302 if (winetest_debug > 1) trace("SetActiveWindow(0)\n");
16303 ret = SetActiveWindow(0);
16304 ok( ret == popup || broken(ret == 0) /* w1064v1809 */, "Failed to SetActiveWindow(0), ret:%p\n", ret);
16305 if (ret == popup) ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", FALSE);
16306 flush_sequence();
16308 if (winetest_debug > 1) trace("SetActiveWindow(hwnd), hwnd visible\n");
16309 ret = SetActiveWindow(hwnd);
16310 if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
16311 flush_sequence();
16313 if (winetest_debug > 1) trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
16314 ret = SetActiveWindow(popup);
16315 ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
16316 ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
16317 flush_sequence();
16319 ShowWindow(hwnd, SW_HIDE);
16320 ShowWindow(popup, SW_HIDE);
16321 flush_sequence();
16323 if (winetest_debug > 1) trace("SetActiveWindow(hwnd), hwnd not visible\n");
16324 ret = SetActiveWindow(hwnd);
16325 ok( ret == NULL, "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret );
16326 ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
16327 flush_sequence();
16329 if (winetest_debug > 1) trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
16330 ret = SetActiveWindow(popup);
16331 ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
16332 ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
16333 flush_sequence();
16335 if (winetest_debug > 1) trace("done\n");
16337 DestroyWindow(hwnd);
16340 static const struct message SetForegroundWindowSeq[] =
16342 { WM_NCACTIVATE, sent|wparam, 0 },
16343 { WM_GETTEXT, sent|defwinproc|optional },
16344 { WM_ACTIVATE, sent|wparam, 0 },
16345 { WM_ACTIVATEAPP, sent|wparam, 0 },
16346 { WM_KILLFOCUS, sent },
16347 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
16348 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
16349 { 0 }
16352 static void test_SetForegroundWindow(void)
16354 HWND hwnd;
16356 hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
16357 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
16358 100, 100, 200, 200, 0, 0, 0, NULL);
16359 ok (hwnd != 0, "Failed to create overlapped window\n");
16360 SetForegroundWindow( hwnd );
16361 flush_sequence();
16363 if (winetest_debug > 1) trace("SetForegroundWindow( 0 )\n");
16364 SetForegroundWindow( 0 );
16365 ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
16366 if (winetest_debug > 1) trace("SetForegroundWindow( GetDesktopWindow() )\n");
16367 SetForegroundWindow( GetDesktopWindow() );
16368 ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
16369 "foreground top level window", FALSE);
16370 if (winetest_debug > 1) trace("done\n");
16372 DestroyWindow(hwnd);
16375 static DWORD get_input_codepage( void )
16377 DWORD cp;
16378 int ret;
16379 HKL hkl = GetKeyboardLayout( 0 );
16381 ret = GetLocaleInfoW( LOWORD(hkl), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
16382 (WCHAR *)&cp, sizeof(cp) / sizeof(WCHAR) );
16383 if (!ret) cp = CP_ACP;
16384 return cp;
16387 static void test_dbcs_wm_char(void)
16389 BYTE dbch[2];
16390 WCHAR wch, bad_wch;
16391 HWND hwnd, hwnd2;
16392 MSG msg;
16393 DWORD time;
16394 POINT pt;
16395 DWORD_PTR res;
16396 CPINFOEXA cpinfo;
16397 UINT i, j, k;
16398 struct message wmCharSeq[2];
16399 BOOL ret;
16400 DWORD cp = get_input_codepage();
16402 if (!pGetCPInfoExA)
16404 win_skip("GetCPInfoExA is not available\n");
16405 return;
16408 pGetCPInfoExA( cp, 0, &cpinfo );
16409 if (cpinfo.MaxCharSize != 2)
16411 skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
16412 return;
16415 dbch[0] = dbch[1] = 0;
16416 wch = 0;
16417 bad_wch = cpinfo.UnicodeDefaultChar;
16418 for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
16419 for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
16420 for (k = 128; k <= 255; k++)
16422 char str[2];
16423 WCHAR wstr[2];
16424 str[0] = j;
16425 str[1] = k;
16426 if (MultiByteToWideChar( cp, 0, str, 2, wstr, 2 ) == 1 &&
16427 WideCharToMultiByte( cp, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
16428 (BYTE)str[0] == j && (BYTE)str[1] == k &&
16429 HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
16431 dbch[0] = j;
16432 dbch[1] = k;
16433 wch = wstr[0];
16434 break;
16438 if (!wch)
16440 skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
16441 return;
16443 if (winetest_debug > 1) trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
16444 dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
16446 hwnd = CreateWindowExW(0, testWindowClassW, NULL,
16447 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
16448 hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
16449 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
16450 ok (hwnd != 0, "Failed to create overlapped window\n");
16451 ok (hwnd2 != 0, "Failed to create overlapped window\n");
16452 flush_events();
16453 flush_sequence();
16455 memset( wmCharSeq, 0, sizeof(wmCharSeq) );
16456 wmCharSeq[0].message = WM_CHAR;
16457 wmCharSeq[0].flags = sent|wparam;
16458 wmCharSeq[0].wParam = wch;
16460 /* posted message */
16461 PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
16462 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16463 ok( !ret, "got message %x\n", msg.message );
16464 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
16465 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16466 ok( ret, "no message\n" );
16467 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16468 ok( msg.wParam == wch, "bad wparam %Ix/%x\n", msg.wParam, wch );
16469 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16470 ok( !ret, "got message %x\n", msg.message );
16472 /* posted thread message */
16473 PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
16474 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16475 ok( !ret, "got message %x\n", msg.message );
16476 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
16477 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16478 ok( ret, "no message\n" );
16479 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16480 ok( msg.wParam == wch, "bad wparam %Ix/%x\n", msg.wParam, wch );
16481 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16482 ok( !ret, "got message %x\n", msg.message );
16484 /* sent message */
16485 flush_sequence();
16486 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
16487 ok_sequence( WmEmptySeq, "no messages", FALSE );
16488 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
16489 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16490 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16491 ok( !ret, "got message %x\n", msg.message );
16493 /* sent message with timeout */
16494 flush_sequence();
16495 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
16496 ok_sequence( WmEmptySeq, "no messages", FALSE );
16497 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
16498 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16499 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16500 ok( !ret, "got message %x\n", msg.message );
16502 /* sent message with timeout and callback */
16503 flush_sequence();
16504 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
16505 ok_sequence( WmEmptySeq, "no messages", FALSE );
16506 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
16507 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16508 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16509 ok( !ret, "got message %x\n", msg.message );
16511 /* sent message with callback */
16512 flush_sequence();
16513 SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
16514 ok_sequence( WmEmptySeq, "no messages", FALSE );
16515 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
16516 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16517 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16518 ok( !ret, "got message %x\n", msg.message );
16520 /* direct window proc call */
16521 flush_sequence();
16522 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
16523 ok_sequence( WmEmptySeq, "no messages", FALSE );
16524 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
16525 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16527 /* dispatch message */
16528 msg.hwnd = hwnd;
16529 msg.message = WM_CHAR;
16530 msg.wParam = dbch[0];
16531 msg.lParam = 0;
16532 DispatchMessageA( &msg );
16533 ok_sequence( WmEmptySeq, "no messages", FALSE );
16534 msg.wParam = dbch[1];
16535 DispatchMessageA( &msg );
16536 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16538 /* window handle is irrelevant */
16539 flush_sequence();
16540 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
16541 ok_sequence( WmEmptySeq, "no messages", FALSE );
16542 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
16543 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16544 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16545 ok( !ret, "got message %x\n", msg.message );
16547 /* interleaved post and send */
16548 flush_sequence();
16549 PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
16550 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
16551 ok_sequence( WmEmptySeq, "no messages", FALSE );
16552 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16553 ok( !ret, "got message %x\n", msg.message );
16554 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
16555 ok_sequence( WmEmptySeq, "no messages", FALSE );
16556 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16557 ok( ret, "no message\n" );
16558 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16559 ok( msg.wParam == wch, "bad wparam %Ix/%x\n", msg.wParam, wch );
16560 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16561 ok( !ret, "got message %x\n", msg.message );
16562 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
16563 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16564 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16565 ok( !ret, "got message %x\n", msg.message );
16567 /* interleaved sent message and winproc */
16568 flush_sequence();
16569 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
16570 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
16571 ok_sequence( WmEmptySeq, "no messages", FALSE );
16572 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
16573 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16574 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
16575 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16577 /* interleaved winproc and dispatch */
16578 msg.hwnd = hwnd;
16579 msg.message = WM_CHAR;
16580 msg.wParam = dbch[0];
16581 msg.lParam = 0;
16582 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
16583 DispatchMessageA( &msg );
16584 ok_sequence( WmEmptySeq, "no messages", FALSE );
16585 msg.wParam = dbch[1];
16586 DispatchMessageA( &msg );
16587 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16588 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
16589 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16591 /* interleaved sends */
16592 flush_sequence();
16593 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
16594 SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
16595 ok_sequence( WmEmptySeq, "no messages", FALSE );
16596 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
16597 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16598 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
16599 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16601 /* dbcs WM_CHAR */
16602 flush_sequence();
16603 SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
16604 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16605 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16606 ok( !ret, "got message %x\n", msg.message );
16608 /* other char messages are not magic */
16609 PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
16610 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16611 ok( ret, "no message\n" );
16612 ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
16613 ok( msg.wParam == bad_wch, "bad wparam %Ix/%x\n", msg.wParam, bad_wch );
16614 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16615 ok( !ret, "got message %x\n", msg.message );
16616 PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
16617 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16618 ok( ret, "no message\n" );
16619 ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
16620 ok( msg.wParam == bad_wch, "bad wparam %Ix/%x\n", msg.wParam, bad_wch );
16621 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16622 ok( !ret, "got message %x\n", msg.message );
16624 /* test retrieving messages */
16626 PostMessageW( hwnd, WM_CHAR, wch, 0 );
16627 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
16628 ok( ret, "no message\n" );
16629 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
16630 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16631 ok( msg.wParam == dbch[0], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
16632 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
16633 ok( ret, "no message\n" );
16634 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
16635 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16636 ok( msg.wParam == dbch[1], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
16637 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
16638 ok( !ret, "got message %x\n", msg.message );
16640 /* message filters */
16641 PostMessageW( hwnd, WM_CHAR, wch, 0 );
16642 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
16643 ok( ret, "no message\n" );
16644 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
16645 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16646 ok( msg.wParam == dbch[0], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
16647 /* message id is filtered, hwnd is not */
16648 ret = PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE );
16649 ok( !ret, "no message\n" );
16650 ret = PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE );
16651 ok( ret, "no message\n" );
16652 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
16653 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16654 ok( msg.wParam == dbch[1], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
16655 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
16656 ok( !ret, "got message %x\n", msg.message );
16658 /* mixing GetMessage and PostMessage */
16659 PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
16660 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
16661 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
16662 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16663 ok( msg.wParam == dbch[0], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
16664 ok( msg.lParam == 0xbeef, "bad lparam %Ix\n", msg.lParam );
16665 time = msg.time;
16666 pt = msg.pt;
16667 ok( time - GetTickCount() <= 100, "bad time %lx\n", msg.time );
16668 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
16669 ok( ret, "no message\n" );
16670 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
16671 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16672 ok( msg.wParam == dbch[1], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
16673 ok( msg.lParam == 0xbeef, "bad lparam %Ix\n", msg.lParam );
16674 ok( msg.time == time, "bad time %lx/%lx\n", msg.time, time );
16675 ok( msg.pt.x == pt.x && msg.pt.y == pt.y, "bad point %lu,%lu/%lu,%lu\n", msg.pt.x, msg.pt.y, pt.x, pt.y );
16676 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
16677 ok( !ret, "got message %x\n", msg.message );
16679 /* without PM_REMOVE */
16680 PostMessageW( hwnd, WM_CHAR, wch, 0 );
16681 ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
16682 ok( ret, "no message\n" );
16683 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
16684 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16685 ok( msg.wParam == dbch[0], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
16686 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
16687 ok( ret, "no message\n" );
16688 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
16689 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16690 ok( msg.wParam == dbch[0], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
16691 ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
16692 ok( ret, "no message\n" );
16693 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
16694 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16695 ok( msg.wParam == dbch[1], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
16696 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
16697 ok( ret, "no message\n" );
16698 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
16699 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16700 ok( msg.wParam == dbch[1], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
16701 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
16702 ok( !ret, "got message %x\n", msg.message );
16704 DestroyWindow(hwnd);
16705 DestroyWindow(hwnd2);
16708 static void test_unicode_wm_char(void)
16710 HWND hwnd;
16711 MSG msg;
16712 struct message seq[2];
16713 HKL hkl_orig, hkl_greek;
16714 DWORD cp;
16715 LCID thread_locale;
16717 hkl_orig = GetKeyboardLayout( 0 );
16718 GetLocaleInfoW( LOWORD( hkl_orig ), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, (WCHAR*)&cp, sizeof(cp) / sizeof(WCHAR) );
16719 if (cp != 1252)
16721 skip( "Default codepage %ld\n", cp );
16722 return;
16725 hkl_greek = LoadKeyboardLayoutA( "00000408", 0 );
16726 if (!hkl_greek || hkl_greek == hkl_orig /* win2k */)
16728 skip( "Unable to load Greek keyboard layout\n" );
16729 return;
16732 hwnd = CreateWindowExW( 0, testWindowClassW, NULL, WS_OVERLAPPEDWINDOW,
16733 100, 100, 200, 200, 0, 0, 0, NULL );
16734 flush_sequence();
16736 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
16738 while (GetMessageW( &msg, hwnd, 0, 0 ))
16740 if (!ignore_message( msg.message )) break;
16743 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
16744 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16745 ok( msg.wParam == 0x3b1, "bad wparam %Ix\n", msg.wParam );
16746 ok( msg.lParam == 0, "bad lparam %Ix\n", msg.lParam );
16748 DispatchMessageW( &msg );
16750 memset( seq, 0, sizeof(seq) );
16751 seq[0].message = WM_CHAR;
16752 seq[0].flags = sent|wparam;
16753 seq[0].wParam = 0x3b1;
16755 ok_sequence( seq, "unicode WM_CHAR", FALSE );
16757 flush_sequence();
16759 /* greek alpha -> 'a' in cp1252 */
16760 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
16762 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
16763 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
16764 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16765 ok( msg.wParam == 0x61, "bad wparam %Ix\n", msg.wParam );
16766 ok( msg.lParam == 0, "bad lparam %Ix\n", msg.lParam );
16768 DispatchMessageA( &msg );
16770 seq[0].wParam = 0x61;
16771 ok_sequence( seq, "unicode WM_CHAR", FALSE );
16773 thread_locale = GetThreadLocale();
16774 ActivateKeyboardLayout( hkl_greek, 0 );
16775 ok( GetThreadLocale() == thread_locale, "locale changed from %08lx to %08lx\n",
16776 thread_locale, GetThreadLocale() );
16778 flush_sequence();
16780 /* greek alpha -> 0xe1 in cp1253 */
16781 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
16783 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
16784 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
16785 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16786 ok( msg.wParam == 0xe1, "bad wparam %Ix\n", msg.wParam );
16787 ok( msg.lParam == 0, "bad lparam %Ix\n", msg.lParam );
16789 DispatchMessageA( &msg );
16791 seq[0].wParam = 0x3b1;
16792 ok_sequence( seq, "unicode WM_CHAR", FALSE );
16794 DestroyWindow( hwnd );
16795 ActivateKeyboardLayout( hkl_orig, 0 );
16798 #define ID_LISTBOX 0x000f
16800 static const struct message wm_lb_setcursel_0[] =
16802 { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
16803 { WM_CTLCOLORLISTBOX, sent|parent },
16804 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
16805 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 1 },
16806 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 1 },
16807 { 0 }
16809 static const struct message wm_lb_setcursel_1[] =
16811 { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
16812 { WM_CTLCOLORLISTBOX, sent|parent },
16813 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
16814 { WM_CTLCOLORLISTBOX, sent|parent },
16815 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
16816 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 2 },
16817 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 2 },
16818 { 0 }
16820 static const struct message wm_lb_setcursel_2[] =
16822 { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
16823 { WM_CTLCOLORLISTBOX, sent|parent },
16824 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
16825 { WM_CTLCOLORLISTBOX, sent|parent },
16826 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
16827 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 3 },
16828 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 3 },
16829 { 0 }
16831 static const struct message wm_lb_click_0[] =
16833 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
16834 { HCBT_SETFOCUS, hook },
16835 { WM_KILLFOCUS, sent|parent },
16836 { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
16837 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
16838 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
16839 { WM_SETFOCUS, sent|defwinproc },
16841 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
16842 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
16843 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 3 },
16844 { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
16845 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
16847 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
16848 { WM_CTLCOLORLISTBOX, sent|parent },
16849 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
16850 { WM_CTLCOLORLISTBOX, sent|parent },
16851 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
16852 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
16854 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 1 },
16855 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 1 },
16857 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
16858 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
16859 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
16860 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
16861 { 0 }
16863 static const struct message wm_lb_deletestring[] =
16865 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
16866 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 1 },
16867 { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
16868 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
16869 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
16870 { 0 }
16872 static const struct message wm_lb_deletestring_reset[] =
16874 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
16875 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 1 },
16876 { LB_RESETCONTENT, sent|wparam|lparam|defwinproc|optional, 0, 0 },
16877 { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
16878 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
16879 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
16880 { 0 }
16882 static const struct message wm_lb_addstring[] =
16884 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
16885 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 1 },
16886 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
16887 /* Child ID changes each test, don't test lparam. */
16888 { EVENT_OBJECT_CREATE, winevent_hook|wparam|msg_todo, OBJID_CLIENT, 0 },
16889 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
16890 { EVENT_OBJECT_CREATE, winevent_hook|wparam|msg_todo, OBJID_CLIENT, 0 },
16891 { 0 }
16893 static const struct message wm_lb_addstring_ownerdraw[] =
16895 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
16896 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf0f2, 0xf30604ed },
16897 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 1 },
16898 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
16899 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf1f2, 0xf30604ee },
16900 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 2 },
16901 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
16902 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf2f2, 0xf30604ef },
16903 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 3 },
16904 { 0 }
16906 static const struct message wm_lb_addstring_sort_ownerdraw[] =
16908 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
16909 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf0f2, 0xf30604ed },
16910 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 1 },
16911 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
16912 { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ed, 0xf30604ee },
16913 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf1f2, 0xf30604ee },
16914 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 2 },
16915 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
16916 { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ed, 0xf30604ef },
16917 { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ee, 0xf30604ef },
16918 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf2f2, 0xf30604ef },
16919 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 3 },
16920 { 0 }
16922 static const struct message wm_lb_dblclick_0[] =
16924 { WM_LBUTTONDBLCLK, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
16925 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
16926 { 0 }
16929 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
16931 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
16933 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
16935 static LONG defwndproc_counter = 0;
16936 LRESULT ret;
16937 struct recvd_message msg;
16939 /* do not log painting messages */
16940 if (message != WM_PAINT &&
16941 message != WM_NCPAINT &&
16942 message != WM_SYNCPAINT &&
16943 message != WM_ERASEBKGND &&
16944 message != WM_NCHITTEST &&
16945 message != WM_GETTEXT &&
16946 !ignore_message( message ))
16948 msg.hwnd = hwnd;
16949 msg.message = message;
16950 msg.flags = sent|wparam|lparam;
16951 if (defwndproc_counter) msg.flags |= defwinproc;
16952 msg.wParam = wp;
16953 if (message == LB_ADDSTRING)
16954 msg.lParam = lp ? hash_Ly((const char *)lp) : 0;
16955 else
16956 msg.lParam = lp;
16957 msg.descr = "listbox";
16958 add_message(&msg);
16961 defwndproc_counter++;
16962 ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
16963 defwndproc_counter--;
16965 return ret;
16968 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
16969 int caret_index, int top_index, int line)
16971 LRESULT ret;
16973 /* calling an orig proc helps to avoid unnecessary message logging */
16974 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
16975 ok_(__FILE__, line)(ret == count, "expected count %d, got %Id\n", count, ret);
16976 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
16977 ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %Id\n", cur_sel, ret);
16978 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
16979 ok_(__FILE__, line)(ret == caret_index ||
16980 broken(cur_sel == -1 && caret_index == 0 && ret == -1), /* nt4 */
16981 "expected caret index %d, got %Id\n", caret_index, ret);
16982 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
16983 ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %Id\n", top_index, ret);
16986 static void test_listbox_messages(void)
16988 HWND parent, listbox;
16989 LRESULT ret;
16991 parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
16992 100, 100, 200, 200, 0, 0, 0, NULL);
16993 /* with LBS_HASSTRINGS */
16994 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
16995 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
16996 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
16997 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
16999 check_lb_state(listbox, 0, LB_ERR, 0, 0);
17001 flush_sequence();
17003 log_all_parent_messages++;
17005 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
17006 ok(ret == 0, "expected 0, got %Id\n", ret);
17007 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
17008 ok(ret == 1, "expected 1, got %Id\n", ret);
17009 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
17010 ok(ret == 2, "expected 2, got %Id\n", ret);
17012 ok_sequence(wm_lb_addstring_ownerdraw, "LB_ADDSTRING", FALSE);
17013 check_lb_state(listbox, 3, LB_ERR, 0, 0);
17015 flush_sequence();
17017 if (winetest_debug > 1) trace("selecting item 0\n");
17018 ret = SendMessageA(listbox, LB_SETCURSEL, 0, 0);
17019 ok(ret == 0, "expected 0, got %Id\n", ret);
17020 ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
17021 check_lb_state(listbox, 3, 0, 0, 0);
17022 flush_sequence();
17024 if (winetest_debug > 1) trace("selecting item 1\n");
17025 ret = SendMessageA(listbox, LB_SETCURSEL, 1, 0);
17026 ok(ret == 1, "expected 1, got %Id\n", ret);
17027 ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
17028 check_lb_state(listbox, 3, 1, 1, 0);
17030 if (winetest_debug > 1) trace("selecting item 2\n");
17031 ret = SendMessageA(listbox, LB_SETCURSEL, 2, 0);
17032 ok(ret == 2, "expected 2, got %Id\n", ret);
17033 ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
17034 check_lb_state(listbox, 3, 2, 2, 0);
17036 if (winetest_debug > 1) trace("clicking on item 0\n");
17037 ret = SendMessageA(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
17038 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
17039 ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0);
17040 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
17041 ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
17042 check_lb_state(listbox, 3, 0, 0, 0);
17043 flush_sequence();
17045 if (winetest_debug > 1) trace("deleting item 0\n");
17046 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
17047 ok(ret == 2, "expected 2, got %Id\n", ret);
17048 ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
17049 check_lb_state(listbox, 2, -1, 0, 0);
17050 flush_sequence();
17052 if (winetest_debug > 1) trace("deleting item 0\n");
17053 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
17054 ok(ret == 1, "expected 1, got %Id\n", ret);
17055 ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
17056 check_lb_state(listbox, 1, -1, 0, 0);
17057 flush_sequence();
17059 if (winetest_debug > 1) trace("deleting item 0\n");
17060 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
17061 ok(ret == 0, "expected 0, got %Id\n", ret);
17062 ok_sequence(wm_lb_deletestring_reset, "LB_DELETESTRING 0", FALSE );
17063 check_lb_state(listbox, 0, -1, 0, 0);
17064 flush_sequence();
17066 if (winetest_debug > 1) trace("deleting item 0\n");
17067 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
17068 ok(ret == LB_ERR, "expected LB_ERR, got %Id\n", ret);
17069 check_lb_state(listbox, 0, -1, 0, 0);
17070 flush_sequence();
17072 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
17073 ok(ret == LB_ERR, "expected LB_ERR, got %Id\n", ret);
17074 check_lb_state(listbox, 0, LB_ERR, 0, 0);
17075 flush_sequence();
17077 ret = SendMessageA(listbox, LB_RESETCONTENT, 0, 0);
17078 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
17079 check_lb_state(listbox, 0, LB_ERR, 0, 0);
17080 flush_sequence();
17082 if (winetest_debug > 1) trace("clicking on item 0\n");
17083 ret = SendMessageA(listbox, WM_LBUTTONDBLCLK, 0, MAKELPARAM(1, 1));
17084 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
17085 ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0);
17086 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
17087 ok_sequence(wm_lb_dblclick_0, "WM_LBUTTONDBLCLK 0", FALSE );
17088 check_lb_state(listbox, 0, LB_ERR, 0, 0);
17089 flush_sequence();
17091 log_all_parent_messages--;
17093 DestroyWindow(listbox);
17095 /* with LBS_SORT and without LBS_HASSTRINGS */
17096 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
17097 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_SORT | WS_VISIBLE,
17098 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
17099 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
17101 check_lb_state(listbox, 0, LB_ERR, 0, 0);
17103 flush_sequence();
17105 log_all_parent_messages++;
17107 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
17108 ok(ret == 0, "expected 0, got %Id\n", ret);
17109 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
17110 ok(ret == 1, "expected 1, got %Id\n", ret);
17111 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
17112 ok(ret == 2, "expected 2, got %Id\n", ret);
17114 ok_sequence(wm_lb_addstring_sort_ownerdraw, "LB_ADDSTRING", FALSE);
17115 check_lb_state(listbox, 3, LB_ERR, 0, 0);
17117 ret = SendMessageA(listbox, LB_RESETCONTENT, 0, 0);
17118 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
17119 check_lb_state(listbox, 0, LB_ERR, 0, 0);
17120 SetFocus(listbox); /* avoid focus messages */
17121 flush_sequence();
17123 if (winetest_debug > 1) trace("clicking on item 0\n");
17124 ret = SendMessageA(listbox, WM_LBUTTONDBLCLK, 0, MAKELPARAM(1, 1));
17125 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
17126 ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0);
17127 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
17128 ok_sequence(wm_lb_dblclick_0, "WM_LBUTTONDBLCLK 0", FALSE );
17129 check_lb_state(listbox, 0, LB_ERR, 0, 0);
17130 flush_sequence();
17132 log_all_parent_messages--;
17134 DestroyWindow(listbox);
17136 /* with LBS_HASSTRINGS */
17137 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
17138 WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | WS_VISIBLE,
17139 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
17140 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
17142 check_lb_state(listbox, 0, LB_ERR, 0, 0);
17144 flush_sequence();
17146 log_all_parent_messages++;
17148 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
17149 ok(ret == 0, "expected 0, got %Id\n", ret);
17150 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
17151 ok(ret == 1, "expected 1, got %Id\n", ret);
17152 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
17153 ok(ret == 2, "expected 2, got %Id\n", ret);
17155 ok_sequence(wm_lb_addstring, "LB_ADDSTRING", FALSE);
17156 check_lb_state(listbox, 3, LB_ERR, 0, 0);
17158 ret = SendMessageA(listbox, LB_RESETCONTENT, 0, 0);
17159 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
17160 check_lb_state(listbox, 0, LB_ERR, 0, 0);
17161 SetFocus(listbox); /* avoid focus messages */
17162 flush_sequence();
17164 if (winetest_debug > 1) trace("clicking on item 0\n");
17165 ret = SendMessageA(listbox, WM_LBUTTONDBLCLK, 0, MAKELPARAM(1, 1));
17166 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
17167 ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0);
17168 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
17169 ok_sequence(wm_lb_dblclick_0, "WM_LBUTTONDBLCLK 0", FALSE );
17170 check_lb_state(listbox, 0, LB_ERR, 0, 0);
17171 flush_sequence();
17173 log_all_parent_messages--;
17175 DestroyWindow(listbox);
17177 /* with LBS_HASSTRINGS and LBS_SORT */
17178 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
17179 WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | LBS_SORT | WS_VISIBLE,
17180 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
17181 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
17183 check_lb_state(listbox, 0, LB_ERR, 0, 0);
17185 flush_sequence();
17187 log_all_parent_messages++;
17189 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
17190 ok(ret == 0, "expected 0, got %Id\n", ret);
17191 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
17192 ok(ret == 0, "expected 0, got %Id\n", ret);
17193 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
17194 ok(ret == 1, "expected 1, got %Id\n", ret);
17196 ok_sequence(wm_lb_addstring, "LB_ADDSTRING", FALSE);
17197 check_lb_state(listbox, 3, LB_ERR, 0, 0);
17199 ret = SendMessageA(listbox, LB_RESETCONTENT, 0, 0);
17200 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
17201 check_lb_state(listbox, 0, LB_ERR, 0, 0);
17202 SetFocus(listbox); /* avoid focus messages */
17203 flush_sequence();
17205 if (winetest_debug > 1) trace("clicking on item 0\n");
17206 ret = SendMessageA(listbox, WM_LBUTTONDBLCLK, 0, MAKELPARAM(1, 1));
17207 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
17208 ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0);
17209 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
17210 ok_sequence(wm_lb_dblclick_0, "WM_LBUTTONDBLCLK 0", FALSE );
17211 check_lb_state(listbox, 0, LB_ERR, 0, 0);
17212 flush_sequence();
17214 log_all_parent_messages--;
17216 DestroyWindow(listbox);
17217 DestroyWindow(parent);
17220 /*************************** Menu test ******************************/
17221 static const struct message wm_popup_menu_1[] =
17223 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
17224 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
17225 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
17226 { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
17227 { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
17228 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
17229 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
17230 { WM_INITMENU, sent|lparam, 0, 0 },
17231 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
17232 { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
17233 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
17234 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
17235 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
17236 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
17237 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
17238 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
17239 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
17240 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 1 },
17241 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
17242 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
17243 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001, 0, 0x40000000 },
17244 { EVENT_OBJECT_INVOKED, winevent_hook|wparam|lparam|msg_todo, OBJID_MENU, 0 },
17245 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
17246 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
17247 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
17248 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
17249 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
17250 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
17251 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
17252 { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
17253 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
17254 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
17255 { 0 }
17257 static const struct message wm_popup_menu_2[] =
17259 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
17260 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
17261 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
17262 { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
17263 { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
17264 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
17265 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
17266 { WM_INITMENU, sent|lparam, 0, 0 },
17267 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
17268 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
17269 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
17270 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
17271 { HCBT_CREATEWND, hook },
17272 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
17273 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
17274 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
17275 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
17276 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
17277 { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
17278 |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
17279 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 1 },
17280 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
17281 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
17282 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
17283 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
17284 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
17285 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
17286 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
17287 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
17288 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
17289 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
17290 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
17291 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 1 },
17292 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
17293 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
17294 { EVENT_OBJECT_INVOKED, winevent_hook|wparam|lparam|msg_todo, OBJID_MENU, 0 },
17295 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
17296 { HCBT_DESTROYWND, hook },
17297 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
17298 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
17299 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
17300 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
17301 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
17302 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
17303 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
17304 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
17305 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
17306 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
17307 { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
17308 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
17309 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
17310 { 0 }
17312 static const struct message wm_popup_menu_3[] =
17314 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
17315 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
17316 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
17317 { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
17318 { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
17319 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
17320 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
17321 { WM_INITMENU, sent|lparam, 0, 0 },
17322 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
17323 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
17324 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
17325 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
17326 { HCBT_CREATEWND, hook },
17327 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
17328 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
17329 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
17330 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
17331 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
17332 { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
17333 |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
17334 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 1 },
17335 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
17336 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
17337 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
17338 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
17339 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
17340 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
17341 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
17342 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
17343 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
17344 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
17345 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
17346 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 1 },
17347 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
17348 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
17349 { EVENT_OBJECT_INVOKED, winevent_hook|wparam|lparam|msg_todo, OBJID_MENU, 100 },
17350 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
17351 { HCBT_DESTROYWND, hook },
17352 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
17353 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
17354 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
17355 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 },
17356 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
17357 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
17358 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
17359 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
17360 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
17361 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
17362 { WM_COMMAND, sent|wparam|lparam, 100, 0 },
17363 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
17364 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
17365 { 0 }
17368 static const struct message wm_single_menu_item[] =
17370 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
17371 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
17372 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0x20000001 },
17373 { WM_SYSKEYDOWN, sent|wparam|lparam, 'Q', 0x20000001 },
17374 { WM_SYSCHAR, sent|wparam|lparam, 'q', 0x20000001 },
17375 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'q' },
17376 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
17377 { WM_INITMENU, sent|lparam, 0, 0 },
17378 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(300,MF_HILITE) },
17379 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
17380 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
17381 { WM_MENUCOMMAND, sent },
17382 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0xe0000001 },
17383 { WM_SYSKEYUP, sent|wparam|lparam, 'Q', 0xe0000001 },
17384 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 },
17385 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
17387 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 1 },
17388 { WM_KEYDOWN, sent|wparam|lparam, VK_ESCAPE, 1 },
17389 { WM_CHAR, sent|wparam|lparam, VK_ESCAPE, 0x00000001 },
17390 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 },
17391 { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
17392 { 0 }
17395 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
17397 if (message == WM_ENTERIDLE ||
17398 message == WM_INITMENU ||
17399 message == WM_INITMENUPOPUP ||
17400 message == WM_MENUSELECT ||
17401 message == WM_PARENTNOTIFY ||
17402 message == WM_ENTERMENULOOP ||
17403 message == WM_EXITMENULOOP ||
17404 message == WM_UNINITMENUPOPUP ||
17405 message == WM_KEYDOWN ||
17406 message == WM_KEYUP ||
17407 message == WM_CHAR ||
17408 message == WM_SYSKEYDOWN ||
17409 message == WM_SYSKEYUP ||
17410 message == WM_SYSCHAR ||
17411 message == WM_COMMAND ||
17412 message == WM_MENUCOMMAND)
17414 struct recvd_message msg;
17416 msg.hwnd = hwnd;
17417 msg.message = message;
17418 msg.flags = sent|wparam|lparam;
17419 msg.wParam = wp;
17420 msg.lParam = lp;
17421 msg.descr = "parent_menu_proc";
17422 add_message(&msg);
17425 return DefWindowProcA(hwnd, message, wp, lp);
17428 static void set_menu_style(HMENU hmenu, DWORD style)
17430 MENUINFO mi;
17431 BOOL ret;
17433 mi.cbSize = sizeof(mi);
17434 mi.fMask = MIM_STYLE;
17435 mi.dwStyle = style;
17436 SetLastError(0xdeadbeef);
17437 ret = SetMenuInfo(hmenu, &mi);
17438 ok(ret, "SetMenuInfo error %lu\n", GetLastError());
17441 static DWORD get_menu_style(HMENU hmenu)
17443 MENUINFO mi;
17444 BOOL ret;
17446 mi.cbSize = sizeof(mi);
17447 mi.fMask = MIM_STYLE;
17448 mi.dwStyle = 0;
17449 SetLastError(0xdeadbeef);
17450 ret = GetMenuInfo(hmenu, &mi);
17451 ok(ret, "GetMenuInfo error %lu\n", GetLastError());
17453 return mi.dwStyle;
17456 static void test_menu_messages(void)
17458 MSG msg;
17459 WNDCLASSA cls;
17460 HMENU hmenu, hmenu_popup;
17461 HWND hwnd;
17462 DWORD style;
17463 BOOL us_kbd = (GetKeyboardLayout(0) == (HKL)(ULONG_PTR)0x04090409);
17465 cls.style = 0;
17466 cls.lpfnWndProc = parent_menu_proc;
17467 cls.cbClsExtra = 0;
17468 cls.cbWndExtra = 0;
17469 cls.hInstance = GetModuleHandleA(0);
17470 cls.hIcon = 0;
17471 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
17472 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
17473 cls.lpszMenuName = NULL;
17474 cls.lpszClassName = "TestMenuClass";
17475 UnregisterClassA(cls.lpszClassName, cls.hInstance);
17476 register_class(&cls);
17478 SetLastError(0xdeadbeef);
17479 hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
17480 100, 100, 200, 200, 0, 0, 0, NULL);
17481 ok(hwnd != 0, "LoadMenuA error %lu\n", GetLastError());
17483 SetLastError(0xdeadbeef);
17484 hmenu = LoadMenuA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
17485 ok(hmenu != 0, "LoadMenuA error %lu\n", GetLastError());
17487 SetMenu(hwnd, hmenu);
17488 SetForegroundWindow( hwnd );
17489 flush_events();
17491 set_menu_style(hmenu, MNS_NOTIFYBYPOS);
17492 style = get_menu_style(hmenu);
17493 ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %lu\n", style);
17495 hmenu_popup = GetSubMenu(hmenu, 0);
17496 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
17497 style = get_menu_style(hmenu_popup);
17498 ok(style == 0, "expected 0, got %lu\n", style);
17500 hmenu_popup = GetSubMenu(hmenu_popup, 0);
17501 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
17502 style = get_menu_style(hmenu_popup);
17503 ok(style == 0, "expected 0, got %lu\n", style);
17505 if (!us_kbd)
17507 skip("skipping ascii VK events on non-us keyboard\n");
17508 goto done;
17511 /* Alt+E, Enter */
17512 if (winetest_debug > 1) trace("testing a popup menu command\n");
17513 flush_sequence();
17514 keybd_event(VK_MENU, 0, 0, 0);
17515 keybd_event('E', 0, 0, 0);
17516 keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
17517 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
17518 keybd_event(VK_RETURN, 0, 0, 0);
17519 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
17520 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
17522 TranslateMessage(&msg);
17523 DispatchMessageA(&msg);
17525 if (!sequence_cnt) /* we didn't get any message */
17527 skip( "queuing key events not supported\n" );
17528 goto done;
17530 /* win98 queues only a WM_KEYUP and doesn't start menu tracking */
17531 if (sequence[0].message == WM_KEYUP && sequence[0].wParam == VK_MENU)
17533 win_skip( "menu tracking through VK_MENU not supported\n" );
17534 goto done;
17536 ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
17538 /* Alt+F, Right, Enter */
17539 if (winetest_debug > 1) trace("testing submenu of a popup menu command\n");
17540 flush_sequence();
17541 keybd_event(VK_MENU, 0, 0, 0);
17542 keybd_event('F', 0, 0, 0);
17543 keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
17544 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
17545 keybd_event(VK_RIGHT, 0, 0, 0);
17546 keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
17547 keybd_event(VK_RETURN, 0, 0, 0);
17548 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
17549 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
17551 TranslateMessage(&msg);
17552 DispatchMessageA(&msg);
17554 ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
17556 if (winetest_debug > 1) trace("testing single menu item command\n");
17557 flush_sequence();
17558 keybd_event(VK_MENU, 0, 0, 0);
17559 keybd_event('Q', 0, 0, 0);
17560 keybd_event('Q', 0, KEYEVENTF_KEYUP, 0);
17561 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
17562 keybd_event(VK_ESCAPE, 0, 0, 0);
17563 keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
17564 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
17566 TranslateMessage(&msg);
17567 DispatchMessageA(&msg);
17569 ok_sequence(wm_single_menu_item, "single menu item command", FALSE);
17571 set_menu_style(hmenu, 0);
17572 style = get_menu_style(hmenu);
17573 ok(style == 0, "expected 0, got %lu\n", style);
17575 hmenu_popup = GetSubMenu(hmenu, 0);
17576 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
17577 set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
17578 style = get_menu_style(hmenu_popup);
17579 ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %lu\n", style);
17581 hmenu_popup = GetSubMenu(hmenu_popup, 0);
17582 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
17583 style = get_menu_style(hmenu_popup);
17584 ok(style == 0, "expected 0, got %lu\n", style);
17586 /* Alt+F, Right, Enter */
17587 if (winetest_debug > 1) trace("testing submenu of a popup menu command\n");
17588 flush_sequence();
17589 keybd_event(VK_MENU, 0, 0, 0);
17590 keybd_event('F', 0, 0, 0);
17591 keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
17592 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
17593 keybd_event(VK_RIGHT, 0, 0, 0);
17594 keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
17595 keybd_event(VK_RETURN, 0, 0, 0);
17596 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
17597 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
17599 TranslateMessage(&msg);
17600 DispatchMessageA(&msg);
17602 ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
17604 done:
17605 DestroyWindow(hwnd);
17606 DestroyMenu(hmenu);
17610 static void test_paintingloop(void)
17612 HWND hwnd;
17614 paint_loop_done = FALSE;
17615 hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
17616 "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
17617 100, 100, 100, 100, 0, 0, 0, NULL );
17618 ok(hwnd != 0, "PaintLoop window error %lu\n", GetLastError());
17619 ShowWindow(hwnd,SW_NORMAL);
17620 SetFocus(hwnd);
17622 while (!paint_loop_done)
17624 MSG msg;
17625 if (PeekMessageA(&msg, 0, 0, 0, 1))
17627 TranslateMessage(&msg);
17628 DispatchMessageA(&msg);
17631 DestroyWindow(hwnd);
17634 static const struct message NCRBUTTONDOWNSeq[] =
17636 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
17637 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
17638 { WM_CAPTURECHANGED, sent },
17639 { WM_CONTEXTMENU, sent, /*hwnd*/0, -1 },
17640 { 0 }
17643 static const struct message NCXBUTTONUPSeq1[] =
17645 { WM_APPCOMMAND, sent|lparam, /*hwnd*/0, MAKELPARAM(0, FAPPCOMMAND_MOUSE | APPCOMMAND_BROWSER_BACKWARD) },
17646 { 0 }
17649 static const struct message NCXBUTTONUPSeq2[] =
17651 { WM_APPCOMMAND, sent|lparam, /*hwnd*/0, MAKELPARAM(0, FAPPCOMMAND_MOUSE | APPCOMMAND_BROWSER_FORWARD) },
17652 { 0 }
17655 /* DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0) to minimized visible window */
17656 static const struct message WmRestoreMinimizedOverlappedSeq[] =
17658 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_RESTORE, 0 },
17659 { HCBT_MINMAX, hook },
17660 { WM_QUERYOPEN, sent },
17661 { WM_GETTEXT, sent|optional },
17662 { WM_NCACTIVATE, sent|optional },
17663 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
17664 { WM_WINDOWPOSCHANGED, sent|optional },
17665 { WM_WINDOWPOSCHANGING, sent|optional },
17666 { WM_GETMINMAXINFO, sent|defwinproc },
17667 { WM_NCCALCSIZE, sent|optional },
17668 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
17669 { WM_NCPAINT, sent|optional },
17670 { WM_GETTEXT, sent|defwinproc|optional },
17671 { WM_ERASEBKGND, sent|optional },
17672 { WM_WINDOWPOSCHANGED, sent|optional },
17673 { HCBT_ACTIVATE, hook },
17674 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
17675 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
17676 { WM_ACTIVATEAPP, sent|wparam, TRUE },
17677 { WM_NCACTIVATE, sent|wparam, TRUE },
17678 { WM_GETTEXT, sent|defwinproc|optional },
17679 { WM_ACTIVATE, sent|wparam, TRUE },
17680 { HCBT_SETFOCUS, hook },
17681 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
17682 { WM_SETFOCUS, sent|defwinproc },
17683 { WM_NCPAINT, sent },
17684 { WM_GETTEXT, sent|defwinproc|optional },
17685 { WM_ERASEBKGND, sent },
17686 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_FRAMECHANGED|SWP_STATECHANGED },
17687 { WM_MOVE, sent|defwinproc },
17688 { WM_SIZE, sent|defwinproc },
17689 { WM_NCCALCSIZE, sent|optional },
17690 { WM_NCPAINT, sent|optional },
17691 { WM_ERASEBKGND, sent|optional },
17692 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
17693 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
17694 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
17695 { WM_ACTIVATE, sent|wparam, TRUE },
17696 { WM_SYNCPAINT, sent|optional },
17697 { WM_PAINT, sent },
17698 { 0 }
17701 /* DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0) to an active minimized window */
17702 static const struct message WmRestoreActiveMinimizedOverlappedSeq[] =
17704 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_RESTORE, 0 },
17705 { HCBT_MINMAX, hook },
17706 { WM_QUERYOPEN, sent },
17707 { WM_GETTEXT, sent|optional },
17708 { WM_NCACTIVATE, sent },
17709 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
17710 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
17711 { WM_NCCALCSIZE, sent|optional },
17712 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sent on Win7. */
17713 { WM_MOVE, sent|optional },
17714 { WM_SIZE, sent|optional },
17715 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sent on Win7. */
17716 { WM_GETTEXT, sent|optional },
17717 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
17718 { WM_GETMINMAXINFO, sent|defwinproc },
17719 { WM_NCCALCSIZE, sent },
17720 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sent on Win8+. */
17721 { WM_NCPAINT, sent },
17722 { WM_GETTEXT, sent|defwinproc|optional },
17723 { WM_ERASEBKGND, sent },
17724 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
17725 { WM_MOVE, sent|defwinproc },
17726 { WM_SIZE, sent|defwinproc },
17727 { WM_NCCALCSIZE, sent|optional },
17728 { WM_NCPAINT, sent|optional },
17729 { WM_ERASEBKGND, sent|optional },
17730 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
17731 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
17732 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
17733 { HCBT_SETFOCUS, hook },
17734 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
17735 { WM_SETFOCUS, sent },
17736 /* Note this WM_ACTIVATE messages even if the window is already active */
17737 { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, 0 },
17738 { WM_SYNCPAINT, sent|optional },
17739 { WM_PAINT, sent },
17740 { WM_GETMINMAXINFO, sent|optional },
17741 { 0 }
17744 static struct message WmContextMenuSeq[] = {
17745 { WM_CONTEXTMENU, sent|wparam, 0 }, /* wparams set in the code */
17746 { WM_CONTEXTMENU, sent|wparam|defwinproc, 0 },
17747 { WM_CONTEXTMENU, sent|wparam|defwinproc, 0 },
17748 { 0 }
17751 struct rbuttonup_thread_data
17753 HWND hwnd;
17754 HANDLE wndproc_finished;
17757 static DWORD CALLBACK post_rbuttonup_msg( void *arg )
17759 struct rbuttonup_thread_data *data = arg;
17760 DWORD ret;
17762 ret = WaitForSingleObject( data->wndproc_finished, 500 );
17763 todo_wine ok( ret == WAIT_OBJECT_0, "WaitForSingleObject returned %lx\n", ret );
17764 if( ret == WAIT_OBJECT_0 ) return 0;
17766 PostMessageA( data->hwnd, WM_RBUTTONUP, 0, 0 );
17767 return 0;
17770 static void test_defwinproc(void)
17772 HWND hwnd, child[3];
17773 MSG msg;
17774 BOOL gotwmquit = FALSE;
17775 POINT pos;
17776 RECT rect;
17777 INT x, y;
17778 LRESULT res;
17779 struct rbuttonup_thread_data data;
17780 char buffA[64];
17781 HANDLE thread;
17783 hwnd = CreateWindowExA(0, "TestWindowClass", "test_defwndproc",
17784 WS_VISIBLE | WS_CAPTION | WS_OVERLAPPEDWINDOW, 0,0,500,100,0,0,0, NULL);
17785 ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError());
17786 flush_events();
17788 buffA[0] = 0;
17789 GetWindowTextA(hwnd, buffA, ARRAY_SIZE(buffA));
17790 ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
17792 /* Zero high word of the lParam */
17793 res = DefWindowProcA(hwnd, WM_SETTEXT, 0, 0x1234);
17794 ok(res == 0, "WM_SETTEXT was expected to fail, %Id\n", res);
17796 GetWindowTextA(hwnd, buffA, ARRAY_SIZE(buffA));
17797 ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
17799 res = DefWindowProcW(hwnd, WM_SETTEXT, 0, 0x1234);
17800 ok(res == 0, "WM_SETTEXT was expected to fail, %Id\n", res);
17802 GetWindowTextA(hwnd, buffA, ARRAY_SIZE(buffA));
17803 ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
17805 ShowWindow(hwnd, SW_MINIMIZE);
17806 flush_events();
17807 flush_sequence();
17809 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
17810 flush_events();
17811 ok_sequence(WmRestoreMinimizedOverlappedSeq, "DefWindowProcA(SC_RESTORE):overlapped", TRUE);
17813 ShowWindow(hwnd, SW_MINIMIZE);
17814 SetActiveWindow(hwnd);
17815 ok(GetActiveWindow() == hwnd, "Unexpected active window\n");
17816 flush_events();
17817 flush_sequence();
17818 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
17819 flush_events();
17820 ok_sequence(WmRestoreActiveMinimizedOverlappedSeq, "DefWindowProcA(SC_RESTORE):active minimized overlapped", TRUE);
17822 child[0] = CreateWindowExA(0, "TestWindowClass", "1st child",
17823 WS_VISIBLE | WS_CHILD, 0,0,500,100, hwnd, 0, 0, NULL);
17824 child[1] = CreateWindowExA(0, "TestWindowClass", "2nd child",
17825 WS_VISIBLE | WS_CHILD, 0,0,500,100, child[0], 0, 0, NULL);
17826 child[2] = CreateWindowExA(0, "TestWindowClass", "3rd child",
17827 WS_VISIBLE | WS_CHILD, 0,0,500,100, child[1], 0, 0, NULL);
17828 flush_events();
17829 flush_sequence();
17830 test_context_menu = TRUE;
17831 DefWindowProcA(child[2], WM_CONTEXTMENU, 0xcafe, 0);
17832 test_context_menu = FALSE;
17833 WmContextMenuSeq[0].wParam = (WPARAM)child[2];
17834 WmContextMenuSeq[1].wParam = (WPARAM)child[1];
17835 WmContextMenuSeq[2].wParam = (WPARAM)child[0];
17836 ok_sequence(WmContextMenuSeq, "DefWindowProcA(WM_CONTEXTMENU)", FALSE);
17837 DestroyWindow(child[0]);
17839 GetCursorPos(&pos);
17840 GetWindowRect(hwnd, &rect);
17841 x = (rect.left+rect.right) / 2;
17842 y = rect.top + GetSystemMetrics(SM_CYFRAME) + 1;
17843 SetCursorPos(x, y);
17844 flush_events();
17845 res = DefWindowProcA( hwnd, WM_NCHITTEST, 0, MAKELPARAM(x, y));
17846 ok(res == HTCAPTION, "WM_NCHITTEST returned %Id\n", res);
17848 mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 );
17849 mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 );
17850 flush_events();
17852 flush_sequence();
17853 mouse_event( MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0 );
17854 /* workaround for missing support for clicking on window frame */
17855 data.hwnd = hwnd;
17856 data.wndproc_finished = CreateEventA( NULL, FALSE, FALSE, NULL );
17857 thread = CreateThread( NULL, 0, post_rbuttonup_msg, (void*)&data, 0, NULL );
17859 DefWindowProcA( hwnd, WM_NCRBUTTONDOWN, HTCAPTION, MAKELPARAM(x, y));
17860 ok_sequence(NCRBUTTONDOWNSeq, "WM_NCRBUTTONDOWN on caption", FALSE);
17862 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, 0, MAKELPARAM(x, y));
17863 ok(!res, "WM_NCXBUTTONUP returned %Id\n", res);
17864 ok_sequence(WmEmptySeq, "WM_NCXBUTTONUP without button", FALSE);
17866 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, XBUTTON1), MAKELPARAM(x, y));
17867 ok(!res, "WM_NCXBUTTONUP returned %Id\n", res);
17868 ok_sequence(NCXBUTTONUPSeq1, "WM_NCXBUTTONUP with XBUTTON1", FALSE);
17870 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, XBUTTON2), MAKELPARAM(x, y));
17871 ok(!res, "WM_NCXBUTTONUP returned %Id\n", res);
17872 ok_sequence(NCXBUTTONUPSeq2, "WM_NCXBUTTONUP with XBUTTON2", FALSE);
17874 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, 3), MAKELPARAM(x, y));
17875 ok(!res, "WM_NCXBUTTONUP returned %Id\n", res);
17876 ok_sequence(WmEmptySeq, "WM_NCXBUTTONUP with invalid button", FALSE);
17878 /* Test WM_MOUSEACTIVATE */
17879 #define TEST_MOUSEACTIVATE(A,B,C) \
17880 res = DefWindowProcA(hwnd, WM_MOUSEACTIVATE, (WPARAM)hwnd, (LPARAM)MAKELRESULT(A,0)); \
17881 ok(res == B, "WM_MOUSEACTIVATE for %s returned %Id\n", #A, res); \
17882 res = DefWindowProcA(hwnd, WM_MOUSEACTIVATE, (WPARAM)hwnd, (LPARAM)MAKELRESULT(A,WM_LBUTTONDOWN)); \
17883 ok(res == C, "WM_MOUSEACTIVATE for %s returned %Id\n", #A, res);
17885 TEST_MOUSEACTIVATE(HTERROR, MA_ACTIVATE, MA_ACTIVATE);
17886 TEST_MOUSEACTIVATE(HTTRANSPARENT, MA_ACTIVATE, MA_ACTIVATE);
17887 TEST_MOUSEACTIVATE(HTNOWHERE, MA_ACTIVATE, MA_ACTIVATE);
17888 TEST_MOUSEACTIVATE(HTCLIENT, MA_ACTIVATE, MA_ACTIVATE);
17889 TEST_MOUSEACTIVATE(HTCAPTION, MA_ACTIVATE, MA_NOACTIVATE);
17890 TEST_MOUSEACTIVATE(HTSYSMENU, MA_ACTIVATE, MA_ACTIVATE);
17891 TEST_MOUSEACTIVATE(HTSIZE, MA_ACTIVATE, MA_ACTIVATE);
17892 TEST_MOUSEACTIVATE(HTMENU, MA_ACTIVATE, MA_ACTIVATE);
17893 TEST_MOUSEACTIVATE(HTHSCROLL, MA_ACTIVATE, MA_ACTIVATE);
17894 TEST_MOUSEACTIVATE(HTVSCROLL, MA_ACTIVATE, MA_ACTIVATE);
17895 TEST_MOUSEACTIVATE(HTMINBUTTON, MA_ACTIVATE, MA_ACTIVATE);
17896 TEST_MOUSEACTIVATE(HTMAXBUTTON, MA_ACTIVATE, MA_ACTIVATE);
17897 TEST_MOUSEACTIVATE(HTLEFT, MA_ACTIVATE, MA_ACTIVATE);
17898 TEST_MOUSEACTIVATE(HTRIGHT, MA_ACTIVATE, MA_ACTIVATE);
17899 TEST_MOUSEACTIVATE(HTTOP, MA_ACTIVATE, MA_ACTIVATE);
17900 TEST_MOUSEACTIVATE(HTTOPLEFT, MA_ACTIVATE, MA_ACTIVATE);
17901 TEST_MOUSEACTIVATE(HTTOPRIGHT, MA_ACTIVATE, MA_ACTIVATE);
17902 TEST_MOUSEACTIVATE(HTBOTTOM, MA_ACTIVATE, MA_ACTIVATE);
17903 TEST_MOUSEACTIVATE(HTBOTTOMLEFT, MA_ACTIVATE, MA_ACTIVATE);
17904 TEST_MOUSEACTIVATE(HTBOTTOMRIGHT, MA_ACTIVATE, MA_ACTIVATE);
17905 TEST_MOUSEACTIVATE(HTBORDER, MA_ACTIVATE, MA_ACTIVATE);
17906 TEST_MOUSEACTIVATE(HTOBJECT, MA_ACTIVATE, MA_ACTIVATE);
17907 TEST_MOUSEACTIVATE(HTCLOSE, MA_ACTIVATE, MA_ACTIVATE);
17908 TEST_MOUSEACTIVATE(HTHELP, MA_ACTIVATE, MA_ACTIVATE);
17910 SetEvent( data.wndproc_finished );
17911 WaitForSingleObject( thread, 1000 );
17912 CloseHandle( data.wndproc_finished );
17913 CloseHandle( thread );
17915 SetCursorPos(pos.x, pos.y);
17917 DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0);
17918 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) {
17919 if( msg.message == WM_QUIT) gotwmquit = TRUE;
17920 DispatchMessageA( &msg );
17922 ok(!gotwmquit, "Unexpected WM_QUIT message!\n");
17923 DestroyWindow( hwnd);
17926 static void test_desktop_winproc(void)
17928 HINSTANCE instance = GetModuleHandleA(NULL);
17929 RECT rect, default_rect;
17930 WNDPROC desktop_proc;
17931 char buffer[256];
17932 WNDCLASSA cls;
17933 LRESULT res;
17934 HWND hwnd;
17935 BOOL ret;
17937 ret = GetClassInfoA(instance, (const CHAR *)MAKEINTATOM(32769), &cls);
17938 ok(ret, "Failed to get desktop class.\n");
17939 desktop_proc = cls.lpfnWndProc;
17941 memset(&cls, 0, sizeof(cls));
17942 cls.lpfnWndProc = desktop_proc;
17943 cls.hInstance = instance;
17944 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
17945 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
17946 cls.lpszClassName = "TestDesktopClass";
17947 register_class(&cls);
17949 hwnd = CreateWindowExA(0, cls.lpszClassName, "test_desktop_wndproc",
17950 WS_VISIBLE | WS_CAPTION | WS_OVERLAPPEDWINDOW, 0, 0, 500, 100, 0, 0, 0, NULL);
17951 if (!hwnd) /* win2003 */
17953 skip("Failed to create window with desktop window procedure.\n");
17954 goto out_unregister;
17957 memset(&cls, 0, sizeof(cls));
17958 ret = GetClassInfoA(instance, "TestDesktopClass", &cls);
17959 ok(ret, "Failed to get class info.\n");
17960 ok(cls.lpfnWndProc == desktop_proc, "Got %p, expected %p.\n", cls.lpfnWndProc, desktop_proc);
17962 GetWindowTextA(hwnd, buffer, ARRAY_SIZE(buffer));
17963 todo_wine ok(!strcmp(buffer, "test_desktop_wndproc"), "Got unexpected window text: %s.\n", buffer);
17965 res = CallWindowProcA(desktop_proc, hwnd, WM_SETTEXT, 0, (LPARAM)"test");
17966 ok(res == TRUE, "Failed to set text, %Id.\n", res);
17967 GetWindowTextA(hwnd, buffer, ARRAY_SIZE(buffer));
17968 ok(!strcmp(buffer, "test"), "Got unexpected window text: %s.\n", buffer);
17970 SetRect(&default_rect, 0, 0, 100, 100);
17971 res = DefWindowProcW(hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&default_rect);
17972 ok(!res, "Got unexpected result %Id.\n", res);
17974 SetRect(&rect, 0, 0, 100, 100);
17975 res = CallWindowProcA(desktop_proc, hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rect);
17976 ok(!res, "Got unexpected result %Id.\n", res);
17977 todo_wine ok(EqualRect(&rect, &default_rect), "rect Got %s, expected %s.\n",
17978 wine_dbgstr_rect(&rect), wine_dbgstr_rect(&default_rect));
17980 DestroyWindow(hwnd);
17982 out_unregister:
17983 UnregisterClassA("TestDesktopClass", instance);
17986 #define open_clipboard(hwnd) open_clipboard_(__LINE__, hwnd)
17987 static BOOL open_clipboard_(int line, HWND hwnd)
17989 DWORD start = GetTickCount();
17990 while (1)
17992 BOOL ret = OpenClipboard(hwnd);
17993 if (ret || GetLastError() != ERROR_ACCESS_DENIED)
17994 return ret;
17995 if (GetTickCount() - start > 100)
17997 char classname[256];
17998 DWORD le = GetLastError();
17999 HWND clipwnd = GetOpenClipboardWindow();
18000 /* Provide a hint as to the source of interference:
18001 * - The class name would typically be CLIPBRDWNDCLASS if the
18002 * clipboard was opened by a Windows application using the
18003 * ole32 API.
18004 * - And it would be __wine_clipboard_manager if it was opened in
18005 * response to a native application.
18007 GetClassNameA(clipwnd, classname, ARRAY_SIZE(classname));
18008 trace_(__FILE__, line)("%p (%s) opened the clipboard\n", clipwnd, classname);
18009 SetLastError(le);
18010 return ret;
18012 Sleep(15);
18016 #define clear_clipboard(hwnd) clear_clipboard_(__LINE__, (hwnd))
18017 static void clear_clipboard_(int line, HWND hWnd)
18019 BOOL succ;
18020 succ = open_clipboard_(line, hWnd);
18021 ok_(__FILE__, line)(succ, "OpenClipboard failed, err=%lu\n", GetLastError());
18022 succ = EmptyClipboard();
18023 ok_(__FILE__, line)(succ, "EmptyClipboard failed, err=%lu\n", GetLastError());
18024 succ = CloseClipboard();
18025 ok_(__FILE__, line)(succ, "CloseClipboard failed, err=%lu\n", GetLastError());
18028 #define expect_HWND(expected, got) expect_HWND_(__LINE__, (expected), (got))
18029 static void expect_HWND_(int line, HWND expected, HWND got)
18031 ok_(__FILE__, line)(got==expected, "Expected %p, got %p\n", expected, got);
18034 static WNDPROC pOldViewerProc;
18036 static LRESULT CALLBACK recursive_viewer_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
18038 static BOOL recursion_guard;
18040 if (message == WM_DRAWCLIPBOARD && !recursion_guard)
18042 recursion_guard = TRUE;
18043 clear_clipboard(hWnd);
18044 recursion_guard = FALSE;
18046 return CallWindowProcA(pOldViewerProc, hWnd, message, wParam, lParam);
18049 static void test_clipboard_viewers(void)
18051 static struct message wm_change_cb_chain[] =
18053 { WM_CHANGECBCHAIN, sent|wparam|lparam, 0, 0 },
18054 { 0 }
18056 static const struct message wm_clipboard_destroyed[] =
18058 { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
18059 { 0 }
18061 static struct message wm_clipboard_changed[] =
18063 { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
18064 { 0 }
18066 static struct message wm_clipboard_changed_and_owned[] =
18068 { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
18069 { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
18070 { 0 }
18073 HINSTANCE hInst = GetModuleHandleA(NULL);
18074 HWND hWnd1, hWnd2, hWnd3;
18075 HWND hOrigViewer;
18076 HWND hRet;
18078 hWnd1 = CreateWindowExA(0, "TestWindowClass", "Clipboard viewer test wnd 1",
18079 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
18080 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
18081 GetDesktopWindow(), NULL, hInst, NULL);
18082 ok(!!hWnd1, "Failed to create window, error %lu.\n", GetLastError());
18083 hWnd2 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 2",
18084 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
18085 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
18086 GetDesktopWindow(), NULL, hInst, NULL);
18087 ok(!!hWnd2, "Failed to create window, error %lu.\n", GetLastError());
18088 hWnd3 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 3",
18089 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
18090 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
18091 GetDesktopWindow(), NULL, hInst, NULL);
18092 ok(!!hWnd3, "Failed to create window, error %lu.\n", GetLastError());
18093 if (winetest_debug > 1) trace("clipbd viewers: hWnd1=%p, hWnd2=%p, hWnd3=%p\n", hWnd1, hWnd2, hWnd3);
18095 CountClipboardFormats(); /* Ensure that we do not have an X11 update to the clipboard */
18096 flush_sequence();
18098 /* Test getting the clipboard viewer and setting the viewer to NULL. */
18099 hOrigViewer = GetClipboardViewer();
18100 hRet = SetClipboardViewer(NULL);
18101 ok_sequence(WmEmptySeq, "set viewer to NULL", FALSE);
18102 expect_HWND(hOrigViewer, hRet);
18103 expect_HWND(NULL, GetClipboardViewer());
18105 /* Test registering hWnd1 as a viewer. */
18106 hRet = SetClipboardViewer(hWnd1);
18107 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
18108 ok_sequence(wm_clipboard_changed, "set viewer NULL->1", FALSE);
18109 expect_HWND(NULL, hRet);
18110 expect_HWND(hWnd1, GetClipboardViewer());
18112 /* Test that changing the clipboard actually refreshes the registered viewer. */
18113 clear_clipboard(hWnd1);
18114 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
18115 ok_sequence(wm_clipboard_changed, "clear clipbd (viewer=owner=1)", FALSE);
18117 /* Again, but with different owner. */
18118 clear_clipboard(hWnd2);
18119 wm_clipboard_changed_and_owned[1].wParam = (WPARAM) GetClipboardOwner();
18120 ok_sequence(wm_clipboard_changed_and_owned, "clear clipbd (viewer=1, owner=2)", FALSE);
18122 /* Test re-registering same window. */
18123 hRet = SetClipboardViewer(hWnd1);
18124 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
18125 ok_sequence(wm_clipboard_changed, "set viewer 1->1", FALSE);
18126 expect_HWND(hWnd1, hRet);
18127 expect_HWND(hWnd1, GetClipboardViewer());
18129 /* Test ChangeClipboardChain. */
18130 ChangeClipboardChain(hWnd2, hWnd3);
18131 wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
18132 wm_change_cb_chain[0].lParam = (LPARAM) hWnd3;
18133 ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=3)", FALSE);
18134 expect_HWND(hWnd1, GetClipboardViewer());
18136 ChangeClipboardChain(hWnd2, NULL);
18137 wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
18138 wm_change_cb_chain[0].lParam = 0;
18139 ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=NULL)", FALSE);
18140 expect_HWND(hWnd1, GetClipboardViewer());
18142 ChangeClipboardChain(NULL, hWnd2);
18143 ok_sequence(WmEmptySeq, "change chain (viewer=1, remove=NULL, next=2)", FALSE);
18144 expect_HWND(hWnd1, GetClipboardViewer());
18146 /* Actually change clipboard viewer with ChangeClipboardChain. */
18147 ChangeClipboardChain(hWnd1, hWnd2);
18148 ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=2)", FALSE);
18149 expect_HWND(hWnd2, GetClipboardViewer());
18151 /* Test that no refresh messages are sent when viewer has unregistered. */
18152 clear_clipboard(hWnd2);
18153 ok_sequence(WmEmptySeq, "clear clipd (viewer=2, owner=1)", FALSE);
18155 /* Register hWnd1 again. */
18156 ChangeClipboardChain(hWnd2, hWnd1);
18157 ok_sequence(WmEmptySeq, "change chain (viewer=remove=2, next=1)", FALSE);
18158 expect_HWND(hWnd1, GetClipboardViewer());
18160 /* Subclass hWnd1 so that when it receives a WM_DRAWCLIPBOARD message, it
18161 * changes the clipboard. When this happens, the system shouldn't send
18162 * another WM_DRAWCLIPBOARD (as this could cause an infinite loop).
18164 pOldViewerProc = (WNDPROC) SetWindowLongPtrA(hWnd1, GWLP_WNDPROC, (LONG_PTR) recursive_viewer_proc);
18165 clear_clipboard(hWnd2);
18166 /* The clipboard owner is changed in recursive_viewer_proc: */
18167 wm_clipboard_changed[0].wParam = (WPARAM) hWnd2;
18168 ok_sequence(wm_clipboard_changed, "recursive clear clipbd (viewer=1, owner=2)", TRUE);
18170 /* Test unregistering. */
18171 ChangeClipboardChain(hWnd1, NULL);
18172 ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=NULL)", FALSE);
18173 expect_HWND(NULL, GetClipboardViewer());
18175 clear_clipboard(hWnd1);
18176 ok_sequence(wm_clipboard_destroyed, "clear clipbd (no viewer, owner=1)", FALSE);
18178 DestroyWindow(hWnd1);
18179 DestroyWindow(hWnd2);
18180 DestroyWindow(hWnd3);
18181 SetClipboardViewer(hOrigViewer);
18184 static void test_PostMessage(void)
18186 static const struct
18188 HWND hwnd;
18189 BOOL ret;
18190 } data[] =
18192 { HWND_TOP /* 0 */, TRUE },
18193 { HWND_BROADCAST, TRUE },
18194 { HWND_BOTTOM, TRUE },
18195 { HWND_TOPMOST, TRUE },
18196 { HWND_NOTOPMOST, FALSE },
18197 { HWND_MESSAGE, FALSE },
18198 { (HWND)0xdeadbeef, FALSE }
18200 int i;
18201 HWND hwnd;
18202 BOOL ret;
18203 MSG msg;
18204 static const WCHAR staticW[] = {'s','t','a','t','i','c',0};
18206 SetLastError(0xdeadbeef);
18207 hwnd = CreateWindowExW(0, staticW, NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
18208 if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
18210 win_skip("Skipping some PostMessage tests on Win9x/WinMe\n");
18211 return;
18213 ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError());
18215 flush_events();
18217 PostMessageA(hwnd, WM_USER+1, 0x1234, 0x5678);
18218 PostMessageA(0, WM_USER+2, 0x5678, 0x1234);
18220 for (i = 0; i < ARRAY_SIZE(data); i++)
18222 memset(&msg, 0xab, sizeof(msg));
18223 ret = PeekMessageA(&msg, data[i].hwnd, 0, 0, PM_NOREMOVE);
18224 ok(ret == data[i].ret, "%d: hwnd %p expected %d, got %d\n", i, data[i].hwnd, data[i].ret, ret);
18225 if (data[i].ret)
18227 if (data[i].hwnd)
18228 ok(ret && msg.hwnd == 0 && msg.message == WM_USER+2 &&
18229 msg.wParam == 0x5678 && msg.lParam == 0x1234,
18230 "%d: got ret %d hwnd %p msg %04x wParam %08Ix lParam %08Ix instead of TRUE/0/WM_USER+2/0x5678/0x1234\n",
18231 i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam);
18232 else
18233 ok(ret && msg.hwnd == hwnd && msg.message == WM_USER+1 &&
18234 msg.wParam == 0x1234 && msg.lParam == 0x5678,
18235 "%d: got ret %d hwnd %p msg %04x wParam %08Ix lParam %08Ix instead of TRUE/%p/WM_USER+1/0x1234/0x5678\n",
18236 i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam, msg.hwnd);
18240 DestroyWindow(hwnd);
18241 flush_events();
18244 static WPARAM g_broadcast_wparam;
18245 static UINT g_broadcast_msg;
18246 static LRESULT WINAPI broadcast_test_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
18248 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
18250 if (message == g_broadcast_msg)
18251 g_broadcast_wparam = wParam;
18253 return CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
18255 static WNDPROC *g_oldproc_sub;
18256 static WPARAM *g_broadcast_sub_wparam;
18257 static LRESULT WINAPI broadcast_test_sub_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
18259 int sub_index = GetWindowLongPtrA(hwnd, GWLP_USERDATA);
18261 if (message == g_broadcast_msg)
18262 g_broadcast_sub_wparam[sub_index] = wParam;
18264 return CallWindowProcA(g_oldproc_sub[sub_index], hwnd, message, wParam, lParam);
18267 static void test_broadcast(void)
18269 static const UINT messages[] =
18271 WM_USER-1,
18272 WM_USER,
18273 WM_USER+1,
18274 0xc000-1,
18275 0xc000, /* lowest possible atom returned by RegisterWindowMessage */
18276 0xffff,
18278 static const struct
18280 LONG style;
18281 BOOL receive;
18282 } bcast_expect[] =
18284 {WS_OVERLAPPED, TRUE},
18285 {WS_OVERLAPPED|WS_DLGFRAME, TRUE},
18286 {WS_OVERLAPPED|WS_BORDER, TRUE},
18287 {WS_OVERLAPPED|WS_CAPTION, TRUE},
18288 {WS_CHILD, FALSE},
18289 {WS_CHILD|WS_DLGFRAME, FALSE},
18290 {WS_CHILD|WS_BORDER, FALSE},
18291 {WS_CHILD|WS_CAPTION, FALSE},
18292 {WS_CHILD|WS_POPUP, TRUE},
18293 {WS_POPUP, TRUE},
18294 {WS_POPUP|WS_DLGFRAME, TRUE},
18295 {WS_POPUP|WS_BORDER, TRUE},
18296 {WS_POPUP|WS_CAPTION, TRUE},
18298 WNDPROC oldproc;
18299 unsigned int i, j;
18300 HWND hwnd;
18301 HWND *hwnd_sub;
18303 hwnd_sub = malloc(ARRAY_SIZE(bcast_expect) * sizeof(*hwnd_sub));
18304 g_oldproc_sub = malloc(ARRAY_SIZE(bcast_expect) * sizeof(*g_oldproc_sub));
18305 g_broadcast_sub_wparam = malloc(ARRAY_SIZE(bcast_expect) * sizeof(*g_broadcast_sub_wparam));
18307 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, NULL);
18308 ok(hwnd != NULL, "got %p\n", hwnd);
18310 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)broadcast_test_proc);
18311 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
18313 for (i = 0; i < ARRAY_SIZE(messages); i++)
18315 BOOL ret;
18316 BOOL msg_expected = (messages[i] < WM_USER || messages[i] >= 0xc000);
18317 MSG msg;
18319 flush_events();
18320 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
18323 /* post, broadcast */
18324 ret = PostMessageA(HWND_BROADCAST, messages[i], 0, 0);
18325 ok(ret, "%d: got %d, error %ld\n", i, ret, GetLastError());
18327 memset(&msg, 0xab, sizeof(msg));
18328 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
18329 ok(ret == msg_expected, "%d: message %04x, got %d, error %ld\n", i, messages[i], ret, GetLastError());
18330 if (msg_expected)
18331 ok(msg.hwnd == hwnd, "%d: got %p\n", i, msg.hwnd);
18333 /* post, topmost */
18334 ret = PostMessageA(HWND_TOPMOST, messages[i], 0, 0);
18335 ok(ret, "%d: got %d, error %ld\n", i, ret, GetLastError());
18337 memset(&msg, 0xab, sizeof(msg));
18338 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
18339 ok(ret == msg_expected, "%d: message %04x, got %d, error %ld\n", i, messages[i], ret, GetLastError());
18340 if (msg_expected)
18341 ok(msg.hwnd == hwnd, "%d: got %p\n", i, msg.hwnd);
18344 for (j = 0; j < ARRAY_SIZE(bcast_expect); j++)
18346 hwnd_sub[j] = CreateWindowA("static", NULL, bcast_expect[j].style, 0, 0, 0, 0, hwnd, 0, 0, NULL);
18347 ok(hwnd_sub[j] != NULL, "got %p\n", hwnd_sub[j]);
18348 /* CreateWindow adds extra style flags, so call SetWindowLong to clear some of those. */
18349 SetWindowLongA(hwnd_sub[j], GWL_STYLE, bcast_expect[j].style);
18351 g_oldproc_sub[j] = (WNDPROC)SetWindowLongPtrA(hwnd_sub[j], GWLP_WNDPROC, (LONG_PTR)broadcast_test_sub_proc);
18352 SetWindowLongPtrA(hwnd_sub[j], GWLP_USERDATA, (LONG_PTR)j);
18355 for (i = 0; i < ARRAY_SIZE(messages); i++)
18357 BOOL ret;
18358 BOOL msg_expected = (messages[i] < WM_USER || messages[i] >= 0xc000);
18360 /* send, broadcast */
18361 g_broadcast_wparam = 0xdead;
18362 for (j = 0; j < ARRAY_SIZE(bcast_expect); j++)
18363 g_broadcast_sub_wparam[j] = 0xdead;
18364 g_broadcast_msg = messages[i];
18365 ret = SendMessageTimeoutA(HWND_BROADCAST, messages[i], 0xbaadbeef, 0, SMTO_NORMAL, 2000, NULL);
18366 if (!ret && GetLastError() == ERROR_TIMEOUT)
18367 win_skip("broadcasting test %d, timeout\n", i);
18368 else
18370 WPARAM wparam_expected = msg_expected ? 0xbaadbeef : 0xdead;
18371 ok(g_broadcast_wparam == wparam_expected, "%d: message %04x, got %#Ix, error %ld\n",
18372 i, messages[i], g_broadcast_wparam, GetLastError());
18373 for (j = 0; j < ARRAY_SIZE(bcast_expect); j++)
18375 wparam_expected = (msg_expected && bcast_expect[j].receive) ? 0xbaadbeef : 0xdead;
18376 ok(g_broadcast_sub_wparam[j] == wparam_expected,
18377 "%d,%d: message %04x, got %#Ix, error %ld\n", i, j, messages[i],
18378 g_broadcast_sub_wparam[j], GetLastError());
18382 /* send, topmost */
18383 g_broadcast_wparam = 0xdead;
18384 for (j = 0; j < ARRAY_SIZE(bcast_expect); j++)
18385 g_broadcast_sub_wparam[j] = 0xdead;
18386 ret = SendMessageTimeoutA(HWND_TOPMOST, messages[i], 0xbaadbeef, 0, SMTO_NORMAL, 2000, NULL);
18387 if (!ret && GetLastError() == ERROR_TIMEOUT)
18388 win_skip("broadcasting test %d, timeout\n", i);
18389 else
18391 WPARAM wparam_expected = msg_expected ? 0xbaadbeef : 0xdead;
18392 ok(g_broadcast_wparam == wparam_expected, "%d: message %04x, got %#Ix, error %ld\n",
18393 i, messages[i], g_broadcast_wparam, GetLastError());
18394 for (j = 0; j < ARRAY_SIZE(bcast_expect); j++)
18396 wparam_expected = (msg_expected && bcast_expect[j].receive) ? 0xbaadbeef : 0xdead;
18397 ok(g_broadcast_sub_wparam[j] == wparam_expected,
18398 "%d,%d: message %04x, got %#Ix, error %ld\n", i, j, messages[i],
18399 g_broadcast_sub_wparam[j], GetLastError());
18404 for (j = 0; j < ARRAY_SIZE(bcast_expect); j++)
18405 DestroyWindow(hwnd_sub[j]);
18407 free(g_broadcast_sub_wparam);
18408 free(g_oldproc_sub);
18409 free(hwnd_sub);
18411 DestroyWindow(hwnd);
18414 static const struct
18416 DWORD exp, broken;
18417 BOOL todo;
18418 } wait_idle_expect[] =
18420 /* 0 */ { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
18421 { WAIT_TIMEOUT, 0, FALSE },
18422 { WAIT_TIMEOUT, 0, FALSE },
18423 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
18424 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
18425 /* 5 */ { WAIT_TIMEOUT, 0, FALSE },
18426 { WAIT_TIMEOUT, 0, FALSE },
18427 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
18428 { 0, 0, FALSE },
18429 { 0, 0, FALSE },
18430 /* 10 */ { 0, 0, FALSE },
18431 { 0, 0, FALSE },
18432 { 0, WAIT_TIMEOUT, FALSE },
18433 { 0, 0, FALSE },
18434 { 0, 0, FALSE },
18435 /* 15 */ { 0, 0, FALSE },
18436 { WAIT_TIMEOUT, 0, FALSE },
18437 { WAIT_TIMEOUT, 0, FALSE },
18438 { WAIT_TIMEOUT, 0, FALSE },
18439 { WAIT_TIMEOUT, 0, FALSE },
18440 /* 20 */ { WAIT_TIMEOUT, 0, FALSE },
18443 static DWORD CALLBACK do_wait_idle_child_thread( void *arg )
18445 MSG msg;
18447 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
18448 Sleep( 200 );
18449 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
18450 return 0;
18453 static void do_wait_idle_child( int arg )
18455 WNDCLASSA cls;
18456 MSG msg;
18457 HWND hwnd = 0;
18458 HANDLE thread;
18459 DWORD id;
18460 HANDLE start_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_start" );
18461 HANDLE end_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_end" );
18463 memset( &cls, 0, sizeof(cls) );
18464 cls.lpfnWndProc = DefWindowProcA;
18465 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
18466 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
18467 cls.lpszClassName = "TestClass";
18468 register_class(&cls);
18470 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ); /* create the msg queue */
18472 ok( start_event != 0, "failed to create start event, error %lu\n", GetLastError() );
18473 ok( end_event != 0, "failed to create end event, error %lu\n", GetLastError() );
18475 switch (arg)
18477 case 0:
18478 SetEvent( start_event );
18479 break;
18480 case 1:
18481 SetEvent( start_event );
18482 Sleep( 200 );
18483 PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
18484 break;
18485 case 2:
18486 SetEvent( start_event );
18487 Sleep( 200 );
18488 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
18489 PostThreadMessageA( GetCurrentThreadId(), WM_COMMAND, 0x1234, 0xabcd );
18490 PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
18491 break;
18492 case 3:
18493 SetEvent( start_event );
18494 Sleep( 200 );
18495 SendMessageA( HWND_BROADCAST, WM_WININICHANGE, 0, 0 );
18496 break;
18497 case 4:
18498 SetEvent( start_event );
18499 Sleep( 200 );
18500 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
18501 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
18502 break;
18503 case 5:
18504 SetEvent( start_event );
18505 Sleep( 200 );
18506 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
18507 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
18508 break;
18509 case 6:
18510 SetEvent( start_event );
18511 Sleep( 200 );
18512 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
18513 while (PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ))
18515 GetMessageA( &msg, 0, 0, 0 );
18516 DispatchMessageA( &msg );
18518 break;
18519 case 7:
18520 SetEvent( start_event );
18521 Sleep( 200 );
18522 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
18523 SetTimer( hwnd, 3, 1, NULL );
18524 Sleep( 200 );
18525 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
18526 break;
18527 case 8:
18528 SetEvent( start_event );
18529 Sleep( 200 );
18530 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
18531 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
18532 break;
18533 case 9:
18534 SetEvent( start_event );
18535 Sleep( 200 );
18536 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
18537 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
18538 for (;;) GetMessageA( &msg, 0, 0, 0 );
18539 break;
18540 case 10:
18541 SetEvent( start_event );
18542 Sleep( 200 );
18543 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
18544 SetTimer( hwnd, 3, 1, NULL );
18545 Sleep( 200 );
18546 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
18547 break;
18548 case 11:
18549 SetEvent( start_event );
18550 Sleep( 200 );
18551 return; /* exiting the process makes WaitForInputIdle return success too */
18552 case 12:
18553 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
18554 Sleep( 200 );
18555 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
18556 SetEvent( start_event );
18557 break;
18558 case 13:
18559 SetEvent( start_event );
18560 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
18561 Sleep( 200 );
18562 thread = CreateThread( NULL, 0, do_wait_idle_child_thread, NULL, 0, &id );
18563 WaitForSingleObject( thread, 10000 );
18564 CloseHandle( thread );
18565 break;
18566 case 14:
18567 SetEvent( start_event );
18568 Sleep( 200 );
18569 PeekMessageA( &msg, HWND_TOPMOST, 0, 0, PM_NOREMOVE );
18570 break;
18571 case 15:
18572 SetEvent( start_event );
18573 Sleep( 200 );
18574 PeekMessageA( &msg, HWND_BROADCAST, 0, 0, PM_NOREMOVE );
18575 break;
18576 case 16:
18577 SetEvent( start_event );
18578 Sleep( 200 );
18579 PeekMessageA( &msg, HWND_BOTTOM, 0, 0, PM_NOREMOVE );
18580 break;
18581 case 17:
18582 SetEvent( start_event );
18583 Sleep( 200 );
18584 PeekMessageA( &msg, (HWND)0xdeadbeef, 0, 0, PM_NOREMOVE );
18585 break;
18586 case 18:
18587 SetEvent( start_event );
18588 Sleep( 200 );
18589 PeekMessageA( &msg, HWND_NOTOPMOST, 0, 0, PM_NOREMOVE );
18590 break;
18591 case 19:
18592 SetEvent( start_event );
18593 Sleep( 200 );
18594 PeekMessageA( &msg, HWND_MESSAGE, 0, 0, PM_NOREMOVE );
18595 break;
18596 case 20:
18597 SetEvent( start_event );
18598 Sleep( 200 );
18599 PeekMessageA( &msg, GetDesktopWindow(), 0, 0, PM_NOREMOVE );
18600 break;
18602 WaitForSingleObject( end_event, 2000 );
18603 CloseHandle( start_event );
18604 CloseHandle( end_event );
18605 if (hwnd) DestroyWindow( hwnd );
18608 static LRESULT CALLBACK wait_idle_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
18610 if (msg == WM_WININICHANGE) Sleep( 200 ); /* make sure the child waits */
18611 return DefWindowProcA( hwnd, msg, wp, lp );
18614 static DWORD CALLBACK wait_idle_thread( void *arg )
18616 WNDCLASSA cls;
18617 MSG msg;
18618 HWND hwnd;
18620 memset( &cls, 0, sizeof(cls) );
18621 cls.lpfnWndProc = wait_idle_proc;
18622 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
18623 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
18624 cls.lpszClassName = "TestClass";
18625 register_class(&cls);
18627 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL);
18628 while (GetMessageA( &msg, 0, 0, 0 )) DispatchMessageA( &msg );
18629 DestroyWindow(hwnd);
18630 return 0;
18633 static void test_WaitForInputIdle( char *argv0 )
18635 char path[MAX_PATH];
18636 PROCESS_INFORMATION pi;
18637 STARTUPINFOA startup;
18638 BOOL ret;
18639 HANDLE start_event, end_event, thread;
18640 unsigned int i;
18641 DWORD id;
18642 const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)GetModuleHandleA(0);
18643 const IMAGE_NT_HEADERS *nt = (const IMAGE_NT_HEADERS *)((const char *)dos + dos->e_lfanew);
18644 BOOL console_app = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI);
18646 if (console_app) /* build the test with -mwindows for better coverage */
18647 trace( "not built as a GUI app, WaitForInputIdle may not be fully tested\n" );
18649 start_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_start");
18650 end_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_end");
18651 ok(start_event != 0, "failed to create start event, error %lu\n", GetLastError());
18652 ok(end_event != 0, "failed to create end event, error %lu\n", GetLastError());
18654 memset( &startup, 0, sizeof(startup) );
18655 startup.cb = sizeof(startup);
18656 startup.dwFlags = STARTF_USESHOWWINDOW;
18657 startup.wShowWindow = SW_SHOWNORMAL;
18659 thread = CreateThread( NULL, 0, wait_idle_thread, NULL, 0, &id );
18661 for (i = 0; i < ARRAY_SIZE(wait_idle_expect); i++)
18663 ResetEvent( start_event );
18664 ResetEvent( end_event );
18665 sprintf( path, "%s msg %u", argv0, i );
18666 ret = CreateProcessA( NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &pi );
18667 ok( ret, "CreateProcess '%s' failed err %lu.\n", path, GetLastError() );
18668 if (ret)
18670 ret = WaitForSingleObject( start_event, 5000 );
18671 ok( ret == WAIT_OBJECT_0, "%u: WaitForSingleObject failed\n", i );
18672 if (ret == WAIT_OBJECT_0)
18674 ret = WaitForInputIdle( pi.hProcess, 1000 );
18675 if (ret == WAIT_FAILED)
18676 ok( console_app ||
18677 ret == wait_idle_expect[i].exp ||
18678 broken(ret == wait_idle_expect[i].broken),
18679 "%u: WaitForInputIdle error %08x expected %08lx\n",
18680 i, ret, wait_idle_expect[i].exp );
18681 else todo_wine_if (wait_idle_expect[i].todo)
18682 ok( ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken),
18683 "%u: WaitForInputIdle error %08x expected %08lx\n",
18684 i, ret, wait_idle_expect[i].exp );
18685 SetEvent( end_event );
18686 WaitForSingleObject( pi.hProcess, 1000 ); /* give it a chance to exit on its own */
18688 TerminateProcess( pi.hProcess, 0 ); /* just in case */
18689 wait_child_process( pi.hProcess );
18690 ret = WaitForInputIdle( pi.hProcess, 100 );
18691 ok( ret == WAIT_FAILED, "%u: WaitForInputIdle after exit error %08x\n", i, ret );
18692 CloseHandle( pi.hProcess );
18693 CloseHandle( pi.hThread );
18696 CloseHandle( end_event );
18697 CloseHandle( start_event );
18698 PostThreadMessageA( id, WM_QUIT, 0, 0 );
18699 WaitForSingleObject( thread, 10000 );
18700 CloseHandle( thread );
18703 static const struct message WmSetParentSeq_1[] = {
18704 { WM_SHOWWINDOW, sent|wparam, 0 },
18705 { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
18706 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
18707 { WM_CHILDACTIVATE, sent },
18708 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE },
18709 { WM_MOVE, sent|defwinproc|wparam, 0 },
18710 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
18711 { WM_SHOWWINDOW, sent|wparam, 1 },
18712 { 0 }
18715 static const struct message WmSetParentSeq_2[] = {
18716 { WM_SHOWWINDOW, sent|wparam, 0 },
18717 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
18718 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
18719 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
18720 { HCBT_SETFOCUS, hook|optional },
18721 { WM_NCACTIVATE, sent|wparam|optional, 0 },
18722 { WM_ACTIVATE, sent|wparam|optional, 0 },
18723 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
18724 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
18725 { WM_KILLFOCUS, sent|wparam, 0 },
18726 { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
18727 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
18728 { HCBT_ACTIVATE, hook|optional },
18729 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|optional, 0, 0 },
18730 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
18731 { WM_NCACTIVATE, sent|wparam|optional, 1 },
18732 { WM_ACTIVATE, sent|wparam|optional, 1 },
18733 { HCBT_SETFOCUS, hook|optional },
18734 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
18735 { WM_SETFOCUS, sent|optional|defwinproc },
18736 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOCLIENTSIZE },
18737 { WM_MOVE, sent|defwinproc|wparam, 0 },
18738 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
18739 { WM_SHOWWINDOW, sent|wparam, 1 },
18740 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
18741 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
18742 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
18743 { 0 }
18747 static void test_SetParent(void)
18749 HWND parent1, parent2, child, popup;
18750 RECT rc, rc_old;
18752 parent1 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
18753 100, 100, 200, 200, 0, 0, 0, NULL);
18754 ok(parent1 != 0, "Failed to create parent1 window\n");
18756 parent2 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
18757 400, 100, 200, 200, 0, 0, 0, NULL);
18758 ok(parent2 != 0, "Failed to create parent2 window\n");
18760 /* WS_CHILD window */
18761 child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD | WS_VISIBLE,
18762 10, 10, 150, 150, parent1, 0, 0, NULL);
18763 ok(child != 0, "Failed to create child window\n");
18765 GetWindowRect(parent1, &rc);
18766 if (winetest_debug > 1) trace("parent1 %s\n", wine_dbgstr_rect(&rc));
18767 GetWindowRect(child, &rc_old);
18768 MapWindowPoints(0, parent1, (POINT *)&rc_old, 2);
18769 if (winetest_debug > 1) trace("child %s\n", wine_dbgstr_rect(&rc_old));
18771 flush_sequence();
18773 SetParent(child, parent2);
18774 flush_events();
18775 ok_sequence(WmSetParentSeq_1, "SetParent() visible WS_CHILD", FALSE);
18777 ok(GetWindowLongA(child, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
18778 ok(!IsWindowVisible(child), "IsWindowVisible() should return FALSE\n");
18780 GetWindowRect(parent2, &rc);
18781 if (winetest_debug > 1) trace("parent2 %s\n", wine_dbgstr_rect(&rc));
18782 GetWindowRect(child, &rc);
18783 MapWindowPoints(0, parent2, (POINT *)&rc, 2);
18784 if (winetest_debug > 1) trace("child %s\n", wine_dbgstr_rect(&rc));
18786 ok(EqualRect(&rc_old, &rc), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc_old),
18787 wine_dbgstr_rect(&rc));
18789 /* WS_POPUP window */
18790 popup = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP | WS_VISIBLE,
18791 20, 20, 100, 100, 0, 0, 0, NULL);
18792 ok(popup != 0, "Failed to create popup window\n");
18794 GetWindowRect(popup, &rc_old);
18795 if (winetest_debug > 1) trace("popup %s\n", wine_dbgstr_rect(&rc_old));
18797 flush_sequence();
18799 SetParent(popup, child);
18800 flush_events();
18801 ok_sequence(WmSetParentSeq_2, "SetParent() visible WS_POPUP", TRUE);
18803 ok(GetWindowLongA(popup, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
18804 ok(!IsWindowVisible(popup), "IsWindowVisible() should return FALSE\n");
18806 GetWindowRect(child, &rc);
18807 if (winetest_debug > 1) trace("parent2 %s\n", wine_dbgstr_rect(&rc));
18808 GetWindowRect(popup, &rc);
18809 MapWindowPoints(0, child, (POINT *)&rc, 2);
18810 if (winetest_debug > 1) trace("popup %s\n", wine_dbgstr_rect(&rc));
18812 ok(EqualRect(&rc_old, &rc), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc_old),
18813 wine_dbgstr_rect(&rc));
18815 DestroyWindow(popup);
18816 DestroyWindow(child);
18817 DestroyWindow(parent1);
18818 DestroyWindow(parent2);
18820 flush_sequence();
18823 static const struct message WmKeyReleaseOnly[] = {
18824 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x80000001 },
18825 { WM_KEYUP, sent|wparam|lparam, 0x41, 0x80000001 },
18826 { 0 }
18828 static const struct message WmKeyPressNormal[] = {
18829 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x1 },
18830 { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x1 },
18831 { 0 }
18833 static const struct message WmKeyPressRepeat[] = {
18834 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x40000001 },
18835 { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x40000001 },
18836 { 0 }
18838 static const struct message WmKeyReleaseNormal[] = {
18839 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0xc0000001 },
18840 { WM_KEYUP, sent|wparam|lparam, 0x41, 0xc0000001 },
18841 { 0 }
18844 static void test_keyflags(void)
18846 HWND test_window;
18847 SHORT key_state;
18848 BYTE keyboard_state[256];
18849 MSG msg;
18851 test_window = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
18852 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
18853 0, 0, 0, NULL);
18855 flush_events();
18856 flush_sequence();
18858 /* keyup without a keydown */
18859 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
18860 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
18861 DispatchMessageA(&msg);
18862 ok_sequence(WmKeyReleaseOnly, "key release only", TRUE);
18864 key_state = GetAsyncKeyState(0x41);
18865 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
18867 key_state = GetKeyState(0x41);
18868 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
18870 /* keydown */
18871 keybd_event(0x41, 0, 0, 0);
18872 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
18873 DispatchMessageA(&msg);
18874 ok_sequence(WmKeyPressNormal, "key press only", FALSE);
18876 key_state = GetAsyncKeyState(0x41);
18877 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
18879 key_state = GetKeyState(0x41);
18880 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
18882 /* keydown repeat */
18883 keybd_event(0x41, 0, 0, 0);
18884 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
18885 DispatchMessageA(&msg);
18886 ok_sequence(WmKeyPressRepeat, "key press repeat", FALSE);
18888 key_state = GetAsyncKeyState(0x41);
18889 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
18891 key_state = GetKeyState(0x41);
18892 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
18894 /* keyup */
18895 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
18896 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
18897 DispatchMessageA(&msg);
18898 ok_sequence(WmKeyReleaseNormal, "key release repeat", FALSE);
18900 key_state = GetAsyncKeyState(0x41);
18901 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
18903 key_state = GetKeyState(0x41);
18904 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
18906 /* set the key state in this thread */
18907 GetKeyboardState(keyboard_state);
18908 keyboard_state[0x41] = 0x80;
18909 SetKeyboardState(keyboard_state);
18911 key_state = GetAsyncKeyState(0x41);
18912 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
18914 /* keydown */
18915 keybd_event(0x41, 0, 0, 0);
18916 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
18917 DispatchMessageA(&msg);
18918 ok_sequence(WmKeyPressRepeat, "key press after setkeyboardstate", TRUE);
18920 key_state = GetAsyncKeyState(0x41);
18921 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
18923 key_state = GetKeyState(0x41);
18924 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
18926 /* clear the key state in this thread */
18927 GetKeyboardState(keyboard_state);
18928 keyboard_state[0x41] = 0;
18929 SetKeyboardState(keyboard_state);
18931 key_state = GetAsyncKeyState(0x41);
18932 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
18934 /* keyup */
18935 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
18936 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
18937 DispatchMessageA(&msg);
18938 ok_sequence(WmKeyReleaseOnly, "key release after setkeyboardstate", TRUE);
18940 key_state = GetAsyncKeyState(0x41);
18941 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
18943 key_state = GetKeyState(0x41);
18944 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
18946 DestroyWindow(test_window);
18947 flush_sequence();
18950 static const struct message WmHotkeyPressLWIN[] = {
18951 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
18952 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
18953 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
18954 { 0 }
18956 static const struct message WmHotkeyPress[] = {
18957 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
18958 { WM_HOTKEY, sent|wparam, 5 },
18959 { 0 }
18961 static const struct message WmHotkeyRelease[] = {
18962 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
18963 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 0x80000001 },
18964 { WM_KEYUP, sent|lparam, 0, 0x80000001 },
18965 { 0 }
18967 static const struct message WmHotkeyReleaseLWIN[] = {
18968 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
18969 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
18970 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
18971 { 0 }
18973 static const struct message WmHotkeyCombined[] = {
18974 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
18975 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
18976 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
18977 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
18978 { WM_APP, sent, 0, 0 },
18979 { WM_HOTKEY, sent|wparam, 5 },
18980 { WM_APP+1, sent, 0, 0 },
18981 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
18982 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
18983 { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
18984 { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
18985 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
18986 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
18987 { 0 }
18989 static const struct message WmHotkeyPrevious[] = {
18990 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
18991 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
18992 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
18993 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
18994 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
18995 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
18996 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 1 },
18997 { WM_KEYDOWN, sent|lparam, 0, 1 },
18998 { HCBT_KEYSKIPPED, hook|optional|lparam, 0, 0xc0000001 },
18999 { WM_KEYUP, sent|lparam, 0, 0xc0000001 },
19000 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
19001 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
19002 { 0 }
19004 static const struct message WmHotkeyNew[] = {
19005 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
19006 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
19007 { WM_HOTKEY, sent|wparam, 5 },
19008 { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
19009 { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
19010 { 0 }
19012 static const struct message WmHotkeyPressALT[] = {
19013 { WM_SYSKEYDOWN, kbd_hook|wparam|lparam, VK_LMENU, LLKHF_INJECTED|LLKHF_ALTDOWN },
19014 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
19015 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
19016 { 0 }
19018 static const struct message WmHotkeyPressWithALT[] = {
19019 { WM_SYSKEYDOWN, kbd_hook, 0, LLKHF_INJECTED|LLKHF_ALTDOWN }, /* lparam not checked */
19020 { WM_HOTKEY, sent|wparam, 6 },
19021 { 0 }
19023 static const struct message WmHotkeyReleaseWithALT[] = {
19024 { WM_SYSKEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP|LLKHF_ALTDOWN },
19025 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 0xa0000001 },
19026 { WM_SYSKEYUP, sent|lparam, 0, 0xa0000001 },
19027 { 0 }
19029 static const struct message WmHotkeyReleaseALT[] = {
19030 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LMENU, LLKHF_INJECTED|LLKHF_UP },
19031 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 },
19032 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
19033 { 0 }
19036 static int hotkey_letter;
19038 static LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
19040 struct recvd_message msg;
19042 if (nCode == HC_ACTION)
19044 KBDLLHOOKSTRUCT *kdbhookstruct = (KBDLLHOOKSTRUCT*)lParam;
19046 msg.hwnd = 0;
19047 msg.message = wParam;
19048 msg.flags = kbd_hook|wparam|lparam;
19049 msg.wParam = kdbhookstruct->vkCode;
19050 msg.lParam = kdbhookstruct->flags;
19051 msg.descr = "KeyboardHookProc";
19052 add_message(&msg);
19054 if (wParam == WM_KEYUP || wParam == WM_KEYDOWN ||
19055 wParam == WM_SYSKEYUP || wParam == WM_SYSKEYDOWN)
19057 ok(kdbhookstruct->vkCode == VK_LWIN ||
19058 kdbhookstruct->vkCode == VK_LMENU ||
19059 kdbhookstruct->vkCode == hotkey_letter,
19060 "unexpected keycode %lx\n", kdbhookstruct->vkCode);
19064 return CallNextHookEx(hKBD_hook, nCode, wParam, lParam);
19067 static void test_hotkey(void)
19069 HWND test_window, taskbar_window;
19070 BOOL ret;
19071 MSG msg;
19072 DWORD queue_status;
19073 SHORT key_state;
19075 SetLastError(0xdeadbeef);
19076 ret = UnregisterHotKey(NULL, 0);
19077 if (ret == TRUE)
19079 skip("hotkeys not supported\n");
19080 return;
19083 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
19084 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
19085 "unexpected error %ld\n", GetLastError());
19087 test_window = CreateWindowExA(0, "HotkeyWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
19088 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
19089 0, 0, 0, NULL);
19091 SetForegroundWindow(test_window);
19092 flush_events();
19093 flush_sequence();
19095 SetLastError(0xdeadbeef);
19096 ret = UnregisterHotKey(test_window, 0);
19097 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
19098 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
19099 "unexpected error %ld\n", GetLastError());
19101 /* Search for a Windows Key + letter combination that hasn't been registered */
19102 for (hotkey_letter = 'A'; hotkey_letter <= 'Z'; hotkey_letter ++)
19104 SetLastError(0xdeadbeef);
19105 ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
19107 if (ret == TRUE)
19109 break;
19111 else
19113 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
19114 "unexpected error %ld\n", GetLastError());
19118 if (hotkey_letter > 'Z')
19120 ok(0, "Couldn't find any free Windows Key + letter combination\n");
19121 goto end;
19124 hKBD_hook = SetWindowsHookExA(WH_KEYBOARD_LL, KeyboardHookProc, GetModuleHandleA(NULL), 0);
19125 if (!hKBD_hook) win_skip("WH_KEYBOARD_LL is not supported\n");
19127 /* Same key combination, different id */
19128 SetLastError(0xdeadbeef);
19129 ret = RegisterHotKey(test_window, 4, MOD_WIN, hotkey_letter);
19130 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
19131 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
19132 "unexpected error %ld\n", GetLastError());
19134 /* Same key combination, different window */
19135 SetLastError(0xdeadbeef);
19136 ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
19137 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
19138 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
19139 "unexpected error %ld\n", GetLastError());
19141 /* Register the same hotkey twice */
19142 SetLastError(0xdeadbeef);
19143 ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
19144 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
19145 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
19146 "unexpected error %ld\n", GetLastError());
19148 /* Window on another thread */
19149 taskbar_window = FindWindowA("Shell_TrayWnd", NULL);
19150 if (!taskbar_window)
19152 skip("no taskbar?\n");
19154 else
19156 SetLastError(0xdeadbeef);
19157 ret = RegisterHotKey(taskbar_window, 5, 0, hotkey_letter);
19158 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
19159 ok(GetLastError() == ERROR_WINDOW_OF_OTHER_THREAD || broken(GetLastError() == 0xdeadbeef),
19160 "unexpected error %ld\n", GetLastError());
19163 /* Inject the appropriate key sequence */
19164 keybd_event(VK_LWIN, 0, 0, 0);
19165 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
19166 DispatchMessageA(&msg);
19167 ok_sequence(WmHotkeyPressLWIN, "window hotkey press LWIN", FALSE);
19169 keybd_event(hotkey_letter, 0, 0, 0);
19170 queue_status = GetQueueStatus(QS_HOTKEY);
19171 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %lx\n", queue_status);
19172 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
19174 if (msg.message == WM_HOTKEY)
19176 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
19177 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %Ix\n", msg.lParam);
19179 DispatchMessageA(&msg);
19181 ok_sequence(WmHotkeyPress, "window hotkey press", FALSE);
19183 queue_status = GetQueueStatus(QS_HOTKEY);
19184 ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %lx\n", queue_status);
19186 key_state = GetAsyncKeyState(hotkey_letter);
19187 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
19189 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
19190 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
19191 DispatchMessageA(&msg);
19192 ok_sequence(WmHotkeyRelease, "window hotkey release", TRUE);
19194 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
19195 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
19196 DispatchMessageA(&msg);
19197 ok_sequence(WmHotkeyReleaseLWIN, "window hotkey release LWIN", FALSE);
19199 /* normal posted WM_HOTKEY messages set QS_HOTKEY */
19200 PostMessageA(test_window, WM_HOTKEY, 0, 0);
19201 queue_status = GetQueueStatus(QS_HOTKEY);
19202 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %lx\n", queue_status);
19203 queue_status = GetQueueStatus(QS_POSTMESSAGE);
19204 ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %lx\n", queue_status);
19205 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
19206 DispatchMessageA(&msg);
19207 flush_sequence();
19209 /* Send and process all messages at once */
19210 PostMessageA(test_window, WM_APP, 0, 0);
19211 keybd_event(VK_LWIN, 0, 0, 0);
19212 keybd_event(hotkey_letter, 0, 0, 0);
19213 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
19214 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
19216 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
19218 if (msg.message == WM_HOTKEY)
19220 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
19221 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %Ix\n", msg.lParam);
19223 DispatchMessageA(&msg);
19225 ok_sequence(WmHotkeyCombined, "window hotkey combined", FALSE);
19227 /* Register same hwnd/id with different key combination */
19228 ret = RegisterHotKey(test_window, 5, 0, hotkey_letter);
19229 ok(ret == TRUE, "expected TRUE, got %i, err=%ld\n", ret, GetLastError());
19231 /* Previous key combination does not work */
19232 keybd_event(VK_LWIN, 0, 0, 0);
19233 keybd_event(hotkey_letter, 0, 0, 0);
19234 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
19235 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
19237 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
19238 DispatchMessageA(&msg);
19239 ok_sequence(WmHotkeyPrevious, "window hotkey previous", FALSE);
19241 /* New key combination works */
19242 keybd_event(hotkey_letter, 0, 0, 0);
19243 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
19245 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
19247 if (msg.message == WM_HOTKEY)
19249 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
19250 ok(msg.lParam == MAKELPARAM(0, hotkey_letter), "unexpected WM_HOTKEY lparam %Ix\n", msg.lParam);
19252 DispatchMessageA(&msg);
19254 ok_sequence(WmHotkeyNew, "window hotkey new", FALSE);
19256 /* Unregister hotkey properly */
19257 ret = UnregisterHotKey(test_window, 5);
19258 ok(ret == TRUE, "expected TRUE, got %i, err=%ld\n", ret, GetLastError());
19260 /* Unregister hotkey again */
19261 SetLastError(0xdeadbeef);
19262 ret = UnregisterHotKey(test_window, 5);
19263 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
19264 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
19265 "unexpected error %ld\n", GetLastError());
19267 /* Register thread hotkey */
19268 ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
19269 ok(ret == TRUE, "expected TRUE, got %i, err=%ld\n", ret, GetLastError());
19271 /* Inject the appropriate key sequence */
19272 keybd_event(VK_LWIN, 0, 0, 0);
19273 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
19275 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
19276 DispatchMessageA(&msg);
19278 ok_sequence(WmHotkeyPressLWIN, "thread hotkey press LWIN", FALSE);
19280 keybd_event(hotkey_letter, 0, 0, 0);
19281 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
19283 if (msg.message == WM_HOTKEY)
19285 struct recvd_message message;
19286 ok(msg.hwnd == NULL, "unexpected hwnd %p\n", msg.hwnd);
19287 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %Ix\n", msg.lParam);
19288 message.message = msg.message;
19289 message.flags = sent|wparam|lparam;
19290 message.wParam = msg.wParam;
19291 message.lParam = msg.lParam;
19292 message.descr = "test_hotkey thread message";
19293 add_message(&message);
19295 else
19296 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
19297 DispatchMessageA(&msg);
19299 ok_sequence(WmHotkeyPress, "thread hotkey press", FALSE);
19301 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
19302 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
19304 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
19305 DispatchMessageA(&msg);
19307 ok_sequence(WmHotkeyRelease, "thread hotkey release", TRUE);
19309 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
19310 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
19312 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
19313 DispatchMessageA(&msg);
19315 ok_sequence(WmHotkeyReleaseLWIN, "thread hotkey release LWIN", FALSE);
19317 /* Search for an ALT + letter combination that hasn't been registered */
19318 for (hotkey_letter = 'A'; hotkey_letter <= 'Z'; hotkey_letter ++)
19320 SetLastError(0xdeadbeef);
19321 ret = RegisterHotKey(test_window, 6, MOD_ALT, hotkey_letter);
19323 if (ret == TRUE)
19325 break;
19327 else
19329 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
19330 "unexpected error %ld\n", GetLastError());
19334 if (hotkey_letter > 'Z')
19336 ok(0, "Couldn't find any free ALT + letter combination\n");
19337 goto end;
19340 keybd_event(VK_LMENU, 0, 0, 0);
19341 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
19342 DispatchMessageA(&msg);
19343 ok_sequence(WmHotkeyPressALT, "window hotkey press ALT", TRUE);
19345 keybd_event(hotkey_letter, 0, 0, 0);
19346 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
19348 if (msg.message == WM_HOTKEY)
19350 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
19351 ok(msg.lParam == MAKELPARAM(MOD_ALT, hotkey_letter), "unexpected WM_HOTKEY lparam %Ix\n", msg.lParam);
19353 DispatchMessageA(&msg);
19355 ok_sequence(WmHotkeyPressWithALT, "window hotkey press with ALT", FALSE);
19357 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
19358 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
19359 DispatchMessageA(&msg);
19360 ok_sequence(WmHotkeyReleaseWithALT, "window hotkey release with ALT", TRUE);
19362 keybd_event(VK_LMENU, 0, KEYEVENTF_KEYUP, 0);
19363 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
19364 DispatchMessageA(&msg);
19365 ok_sequence(WmHotkeyReleaseALT, "window hotkey release ALT", FALSE);
19367 /* Unregister thread hotkey */
19368 ret = UnregisterHotKey(NULL, 5);
19369 ok(ret == TRUE, "expected TRUE, got %i, err=%ld\n", ret, GetLastError());
19371 if (hKBD_hook) UnhookWindowsHookEx(hKBD_hook);
19372 hKBD_hook = NULL;
19374 end:
19375 UnregisterHotKey(NULL, 5);
19376 UnregisterHotKey(test_window, 5);
19377 UnregisterHotKey(test_window, 6);
19378 DestroyWindow(test_window);
19379 flush_sequence();
19383 static const struct message WmSetFocus_1[] = {
19384 { HCBT_SETFOCUS, hook }, /* child */
19385 { HCBT_ACTIVATE, hook }, /* parent */
19386 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
19387 { WM_QUERYNEWPALETTE, sent|wparam|lparam|parent|optional, 0, 0 },
19388 { WM_WINDOWPOSCHANGING, sent|parent, 0, SWP_NOSIZE|SWP_NOMOVE },
19389 { WM_ACTIVATEAPP, sent|wparam|parent, 1 },
19390 { WM_NCACTIVATE, sent|parent },
19391 { WM_GETTEXT, sent|defwinproc|parent|optional },
19392 { WM_GETTEXT, sent|defwinproc|parent|optional },
19393 { WM_ACTIVATE, sent|wparam|parent, 1 },
19394 { HCBT_SETFOCUS, hook }, /* parent */
19395 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
19396 { WM_SETFOCUS, sent|defwinproc|parent },
19397 { WM_KILLFOCUS, sent|parent },
19398 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
19399 { WM_SETFOCUS, sent },
19400 { 0 }
19402 static const struct message WmSetFocus_2[] = {
19403 { HCBT_SETFOCUS, hook }, /* parent */
19404 { WM_KILLFOCUS, sent },
19405 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
19406 { WM_SETFOCUS, sent|parent },
19407 { 0 }
19409 static const struct message WmSetFocus_3[] = {
19410 { HCBT_SETFOCUS, hook }, /* child */
19411 { 0 }
19414 static void test_SetFocus(void)
19416 HWND parent, old_parent, child, old_focus, old_active;
19417 MSG msg;
19418 struct wnd_event wnd_event;
19419 HANDLE hthread;
19420 DWORD ret, tid;
19422 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
19423 ok(wnd_event.start_event != 0, "CreateEvent error %ld\n", GetLastError());
19424 hthread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
19425 ok(hthread != 0, "CreateThread error %ld\n", GetLastError());
19426 ret = WaitForSingleObject(wnd_event.start_event, INFINITE);
19427 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
19428 CloseHandle(wnd_event.start_event);
19430 parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
19431 0, 0, 0, 0, 0, 0, 0, NULL);
19432 ok(parent != 0, "failed to create parent window\n");
19433 child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
19434 0, 0, 0, 0, parent, 0, 0, NULL);
19435 ok(child != 0, "failed to create child window\n");
19437 if (winetest_debug > 1) trace("parent %p, child %p, thread window %p\n", parent, child, wnd_event.hwnd);
19439 SetFocus(0);
19440 SetActiveWindow(0);
19442 flush_events();
19443 flush_sequence();
19445 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
19446 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
19448 log_all_parent_messages++;
19450 old_focus = SetFocus(child);
19451 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
19452 ok_sequence(WmSetFocus_1, "SetFocus on a child window", TRUE);
19453 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
19454 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
19455 ok(GetFocus() == child, "expected focus %p, got %p\n", child, GetFocus());
19457 old_focus = SetFocus(parent);
19458 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
19459 ok_sequence(WmSetFocus_2, "SetFocus on a parent window", FALSE);
19460 ok(old_focus == child, "expected old focus %p, got %p\n", child, old_focus);
19461 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
19462 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
19464 SetLastError(0xdeadbeef);
19465 old_focus = SetFocus((HWND)0xdeadbeef);
19466 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
19467 "expected ERROR_INVALID_WINDOW_HANDLE, got %ld\n", GetLastError());
19468 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
19469 ok_sequence(WmEmptySeq, "SetFocus on an invalid window", FALSE);
19470 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
19471 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
19472 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
19474 SetLastError(0xdeadbeef);
19475 old_focus = SetFocus(GetDesktopWindow());
19476 ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
19477 broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
19478 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
19479 ok_sequence(WmEmptySeq, "SetFocus on a desktop window", TRUE);
19480 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
19481 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
19482 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
19484 SetLastError(0xdeadbeef);
19485 old_focus = SetFocus(wnd_event.hwnd);
19486 ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
19487 broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
19488 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
19489 ok_sequence(WmEmptySeq, "SetFocus on another thread window", TRUE);
19490 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
19491 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
19492 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
19494 SetLastError(0xdeadbeef);
19495 old_active = SetActiveWindow((HWND)0xdeadbeef);
19496 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
19497 "expected ERROR_INVALID_WINDOW_HANDLE, got %ld\n", GetLastError());
19498 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
19499 ok_sequence(WmEmptySeq, "SetActiveWindow on an invalid window", FALSE);
19500 ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
19501 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
19502 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
19504 SetLastError(0xdeadbeef);
19505 old_active = SetActiveWindow(GetDesktopWindow());
19506 todo_wine
19507 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
19508 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
19509 ok_sequence(WmEmptySeq, "SetActiveWindow on a desktop window", TRUE);
19510 ok(old_active == 0, "expected old focus 0, got %p\n", old_focus);
19511 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
19512 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
19514 SetLastError(0xdeadbeef);
19515 old_active = SetActiveWindow(wnd_event.hwnd);
19516 todo_wine
19517 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
19518 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
19519 ok_sequence(WmEmptySeq, "SetActiveWindow on another thread window", TRUE);
19520 ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
19521 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
19522 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
19524 SetLastError(0xdeadbeef);
19525 ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE);
19526 ok(ret, "AttachThreadInput error %ld\n", GetLastError());
19528 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
19529 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
19531 flush_events();
19532 flush_sequence();
19534 old_focus = SetFocus(wnd_event.hwnd);
19535 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
19536 ok(old_focus == wnd_event.hwnd, "expected old focus %p, got %p\n", wnd_event.hwnd, old_focus);
19537 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
19538 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
19540 old_focus = SetFocus(parent);
19541 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
19542 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
19543 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
19544 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
19546 flush_events();
19547 flush_sequence();
19549 old_active = SetActiveWindow(wnd_event.hwnd);
19550 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
19551 ok(old_active == parent, "expected old focus %p, got %p\n", parent, old_active);
19552 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
19553 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
19555 SetLastError(0xdeadbeef);
19556 ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE);
19557 ok(ret, "AttachThreadInput error %ld\n", GetLastError());
19559 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
19560 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
19562 old_parent = SetParent(child, GetDesktopWindow());
19563 ok(old_parent == parent, "expected old parent %p, got %p\n", parent, old_parent);
19565 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
19566 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
19568 old_focus = SetFocus(parent);
19569 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
19570 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
19571 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
19572 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
19574 flush_events();
19575 flush_sequence();
19577 SetLastError(0xdeadbeef);
19578 old_focus = SetFocus(child);
19579 todo_wine
19580 ok(GetLastError() == ERROR_INVALID_PARAMETER /* Vista+ */ ||
19581 broken(GetLastError() == 0) /* XP */ ||
19582 broken(GetLastError() == 0xdeadbeef), "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
19583 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
19584 ok_sequence(WmSetFocus_3, "SetFocus on a child window", TRUE);
19585 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
19586 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
19587 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
19589 SetLastError(0xdeadbeef);
19590 old_active = SetActiveWindow(child);
19591 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
19592 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
19593 ok_sequence(WmEmptySeq, "SetActiveWindow on a child window", FALSE);
19594 ok(old_active == parent, "expected old active %p, got %p\n", parent, old_active);
19595 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
19596 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
19598 log_all_parent_messages--;
19600 DestroyWindow(child);
19601 DestroyWindow(parent);
19603 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
19604 ok(ret, "PostMessage(WM_QUIT) error %ld\n", GetLastError());
19605 ret = WaitForSingleObject(hthread, INFINITE);
19606 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
19607 CloseHandle(hthread);
19610 static const struct message WmSetLayeredStyle[] = {
19611 { WM_STYLECHANGING, sent },
19612 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
19613 { WM_STYLECHANGED, sent },
19614 { WM_GETTEXT, sent|defwinproc|optional },
19615 { 0 }
19618 static const struct message WmSetLayeredStyle2[] = {
19619 { WM_STYLECHANGING, sent },
19620 { WM_STYLECHANGED, sent },
19621 { WM_WINDOWPOSCHANGING, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
19622 { WM_NCCALCSIZE, sent|optional|wparam|defwinproc, 1 },
19623 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
19624 { WM_WINDOWPOSCHANGED, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
19625 { WM_MOVE, sent|optional|defwinproc|wparam, 0 },
19626 { WM_SIZE, sent|optional|defwinproc|wparam, SIZE_RESTORED },
19627 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
19628 { 0 }
19631 static const struct message WmLayeredWinEmptySeq[] = {
19632 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
19633 { 0 }
19636 struct layered_window_info
19638 HWND hwnd;
19639 HDC hdc;
19640 SIZE size;
19641 HANDLE event;
19642 BOOL ret;
19645 static DWORD CALLBACK update_layered_proc( void *param )
19647 struct layered_window_info *info = param;
19648 POINT src = { 0, 0 };
19650 info->ret = pUpdateLayeredWindow( info->hwnd, 0, NULL, &info->size,
19651 info->hdc, &src, 0, NULL, ULW_OPAQUE );
19652 ok( info->ret, "failed\n");
19653 SetEvent( info->event );
19654 return 0;
19657 static void test_layered_window(void)
19659 HWND hwnd;
19660 HDC hdc;
19661 HBITMAP bmp;
19662 BOOL ret;
19663 SIZE size;
19664 POINT pos, src;
19665 RECT rect, client;
19666 HANDLE thread;
19667 DWORD tid;
19668 struct layered_window_info info;
19670 if (!pUpdateLayeredWindow)
19672 win_skip( "UpdateLayeredWindow not supported\n" );
19673 return;
19676 hdc = CreateCompatibleDC( 0 );
19677 bmp = CreateCompatibleBitmap( hdc, 300, 300 );
19678 SelectObject( hdc, bmp );
19680 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_CAPTION | WS_THICKFRAME | WS_SYSMENU,
19681 100, 100, 300, 300, 0, 0, 0, NULL);
19682 ok( hwnd != 0, "failed to create window\n" );
19683 ShowWindow( hwnd, SW_SHOWNORMAL );
19684 UpdateWindow( hwnd );
19685 flush_events();
19686 flush_sequence();
19688 GetWindowRect( hwnd, &rect );
19689 GetClientRect( hwnd, &client );
19690 ok( client.right < rect.right - rect.left, "wrong client area\n" );
19691 ok( client.bottom < rect.bottom - rect.top, "wrong client area\n" );
19693 src.x = src.y = 0;
19694 pos.x = pos.y = 300;
19695 size.cx = size.cy = 250;
19696 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
19697 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
19698 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() );
19699 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
19700 ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
19702 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
19703 ok( ret, "UpdateLayeredWindow failed err %lu\n", GetLastError() );
19704 ok_sequence( WmLayeredWinEmptySeq, "UpdateLayeredWindow", FALSE );
19705 GetWindowRect( hwnd, &rect );
19706 ok( rect.left == 300 && rect.top == 300 && rect.right == 550 && rect.bottom == 550,
19707 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
19708 GetClientRect( hwnd, &rect );
19709 ok( rect.right == client.right - 50 && rect.bottom == client.bottom - 50,
19710 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
19712 size.cx = 150;
19713 pos.y = 200;
19714 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
19715 ok( ret, "UpdateLayeredWindow failed err %lu\n", GetLastError() );
19716 ok_sequence( WmLayeredWinEmptySeq, "UpdateLayeredWindow", FALSE );
19717 GetWindowRect( hwnd, &rect );
19718 ok( rect.left == 300 && rect.top == 200 && rect.right == 450 && rect.bottom == 450,
19719 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
19720 GetClientRect( hwnd, &rect );
19721 ok( rect.right == client.right - 150 && rect.bottom == client.bottom - 50,
19722 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
19724 SetWindowLongA( hwnd, GWL_STYLE,
19725 GetWindowLongA(hwnd, GWL_STYLE) & ~(WS_CAPTION | WS_THICKFRAME | WS_SYSMENU) );
19726 ok_sequence( WmSetLayeredStyle2, "WmSetLayeredStyle2", FALSE );
19728 size.cx = 200;
19729 pos.x = 200;
19730 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
19731 ok( ret, "UpdateLayeredWindow failed err %lu\n", GetLastError() );
19732 ok_sequence( WmLayeredWinEmptySeq, "UpdateLayeredWindow", FALSE );
19733 GetWindowRect( hwnd, &rect );
19734 ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
19735 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
19736 GetClientRect( hwnd, &rect );
19737 ok( (rect.right == 200 && rect.bottom == 250) ||
19738 broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
19739 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
19741 size.cx = 0;
19742 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
19743 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
19744 ok( GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == ERROR_MR_MID_NOT_FOUND) ||
19745 broken(GetLastError() == ERROR_GEN_FAILURE) /* win7 */, "wrong error %lu\n", GetLastError() );
19746 size.cx = 1;
19747 size.cy = -1;
19748 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
19749 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
19750 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() );
19752 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED );
19753 ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
19754 GetWindowRect( hwnd, &rect );
19755 ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
19756 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
19757 GetClientRect( hwnd, &rect );
19758 ok( (rect.right == 200 && rect.bottom == 250) ||
19759 broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
19760 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
19762 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
19763 info.hwnd = hwnd;
19764 info.hdc = hdc;
19765 info.size.cx = 250;
19766 info.size.cy = 300;
19767 info.event = CreateEventA( NULL, TRUE, FALSE, NULL );
19768 info.ret = FALSE;
19769 thread = CreateThread( NULL, 0, update_layered_proc, &info, 0, &tid );
19770 ok( WaitForSingleObject( info.event, 1000 ) == 0, "wait failed\n" );
19771 ok( info.ret, "UpdateLayeredWindow failed in other thread\n" );
19772 WaitForSingleObject( thread, 1000 );
19773 CloseHandle( thread );
19774 GetWindowRect( hwnd, &rect );
19775 ok( rect.left == 200 && rect.top == 200 && rect.right == 450 && rect.bottom == 500,
19776 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
19777 GetClientRect( hwnd, &rect );
19778 ok( (rect.right == 250 && rect.bottom == 300) ||
19779 broken(rect.right == client.right - 50 && rect.bottom == client.bottom),
19780 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
19782 DestroyWindow( hwnd );
19783 DeleteDC( hdc );
19784 DeleteObject( bmp );
19787 static HMENU hpopupmenu;
19789 static LRESULT WINAPI minimize_popup_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
19791 LRESULT ret;
19793 if (ignore_message( message )) return 0;
19794 ret = MsgCheckProc( FALSE, hwnd, message, wParam, lParam );
19796 switch (message) {
19797 case WM_ENTERIDLE:
19798 ShowWindow(hwnd, SW_MINIMIZE);
19799 break;
19800 case WM_TIMER:
19801 EndMenu();
19802 break;
19805 return ret;
19808 static LRESULT WINAPI cancel_popup_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
19810 if (ignore_message( message )) return 0;
19812 switch (message) {
19813 case WM_ENTERIDLE:
19814 todo_wine ok(GetCapture() == hwnd, "expected %p, got %p\n", hwnd, GetCapture());
19815 EndMenu();
19816 break;
19817 case WM_INITMENU:
19818 case WM_INITMENUPOPUP:
19819 case WM_UNINITMENUPOPUP:
19820 ok((HMENU)wParam == hpopupmenu, "expected %p, got %Ix\n", hpopupmenu, wParam);
19821 break;
19822 case WM_CAPTURECHANGED:
19823 todo_wine ok(!lParam || (HWND)lParam == hwnd, "lost capture to %Ix\n", lParam);
19824 break;
19827 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
19830 static LRESULT WINAPI cancel_init_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
19832 if (ignore_message( message )) return 0;
19834 switch (message) {
19835 case WM_ENTERMENULOOP:
19836 ok(EndMenu() == TRUE, "EndMenu() failed\n");
19837 break;
19840 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
19843 static void test_TrackPopupMenu(void)
19845 MSG msg;
19846 HWND hwnd;
19847 BOOL ret;
19849 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
19850 0, 0, 1, 1, 0,
19851 NULL, NULL, 0);
19852 ok(hwnd != NULL, "CreateWindowEx failed with error %ld\n", GetLastError());
19854 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
19856 hpopupmenu = CreatePopupMenu();
19857 ok(hpopupmenu != NULL, "CreateMenu failed with error %ld\n", GetLastError());
19859 AppendMenuA(hpopupmenu, MF_STRING, 100, "item 1");
19860 AppendMenuA(hpopupmenu, MF_STRING, 100, "item 2");
19862 flush_events();
19863 flush_sequence();
19864 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
19865 ok_sequence(WmTrackPopupMenu, "TrackPopupMenu", TRUE);
19866 ok(ret == 1, "TrackPopupMenu failed with error %li\n", GetLastError());
19868 /* Test popup closing with an ESC-press */
19869 flush_events();
19870 PostMessageW(hwnd, WM_KEYDOWN, VK_ESCAPE, 0);
19871 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
19872 ok(ret == 1, "TrackPopupMenu failed with error %li\n", GetLastError());
19873 PostQuitMessage(0);
19874 flush_sequence();
19875 while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
19877 TranslateMessage(&msg);
19878 DispatchMessageA(&msg);
19880 ok_sequence(WmTrackPopupMenuEsc, "TrackPopupMenuEsc", FALSE); /* Shouldn't get any message */
19882 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_init_proc);
19884 flush_events();
19885 flush_sequence();
19886 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
19887 ok_sequence(WmTrackPopupMenuAbort, "WmTrackPopupMenuAbort", TRUE);
19888 ok(ret == TRUE, "TrackPopupMenu failed\n");
19890 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)minimize_popup_proc);
19892 /* set cursor over the window, otherwise the WM_CANCELMODE message may not always be sent */
19893 SetCursorPos( 0, 0 );
19894 ShowWindow( hwnd, SW_SHOW );
19896 flush_events();
19897 flush_sequence();
19898 SetTimer( hwnd, TIMER_ID, 500, NULL );
19899 ret = TrackPopupMenu( hpopupmenu, 0, 100,100, 0, hwnd, NULL );
19900 ok_sequence( WmTrackPopupMenuMinimizeWindow, "TrackPopupMenuMinimizeWindow", TRUE );
19901 ok( ret == 1, "TrackPopupMenu failed with error %li\n", GetLastError() );
19902 KillTimer( hwnd, TIMER_ID );
19903 ShowWindow( hwnd, SW_RESTORE );
19905 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
19907 SetCapture(hwnd);
19909 flush_events();
19910 flush_sequence();
19911 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
19912 ok_sequence(WmTrackPopupMenuCapture, "TrackPopupMenuCapture", TRUE);
19913 ok(ret == 1, "TrackPopupMenuCapture failed with error %li\n", GetLastError());
19915 DestroyMenu(hpopupmenu);
19916 DestroyWindow(hwnd);
19919 static void test_TrackPopupMenuEmpty(void)
19921 HWND hwnd;
19922 BOOL ret;
19924 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
19925 0, 0, 1, 1, 0,
19926 NULL, NULL, 0);
19927 ok(hwnd != NULL, "CreateWindowEx failed with error %ld\n", GetLastError());
19929 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
19931 hpopupmenu = CreatePopupMenu();
19932 ok(hpopupmenu != NULL, "CreateMenu failed with error %ld\n", GetLastError());
19934 flush_events();
19935 flush_sequence();
19936 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
19937 ok_sequence(WmTrackPopupMenuEmpty, "TrackPopupMenuEmpty", TRUE);
19938 ok(ret == 0, "TrackPopupMenu succeeded\n");
19940 DestroyMenu(hpopupmenu);
19941 DestroyWindow(hwnd);
19944 static const struct message send_message_1[] = {
19945 { WM_USER+2, sent|wparam|lparam, 0, 0 },
19946 { WM_USER, sent|wparam|lparam, 0, 0 },
19947 { 0 }
19949 static const struct message send_message_2[] = {
19950 { WM_USER+4, sent|wparam|lparam, 0, 0 },
19951 { 0 }
19953 static const struct message send_message_3[] = {
19954 { WM_USER+3, sent|wparam|lparam, 0, 0 },
19955 { WM_USER+1, sent|wparam|lparam, 0, 0 },
19956 { 0 }
19958 static const struct message send_message_5[] = {
19959 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE, 0, SWP_NOZORDER }, /* win7+ dual monitor */
19960 { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* win7+ dual monitor */
19961 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE, 0, SWP_NOZORDER }, /* win7+ dual monitor */
19962 { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* win7+ dual monitor */
19963 { 0 }
19966 static DWORD WINAPI SendMessage_thread_1(void *param)
19968 struct wnd_event *wnd_event = param;
19969 DWORD ret;
19971 if (winetest_debug > 1) trace("thread: starting\n");
19972 WaitForSingleObject(wnd_event->start_event, INFINITE);
19974 if (winetest_debug > 1) trace("thread: call PostMessage\n");
19975 PostMessageA(wnd_event->hwnd, WM_USER, 0, 0);
19977 if (winetest_debug > 1) trace("thread: call PostMessage\n");
19978 PostMessageA(wnd_event->hwnd, WM_USER+1, 0, 0);
19980 if (winetest_debug > 1) trace("thread: call SendMessage\n");
19981 SendMessageA(wnd_event->hwnd, WM_USER+2, 0, 0);
19982 SetEvent(wnd_event->stop_event);
19983 ret = WaitForSingleObject(wnd_event->getmessage_complete, 100);
19984 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed, ret:%lx\n", ret);
19986 if (winetest_debug > 1) trace("thread: call SendMessage\n");
19987 SendMessageA(wnd_event->hwnd, WM_USER+3, 0, 0);
19989 return 0;
19992 static void test_SendMessage_other_thread(void)
19994 DWORD qs_all_input = QS_ALLINPUT & ~QS_RAWINPUT;
19995 HANDLE hthread;
19996 struct wnd_event wnd_event;
19997 DWORD tid, ret;
19998 MSG msg;
20000 wnd_event.start_event = CreateEventA(NULL, 0, 0, NULL);
20001 wnd_event.stop_event = CreateEventA(NULL, 0, 0, NULL);
20002 wnd_event.getmessage_complete = CreateEventA(NULL, 0, 0, NULL);
20004 wnd_event.hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
20005 100, 100, 200, 200, 0, 0, 0, NULL);
20006 ok(wnd_event.hwnd != 0, "CreateWindowEx failed\n");
20008 hthread = CreateThread(NULL, 0, SendMessage_thread_1, &wnd_event, 0, &tid);
20009 ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError());
20010 CloseHandle(hthread);
20012 flush_events();
20013 flush_sequence();
20015 ret = GetQueueStatus(QS_SENDMESSAGE);
20016 ok(ret == 0, "wrong status %08lx\n", ret);
20018 SetEvent(wnd_event.start_event);
20020 /* wait for other thread's SendMessage */
20021 for (;;)
20023 ret = GetQueueStatus(QS_SENDMESSAGE);
20024 if (ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE)) break;
20025 Sleep(50);
20028 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
20029 ok(ret == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08lx\n", ret);
20031 if (winetest_debug > 1) trace("main: call GetMessage\n");
20032 GetMessageA(&msg, 0, 0, 0);
20033 ok(msg.message == WM_USER, "expected WM_USER, got %04x\n", msg.message);
20034 DispatchMessageA(&msg);
20035 ok_sequence(send_message_1, "SendMessage from other thread 1", FALSE);
20037 SetEvent(wnd_event.getmessage_complete);
20039 ret = WaitForSingleObject(wnd_event.stop_event, 100);
20040 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed, ret:%lx\n", ret);
20042 /* intentionally yield */
20043 MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input);
20045 if (winetest_debug > 1) trace("main: call SendMessage\n");
20046 SendMessageA(wnd_event.hwnd, WM_USER+4, 0, 0);
20047 ok_sequence(send_message_2, "SendMessage from other thread 2", FALSE);
20049 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
20050 ok(ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08lx\n", ret);
20052 if (winetest_debug > 1) trace("main: call PeekMessage\n");
20053 ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should not fail\n");
20054 ok(msg.message == WM_USER+1, "expected WM_USER+1, got %04x\n", msg.message);
20055 DispatchMessageA(&msg);
20056 ok_sequence(send_message_3, "SendMessage from other thread 3", FALSE);
20058 /* intentionally yield */
20059 MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input);
20061 if (winetest_debug > 1) trace("main: call PeekMessage\n");
20062 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
20063 ok(ignore_message(msg.message), "got unexpected message %04x from PeekMessageA\n", msg.message);
20065 ok_sequence(send_message_5, "SendMessage from other thread 5", FALSE);
20067 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
20068 ok(ret == 0, "wrong status %08lx\n", ret);
20070 if (winetest_debug > 1) trace("main: call DestroyWindow\n");
20071 DestroyWindow(msg.hwnd);
20073 flush_events();
20074 flush_sequence();
20076 CloseHandle(wnd_event.start_event);
20077 CloseHandle(wnd_event.stop_event);
20078 CloseHandle(wnd_event.getmessage_complete);
20081 static DWORD WINAPI SetParent_thread(void *param)
20083 struct wnd_event *wnd_event = param;
20085 if (winetest_debug > 1) trace("thread: started\n");
20086 SetEvent(wnd_event->start_event);
20088 /* this leads to sending an internal message under Wine */
20089 if (winetest_debug > 1) trace("thread: call SetParent\n");
20090 SetParent(wnd_event->hwnd, wnd_event->hwnd);
20092 return 0;
20095 static void test_setparent_status(void)
20097 HANDLE hthread;
20098 struct wnd_event wnd_event;
20099 DWORD ret;
20101 wnd_event.start_event = CreateEventA(NULL, 0, 0, NULL);
20103 wnd_event.hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
20104 100, 100, 200, 200, 0, 0, 0, NULL);
20105 ok(wnd_event.hwnd != 0, "CreateWindowEx failed\n");
20107 ret = GetQueueStatus(QS_SENDMESSAGE);
20108 ok(ret == 0, "wrong status %08lx\n", ret);
20110 hthread = CreateThread(NULL, 0, SetParent_thread, &wnd_event, 0, NULL);
20111 ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError());
20113 WaitForSingleObject(wnd_event.start_event, INFINITE);
20115 /* background thread's SetParent should complete allowing the thread to exit */
20116 ret = MsgWaitForMultipleObjects(1, &hthread, FALSE, 1000, QS_SENDMESSAGE);
20117 todo_wine ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %08lx\n", ret);
20119 /* QS_SENDMESSAGE status should not have been set by SetParent */
20120 ret = GetQueueStatus(QS_SENDMESSAGE);
20121 todo_wine ok(ret == 0, "wrong status %08lx\n", ret);
20123 DestroyWindow(wnd_event.hwnd);
20125 WaitForSingleObject(hthread, INFINITE);
20126 CloseHandle(hthread);
20127 CloseHandle(wnd_event.start_event);
20130 static LRESULT CALLBACK insendmessage_wnd_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
20132 DWORD flags = InSendMessageEx( NULL );
20133 BOOL ret;
20135 switch (msg)
20137 case WM_USER:
20138 ok( flags == ISMEX_SEND, "wrong flags %lx\n", flags );
20139 ok( InSendMessage(), "InSendMessage returned false\n" );
20140 ret = ReplyMessage( msg );
20141 ok( ret, "ReplyMessage failed err %lu\n", GetLastError() );
20142 flags = InSendMessageEx( NULL );
20143 ok( flags == (ISMEX_SEND | ISMEX_REPLIED) || broken( flags == (ISMEX_NOTIFY | ISMEX_REPLIED) ),
20144 "wrong flags %lx\n", flags );
20145 ok( InSendMessage(), "InSendMessage returned false\n" );
20146 break;
20147 case WM_USER + 1:
20148 ok( flags == ISMEX_NOTIFY, "wrong flags %lx\n", flags );
20149 ok( InSendMessage(), "InSendMessage returned false\n" );
20150 ret = ReplyMessage( msg );
20151 ok( ret, "ReplyMessage failed err %lu\n", GetLastError() );
20152 flags = InSendMessageEx( NULL );
20153 ok( flags == ISMEX_NOTIFY, "wrong flags %lx\n", flags );
20154 ok( InSendMessage(), "InSendMessage returned false\n" );
20155 break;
20156 case WM_USER + 2:
20157 ok( flags == ISMEX_CALLBACK, "wrong flags %lx\n", flags );
20158 ok( InSendMessage(), "InSendMessage returned false\n" );
20159 ret = ReplyMessage( msg );
20160 ok( ret, "ReplyMessage failed err %lu\n", GetLastError() );
20161 flags = InSendMessageEx( NULL );
20162 ok( flags == (ISMEX_CALLBACK | ISMEX_REPLIED) || flags == ISMEX_SEND, "wrong flags %lx\n", flags );
20163 ok( InSendMessage(), "InSendMessage returned false\n" );
20164 break;
20165 case WM_USER + 3:
20166 ok( flags == ISMEX_NOSEND, "wrong flags %lx\n", flags );
20167 ok( !InSendMessage(), "InSendMessage returned true\n" );
20168 ret = ReplyMessage( msg );
20169 ok( !ret, "ReplyMessage succeeded\n" );
20170 break;
20173 return DefWindowProcA( hwnd, msg, wp, lp );
20176 static void CALLBACK msg_callback( HWND hwnd, UINT msg, ULONG_PTR arg, LRESULT result )
20178 ok( msg == WM_USER + 2, "wrong msg %x\n", msg );
20179 ok( result == WM_USER + 2, "wrong result %Ix\n", result );
20182 static DWORD WINAPI send_message_thread( void *arg )
20184 HWND win = arg;
20186 SendMessageA( win, WM_USER, 0, 0 );
20187 SendNotifyMessageA( win, WM_USER + 1, 0, 0 );
20188 SendMessageCallbackA( win, WM_USER + 2, 0, 0, msg_callback, 0 );
20189 PostMessageA( win, WM_USER + 3, 0, 0 );
20190 PostMessageA( win, WM_QUIT, 0, 0 );
20191 return 0;
20194 static void test_InSendMessage(void)
20196 WNDCLASSA cls;
20197 HWND win;
20198 MSG msg;
20199 HANDLE thread;
20200 DWORD tid;
20202 memset(&cls, 0, sizeof(cls));
20203 cls.lpfnWndProc = insendmessage_wnd_proc;
20204 cls.hInstance = GetModuleHandleA(NULL);
20205 cls.lpszClassName = "InSendMessage_test";
20206 register_class(&cls);
20208 win = CreateWindowA( "InSendMessage_test", NULL, 0, 0, 0, 0, 0, NULL, 0, NULL, 0 );
20209 ok( win != NULL, "CreateWindow failed: %ld\n", GetLastError() );
20211 thread = CreateThread( NULL, 0, send_message_thread, win, 0, &tid );
20212 ok( thread != NULL, "CreateThread failed: %ld\n", GetLastError() );
20214 while (GetMessageA(&msg, NULL, 0, 0)) DispatchMessageA( &msg );
20216 ok( WaitForSingleObject( thread, 30000 ) == WAIT_OBJECT_0, "WaitForSingleObject failed\n" );
20217 CloseHandle( thread );
20219 DestroyWindow( win );
20220 UnregisterClassA( "InSendMessage_test", GetModuleHandleA(NULL) );
20223 static const struct message DoubleSetCaptureSeq[] =
20225 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
20226 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
20227 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
20228 { WM_CAPTURECHANGED, sent },
20229 { 0 }
20232 static void test_DoubleSetCapture(void)
20234 HWND hwnd;
20236 hwnd = CreateWindowExA(0, "TestWindowClass", "Test DoubleSetCapture",
20237 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
20238 100, 100, 200, 200, 0, 0, 0, NULL);
20239 ok (hwnd != 0, "Failed to create overlapped window\n");
20241 ShowWindow( hwnd, SW_SHOW );
20242 UpdateWindow( hwnd );
20243 flush_events();
20244 flush_sequence();
20246 SetCapture( hwnd );
20247 SetCapture( hwnd );
20248 ok_sequence(DoubleSetCaptureSeq, "SetCapture( hwnd ) twice", FALSE);
20250 DestroyWindow(hwnd);
20253 static const struct message WmRestoreMinimizedSeq[] =
20255 { HCBT_ACTIVATE, hook },
20256 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
20257 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
20258 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
20259 { WM_ACTIVATEAPP, sent|wparam, 1 },
20260 { WM_NCACTIVATE, sent|wparam, 0x200001 },
20261 { WM_GETTEXT, sent|defwinproc|optional },
20262 { WM_ACTIVATE, sent|wparam, 0x200001 }, /* Note that activate messages are after WM_WINDOWPOSCHANGED and before WM_SYSCOMMAND */
20263 { HCBT_KEYSKIPPED, hook|optional },
20264 { WM_SYSKEYUP, sent|optional },
20265 { WM_SYSCOMMAND, sent|wparam, SC_RESTORE },
20266 { HCBT_SYSCOMMAND, hook|wparam, SC_RESTORE },
20267 { HCBT_SYSCOMMAND, hook|wparam|optional, SC_RESTORE },
20268 { HCBT_MINMAX, hook },
20269 { HCBT_MINMAX, hook|optional },
20270 { WM_QUERYOPEN, sent|defwinproc },
20271 { WM_QUERYOPEN, sent|optional },
20272 { WM_GETTEXT, sent|defwinproc|optional },
20273 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
20274 { WM_GETMINMAXINFO, sent|defwinproc },
20275 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
20276 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
20277 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
20278 { WM_GETTEXT, sent|defwinproc|optional },
20279 { WM_ERASEBKGND, sent|defwinproc },
20280 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
20281 { WM_MOVE, sent|defwinproc },
20282 { WM_SIZE, sent|defwinproc },
20283 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
20284 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 },
20285 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
20286 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
20287 { WM_ERASEBKGND, sent|defwinproc|optional },
20288 { HCBT_SETFOCUS, hook },
20289 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
20290 { WM_SETFOCUS, sent|defwinproc },
20291 { WM_ACTIVATE, sent|wparam|defwinproc, 1 },
20292 { WM_PAINT, sent| optional },
20293 { WM_SETFOCUS, sent|defwinproc|optional },
20294 { HCBT_KEYSKIPPED, hook|optional },
20295 { WM_KEYUP, sent|optional },
20296 { HCBT_KEYSKIPPED, hook|optional },
20297 { WM_SYSKEYUP, sent|optional },
20298 { HCBT_KEYSKIPPED, hook|optional },
20299 { WM_KEYUP, sent|optional },
20300 { HCBT_KEYSKIPPED, hook|optional },
20301 { WM_SYSKEYUP, sent|optional },
20302 { HCBT_KEYSKIPPED, hook|optional },
20303 { WM_KEYUP, sent|optional },
20304 { WM_PAINT, sent| optional },
20305 { 0 }
20308 static void test_restore_messages(void)
20310 INPUT ip = {0};
20311 HWND hwnd;
20312 INT i;
20314 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100,
20315 100, 200, 200, 0, 0, 0, NULL);
20316 ok (hwnd != 0, "Failed to create overlapped window\n");
20317 SetForegroundWindow(hwnd);
20318 ShowWindow(hwnd, SW_MINIMIZE);
20319 flush_events();
20320 flush_sequence();
20322 for (i = 0; i < 5; i++)
20324 /* Send Alt+Tab to restore test window from minimized state */
20325 ip.type = INPUT_KEYBOARD;
20326 ip.ki.wVk = VK_MENU;
20327 SendInput(1, &ip, sizeof(INPUT));
20328 ip.ki.wVk = VK_TAB;
20329 SendInput(1, &ip, sizeof(INPUT));
20330 ip.ki.wVk = VK_MENU;
20331 ip.ki.dwFlags = KEYEVENTF_KEYUP;
20332 SendInput(1, &ip, sizeof(INPUT));
20333 ip.ki.wVk = VK_TAB;
20334 ip.ki.dwFlags = KEYEVENTF_KEYUP;
20335 SendInput(1, &ip, sizeof(INPUT));
20336 flush_events();
20337 if (!IsIconic(hwnd))
20338 break;
20341 if (IsIconic(hwnd))
20343 skip("Alt+Tab failed to bring up test window.\n");
20344 goto done;
20346 ok_sequence(WmRestoreMinimizedSeq, "Restore minimized window", TRUE);
20348 done:
20349 DestroyWindow(hwnd);
20352 static void test_invalid_window(void)
20354 MSG msg;
20355 BOOL ret;
20357 SetLastError(0xdeadbeef);
20358 ret = GetMessageA(&msg, (HWND)0xdeadbeef, 0, 0);
20359 ok(ret == -1, "wrong ret %d\n", ret);
20360 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %lu\n", GetLastError());
20362 SetLastError(0xdeadbeef);
20363 ret = PeekMessageA(&msg, (HWND)0xdeadbeef, 0, 0, PM_REMOVE);
20364 ok(!ret, "wrong ret %d\n", ret);
20365 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %lu\n", GetLastError());
20368 static void test_button_style(void)
20370 DWORD type, expected_type;
20371 HWND button;
20372 LRESULT ret;
20373 DWORD i, j;
20375 for (i = BS_PUSHBUTTON; i <= BS_DEFCOMMANDLINK; ++i)
20377 button = CreateWindowA(WC_BUTTONA, "test", i, 0, 0, 50, 50, NULL, 0, 0, NULL);
20378 ok(button != NULL, "Expected button not null.\n");
20380 type = GetWindowLongW(button, GWL_STYLE) & BS_TYPEMASK;
20381 expected_type = (i == BS_USERBUTTON ? BS_PUSHBUTTON : i);
20382 ok(type == expected_type, "Expected type %#lx, got %#lx.\n", expected_type, type);
20384 for (j = BS_PUSHBUTTON; j <= BS_DEFCOMMANDLINK; ++j)
20386 ret = SendMessageA(button, BM_SETSTYLE, j, FALSE);
20387 ok(ret == 0, "Expected %#x, got %#Ix.\n", 0, ret);
20389 type = GetWindowLongW(button, GWL_STYLE) & BS_TYPEMASK;
20390 expected_type = j;
20392 ok(type == expected_type, "Original type %#lx, expected new type %#lx, got %#lx.\n", i,
20393 expected_type, type);
20395 DestroyWindow(button);
20399 static LRESULT WINAPI test_create_name_procW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
20401 switch (msg)
20403 case WM_NCCREATE:
20404 case WM_CREATE:
20406 CREATESTRUCTW *cs = (CREATESTRUCTW *)lparam;
20407 memcpy( cs->lpCreateParams, cs->lpszName, 3 * sizeof(WCHAR) );
20408 break;
20410 case WM_SETTEXT:
20411 if (winetest_debug > 1) trace("%s\n", debugstr_w((const WCHAR *)lparam));
20412 break;
20415 return DefWindowProcW( hwnd, msg, wparam, lparam );
20418 static void test_create_name(void)
20420 WNDCLASSW clsW = { 0 };
20421 WCHAR name_buf[3];
20422 HWND hwnd;
20424 clsW.lpfnWndProc = test_create_name_procW;
20425 clsW.lpszClassName = L"TestCreateNameClassW";
20426 RegisterClassW( &clsW );
20428 hwnd = CreateWindowExW( 0, L"TestCreateNameClassW", L"\xffff\x6162",
20429 WS_POPUP, 0,0,0,0,0,0,0, name_buf );
20430 ok( hwnd != NULL, "CreateWindowEx failed: %lu\n", GetLastError() );
20431 ok(!memcmp(name_buf, L"\xffff\x6162", 2 * sizeof(WCHAR)),
20432 "name param = %s\n", debugstr_wn(name_buf, 2));
20433 DestroyWindow( hwnd );
20435 hwnd = CreateWindowExA( 0, "TestCreateNameClassW", "\xff\0\x61\x60",
20436 WS_POPUP, 0,0,0,0,0,0,0, name_buf );
20437 ok( hwnd != NULL, "CreateWindowEx failed: %lu\n", GetLastError() );
20438 ok(!memcmp(name_buf, L"\xffff\x6100", 2 * sizeof(WCHAR)),
20439 "name param = %s\n", debugstr_wn(name_buf, 2));
20440 DestroyWindow( hwnd );
20442 UnregisterClassW( L"TestCreateNameClassW", NULL );
20445 static LRESULT WINAPI changed_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
20447 if (msg == WM_USER) return 3;
20448 return DefWindowProcW( hwnd, msg, wparam, lparam );
20451 static LRESULT WINAPI call_window_proc_hook( INT code, WPARAM wparam, LPARAM lparam )
20453 CWPSTRUCT *cwp = (CWPSTRUCT *)lparam;
20455 ok( cwp->message == WM_USER, "message = %u\n", cwp->message );
20456 SetWindowLongPtrW( cwp->hwnd, GWLP_WNDPROC, (LONG_PTR)changed_window_proc );
20457 return CallNextHookEx( NULL, code, wparam, lparam );
20460 static void test_hook_changing_window_proc(void)
20462 HWND hwnd;
20463 HHOOK hook;
20464 LRESULT res;
20466 hwnd = CreateWindowExW( 0, L"static", NULL, WS_POPUP, 0,0,0,0,GetDesktopWindow(),0,0, NULL );
20467 hook = SetWindowsHookExW( WH_CALLWNDPROC, call_window_proc_hook, NULL, GetCurrentThreadId() );
20468 ok( hook != NULL, "SetWindowsHookExW failed: %lu\n", GetLastError() );
20470 res = SendMessageW( hwnd, WM_USER, 1, 2 );
20471 ok( res == 3, "SendMessageW(WM_USER) returned %Iu\n", res );
20473 UnhookWindowsHookEx( hook );
20474 DestroyWindow( hwnd );
20477 START_TEST(msg)
20479 char **test_argv;
20480 BOOL ret;
20481 BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
20482 int argc;
20484 argc = winetest_get_mainargs( &test_argv );
20485 if (argc >= 3)
20487 unsigned int arg;
20488 /* Child process. */
20489 sscanf (test_argv[2], "%d", (unsigned int *) &arg);
20490 do_wait_idle_child( arg );
20491 return;
20494 InitializeCriticalSection( &sequence_cs );
20495 init_procs();
20496 ImmDisableIME(0);
20498 register_classes();
20500 if (pSetWinEventHook)
20502 hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
20503 GetModuleHandleA(0), win_event_proc,
20504 0, GetCurrentThreadId(),
20505 WINEVENT_INCONTEXT);
20506 if (pIsWinEventHookInstalled && hEvent_hook)
20508 UINT event;
20509 for (event = EVENT_MIN; event <= EVENT_MAX; event++)
20510 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
20513 if (!hEvent_hook) win_skip( "no win event hook support\n" );
20515 cbt_hook_thread_id = winevent_hook_thread_id = GetCurrentThreadId();
20516 hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
20517 if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
20519 test_winevents();
20520 test_SendMessage_other_thread();
20521 test_setparent_status();
20522 test_InSendMessage();
20523 test_SetFocus();
20524 test_SetParent();
20525 test_PostMessage();
20526 test_broadcast();
20527 test_ShowWindow();
20528 test_PeekMessage();
20529 test_PeekMessage2();
20530 test_PeekMessage3();
20531 test_WaitForInputIdle( test_argv[0] );
20532 test_scrollwindowex();
20533 test_messages();
20534 test_setwindowpos();
20535 test_showwindow();
20536 invisible_parent_tests();
20537 test_mdi_messages();
20538 test_button_messages();
20539 test_button_bm_get_set_image();
20540 test_button_style();
20541 test_autoradio_BM_CLICK();
20542 test_autoradio_kbd_move();
20543 test_static_messages();
20544 test_listbox_messages();
20545 test_combobox_messages();
20546 test_wmime_keydown_message();
20547 test_paint_messages();
20548 run_in_temp_desktop(test_swp_paint_regions);
20549 run_in_temp_desktop(test_swp_paint_region_on_show);
20550 run_in_temp_desktop(test_swp_paint_region_on_extend_zerosize);
20551 run_in_temp_desktop(test_hvredraw);
20552 test_interthread_messages();
20553 test_message_conversion();
20554 test_accelerators();
20555 test_timers();
20556 test_timers_no_wnd();
20557 test_timers_exceptions();
20558 if (hCBT_hook)
20560 test_set_hook();
20561 test_recursive_hook();
20563 test_recursive_messages();
20564 test_DestroyWindow();
20565 test_DispatchMessage();
20566 test_SendMessageTimeout();
20567 test_edit_messages();
20568 test_quit_message();
20569 test_notify_message();
20570 test_SetActiveWindow();
20571 test_restore_messages();
20572 test_invalid_window();
20573 test_menu_messages();
20574 test_paintingloop();
20576 if (!pTrackMouseEvent)
20577 win_skip("TrackMouseEvent is not available\n");
20578 else
20579 test_TrackMouseEvent();
20581 test_SetWindowRgn();
20582 test_sys_menu();
20583 test_dialog_messages();
20584 test_EndDialog();
20585 test_nullCallback();
20586 test_dbcs_wm_char();
20587 test_unicode_wm_char();
20588 test_defwinproc();
20589 test_desktop_winproc();
20590 test_clipboard_viewers();
20591 test_keyflags();
20592 test_hotkey();
20593 test_layered_window();
20594 test_TrackPopupMenu();
20595 test_TrackPopupMenuEmpty();
20596 test_DoubleSetCapture();
20597 test_create_name();
20598 test_hook_changing_window_proc();
20599 /* keep it the last test, under Windows it tends to break the tests
20600 * which rely on active/foreground windows being correct.
20602 test_SetForegroundWindow();
20604 UnhookWindowsHookEx(hCBT_hook);
20605 if (pUnhookWinEvent && hEvent_hook)
20607 ret = pUnhookWinEvent(hEvent_hook);
20608 ok( ret, "UnhookWinEvent error %ld\n", GetLastError());
20609 SetLastError(0xdeadbeef);
20610 ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
20611 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
20612 GetLastError() == 0xdeadbeef, /* Win9x */
20613 "unexpected error %ld\n", GetLastError());
20615 DeleteCriticalSection( &sequence_cs );