user32/edit: Let DefWindowProcA/W() handle WM_IME_CHAR.
[wine.git] / dlls / user32 / tests / msg.c
blob2d43c1ad1aafd5b94a297467c65eadc5bd0056f5
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 <assert.h>
24 #include <limits.h>
25 #include <stdarg.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 __x86_64__
67 #define ARCH "amd64"
68 #elif defined __arm__
69 #define ARCH "arm"
70 #elif defined __aarch64__
71 #define ARCH "arm64"
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);
123 FIXME: add tests for these
124 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
125 WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
126 WS_THICKFRAME: thick border
127 WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
128 WS_BORDER (default for overlapped windows): single black border
129 none (default for child (and popup?) windows): no border
132 typedef enum {
133 sent=0x1,
134 posted=0x2,
135 parent=0x4,
136 wparam=0x8,
137 lparam=0x10,
138 defwinproc=0x20,
139 beginpaint=0x40,
140 optional=0x80,
141 hook=0x100,
142 winevent_hook=0x200,
143 kbd_hook=0x400,
144 winevent_hook_todo=0x800
145 } msg_flags_t;
147 struct message {
148 UINT message; /* the WM_* code */
149 msg_flags_t flags; /* message props */
150 WPARAM wParam; /* expected value of wParam */
151 LPARAM lParam; /* expected value of lParam */
152 WPARAM wp_mask; /* mask for wParam checks */
153 LPARAM lp_mask; /* mask for lParam checks */
156 struct recvd_message {
157 UINT message; /* the WM_* code */
158 msg_flags_t flags; /* message props */
159 HWND hwnd; /* window that received the message */
160 WPARAM wParam; /* expected value of wParam */
161 LPARAM lParam; /* expected value of lParam */
162 int line; /* source line where logged */
163 const char *descr; /* description for trace output */
164 char output[512]; /* trace output */
167 /* Empty message sequence */
168 static const struct message WmEmptySeq[] =
170 { 0 }
172 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
173 static const struct message WmCreateOverlappedSeq[] = {
174 { HCBT_CREATEWND, hook },
175 { WM_GETMINMAXINFO, sent },
176 { WM_NCCREATE, sent },
177 { WM_NCCALCSIZE, sent|wparam, 0 },
178 { 0x0093, sent|defwinproc|optional },
179 { 0x0094, sent|defwinproc|optional },
180 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on win10. */
181 { WM_CREATE, sent },
182 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
183 { 0 }
185 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
186 * for a not visible overlapped window.
188 static const struct message WmSWP_ShowOverlappedSeq[] = {
189 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
190 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
191 { WM_NCPAINT, sent|wparam|optional, 1 },
192 { WM_GETTEXT, sent|defwinproc|optional },
193 { WM_ERASEBKGND, sent|optional },
194 { HCBT_ACTIVATE, hook },
195 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
196 { WM_NOTIFYFORMAT, sent|optional },
197 { WM_QUERYUISTATE, sent|optional },
198 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
199 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
200 { WM_ACTIVATEAPP, sent|wparam, 1 },
201 { WM_NCACTIVATE, sent },
202 { WM_GETTEXT, sent|defwinproc|optional },
203 { WM_ACTIVATE, sent|wparam, 1 },
204 { HCBT_SETFOCUS, hook },
205 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
206 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
207 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
208 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
209 { WM_GETTEXT, sent|optional },
210 { WM_NCPAINT, sent|wparam|optional, 1 },
211 { WM_GETTEXT, sent|defwinproc|optional },
212 { WM_ERASEBKGND, sent|optional },
213 /* Win9x adds SWP_NOZORDER below */
214 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
215 { WM_GETTEXT, sent|optional },
216 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
217 { WM_NCPAINT, sent|wparam|optional, 1 },
218 { WM_ERASEBKGND, sent|optional },
219 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on win10 */
220 { WM_SYNCPAINT, sent|optional },
221 { WM_GETTITLEBARINFOEX, sent|optional },
222 { WM_PAINT, sent|optional },
223 { WM_NCPAINT, sent|beginpaint|optional },
224 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
225 { WM_ERASEBKGND, sent|beginpaint|optional },
226 { 0 }
228 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
229 * for a visible overlapped window.
231 static const struct message WmSWP_HideOverlappedSeq[] = {
232 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
233 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
234 { HCBT_ACTIVATE, hook|optional },
235 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
236 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
237 { WM_NCACTIVATE, sent|optional },
238 { WM_ACTIVATE, sent|optional },
239 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
240 { 0 }
243 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
244 * for a visible overlapped window.
246 static const struct message WmSWP_ResizeSeq[] = {
247 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
248 { WM_GETMINMAXINFO, sent|defwinproc },
249 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
250 { WM_NCPAINT, sent|optional },
251 { WM_GETTEXT, sent|defwinproc|optional },
252 { WM_ERASEBKGND, sent|optional },
253 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
254 { WM_SIZE, sent|defwinproc|optional },
255 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
256 { WM_NCPAINT, sent|optional },
257 { WM_GETTEXT, sent|defwinproc|optional },
258 { WM_ERASEBKGND, sent|optional },
259 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
260 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
261 { 0 }
264 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
265 * for a visible popup window.
267 static const struct message WmSWP_ResizePopupSeq[] = {
268 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
269 { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */
270 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
271 { WM_NCPAINT, sent|optional },
272 { WM_GETTEXT, sent|defwinproc|optional },
273 { WM_ERASEBKGND, sent|optional },
274 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
275 { WM_SIZE, sent|defwinproc|wparam|optional, SIZE_RESTORED },
276 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
277 { WM_NCPAINT, sent|optional },
278 { WM_GETTEXT, sent|defwinproc|optional },
279 { WM_ERASEBKGND, sent|optional },
280 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
281 { 0 }
284 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
285 * for a visible overlapped window.
287 static const struct message WmSWP_MoveSeq[] = {
288 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
289 { WM_NCPAINT, sent|optional },
290 { WM_GETTEXT, sent|defwinproc|optional },
291 { WM_ERASEBKGND, sent|optional },
292 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
293 { WM_MOVE, sent|defwinproc|wparam, 0 },
294 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
295 { 0 }
297 /* Resize with SetWindowPos(SWP_NOZORDER)
298 * for a visible overlapped window
299 * SWP_NOZORDER is stripped by the logging code
301 static const struct message WmSWP_ResizeNoZOrder[] = {
302 { WM_WINDOWPOSCHANGING, sent|wparam, /*SWP_NOZORDER|*/SWP_NOACTIVATE },
303 { WM_GETMINMAXINFO, sent|defwinproc },
304 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
305 { WM_NCPAINT, sent|optional },
306 { WM_GETTEXT, sent|defwinproc|optional },
307 { WM_ERASEBKGND, sent|optional },
308 { WM_WINDOWPOSCHANGED, sent|wparam|optional, /*SWP_NOZORDER|*/SWP_NOACTIVATE, 0,
309 SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
310 { WM_MOVE, sent|defwinproc|optional },
311 { WM_SIZE, sent|defwinproc|optional },
312 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
313 { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
314 { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */
315 { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */
316 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
317 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on win10. */
318 { 0 }
321 /* Switch visible mdi children */
322 static const struct message WmSwitchChild[] = {
323 /* Switch MDI child */
324 { WM_MDIACTIVATE, sent },/* in the MDI client */
325 { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 1st MDI child */
326 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
327 { WM_CHILDACTIVATE, sent },/* in the 1st MDI child */
328 /* Deactivate 2nd MDI child */
329 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
330 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
331 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
332 /* Preparing for maximize and maximize the 1st MDI child */
333 { WM_GETMINMAXINFO, sent|defwinproc }, /* in the 1st MDI child */
334 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED }, /* in the 1st MDI child */
335 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
336 { WM_CHILDACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
337 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 1st MDI child */
338 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, /* in the 1st MDI child */
339 /* Lock redraw 2nd MDI child */
340 { WM_SETREDRAW, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
341 { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
342 /* Restore 2nd MDI child */
343 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },/* in the 2nd MDI child */
344 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
345 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
346 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 2nd MDI child */
347 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, /* in the 2nd MDI child */
348 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
349 /* Redraw 2nd MDI child */
350 { WM_SETREDRAW, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
351 /* Redraw MDI frame */
352 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },/* in MDI frame */
353 { WM_NCCALCSIZE, sent|wparam, 1 },/* in MDI frame */
354 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in MDI frame */
355 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in MDI frame */
356 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
357 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
358 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
359 { HCBT_SETFOCUS, hook },
360 { WM_KILLFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
361 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },/* in the 1st MDI child */
362 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
363 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
364 { WM_SETFOCUS, sent },/* in the MDI client */
365 { HCBT_SETFOCUS, hook },
366 { WM_KILLFOCUS, sent },/* in the MDI client */
367 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
368 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, /* in the 1st MDI child */
369 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
370 { WM_SETFOCUS, sent|defwinproc }, /* in the 1st MDI child */
371 { WM_MDIACTIVATE, sent|defwinproc },/* in the 1st MDI child */
372 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* in the 1st MDI child */
373 { 0 }
376 /* Switch visible not maximized mdi children */
377 static const struct message WmSwitchNotMaximizedChild[] = {
378 /* Switch not maximized MDI child */
379 { WM_MDIACTIVATE, sent },/* in the MDI client */
380 { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 2nd MDI child */
381 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
382 { WM_CHILDACTIVATE, sent },/* in the 2nd MDI child */
383 /* Deactivate 1st MDI child */
384 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
385 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
386 /* Activate 2nd MDI child */
387 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE}, /* in the 2nd MDI child */
388 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 2nd MDI child */
389 { HCBT_SETFOCUS, hook }, /* in the 1st MDI child */
390 { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
391 { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
392 { WM_IME_SETCONTEXT, sent|optional }, /* in the MDI client */
393 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
394 { WM_SETFOCUS, sent, 0 }, /* in the MDI client */
395 { HCBT_SETFOCUS, hook },
396 { WM_KILLFOCUS, sent }, /* in the MDI client */
397 { WM_IME_SETCONTEXT, sent|optional }, /* in the MDI client */
398 { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
399 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
400 { WM_SETFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
401 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
402 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in the 2nd MDI child */
403 { 0 }
407 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
408 SWP_NOZORDER|SWP_FRAMECHANGED)
409 * for a visible overlapped window with WS_CLIPCHILDREN style set.
411 static const struct message WmSWP_FrameChanged_clip[] = {
412 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
413 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
414 { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
415 { WM_GETTEXT, sent|parent|defwinproc|optional },
416 { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
417 { WM_NCPAINT, sent }, /* wparam != 1 */
418 { WM_ERASEBKGND, sent },
419 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
420 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
421 { WM_PAINT, sent },
422 { 0 }
424 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
425 SWP_NOZORDER|SWP_FRAMECHANGED)
426 * for a visible overlapped window.
428 static const struct message WmSWP_FrameChangedDeferErase[] = {
429 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
430 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
431 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
432 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
433 { WM_PAINT, sent|parent|optional },
434 { WM_NCPAINT, sent|beginpaint|parent|optional }, /* wparam != 1 */
435 { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
436 { WM_PAINT, sent },
437 { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
438 { WM_ERASEBKGND, sent|beginpaint|optional },
439 { 0 }
442 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
443 SWP_NOZORDER|SWP_FRAMECHANGED)
444 * for a visible overlapped window without WS_CLIPCHILDREN style set.
446 static const struct message WmSWP_FrameChanged_noclip[] = {
447 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
448 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
449 { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
450 { WM_GETTEXT, sent|parent|defwinproc|optional },
451 { WM_ERASEBKGND, sent|parent|optional },
452 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
453 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
454 { WM_PAINT, sent },
455 { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
456 { WM_ERASEBKGND, sent|beginpaint|optional },
457 { 0 }
460 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
461 static const struct message WmShowOverlappedSeq[] = {
462 { WM_SHOWWINDOW, sent|wparam, 1 },
463 { WM_NCPAINT, sent|wparam|optional, 1 },
464 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
465 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
466 { WM_NCPAINT, sent|wparam|optional, 1 },
467 { WM_GETTEXT, sent|defwinproc|optional },
468 { WM_ERASEBKGND, sent|optional },
469 { HCBT_ACTIVATE, hook|optional },
470 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|optional, 0, 0 },
471 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
472 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
473 { WM_NCPAINT, sent|wparam|optional, 1 },
474 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
475 { WM_NCACTIVATE, sent|wparam|optional, 1 },
476 { WM_GETTEXT, sent|defwinproc|optional },
477 { WM_ACTIVATE, sent|wparam|optional, 1 },
478 { HCBT_SETFOCUS, hook|optional },
479 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
480 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
481 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
482 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
483 { WM_GETTEXT, sent|optional },
484 { WM_NCPAINT, sent|wparam|optional, 1 },
485 { WM_GETTEXT, sent|defwinproc|optional },
486 { WM_ERASEBKGND, sent|optional },
487 /* Win9x adds SWP_NOZORDER below */
488 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
489 { WM_NCCALCSIZE, sent|optional },
490 { WM_GETTEXT, sent|optional },
491 { WM_NCPAINT, sent|optional },
492 { WM_ERASEBKGND, sent|optional },
493 { WM_SYNCPAINT, sent|optional },
494 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
495 * messages. Does that mean that CreateWindow doesn't set initial
496 * window dimensions for overlapped windows?
498 { WM_SIZE, sent },
499 { WM_MOVE, sent },
500 #endif
501 { WM_PAINT, sent|optional },
502 { WM_NCPAINT, sent|beginpaint|optional },
503 { 0 }
505 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
506 static const struct message WmShowMaxOverlappedSeq[] = {
507 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
508 { WM_GETMINMAXINFO, sent },
509 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
510 { WM_GETMINMAXINFO, sent|defwinproc },
511 { WM_NCCALCSIZE, sent|wparam, TRUE },
512 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
513 { HCBT_ACTIVATE, hook|optional },
514 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|optional, 0, 0 },
515 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
516 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
517 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
518 { WM_NCACTIVATE, sent|wparam|optional, 1 },
519 { WM_GETTEXT, sent|defwinproc|optional },
520 { WM_ACTIVATE, sent|wparam|optional, 1 },
521 { HCBT_SETFOCUS, hook|optional },
522 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
523 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
524 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
525 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
526 { WM_GETTEXT, sent|optional },
527 { WM_NCPAINT, sent|wparam|optional, 1 },
528 { WM_GETTEXT, sent|defwinproc|optional },
529 { WM_ERASEBKGND, sent|optional },
530 /* Win9x adds SWP_NOZORDER below */
531 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
532 { WM_MOVE, sent|defwinproc },
533 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
534 { WM_GETTEXT, sent|optional },
535 { WM_NCCALCSIZE, sent|optional },
536 { WM_NCPAINT, sent|optional },
537 { WM_ERASEBKGND, sent|optional },
538 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
539 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on win10. */
540 { WM_SYNCPAINT, sent|optional },
541 { WM_GETTITLEBARINFOEX, sent|optional },
542 { WM_PAINT, sent|optional },
543 { WM_NCPAINT, sent|beginpaint|optional },
544 { WM_ERASEBKGND, sent|beginpaint|optional },
545 { 0 }
547 /* ShowWindow(SW_RESTORE) for a not visible maximized overlapped window */
548 static const struct message WmShowRestoreMaxOverlappedSeq[] = {
549 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
550 { WM_GETTEXT, sent|optional },
551 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
552 { WM_GETMINMAXINFO, sent|defwinproc },
553 { WM_NCCALCSIZE, sent|wparam, TRUE },
554 { WM_NCPAINT, sent|optional },
555 { WM_GETTEXT, sent|defwinproc|optional },
556 { WM_ERASEBKGND, sent|optional },
557 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
558 { WM_MOVE, sent|defwinproc|optional },
559 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
560 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
561 { WM_NCPAINT, sent|optional },
562 { WM_ERASEBKGND, sent|optional },
563 { WM_PAINT, sent|optional },
564 { WM_GETTITLEBARINFOEX, sent|optional },
565 { WM_NCPAINT, sent|beginpaint|optional },
566 { WM_ERASEBKGND, sent|beginpaint|optional },
567 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
568 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
569 { WM_SYNCPAINT, sent|optional },
570 { 0 }
572 /* ShowWindow(SW_RESTORE) for a not visible minimized overlapped window */
573 static const struct message WmShowRestoreMinOverlappedSeq[] = {
574 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
575 { WM_QUERYOPEN, sent|optional },
576 { WM_GETTEXT, sent|optional },
577 { WM_NCACTIVATE, sent|wparam|optional, 1 },
578 { WM_WINDOWPOSCHANGING, sent|optional }, /* SWP_NOSIZE|SWP_NOMOVE */
579 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
580 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
581 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sent on Win7. */
582 { WM_MOVE, sent|optional },
583 { WM_SIZE, sent|wparam|optional, SIZE_RESTORED },
584 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sent on Win7. */
585 { WM_GETTEXT, sent|optional },
586 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED|SWP_NOCOPYBITS },
587 { WM_GETMINMAXINFO, sent|defwinproc|optional },
588 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
589 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sent on Win10. */
590 { HCBT_ACTIVATE, hook|optional },
591 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|optional, 0, 0 },
592 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
593 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
594 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
595 { WM_NCACTIVATE, sent|wparam|optional, 1 },
596 { WM_GETTEXT, sent|defwinproc|optional },
597 { WM_ACTIVATE, sent|wparam|optional, 1 },
598 { HCBT_SETFOCUS, hook|optional },
599 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
600 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
601 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
602 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
603 { WM_GETTEXT, sent|optional },
604 { WM_NCPAINT, sent|wparam|optional, 1 },
605 { WM_GETTEXT, sent|defwinproc|optional },
606 { WM_ERASEBKGND, sent },
607 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_STATECHANGED|SWP_FRAMECHANGED|SWP_NOCOPYBITS },
608 { WM_MOVE, sent|defwinproc },
609 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
610 { HCBT_SETFOCUS, hook|optional },
611 { WM_SETFOCUS, sent|wparam|optional, 0 },
612 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
613 { WM_NCPAINT, sent|wparam|optional, 1 },
614 { WM_ERASEBKGND, sent|optional },
615 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
616 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
617 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
618 { HCBT_SETFOCUS, hook|optional },
619 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
620 { WM_SETFOCUS, sent|wparam|optional, 0 },
621 { WM_ACTIVATE, sent|wparam, 1 },
622 { WM_GETTEXT, sent|optional },
623 { WM_PAINT, sent|optional },
624 { WM_GETTITLEBARINFOEX, sent|optional },
625 { WM_NCPAINT, sent|beginpaint|optional },
626 { WM_ERASEBKGND, sent|beginpaint|optional },
627 { 0 }
629 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
630 static const struct message WmShowMinOverlappedSeq[] = {
631 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
632 { HCBT_SETFOCUS, hook|optional },
633 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
634 { WM_KILLFOCUS, sent|optional },
635 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
636 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
637 { WM_GETTEXT, sent|optional },
638 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
639 { WM_GETMINMAXINFO, sent|defwinproc },
640 { WM_NCCALCSIZE, sent|wparam, TRUE },
641 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
642 { WM_NCPAINT, sent|optional },
643 { WM_GETTEXT, sent|defwinproc|optional },
644 { WM_WINDOWPOSCHANGED, sent },
645 { WM_MOVE, sent|defwinproc },
646 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
647 { WM_NCCALCSIZE, sent|optional },
648 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
649 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on win10. */
650 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
651 { WM_NCACTIVATE, sent|wparam|optional, 0 },
652 { WM_GETTEXT, sent|defwinproc|optional },
653 { WM_ACTIVATE, sent|optional },
654 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
656 /* Vista sometimes restores the window right away... */
657 { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
658 { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
659 { HCBT_MINMAX, hook|optional|lparam, 0, SW_RESTORE },
660 { WM_QUERYOPEN, sent|optional },
661 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
662 { WM_GETMINMAXINFO, sent|optional|defwinproc },
663 { WM_NCCALCSIZE, sent|optional|wparam, TRUE },
664 { HCBT_ACTIVATE, hook|optional },
665 { WM_ACTIVATEAPP, sent|optional|wparam, 1 },
666 { WM_NCACTIVATE, sent|optional },
667 { WM_GETTEXT, sent|optional },
668 { WM_ACTIVATE, sent|optional|wparam, 1 },
669 { HCBT_SETFOCUS, hook|optional },
670 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
671 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
672 { WM_SETFOCUS, sent|optional },
673 { WM_NCPAINT, sent|optional },
674 { WM_GETTEXT, sent|defwinproc|optional },
675 { WM_ERASEBKGND, sent|optional },
676 { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
677 { WM_MOVE, sent|defwinproc|optional },
678 { WM_SIZE, sent|defwinproc|optional|wparam, SIZE_RESTORED },
679 { WM_ACTIVATE, sent|optional|wparam, 1 },
680 { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
681 { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
683 { WM_PAINT, sent|optional },
684 { WM_NCPAINT, sent|beginpaint|optional },
685 { WM_ERASEBKGND, sent|beginpaint|optional },
686 { 0 }
688 /* ShowWindow(SW_HIDE) for a visible overlapped window */
689 static const struct message WmHideOverlappedSeq[] = {
690 { WM_SHOWWINDOW, sent|wparam, 0 },
691 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
692 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
693 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
694 { WM_SIZE, sent|optional }, /* XP doesn't send it */
695 { WM_MOVE, sent|optional }, /* XP doesn't send it */
696 { WM_NCACTIVATE, sent|wparam|optional, 0 },
697 { WM_ACTIVATE, sent|wparam|optional, 0 },
698 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
699 { HCBT_SETFOCUS, hook|optional },
700 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
701 { WM_KILLFOCUS, sent|wparam|optional, 0 },
702 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
703 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
704 { 0 }
706 /* DestroyWindow for a visible overlapped window */
707 static const struct message WmDestroyOverlappedSeq[] = {
708 { HCBT_DESTROYWND, hook },
709 { 0x0090, sent|optional },
710 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
711 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
712 { 0x0090, sent|optional },
713 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
714 { WM_NCACTIVATE, sent|optional|wparam, 0 },
715 { WM_ACTIVATE, sent|optional },
716 { WM_ACTIVATEAPP, sent|optional|wparam, 0 },
717 { WM_KILLFOCUS, sent|optional|wparam, 0 },
718 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
719 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
720 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
721 { WM_DESTROY, sent },
722 { WM_NCDESTROY, sent },
723 { 0 }
725 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
726 static const struct message WmCreateMaxPopupSeq[] = {
727 { HCBT_CREATEWND, hook },
728 { WM_NCCREATE, sent },
729 { WM_NCCALCSIZE, sent|wparam, 0 },
730 { WM_CREATE, sent },
731 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
732 { WM_SIZE, sent|wparam, SIZE_RESTORED },
733 { WM_MOVE, sent },
734 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
735 { WM_GETMINMAXINFO, sent },
736 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
737 { WM_NCCALCSIZE, sent|wparam, TRUE },
738 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
739 { WM_MOVE, sent|defwinproc },
740 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
741 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
742 { WM_SHOWWINDOW, sent|wparam, 1 },
743 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
744 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
745 { HCBT_ACTIVATE, hook },
746 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
747 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
748 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
749 { WM_NCPAINT, sent|wparam|optional, 1 },
750 { WM_ERASEBKGND, sent|optional },
751 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_NOMOVE|SWP_NOSIZE },
752 { WM_ACTIVATEAPP, sent|wparam, 1 },
753 { WM_NCACTIVATE, sent },
754 { WM_ACTIVATE, sent|wparam, 1 },
755 { HCBT_SETFOCUS, hook },
756 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
757 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
758 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
759 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
760 { WM_GETTEXT, sent|optional },
761 { WM_SYNCPAINT, sent|wparam|optional, 4 },
762 { WM_NCPAINT, sent|wparam|optional, 1 },
763 { WM_ERASEBKGND, sent|optional },
764 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
765 { WM_ERASEBKGND, sent|defwinproc|optional },
766 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
767 { 0 }
769 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
770 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
771 { HCBT_CREATEWND, hook },
772 { WM_NCCREATE, sent },
773 { WM_NCCALCSIZE, sent|wparam, 0 },
774 { WM_CREATE, sent },
775 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
776 { WM_SIZE, sent|wparam, SIZE_RESTORED },
777 { WM_MOVE, sent },
778 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
779 { WM_GETMINMAXINFO, sent },
780 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
781 { WM_NCCALCSIZE, sent|wparam, TRUE },
782 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
783 { WM_MOVE, sent|defwinproc },
784 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
785 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
786 { 0 }
788 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
789 static const struct message WmShowMaxPopupResizedSeq[] = {
790 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
791 { WM_GETMINMAXINFO, sent },
792 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED, 0, SWP_STATECHANGED /* w1064v1809 */ },
793 { WM_NCCALCSIZE, sent|wparam, TRUE },
794 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
795 { HCBT_ACTIVATE, hook },
796 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
797 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
798 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
799 { WM_NCPAINT, sent|wparam|optional, 1 },
800 { WM_ERASEBKGND, sent|optional },
801 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
802 { WM_ACTIVATEAPP, sent|wparam, 1 },
803 { WM_NCACTIVATE, sent },
804 { WM_ACTIVATE, sent|wparam, 1 },
805 { HCBT_SETFOCUS, hook },
806 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
807 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
808 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
809 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
810 { WM_GETTEXT, sent|optional },
811 { WM_NCPAINT, sent|wparam|optional, 1 },
812 { WM_ERASEBKGND, sent|optional },
813 { WM_WINDOWPOSCHANGED, sent },
814 /* WinNT4.0 sends WM_MOVE */
815 { WM_MOVE, sent|defwinproc|optional },
816 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
817 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
818 { 0 }
820 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
821 static const struct message WmShowMaxPopupSeq[] = {
822 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
823 { WM_GETMINMAXINFO, sent },
824 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED, 0, SWP_STATECHANGED /* w1064v1809 */ },
825 { WM_NCCALCSIZE, sent|wparam, TRUE },
826 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
827 { HCBT_ACTIVATE, hook },
828 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
829 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
830 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
831 { WM_NCPAINT, sent|wparam|optional, 1 },
832 { WM_ERASEBKGND, sent|optional },
833 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOMOVE|SWP_NOSIZE },
834 { WM_ACTIVATEAPP, sent|wparam, 1 },
835 { WM_NCACTIVATE, sent },
836 { WM_ACTIVATE, sent|wparam, 1 },
837 { HCBT_SETFOCUS, hook },
838 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
839 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
840 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
841 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
842 { WM_GETTEXT, sent|optional },
843 { WM_SYNCPAINT, sent|wparam|optional, 4 },
844 { WM_NCPAINT, sent|wparam|optional, 1 },
845 { WM_ERASEBKGND, sent|optional },
846 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
847 { WM_ERASEBKGND, sent|defwinproc|optional },
848 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE, 0, SWP_STATECHANGED /* w1064v1809 */ },
849 { WM_SIZE, sent|defwinproc|optional },
850 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
851 { 0 }
853 /* CreateWindow(WS_VISIBLE) for popup window */
854 static const struct message WmCreatePopupSeq[] = {
855 { HCBT_CREATEWND, hook },
856 { WM_NCCREATE, sent },
857 { WM_NCCALCSIZE, sent|wparam, 0 },
858 { WM_CREATE, sent },
859 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
860 { WM_SIZE, sent|wparam, SIZE_RESTORED },
861 { WM_MOVE, sent },
862 { WM_SHOWWINDOW, sent|wparam, 1 },
863 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
864 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
865 { HCBT_ACTIVATE, hook },
866 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
867 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
868 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
869 { WM_NCPAINT, sent|wparam|optional, 1 },
870 { WM_ERASEBKGND, sent|optional },
871 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
872 { WM_ACTIVATEAPP, sent|wparam, 1 },
873 { WM_NCACTIVATE, sent },
874 { WM_ACTIVATE, sent|wparam, 1 },
875 { HCBT_SETFOCUS, hook },
876 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
877 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
878 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
879 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
880 { WM_GETTEXT, sent|optional },
881 { WM_SYNCPAINT, sent|wparam|optional, 4 },
882 { WM_NCPAINT, sent|wparam|optional, 1 },
883 { WM_ERASEBKGND, sent|optional },
884 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
885 { 0 }
887 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
888 static const struct message WmShowVisMaxPopupSeq[] = {
889 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
890 { WM_GETMINMAXINFO, sent },
891 { WM_GETTEXT, sent|optional },
892 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
893 { WM_GETTEXT, sent|optional },
894 { WM_NCCALCSIZE, sent|wparam, TRUE },
895 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
896 { WM_NCPAINT, sent|wparam|optional, 1 },
897 { WM_ERASEBKGND, sent|optional },
898 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
899 { WM_MOVE, sent|defwinproc },
900 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
901 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
902 { 0 }
904 /* ShowWindow(hwnd, SW_RESTORE) to a minimized window */
905 static const struct message WmShowRestoreMinimizedOverlappedSeq[] =
907 { HCBT_MINMAX, hook },
908 { WM_QUERYOPEN, sent },
909 { WM_GETTEXT, sent|optional },
910 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
911 { WM_GETMINMAXINFO, sent|defwinproc },
912 { WM_NCCALCSIZE, sent },
913 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
914 { HCBT_ACTIVATE, hook },
915 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
916 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
917 { WM_NCACTIVATE, sent },
918 { WM_GETTEXT, sent|defwinproc|optional },
919 { WM_ACTIVATE, sent|wparam, WA_ACTIVE },
920 { HCBT_SETFOCUS, hook },
921 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
922 { WM_SETFOCUS, sent|defwinproc },
923 { WM_NCPAINT, sent },
924 { WM_GETTEXT, sent|defwinproc|optional },
925 { WM_GETTEXT, sent|defwinproc|optional },
926 { WM_ERASEBKGND, sent },
927 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
928 { WM_MOVE, sent|defwinproc },
929 { WM_SIZE, sent|defwinproc },
930 { WM_NCCALCSIZE, sent|optional },
931 { WM_NCPAINT, sent|optional },
932 { WM_ERASEBKGND, sent|optional },
933 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
934 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
935 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
936 /* Note this WM_ACTIVATE message even if the window is already active and focused */
937 { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, 0 },
938 { WM_SYNCPAINT, sent|optional },
939 { WM_PAINT, sent },
940 { WM_GETMINMAXINFO, sent|optional },
941 { 0 }
943 /* ShowWindow(hwnd, SW_SHOWNOACTIVATE) to a minimized window */
944 static const struct message WmShowNoActivateMinimizedOverlappedSeq[] =
946 { HCBT_MINMAX, hook },
947 { WM_QUERYOPEN, sent },
948 { WM_GETTEXT, sent|optional },
949 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
950 { WM_GETMINMAXINFO, sent|defwinproc },
951 { WM_NCCALCSIZE, sent },
952 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
953 { WM_NCPAINT, sent },
954 { WM_GETTEXT, sent|defwinproc|optional },
955 { WM_ERASEBKGND, sent },
956 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
957 { WM_MOVE, sent|defwinproc },
958 { WM_SIZE, sent|defwinproc },
959 /* Following optional messages are on XP/2003 */
960 { WM_NCCALCSIZE, sent|optional },
961 { WM_NCPAINT, sent|optional },
962 { WM_ERASEBKGND, sent|optional },
963 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
964 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
965 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
966 { HCBT_SETFOCUS, hook|optional },
967 { WM_SETFOCUS, sent|optional },
968 { HCBT_ACTIVATE, hook|optional },
969 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
970 { WM_NCACTIVATE, sent|optional },
971 { WM_GETTEXT, sent|defwinproc|optional },
972 { WM_ACTIVATE, sent|wparam|optional, WA_ACTIVE },
973 { HCBT_SETFOCUS, hook|optional },
974 { WM_SETFOCUS, sent|defwinproc|optional },
975 { WM_KILLFOCUS, sent|optional },
976 { WM_SETFOCUS, sent|optional },
977 /* Note this WM_ACTIVATE message on XP even if the window is already active and focused */
978 { WM_ACTIVATE, sent|wparam|lparam|optional, WA_ACTIVE, 0 },
979 { WM_SYNCPAINT, sent|optional },
980 { WM_PAINT, sent },
981 { WM_GETMINMAXINFO, sent|optional },
982 { 0 }
984 /* ShowWindow(hwnd, SW_RESTORE) to an active minimized window */
985 static const struct message WmShowRestoreActiveMinimizedOverlappedSeq[] =
987 { HCBT_MINMAX, hook },
988 { WM_QUERYOPEN, sent },
989 { WM_GETTEXT, sent|optional },
990 { WM_NCACTIVATE, sent },
991 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
992 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
993 { WM_NCCALCSIZE, sent|optional },
994 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends this. */
995 { WM_MOVE, sent|optional },
996 { WM_SIZE, sent|optional },
997 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends this. */
998 { WM_GETTEXT, sent|optional },
999 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1000 { WM_GETMINMAXINFO, sent|defwinproc },
1001 { WM_NCCALCSIZE, sent },
1002 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win8+ sends this. */
1003 { WM_NCPAINT, sent },
1004 { WM_GETTEXT, sent|defwinproc|optional },
1005 { WM_ERASEBKGND, sent },
1006 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1007 { WM_MOVE, sent|defwinproc },
1008 { WM_SIZE, sent|defwinproc },
1009 { WM_NCCALCSIZE, sent|optional },
1010 { WM_NCPAINT, sent|optional },
1011 { WM_ERASEBKGND, sent|optional },
1012 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1013 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
1014 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1015 { HCBT_SETFOCUS, hook },
1016 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1017 { WM_SETFOCUS, sent },
1018 /* Note this WM_ACTIVATE message even if the window is already active */
1019 { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, 0 },
1020 { WM_SYNCPAINT, sent|optional },
1021 { WM_PAINT, sent },
1022 { WM_GETMINMAXINFO, sent|optional },
1023 { 0 }
1025 /* ShowWindow(hwnd, SW_SHOWNOACTIVATE) to an active minimized window */
1026 static const struct message WmShowNoActivateActiveMinimizedOverlappedSeq[] =
1028 { HCBT_MINMAX, hook },
1029 { WM_QUERYOPEN, sent },
1030 { WM_GETTEXT, sent|optional },
1031 { WM_NCACTIVATE, sent },
1032 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1033 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1034 { WM_NCCALCSIZE, sent|optional },
1035 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends this. */
1036 { WM_MOVE, sent|optional },
1037 { WM_SIZE, sent|optional },
1038 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends this. */
1039 { WM_GETTEXT, sent|optional },
1040 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1041 { WM_GETMINMAXINFO, sent|defwinproc },
1042 { WM_NCCALCSIZE, sent },
1043 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win8+ sends this. */
1044 { WM_NCPAINT, sent },
1045 { WM_GETTEXT, sent|defwinproc|optional },
1046 { WM_ERASEBKGND, sent },
1047 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1048 { WM_MOVE, sent|defwinproc },
1049 { WM_SIZE, sent|defwinproc },
1050 { WM_NCCALCSIZE, sent|optional },
1051 { WM_NCPAINT, sent|optional },
1052 { WM_ERASEBKGND, sent|optional },
1053 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1054 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
1055 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1056 /* Following optional messages are present on XP */
1057 { HCBT_SETFOCUS, hook|optional },
1058 { WM_SETFOCUS, sent|optional },
1059 /* Note this WM_ACTIVATE message even if the window is already active and with flag SW_SHOWNOACTIVATE */
1060 { WM_ACTIVATE, sent|wparam|lparam|optional, WA_ACTIVE, 0 },
1061 { WM_SYNCPAINT, sent|optional },
1062 { WM_PAINT, sent },
1063 { WM_GETMINMAXINFO, sent|optional },
1064 { 0 }
1066 /* CreateWindow (for a child popup window, not initially visible) */
1067 static const struct message WmCreateChildPopupSeq[] = {
1068 { HCBT_CREATEWND, hook },
1069 { WM_NCCREATE, sent },
1070 { WM_NCCALCSIZE, sent|wparam, 0 },
1071 { WM_CREATE, sent },
1072 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1073 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1074 { WM_MOVE, sent },
1075 { 0 }
1077 /* CreateWindow (for a popup window, not initially visible,
1078 * which sets WS_VISIBLE in WM_CREATE handler)
1080 static const struct message WmCreateInvisiblePopupSeq[] = {
1081 { HCBT_CREATEWND, hook },
1082 { WM_NCCREATE, sent },
1083 { WM_NCCALCSIZE, sent|wparam, 0 },
1084 { WM_CREATE, sent },
1085 { WM_STYLECHANGING, sent },
1086 { WM_STYLECHANGED, sent },
1087 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1088 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1089 { WM_MOVE, sent },
1090 { 0 }
1092 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
1093 * for a popup window with WS_VISIBLE style set
1095 static const struct message WmShowVisiblePopupSeq_2[] = {
1096 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1097 { 0 }
1099 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1100 * for a popup window with WS_VISIBLE style set
1102 static const struct message WmShowVisiblePopupSeq_3[] = {
1103 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1104 { HCBT_ACTIVATE, hook },
1105 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1106 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1107 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1108 { WM_NCACTIVATE, sent },
1109 { WM_ACTIVATE, sent|wparam, 1 },
1110 { HCBT_SETFOCUS, hook },
1111 { WM_KILLFOCUS, sent|parent },
1112 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1113 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1114 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1115 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1116 { WM_SETFOCUS, sent|defwinproc },
1117 { WM_GETTEXT, sent|optional },
1118 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_SHOWWINDOW },
1119 { 0 }
1121 /* CreateWindow (for a popup window with WS_VISIBLE style set and extreme location)
1123 static const struct message WmShowPopupExtremeLocationSeq[] = {
1124 { HCBT_CREATEWND, hook },
1125 { WM_NCCREATE, sent },
1126 { WM_NCCALCSIZE, sent|wparam, 0 },
1127 { WM_CREATE, sent },
1128 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1129 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1130 { WM_MOVE, sent },
1131 { WM_SHOWWINDOW, sent|wparam, 1 },
1132 { WM_WINDOWPOSCHANGING, sent },
1133 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1134 { HCBT_ACTIVATE, hook },
1135 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1136 { WM_WINDOWPOSCHANGING, sent|optional },
1137 { WM_QUERYNEWPALETTE, sent|optional },
1139 /* occasionally received on test machines */
1140 { WM_NCPAINT, sent|optional },
1141 { WM_ERASEBKGND, sent|optional },
1142 { WM_WINDOWPOSCHANGED, sent|optional },
1144 { WM_ACTIVATEAPP, sent },
1145 { WM_NCACTIVATE, sent },
1146 { WM_ACTIVATE, sent },
1147 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1148 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1149 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1150 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Not sent on Win10. */
1151 { HCBT_SETFOCUS, hook },
1152 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
1153 { WM_SETFOCUS, sent|defwinproc },
1154 { WM_NCPAINT, sent|wparam|optional, 1 }, /* Not always sent on Win8+ */
1155 { WM_ERASEBKGND, sent|optional }, /* Not always sent on Win8+ */
1156 { WM_WINDOWPOSCHANGED, sent },
1157 /* occasionally received on test machines */
1158 { WM_NCPAINT, sent|optional },
1159 { WM_ERASEBKGND, sent|optional },
1160 { 0 }
1162 /* CreateWindow (for a popup window with WS_VISIBLE style set)
1164 static const struct message WmShowPopupFirstDrawSeq_1[] = {
1165 { HCBT_CREATEWND, hook },
1166 { WM_NCCREATE, sent },
1167 { WM_NCCALCSIZE, sent|wparam, 0 },
1168 { WM_CREATE, sent },
1169 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1170 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1171 { WM_MOVE, sent },
1172 { WM_SHOWWINDOW, sent|wparam, 1 },
1173 { WM_WINDOWPOSCHANGING, sent },
1174 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1175 { HCBT_ACTIVATE, hook },
1176 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1177 { WM_WINDOWPOSCHANGING, sent|optional },
1178 { WM_QUERYNEWPALETTE, sent|optional },
1179 { WM_ACTIVATEAPP, sent },
1180 { WM_NCACTIVATE, sent },
1181 { WM_ACTIVATE, sent },
1182 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1183 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1184 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1185 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Not sent on Win10. */
1186 { HCBT_SETFOCUS, hook },
1187 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
1188 { WM_SETFOCUS, sent|defwinproc },
1189 { WM_NCPAINT, sent|wparam, 1 },
1190 { WM_ERASEBKGND, sent },
1191 { WM_WINDOWPOSCHANGED, sent },
1192 { WM_PAINT, sent },
1193 /* occasionally received on test machines */
1194 { WM_NCPAINT, sent|beginpaint|optional },
1195 { WM_ERASEBKGND, sent|beginpaint|optional },
1196 { 0 }
1198 /* CreateWindow (for a popup window that is shown with ShowWindow(SW_SHOWMAXIMIZED))
1200 static const struct message WmShowPopupFirstDrawSeq_2[] = {
1201 { HCBT_CREATEWND, hook },
1202 { WM_NCCREATE, sent },
1203 { WM_NCCALCSIZE, sent|wparam, 0 },
1204 { WM_CREATE, sent },
1205 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1206 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1207 { WM_MOVE, sent },
1208 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1209 { WM_GETMINMAXINFO, sent },
1210 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_STATECHANGED|SWP_SHOWWINDOW|SWP_FRAMECHANGED },
1211 { WM_NCCALCSIZE, sent|wparam, TRUE },
1212 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1213 { HCBT_ACTIVATE, hook },
1214 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1215 { WM_WINDOWPOSCHANGING, sent|optional },
1216 { WM_NCPAINT, sent|optional|wparam, 1 },
1217 { WM_ERASEBKGND, sent|optional },
1218 { WM_WINDOWPOSCHANGED, sent|optional },
1219 { WM_QUERYNEWPALETTE, sent|optional },
1220 { WM_ACTIVATEAPP, sent },
1221 { WM_NCACTIVATE, sent },
1222 { WM_ACTIVATE, sent },
1223 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1224 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1225 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1226 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Not sent on Win10. */
1227 { HCBT_SETFOCUS, hook },
1228 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
1229 { WM_SETFOCUS, sent|defwinproc },
1230 { WM_NCPAINT, sent|wparam, 1 },
1231 { WM_ERASEBKGND, sent },
1232 { WM_WINDOWPOSCHANGED, sent|optional },
1233 { WM_MOVE, sent|defwinproc },
1234 { WM_SIZE, sent|defwinproc, 0 },
1235 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1236 { WM_PAINT, sent},
1237 /* occasionally received on test machines */
1238 { WM_NCPAINT, sent|beginpaint|optional },
1239 { WM_ERASEBKGND, sent|beginpaint|optional },
1240 { 0 }
1242 static const struct message WmFirstDrawSetWindowPosSeq1[] = {
1243 { HCBT_CREATEWND, hook },
1244 { WM_NCCREATE, sent },
1245 { WM_NCCALCSIZE, sent|wparam, 0 },
1246 { WM_CREATE, sent },
1247 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1248 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1249 { WM_MOVE, sent },
1250 { WM_WINDOWPOSCHANGING, sent },
1251 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1252 { HCBT_ACTIVATE, hook },
1253 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1254 { WM_WINDOWPOSCHANGING, sent|optional },
1255 { WM_QUERYNEWPALETTE, sent|optional },
1256 { WM_ACTIVATEAPP, sent },
1257 { WM_NCACTIVATE, sent },
1258 { WM_ACTIVATE, sent },
1259 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1260 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1261 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1262 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Not sent on Win10. */
1263 { HCBT_SETFOCUS, hook },
1264 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
1265 { WM_SETFOCUS, sent|defwinproc },
1266 { WM_NCPAINT, sent|wparam, 1 },
1267 { WM_ERASEBKGND, sent },
1268 { WM_WINDOWPOSCHANGED, sent },
1269 { WM_MOVE, sent|defwinproc },
1270 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1271 { 0 }
1273 static const struct message WmFirstDrawSetWindowPosSeq2[] = {
1274 { HCBT_CREATEWND, hook },
1275 { WM_NCCREATE, sent },
1276 { WM_NCCALCSIZE, sent|wparam, 0 },
1277 { WM_CREATE, sent },
1278 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1279 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1280 { WM_MOVE, sent },
1281 { WM_WINDOWPOSCHANGING, sent },
1282 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not always sent. */
1283 { HCBT_ACTIVATE, hook },
1284 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1285 { WM_QUERYNEWPALETTE, sent|optional },
1286 { WM_WINDOWPOSCHANGING, sent|optional },
1287 { WM_ACTIVATEAPP, sent },
1288 { WM_NCACTIVATE, sent },
1289 { WM_ACTIVATE, sent },
1290 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1291 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1292 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1293 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Not sent on Win10. */
1294 { HCBT_SETFOCUS, hook },
1295 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
1296 { WM_SETFOCUS, sent|defwinproc },
1297 { WM_WINDOWPOSCHANGED, sent },
1298 { WM_MOVE, sent|defwinproc },
1299 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1300 { 0 }
1302 static const struct message WmFirstDrawSetWindowPosSeq3[] = {
1303 { HCBT_CREATEWND, hook },
1304 { WM_NCCREATE, sent },
1305 { WM_NCCALCSIZE, sent|wparam, 0 },
1306 { WM_CREATE, sent },
1307 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1308 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1309 { WM_MOVE, sent },
1310 { HCBT_ACTIVATE, hook|optional },
1311 /* Probably shouldn't happen, but not part of this test */
1312 { WM_QUERYNEWPALETTE, sent|optional },
1313 { WM_ACTIVATEAPP, sent|optional },
1314 { WM_NCACTIVATE, sent|optional },
1315 { WM_ACTIVATE, sent|optional },
1316 { HCBT_SETFOCUS, hook|optional },
1317 { WM_SETFOCUS, sent|defwinproc|optional },
1318 { 0 }
1320 static const struct message WmFirstDrawSetWindowPosSeq4[] = {
1321 { HCBT_CREATEWND, hook },
1322 { WM_NCCREATE, sent },
1323 { WM_NCCALCSIZE, sent|wparam, 0 },
1324 { WM_CREATE, sent },
1325 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1326 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1327 { WM_MOVE, sent },
1328 { WM_WINDOWPOSCHANGING, sent },
1329 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1330 { HCBT_ACTIVATE, hook },
1331 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1332 { WM_WINDOWPOSCHANGING, sent|optional },
1333 { WM_QUERYNEWPALETTE, sent|optional },
1334 { WM_ACTIVATEAPP, sent },
1335 { WM_NCACTIVATE, sent },
1336 { WM_ACTIVATE, sent },
1337 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1338 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1339 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1340 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Not sent on Win10. */
1341 { HCBT_SETFOCUS, hook },
1342 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
1343 { WM_SETFOCUS, sent|defwinproc },
1344 { WM_NCPAINT, sent|wparam, 1 },
1345 { WM_ERASEBKGND, sent },
1346 { WM_WINDOWPOSCHANGED, sent },
1347 { 0 }
1349 static const struct message WmFirstDrawSetWindowPosSeq5[] = {
1350 { HCBT_CREATEWND, hook },
1351 { WM_NCCREATE, sent },
1352 { WM_NCCALCSIZE, sent|wparam, 0 },
1353 { WM_CREATE, sent },
1354 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1355 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1356 { WM_MOVE, sent },
1357 { WM_WINDOWPOSCHANGING, sent },
1358 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1359 { HCBT_ACTIVATE, hook },
1360 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1361 { WM_WINDOWPOSCHANGING, sent|optional },
1362 { WM_QUERYNEWPALETTE, sent|optional },
1363 { WM_ACTIVATEAPP, sent },
1364 { WM_NCACTIVATE, sent },
1365 { WM_ACTIVATE, sent },
1366 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1367 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1368 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1369 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Not sent on Win10. */
1370 { HCBT_SETFOCUS, hook },
1371 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
1372 { WM_SETFOCUS, sent|defwinproc },
1373 { WM_WINDOWPOSCHANGED, sent },
1374 { 0 }
1376 static const struct message WmFirstDrawChildSeq1[] = {
1377 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1378 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
1379 { 0 }
1381 static const struct message WmFirstDrawChildSeq2[] = {
1382 { WM_NCPAINT, sent|wparam, 1 },
1383 { WM_ERASEBKGND, sent },
1384 /* occasionally received on test machines */
1385 { WM_NCPAINT, sent|optional },
1386 { WM_ERASEBKGND, sent|optional },
1387 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1388 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
1389 { 0 }
1391 /* CreateWindow (for child window, not initially visible) */
1392 static const struct message WmCreateChildSeq[] = {
1393 { HCBT_CREATEWND, hook },
1394 { WM_NCCREATE, sent },
1395 /* child is inserted into parent's child list after WM_NCCREATE returns */
1396 { WM_NCCALCSIZE, sent|wparam, 0 },
1397 { WM_CREATE, sent },
1398 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1399 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1400 { WM_MOVE, sent },
1401 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1402 { 0 }
1404 /* CreateWindow (for maximized child window, not initially visible) */
1405 static const struct message WmCreateMaximizedChildSeq[] = {
1406 { HCBT_CREATEWND, hook },
1407 { WM_NCCREATE, sent },
1408 { WM_NCCALCSIZE, sent|wparam, 0 },
1409 { WM_CREATE, sent },
1410 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1411 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1412 { WM_MOVE, sent },
1413 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1414 { WM_GETMINMAXINFO, sent },
1415 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
1416 { WM_NCCALCSIZE, sent|wparam, 1 },
1417 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1418 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1419 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1420 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1421 { 0 }
1423 /* CreateWindow (for a child window, initially visible) */
1424 static const struct message WmCreateVisibleChildSeq[] = {
1425 { HCBT_CREATEWND, hook },
1426 { WM_NCCREATE, sent },
1427 /* child is inserted into parent's child list after WM_NCCREATE returns */
1428 { WM_NCCALCSIZE, sent|wparam, 0 },
1429 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win10. */
1430 { WM_CREATE, sent },
1431 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1432 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1433 { WM_MOVE, sent },
1434 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1435 { WM_SHOWWINDOW, sent|wparam, 1 },
1436 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1437 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1438 { WM_ERASEBKGND, sent|parent|optional },
1439 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1440 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
1441 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1442 { 0 }
1444 /* ShowWindow(SW_SHOW) for a not visible child window */
1445 static const struct message WmShowChildSeq[] = {
1446 { WM_SHOWWINDOW, sent|wparam, 1 },
1447 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1448 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1449 { WM_ERASEBKGND, sent|parent|optional },
1450 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1451 { 0 }
1453 /* ShowWindow(SW_HIDE) for a visible child window */
1454 static const struct message WmHideChildSeq[] = {
1455 { WM_SHOWWINDOW, sent|wparam, 0 },
1456 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1457 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1458 { WM_ERASEBKGND, sent|parent|optional },
1459 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1460 { 0 }
1462 /* ShowWindow(SW_HIDE) for a visible child window checking all parent events*/
1463 static const struct message WmHideChildSeq2[] = {
1464 { WM_SHOWWINDOW, sent|wparam, 0 },
1465 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1466 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1467 { WM_ERASEBKGND, sent|parent|optional },
1468 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1469 { 0 }
1471 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1472 * for a not visible child window
1474 static const struct message WmShowChildSeq_2[] = {
1475 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1476 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1477 { WM_CHILDACTIVATE, sent },
1478 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1479 { 0 }
1481 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
1482 * for a not visible child window
1484 static const struct message WmShowChildSeq_3[] = {
1485 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1486 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1487 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1488 { 0 }
1490 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1491 * for a visible child window with a caption
1493 static const struct message WmShowChildSeq_4[] = {
1494 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1495 { WM_CHILDACTIVATE, sent },
1496 { 0 }
1498 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
1499 static const struct message WmShowChildInvisibleParentSeq_1[] = {
1500 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1501 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1502 { WM_NCCALCSIZE, sent|wparam, 1 },
1503 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1504 { WM_CHILDACTIVATE, sent|optional },
1505 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1506 { WM_MOVE, sent|defwinproc },
1507 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1508 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1509 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1510 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1511 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1512 { WM_GETTEXT, sent|optional },
1513 { 0 }
1515 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
1516 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
1517 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1518 { 0 }
1520 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1521 static const struct message WmShowChildInvisibleParentSeq_2[] = {
1522 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1523 { WM_GETMINMAXINFO, sent },
1524 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
1525 { WM_NCCALCSIZE, sent|wparam, 1 },
1526 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1527 { WM_CHILDACTIVATE, sent },
1528 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1529 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1530 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1531 { 0 }
1533 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1534 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
1535 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1536 { 0 }
1538 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1539 static const struct message WmShowChildInvisibleParentSeq_3[] = {
1540 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1541 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1542 { WM_NCCALCSIZE, sent|wparam, 1 },
1543 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1544 { WM_CHILDACTIVATE, sent },
1545 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1546 { WM_MOVE, sent|defwinproc },
1547 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1548 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1549 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1550 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1551 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1552 { WM_GETTEXT, sent|optional },
1553 { 0 }
1555 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1556 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
1557 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1558 { 0 }
1560 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1561 static const struct message WmShowChildInvisibleParentSeq_4[] = {
1562 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1563 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
1564 { WM_NCCALCSIZE, sent|wparam, 1 },
1565 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1566 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1567 { WM_MOVE, sent|defwinproc },
1568 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1569 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1570 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1571 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1572 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1573 { WM_GETTEXT, sent|optional },
1574 { 0 }
1576 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1577 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
1578 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1579 { 0 }
1581 /* ShowWindow(SW_SHOW) for child with invisible parent */
1582 static const struct message WmShowChildInvisibleParentSeq_5[] = {
1583 { WM_SHOWWINDOW, sent|wparam, 1 },
1584 { 0 }
1586 /* ShowWindow(SW_HIDE) for child with invisible parent */
1587 static const struct message WmHideChildInvisibleParentSeq[] = {
1588 { WM_SHOWWINDOW, sent|wparam, 0 },
1589 { 0 }
1591 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
1592 static const struct message WmShowChildInvisibleParentSeq_6[] = {
1593 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1594 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1595 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1596 { 0 }
1598 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
1599 static const struct message WmHideChildInvisibleParentSeq_2[] = {
1600 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1601 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1602 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1603 { 0 }
1605 /* DestroyWindow for a visible child window */
1606 static const struct message WmDestroyChildSeq[] = {
1607 { HCBT_DESTROYWND, hook },
1608 { 0x0090, sent|optional },
1609 { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1610 { WM_SHOWWINDOW, sent|wparam, 0 },
1611 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1612 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1613 { WM_ERASEBKGND, sent|parent|optional },
1614 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1615 { HCBT_SETFOCUS, hook }, /* set focus to a parent */
1616 { WM_KILLFOCUS, sent },
1617 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1618 { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
1619 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1620 { WM_SETFOCUS, sent|parent },
1621 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1622 { WM_DESTROY, sent },
1623 { WM_DESTROY, sent|optional }, /* some other (IME?) window */
1624 { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
1625 { WM_NCDESTROY, sent },
1626 { 0 }
1628 /* visible child window destroyed by thread exit */
1629 static const struct message WmExitThreadSeq[] = {
1630 { WM_NCDESTROY, sent }, /* actually in grandchild */
1631 { WM_PAINT, sent|parent },
1632 { WM_ERASEBKGND, sent|parent|beginpaint },
1633 { 0 }
1635 /* DestroyWindow for a visible child window with invisible parent */
1636 static const struct message WmDestroyInvisibleChildSeq[] = {
1637 { HCBT_DESTROYWND, hook },
1638 { 0x0090, sent|optional },
1639 { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1640 { WM_SHOWWINDOW, sent|wparam, 0 },
1641 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1642 { WM_DESTROY, sent },
1643 { WM_NCDESTROY, sent },
1644 { 0 }
1646 /* Resizing child window with MoveWindow (32) */
1647 static const struct message WmResizingChildWithMoveWindowSeq[] = {
1648 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
1649 { WM_NCCALCSIZE, sent|wparam, 1 },
1650 { WM_ERASEBKGND, sent|parent|optional },
1651 { WM_ERASEBKGND, sent|optional },
1652 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
1653 { WM_MOVE, sent|defwinproc },
1654 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1655 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1656 { 0 }
1658 /* Creation of a custom dialog (32) */
1659 static const struct message WmCreateCustomDialogSeq[] = {
1660 { HCBT_CREATEWND, hook },
1661 { WM_GETMINMAXINFO, sent },
1662 { WM_NCCREATE, sent },
1663 { WM_NCCALCSIZE, sent|wparam, 0 },
1664 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win10. */
1665 { WM_CREATE, sent },
1666 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1667 { WM_NOTIFYFORMAT, sent|optional },
1668 { WM_QUERYUISTATE, sent|optional },
1669 { WM_WINDOWPOSCHANGING, sent|optional },
1670 { WM_GETMINMAXINFO, sent|optional },
1671 { WM_NCCALCSIZE, sent|optional },
1672 { WM_WINDOWPOSCHANGED, sent|optional },
1673 { WM_SHOWWINDOW, sent|wparam, 1 },
1674 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1675 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1676 { HCBT_ACTIVATE, hook },
1677 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1680 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1682 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1684 { WM_NCACTIVATE, sent },
1685 { WM_GETTEXT, sent|optional|defwinproc },
1686 { WM_GETTEXT, sent|optional|defwinproc },
1687 { WM_GETTEXT, sent|optional|defwinproc },
1688 { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1689 { WM_ACTIVATE, sent|wparam, 1 },
1690 { WM_GETTEXT, sent|optional },
1691 { WM_KILLFOCUS, sent|parent },
1692 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1693 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1694 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1695 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1696 { WM_SETFOCUS, sent },
1697 { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1698 { WM_NCPAINT, sent|wparam, 1 },
1699 { WM_GETTEXT, sent|optional|defwinproc },
1700 { WM_GETTEXT, sent|optional|defwinproc },
1701 { WM_ERASEBKGND, sent },
1702 { WM_CTLCOLORDLG, sent|optional|defwinproc },
1703 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1704 { WM_GETTEXT, sent|optional },
1705 { WM_GETTEXT, sent|optional },
1706 { WM_NCCALCSIZE, sent|optional },
1707 { WM_NCPAINT, sent|optional },
1708 { WM_GETTEXT, sent|optional|defwinproc },
1709 { WM_GETTEXT, sent|optional|defwinproc },
1710 { WM_ERASEBKGND, sent|optional },
1711 { WM_CTLCOLORDLG, sent|optional|defwinproc },
1712 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win10. */
1713 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1714 { WM_MOVE, sent },
1715 { 0 }
1717 /* Calling EndDialog for a custom dialog (32) */
1718 static const struct message WmEndCustomDialogSeq[] = {
1719 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1720 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1721 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1722 { WM_GETTEXT, sent|optional },
1723 { HCBT_ACTIVATE, hook },
1724 { WM_NCACTIVATE, sent|wparam, 0 },
1725 { WM_GETTEXT, sent|optional|defwinproc },
1726 { WM_GETTEXT, sent|optional|defwinproc },
1727 { WM_ACTIVATE, sent|wparam, 0 },
1728 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1729 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1730 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1731 { WM_GETTEXT, sent|optional|defwinproc },
1732 { WM_GETTEXT, sent|optional|defwinproc },
1733 { HCBT_SETFOCUS, hook },
1734 { WM_KILLFOCUS, sent },
1735 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1736 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1737 { WM_IME_NOTIFY, sent|wparam|optional, 1 },
1738 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1739 { WM_SETFOCUS, sent|parent|defwinproc },
1740 { 0 }
1742 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
1743 static const struct message WmShowCustomDialogSeq[] = {
1744 { WM_SHOWWINDOW, sent|wparam, 1 },
1745 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1746 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1747 { HCBT_ACTIVATE, hook },
1748 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1750 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1752 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1753 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1754 { WM_NCACTIVATE, sent },
1755 { WM_ACTIVATE, sent|wparam, 1 },
1756 { WM_GETTEXT, sent|optional },
1758 { WM_KILLFOCUS, sent|parent },
1759 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1760 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1761 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1762 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1763 { WM_SETFOCUS, sent },
1764 { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1765 { WM_NCPAINT, sent|wparam, 1 },
1766 { WM_ERASEBKGND, sent },
1767 { WM_CTLCOLORDLG, sent|defwinproc },
1768 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1769 { 0 }
1771 /* Creation and destruction of a modal dialog (32) */
1772 static const struct message WmModalDialogSeq[] = {
1773 { WM_CANCELMODE, sent|parent },
1774 { HCBT_SETFOCUS, hook },
1775 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1776 { WM_KILLFOCUS, sent|parent },
1777 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1778 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1779 { WM_ENABLE, sent|parent|wparam, 0 },
1780 { HCBT_CREATEWND, hook },
1781 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win10. */
1782 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1783 { WM_SETFONT, sent },
1784 { WM_INITDIALOG, sent },
1785 { WM_CHANGEUISTATE, sent|optional },
1786 { WM_UPDATEUISTATE, sent|optional },
1787 { WM_SHOWWINDOW, sent },
1788 { HCBT_ACTIVATE, hook },
1789 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1790 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1791 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1792 { WM_NCACTIVATE, sent },
1793 { WM_GETTEXT, sent|optional },
1794 { WM_ACTIVATE, sent|wparam, 1 },
1795 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1796 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1797 { WM_NCPAINT, sent|optional },
1798 { WM_GETTEXT, sent|optional },
1799 { WM_ERASEBKGND, sent|optional },
1800 { WM_CTLCOLORDLG, sent|optional },
1801 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1802 { WM_GETTEXT, sent|optional },
1803 { WM_NCCALCSIZE, sent|optional },
1804 { WM_NCPAINT, sent|optional },
1805 { WM_GETTEXT, sent|optional },
1806 { WM_ERASEBKGND, sent|optional },
1807 { WM_CTLCOLORDLG, sent|optional },
1808 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win10. */
1809 { WM_PAINT, sent|optional },
1810 { WM_CTLCOLORBTN, sent|optional },
1811 { WM_GETTITLEBARINFOEX, sent|optional },
1812 { WM_ENTERIDLE, sent|parent|optional },
1813 { WM_ENTERIDLE, sent|parent|optional },
1814 { WM_ENTERIDLE, sent|parent|optional },
1815 { WM_ENTERIDLE, sent|parent|optional },
1816 { WM_ENTERIDLE, sent|parent|optional },
1817 { WM_ENTERIDLE, sent|parent|optional },
1818 { WM_ENTERIDLE, sent|parent|optional },
1819 { WM_ENTERIDLE, sent|parent|optional },
1820 { WM_ENTERIDLE, sent|parent|optional },
1821 { WM_ENTERIDLE, sent|parent|optional },
1822 { WM_ENTERIDLE, sent|parent|optional },
1823 { WM_ENTERIDLE, sent|parent|optional },
1824 { WM_ENTERIDLE, sent|parent|optional },
1825 { WM_ENTERIDLE, sent|parent|optional },
1826 { WM_ENTERIDLE, sent|parent|optional },
1827 { WM_ENTERIDLE, sent|parent|optional },
1828 { WM_ENTERIDLE, sent|parent|optional },
1829 { WM_ENTERIDLE, sent|parent|optional },
1830 { WM_ENTERIDLE, sent|parent|optional },
1831 { WM_ENTERIDLE, sent|parent|optional },
1832 { WM_TIMER, sent },
1833 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1834 { WM_ENABLE, sent|parent|wparam, 1 },
1835 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1836 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1837 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1838 { WM_GETTEXT, sent|optional },
1839 { HCBT_ACTIVATE, hook },
1840 { WM_NCACTIVATE, sent|wparam, 0 },
1841 { WM_GETTEXT, sent|optional },
1842 { WM_ACTIVATE, sent|wparam, 0 },
1843 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1844 { WM_WINDOWPOSCHANGING, sent|optional },
1845 { WM_WINDOWPOSCHANGED, sent|optional },
1846 { HCBT_SETFOCUS, hook },
1847 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1848 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1849 { WM_SETFOCUS, sent|parent|defwinproc },
1850 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1851 { HCBT_DESTROYWND, hook },
1852 { 0x0090, sent|optional },
1853 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1854 { WM_DESTROY, sent },
1855 { WM_NCDESTROY, sent },
1856 { 0 }
1858 static const struct message WmModalDialogSeq_2[] = {
1859 { WM_CANCELMODE, sent },
1860 { HCBT_SETFOCUS, hook },
1861 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1862 { WM_KILLFOCUS, sent },
1863 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1864 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1865 { WM_ENABLE, sent|wparam, 0 },
1866 { HCBT_CREATEWND, hook },
1867 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
1868 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1869 { WM_SETFONT, sent },
1870 { WM_INITDIALOG, sent },
1871 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1872 { WM_CHANGEUISTATE, sent|optional },
1873 { WM_UPDATEUISTATE, sent|optional },
1874 { WM_ENABLE, sent|wparam, 1 },
1875 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1876 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 },
1877 { WM_CHANGEUISTATE, sent|optional },
1878 { WM_UPDATEUISTATE, sent|optional },
1879 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1880 { HCBT_DESTROYWND, hook },
1881 { 0x0090, sent|optional },
1882 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1883 { WM_DESTROY, sent },
1884 { WM_NCDESTROY, sent },
1885 { 0 }
1887 /* SetMenu for NonVisible windows with size change*/
1888 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1889 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1890 { WM_NCCALCSIZE, sent|wparam, 1 },
1891 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1892 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1893 { WM_MOVE, sent|defwinproc },
1894 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1895 { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1896 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1897 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1898 { WM_GETTEXT, sent|optional },
1899 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1900 { 0 }
1902 /* SetMenu for NonVisible windows with no size change */
1903 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1904 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1905 { WM_NCCALCSIZE, sent|wparam, 1 },
1906 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1907 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1908 { 0 }
1910 /* SetMenu for Visible windows with size change */
1911 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1912 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1913 { WM_NCCALCSIZE, sent|wparam, 1 },
1914 { 0x0093, sent|defwinproc|optional },
1915 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1916 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1917 { 0x0093, sent|defwinproc|optional },
1918 { 0x0093, sent|defwinproc|optional },
1919 { 0x0091, sent|defwinproc|optional },
1920 { 0x0092, sent|defwinproc|optional },
1921 { WM_GETTEXT, sent|defwinproc|optional },
1922 { WM_ERASEBKGND, sent|optional },
1923 { WM_ACTIVATE, sent|optional },
1924 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1925 { WM_MOVE, sent|defwinproc },
1926 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1927 { 0x0093, sent|optional },
1928 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1929 { 0x0093, sent|defwinproc|optional },
1930 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1931 { 0x0093, sent|defwinproc|optional },
1932 { 0x0093, sent|defwinproc|optional },
1933 { 0x0091, sent|defwinproc|optional },
1934 { 0x0092, sent|defwinproc|optional },
1935 { WM_ERASEBKGND, sent|optional },
1936 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1937 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1938 { 0 }
1940 /* SetMenu for Visible windows with no size change */
1941 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1942 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1943 { WM_NCCALCSIZE, sent|wparam, 1 },
1944 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1945 { WM_GETTEXT, sent|defwinproc|optional },
1946 { WM_ERASEBKGND, sent|optional },
1947 { WM_ACTIVATE, sent|optional },
1948 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1949 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1950 { 0 }
1952 /* DrawMenuBar for a visible window */
1953 static const struct message WmDrawMenuBarSeq[] =
1955 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1956 { WM_NCCALCSIZE, sent|wparam, 1 },
1957 { 0x0093, sent|defwinproc|optional },
1958 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1959 { 0x0093, sent|defwinproc|optional },
1960 { 0x0093, sent|defwinproc|optional },
1961 { 0x0091, sent|defwinproc|optional },
1962 { 0x0092, sent|defwinproc|optional },
1963 { WM_GETTEXT, sent|defwinproc|optional },
1964 { WM_ERASEBKGND, sent|optional },
1965 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1966 { 0x0093, sent|optional },
1967 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1968 { 0 }
1971 static const struct message WmSetRedrawFalseSeq[] =
1973 { WM_SETREDRAW, sent|wparam, 0 },
1974 { 0 }
1977 static const struct message WmSetRedrawTrueSeq[] =
1979 { WM_SETREDRAW, sent|wparam, 1 },
1980 { 0 }
1983 static const struct message WmEnableWindowSeq_1[] =
1985 { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1986 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1987 { HCBT_SETFOCUS, hook|optional },
1988 { WM_KILLFOCUS, sent|optional },
1989 { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1990 { 0 }
1993 static const struct message WmEnableWindowSeq_2[] =
1995 { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1996 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win10. */
1997 { 0 }
2000 static const struct message WmEnableWindowSeq_3[] =
2002 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2003 { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
2004 { 0 }
2007 static const struct message WmEnableWindowSeq_4[] =
2009 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win10. */
2010 { 0 }
2013 static const struct message WmGetScrollRangeSeq[] =
2015 { SBM_GETRANGE, sent },
2016 { 0 }
2018 static const struct message WmGetScrollInfoSeq[] =
2020 { SBM_GETSCROLLINFO, sent },
2021 { 0 }
2023 static const struct message WmSetScrollRangeSeq[] =
2025 /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
2026 sends SBM_SETSCROLLINFO.
2028 { SBM_SETSCROLLINFO, sent },
2029 { 0 }
2031 /* SetScrollRange for a window without a non-client area */
2032 static const struct message WmSetScrollRangeHSeq_empty[] =
2034 { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_HSCROLL, 0 },
2035 { 0 }
2037 static const struct message WmSetScrollRangeVSeq_empty[] =
2039 { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_VSCROLL, 0 },
2040 { 0 }
2042 static const struct message WmSetScrollRangeHVSeq[] =
2044 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
2045 { WM_NCCALCSIZE, sent|wparam, 1 },
2046 { WM_GETTEXT, sent|defwinproc|optional },
2047 { WM_ERASEBKGND, sent|optional },
2048 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2049 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2050 { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
2051 { 0 }
2053 /* SetScrollRange for a window with a non-client area */
2054 static const struct message WmSetScrollRangeHV_NC_Seq[] =
2056 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
2057 { WM_NCCALCSIZE, sent|wparam, 1 },
2058 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2059 { WM_NCPAINT, sent|optional },
2060 { WM_STYLECHANGING, sent|defwinproc|optional },
2061 { WM_STYLECHANGED, sent|defwinproc|optional },
2062 { WM_STYLECHANGING, sent|defwinproc|optional },
2063 { WM_STYLECHANGED, sent|defwinproc|optional },
2064 { WM_STYLECHANGING, sent|defwinproc|optional },
2065 { WM_STYLECHANGED, sent|defwinproc|optional },
2066 { WM_STYLECHANGING, sent|defwinproc|optional },
2067 { WM_STYLECHANGED, sent|defwinproc|optional },
2068 { WM_GETTEXT, sent|defwinproc|optional },
2069 { WM_GETTEXT, sent|defwinproc|optional },
2070 { WM_ERASEBKGND, sent|optional },
2071 { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
2072 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOCLIENTSIZE },
2073 { WM_SIZE, sent|defwinproc|optional },
2074 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2075 { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
2076 { WM_GETTEXT, sent|optional },
2077 { WM_GETTEXT, sent|optional },
2078 { WM_GETTEXT, sent|optional },
2079 { WM_GETTEXT, sent|optional },
2080 { 0 }
2082 /* test if we receive the right sequence of messages */
2083 /* after calling ShowWindow( SW_SHOWNA) */
2084 static const struct message WmSHOWNAChildInvisParInvis[] = {
2085 { WM_SHOWWINDOW, sent|wparam, 1 },
2086 { 0 }
2088 static const struct message WmSHOWNAChildVisParInvis[] = {
2089 { WM_SHOWWINDOW, sent|wparam, 1 },
2090 { 0 }
2092 static const struct message WmSHOWNAChildVisParVis[] = {
2093 { WM_SHOWWINDOW, sent|wparam, 1 },
2094 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
2095 { 0 }
2097 static const struct message WmSHOWNAChildInvisParVis[] = {
2098 { WM_SHOWWINDOW, sent|wparam, 1 },
2099 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2100 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2101 { WM_ERASEBKGND, sent|optional },
2102 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
2103 { 0 }
2105 static const struct message WmSHOWNATopVisible[] = {
2106 { WM_SHOWWINDOW, sent|wparam, 1 },
2107 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
2108 { WM_NCPAINT, sent|wparam|optional, 1 },
2109 { WM_GETTEXT, sent|defwinproc|optional },
2110 { WM_ERASEBKGND, sent|optional },
2111 { WM_WINDOWPOSCHANGED, sent|optional },
2112 { 0 }
2114 static const struct message WmSHOWNATopInvisible[] = {
2115 { WM_NOTIFYFORMAT, sent|optional },
2116 { WM_QUERYUISTATE, sent|optional },
2117 { WM_WINDOWPOSCHANGING, sent|optional },
2118 { WM_GETMINMAXINFO, sent|optional },
2119 { WM_NCCALCSIZE, sent|optional },
2120 { WM_WINDOWPOSCHANGED, sent|optional },
2121 { WM_SHOWWINDOW, sent|wparam, 1 },
2122 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2123 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2124 { WM_NCPAINT, sent|wparam|optional, 1 },
2125 { WM_GETTEXT, sent|defwinproc|optional },
2126 { WM_ERASEBKGND, sent|optional },
2127 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2128 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2129 { WM_NCPAINT, sent|wparam|optional, 1 },
2130 { WM_ERASEBKGND, sent|optional },
2131 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends it, but Win8+ doesn't. */
2132 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2133 { WM_MOVE, sent },
2134 { 0 }
2137 static const struct message WmTrackPopupMenuMinimizeWindow[] = {
2138 { HCBT_CREATEWND, hook },
2139 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2140 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
2141 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2142 { WM_INITMENU, sent|lparam, 0, 0 },
2143 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2144 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
2145 { 0x0093, sent|optional },
2146 { 0x0094, sent|optional },
2147 { 0x0094, sent|optional },
2148 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2149 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2150 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
2151 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
2152 { WM_ENTERIDLE, sent|wparam, 2 },
2153 { HCBT_MINMAX, hook },
2154 { HCBT_SETFOCUS, hook },
2155 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2156 { WM_KILLFOCUS, sent|wparam, 0 },
2157 { WM_GETTEXT, sent|optional },
2158 { WM_WINDOWPOSCHANGING, sent },
2159 { WM_GETMINMAXINFO, sent|defwinproc },
2160 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2161 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2162 { WM_WINDOWPOSCHANGED, sent },
2163 { WM_MOVE, sent|defwinproc },
2164 { WM_SIZE, sent|defwinproc },
2165 { WM_GETTEXT, sent|optional },
2166 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2167 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2168 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
2169 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2170 { WM_CANCELMODE, sent },
2171 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2172 { WM_CAPTURECHANGED, sent|defwinproc },
2173 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
2174 { HCBT_DESTROYWND, hook },
2175 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2176 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2177 { WM_UNINITMENUPOPUP, sent|defwinproc|lparam, 0, 0 },
2178 { WM_MENUSELECT, sent|defwinproc|wparam|lparam, 0xffff0000, 0 },
2179 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2180 { WM_EXITMENULOOP, sent|defwinproc|wparam|lparam, 1, 0 },
2181 { WM_NCACTIVATE, sent },
2182 { WM_GETTEXT, sent|defwinproc|optional },
2183 { WM_GETTEXT, sent|defwinproc|optional },
2184 { WM_ACTIVATE, sent },
2185 { WM_ACTIVATEAPP, sent|wparam, 0 },
2186 { 0 }
2189 static const struct message WmTrackPopupMenu[] = {
2190 { HCBT_CREATEWND, hook },
2191 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2192 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
2193 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2194 { WM_INITMENU, sent|lparam, 0, 0 },
2195 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2196 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
2197 { 0x0093, sent|optional },
2198 { 0x0094, sent|optional },
2199 { 0x0094, sent|optional },
2200 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2201 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2202 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
2203 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
2204 { WM_ENTERIDLE, sent|wparam, 2 },
2205 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2206 { WM_CAPTURECHANGED, sent },
2207 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
2208 { HCBT_DESTROYWND, hook },
2209 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2210 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2211 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
2212 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
2213 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2214 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
2215 { 0 }
2218 static const struct message WmTrackPopupMenuEsc[] = {
2219 { 0 }
2222 static const struct message WmTrackPopupMenuCapture[] = {
2223 { HCBT_CREATEWND, hook },
2224 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2225 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
2226 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2227 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2228 { WM_CAPTURECHANGED, sent },
2229 { WM_INITMENU, sent|lparam, 0, 0 },
2230 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2231 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
2232 { 0x0093, sent|optional },
2233 { 0x0094, sent|optional },
2234 { 0x0094, sent|optional },
2235 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2236 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2237 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
2238 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
2239 { WM_ENTERIDLE, sent|wparam, 2 },
2240 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2241 { WM_CAPTURECHANGED, sent },
2242 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
2243 { HCBT_DESTROYWND, hook },
2244 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2245 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2246 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
2247 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
2248 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2249 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
2250 { 0 }
2253 static const struct message WmTrackPopupMenuEmpty[] = {
2254 { HCBT_CREATEWND, hook },
2255 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2256 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
2257 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2258 { WM_INITMENU, sent|lparam, 0, 0 },
2259 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2260 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
2261 { 0x0093, sent|optional },
2262 { 0x0094, sent|optional },
2263 { 0x0094, sent|optional },
2264 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2265 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2266 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2267 { WM_CAPTURECHANGED, sent },
2268 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
2269 { HCBT_DESTROYWND, hook },
2270 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2271 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
2272 { 0 }
2275 static const struct message WmTrackPopupMenuAbort[] = {
2276 { HCBT_CREATEWND, hook },
2277 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2278 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
2279 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2280 { WM_INITMENU, sent|lparam, 0, 0 },
2281 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2282 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
2283 { 0x0093, sent|optional },
2284 { 0x0094, sent|optional },
2285 { 0x0094, sent|optional },
2286 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2287 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2288 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
2289 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
2290 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2291 { WM_CAPTURECHANGED, sent },
2292 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
2293 { HCBT_DESTROYWND, hook },
2294 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2295 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2296 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
2297 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
2298 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2299 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
2300 { 0 }
2303 static BOOL after_end_dialog, test_def_id, paint_loop_done;
2304 static int sequence_cnt, sequence_size;
2305 static struct recvd_message* sequence;
2306 static int log_all_parent_messages;
2307 static CRITICAL_SECTION sequence_cs;
2309 /* user32 functions */
2310 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
2311 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
2312 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
2313 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
2314 static BOOL (WINAPI *pUpdateLayeredWindow)(HWND,HDC,POINT*,SIZE*,HDC,POINT*,COLORREF,BLENDFUNCTION*,DWORD);
2315 static UINT_PTR (WINAPI *pSetSystemTimer)(HWND, UINT_PTR, UINT, TIMERPROC);
2316 static UINT_PTR (WINAPI *pKillSystemTimer)(HWND, UINT_PTR);
2317 static UINT_PTR (WINAPI *pSetCoalescableTimer)(HWND, UINT_PTR, UINT, TIMERPROC, ULONG);
2318 /* kernel32 functions */
2319 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
2321 static void init_procs(void)
2323 HMODULE user32 = GetModuleHandleA("user32.dll");
2324 HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
2326 #define GET_PROC(dll, func) \
2327 p ## func = (void*)GetProcAddress(dll, #func); \
2328 if(!p ## func) { \
2329 trace("GetProcAddress(%s) failed\n", #func); \
2332 GET_PROC(user32, NotifyWinEvent)
2333 GET_PROC(user32, SetWinEventHook)
2334 GET_PROC(user32, TrackMouseEvent)
2335 GET_PROC(user32, UnhookWinEvent)
2336 GET_PROC(user32, UpdateLayeredWindow)
2337 GET_PROC(user32, SetSystemTimer)
2338 GET_PROC(user32, KillSystemTimer)
2339 GET_PROC(user32, SetCoalescableTimer)
2341 GET_PROC(kernel32, GetCPInfoExA)
2343 #undef GET_PROC
2346 static const char *get_winpos_flags(UINT flags)
2348 static char buffer[300];
2350 buffer[0] = 0;
2351 #define DUMP(flag) do { if (flags & flag) { strcat( buffer, "|" #flag ); flags &= ~flag; } } while(0)
2352 DUMP( SWP_SHOWWINDOW );
2353 DUMP( SWP_HIDEWINDOW );
2354 DUMP( SWP_NOACTIVATE );
2355 DUMP( SWP_FRAMECHANGED );
2356 DUMP( SWP_NOCOPYBITS );
2357 DUMP( SWP_NOOWNERZORDER );
2358 DUMP( SWP_NOSENDCHANGING );
2359 DUMP( SWP_DEFERERASE );
2360 DUMP( SWP_ASYNCWINDOWPOS );
2361 DUMP( SWP_NOZORDER );
2362 DUMP( SWP_NOREDRAW );
2363 DUMP( SWP_NOSIZE );
2364 DUMP( SWP_NOMOVE );
2365 DUMP( SWP_NOCLIENTSIZE );
2366 DUMP( SWP_NOCLIENTMOVE );
2367 if (flags) sprintf(buffer + strlen(buffer),"|0x%04x", flags);
2368 return buffer + 1;
2369 #undef DUMP
2372 static BOOL ignore_message( UINT message )
2374 /* these are always ignored */
2375 return (message >= 0xc000 ||
2376 message == WM_GETICON ||
2377 message == WM_GETOBJECT ||
2378 message == WM_TIMECHANGE ||
2379 message == WM_DISPLAYCHANGE ||
2380 message == WM_DEVICECHANGE ||
2381 message == WM_DWMNCRENDERINGCHANGED ||
2382 message == WM_WININICHANGE);
2385 static unsigned hash_Ly_W(const WCHAR *str)
2387 unsigned hash = 0;
2389 for (; *str; str++)
2390 hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u;
2392 return hash;
2395 static unsigned hash_Ly(const char *str)
2397 unsigned hash = 0;
2399 for (; *str; str++)
2400 hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u;
2402 return hash;
2405 #define add_message(msg) add_message_(__LINE__,msg);
2406 static void add_message_(int line, const struct recvd_message *msg)
2408 struct recvd_message *seq;
2410 EnterCriticalSection( &sequence_cs );
2411 if (!sequence)
2413 sequence_size = 10;
2414 sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof(*sequence) );
2416 if (sequence_cnt == sequence_size)
2418 sequence_size *= 2;
2419 sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof(*sequence) );
2421 assert(sequence);
2423 seq = &sequence[sequence_cnt++];
2424 seq->hwnd = msg->hwnd;
2425 seq->message = msg->message;
2426 seq->flags = msg->flags;
2427 seq->wParam = msg->wParam;
2428 seq->lParam = msg->lParam;
2429 seq->line = line;
2430 seq->descr = msg->descr;
2431 seq->output[0] = 0;
2432 LeaveCriticalSection( &sequence_cs );
2434 if (msg->descr)
2436 if (msg->flags & hook)
2438 static const char * const CBT_code_name[10] =
2440 "HCBT_MOVESIZE",
2441 "HCBT_MINMAX",
2442 "HCBT_QS",
2443 "HCBT_CREATEWND",
2444 "HCBT_DESTROYWND",
2445 "HCBT_ACTIVATE",
2446 "HCBT_CLICKSKIPPED",
2447 "HCBT_KEYSKIPPED",
2448 "HCBT_SYSCOMMAND",
2449 "HCBT_SETFOCUS"
2451 const char *code_name = (msg->message <= HCBT_SETFOCUS) ? CBT_code_name[msg->message] : "Unknown";
2453 sprintf( seq->output, "%s: hook %d (%s) wp %08Ix lp %08Ix",
2454 msg->descr, msg->message, code_name, msg->wParam, msg->lParam );
2456 else if (msg->flags & winevent_hook)
2458 sprintf( seq->output, "%s: winevent %p %08x %08Ix %08Ix",
2459 msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
2461 else
2463 switch (msg->message)
2465 case WM_WINDOWPOSCHANGING:
2466 case WM_WINDOWPOSCHANGED:
2468 WINDOWPOS *winpos = (WINDOWPOS *)msg->lParam;
2470 sprintf( seq->output, "%s: %p WM_WINDOWPOS%s wp %08Ix lp %08Ix after %p x %d y %d cx %d cy %d flags %s",
2471 msg->descr, msg->hwnd,
2472 (msg->message == WM_WINDOWPOSCHANGING) ? "CHANGING" : "CHANGED",
2473 msg->wParam, msg->lParam, winpos->hwndInsertAfter,
2474 winpos->x, winpos->y, winpos->cx, winpos->cy,
2475 get_winpos_flags(winpos->flags) );
2477 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2478 * in the high word for internal purposes
2480 seq->wParam = winpos->flags & 0xffff;
2481 /* We are not interested in the flags that don't match under XP and Win9x */
2482 seq->wParam &= ~SWP_NOZORDER;
2483 seq->lParam = (!!winpos->cx) | ((!!winpos->cy) << 1)
2484 | ((!!winpos->x) << 2) | ((!!winpos->y) << 3);
2485 break;
2488 case WM_NCCALCSIZE:
2489 if (msg->wParam)
2491 NCCALCSIZE_PARAMS *p = (NCCALCSIZE_PARAMS *)msg->lParam;
2492 WINDOWPOS *winpos = p->lppos;
2494 sprintf(seq->output, "%s: %p WM_NCCALCSIZE: winpos->cx %u, winpos->cy %u",
2495 msg->descr, msg->hwnd, winpos->cx, winpos->cy);
2496 seq->lParam = (!!winpos->cx) | ((!!winpos->cy) << 1)
2497 | ((!!winpos->x) << 2) | ((!!winpos->y) << 3);
2499 else
2501 seq->lParam = 0;
2503 break;
2504 case WM_DRAWITEM:
2506 DRAW_ITEM_STRUCT di;
2507 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)msg->lParam;
2509 sprintf( seq->output, "%s: %p WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x",
2510 msg->descr, msg->hwnd, dis->CtlType, dis->CtlID,
2511 dis->itemID, dis->itemAction, dis->itemState);
2513 di.u.lp = 0;
2514 di.u.item.type = dis->CtlType;
2515 di.u.item.ctl_id = dis->CtlID;
2516 if (dis->CtlType == ODT_LISTBOX ||
2517 dis->CtlType == ODT_COMBOBOX ||
2518 dis->CtlType == ODT_MENU)
2519 di.u.item.item_id = dis->itemID;
2520 di.u.item.action = dis->itemAction;
2521 di.u.item.state = dis->itemState;
2523 seq->lParam = di.u.lp;
2524 break;
2527 case WM_MEASUREITEM:
2529 MEASURE_ITEM_STRUCT mi;
2530 MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)msg->lParam;
2531 BOOL is_unicode_data = TRUE;
2533 sprintf( seq->output, "%s: %p WM_MEASUREITEM: CtlType %#x, CtlID %#x, itemID %#x, itemData %#Ix",
2534 msg->descr, msg->hwnd, mis->CtlType, mis->CtlID,
2535 mis->itemID, mis->itemData);
2537 if (mis->CtlType == ODT_LISTBOX)
2539 HWND ctrl = GetDlgItem(msg->hwnd, mis->CtlID);
2540 is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
2543 mi.u.wp = 0;
2544 mi.u.item.CtlType = mis->CtlType;
2545 mi.u.item.CtlID = mis->CtlID;
2546 mi.u.item.itemID = mis->itemID;
2547 mi.u.item.wParam = msg->wParam;
2548 seq->wParam = mi.u.wp;
2549 if (is_unicode_data)
2550 seq->lParam = mis->itemData ? hash_Ly_W((const WCHAR *)mis->itemData) : 0;
2551 else
2552 seq->lParam = mis->itemData ? hash_Ly((const char *)mis->itemData) : 0;
2553 break;
2556 case WM_COMPAREITEM:
2558 COMPAREITEMSTRUCT *cis = (COMPAREITEMSTRUCT *)msg->lParam;
2559 HWND ctrl = GetDlgItem(msg->hwnd, cis->CtlID);
2560 BOOL is_unicode_data = TRUE;
2562 ok(msg->wParam == cis->CtlID, "expected %#x, got %#Ix\n", cis->CtlID, msg->wParam);
2563 ok(cis->hwndItem == ctrl, "expected %p, got %p\n", ctrl, cis->hwndItem);
2564 ok((int)cis->itemID1 >= 0, "expected >= 0, got %d\n", cis->itemID1);
2565 ok((int)cis->itemID2 == -1, "expected -1, got %d\n", cis->itemID2);
2567 sprintf( seq->output, "%s: %p WM_COMPAREITEM: CtlType %#x, CtlID %#x, itemID1 %#x, itemData1 %#Ix, itemID2 %#x, itemData2 %#Ix",
2568 msg->descr, msg->hwnd, cis->CtlType, cis->CtlID,
2569 cis->itemID1, cis->itemData1, cis->itemID2, cis->itemData2);
2571 if (cis->CtlType == ODT_LISTBOX)
2572 is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
2574 if (is_unicode_data)
2576 seq->wParam = cis->itemData1 ? hash_Ly_W((const WCHAR *)cis->itemData1) : 0;
2577 seq->lParam = cis->itemData2 ? hash_Ly_W((const WCHAR *)cis->itemData2) : 0;
2579 else
2581 seq->wParam = cis->itemData1 ? hash_Ly((const char *)cis->itemData1) : 0;
2582 seq->lParam = cis->itemData2 ? hash_Ly((const char *)cis->itemData2) : 0;
2584 break;
2587 default:
2588 if (msg->message >= 0xc000) return; /* ignore registered messages */
2589 sprintf( seq->output, "%s: %p %04x wp %08Ix lp %08Ix",
2590 msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
2592 if (msg->flags & (sent|posted|parent|defwinproc|beginpaint))
2593 sprintf( seq->output + strlen(seq->output), " (flags %x)", msg->flags );
2598 /* try to make sure pending X events have been processed before continuing */
2599 static void flush_events(void)
2601 MSG msg;
2602 int diff = 200;
2603 int min_timeout = 100;
2604 DWORD time = GetTickCount() + diff;
2606 while (diff > 0)
2608 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
2609 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
2610 diff = time - GetTickCount();
2614 static void flush_sequence(void)
2616 EnterCriticalSection( &sequence_cs );
2617 HeapFree(GetProcessHeap(), 0, sequence);
2618 sequence = 0;
2619 sequence_cnt = sequence_size = 0;
2620 LeaveCriticalSection( &sequence_cs );
2623 static void dump_sequence(const struct message *expected, const char *context, const char *file, int line)
2625 const struct recvd_message *actual = sequence;
2626 unsigned int count = 0;
2628 trace_(file, line)("Failed sequence %s:\n", context );
2629 while (expected->message && actual->message)
2631 if (actual->output[0])
2633 if (expected->flags & hook)
2635 trace_(file, line)( " %u: expected: hook %04x - actual: %s\n",
2636 count, expected->message, actual->output );
2638 else if (expected->flags & winevent_hook)
2640 trace_(file, line)( " %u: expected: winevent %04x - actual: %s\n",
2641 count, expected->message, actual->output );
2643 else if (expected->flags & kbd_hook)
2645 trace_(file, line)( " %u: expected: kbd %04x - actual: %s\n",
2646 count, expected->message, actual->output );
2648 else
2650 trace_(file, line)( " %u: expected: msg %04x - actual: %s\n",
2651 count, expected->message, actual->output );
2655 if (expected->message == actual->message)
2657 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) &&
2658 (expected->flags & optional))
2660 /* don't match messages if their defwinproc status differs */
2661 expected++;
2663 else
2665 expected++;
2666 actual++;
2669 /* silently drop winevent messages if there is no support for them */
2670 else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook) ||
2671 ((expected->flags & winevent_hook_todo) && !strcmp(winetest_platform, "wine")))
2672 expected++;
2673 else
2675 expected++;
2676 actual++;
2678 count++;
2681 /* optional trailing messages */
2682 while (expected->message && ((expected->flags & optional) ||
2683 ((expected->flags & winevent_hook) && !hEvent_hook)))
2685 trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2686 expected++;
2687 count++;
2690 if (expected->message)
2692 trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2693 return;
2696 while (actual->message && actual->output[0])
2698 trace_(file, line)( " %u: expected: nothing - actual: %s\n", count, actual->output );
2699 actual++;
2700 count++;
2704 #define ok_sequence( exp, contx, todo) \
2705 ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
2708 static void ok_sequence_(const struct message *expected_list, const char *context, BOOL todo,
2709 const char *file, int line)
2711 static const struct recvd_message end_of_sequence;
2712 const struct message *expected = expected_list;
2713 const struct recvd_message *actual;
2714 int failcount = 0, dump = 0;
2715 unsigned int count = 0;
2717 add_message(&end_of_sequence);
2719 actual = sequence;
2721 while (expected->message && actual->message)
2723 if (expected->message == actual->message &&
2724 !((expected->flags ^ actual->flags) & (hook|winevent_hook|kbd_hook)))
2726 if (expected->flags & wparam)
2728 if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && todo)
2730 todo_wine {
2731 failcount ++;
2732 if (strcmp(winetest_platform, "wine")) dump++;
2733 ok_( file, line) (FALSE,
2734 "%s: %u: in msg 0x%04x expecting wParam 0x%Ix got 0x%Ix\n",
2735 context, count, expected->message, expected->wParam, actual->wParam);
2738 else
2740 ok_( file, line)( ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) == 0,
2741 "%s: %u: in msg 0x%04x expecting wParam 0x%Ix got 0x%Ix\n",
2742 context, count, expected->message, expected->wParam, actual->wParam);
2743 if ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) dump++;
2747 if (expected->flags & lparam)
2749 if (((expected->lParam ^ actual->lParam) & ~expected->lp_mask) && todo)
2751 todo_wine {
2752 failcount ++;
2753 if (strcmp(winetest_platform, "wine")) dump++;
2754 ok_( file, line) (FALSE,
2755 "%s: %u: in msg 0x%04x expecting lParam 0x%Ix got 0x%Ix\n",
2756 context, count, expected->message, expected->lParam, actual->lParam);
2759 else
2761 ok_( file, line)(((expected->lParam ^ actual->lParam) & ~expected->lp_mask) == 0,
2762 "%s: %u: in msg 0x%04x expecting lParam 0x%Ix got 0x%Ix\n",
2763 context, count, expected->message, expected->lParam, actual->lParam);
2764 if ((expected->lParam ^ actual->lParam) & ~expected->lp_mask) dump++;
2767 if ((expected->flags & optional) &&
2768 ((expected->flags ^ actual->flags) & (defwinproc|parent)))
2770 /* don't match optional messages if their defwinproc or parent status differs */
2771 expected++;
2772 count++;
2773 continue;
2775 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
2777 todo_wine {
2778 failcount ++;
2779 if (strcmp(winetest_platform, "wine")) dump++;
2780 ok_( file, line) (FALSE,
2781 "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2782 context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2785 else
2787 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
2788 "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2789 context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2790 if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++;
2793 ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
2794 "%s: %u: the msg 0x%04x should %shave been sent by BeginPaint\n",
2795 context, count, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
2796 if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++;
2798 ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
2799 "%s: %u: the msg 0x%04x should have been %s\n",
2800 context, count, expected->message, (expected->flags & posted) ? "posted" : "sent");
2801 if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++;
2803 ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
2804 "%s: %u: the msg 0x%04x was expected in %s\n",
2805 context, count, expected->message, (expected->flags & parent) ? "parent" : "child");
2806 if ((expected->flags & parent) != (actual->flags & parent)) dump++;
2808 ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
2809 "%s: %u: the msg 0x%04x should have been sent by a hook\n",
2810 context, count, expected->message);
2811 if ((expected->flags & hook) != (actual->flags & hook)) dump++;
2813 ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
2814 "%s: %u: the msg 0x%04x should have been sent by a winevent hook\n",
2815 context, count, expected->message);
2816 if ((expected->flags & winevent_hook) != (actual->flags & winevent_hook)) dump++;
2818 ok_( file, line) ((expected->flags & kbd_hook) == (actual->flags & kbd_hook),
2819 "%s: %u: the msg 0x%04x should have been sent by a keyboard hook\n",
2820 context, count, expected->message);
2821 if ((expected->flags & kbd_hook) != (actual->flags & kbd_hook)) dump++;
2823 expected++;
2824 actual++;
2827 * silently drop hook messages if there is no support for them, mark
2828 * winevent todo's.
2830 else if ((expected->flags & optional) ||
2831 ((expected->flags & hook) && !hCBT_hook) ||
2832 ((expected->flags & winevent_hook) && !hEvent_hook) ||
2833 ((expected->flags & kbd_hook) && !hKBD_hook) ||
2834 ((expected->flags & winevent_hook_todo) && !strcmp(winetest_platform, "wine")))
2836 if ((expected->flags & winevent_hook_todo) && hEvent_hook)
2838 todo_wine {
2839 ok_( file, line) (FALSE,
2840 "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2841 context, count, expected->message, actual->message);
2844 expected++;
2846 else if (todo)
2848 failcount++;
2849 todo_wine {
2850 if (strcmp(winetest_platform, "wine")) dump++;
2851 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2852 context, count, expected->message, actual->message);
2854 goto done;
2856 else
2858 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2859 context, count, expected->message, actual->message);
2860 dump++;
2861 expected++;
2862 actual++;
2864 count++;
2867 /* skip all optional trailing messages, check for winevent todo's. */
2868 while (expected->message && ((expected->flags & optional) ||
2869 ((expected->flags & hook) && !hCBT_hook) ||
2870 ((expected->flags & winevent_hook) && !hEvent_hook) ||
2871 ((expected->flags & winevent_hook_todo) && !strcmp(winetest_platform, "wine"))))
2873 if ((expected->flags & winevent_hook_todo) && hEvent_hook)
2875 todo_wine {
2876 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected 0x%04x - actual 0x%04x\n",
2877 context, count, expected->message, actual->message);
2880 expected++;
2883 if (todo)
2885 todo_wine {
2886 if (expected->message || actual->message) {
2887 failcount++;
2888 if (strcmp(winetest_platform, "wine")) dump++;
2889 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2890 context, count, expected->message, actual->message);
2894 else
2896 if (expected->message || actual->message)
2898 dump++;
2899 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2900 context, count, expected->message, actual->message);
2903 if( todo && !failcount) /* succeeded yet marked todo */
2904 todo_wine {
2905 if (!strcmp(winetest_platform, "wine")) dump++;
2906 ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
2909 done:
2910 if (dump) dump_sequence(expected_list, context, file, line);
2911 flush_sequence();
2914 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %ld\n", (EXPECTED), (GOT))
2916 /******************************** MDI test **********************************/
2918 /* CreateWindow for MDI frame window, initially visible */
2919 static const struct message WmCreateMDIframeSeq[] = {
2920 { HCBT_CREATEWND, hook },
2921 { WM_GETMINMAXINFO, sent },
2922 { WM_NCCREATE, sent },
2923 { WM_NCCALCSIZE, sent|wparam, 0 },
2924 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win8+. */
2925 { WM_CREATE, sent },
2926 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2927 { WM_NOTIFYFORMAT, sent|optional },
2928 { WM_QUERYUISTATE, sent|optional },
2929 { WM_WINDOWPOSCHANGING, sent|optional },
2930 { WM_GETMINMAXINFO, sent|optional },
2931 { WM_NCCALCSIZE, sent|optional },
2932 { WM_WINDOWPOSCHANGED, sent|optional },
2933 { WM_SHOWWINDOW, sent|wparam, 1 },
2934 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2935 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2936 { HCBT_ACTIVATE, hook },
2937 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2938 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
2939 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
2940 { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
2941 { WM_NCACTIVATE, sent },
2942 { WM_GETTEXT, sent|defwinproc|optional },
2943 { WM_ACTIVATE, sent|wparam, 1 },
2944 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
2945 { HCBT_SETFOCUS, hook },
2946 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2947 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2948 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
2949 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
2950 /* Win9x adds SWP_NOZORDER below */
2951 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2952 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2953 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win8+. */
2954 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2955 { WM_MOVE, sent },
2956 { 0 }
2958 /* DestroyWindow for MDI frame window, initially visible */
2959 static const struct message WmDestroyMDIframeSeq[] = {
2960 { HCBT_DESTROYWND, hook },
2961 { 0x0090, sent|optional },
2962 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2963 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2964 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2965 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2966 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
2967 { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2968 { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
2969 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
2970 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2971 { WM_DESTROY, sent },
2972 { WM_NCDESTROY, sent },
2973 { 0 }
2975 /* CreateWindow for MDI client window, initially visible */
2976 static const struct message WmCreateMDIclientSeq[] = {
2977 { HCBT_CREATEWND, hook },
2978 { WM_NCCREATE, sent },
2979 { WM_NCCALCSIZE, sent|wparam, 0 },
2980 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2981 { WM_CREATE, sent },
2982 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2983 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2984 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2985 { WM_MOVE, sent },
2986 { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
2987 { WM_SHOWWINDOW, sent|wparam, 1 },
2988 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2989 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2990 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2991 { 0 }
2993 /* ShowWindow(SW_SHOW) for MDI client window */
2994 static const struct message WmShowMDIclientSeq[] = {
2995 { WM_SHOWWINDOW, sent|wparam, 1 },
2996 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2997 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2998 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2999 { 0 }
3001 /* ShowWindow(SW_HIDE) for MDI client window */
3002 static const struct message WmHideMDIclientSeq[] = {
3003 { WM_SHOWWINDOW, sent|wparam, 0 },
3004 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3005 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
3006 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
3007 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3008 { 0 }
3010 /* DestroyWindow for MDI client window, initially visible */
3011 static const struct message WmDestroyMDIclientSeq[] = {
3012 { HCBT_DESTROYWND, hook },
3013 { 0x0090, sent|optional },
3014 { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
3015 { WM_SHOWWINDOW, sent|wparam, 0 },
3016 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3017 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3018 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3019 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3020 { WM_DESTROY, sent },
3021 { WM_NCDESTROY, sent },
3022 { 0 }
3024 /* CreateWindow for MDI child window, initially visible */
3025 static const struct message WmCreateMDIchildVisibleSeq[] = {
3026 { HCBT_CREATEWND, hook },
3027 { WM_NCCREATE, sent },
3028 { WM_NCCALCSIZE, sent|wparam, 0 },
3029 { WM_CREATE, sent },
3030 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3031 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3032 { WM_MOVE, sent },
3033 /* Win2k sends wparam set to
3034 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3035 * while Win9x doesn't bother to set child window id according to
3036 * CLIENTCREATESTRUCT.idFirstChild
3038 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3039 { WM_SHOWWINDOW, sent|wparam, 1 },
3040 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3041 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3042 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3043 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
3044 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3045 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3046 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3048 /* Win9x: message sequence terminates here. */
3050 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3051 { HCBT_SETFOCUS, hook }, /* in MDI client */
3052 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3053 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
3054 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
3055 { WM_SETFOCUS, sent }, /* in MDI client */
3056 { HCBT_SETFOCUS, hook },
3057 { WM_KILLFOCUS, sent }, /* in MDI client */
3058 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3059 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3060 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3061 { WM_SETFOCUS, sent|defwinproc },
3062 { WM_MDIACTIVATE, sent|defwinproc },
3063 { 0 }
3065 /* WM_CHILDACTIVATE sent to disabled window */
3066 static const struct message WmChildActivateDisabledWindowSeq[] = {
3067 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3068 { 0 }
3070 /* WM_CHILDACTIVATE sent to enabled window */
3071 static const struct message WmChildActivateWindowSeq[] = {
3072 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3073 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 },
3074 { WM_MDIACTIVATE, sent|defwinproc },
3075 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3076 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
3077 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3078 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3079 { HCBT_SETFOCUS, hook },
3080 { WM_KILLFOCUS, sent|defwinproc },
3081 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3082 { WM_SETFOCUS, sent },
3083 { HCBT_SETFOCUS, hook },
3084 { WM_KILLFOCUS, sent },
3085 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3086 { WM_SETFOCUS, sent|defwinproc },
3087 { WM_MDIACTIVATE, sent|defwinproc },
3088 { 0 }
3090 /* CreateWindow for MDI child window with invisible parent */
3091 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
3092 { HCBT_CREATEWND, hook },
3093 { WM_GETMINMAXINFO, sent },
3094 { WM_NCCREATE, sent },
3095 { WM_NCCALCSIZE, sent|wparam, 0 },
3096 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
3097 { WM_CREATE, sent },
3098 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3099 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3100 { WM_MOVE, sent },
3101 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3102 { WM_SHOWWINDOW, sent|wparam, 1 },
3103 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
3104 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3105 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3106 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3108 /* Win9x: message sequence terminates here. */
3110 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3111 { HCBT_SETFOCUS, hook }, /* in MDI client */
3112 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3113 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
3114 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
3115 { WM_SETFOCUS, sent }, /* in MDI client */
3116 { HCBT_SETFOCUS, hook },
3117 { WM_KILLFOCUS, sent }, /* in MDI client */
3118 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3119 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3120 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3121 { WM_SETFOCUS, sent|defwinproc },
3122 { WM_MDIACTIVATE, sent|defwinproc },
3123 { 0 }
3125 /* DestroyWindow for MDI child window, initially visible */
3126 static const struct message WmDestroyMDIchildVisibleSeq[] = {
3127 { HCBT_DESTROYWND, hook },
3128 /* Win2k sends wparam set to
3129 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3130 * while Win9x doesn't bother to set child window id according to
3131 * CLIENTCREATESTRUCT.idFirstChild
3133 { 0x0090, sent|optional },
3134 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3135 { WM_SHOWWINDOW, sent|wparam, 0 },
3136 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3137 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3138 { WM_ERASEBKGND, sent|parent|optional },
3139 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3141 /* { WM_DESTROY, sent }
3142 * Win9x: message sequence terminates here.
3145 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
3146 { WM_KILLFOCUS, sent },
3147 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3148 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3149 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3150 { WM_SETFOCUS, sent }, /* in MDI client */
3152 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
3153 { WM_KILLFOCUS, sent }, /* in MDI client */
3154 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3155 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3156 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3157 { WM_SETFOCUS, sent }, /* in MDI client */
3159 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3161 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
3162 { WM_KILLFOCUS, sent },
3163 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3164 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3165 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3166 { WM_SETFOCUS, sent }, /* in MDI client */
3168 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
3169 { WM_KILLFOCUS, sent }, /* in MDI client */
3170 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3171 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3172 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3173 { WM_SETFOCUS, sent }, /* in MDI client */
3175 { WM_DESTROY, sent },
3177 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
3178 { WM_KILLFOCUS, sent },
3179 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3180 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3181 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3182 { WM_SETFOCUS, sent }, /* in MDI client */
3184 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
3185 { WM_KILLFOCUS, sent }, /* in MDI client */
3186 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3187 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3188 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3189 { WM_SETFOCUS, sent }, /* in MDI client */
3191 { WM_NCDESTROY, sent },
3192 { 0 }
3194 /* CreateWindow for MDI child window, initially invisible */
3195 static const struct message WmCreateMDIchildInvisibleSeq[] = {
3196 { HCBT_CREATEWND, hook },
3197 { WM_NCCREATE, sent },
3198 { WM_NCCALCSIZE, sent|wparam, 0 },
3199 { WM_CREATE, sent },
3200 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3201 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3202 { WM_MOVE, sent },
3203 /* Win2k sends wparam set to
3204 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3205 * while Win9x doesn't bother to set child window id according to
3206 * CLIENTCREATESTRUCT.idFirstChild
3208 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3209 { 0 }
3211 /* DestroyWindow for MDI child window, initially invisible */
3212 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
3213 { HCBT_DESTROYWND, hook },
3214 /* Win2k sends wparam set to
3215 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3216 * while Win9x doesn't bother to set child window id according to
3217 * CLIENTCREATESTRUCT.idFirstChild
3219 { 0x0090, sent|optional },
3220 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3221 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3222 { WM_DESTROY, sent },
3223 { WM_NCDESTROY, sent },
3224 /* FIXME: Wine destroys an icon/title window while Windows doesn't */
3225 { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
3226 { 0 }
3228 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
3229 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
3230 { HCBT_CREATEWND, hook },
3231 { WM_NCCREATE, sent },
3232 { WM_NCCALCSIZE, sent|wparam, 0 },
3233 { WM_CREATE, sent },
3234 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3235 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3236 { WM_MOVE, sent },
3237 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3238 { WM_GETMINMAXINFO, sent },
3239 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3240 { WM_NCCALCSIZE, sent|wparam, 1 },
3241 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3242 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3243 /* in MDI frame */
3244 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3245 { WM_NCCALCSIZE, sent|wparam, 1 },
3246 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3247 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3248 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3249 /* Win2k sends wparam set to
3250 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3251 * while Win9x doesn't bother to set child window id according to
3252 * CLIENTCREATESTRUCT.idFirstChild
3254 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3255 { WM_SHOWWINDOW, sent|wparam, 1 },
3256 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3257 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3258 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3259 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
3260 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3261 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3262 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_FRAMECHANGED },
3264 /* Win9x: message sequence terminates here. */
3266 { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
3267 { HCBT_SETFOCUS, hook|optional }, /* in MDI client */
3268 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3269 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
3270 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3271 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3272 { HCBT_SETFOCUS, hook|optional },
3273 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3274 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3275 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3276 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3277 { WM_SETFOCUS, sent|defwinproc|optional },
3278 { WM_MDIACTIVATE, sent|defwinproc|optional },
3279 /* in MDI frame */
3280 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3281 { WM_NCCALCSIZE, sent|wparam, 1 },
3282 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3283 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3284 { 0 }
3286 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
3287 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
3288 /* restore the 1st MDI child */
3289 { WM_SETREDRAW, sent|wparam, 0 },
3290 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
3291 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3292 { WM_NCCALCSIZE, sent|wparam, 1 },
3293 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3294 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3295 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3296 /* in MDI frame */
3297 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3298 { WM_NCCALCSIZE, sent|wparam, 1 },
3299 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3300 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3301 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3302 { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
3303 /* create the 2nd MDI child */
3304 { HCBT_CREATEWND, hook },
3305 { WM_NCCREATE, sent },
3306 { WM_NCCALCSIZE, sent|wparam, 0 },
3307 { WM_CREATE, sent },
3308 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3309 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3310 { WM_MOVE, sent },
3311 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3312 { WM_GETMINMAXINFO, sent },
3313 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3314 { WM_NCCALCSIZE, sent|wparam, 1 },
3315 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
3316 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3317 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3318 /* in MDI frame */
3319 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3320 { WM_NCCALCSIZE, sent|wparam, 1 },
3321 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3322 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3323 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3324 /* Win2k sends wparam set to
3325 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3326 * while Win9x doesn't bother to set child window id according to
3327 * CLIENTCREATESTRUCT.idFirstChild
3329 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3330 { WM_SHOWWINDOW, sent|wparam, 1 },
3331 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3332 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3333 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3334 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
3335 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3336 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3338 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
3339 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
3341 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3343 /* Win9x: message sequence terminates here. */
3345 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3346 { HCBT_SETFOCUS, hook },
3347 { WM_KILLFOCUS, sent|defwinproc|optional }, /* in the 1st MDI child */
3348 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
3349 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3350 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3351 { WM_SETFOCUS, sent }, /* in MDI client */
3352 { HCBT_SETFOCUS, hook },
3353 { WM_KILLFOCUS, sent }, /* in MDI client */
3354 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3355 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3356 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3357 { WM_SETFOCUS, sent|defwinproc },
3359 { WM_MDIACTIVATE, sent|defwinproc },
3360 /* in MDI frame */
3361 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3362 { WM_NCCALCSIZE, sent|wparam, 1 },
3363 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3364 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3365 { 0 }
3367 /* WM_MDICREATE MDI child window, initially visible and maximized */
3368 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
3369 { WM_MDICREATE, sent },
3370 { HCBT_CREATEWND, hook },
3371 { WM_NCCREATE, sent },
3372 { WM_NCCALCSIZE, sent|wparam, 0 },
3373 { WM_CREATE, sent },
3374 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3375 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3376 { WM_MOVE, sent },
3377 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3378 { WM_GETMINMAXINFO, sent },
3379 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3380 { WM_NCCALCSIZE, sent|wparam, 1 },
3381 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3382 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3384 /* in MDI frame */
3385 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3386 { WM_NCCALCSIZE, sent|wparam, 1 },
3387 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3388 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3389 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3391 /* Win2k sends wparam set to
3392 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3393 * while Win9x doesn't bother to set child window id according to
3394 * CLIENTCREATESTRUCT.idFirstChild
3396 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3397 { WM_SHOWWINDOW, sent|wparam, 1 },
3398 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3400 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3402 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3403 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
3404 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3406 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3407 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3409 /* Win9x: message sequence terminates here. */
3411 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3412 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3413 { HCBT_SETFOCUS, hook }, /* in MDI client */
3414 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3415 { WM_IME_NOTIFY, sent|wparam|optional, 2 },
3416 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
3417 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3418 { HCBT_SETFOCUS, hook|optional },
3419 { WM_KILLFOCUS, sent }, /* in MDI client */
3420 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3421 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3422 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3423 { WM_SETFOCUS, sent|defwinproc },
3425 { WM_MDIACTIVATE, sent|defwinproc },
3427 /* in MDI child */
3428 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3429 { WM_NCCALCSIZE, sent|wparam, 1 },
3430 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3431 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3433 /* in MDI frame */
3434 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3435 { WM_NCCALCSIZE, sent|wparam, 1 },
3436 { 0x0093, sent|defwinproc|optional },
3437 { 0x0093, sent|defwinproc|optional },
3438 { 0x0093, sent|defwinproc|optional },
3439 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3440 { WM_MOVE, sent|defwinproc },
3441 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3443 /* in MDI client */
3444 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3445 { WM_NCCALCSIZE, sent|wparam, 1 },
3446 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3447 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3449 /* in MDI child */
3450 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3451 { WM_NCCALCSIZE, sent|wparam, 1 },
3452 { 0x0093, sent|optional },
3453 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3454 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3456 { 0x0093, sent|optional },
3457 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3458 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client, not sent on Win7. */
3459 { 0x0093, sent|optional }, /* Win8+ sends an extra. */
3460 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
3461 { 0x0093, sent|defwinproc|optional },
3462 { 0x0093, sent|defwinproc|optional },
3463 { 0x0093, sent|defwinproc|optional },
3464 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3465 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
3467 { 0 }
3469 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
3470 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
3471 { HCBT_CREATEWND, hook },
3472 { WM_GETMINMAXINFO, sent },
3473 { WM_NCCREATE, sent },
3474 { WM_NCCALCSIZE, sent|wparam, 0 },
3475 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win8+. */
3476 { WM_CREATE, sent },
3477 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3478 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3479 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOZORDER }, /* MDI frame */
3480 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI frame */
3481 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOZORDER }, /* MDI frame */
3482 { WM_MOVE, sent },
3483 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3484 { WM_GETMINMAXINFO, sent },
3485 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3486 { WM_GETMINMAXINFO, sent|defwinproc },
3487 { WM_NCCALCSIZE, sent|wparam, 1 },
3488 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_STATECHANGED },
3489 { WM_MOVE, sent|defwinproc },
3490 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3491 /* in MDI frame */
3492 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3493 { WM_NCCALCSIZE, sent|wparam, 1 },
3494 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3495 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3496 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
3497 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3498 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3499 /* Win2k sends wparam set to
3500 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3501 * while Win9x doesn't bother to set child window id according to
3502 * CLIENTCREATESTRUCT.idFirstChild
3504 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3505 { 0 }
3507 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
3508 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
3509 { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
3510 { HCBT_SYSCOMMAND, hook },
3511 { WM_CLOSE, sent|defwinproc },
3512 { WM_MDIDESTROY, sent }, /* in MDI client */
3514 /* bring the 1st MDI child to top */
3515 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
3516 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
3518 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
3520 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
3521 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
3522 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
3524 /* maximize the 1st MDI child */
3525 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3526 { WM_GETMINMAXINFO, sent|defwinproc },
3527 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED },
3528 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
3529 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
3530 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3531 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3533 /* restore the 2nd MDI child */
3534 { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
3535 { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
3536 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
3537 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
3539 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3541 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3542 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3544 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3546 { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
3547 /* in MDI frame */
3548 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3549 { WM_NCCALCSIZE, sent|wparam, 1 },
3550 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3551 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3552 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3554 /* bring the 1st MDI child to top */
3555 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3556 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3557 { HCBT_SETFOCUS, hook },
3558 { WM_KILLFOCUS, sent|defwinproc },
3559 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
3560 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3561 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3562 { WM_SETFOCUS, sent }, /* in MDI client */
3563 { HCBT_SETFOCUS, hook },
3564 { WM_KILLFOCUS, sent }, /* in MDI client */
3565 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3566 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3567 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3568 { WM_SETFOCUS, sent|defwinproc },
3569 { WM_MDIACTIVATE, sent|defwinproc },
3570 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3572 /* apparently ShowWindow(SW_SHOW) on an MDI client */
3573 { WM_SHOWWINDOW, sent|wparam, 1 },
3574 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3575 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3576 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3577 { WM_MDIREFRESHMENU, sent },
3579 { HCBT_DESTROYWND, hook },
3580 /* Win2k sends wparam set to
3581 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3582 * while Win9x doesn't bother to set child window id according to
3583 * CLIENTCREATESTRUCT.idFirstChild
3585 { 0x0090, sent|defwinproc|optional },
3586 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3587 { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
3588 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3589 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3590 { WM_ERASEBKGND, sent|parent|optional },
3591 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3593 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3594 { WM_DESTROY, sent|defwinproc },
3595 { WM_NCDESTROY, sent|defwinproc },
3596 { 0 }
3598 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
3599 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
3600 { WM_MDIDESTROY, sent }, /* in MDI client */
3601 { WM_SHOWWINDOW, sent|wparam, 0 },
3602 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3603 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3604 { WM_ERASEBKGND, sent|parent|optional },
3605 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3607 { HCBT_SETFOCUS, hook },
3608 { WM_KILLFOCUS, sent },
3609 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3610 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3611 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3612 { WM_SETFOCUS, sent }, /* in MDI client */
3613 { HCBT_SETFOCUS, hook },
3614 { WM_KILLFOCUS, sent }, /* in MDI client */
3615 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3616 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3617 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3618 { WM_SETFOCUS, sent },
3620 /* in MDI child */
3621 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3622 { WM_NCCALCSIZE, sent|wparam, 1 },
3623 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3624 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3626 /* in MDI frame */
3627 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3628 { WM_NCCALCSIZE, sent|wparam, 1 },
3629 { 0x0093, sent|defwinproc|optional },
3630 { 0x0093, sent|defwinproc|optional },
3631 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3632 { WM_MOVE, sent|defwinproc },
3633 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3635 /* in MDI client */
3636 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3637 { WM_NCCALCSIZE, sent|wparam, 1 },
3638 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3639 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3641 /* in MDI child */
3642 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3643 { WM_NCCALCSIZE, sent|wparam, 1 },
3644 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3645 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3647 /* in MDI child */
3648 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3649 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3650 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3651 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3653 /* in MDI frame */
3654 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3655 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3656 { 0x0093, sent|defwinproc|optional },
3657 { 0x0093, sent|defwinproc|optional },
3658 { 0x0093, sent|defwinproc|optional },
3659 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3660 { WM_MOVE, sent|defwinproc },
3661 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3663 /* in MDI client */
3664 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3665 { WM_NCCALCSIZE, sent|wparam, 1 },
3666 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3667 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3669 /* in MDI child */
3670 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3671 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3672 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3673 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3674 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3675 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI client */
3677 { 0x0093, sent|defwinproc|optional },
3678 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
3679 { 0x0093, sent|defwinproc|optional },
3680 { 0x0093, sent|defwinproc|optional },
3681 { 0x0093, sent|defwinproc|optional },
3682 { 0x0093, sent|optional },
3684 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3685 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3686 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI client */
3687 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame */
3688 { 0x0093, sent|optional }, /* Win8+ sends an extra. */
3689 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
3691 /* in MDI frame */
3692 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3693 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3694 { 0x0093, sent|defwinproc|optional },
3695 { 0x0093, sent|defwinproc|optional },
3696 { 0x0093, sent|defwinproc|optional },
3697 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3698 { 0x0093, sent|optional }, /* Win8+ sends an extra. */
3699 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3700 { 0x0093, sent|optional },
3702 { WM_NCACTIVATE, sent|wparam, 0 },
3703 { WM_MDIACTIVATE, sent },
3705 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
3706 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
3707 { WM_NCCALCSIZE, sent|wparam, 1 },
3709 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3711 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3712 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3713 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3715 /* in MDI child */
3716 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3717 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3718 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3719 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3721 /* in MDI frame */
3722 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3723 { WM_NCCALCSIZE, sent|wparam, 1 },
3724 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3725 { WM_MOVE, sent|defwinproc },
3726 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3728 /* in MDI client */
3729 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3730 { WM_NCCALCSIZE, sent|wparam, 1 },
3731 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3732 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3733 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3734 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
3735 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI client */
3736 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3737 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
3739 { HCBT_SETFOCUS, hook },
3740 { WM_KILLFOCUS, sent },
3741 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3742 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3743 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3744 { WM_SETFOCUS, sent }, /* in MDI client */
3746 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
3748 { HCBT_DESTROYWND, hook },
3749 /* Win2k sends wparam set to
3750 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3751 * while Win9x doesn't bother to set child window id according to
3752 * CLIENTCREATESTRUCT.idFirstChild
3754 { 0x0090, sent|optional },
3755 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3757 { WM_SHOWWINDOW, sent|wparam, 0 },
3758 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3759 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3760 { WM_ERASEBKGND, sent|parent|optional },
3761 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3763 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3764 { WM_DESTROY, sent },
3765 { WM_NCDESTROY, sent },
3766 { 0 }
3768 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
3769 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
3770 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3771 { WM_GETMINMAXINFO, sent },
3772 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3773 { WM_NCCALCSIZE, sent|wparam, 1 },
3774 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3775 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3777 { WM_WINDOWPOSCHANGING, sent|wparam|optional|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3778 { WM_NCACTIVATE, sent|wparam|optional|defwinproc, 1 },
3779 { HCBT_SETFOCUS, hook|optional },
3780 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3781 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
3782 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3783 { HCBT_SETFOCUS, hook|optional },
3784 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3785 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3786 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3787 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3788 { WM_SETFOCUS, sent|optional|defwinproc },
3789 { WM_MDIACTIVATE, sent|optional|defwinproc },
3790 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3791 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3792 /* in MDI frame */
3793 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3794 { WM_NCCALCSIZE, sent|wparam, 1 },
3795 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3796 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3797 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3798 { 0 }
3800 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
3801 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
3802 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3803 { WM_GETMINMAXINFO, sent },
3804 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED, 0, SWP_STATECHANGED /* w1064v1809 */ },
3805 { WM_GETMINMAXINFO, sent|defwinproc },
3806 { WM_NCCALCSIZE, sent|wparam, 1 },
3807 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3808 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3810 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3811 { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
3812 { HCBT_SETFOCUS, hook|optional },
3813 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3814 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
3815 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3816 { HCBT_SETFOCUS, hook|optional },
3817 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3818 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3819 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3820 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3821 { WM_SETFOCUS, sent|defwinproc|optional },
3822 { WM_MDIACTIVATE, sent|defwinproc|optional },
3823 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_STATECHANGED /* w1064v1809 */ },
3824 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child, not sent on Win8+. */
3825 { WM_SIZE, sent|defwinproc|optional },
3826 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* w1064v1809. */
3827 { 0 }
3829 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
3830 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
3831 { WM_MDIMAXIMIZE, sent }, /* in MDI client */
3832 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3833 { WM_GETMINMAXINFO, sent },
3834 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3835 { WM_GETMINMAXINFO, sent|defwinproc },
3836 { WM_NCCALCSIZE, sent|wparam, 1 },
3837 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
3838 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3839 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
3840 { WM_MOVE, sent|defwinproc },
3841 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3843 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3844 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3845 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3846 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3847 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3848 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3849 /* in MDI frame */
3850 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3851 { WM_NCCALCSIZE, sent|wparam, 1 },
3852 { 0x0093, sent|defwinproc|optional },
3853 { 0x0094, sent|defwinproc|optional },
3854 { 0x0094, sent|defwinproc|optional },
3855 { 0x0094, sent|defwinproc|optional },
3856 { 0x0094, sent|defwinproc|optional },
3857 { 0x0093, sent|defwinproc|optional },
3858 { 0x0093, sent|defwinproc|optional },
3859 { 0x0091, sent|defwinproc|optional },
3860 { 0x0092, sent|defwinproc|optional },
3861 { 0x0092, sent|defwinproc|optional },
3862 { 0x0092, sent|defwinproc|optional },
3863 { 0x0092, sent|defwinproc|optional },
3864 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3865 { WM_MOVE, sent|defwinproc },
3866 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3867 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
3868 /* in MDI client */
3869 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3870 { WM_NCCALCSIZE, sent|wparam, 1 },
3871 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3872 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3873 /* in MDI child */
3874 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3875 { WM_GETMINMAXINFO, sent|defwinproc },
3876 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3877 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3878 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3879 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
3880 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3881 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3882 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3883 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3884 /* in MDI frame */
3885 { 0x0093, sent|optional },
3886 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3887 { 0x0093, sent|defwinproc|optional },
3888 { 0x0093, sent|defwinproc|optional },
3889 { 0x0093, sent|defwinproc|optional },
3890 { 0x0091, sent|defwinproc|optional },
3891 { 0x0092, sent|defwinproc|optional },
3892 { 0x0092, sent|defwinproc|optional },
3893 { 0x0092, sent|defwinproc|optional },
3894 { 0x0092, sent|defwinproc|optional },
3895 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3896 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3897 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3898 { 0 }
3900 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
3901 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
3902 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3903 { WM_GETMINMAXINFO, sent },
3904 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3905 { WM_NCCALCSIZE, sent|wparam, 1 },
3906 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3907 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3908 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3909 /* in MDI frame */
3910 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3911 { WM_NCCALCSIZE, sent|wparam, 1 },
3912 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3913 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3914 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3915 { 0 }
3917 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
3918 static const struct message WmRestoreMDIchildVisibleSeq[] = {
3919 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3920 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3921 { WM_NCCALCSIZE, sent|wparam, 1 },
3922 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3923 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3924 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3925 /* in MDI frame */
3926 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3927 { WM_NCCALCSIZE, sent|wparam, 1 },
3928 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3929 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3930 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3931 { 0 }
3933 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
3934 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
3935 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3936 { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
3937 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3938 { WM_NCCALCSIZE, sent|wparam, 1 },
3939 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3940 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3941 { WM_MOVE, sent|defwinproc },
3942 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3943 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3944 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3945 { HCBT_SETFOCUS, hook },
3946 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3947 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
3948 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
3949 { WM_SETFOCUS, sent },
3950 { 0 }
3952 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
3953 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
3954 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
3955 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3956 { WM_NCCALCSIZE, sent|wparam, 1 },
3957 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3958 { WM_MOVE, sent|defwinproc },
3959 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
3960 { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
3961 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3962 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3963 /* FIXME: Wine creates an icon/title window while Windows doesn't */
3964 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
3965 { 0 }
3967 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
3968 static const struct message WmRestoreMDIchildInvisibleSeq[] = {
3969 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3970 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3971 { WM_NCCALCSIZE, sent|wparam, 1 },
3972 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3973 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3974 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3975 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3976 /* in MDI frame */
3977 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3978 { WM_NCCALCSIZE, sent|wparam, 1 },
3979 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3980 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3981 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3982 { 0 }
3985 static HWND mdi_client;
3986 static WNDPROC old_mdi_client_proc;
3988 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3990 struct recvd_message msg;
3992 /* do not log painting messages */
3993 if (message != WM_PAINT &&
3994 message != WM_NCPAINT &&
3995 message != WM_SYNCPAINT &&
3996 message != WM_ERASEBKGND &&
3997 message != WM_NCHITTEST &&
3998 message != WM_GETTEXT &&
3999 message != WM_MDIGETACTIVE &&
4000 !ignore_message( message ))
4002 msg.hwnd = hwnd;
4003 msg.message = message;
4004 msg.flags = sent|wparam|lparam;
4005 msg.wParam = wParam;
4006 msg.lParam = lParam;
4007 msg.descr = "mdi client";
4008 add_message(&msg);
4011 return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
4014 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4016 static LONG defwndproc_counter = 0;
4017 LRESULT ret;
4018 struct recvd_message msg;
4020 /* do not log painting messages */
4021 if (message != WM_PAINT &&
4022 message != WM_NCPAINT &&
4023 message != WM_SYNCPAINT &&
4024 message != WM_ERASEBKGND &&
4025 message != WM_NCHITTEST &&
4026 message != WM_GETTEXT &&
4027 !ignore_message( message ))
4029 switch (message)
4031 case WM_MDIACTIVATE:
4033 HWND active, client = GetParent(hwnd);
4035 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
4037 if (hwnd == (HWND)lParam) /* if we are being activated */
4038 ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
4039 else
4040 ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
4041 break;
4045 msg.hwnd = hwnd;
4046 msg.message = message;
4047 msg.flags = sent|wparam|lparam;
4048 if (defwndproc_counter) msg.flags |= defwinproc;
4049 msg.wParam = wParam;
4050 msg.lParam = lParam;
4051 msg.descr = "mdi child";
4052 add_message(&msg);
4055 defwndproc_counter++;
4056 ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
4057 defwndproc_counter--;
4059 return ret;
4062 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4064 static LONG defwndproc_counter = 0;
4065 LRESULT ret;
4066 struct recvd_message msg;
4068 /* do not log painting messages */
4069 if (message != WM_PAINT &&
4070 message != WM_NCPAINT &&
4071 message != WM_SYNCPAINT &&
4072 message != WM_ERASEBKGND &&
4073 message != WM_NCHITTEST &&
4074 message != WM_GETTEXT &&
4075 !ignore_message( message ))
4077 msg.hwnd = hwnd;
4078 msg.message = message;
4079 msg.flags = sent|wparam|lparam;
4080 if (defwndproc_counter) msg.flags |= defwinproc;
4081 msg.wParam = wParam;
4082 msg.lParam = lParam;
4083 msg.descr = "mdi frame";
4084 add_message(&msg);
4087 defwndproc_counter++;
4088 ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
4089 defwndproc_counter--;
4091 return ret;
4094 static BOOL mdi_RegisterWindowClasses(void)
4096 WNDCLASSA cls;
4098 cls.style = 0;
4099 cls.lpfnWndProc = mdi_frame_wnd_proc;
4100 cls.cbClsExtra = 0;
4101 cls.cbWndExtra = 0;
4102 cls.hInstance = GetModuleHandleA(0);
4103 cls.hIcon = 0;
4104 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
4105 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
4106 cls.lpszMenuName = NULL;
4107 cls.lpszClassName = "MDI_frame_class";
4108 if (!RegisterClassA(&cls)) return FALSE;
4110 cls.lpfnWndProc = mdi_child_wnd_proc;
4111 cls.lpszClassName = "MDI_child_class";
4112 if (!RegisterClassA(&cls)) return FALSE;
4114 if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
4115 old_mdi_client_proc = cls.lpfnWndProc;
4116 cls.hInstance = GetModuleHandleA(0);
4117 cls.lpfnWndProc = mdi_client_hook_proc;
4118 cls.lpszClassName = "MDI_client_class";
4119 if (!RegisterClassA(&cls)) assert(0);
4121 return TRUE;
4124 static void test_mdi_messages(void)
4126 MDICREATESTRUCTA mdi_cs;
4127 CLIENTCREATESTRUCT client_cs;
4128 HWND mdi_frame, mdi_child, mdi_child2, active_child;
4129 BOOL zoomed;
4130 RECT rc;
4131 HMENU hMenu = CreateMenu();
4132 LONG val;
4134 if (!mdi_RegisterWindowClasses()) assert(0);
4136 flush_sequence();
4138 trace("creating MDI frame window\n");
4139 mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
4140 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
4141 WS_MAXIMIZEBOX | WS_VISIBLE,
4142 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
4143 GetDesktopWindow(), hMenu,
4144 GetModuleHandleA(0), NULL);
4145 assert(mdi_frame);
4146 ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
4148 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4149 ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
4151 trace("creating MDI client window\n");
4152 GetClientRect(mdi_frame, &rc);
4153 client_cs.hWindowMenu = 0;
4154 client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
4155 mdi_client = CreateWindowExA(0, "MDI_client_class",
4156 NULL,
4157 WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
4158 rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
4159 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
4160 assert(mdi_client);
4161 SetWindowLongA(mdi_client, 0, 0xdeadbeef);
4163 ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
4164 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4165 ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
4167 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4168 ok(!active_child, "wrong active MDI child %p\n", active_child);
4169 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4171 SetFocus(0);
4172 flush_sequence();
4174 trace("creating invisible MDI child window\n");
4175 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4176 WS_CHILD,
4177 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4178 mdi_client, 0, GetModuleHandleA(0), NULL);
4179 assert(mdi_child);
4181 flush_sequence();
4182 ShowWindow(mdi_child, SW_SHOWNORMAL);
4183 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
4185 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4186 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
4188 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4189 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4191 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4192 ok(!active_child, "wrong active MDI child %p\n", active_child);
4193 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4195 ShowWindow(mdi_child, SW_HIDE);
4196 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
4197 flush_sequence();
4199 ShowWindow(mdi_child, SW_SHOW);
4200 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
4202 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4203 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
4205 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4206 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4208 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4209 ok(!active_child, "wrong active MDI child %p\n", active_child);
4210 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4212 DestroyWindow(mdi_child);
4213 flush_sequence();
4215 trace("creating visible MDI child window\n");
4216 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4217 WS_CHILD | WS_VISIBLE,
4218 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4219 mdi_client, 0, GetModuleHandleA(0), NULL);
4220 assert(mdi_child);
4221 ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
4223 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4224 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
4226 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4227 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4229 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4230 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4231 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4232 flush_sequence();
4234 DestroyWindow(mdi_child);
4235 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4237 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4238 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4240 /* Win2k: MDI client still returns a just destroyed child as active
4241 * Win9x: MDI client returns 0
4243 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4244 ok(active_child == mdi_child || /* win2k */
4245 !active_child, /* win9x */
4246 "wrong active MDI child %p\n", active_child);
4247 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4249 flush_sequence();
4251 trace("creating invisible MDI child window\n");
4252 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4253 WS_CHILD,
4254 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4255 mdi_client, 0, GetModuleHandleA(0), NULL);
4256 assert(mdi_child2);
4257 ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
4259 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
4260 ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
4262 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4263 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4265 /* Win2k: MDI client still returns a just destroyed child as active
4266 * Win9x: MDI client returns mdi_child2
4268 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4269 ok(active_child == mdi_child || /* win2k */
4270 active_child == mdi_child2, /* win9x */
4271 "wrong active MDI child %p\n", active_child);
4272 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4273 flush_sequence();
4275 ShowWindow(mdi_child2, SW_MAXIMIZE);
4276 ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
4278 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4279 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
4281 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4282 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4283 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4284 flush_sequence();
4286 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4287 ok(GetFocus() == mdi_child2 || /* win2k */
4288 GetFocus() == 0, /* win9x */
4289 "wrong focus window %p\n", GetFocus());
4291 SetFocus(0);
4292 flush_sequence();
4294 ShowWindow(mdi_child2, SW_HIDE);
4295 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
4297 ShowWindow(mdi_child2, SW_RESTORE);
4298 ok_sequence(WmRestoreMDIchildInvisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
4299 flush_sequence();
4301 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4302 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
4304 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4305 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4306 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4307 flush_sequence();
4309 SetFocus(0);
4310 flush_sequence();
4312 ShowWindow(mdi_child2, SW_HIDE);
4313 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
4315 ShowWindow(mdi_child2, SW_SHOW);
4316 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
4318 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4319 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4321 ShowWindow(mdi_child2, SW_MAXIMIZE);
4322 ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
4324 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4325 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4327 ShowWindow(mdi_child2, SW_RESTORE);
4328 ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
4330 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4331 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4333 ShowWindow(mdi_child2, SW_MINIMIZE);
4334 ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", FALSE);
4336 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4337 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4339 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4340 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4341 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4342 flush_sequence();
4344 ShowWindow(mdi_child2, SW_RESTORE);
4345 ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", FALSE);
4347 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4348 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
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 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4362 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4364 DestroyWindow(mdi_child2);
4365 ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
4367 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4368 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4370 trace("Testing WM_CHILDACTIVATE\n");
4372 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4373 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_DISABLED,
4374 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4375 mdi_client, 0, GetModuleHandleA(0), NULL);
4377 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4378 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX,
4379 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4380 mdi_client, 0, GetModuleHandleA(0), NULL);
4382 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4383 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4384 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4386 flush_sequence();
4387 SendMessageW(mdi_child, WM_CHILDACTIVATE, 0, 0);
4388 ok_sequence(WmChildActivateDisabledWindowSeq, "WM_CHILDACTIVATE sent to disabled window", FALSE);
4390 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4391 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4392 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4393 flush_sequence();
4395 EnableWindow(mdi_child, TRUE);
4397 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4398 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4399 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4401 flush_sequence();
4402 SendMessageW(mdi_child, WM_CHILDACTIVATE, 0, 0);
4403 ok_sequence(WmChildActivateWindowSeq, "WM_CHILDACTIVATE sent to enabled window", FALSE);
4405 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4406 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4407 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4408 flush_sequence();
4410 DestroyWindow(mdi_child);
4411 DestroyWindow(mdi_child2);
4412 flush_sequence();
4414 /* test for maximized MDI children */
4415 trace("creating maximized visible MDI child window 1\n");
4416 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4417 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4418 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4419 mdi_client, 0, GetModuleHandleA(0), NULL);
4420 assert(mdi_child);
4421 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
4422 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4424 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4425 ok(GetFocus() == mdi_child || /* win2k */
4426 GetFocus() == 0, /* win9x */
4427 "wrong focus window %p\n", GetFocus());
4429 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4430 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4431 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4432 flush_sequence();
4434 trace("creating maximized visible MDI child window 2\n");
4435 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4436 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4437 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4438 mdi_client, 0, GetModuleHandleA(0), NULL);
4439 assert(mdi_child2);
4440 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
4441 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
4442 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4444 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4445 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4447 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4448 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4449 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4450 flush_sequence();
4452 trace("destroying maximized visible MDI child window 2\n");
4453 DestroyWindow(mdi_child2);
4454 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4456 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4458 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4459 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4461 /* Win2k: MDI client still returns a just destroyed child as active
4462 * Win9x: MDI client returns 0
4464 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4465 ok(active_child == mdi_child2 || /* win2k */
4466 !active_child, /* win9x */
4467 "wrong active MDI child %p\n", active_child);
4468 flush_sequence();
4470 ShowWindow(mdi_child, SW_MAXIMIZE);
4471 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4472 flush_sequence();
4474 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4475 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4477 trace("re-creating maximized visible MDI child window 2\n");
4478 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4479 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4480 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4481 mdi_client, 0, GetModuleHandleA(0), NULL);
4482 assert(mdi_child2);
4483 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
4484 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
4485 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4487 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4488 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4490 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4491 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4492 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4493 flush_sequence();
4495 SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
4496 ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
4497 ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
4499 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4500 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4501 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4503 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4504 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4505 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4506 flush_sequence();
4508 DestroyWindow(mdi_child);
4509 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4511 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4512 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4514 /* Win2k: MDI client still returns a just destroyed child as active
4515 * Win9x: MDI client returns 0
4517 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4518 ok(active_child == mdi_child || /* win2k */
4519 !active_child, /* win9x */
4520 "wrong active MDI child %p\n", active_child);
4521 flush_sequence();
4523 trace("creating maximized invisible MDI child window\n");
4524 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4525 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
4526 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4527 mdi_client, 0, GetModuleHandleA(0), NULL);
4528 assert(mdi_child2);
4529 ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE);
4530 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
4531 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
4532 ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
4534 /* Win2k: MDI client still returns a just destroyed child as active
4535 * Win9x: MDI client returns 0
4537 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4538 ok(active_child == mdi_child || /* win2k */
4539 !active_child || active_child == mdi_child2, /* win9x */
4540 "wrong active MDI child %p\n", active_child);
4541 flush_sequence();
4543 trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
4544 ShowWindow(mdi_child2, SW_MAXIMIZE);
4545 ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
4546 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
4547 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4548 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
4550 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4551 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4552 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4553 flush_sequence();
4555 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
4556 flush_sequence();
4558 /* end of test for maximized MDI children */
4559 SetFocus(0);
4560 flush_sequence();
4561 trace("creating maximized visible MDI child window 1(Switch test)\n");
4562 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4563 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4564 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4565 mdi_client, 0, GetModuleHandleA(0), NULL);
4566 assert(mdi_child);
4567 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
4568 ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
4570 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
4571 ok(GetFocus() == mdi_child || /* win2k */
4572 GetFocus() == 0, /* win9x */
4573 "wrong focus window %p(Switch test)\n", GetFocus());
4575 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4576 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
4577 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
4578 flush_sequence();
4580 trace("creating maximized visible MDI child window 2(Switch test)\n");
4581 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4582 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4583 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4584 mdi_client, 0, GetModuleHandleA(0), NULL);
4585 assert(mdi_child2);
4586 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
4588 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
4589 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
4591 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
4592 ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
4594 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4595 ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
4596 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
4597 flush_sequence();
4599 trace("Switch child window.\n");
4600 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
4601 ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
4602 trace("end of test for switch maximized MDI children\n");
4603 flush_sequence();
4605 /* Prepare for switching test of not maximized MDI children */
4606 ShowWindow( mdi_child, SW_NORMAL );
4607 ok(!IsZoomed(mdi_child), "wrong zoomed state for %p(Switch test)\n", mdi_child);
4608 ok(!IsZoomed(mdi_child2), "wrong zoomed state for %p(Switch test)\n", mdi_child2);
4609 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
4610 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
4611 flush_sequence();
4613 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0);
4614 ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE);
4615 trace("end of test for switch not maximized MDI children\n");
4616 flush_sequence();
4618 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
4619 flush_sequence();
4621 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
4622 flush_sequence();
4624 SetFocus(0);
4625 flush_sequence();
4626 /* end of tests for switch maximized/not maximized MDI children */
4628 mdi_cs.szClass = "MDI_child_Class";
4629 mdi_cs.szTitle = "MDI child";
4630 mdi_cs.hOwner = GetModuleHandleA(0);
4631 mdi_cs.x = 0;
4632 mdi_cs.y = 0;
4633 mdi_cs.cx = CW_USEDEFAULT;
4634 mdi_cs.cy = CW_USEDEFAULT;
4635 mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
4636 mdi_cs.lParam = 0;
4637 mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
4638 ok(mdi_child != 0, "MDI child creation failed\n");
4639 ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
4641 ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
4643 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4644 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4646 ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
4647 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4648 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4650 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4651 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4652 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4653 flush_sequence();
4655 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
4656 ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
4658 ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
4659 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4660 ok(!active_child, "wrong active MDI child %p\n", active_child);
4662 SetFocus(0);
4663 flush_sequence();
4665 val = GetWindowLongA(mdi_client, 0);
4666 ok(val == 0xdeadbeef || broken(val == 0) /* >= Win Vista */, "Expected 0xdeadbeef, got 0x%lx\n", val);
4667 DestroyWindow(mdi_client);
4668 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
4670 /* test maximization of MDI child with invisible parent */
4671 client_cs.hWindowMenu = 0;
4672 mdi_client = CreateWindowA("MDI_client_class",
4673 NULL,
4674 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
4675 0, 0, 660, 430,
4676 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
4677 ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
4679 ShowWindow(mdi_client, SW_HIDE);
4680 ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
4682 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4683 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
4684 0, 0, 650, 440,
4685 mdi_client, 0, GetModuleHandleA(0), NULL);
4686 ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
4688 SendMessageA(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
4689 ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
4690 zoomed = IsZoomed(mdi_child);
4691 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4693 ShowWindow(mdi_client, SW_SHOW);
4694 ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
4696 DestroyWindow(mdi_child);
4697 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
4699 /* end of test for maximization of MDI child with invisible parent */
4701 DestroyWindow(mdi_client);
4702 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
4704 DestroyWindow(mdi_frame);
4705 ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
4707 /************************* End of MDI test **********************************/
4709 static void test_WM_SETREDRAW(HWND hwnd)
4711 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
4713 flush_events();
4714 flush_sequence();
4716 SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
4717 ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
4719 ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
4720 ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
4722 flush_sequence();
4723 SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
4724 ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
4726 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4727 ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
4729 /* restore original WS_VISIBLE state */
4730 SetWindowLongA(hwnd, GWL_STYLE, style);
4732 flush_events();
4733 flush_sequence();
4736 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4738 struct recvd_message msg;
4740 if (ignore_message( message )) return 0;
4742 switch (message)
4744 /* ignore */
4745 case WM_MOUSEMOVE:
4746 case WM_NCMOUSEMOVE:
4747 case WM_NCMOUSELEAVE:
4748 case WM_SETCURSOR:
4749 return 0;
4750 case WM_NCHITTEST:
4751 return HTCLIENT;
4754 msg.hwnd = hwnd;
4755 msg.message = message;
4756 msg.flags = sent|wparam|lparam;
4757 msg.wParam = wParam;
4758 msg.lParam = lParam;
4759 msg.descr = "dialog";
4760 add_message(&msg);
4762 if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
4763 if (message == WM_TIMER) EndDialog( hwnd, 0 );
4764 return 0;
4767 static INT_PTR CALLBACK TestModalDlgProc2(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4769 struct recvd_message msg;
4771 if (ignore_message( message )) return 0;
4773 switch (message)
4775 /* ignore */
4776 case WM_MOUSEMOVE:
4777 case WM_NCMOUSEMOVE:
4778 case WM_NCMOUSELEAVE:
4779 case WM_SETCURSOR:
4780 return 0;
4781 case WM_NCHITTEST:
4782 return HTCLIENT;
4785 msg.hwnd = hwnd;
4786 msg.message = message;
4787 msg.flags = sent|wparam|lparam;
4788 msg.wParam = wParam;
4789 msg.lParam = lParam;
4790 msg.descr = "dialog";
4791 add_message(&msg);
4793 if (message == WM_INITDIALOG) EndDialog( hwnd, 0 );
4794 return 0;
4797 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4799 DWORD style, exstyle;
4800 INT xmin, xmax;
4801 BOOL ret;
4803 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4804 style = GetWindowLongA(hwnd, GWL_STYLE);
4805 /* do not be confused by WS_DLGFRAME set */
4806 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4808 if (clear) ok(style & clear, "style %08lx should be set\n", clear);
4809 if (set) ok(!(style & set), "style %08lx should not be set\n", set);
4811 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4812 ok( ret, "SetScrollRange(%d) error %ld\n", ctl, GetLastError());
4813 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4814 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
4815 else
4816 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
4818 style = GetWindowLongA(hwnd, GWL_STYLE);
4819 if (set) ok(style & set, "style %08lx should be set\n", set);
4820 if (clear) ok(!(style & clear), "style %08lx should not be set\n", clear);
4822 /* a subsequent call should do nothing */
4823 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4824 ok( ret, "SetScrollRange(%d) error %ld\n", ctl, GetLastError());
4825 ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4827 xmin = 0xdeadbeef;
4828 xmax = 0xdeadbeef;
4829 ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
4830 ok( ret, "GetScrollRange(%d) error %ld\n", ctl, GetLastError());
4831 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4832 ok(xmin == min, "unexpected min scroll value %d\n", xmin);
4833 ok(xmax == max, "unexpected max scroll value %d\n", xmax);
4836 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4838 DWORD style, exstyle;
4839 SCROLLINFO si;
4840 BOOL ret;
4842 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4843 style = GetWindowLongA(hwnd, GWL_STYLE);
4844 /* do not be confused by WS_DLGFRAME set */
4845 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4847 if (clear) ok(style & clear, "style %08lx should be set\n", clear);
4848 if (set) ok(!(style & set), "style %08lx should not be set\n", set);
4850 si.cbSize = sizeof(si);
4851 si.fMask = SIF_RANGE;
4852 si.nMin = min;
4853 si.nMax = max;
4854 SetScrollInfo(hwnd, ctl, &si, TRUE);
4855 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4856 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
4857 else
4858 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
4860 style = GetWindowLongA(hwnd, GWL_STYLE);
4861 if (set) ok(style & set, "style %08lx should be set\n", set);
4862 if (clear) ok(!(style & clear), "style %08lx should not be set\n", clear);
4864 /* a subsequent call should do nothing */
4865 SetScrollInfo(hwnd, ctl, &si, TRUE);
4866 if (style & WS_HSCROLL)
4867 ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4868 else if (style & WS_VSCROLL)
4869 ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4870 else
4871 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4873 si.fMask = SIF_PAGE;
4874 si.nPage = 5;
4875 SetScrollInfo(hwnd, ctl, &si, FALSE);
4876 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4878 si.fMask = SIF_POS;
4879 si.nPos = max - 1;
4880 SetScrollInfo(hwnd, ctl, &si, FALSE);
4881 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4883 si.fMask = SIF_RANGE;
4884 si.nMin = 0xdeadbeef;
4885 si.nMax = 0xdeadbeef;
4886 ret = GetScrollInfo(hwnd, ctl, &si);
4887 ok( ret, "GetScrollInfo error %ld\n", GetLastError());
4888 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4889 ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
4890 ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
4893 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
4894 static void test_scroll_messages(HWND hwnd)
4896 SCROLLINFO si;
4897 INT min, max;
4898 BOOL ret;
4900 flush_events();
4901 flush_sequence();
4903 min = 0xdeadbeef;
4904 max = 0xdeadbeef;
4905 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4906 ok( ret, "GetScrollRange error %ld\n", GetLastError());
4907 if (sequence->message != WmGetScrollRangeSeq[0].message)
4908 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4909 /* values of min and max are undefined */
4910 flush_sequence();
4912 ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
4913 ok( ret, "SetScrollRange error %ld\n", GetLastError());
4914 if (sequence->message != WmSetScrollRangeSeq[0].message)
4915 trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4916 flush_sequence();
4918 min = 0xdeadbeef;
4919 max = 0xdeadbeef;
4920 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4921 ok( ret, "GetScrollRange error %ld\n", GetLastError());
4922 if (sequence->message != WmGetScrollRangeSeq[0].message)
4923 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4924 /* values of min and max are undefined */
4925 flush_sequence();
4927 si.cbSize = sizeof(si);
4928 si.fMask = SIF_RANGE;
4929 si.nMin = 20;
4930 si.nMax = 160;
4931 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4932 if (sequence->message != WmSetScrollRangeSeq[0].message)
4933 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4934 flush_sequence();
4936 si.fMask = SIF_PAGE;
4937 si.nPage = 10;
4938 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4939 if (sequence->message != WmSetScrollRangeSeq[0].message)
4940 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4941 flush_sequence();
4943 si.fMask = SIF_POS;
4944 si.nPos = 20;
4945 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4946 if (sequence->message != WmSetScrollRangeSeq[0].message)
4947 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4948 flush_sequence();
4950 si.fMask = SIF_RANGE;
4951 si.nMin = 0xdeadbeef;
4952 si.nMax = 0xdeadbeef;
4953 ret = GetScrollInfo(hwnd, SB_CTL, &si);
4954 ok( ret, "GetScrollInfo error %ld\n", GetLastError());
4955 if (sequence->message != WmGetScrollInfoSeq[0].message)
4956 trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4957 /* values of min and max are undefined */
4958 flush_sequence();
4960 /* set WS_HSCROLL */
4961 test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4962 /* clear WS_HSCROLL */
4963 test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4965 /* set WS_HSCROLL */
4966 test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4967 /* clear WS_HSCROLL */
4968 test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4970 /* set WS_VSCROLL */
4971 test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4972 /* clear WS_VSCROLL */
4973 test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4975 /* set WS_VSCROLL */
4976 test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4977 /* clear WS_VSCROLL */
4978 test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4981 static void test_showwindow(void)
4983 HWND hwnd, hwnd2, hchild;
4984 RECT rc;
4986 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4987 100, 100, 200, 200, 0, 0, 0, NULL);
4988 ok (hwnd != 0, "Failed to create overlapped window\n");
4989 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4990 0, 0, 10, 10, hwnd, 0, 0, NULL);
4991 ok (hchild != 0, "Failed to create child\n");
4992 flush_sequence();
4994 /* ShowWindow( SW_SHOWNA) for invisible top level window */
4995 trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
4996 ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4997 ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", FALSE);
4999 /* ShowWindow( SW_SHOWNA) for now visible top level window */
5000 trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
5001 ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
5002 ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
5003 /* back to invisible */
5004 ShowWindow(hchild, SW_HIDE);
5005 ShowWindow(hwnd, SW_HIDE);
5006 flush_sequence();
5007 /* ShowWindow(SW_SHOWNA) with child and parent invisible */
5008 trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
5009 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
5010 ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
5011 /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */
5012 ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
5013 flush_sequence();
5014 trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
5015 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
5016 ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
5017 /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
5018 ShowWindow( hwnd, SW_SHOW);
5019 flush_sequence();
5020 trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
5021 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
5022 ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
5024 /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
5025 ShowWindow( hchild, SW_HIDE);
5026 flush_sequence();
5027 trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
5028 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
5029 ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
5031 SetCapture(hchild);
5032 ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
5033 DestroyWindow(hchild);
5034 ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
5036 DestroyWindow(hwnd);
5037 flush_sequence();
5039 /* Popup windows */
5040 /* Test 1:
5041 * 1. Create invisible maximized popup window.
5042 * 2. Move and resize it.
5043 * 3. Show it maximized.
5045 trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
5046 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
5047 100, 100, 200, 200, 0, 0, 0, NULL);
5048 ok (hwnd != 0, "Failed to create popup window\n");
5049 ok(IsZoomed(hwnd), "window should be maximized\n");
5050 ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
5052 GetWindowRect(hwnd, &rc);
5053 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
5054 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
5055 "Invalid maximized size before ShowWindow %s\n", wine_dbgstr_rect( &rc ));
5056 /* Reset window's size & position */
5057 SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
5058 ok(IsZoomed(hwnd), "window should be maximized\n");
5059 flush_sequence();
5061 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
5062 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5063 ok(IsZoomed(hwnd), "window should be maximized\n");
5064 ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
5066 GetWindowRect(hwnd, &rc);
5067 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
5068 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
5069 "Invalid maximized size after ShowWindow %s\n", wine_dbgstr_rect( &rc ));
5070 DestroyWindow(hwnd);
5071 flush_sequence();
5073 /* Test 2:
5074 * 1. Create invisible maximized popup window.
5075 * 2. Show it maximized.
5077 trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
5078 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
5079 100, 100, 200, 200, 0, 0, 0, NULL);
5080 ok (hwnd != 0, "Failed to create popup window\n");
5081 ok(IsZoomed(hwnd), "window should be maximized\n");
5082 ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
5084 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
5085 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5086 ok(IsZoomed(hwnd), "window should be maximized\n");
5087 ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
5088 DestroyWindow(hwnd);
5089 flush_sequence();
5091 /* Test 3:
5092 * 1. Create visible maximized popup window.
5094 trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
5095 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
5096 100, 100, 200, 200, 0, 0, 0, NULL);
5097 ok (hwnd != 0, "Failed to create popup window\n");
5098 ok(IsZoomed(hwnd), "window should be maximized\n");
5099 ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
5100 DestroyWindow(hwnd);
5101 flush_sequence();
5103 /* Test 4:
5104 * 1. Create visible popup window.
5105 * 2. Maximize it.
5107 trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
5108 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
5109 100, 100, 200, 200, 0, 0, 0, NULL);
5110 ok (hwnd != 0, "Failed to create popup window\n");
5111 ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
5112 ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
5114 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
5115 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5116 ok(IsZoomed(hwnd), "window should be maximized\n");
5117 ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
5118 DestroyWindow(hwnd);
5119 flush_sequence();
5121 /* Test 5:
5122 * 1. Restoring a minimized window.
5124 hwnd = CreateWindowA("TestWindowClass", "window1", WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 0, 0, 0, 0);
5125 ok(hwnd != NULL, "Failed to create window\n");
5127 hwnd2 = CreateWindowA("static", "window2", WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 0, 0, 0, 0);
5128 ok(hwnd2 != NULL, "Failed to create window\n");
5130 ShowWindow(hwnd, SW_MINIMIZE);
5131 SetActiveWindow(hwnd2);
5132 ok(GetActiveWindow() == hwnd2, "Unexpected active window\n");
5133 flush_events();
5134 flush_sequence();
5135 ShowWindow(hwnd, SW_RESTORE);
5136 flush_events();
5137 ok_sequence(WmShowRestoreMinimizedOverlappedSeq,
5138 "ShowWindow(hwnd, SW_RESTORE): minimized overlapped", TRUE);
5140 ShowWindow(hwnd, SW_MINIMIZE);
5141 SetActiveWindow(hwnd2);
5142 ok(GetActiveWindow() == hwnd2, "Unexpected active window\n");
5143 flush_events();
5144 flush_sequence();
5145 ShowWindow(hwnd, SW_SHOWNOACTIVATE);
5146 flush_events();
5147 ok_sequence(WmShowNoActivateMinimizedOverlappedSeq,
5148 "ShowWindow(hwnd, SW_SHOWNOACTIVATE): minimized overlapped", TRUE);
5150 DestroyWindow(hwnd2);
5151 DestroyWindow(hwnd);
5152 flush_sequence();
5154 /* Test 6:
5155 * 1. Restoring a minimized but active window.
5157 hwnd = CreateWindowA("TestWindowClass", "parent", WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 0, 0, 0, 0);
5158 ok(hwnd != NULL, "Failed to create window\n");
5160 ShowWindow(hwnd, SW_MINIMIZE);
5161 SetActiveWindow(hwnd);
5162 ok(GetActiveWindow() == hwnd, "Unexpected active window\n");
5163 flush_events();
5164 flush_sequence();
5165 ShowWindow(hwnd, SW_RESTORE);
5166 flush_events();
5167 ok_sequence(WmShowRestoreActiveMinimizedOverlappedSeq,
5168 "ShowWindow(hwnd, SW_RESTORE): active minimized overlapped", TRUE);
5170 ShowWindow(hwnd, SW_MINIMIZE);
5171 SetActiveWindow(hwnd);
5172 ok(GetActiveWindow() == hwnd, "Unexpected active window\n");
5173 flush_events();
5174 flush_sequence();
5175 ShowWindow(hwnd, SW_SHOWNOACTIVATE);
5176 flush_events();
5177 ok_sequence(WmShowNoActivateActiveMinimizedOverlappedSeq,
5178 "ShowWindow(hwnd, SW_SHOWNOACTIVATE): active minimized overlapped", TRUE);
5180 DestroyWindow(hwnd);
5181 flush_sequence();
5184 static void test_sys_menu(void)
5186 HWND hwnd;
5187 HMENU hmenu;
5188 UINT state;
5190 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
5191 100, 100, 200, 200, 0, 0, 0, NULL);
5192 ok (hwnd != 0, "Failed to create overlapped window\n");
5194 flush_sequence();
5196 /* test existing window without CS_NOCLOSE style */
5197 hmenu = GetSystemMenu(hwnd, FALSE);
5198 ok(hmenu != 0, "GetSystemMenu error %ld\n", GetLastError());
5200 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
5201 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
5202 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
5204 EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
5205 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
5207 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
5208 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
5209 ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
5211 EnableMenuItem(hmenu, SC_CLOSE, 0);
5212 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
5214 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
5215 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
5216 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
5218 /* test whether removing WS_SYSMENU destroys a system menu */
5219 SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
5220 SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
5221 flush_sequence();
5222 hmenu = GetSystemMenu(hwnd, FALSE);
5223 ok(hmenu != 0, "GetSystemMenu error %ld\n", GetLastError());
5225 DestroyWindow(hwnd);
5227 /* test new window with CS_NOCLOSE style */
5228 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
5229 100, 100, 200, 200, 0, 0, 0, NULL);
5230 ok (hwnd != 0, "Failed to create overlapped window\n");
5232 hmenu = GetSystemMenu(hwnd, FALSE);
5233 ok(hmenu != 0, "GetSystemMenu error %ld\n", GetLastError());
5235 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
5236 ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
5238 DestroyWindow(hwnd);
5240 /* test new window without WS_SYSMENU style */
5241 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
5242 100, 100, 200, 200, 0, 0, 0, NULL);
5243 ok(hwnd != 0, "Failed to create overlapped window\n");
5245 hmenu = GetSystemMenu(hwnd, FALSE);
5246 ok(!hmenu, "GetSystemMenu error %ld\n", GetLastError());
5248 DestroyWindow(hwnd);
5251 /* For shown WS_OVERLAPPEDWINDOW */
5252 static const struct message WmSetIcon_1[] = {
5253 { WM_SETICON, sent },
5254 { 0x00AE, sent|defwinproc|optional }, /* XP */
5255 { WM_GETTEXT, sent|defwinproc|optional },
5256 { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
5257 { 0 }
5260 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
5261 static const struct message WmSetIcon_2[] = {
5262 { WM_SETICON, sent },
5263 { 0 }
5266 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
5267 static const struct message WmInitEndSession[] = {
5268 { 0x003B, sent },
5269 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
5270 { 0 }
5273 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
5274 static const struct message WmInitEndSession_2[] = {
5275 { 0x003B, sent },
5276 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
5277 { 0 }
5280 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
5281 static const struct message WmInitEndSession_3[] = {
5282 { 0x003B, sent },
5283 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
5284 { 0 }
5287 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
5288 static const struct message WmInitEndSession_4[] = {
5289 { 0x003B, sent },
5290 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
5291 { 0 }
5294 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
5295 static const struct message WmInitEndSession_5[] = {
5296 { 0x003B, sent },
5297 { WM_ENDSESSION, sent|defwinproc/*|wparam*/|lparam, 1, ENDSESSION_LOGOFF },
5298 { 0 }
5301 static const struct message WmOptionalPaint[] = {
5302 { WM_PAINT, sent|optional },
5303 { WM_NCPAINT, sent|beginpaint|optional },
5304 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5305 { WM_ERASEBKGND, sent|beginpaint|optional },
5306 { 0 }
5309 static const struct message WmZOrder[] = {
5310 { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 },
5311 { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 },
5312 { HCBT_ACTIVATE, hook },
5313 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
5314 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
5315 { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 },
5316 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 },
5317 { WM_GETTEXT, sent|optional },
5318 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
5319 { WM_ACTIVATEAPP, sent|wparam, 1, 0 },
5320 { WM_NCACTIVATE, sent|lparam, 1, 0 },
5321 { WM_GETTEXT, sent|defwinproc|optional },
5322 { WM_GETTEXT, sent|defwinproc|optional },
5323 { WM_ACTIVATE, sent|wparam|lparam, 1, 0 },
5324 { HCBT_SETFOCUS, hook },
5325 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5326 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5327 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5328 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
5329 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
5330 { WM_GETTEXT, sent|optional },
5331 { WM_NCCALCSIZE, sent|optional },
5332 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends it, but Win8+ doesn't. */
5333 { 0 }
5336 static void CALLBACK apc_test_proc(ULONG_PTR param)
5338 /* nothing */
5341 static void test_MsgWaitForMultipleObjects(HWND hwnd)
5343 DWORD ret;
5344 MSG msg;
5346 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5347 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %lx\n", ret);
5349 PostMessageA(hwnd, WM_USER, 0, 0);
5351 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5352 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %lx\n", ret);
5354 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5355 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5357 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5358 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %lx\n", ret);
5360 PostMessageA(hwnd, WM_USER, 0, 0);
5362 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5363 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %lx\n", ret);
5365 ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
5366 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5368 /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
5369 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5370 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %lx\n", ret);
5372 PostMessageA(hwnd, WM_USER, 0, 0);
5374 /* new incoming message causes it to become signaled again */
5375 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5376 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %lx\n", ret);
5378 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5379 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5380 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5381 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5383 /* MWMO_INPUTAVAILABLE should succeed even if the message was already seen */
5384 PostMessageA( hwnd, WM_USER, 0, 0 );
5385 ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
5386 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5388 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_INPUTAVAILABLE );
5389 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %lx\n", ret);
5391 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5392 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5394 /* without MWMO_ALERTABLE the result is never WAIT_IO_COMPLETION */
5395 ret = QueueUserAPC( apc_test_proc, GetCurrentThread(), 0 );
5396 ok(ret, "QueueUserAPC failed %lu\n", GetLastError());
5398 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, 0 );
5399 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjectsEx returned %lx\n", ret);
5401 /* but even with MWMO_ALERTABLE window events are preferred */
5402 PostMessageA( hwnd, WM_USER, 0, 0 );
5404 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_ALERTABLE );
5405 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %lx\n", ret);
5407 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5408 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5410 /* the APC call is still queued */
5411 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_ALERTABLE );
5412 ok(ret == WAIT_IO_COMPLETION, "MsgWaitForMultipleObjectsEx returned %lx\n", ret);
5415 static void test_WM_DEVICECHANGE(HWND hwnd)
5417 DWORD ret;
5418 MSG msg;
5419 int i;
5420 static const WPARAM wparams[] = {0,
5421 DBT_DEVNODES_CHANGED,
5422 DBT_QUERYCHANGECONFIG,
5423 DBT_CONFIGCHANGED,
5424 DBT_CONFIGCHANGECANCELED,
5425 DBT_NO_DISK_SPACE,
5426 DBT_LOW_DISK_SPACE,
5427 DBT_CONFIGMGPRIVATE, /* 0x7fff */
5428 DBT_DEVICEARRIVAL, /* 0x8000 */
5429 DBT_DEVICEQUERYREMOVE,
5430 DBT_DEVICEQUERYREMOVEFAILED,
5431 DBT_DEVICEREMOVEPENDING,
5432 DBT_DEVICEREMOVECOMPLETE,
5433 DBT_DEVICETYPESPECIFIC,
5434 DBT_CUSTOMEVENT};
5436 for (i = 0; i < ARRAY_SIZE(wparams); i++)
5438 SetLastError(0xdeadbeef);
5439 ret = PostMessageA(hwnd, WM_DEVICECHANGE, wparams[i], 0);
5440 if (wparams[i] & 0x8000)
5442 ok(ret == FALSE, "PostMessage returned %ld\n", ret);
5443 ok(GetLastError() == ERROR_MESSAGE_SYNC_ONLY, "PostMessage error %08lx\n", GetLastError());
5445 else
5447 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5448 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %lx\n", ret);
5449 memset(&msg, 0, sizeof(msg));
5450 ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should succeed\n");
5451 ok(msg.message == WM_DEVICECHANGE, "got %04x instead of WM_DEVICECHANGE\n", msg.message);
5456 static DWORD CALLBACK hide_window_thread( LPVOID arg )
5458 HWND hwnd = arg;
5460 /* function will not return if ShowWindow(SW_HIDE) calls SendMessage() */
5461 ok(ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow(SW_HIDE) expected FALSE\n");
5463 return 0;
5466 static DWORD CALLBACK show_window_thread( LPVOID arg )
5468 HWND hwnd = arg;
5470 /* function will not return if ShowWindow(SW_SHOW) calls SendMessage() */
5471 ok( ShowWindow( hwnd, SW_SHOW ), "ShowWindow(SW_SHOW) expected TRUE\n" ); /* actually it's 24... */
5473 return 0;
5476 /* Helper function to easier test SetWindowPos messages */
5477 #define test_msg_setpos( expected_list, flags, todo ) \
5478 test_msg_setpos_( (expected_list), (flags), (todo), __FILE__, __LINE__)
5479 static void test_msg_setpos_(const struct message *expected_list, UINT flags, BOOL todo, const char *file, int line)
5481 HWND hwnd;
5483 flush_events();
5484 flush_sequence();
5485 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5486 10, 10, 100, 100, NULL, 0, 0, NULL );
5487 ok (hwnd != 0, "Failed to create popup window\n");
5488 SetWindowPos(hwnd, NULL, 0, 0, 100, 100, flags);
5489 ok_sequence_(expected_list, "SetWindowPos:show_popup_first_show_window", todo, file, line);
5490 DestroyWindow(hwnd);
5493 /* test if we receive the right sequence of messages */
5494 static void test_messages(void)
5496 DWORD tid;
5497 HANDLE hthread;
5498 HWND hwnd, hparent, hchild;
5499 HWND hchild2, hbutton;
5500 HMENU hmenu;
5501 MSG msg;
5502 LRESULT res;
5503 POINT pos;
5504 BOOL ret;
5506 flush_sequence();
5508 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5509 100, 100, 200, 200, 0, 0, 0, NULL);
5510 ok (hwnd != 0, "Failed to create overlapped window\n");
5511 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
5513 /* test ShowWindow(SW_HIDE) on a newly created invisible window */
5514 ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
5515 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
5517 /* test WM_SETREDRAW on a not visible top level window */
5518 test_WM_SETREDRAW(hwnd);
5520 SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5521 flush_events();
5522 ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
5523 ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
5525 ok(GetActiveWindow() == hwnd, "window should be active\n");
5526 ok(GetFocus() == hwnd, "window should have input focus\n");
5527 ShowWindow(hwnd, SW_HIDE);
5528 flush_events();
5529 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5531 /* test ShowWindow(SW_HIDE) on a hidden window - single threaded */
5532 ok(ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow(SW_HIDE) expected FALSE\n");
5533 flush_events();
5534 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5536 /* test ShowWindow(SW_HIDE) on a hidden window - multi-threaded */
5537 hthread = CreateThread( NULL, 0, hide_window_thread, hwnd, 0, &tid );
5538 ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError());
5539 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5540 CloseHandle(hthread);
5541 flush_events();
5542 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5544 ShowWindow(hwnd, SW_SHOW);
5545 flush_events();
5546 ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
5548 /* test ShowWindow(SW_SHOW) on a visible window - multi-threaded */
5549 hthread = CreateThread( NULL, 0, show_window_thread, hwnd, 0, &tid );
5550 ok( hthread != NULL, "CreateThread failed, error %ld\n", GetLastError() );
5551 ok( WaitForSingleObject( hthread, INFINITE ) == WAIT_OBJECT_0, "WaitForSingleObject failed\n" );
5552 CloseHandle( hthread );
5553 flush_events();
5554 ok_sequence( WmEmptySeq, "ShowWindow(SW_SHOW):overlapped", FALSE );
5556 ShowWindow(hwnd, SW_HIDE);
5557 flush_events();
5558 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5560 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5561 flush_events();
5562 ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
5563 flush_sequence();
5565 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZE)
5567 ShowWindow(hwnd, SW_RESTORE);
5568 flush_events();
5569 ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
5570 flush_sequence();
5573 ShowWindow(hwnd, SW_MINIMIZE);
5574 flush_events();
5575 ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
5576 flush_sequence();
5578 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)
5580 ShowWindow(hwnd, SW_RESTORE);
5581 flush_events();
5582 ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", FALSE);
5583 flush_sequence();
5586 ShowWindow(hwnd, SW_SHOW);
5587 flush_events();
5588 ok_sequence(WmOptionalPaint, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
5590 SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5591 ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
5592 ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
5593 ok(GetActiveWindow() == hwnd, "window should still be active\n");
5595 /* test WM_SETREDRAW on a visible top level window */
5596 ShowWindow(hwnd, SW_SHOW);
5597 flush_events();
5598 test_WM_SETREDRAW(hwnd);
5600 trace("testing scroll APIs on a visible top level window %p\n", hwnd);
5601 test_scroll_messages(hwnd);
5603 /* test resizing and moving */
5604 SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
5605 ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
5606 flush_events();
5607 flush_sequence();
5608 SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
5609 ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
5610 flush_events();
5611 flush_sequence();
5612 SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER|SWP_NOACTIVATE );
5613 ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
5614 flush_events();
5615 flush_sequence();
5617 /* popups don't get WM_GETMINMAXINFO */
5618 SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
5619 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
5620 flush_sequence();
5621 SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
5622 ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
5624 DestroyWindow(hwnd);
5625 ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
5627 /* Test if windows are correctly drawn when first shown */
5629 /* Visible, redraw */
5630 flush_events();
5631 flush_sequence();
5632 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5633 10, 10, 100, 100, NULL, 0, 0, NULL );
5634 ok (hwnd != 0, "Failed to create popup window\n");
5635 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
5636 ok_sequence(WmShowPopupFirstDrawSeq_1, "RedrawWindow:show_popup_first_draw_visible", FALSE);
5637 DestroyWindow(hwnd);
5639 /* Invisible, show, message */
5640 flush_events();
5641 flush_sequence();
5642 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5643 10, 10, 100, 100, NULL, 0, 0, NULL );
5644 ok (hwnd != 0, "Failed to create popup window\n");
5645 ShowWindow(hwnd, SW_SHOW);
5646 SendMessageW(hwnd, WM_PAINT, 0, 0);
5647 ok_sequence(WmShowPopupFirstDrawSeq_1, "RedrawWindow:show_popup_first_draw_show", FALSE);
5648 DestroyWindow(hwnd);
5650 /* Invisible, show maximized, redraw */
5651 flush_events();
5652 flush_sequence();
5653 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5654 10, 10, 100, 100, NULL, 0, 0, NULL );
5655 ok (hwnd != 0, "Failed to create popup window\n");
5656 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5657 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
5658 ok_sequence(WmShowPopupFirstDrawSeq_2, "RedrawWindow:show_popup_first_draw_show_maximized", FALSE);
5659 DestroyWindow(hwnd);
5661 /* Test SetWindowPos */
5662 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW, FALSE);
5663 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, 0, FALSE);
5664 test_msg_setpos(WmFirstDrawSetWindowPosSeq3,
5665 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER, FALSE);
5667 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOSIZE, FALSE);
5668 test_msg_setpos(WmFirstDrawSetWindowPosSeq4, SWP_SHOWWINDOW | SWP_NOMOVE, FALSE);
5669 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCLIENTSIZE, FALSE);
5670 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCLIENTMOVE, FALSE);
5671 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOZORDER, FALSE);
5673 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE, FALSE);
5674 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOCLIENTMOVE, FALSE);
5675 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOCLIENTSIZE, FALSE);
5676 test_msg_setpos(WmFirstDrawSetWindowPosSeq5, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOMOVE, FALSE);
5677 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOSIZE, FALSE);
5678 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOZORDER, FALSE);
5680 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS, FALSE);
5681 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOCLIENTMOVE, FALSE);
5682 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOCLIENTSIZE, FALSE);
5683 test_msg_setpos(WmFirstDrawSetWindowPosSeq4, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOMOVE, FALSE);
5684 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOSIZE, FALSE);
5685 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOZORDER, FALSE);
5687 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW, FALSE);
5688 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCLIENTMOVE, FALSE);
5689 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCLIENTSIZE, FALSE);
5690 test_msg_setpos(WmFirstDrawSetWindowPosSeq5, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOMOVE, FALSE);
5691 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOSIZE, FALSE);
5692 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOZORDER, FALSE);
5694 /* Test SetWindowPos with child windows */
5695 flush_events();
5696 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5697 100, 100, 200, 200, 0, 0, 0, NULL);
5698 ok (hparent != 0, "Failed to create parent window\n");
5700 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5701 0, 0, 10, 10, hparent, 0, 0, NULL);
5702 ok (hchild != 0, "Failed to create child window\n");
5703 flush_sequence();
5704 SetWindowPos(hparent, NULL, 0, 0, 100, 100, SWP_SHOWWINDOW);
5705 ok_sequence(WmFirstDrawChildSeq1, /* Expect no messages for the child */
5706 "SetWindowPos:show_popup_first_show_window_child1", FALSE);
5707 DestroyWindow(hchild);
5708 DestroyWindow(hparent);
5710 flush_events();
5711 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN,
5712 100, 100, 200, 200, 0, 0, 0, NULL);
5713 ok (hparent != 0, "Failed to create parent window\n");
5715 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5716 0, 0, 10, 10, hparent, 0, 0, NULL);
5717 ok (hchild != 0, "Failed to create child window\n");
5718 flush_sequence();
5719 SetWindowPos(hparent, NULL, 0, 0, 100, 100, SWP_SHOWWINDOW);
5720 ok_sequence(WmFirstDrawChildSeq2, /* Expect child to be redrawn */
5721 "SetWindowPos:show_popup_first_show_window_child2", FALSE);
5722 DestroyWindow(hchild);
5723 DestroyWindow(hparent);
5725 /* Test message sequence for extreme position and size */
5727 flush_sequence();
5728 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5729 -10, -10, 10000, 10000, NULL, 0, 0, NULL );
5730 ok (hwnd != 0, "Failed to create popup window\n");
5731 ok_sequence(WmShowPopupExtremeLocationSeq, "RedrawWindow:show_popup_extreme_location", FALSE);
5732 DestroyWindow(hwnd);
5735 /* Test child windows */
5737 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5738 100, 100, 200, 200, 0, 0, 0, NULL);
5739 ok (hparent != 0, "Failed to create parent window\n");
5740 flush_sequence();
5742 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
5743 0, 0, 10, 10, hparent, 0, 0, NULL);
5744 ok (hchild != 0, "Failed to create child window\n");
5745 ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
5746 DestroyWindow(hchild);
5747 flush_sequence();
5749 /* visible child window with a caption */
5750 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
5751 WS_CHILD | WS_VISIBLE | WS_CAPTION,
5752 0, 0, 10, 10, hparent, 0, 0, NULL);
5753 ok (hchild != 0, "Failed to create child window\n");
5754 ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
5756 trace("testing scroll APIs on a visible child window %p\n", hchild);
5757 test_scroll_messages(hchild);
5759 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5760 ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
5762 DestroyWindow(hchild);
5763 flush_sequence();
5765 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5766 0, 0, 10, 10, hparent, 0, 0, NULL);
5767 ok (hchild != 0, "Failed to create child window\n");
5768 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
5770 hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
5771 100, 100, 50, 50, hparent, 0, 0, NULL);
5772 ok (hchild2 != 0, "Failed to create child2 window\n");
5773 flush_sequence();
5775 hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
5776 0, 100, 50, 50, hchild, 0, 0, NULL);
5777 ok (hbutton != 0, "Failed to create button window\n");
5779 /* test WM_SETREDRAW on a not visible child window */
5780 test_WM_SETREDRAW(hchild);
5782 ShowWindow(hchild, SW_SHOW);
5783 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5785 /* check parent messages too */
5786 log_all_parent_messages++;
5787 ShowWindow(hchild, SW_HIDE);
5788 ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
5789 log_all_parent_messages--;
5791 ShowWindow(hchild, SW_SHOW);
5792 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5794 ShowWindow(hchild, SW_HIDE);
5795 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
5797 ShowWindow(hchild, SW_SHOW);
5798 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5800 /* test WM_SETREDRAW on a visible child window */
5801 test_WM_SETREDRAW(hchild);
5803 log_all_parent_messages++;
5804 MoveWindow(hchild, 10, 10, 20, 20, TRUE);
5805 ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
5806 log_all_parent_messages--;
5808 ShowWindow(hchild, SW_HIDE);
5809 flush_sequence();
5810 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5811 ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
5813 ShowWindow(hchild, SW_HIDE);
5814 flush_sequence();
5815 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
5816 ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
5818 /* DestroyWindow sequence below expects that a child has focus */
5819 SetFocus(hchild);
5820 flush_sequence();
5822 DestroyWindow(hchild);
5823 ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
5824 DestroyWindow(hchild2);
5825 DestroyWindow(hbutton);
5827 flush_sequence();
5828 hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
5829 0, 0, 100, 100, hparent, 0, 0, NULL);
5830 ok (hchild != 0, "Failed to create child popup window\n");
5831 ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
5832 DestroyWindow(hchild);
5834 /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
5835 flush_sequence();
5836 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
5837 0, 0, 100, 100, hparent, 0, 0, NULL);
5838 ok (hchild != 0, "Failed to create popup window\n");
5839 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
5840 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5841 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
5842 flush_sequence();
5843 ShowWindow(hchild, SW_SHOW);
5844 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
5845 flush_sequence();
5846 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5847 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
5848 flush_sequence();
5849 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5850 ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
5851 DestroyWindow(hchild);
5853 /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
5854 * changes nothing in message sequences.
5856 flush_sequence();
5857 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5858 0, 0, 100, 100, hparent, 0, 0, NULL);
5859 ok (hchild != 0, "Failed to create popup window\n");
5860 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
5861 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5862 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
5863 flush_sequence();
5864 ShowWindow(hchild, SW_SHOW);
5865 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
5866 flush_sequence();
5867 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5868 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
5869 DestroyWindow(hchild);
5871 flush_sequence();
5872 hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
5873 0, 0, 100, 100, hparent, 0, 0, NULL);
5874 ok(hwnd != 0, "Failed to create custom dialog window\n");
5875 ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
5877 if(0) {
5878 trace("testing scroll APIs on a visible dialog %p\n", hwnd);
5879 test_scroll_messages(hwnd);
5882 flush_sequence();
5884 test_def_id = TRUE;
5885 SendMessageA(hwnd, WM_NULL, 0, 0);
5887 flush_sequence();
5888 after_end_dialog = TRUE;
5889 EndDialog( hwnd, 0 );
5890 ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
5892 DestroyWindow(hwnd);
5893 after_end_dialog = FALSE;
5894 test_def_id = FALSE;
5896 ok(GetCursorPos(&pos), "GetCursorPos failed\n");
5897 ok(SetCursorPos(109, 109), "SetCursorPos failed\n");
5899 hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP|WS_CHILD,
5900 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
5901 ok(hwnd != 0, "Failed to create custom dialog window\n");
5902 flush_sequence();
5903 trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
5904 ShowWindow(hwnd, SW_SHOW);
5905 ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
5907 flush_events();
5908 flush_sequence();
5909 ret = DrawMenuBar(hwnd);
5910 ok(ret, "DrawMenuBar failed: %ld\n", GetLastError());
5911 flush_events();
5912 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
5913 ok(SetCursorPos(pos.x, pos.y), "SetCursorPos failed\n");
5915 DestroyWindow(hwnd);
5917 hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_CHILD|WS_VISIBLE,
5918 0, 0, 100, 100, hparent, 0, GetModuleHandleA(0), NULL);
5919 ok(hwnd != 0, "Failed to create custom dialog window\n");
5920 flush_events();
5921 flush_sequence();
5922 ret = DrawMenuBar(hwnd);
5923 ok(ret, "DrawMenuBar failed: %ld\n", GetLastError());
5924 flush_events();
5925 ok_sequence(WmEmptySeq, "DrawMenuBar for a child window", FALSE);
5927 DestroyWindow(hwnd);
5929 flush_sequence();
5930 DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
5931 ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
5933 DestroyWindow(hparent);
5934 flush_sequence();
5936 /* Message sequence for SetMenu */
5937 ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a destroyed window\n");
5938 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "last error is %ld\n", GetLastError());
5939 ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
5941 hmenu = CreateMenu();
5942 ok (hmenu != 0, "Failed to create menu\n");
5943 ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
5944 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5945 100, 100, 200, 200, 0, hmenu, 0, NULL);
5946 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
5947 ok (SetMenu(hwnd, 0), "SetMenu\n");
5948 ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
5949 ok (SetMenu(hwnd, 0), "SetMenu\n");
5950 ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
5951 ShowWindow(hwnd, SW_SHOW);
5952 UpdateWindow( hwnd );
5953 flush_events();
5954 flush_sequence();
5955 ok (SetMenu(hwnd, 0), "SetMenu\n");
5956 ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
5957 ok (SetMenu(hwnd, hmenu), "SetMenu\n");
5958 ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
5960 UpdateWindow( hwnd );
5961 flush_events();
5962 flush_sequence();
5963 ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
5964 flush_events();
5965 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
5967 DestroyWindow(hwnd);
5968 flush_sequence();
5970 /* Message sequence for EnableWindow */
5971 hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5972 100, 100, 200, 200, 0, 0, 0, NULL);
5973 ok (hparent != 0, "Failed to create parent window\n");
5974 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5975 0, 0, 10, 10, hparent, 0, 0, NULL);
5976 ok (hchild != 0, "Failed to create child window\n");
5978 SetFocus(hchild);
5979 flush_events();
5980 flush_sequence();
5982 EnableWindow(hparent, FALSE);
5983 ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
5985 EnableWindow(hparent, FALSE);
5986 ok_sequence(WmEnableWindowSeq_2, "EnableWindow(FALSE)", FALSE);
5988 EnableWindow(hparent, TRUE);
5989 ok_sequence(WmEnableWindowSeq_3, "EnableWindow(TRUE)", FALSE);
5991 EnableWindow(hparent, TRUE);
5992 ok_sequence(WmEnableWindowSeq_4, "EnableWindow(TRUE)", FALSE);
5994 flush_events();
5995 flush_sequence();
5997 test_MsgWaitForMultipleObjects(hparent);
5998 test_WM_DEVICECHANGE(hparent);
6000 /* the following test causes an exception in user.exe under win9x */
6001 if (!PostMessageW( hparent, WM_USER, 0, 0 ))
6003 DestroyWindow(hparent);
6004 flush_sequence();
6005 return;
6007 PostMessageW( hparent, WM_USER+1, 0, 0 );
6008 /* PeekMessage(NULL) fails, but still removes the message */
6009 SetLastError(0xdeadbeef);
6010 ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
6011 ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
6012 GetLastError() == 0xdeadbeef, /* NT4 */
6013 "last error is %ld\n", GetLastError() );
6014 ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
6015 ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
6017 DestroyWindow(hchild);
6018 DestroyWindow(hparent);
6019 flush_sequence();
6021 /* Message sequences for WM_SETICON */
6022 trace("testing WM_SETICON\n");
6023 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
6024 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
6025 NULL, NULL, 0);
6026 ShowWindow(hwnd, SW_SHOW);
6027 UpdateWindow(hwnd);
6028 flush_events();
6029 flush_sequence();
6030 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
6031 ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
6033 ShowWindow(hwnd, SW_HIDE);
6034 flush_events();
6035 flush_sequence();
6036 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
6037 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
6038 DestroyWindow(hwnd);
6039 flush_sequence();
6041 hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
6042 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
6043 NULL, NULL, 0);
6044 ShowWindow(hwnd, SW_SHOW);
6045 UpdateWindow(hwnd);
6046 flush_events();
6047 flush_sequence();
6048 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
6049 ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
6051 ShowWindow(hwnd, SW_HIDE);
6052 flush_events();
6053 flush_sequence();
6054 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
6055 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
6057 flush_sequence();
6058 res = SendMessageA(hwnd, 0x3B, 0x8000000b, 0);
6059 if (!res)
6061 todo_wine win_skip( "Message 0x3b not supported\n" );
6062 goto done;
6064 ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
6065 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %Id\n", res);
6066 res = SendMessageA(hwnd, 0x3B, 0x0000000b, 0);
6067 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
6068 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %Id\n", res);
6069 res = SendMessageA(hwnd, 0x3B, 0x0000000f, 0);
6070 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
6071 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %Id\n", res);
6073 flush_sequence();
6074 res = SendMessageA(hwnd, 0x3B, 0x80000008, 0);
6075 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
6076 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %Id\n", res);
6077 res = SendMessageA(hwnd, 0x3B, 0x00000008, 0);
6078 ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
6079 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %Id\n", res);
6081 res = SendMessageA(hwnd, 0x3B, 0x80000004, 0);
6082 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
6083 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %Id\n", res);
6085 res = SendMessageA(hwnd, 0x3B, 0x80000001, 0);
6086 ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
6087 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %Id\n", res);
6089 done:
6090 DestroyWindow(hwnd);
6091 flush_sequence();
6094 static const struct message WmFrameChanged[] = {
6095 { WM_WINDOWPOSCHANGING, sent|wparam|lparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE, 0 },
6096 { WM_NCCALCSIZE, sent|wparam|lparam, 1, 0xf },
6097 { WM_WINDOWPOSCHANGED, sent|wparam|lparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW
6098 |SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0xf },
6099 { WM_GETTEXT, sent|optional },
6100 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
6101 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
6102 { 0 }
6105 static const struct message WmFrameChanged_move[] = {
6106 { WM_WINDOWPOSCHANGING, sent|wparam|lparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE, 0 },
6107 { WM_NCCALCSIZE, sent|wparam|lparam, 1, 0x3 },
6108 { WM_WINDOWPOSCHANGED, sent|wparam|lparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW
6109 |SWP_NOSIZE|SWP_NOCLIENTSIZE, 0x3 },
6110 { WM_MOVE, sent|defwinproc, 0 },
6111 { WM_GETTEXT, sent|optional },
6112 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
6113 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
6114 { 0 }
6117 static void test_setwindowpos(void)
6119 HWND hwnd;
6120 RECT rc;
6121 LRESULT res;
6122 const INT X = 50;
6123 const INT Y = 50;
6124 const INT winX = 100;
6125 const INT winY = 100;
6126 const INT sysX = GetSystemMetrics(SM_CXMINTRACK);
6128 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
6129 X, Y, winX, winY, 0,
6130 NULL, NULL, 0);
6132 GetWindowRect(hwnd, &rc);
6133 expect(sysX + X, rc.right);
6134 expect(winY + Y, rc.bottom);
6136 flush_events();
6137 flush_sequence();
6138 res = SetWindowPos(hwnd, HWND_TOPMOST, 50, 50, winX, winY, 0);
6139 ok_sequence(WmZOrder, "Z-Order", TRUE);
6140 ok(res == TRUE, "SetWindowPos expected TRUE, got %Id\n", res);
6142 GetWindowRect(hwnd, &rc);
6143 expect(sysX + X, rc.right);
6144 expect(winY + Y, rc.bottom);
6146 res = SetWindowPos( hwnd, 0, 0, 0, 0, 0,
6147 SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
6148 ok_sequence(WmFrameChanged, "FrameChanged", FALSE);
6149 ok(res == TRUE, "SetWindowPos expected TRUE, got %Id.\n", res);
6151 GetWindowRect(hwnd, &rc);
6152 expect(sysX + X, rc.right);
6153 expect(winY + Y, rc.bottom);
6155 res = SetWindowPos( hwnd, 0, 0, 0, 0, 0,
6156 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
6157 ok_sequence(WmFrameChanged_move, "FrameChanged", FALSE);
6158 ok(res == TRUE, "SetWindowPos expected TRUE, got %Id.\n", res);
6160 GetWindowRect(hwnd, &rc);
6161 expect(sysX, rc.right);
6162 expect(winY, rc.bottom);
6164 DestroyWindow(hwnd);
6167 static void invisible_parent_tests(void)
6169 HWND hparent, hchild;
6171 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
6172 100, 100, 200, 200, 0, 0, 0, NULL);
6173 ok (hparent != 0, "Failed to create parent window\n");
6174 flush_sequence();
6176 /* test showing child with hidden parent */
6178 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6179 0, 0, 10, 10, hparent, 0, 0, NULL);
6180 ok (hchild != 0, "Failed to create child window\n");
6181 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
6183 ShowWindow( hchild, SW_MINIMIZE );
6184 ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
6185 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6186 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6188 /* repeat */
6189 flush_events();
6190 flush_sequence();
6191 ShowWindow( hchild, SW_MINIMIZE );
6192 ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
6194 DestroyWindow(hchild);
6195 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6196 0, 0, 10, 10, hparent, 0, 0, NULL);
6197 flush_sequence();
6199 ShowWindow( hchild, SW_MAXIMIZE );
6200 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
6201 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6202 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6204 /* repeat */
6205 flush_events();
6206 flush_sequence();
6207 ShowWindow( hchild, SW_MAXIMIZE );
6208 ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
6210 DestroyWindow(hchild);
6211 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6212 0, 0, 10, 10, hparent, 0, 0, NULL);
6213 flush_sequence();
6215 ShowWindow( hchild, SW_RESTORE );
6216 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
6217 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6218 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6220 DestroyWindow(hchild);
6221 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6222 0, 0, 10, 10, hparent, 0, 0, NULL);
6223 flush_sequence();
6225 ShowWindow( hchild, SW_SHOWMINIMIZED );
6226 ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
6227 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6228 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6230 /* repeat */
6231 flush_events();
6232 flush_sequence();
6233 ShowWindow( hchild, SW_SHOWMINIMIZED );
6234 ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
6236 DestroyWindow(hchild);
6237 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6238 0, 0, 10, 10, hparent, 0, 0, NULL);
6239 flush_sequence();
6241 /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
6242 ShowWindow( hchild, SW_SHOWMAXIMIZED );
6243 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
6244 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6245 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6247 DestroyWindow(hchild);
6248 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6249 0, 0, 10, 10, hparent, 0, 0, NULL);
6250 flush_sequence();
6252 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
6253 ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
6254 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6255 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6257 /* repeat */
6258 flush_events();
6259 flush_sequence();
6260 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
6261 ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
6263 DestroyWindow(hchild);
6264 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6265 0, 0, 10, 10, hparent, 0, 0, NULL);
6266 flush_sequence();
6268 /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
6269 ShowWindow( hchild, SW_FORCEMINIMIZE );
6270 ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
6271 todo_wine {
6272 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
6274 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6276 DestroyWindow(hchild);
6277 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6278 0, 0, 10, 10, hparent, 0, 0, NULL);
6279 flush_sequence();
6281 ShowWindow( hchild, SW_SHOWNA );
6282 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
6283 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6284 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6286 /* repeat */
6287 flush_events();
6288 flush_sequence();
6289 ShowWindow( hchild, SW_SHOWNA );
6290 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
6292 DestroyWindow(hchild);
6293 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6294 0, 0, 10, 10, hparent, 0, 0, NULL);
6295 flush_sequence();
6297 ShowWindow( hchild, SW_SHOW );
6298 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
6299 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6300 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6302 /* repeat */
6303 flush_events();
6304 flush_sequence();
6305 ShowWindow( hchild, SW_SHOW );
6306 ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
6308 ShowWindow( hchild, SW_HIDE );
6309 ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
6310 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
6311 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6313 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
6314 ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
6315 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6316 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6318 SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
6319 ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
6320 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
6321 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6323 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
6324 flush_sequence();
6325 DestroyWindow(hchild);
6326 ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
6328 DestroyWindow(hparent);
6329 flush_sequence();
6332 /****************** button message test *************************/
6333 #define ID_BUTTON 0x000e
6335 static const struct message WmSetFocusButtonSeq[] =
6337 { HCBT_SETFOCUS, hook },
6338 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
6339 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
6340 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6341 { WM_SETFOCUS, sent|wparam, 0 },
6342 { WM_CTLCOLORBTN, sent|parent },
6343 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
6344 { WM_APP, sent|wparam|lparam, 0, 0 },
6345 { 0 }
6347 static const struct message WmKillFocusButtonSeq[] =
6349 { HCBT_SETFOCUS, hook },
6350 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6351 { WM_KILLFOCUS, sent|wparam, 0 },
6352 { WM_CTLCOLORBTN, sent|parent },
6353 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
6354 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
6355 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
6356 { WM_APP, sent|wparam|lparam, 0, 0 },
6357 { WM_PAINT, sent },
6358 { WM_CTLCOLORBTN, sent|parent },
6359 { 0 }
6361 static const struct message WmSetFocusStaticSeq[] =
6363 { HCBT_SETFOCUS, hook },
6364 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
6365 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
6366 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6367 { WM_SETFOCUS, sent|wparam, 0 },
6368 { WM_CTLCOLORSTATIC, sent|parent },
6369 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
6370 { WM_COMMAND, sent|wparam|parent|optional, MAKEWPARAM(ID_BUTTON, BN_CLICKED) }, /* radio button */
6371 { WM_APP, sent|wparam|lparam, 0, 0 },
6372 { 0 }
6374 static const struct message WmKillFocusStaticSeq[] =
6376 { HCBT_SETFOCUS, hook },
6377 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6378 { WM_KILLFOCUS, sent|wparam, 0 },
6379 { WM_CTLCOLORSTATIC, sent|parent },
6380 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
6381 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
6382 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
6383 { WM_APP, sent|wparam|lparam, 0, 0 },
6384 { WM_PAINT, sent },
6385 { WM_CTLCOLORSTATIC, sent|parent },
6386 { 0 }
6388 static const struct message WmSetFocusOwnerdrawSeq[] =
6390 { HCBT_SETFOCUS, hook },
6391 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
6392 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
6393 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6394 { WM_SETFOCUS, sent|wparam, 0 },
6395 { WM_CTLCOLORBTN, sent|parent },
6396 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x001040e4 },
6397 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
6398 { WM_APP, sent|wparam|lparam, 0, 0 },
6399 { 0 }
6401 static const struct message WmKillFocusOwnerdrawSeq[] =
6403 { HCBT_SETFOCUS, hook },
6404 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6405 { WM_KILLFOCUS, sent|wparam, 0 },
6406 { WM_CTLCOLORBTN, sent|parent },
6407 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000040e4 },
6408 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
6409 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
6410 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
6411 { WM_APP, sent|wparam|lparam, 0, 0 },
6412 { WM_PAINT, sent },
6413 { WM_CTLCOLORBTN, sent|parent },
6414 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
6415 { 0 }
6417 static const struct message WmLButtonDownSeq[] =
6419 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
6420 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
6421 { HCBT_SETFOCUS, hook },
6422 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
6423 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
6424 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6425 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
6426 { WM_CTLCOLORBTN, sent|defwinproc },
6427 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
6428 { WM_CTLCOLORBTN, sent|defwinproc },
6429 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6430 { 0 }
6432 static const struct message WmLButtonDownStaticSeq[] =
6434 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
6435 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
6436 { HCBT_SETFOCUS, hook },
6437 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
6438 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
6439 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6440 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
6441 { WM_CTLCOLORSTATIC, sent|defwinproc },
6442 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
6443 { WM_CTLCOLORSTATIC, sent|defwinproc },
6444 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6445 { 0 }
6447 static const struct message WmLButtonUpSeq[] =
6449 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6450 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6451 { WM_CTLCOLORBTN, sent|defwinproc },
6452 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6453 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
6454 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6455 { 0 }
6457 static const struct message WmLButtonUpStaticSeq[] =
6459 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6460 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6461 { WM_CTLCOLORSTATIC, sent|defwinproc },
6462 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6463 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
6464 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6465 { 0 }
6467 static const struct message WmLButtonUpAutoSeq[] =
6469 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6470 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6471 { WM_CTLCOLORSTATIC, sent|defwinproc },
6472 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6473 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|optional, 0, 0 },
6474 { BM_SETCHECK, sent|defwinproc },
6475 { WM_CTLCOLORSTATIC, sent|defwinproc|optional, 0, 0 }, /* Sent here on Win7. */
6476 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6477 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
6478 { WM_CTLCOLORSTATIC, sent|defwinproc|optional, 0, 0 }, /* Sent here on Win8+. */
6479 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6480 { 0 }
6482 static const struct message WmLButtonUpBrokenSeq[] =
6484 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6485 { 0 }
6487 static const struct message WmSetFontButtonSeq[] =
6489 { WM_SETFONT, sent },
6490 { WM_PAINT, sent },
6491 { WM_ERASEBKGND, sent|defwinproc|optional },
6492 { WM_CTLCOLORBTN, sent|defwinproc },
6493 { WM_CTLCOLORBTN, sent|defwinproc|optional }, /* FIXME: Wine sends it twice for BS_OWNERDRAW */
6494 { 0 }
6496 static const struct message WmSetFontStaticSeq[] =
6498 { WM_SETFONT, sent },
6499 { WM_PAINT, sent },
6500 { WM_ERASEBKGND, sent|defwinproc|optional },
6501 { WM_CTLCOLORSTATIC, sent|defwinproc },
6502 { 0 }
6504 static const struct message WmSetTextButtonSeq[] =
6506 { WM_SETTEXT, sent },
6507 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
6508 { WM_CTLCOLORBTN, sent|parent },
6509 { WM_CTLCOLORBTN, sent|parent },
6510 { WM_COMMAND, sent|parent|optional },
6511 { WM_DRAWITEM, sent|parent|optional },
6512 { 0 }
6514 static const struct message WmSetTextStaticSeq[] =
6516 { WM_SETTEXT, sent },
6517 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
6518 { WM_CTLCOLORSTATIC, sent|parent },
6519 { WM_CTLCOLORSTATIC, sent|parent },
6520 { 0 }
6522 static const struct message WmSetTextGroupSeq[] =
6524 { WM_SETTEXT, sent },
6525 { WM_CTLCOLORSTATIC, sent|parent },
6526 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
6527 { WM_CTLCOLORSTATIC, sent|parent|optional }, /* FIXME: Missing in Wine */
6528 { WM_CTLCOLORSTATIC, sent|parent|optional }, /* FIXME: Missing in Wine */
6529 { 0 }
6531 static const struct message WmSetTextInvisibleSeq[] =
6533 { WM_SETTEXT, sent },
6534 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
6535 { 0 }
6537 static const struct message WmSetStyleButtonSeq[] =
6539 { BM_SETSTYLE, sent },
6540 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6541 { WM_APP, sent|wparam|lparam, 0, 0 },
6542 { WM_PAINT, sent },
6543 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6544 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6545 { WM_CTLCOLORBTN, sent|parent },
6546 { 0 }
6548 static const struct message WmSetStyleStaticSeq[] =
6550 { BM_SETSTYLE, sent },
6551 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6552 { WM_APP, sent|wparam|lparam, 0, 0 },
6553 { WM_PAINT, sent },
6554 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6555 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6556 { WM_CTLCOLORSTATIC, sent|parent },
6557 { 0 }
6559 static const struct message WmSetStyleUserSeq[] =
6561 { BM_SETSTYLE, sent },
6562 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6563 { WM_APP, sent|wparam|lparam, 0, 0 },
6564 { WM_PAINT, sent },
6565 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6566 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6567 { WM_CTLCOLORBTN, sent|parent },
6568 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_PAINT) },
6569 { 0 }
6571 static const struct message WmSetStyleOwnerdrawSeq[] =
6573 { BM_SETSTYLE, sent },
6574 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6575 { WM_APP, sent|wparam|lparam, 0, 0 },
6576 { WM_PAINT, sent },
6577 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
6578 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6579 { WM_CTLCOLORBTN, sent|parent },
6580 { WM_CTLCOLORBTN, sent|parent|optional }, /* Win9x doesn't send it */
6581 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
6582 { 0 }
6584 static const struct message WmSetStateButtonSeq[] =
6586 { BM_SETSTATE, sent },
6587 { WM_CTLCOLORBTN, sent|parent },
6588 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6589 { WM_APP, sent|wparam|lparam, 0, 0 },
6590 { 0 }
6592 static const struct message WmSetStateStaticSeq[] =
6594 { BM_SETSTATE, sent },
6595 { WM_CTLCOLORSTATIC, sent|parent },
6596 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6597 { WM_APP, sent|wparam|lparam, 0, 0 },
6598 { 0 }
6600 static const struct message WmSetStateUserSeq[] =
6602 { BM_SETSTATE, sent },
6603 { WM_CTLCOLORBTN, sent|parent },
6604 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_HILITE) },
6605 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6606 { WM_APP, sent|wparam|lparam, 0, 0 },
6607 { 0 }
6609 static const struct message WmSetStateOwnerdrawSeq[] =
6611 { BM_SETSTATE, sent },
6612 { WM_CTLCOLORBTN, sent|parent },
6613 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000120e4 },
6614 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6615 { WM_APP, sent|wparam|lparam, 0, 0 },
6616 { 0 }
6618 static const struct message WmClearStateButtonSeq[] =
6620 { BM_SETSTATE, sent },
6621 { WM_CTLCOLORBTN, sent|parent },
6622 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_UNHILITE) },
6623 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6624 { WM_APP, sent|wparam|lparam, 0, 0 },
6625 { 0 }
6627 static const struct message WmDisableButtonSeq[] =
6629 { WM_LBUTTONDOWN, sent },
6630 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
6631 { BM_SETSTATE, sent|defwinproc },
6632 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6633 { WM_CTLCOLORBTN, sent|optional },
6634 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6635 { WM_LBUTTONUP, sent },
6636 { BM_SETSTATE, sent|defwinproc },
6637 { WM_CTLCOLORBTN, sent|defwinproc|optional },
6638 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6639 { BM_SETCHECK, sent|defwinproc|optional },
6640 { WM_CTLCOLORBTN, sent|optional },
6641 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6642 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
6643 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6644 { WM_CAPTURECHANGED, sent|defwinproc },
6645 { WM_COMMAND, sent },
6646 { 0 }
6648 static const struct message WmClearStateOwnerdrawSeq[] =
6650 { BM_SETSTATE, sent },
6651 { WM_CTLCOLORBTN, sent|parent },
6652 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000020e4 },
6653 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6654 { WM_APP, sent|wparam|lparam, 0, 0 },
6655 { 0 }
6657 static const struct message WmSetCheckIgnoredSeq[] =
6659 { BM_SETCHECK, sent },
6660 { WM_APP, sent|wparam|lparam, 0, 0 },
6661 { 0 }
6663 static const struct message WmSetCheckStaticSeq[] =
6665 { BM_SETCHECK, sent },
6666 { WM_CTLCOLORSTATIC, sent|parent },
6667 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
6668 { WM_APP, sent|wparam|lparam, 0, 0 },
6669 { 0 }
6672 static WNDPROC old_button_proc;
6674 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6676 static LONG defwndproc_counter = 0;
6677 LRESULT ret;
6678 struct recvd_message msg;
6680 if (ignore_message( message )) return 0;
6682 switch (message)
6684 case WM_SYNCPAINT:
6685 break;
6686 case BM_SETSTATE:
6687 if (GetCapture())
6688 ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
6690 lParam = (ULONG_PTR)GetMenu(hwnd);
6691 goto log_it;
6693 case WM_GETDLGCODE:
6694 if (lParam)
6696 MSG *msg = (MSG *)lParam;
6697 lParam = MAKELPARAM(msg->message, msg->wParam);
6699 wParam = (ULONG_PTR)GetMenu(hwnd);
6700 goto log_it;
6702 case BM_SETCHECK:
6703 case BM_GETCHECK:
6704 lParam = (ULONG_PTR)GetMenu(hwnd);
6705 /* fall through */
6706 log_it:
6707 default:
6708 msg.hwnd = hwnd;
6709 msg.message = message;
6710 msg.flags = sent|wparam|lparam;
6711 if (defwndproc_counter) msg.flags |= defwinproc;
6712 msg.wParam = wParam;
6713 msg.lParam = lParam;
6714 msg.descr = "button";
6715 add_message(&msg);
6718 defwndproc_counter++;
6719 ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
6720 defwndproc_counter--;
6722 return ret;
6725 static void subclass_button(void)
6727 WNDCLASSA cls;
6729 if (!GetClassInfoA(0, "button", &cls)) assert(0);
6731 old_button_proc = cls.lpfnWndProc;
6733 cls.hInstance = GetModuleHandleA(NULL);
6734 cls.lpfnWndProc = button_hook_proc;
6735 cls.lpszClassName = "my_button_class";
6736 UnregisterClassA(cls.lpszClassName, cls.hInstance);
6737 if (!RegisterClassA(&cls)) assert(0);
6740 static void test_button_messages(void)
6742 static const struct
6744 DWORD style;
6745 DWORD dlg_code;
6746 const struct message *setfocus;
6747 const struct message *killfocus;
6748 const struct message *setstyle;
6749 const struct message *setstate;
6750 const struct message *clearstate;
6751 const struct message *setcheck;
6752 const struct message *lbuttondown;
6753 const struct message *lbuttonup;
6754 const struct message *setfont;
6755 const struct message *settext;
6756 } button[] = {
6757 { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
6758 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
6759 WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq,
6760 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6761 WmSetTextButtonSeq },
6762 { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
6763 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
6764 WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq,
6765 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6766 WmSetTextButtonSeq },
6767 { BS_CHECKBOX, DLGC_BUTTON,
6768 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6769 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6770 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6771 WmSetTextStaticSeq },
6772 { BS_AUTOCHECKBOX, DLGC_BUTTON,
6773 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6774 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6775 WmLButtonDownStaticSeq, WmLButtonUpAutoSeq, WmSetFontStaticSeq,
6776 WmSetTextStaticSeq },
6777 { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
6778 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6779 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6780 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6781 WmSetTextStaticSeq },
6782 { BS_3STATE, DLGC_BUTTON,
6783 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6784 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6785 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6786 WmSetTextStaticSeq },
6787 { BS_AUTO3STATE, DLGC_BUTTON,
6788 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6789 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6790 WmLButtonDownStaticSeq, WmLButtonUpAutoSeq, WmSetFontStaticSeq,
6791 WmSetTextStaticSeq },
6792 { BS_GROUPBOX, DLGC_STATIC,
6793 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6794 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckIgnoredSeq,
6795 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6796 WmSetTextGroupSeq },
6797 { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
6798 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleUserSeq,
6799 WmSetStateUserSeq, WmClearStateButtonSeq, WmSetCheckIgnoredSeq,
6800 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6801 WmSetTextButtonSeq },
6802 { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
6803 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6804 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6805 NULL /* avoid infinite loop */, WmLButtonUpBrokenSeq, WmSetFontStaticSeq,
6806 WmSetTextStaticSeq },
6807 { BS_OWNERDRAW, DLGC_BUTTON,
6808 WmSetFocusOwnerdrawSeq, WmKillFocusOwnerdrawSeq, WmSetStyleOwnerdrawSeq,
6809 WmSetStateOwnerdrawSeq, WmClearStateOwnerdrawSeq, WmSetCheckIgnoredSeq,
6810 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6811 WmSetTextButtonSeq },
6813 LOGFONTA logfont = { 0 };
6814 HFONT zfont, hfont2;
6815 unsigned int i;
6816 HWND hwnd, parent;
6817 DWORD dlg_code;
6819 /* selection with VK_SPACE should capture button window */
6820 hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
6821 0, 0, 50, 14, 0, 0, 0, NULL);
6822 ok(hwnd != 0, "Failed to create button window\n");
6823 ReleaseCapture();
6824 SetFocus(hwnd);
6825 SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
6826 ok(GetCapture() == hwnd, "Should be captured on VK_SPACE WM_KEYDOWN\n");
6827 SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
6828 DestroyWindow(hwnd);
6830 subclass_button();
6832 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6833 100, 100, 200, 200, 0, 0, 0, NULL);
6834 ok(parent != 0, "Failed to create parent window\n");
6836 memset(&logfont, 0, sizeof(logfont));
6837 logfont.lfHeight = -12;
6838 logfont.lfWeight = FW_NORMAL;
6839 strcpy(logfont.lfFaceName, "Tahoma");
6841 hfont2 = CreateFontIndirectA(&logfont);
6842 ok(hfont2 != NULL, "Failed to create Tahoma font\n");
6844 for (i = 0; i < ARRAY_SIZE(button); i++)
6846 MSG msg;
6847 DWORD style, state;
6848 HFONT prevfont;
6849 char desc[64];
6850 HDC hdc;
6852 trace("button style %08lx\n", button[i].style);
6854 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_CHILD | BS_NOTIFY,
6855 0, 0, 50, 14, parent, (HMENU)ID_BUTTON, 0, NULL);
6856 ok(hwnd != 0, "Failed to create button window\n");
6858 style = GetWindowLongA(hwnd, GWL_STYLE);
6859 style &= ~(WS_CHILD | BS_NOTIFY);
6860 /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
6861 if (button[i].style == BS_USERBUTTON)
6862 ok(style == BS_PUSHBUTTON, "expected style BS_PUSHBUTTON got %lx\n", style);
6863 else
6864 ok(style == button[i].style, "expected style %lx got %lx\n", button[i].style, style);
6866 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
6867 ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08lx\n", i, dlg_code);
6869 ShowWindow(hwnd, SW_SHOW);
6870 UpdateWindow(hwnd);
6871 SetFocus(0);
6872 flush_events();
6873 SetFocus(0);
6874 flush_sequence();
6876 log_all_parent_messages++;
6878 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
6879 SetFocus(hwnd);
6880 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6881 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6882 ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
6884 SetFocus(0);
6885 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6886 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6887 ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
6889 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
6891 SendMessageA(hwnd, BM_SETSTYLE, button[i].style | BS_BOTTOM, TRUE);
6892 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6893 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6894 ok_sequence(button[i].setstyle, "BM_SETSTYLE on a button", FALSE);
6896 style = GetWindowLongA(hwnd, GWL_STYLE);
6897 style &= ~(WS_VISIBLE | WS_CHILD | BS_NOTIFY);
6898 /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */
6899 ok(style == button[i].style, "expected style %04lx got %04lx\n", button[i].style, style);
6901 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6902 ok(state == 0, "expected state 0, got %04lx\n", state);
6904 flush_sequence();
6906 SendMessageA(hwnd, BM_SETSTATE, TRUE, 0);
6907 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6908 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6909 ok_sequence(button[i].setstate, "BM_SETSTATE/TRUE on a button", FALSE);
6911 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6912 ok(state == 0x0004, "expected state 0x0004, got %04lx\n", state);
6914 style = GetWindowLongA(hwnd, GWL_STYLE);
6915 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6916 ok(style == button[i].style, "expected style %04lx got %04lx\n", button[i].style, style);
6918 flush_sequence();
6920 SendMessageA(hwnd, BM_SETSTATE, FALSE, 0);
6921 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6922 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6923 ok_sequence(button[i].clearstate, "BM_SETSTATE/FALSE on a button", FALSE);
6925 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6926 ok(state == 0, "expected state 0, got %04lx\n", state);
6928 style = GetWindowLongA(hwnd, GWL_STYLE);
6929 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6930 ok(style == button[i].style, "expected style %04lx got %04lx\n", button[i].style, style);
6932 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6933 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04lx\n", state);
6935 flush_sequence();
6937 SendMessageA(hwnd, BM_SETCHECK, BST_UNCHECKED, 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(WmSetCheckIgnoredSeq, "BM_SETCHECK on a button", FALSE);
6942 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6943 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04lx\n", state);
6945 style = GetWindowLongA(hwnd, GWL_STYLE);
6946 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6947 ok(style == button[i].style, "expected style %04lx got %04lx\n", button[i].style, style);
6949 flush_sequence();
6951 SendMessageA(hwnd, BM_SETCHECK, BST_CHECKED, 0);
6952 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6953 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6954 ok_sequence(button[i].setcheck, "BM_SETCHECK on a button", FALSE);
6956 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 1");
6957 sprintf(desc, "button[%i]: WM_SETTEXT on a visible button", i);
6958 ok_sequence(button[i].settext, desc, FALSE);
6960 ShowWindow(hwnd, SW_HIDE);
6961 flush_events();
6962 flush_sequence();
6964 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 2");
6965 sprintf(desc, "button[%i]: WM_SETTEXT on an invisible button", i);
6966 ok_sequence(WmSetTextInvisibleSeq, desc, FALSE);
6968 ShowWindow(hwnd, SW_SHOW);
6969 ShowWindow(parent, SW_HIDE);
6970 flush_events();
6971 flush_sequence();
6973 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 3");
6974 sprintf(desc, "button[%i]: WM_SETTEXT on an invisible button", i);
6975 ok_sequence(WmSetTextInvisibleSeq, desc, FALSE);
6977 ShowWindow(parent, SW_SHOW);
6978 flush_events();
6980 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6981 if (button[i].style == BS_PUSHBUTTON ||
6982 button[i].style == BS_DEFPUSHBUTTON ||
6983 button[i].style == BS_GROUPBOX ||
6984 button[i].style == BS_USERBUTTON ||
6985 button[i].style == BS_OWNERDRAW)
6986 ok(state == BST_UNCHECKED, "expected check 0, got %04lx\n", state);
6987 else
6988 ok(state == BST_CHECKED, "expected check 1, got %04lx\n", state);
6990 style = GetWindowLongA(hwnd, GWL_STYLE);
6991 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6992 if (button[i].style == BS_RADIOBUTTON ||
6993 button[i].style == BS_AUTORADIOBUTTON)
6994 ok(style == (button[i].style | WS_TABSTOP), "expected style %04lx | WS_TABSTOP got %04lx\n", button[i].style, style);
6995 else
6996 ok(style == button[i].style, "expected style %04lx got %04lx\n", button[i].style, style);
6998 log_all_parent_messages--;
7000 DestroyWindow(hwnd);
7002 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP | WS_VISIBLE,
7003 0, 0, 50, 14, 0, 0, 0, NULL);
7004 ok(hwnd != 0, "Failed to create button window\n");
7006 SetForegroundWindow(hwnd);
7007 flush_events();
7009 SetActiveWindow(hwnd);
7010 SetFocus(0);
7011 flush_sequence();
7013 if (button[i].lbuttondown)
7015 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
7016 sprintf(desc, "button[%i]: WM_LBUTTONDOWN on a button", i);
7017 ok_sequence(button[i].lbuttondown, desc, FALSE);
7020 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
7021 sprintf(desc, "button[%i]: WM_LBUTTONUP on a button", i);
7022 ok_sequence(button[i].lbuttonup, desc, FALSE);
7024 flush_sequence();
7025 zfont = GetStockObject(DEFAULT_GUI_FONT);
7026 SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
7027 UpdateWindow(hwnd);
7028 sprintf(desc, "button[%i]: WM_SETFONT on a button", i);
7029 ok_sequence(button[i].setfont, desc, FALSE);
7031 /* Test that original font is not selected back after painting */
7032 hdc = CreateCompatibleDC(0);
7034 prevfont = SelectObject(hdc, hfont2);
7035 ok(prevfont == GetStockObject(SYSTEM_FONT), "Unexpected default font\n");
7036 SendMessageA(hwnd, WM_PRINTCLIENT, (WPARAM)hdc, 0);
7037 ok(hfont2 != GetCurrentObject(hdc, OBJ_FONT), "button[%u]: unexpected font selected after WM_PRINTCLIENT\n", i);
7038 SelectObject(hdc, prevfont);
7040 prevfont = SelectObject(hdc, hfont2);
7041 ok(prevfont == GetStockObject(SYSTEM_FONT), "Unexpected default font\n");
7042 SendMessageA(hwnd, WM_PAINT, (WPARAM)hdc, 0);
7043 ok(hfont2 != GetCurrentObject(hdc, OBJ_FONT), "button[%u]: unexpected font selected after WM_PAINT\n", i);
7044 SelectObject(hdc, prevfont);
7046 DeleteDC(hdc);
7048 DestroyWindow(hwnd);
7051 DeleteObject(hfont2);
7052 DestroyWindow(parent);
7054 /* Test if WM_LBUTTONDOWN and WM_LBUTTONUP to a disabled button leads to a WM_COMMAND for the parent */
7056 parent = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7057 100, 100, 200, 200, 0, 0, 0, NULL);
7058 ok (hwnd != 0, "Failed to create overlapped window\n");
7060 hwnd = CreateWindowExA(0, "my_button_class", "test", BS_DEFPUSHBUTTON | WS_VISIBLE | WS_CHILD,
7061 0, 0, 50, 14, parent, 0, 0, NULL);
7063 EnableWindow(hwnd, FALSE);
7064 flush_sequence();
7065 SendMessageA(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, 0);
7066 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
7067 ok_sequence(WmDisableButtonSeq, "Mouseclick on a disabled button", FALSE);
7069 DestroyWindow(hwnd);
7070 DestroyWindow(parent);
7073 static void test_button_bm_get_set_image(void)
7075 HWND hwnd;
7076 HDC hdc;
7077 HBITMAP hbmp1x1;
7078 HBITMAP hbmp2x2;
7079 HBITMAP hmask2x2;
7080 ICONINFO icon_info2x2;
7081 HICON hicon2x2;
7082 HBITMAP hbmp;
7083 HICON hicon;
7084 ICONINFO icon_info;
7085 BITMAP bm;
7086 DWORD default_style = BS_PUSHBUTTON | WS_TABSTOP | WS_POPUP | WS_VISIBLE;
7087 LRESULT ret;
7089 hdc = GetDC(0);
7090 hbmp1x1 = CreateCompatibleBitmap(hdc, 1, 1);
7091 hbmp2x2 = CreateCompatibleBitmap(hdc, 2, 2);
7092 ZeroMemory(&bm, sizeof(bm));
7093 ok(GetObjectW(hbmp1x1, sizeof(bm), &bm), "Expect GetObjectW() success\n");
7094 ok(bm.bmWidth == 1 && bm.bmHeight == 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
7095 bm.bmWidth, bm.bmHeight);
7096 ZeroMemory(&bm, sizeof(bm));
7097 ok(GetObjectW(hbmp2x2, sizeof(bm), &bm), "Expect GetObjectW() success\n");
7098 ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
7099 bm.bmWidth, bm.bmHeight);
7101 hmask2x2 = CreateCompatibleBitmap(hdc, 2, 2);
7102 ZeroMemory(&icon_info2x2, sizeof(icon_info2x2));
7103 icon_info2x2.fIcon = TRUE;
7104 icon_info2x2.hbmMask = hmask2x2;
7105 icon_info2x2.hbmColor = hbmp2x2;
7106 hicon2x2 = CreateIconIndirect(&icon_info2x2);
7108 ZeroMemory(&icon_info, sizeof(icon_info));
7109 ok(GetIconInfo(hicon2x2, &icon_info), "Expect GetIconInfo() success\n");
7110 ZeroMemory(&bm, sizeof(bm));
7111 ok(GetObjectW(icon_info.hbmColor, sizeof(bm), &bm), "Expect GetObjectW() success\n");
7112 ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
7113 bm.bmWidth, bm.bmHeight);
7114 DeleteObject(icon_info.hbmColor);
7115 DeleteObject(icon_info.hbmMask);
7117 /* Set bitmap with BS_BITMAP */
7118 hwnd = CreateWindowA("Button", "test", default_style | BS_BITMAP, 0, 0, 100, 100, 0, 0, 0, 0);
7119 ok(hwnd != NULL, "Expect hwnd not NULL\n");
7120 SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp1x1);
7121 hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_BITMAP, 0);
7122 ok(hbmp != 0, "Expect hbmp not 0\n");
7123 ZeroMemory(&bm, sizeof(bm));
7124 ok(GetObjectW(hbmp, sizeof(bm), &bm), "Expect GetObjectW() success\n");
7125 ok(bm.bmWidth == 1 && bm.bmHeight == 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
7126 bm.bmWidth, bm.bmHeight);
7127 DestroyWindow(hwnd);
7129 /* Set bitmap without BS_BITMAP */
7130 hwnd = CreateWindowA("Button", "test", default_style, 0, 0, 100, 100, 0, 0, 0, 0);
7131 ok(hwnd != NULL, "Expect hwnd not NULL\n");
7132 ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp1x1);
7133 ok(ret == 0, "Expect ret to be 0\n");
7134 hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_BITMAP, 0);
7135 ok(hbmp == NULL, "Expect hbmp to be NULL\n");
7136 DestroyWindow(hwnd);
7138 /* Set icon with BS_ICON */
7139 hwnd = CreateWindowA("Button", "test", default_style | BS_ICON, 0, 0, 100, 100, 0, 0, 0, 0);
7140 ok(hwnd != NULL, "Expect hwnd not NULL\n");
7141 SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicon2x2);
7142 hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_ICON, 0);
7143 ok(hicon != NULL, "Expect hicon not NULL\n");
7144 ZeroMemory(&icon_info, sizeof(icon_info));
7145 ok(GetIconInfo(hicon, &icon_info), "Expect GetIconInfo() success\n");
7146 ZeroMemory(&bm, sizeof(bm));
7147 ok(GetObjectW(icon_info.hbmColor, sizeof(bm), &bm), "Expect GetObjectW() success\n");
7148 ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
7149 bm.bmWidth, bm.bmHeight);
7150 DeleteObject(icon_info.hbmColor);
7151 DeleteObject(icon_info.hbmMask);
7152 DestroyWindow(hwnd);
7154 /* Set icon without BS_ICON */
7155 hwnd = CreateWindowA("Button", "test", default_style, 0, 0, 100, 100, 0, 0, 0, 0);
7156 ok(hwnd != NULL, "Expect hwnd not NULL\n");
7157 ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicon2x2);
7158 ok(ret == 0, "Expect ret to be 0\n");
7159 hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_ICON, 0);
7160 ok(hicon == NULL, "Expect hicon to be NULL\n");
7161 DestroyWindow(hwnd);
7163 /* Set icon with BS_BITMAP */
7164 hwnd = CreateWindowA("Button", "test", default_style | BS_BITMAP, 0, 0, 100, 100, 0, 0, 0, 0);
7165 ok(hwnd != NULL, "Expect hwnd to be not NULL\n");
7166 ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicon2x2);
7167 ok(ret == 0, "Expect ret to be 0\n");
7168 hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_ICON, 0);
7169 ok(hicon == NULL, "Expect hicon to be NULL\n");
7170 DestroyWindow(hwnd);
7172 /* Set bitmap with BS_ICON */
7173 hwnd = CreateWindowA("Button", "test", default_style | BS_ICON, 0, 0, 100, 100, 0, 0, 0, 0);
7174 ok(hwnd != NULL, "Expect hwnd to be not NULL\n");
7175 ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp1x1);
7176 ok(ret == 0, "Expect ret to be 0\n");
7177 hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_BITMAP, 0);
7178 ok(hbmp == NULL, "Expect hbmp to be NULL\n");
7179 DestroyWindow(hwnd);
7181 DestroyIcon(hicon2x2);
7182 DeleteObject(hmask2x2);
7183 DeleteObject(hbmp2x2);
7184 DeleteObject(hbmp1x1);
7185 ReleaseDC(0, hdc);
7188 #define ID_RADIO1 501
7189 #define ID_RADIO2 502
7190 #define ID_RADIO3 503
7191 #define ID_TEXT 504
7193 static const struct message auto_radio_button_BM_CLICK[] =
7195 { BM_CLICK, sent|wparam|lparam, 0, 0 },
7196 { WM_LBUTTONDOWN, sent|wparam|lparam|defwinproc, 0, 0 },
7197 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
7198 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO2 },
7199 { WM_CTLCOLORSTATIC, sent|parent },
7200 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
7201 { WM_LBUTTONUP, sent|wparam|lparam|defwinproc, 0, 0 },
7202 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO2 },
7203 { WM_CTLCOLORSTATIC, sent|parent },
7204 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
7205 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO2, 0 },
7206 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO2 },
7207 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO1, 0 },
7208 { BM_SETCHECK, sent|wparam|lparam|defwinproc, 0, ID_RADIO1 },
7209 { WM_CTLCOLORSTATIC, sent|parent },
7210 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
7211 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO3, 0 },
7212 { BM_SETCHECK, sent|wparam|lparam|defwinproc, 0, ID_RADIO3 },
7213 { WM_CTLCOLORSTATIC, sent|parent },
7214 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
7215 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_TEXT, 0 },
7216 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
7217 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
7218 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO2, BN_CLICKED) },
7219 { WM_NCHITTEST, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
7220 { WM_SETCURSOR, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
7221 { WM_MOUSEMOVE, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
7222 { 0 }
7225 static const struct message auto_radio_button_VK_UP_child[] =
7227 { WM_KEYDOWN, sent|wparam|lparam, VK_UP, 0 },
7228 { WM_KEYUP, sent|wparam|lparam, VK_UP, 0 },
7229 { 0 }
7232 static const struct message auto_radio_button_VK_UP_parent[] =
7234 { WM_KEYDOWN, sent|wparam|lparam|parent, VK_UP, 0 },
7235 { WM_KEYUP, sent|wparam|lparam|parent, VK_UP, 0 },
7236 { 0 }
7239 static const struct message auto_radio_button_VK_UP_dialog[] =
7241 { WM_GETDLGCODE, sent|parent, 0, 0 },
7243 /* optional trailer seen on some windows setups */
7244 { WM_CHANGEUISTATE, sent|optional },
7245 { WM_UPDATEUISTATE, sent|optional },
7246 { WM_UPDATEUISTATE, sent|optional },
7247 { WM_UPDATEUISTATE, sent|optional },
7248 { WM_UPDATEUISTATE, sent|optional },
7249 { WM_UPDATEUISTATE, sent|optional },
7250 { WM_UPDATEUISTATE, sent|optional },
7251 { WM_UPDATEUISTATE, sent|optional },
7252 { WM_UPDATEUISTATE, sent|optional },
7253 { WM_UPDATEUISTATE, sent|optional },
7254 { WM_UPDATEUISTATE, sent|optional },
7255 { WM_UPDATEUISTATE, sent|optional },
7256 { WM_UPDATEUISTATE, sent|optional },
7257 { WM_UPDATEUISTATE, sent|optional },
7258 { WM_UPDATEUISTATE, sent|optional },
7259 { WM_UPDATEUISTATE, sent|optional },
7260 { WM_UPDATEUISTATE, sent|optional },
7261 { WM_UPDATEUISTATE, sent|optional },
7262 { WM_UPDATEUISTATE, sent|optional },
7263 { WM_CTLCOLORSTATIC, sent|parent|optional },
7264 { WM_CTLCOLORSTATIC, sent|parent|optional },
7265 { WM_CTLCOLORSTATIC, sent|parent|optional },
7266 { WM_UPDATEUISTATE, sent|optional },
7267 { WM_CTLCOLORSTATIC, sent|parent|optional },
7268 { WM_CTLCOLORSTATIC, sent|parent|optional },
7269 { WM_UPDATEUISTATE, sent|optional },
7270 { WM_CTLCOLORBTN, sent|parent|optional },
7271 { WM_CTLCOLORBTN, sent|parent|optional },
7272 { WM_UPDATEUISTATE, sent|optional },
7273 { WM_CTLCOLORSTATIC, sent|parent|optional },
7274 { WM_CTLCOLORSTATIC, sent|parent|optional },
7275 { 0 }
7278 static const struct message auto_radio_button_VK_DOWN_dialog[] =
7280 { WM_GETDLGCODE, sent|parent, 0, 0 },
7281 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, MAKELPARAM(WM_KEYDOWN, VK_DOWN) },
7282 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
7283 { HCBT_SETFOCUS, hook },
7284 { WM_KILLFOCUS, sent, 0, 0 },
7285 { WM_CTLCOLORSTATIC, sent|parent },
7286 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO3, BN_KILLFOCUS) },
7287 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7288 { WM_SETFOCUS, sent, 0, 0 },
7289 { WM_CTLCOLORSTATIC, sent|parent },
7290 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_SETFOCUS) },
7291 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_CLICKED) },
7292 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
7293 { WM_GETDLGCODE, sent|parent, 0, 0 },
7294 { DM_GETDEFID, sent|parent, 0, 0 },
7295 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
7296 { BM_CLICK, sent|wparam|lparam, 1, 0 },
7297 { WM_LBUTTONDOWN, sent|wparam|lparam|defwinproc, 0, 0 },
7298 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
7299 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO1 },
7300 { WM_CTLCOLORSTATIC, sent|parent },
7301 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
7302 { WM_LBUTTONUP, sent|wparam|lparam|defwinproc, 0, 0 },
7303 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO1 },
7304 { WM_CTLCOLORSTATIC, sent|parent },
7305 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
7306 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO1, 0 },
7307 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO1 },
7308 { WM_CTLCOLORSTATIC, sent|parent },
7309 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
7310 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO3, 0 },
7311 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO3 },
7312 { WM_CTLCOLORSTATIC, sent|parent },
7313 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
7314 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_TEXT, 0 },
7315 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO2, 0 },
7316 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO2 },
7317 { WM_CTLCOLORSTATIC, sent|parent },
7318 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
7319 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
7320 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
7321 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_CLICKED) },
7322 { WM_NCHITTEST, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
7323 { WM_SETCURSOR, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
7324 { WM_MOUSEMOVE, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
7325 { WM_PAINT, sent },
7326 { WM_CTLCOLORSTATIC, sent|parent },
7327 { 0 }
7330 static const struct message auto_radio_button_VK_DOWN_radio3[] =
7332 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
7333 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO2 },
7334 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO3 },
7335 { WM_GETDLGCODE, sent|parent, 0, 0 },
7336 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, MAKELPARAM(WM_KEYDOWN, VK_DOWN) },
7337 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
7338 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
7339 { WM_GETDLGCODE, sent|wparam|lparam|parent, 0, 0 },
7340 { WM_USER, sent|parent, 0, 0 },
7341 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
7342 { 0 }
7345 static const struct message auto_radio_button_VK_UP_radio1[] =
7347 { WM_GETDLGCODE, sent|parent, 0, 0 },
7348 { 0 }
7351 static INT_PTR WINAPI radio_test_dlg_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
7353 ParentMsgCheckProcA(hwnd, msg, wp, lp);
7354 return 1;
7357 static void test_autoradio_BM_CLICK(void)
7359 HWND parent, radio1, radio2, radio3;
7360 RECT rc;
7361 MSG msg;
7362 DWORD ret;
7364 subclass_button();
7366 parent = CreateDialogParamA(0, "AUTORADIO_TEST_DIALOG_1", 0, radio_test_dlg_proc, 0);
7367 ok(parent != 0, "failed to create parent window\n");
7369 radio1 = GetDlgItem(parent, ID_RADIO1);
7370 radio2 = GetDlgItem(parent, ID_RADIO2);
7371 radio3 = GetDlgItem(parent, ID_RADIO3);
7373 /* this avoids focus messages in the generated sequence */
7374 SetFocus(radio2);
7376 flush_events();
7377 flush_sequence();
7379 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
7380 ok(ret == BST_UNCHECKED, "got %08lx\n", ret);
7381 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
7382 ok(ret == BST_UNCHECKED, "got %08lx\n", ret);
7383 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
7384 ok(ret == BST_UNCHECKED, "got %08lx\n", ret);
7386 SendMessageA(radio1, BM_SETCHECK, BST_CHECKED, 0);
7388 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
7389 ok(ret == BST_CHECKED, "got %08lx\n", ret);
7390 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
7391 ok(ret == BST_UNCHECKED, "got %08lx\n", ret);
7392 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
7393 ok(ret == BST_UNCHECKED, "got %08lx\n", ret);
7395 SendMessageA(radio2, BM_SETCHECK, BST_CHECKED, 0);
7397 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
7398 ok(ret == BST_CHECKED, "got %08lx\n", ret);
7399 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
7400 ok(ret == BST_CHECKED, "got %08lx\n", ret);
7401 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
7402 ok(ret == BST_UNCHECKED, "got %08lx\n", ret);
7404 SendMessageA(radio3, BM_SETCHECK, BST_CHECKED, 0);
7406 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
7407 ok(ret == BST_CHECKED, "got %08lx\n", ret);
7408 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
7409 ok(ret == BST_CHECKED, "got %08lx\n", ret);
7410 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
7411 ok(ret == BST_CHECKED, "got %08lx\n", ret);
7413 GetWindowRect(radio2, &rc);
7414 SetCursorPos(rc.left+1, rc.top+1);
7416 flush_events();
7417 flush_sequence();
7419 log_all_parent_messages++;
7421 SendMessageA(radio2, BM_CLICK, 0, 0);
7422 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7423 ok_sequence(auto_radio_button_BM_CLICK, "BM_CLICK on auto-radio button", FALSE);
7425 log_all_parent_messages--;
7427 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
7428 ok(ret == BST_UNCHECKED, "got %08lx\n", ret);
7429 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
7430 ok(ret == BST_CHECKED, "got %08lx\n", ret);
7431 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
7432 ok(ret == BST_UNCHECKED, "got %08lx\n", ret);
7434 DestroyWindow(parent);
7437 #define test_radio(r1, s1, r2, s2, r3, s3) test_radio_dbg(r1, s1, r2, s2, r3, s3, __LINE__)
7438 static void test_radio_dbg(HWND radio1, int state1, HWND radio2, int state2, HWND radio3, int state3, int line)
7440 DWORD ret;
7442 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
7443 ok_(__FILE__,line)(ret == state1 ? BST_CHECKED : BST_UNCHECKED, "got %08lx\n", ret);
7444 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
7445 ok_(__FILE__,line)(ret == state2 ? BST_CHECKED : BST_UNCHECKED, "got %08lx\n", ret);
7446 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
7447 ok_(__FILE__,line)(ret == state3 ? BST_CHECKED : BST_UNCHECKED, "got %08lx\n", ret);
7450 static void set_radio(HWND radio1, int state1, HWND radio2, int state2, HWND radio3, int state3)
7452 SendMessageA(radio1, BM_SETCHECK, state1 ? BST_CHECKED : BST_UNCHECKED, 0);
7453 SendMessageA(radio2, BM_SETCHECK, state2 ? BST_CHECKED : BST_UNCHECKED, 0);
7454 SendMessageA(radio3, BM_SETCHECK, state3 ? BST_CHECKED : BST_UNCHECKED, 0);
7457 static void test_autoradio_kbd_move(void)
7459 HWND parent, radio1, radio2, radio3, hwnd;
7460 RECT rc;
7461 MSG msg;
7462 DWORD ret;
7464 subclass_button();
7466 parent = CreateDialogParamA(0, "AUTORADIO_TEST_DIALOG_2", 0, radio_test_dlg_proc, 0);
7467 ok(parent != 0, "failed to create parent window\n");
7469 radio1 = GetDlgItem(parent, ID_RADIO1);
7470 radio2 = GetDlgItem(parent, ID_RADIO2);
7471 radio3 = GetDlgItem(parent, ID_RADIO3);
7473 flush_events();
7474 flush_sequence();
7476 test_radio(radio1, 0, radio2, 0, radio3, 0);
7477 set_radio(radio1, 1, radio2, 1, radio3, 1);
7478 test_radio(radio1, 1, radio2, 1, radio3, 1);
7480 SetFocus(radio3);
7482 flush_events();
7483 flush_sequence();
7485 log_all_parent_messages++;
7487 SendMessageA(radio3, WM_KEYDOWN, VK_UP, 0);
7488 SendMessageA(radio3, WM_KEYUP, VK_UP, 0);
7489 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7490 ok_sequence(auto_radio_button_VK_UP_child, "press/release VK_UP on auto-radio button", FALSE);
7492 test_radio(radio1, 1, radio2, 1, radio3, 1);
7494 flush_events();
7495 flush_sequence();
7497 DefDlgProcA(parent, WM_KEYDOWN, VK_UP, 0);
7498 DefDlgProcA(parent, WM_KEYUP, VK_UP, 0);
7499 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7500 ok_sequence(auto_radio_button_VK_UP_parent, "press/release VK_UP on dialog", FALSE);
7502 test_radio(radio1, 1, radio2, 1, radio3, 1);
7504 SetFocus(radio3);
7505 GetWindowRect(radio3, &rc);
7507 flush_events();
7508 flush_sequence();
7510 msg.hwnd = parent;
7511 msg.message = WM_KEYDOWN;
7512 msg.wParam = VK_UP;
7513 msg.lParam = 0;
7514 msg.pt.x = rc.left + 1;
7515 msg.pt.y = rc.top + 1;
7516 ret = IsDialogMessageA(parent, &msg);
7517 ok(ret, "IsDialogMessage should return TRUE\n");
7518 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7519 if (0) /* actual message sequence is different on every run in some Windows setups */
7520 ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #1", FALSE);
7521 /* what really matters is that nothing has changed */
7522 test_radio(radio1, 1, radio2, 1, radio3, 1);
7524 set_radio(radio1, 0, radio2, 1, radio3, 1);
7525 test_radio(radio1, 0, radio2, 1, radio3, 1);
7527 flush_events();
7528 flush_sequence();
7530 ret = IsDialogMessageA(parent, &msg);
7531 ok(ret, "IsDialogMessage should return TRUE\n");
7532 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7533 if (0) /* actual message sequence is different on every run in some Windows setups */
7534 ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #2", FALSE);
7535 /* what really matters is that nothing has changed */
7536 test_radio(radio1, 0, radio2, 1, radio3, 1);
7538 /* switch from radio3 ro radio1 */
7539 SetFocus(radio3);
7540 GetWindowRect(radio3, &rc);
7542 flush_events();
7543 flush_sequence();
7545 msg.hwnd = parent;
7546 msg.message = WM_KEYDOWN;
7547 msg.wParam = VK_DOWN;
7548 msg.lParam = 0;
7549 msg.pt.x = rc.left + 1;
7550 msg.pt.y = rc.top + 1;
7551 ret = IsDialogMessageA(parent, &msg);
7552 ok(ret, "IsDialogMessage should return TRUE\n");
7553 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7554 ok_sequence(auto_radio_button_VK_DOWN_dialog, "IsDialogMessage(VK_DOWN)", TRUE);
7556 test_radio(radio1, 1, radio2, 0, radio3, 0);
7558 hwnd = GetFocus();
7559 ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
7560 GetWindowRect(radio1, &rc);
7562 msg.hwnd = parent;
7563 msg.message = WM_KEYDOWN;
7564 msg.wParam = VK_DOWN;
7565 msg.lParam = 0;
7566 msg.pt.x = rc.left + 1;
7567 msg.pt.y = rc.top + 1;
7568 ret = IsDialogMessageA(parent, &msg);
7569 ok(ret, "IsDialogMessage should return TRUE\n");
7570 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7571 ok_sequence(auto_radio_button_VK_DOWN_radio3, "down to radio3", TRUE);
7573 test_radio(radio1, 1, radio2, 0, radio3, 0);
7575 hwnd = GetFocus();
7576 ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
7578 flush_events();
7579 flush_sequence();
7581 msg.hwnd = parent;
7582 msg.message = WM_KEYDOWN;
7583 msg.wParam = VK_UP;
7584 msg.lParam = 0;
7585 msg.pt.x = rc.left + 1;
7586 msg.pt.y = rc.top + 1;
7587 ret = IsDialogMessageA(parent, &msg);
7588 ok(ret, "IsDialogMessage should return TRUE\n");
7589 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7590 ok_sequence(auto_radio_button_VK_UP_radio1, "up to radio1", TRUE);
7592 test_radio(radio1, 1, radio2, 0, radio3, 0);
7594 hwnd = GetFocus();
7595 ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
7597 flush_events();
7598 flush_sequence();
7600 msg.hwnd = parent;
7601 msg.message = WM_KEYDOWN;
7602 msg.wParam = VK_UP;
7603 msg.lParam = 0;
7604 msg.pt.x = rc.left + 1;
7605 msg.pt.y = rc.top + 1;
7606 ret = IsDialogMessageA(parent, &msg);
7607 ok(ret, "IsDialogMessage should return TRUE\n");
7608 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7609 if (0) /* actual message sequence is different on every run in some Windows setups */
7610 ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #3", FALSE);
7611 /* what really matters is that nothing has changed */
7612 test_radio(radio1, 1, radio2, 0, radio3, 0);
7614 log_all_parent_messages--;
7616 DestroyWindow(parent);
7619 /****************** static message test *************************/
7620 static const struct message WmSetFontStaticSeq2[] =
7622 { WM_SETFONT, sent },
7623 { WM_PAINT, sent|defwinproc|optional },
7624 { WM_ERASEBKGND, sent|defwinproc|optional },
7625 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
7626 { 0 }
7629 static WNDPROC old_static_proc;
7631 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7633 static LONG defwndproc_counter = 0;
7634 LRESULT ret;
7635 struct recvd_message msg;
7637 if (ignore_message( message )) return 0;
7639 msg.hwnd = hwnd;
7640 msg.message = message;
7641 msg.flags = sent|wparam|lparam;
7642 if (defwndproc_counter) msg.flags |= defwinproc;
7643 msg.wParam = wParam;
7644 msg.lParam = lParam;
7645 msg.descr = "static";
7646 add_message(&msg);
7648 defwndproc_counter++;
7649 ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
7650 defwndproc_counter--;
7652 return ret;
7655 static void subclass_static(void)
7657 WNDCLASSA cls;
7659 if (!GetClassInfoA(0, "static", &cls)) assert(0);
7661 old_static_proc = cls.lpfnWndProc;
7663 cls.hInstance = GetModuleHandleA(NULL);
7664 cls.lpfnWndProc = static_hook_proc;
7665 cls.lpszClassName = "my_static_class";
7666 UnregisterClassA(cls.lpszClassName, cls.hInstance);
7667 if (!RegisterClassA(&cls)) assert(0);
7670 static void test_static_messages(void)
7672 /* FIXME: make as comprehensive as the button message test */
7673 static const struct
7675 DWORD style;
7676 DWORD dlg_code;
7677 const struct message *setfont;
7678 } static_ctrl[] = {
7679 { SS_LEFT, DLGC_STATIC,
7680 WmSetFontStaticSeq2 }
7682 unsigned int i;
7683 HWND hwnd;
7684 DWORD dlg_code;
7686 subclass_static();
7688 for (i = 0; i < ARRAY_SIZE(static_ctrl); i++)
7690 hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
7691 0, 0, 50, 14, 0, 0, 0, NULL);
7692 ok(hwnd != 0, "Failed to create static window\n");
7694 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
7695 ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08lx\n", i, dlg_code);
7697 ShowWindow(hwnd, SW_SHOW);
7698 UpdateWindow(hwnd);
7699 SetFocus(0);
7700 flush_sequence();
7702 trace("static style %08lx\n", static_ctrl[i].style);
7703 SendMessageA(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
7704 ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
7706 DestroyWindow(hwnd);
7710 /****************** ComboBox message test *************************/
7711 #define ID_COMBOBOX 0x000f
7713 static const struct message SetCurSelComboSeq[] =
7715 { CB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7716 { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7717 { LB_SETTOPINDEX, sent|wparam|lparam, 0, 0 },
7718 { LB_GETCURSEL, sent|wparam|lparam, 0, 0 },
7719 { LB_GETTEXTLEN, sent|wparam|lparam, 0, 0 },
7720 { LB_GETTEXTLEN, sent|wparam|lparam|optional, 0, 0 }, /* TODO: it's sent on all Windows versions */
7721 { LB_GETTEXT, sent|wparam, 0 },
7722 { WM_CTLCOLOREDIT, sent|parent },
7723 { LB_GETITEMDATA, sent|wparam|lparam, 0, 0 },
7724 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_COMBOBOX, 0x100010f3 },
7725 { 0 }
7728 static const struct message SetCurSelComboSeq2[] =
7730 { CB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7731 { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7732 { LB_SETTOPINDEX, sent|wparam|lparam, 0, 0 },
7733 { LB_GETCURSEL, sent|wparam|lparam, 0, 0 },
7734 { LB_GETTEXTLEN, sent|wparam|lparam, 0, 0 },
7735 { LB_GETTEXTLEN, sent|wparam|lparam|optional, 0, 0 }, /* TODO: it's sent on all Windows versions */
7736 { LB_GETTEXT, sent|wparam, 0 },
7737 { 0 }
7740 static const struct message SetCurSelComboSeq_edit[] =
7742 { CB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7743 { WM_SETTEXT, sent|wparam, 0 },
7744 { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
7745 { 0 }
7748 static const struct message WmKeyDownComboSeq[] =
7750 { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
7751 { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
7752 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
7753 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
7754 { WM_CTLCOLOREDIT, sent|parent },
7755 { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
7756 { 0 }
7759 static const struct message WmSetPosComboSeq[] =
7761 { WM_WINDOWPOSCHANGING, sent },
7762 { WM_NCCALCSIZE, sent|wparam, TRUE },
7763 { WM_CHILDACTIVATE, sent },
7764 { WM_WINDOWPOSCHANGED, sent },
7765 { WM_MOVE, sent|defwinproc },
7766 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
7767 { WM_WINDOWPOSCHANGING, sent|defwinproc },
7768 { WM_NCCALCSIZE, sent|defwinproc|wparam, TRUE },
7769 { WM_WINDOWPOSCHANGED, sent|defwinproc },
7770 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
7771 { 0 }
7774 static const struct message WMSetFocusComboBoxSeq[] =
7776 { WM_SETFOCUS, sent },
7777 { WM_KILLFOCUS, sent|parent },
7778 { WM_SETFOCUS, sent },
7779 { WM_COMMAND, sent|defwinproc|wparam, MAKEWPARAM(1001, EN_SETFOCUS) },
7780 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, INT_MAX },
7781 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7782 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7783 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SETFOCUS) },
7784 { 0 }
7787 static const struct message SetFocusButtonSeq[] =
7789 { WM_KILLFOCUS, sent },
7790 { CB_GETCOMBOBOXINFO, sent|optional },/* Windows 2000 */
7791 { 0x0167, sent|optional },/* Undocumented message. Sent on all versions except Windows 2000 */
7792 { WM_LBUTTONUP, sent|defwinproc },
7793 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDCANCEL) },
7794 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, 0 },
7795 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7796 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7797 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_KILLFOCUS) },
7798 { WM_CTLCOLORBTN, sent|parent },
7799 { 0 }
7802 static const struct message SetFocusComboBoxSeq[] =
7804 { WM_CTLCOLORBTN, sent|parent },
7805 { WM_SETFOCUS, sent },
7806 { WM_KILLFOCUS, sent|defwinproc },
7807 { WM_SETFOCUS, sent },
7808 { WM_COMMAND, sent|defwinproc|wparam, MAKEWPARAM(1001, EN_SETFOCUS) },
7809 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, INT_MAX },
7810 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7811 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7812 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SETFOCUS) },
7813 { 0 }
7816 static const struct message SetFocusButtonSeq2[] =
7818 { WM_KILLFOCUS, sent },
7819 { CB_GETCOMBOBOXINFO, sent|optional },/* Windows 2000 */
7820 { 0x0167, sent|optional },/* Undocumented message. Sent on all versions except Windows 2000 */
7821 { WM_LBUTTONUP, sent|defwinproc },
7822 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDCANCEL) },
7823 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, 0 },
7824 { WM_CTLCOLOREDIT, sent|defwinproc },
7825 { WM_CTLCOLOREDIT, sent|parent },
7826 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_KILLFOCUS) },
7827 { WM_CTLCOLORBTN, sent|parent },
7828 { 0 }
7831 static WNDPROC old_combobox_proc, edit_window_proc, lbox_window_proc;
7833 static LRESULT CALLBACK combobox_edit_subclass_proc(HWND hwnd, UINT message,
7834 WPARAM wParam, LPARAM lParam)
7836 static LONG defwndproc_counter = 0;
7837 LRESULT ret;
7838 struct recvd_message msg;
7840 /* do not log painting messages */
7841 if (message != WM_PAINT &&
7842 message != WM_NCPAINT &&
7843 message != WM_SYNCPAINT &&
7844 message != WM_ERASEBKGND &&
7845 message != WM_NCHITTEST &&
7846 message != WM_GETTEXT &&
7847 !ignore_message( message ))
7849 msg.hwnd = hwnd;
7850 msg.message = message;
7851 msg.flags = sent|wparam|lparam;
7852 if (defwndproc_counter) msg.flags |= defwinproc;
7853 msg.wParam = wParam;
7854 msg.lParam = lParam;
7855 msg.descr = "combo edit";
7856 add_message(&msg);
7859 defwndproc_counter++;
7860 ret = CallWindowProcA(edit_window_proc, hwnd, message, wParam, lParam);
7861 defwndproc_counter--;
7863 return ret;
7866 static LRESULT CALLBACK combobox_lbox_subclass_proc(HWND hwnd, UINT message,
7867 WPARAM wParam, LPARAM lParam)
7869 static LONG defwndproc_counter = 0;
7870 LRESULT ret;
7871 struct recvd_message msg;
7873 /* do not log painting messages */
7874 if (message != WM_PAINT &&
7875 message != WM_NCPAINT &&
7876 message != WM_SYNCPAINT &&
7877 message != WM_ERASEBKGND &&
7878 message != WM_NCHITTEST &&
7879 !ignore_message( message ))
7881 msg.hwnd = hwnd;
7882 msg.message = message;
7883 msg.flags = sent|wparam|lparam;
7884 if (defwndproc_counter) msg.flags |= defwinproc;
7885 msg.wParam = wParam;
7886 msg.lParam = lParam;
7887 msg.descr = "combo lbox";
7888 add_message(&msg);
7891 defwndproc_counter++;
7892 ret = CallWindowProcA(lbox_window_proc, hwnd, message, wParam, lParam);
7893 defwndproc_counter--;
7895 return ret;
7898 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7900 static LONG defwndproc_counter = 0;
7901 LRESULT ret;
7902 struct recvd_message msg;
7904 /* do not log painting messages */
7905 if (message != WM_PAINT &&
7906 message != WM_NCPAINT &&
7907 message != WM_SYNCPAINT &&
7908 message != WM_ERASEBKGND &&
7909 message != WM_NCHITTEST &&
7910 message != WM_GETTEXT &&
7911 !ignore_message( message ))
7913 msg.hwnd = hwnd;
7914 msg.message = message;
7915 msg.flags = sent|wparam|lparam;
7916 if (defwndproc_counter) msg.flags |= defwinproc;
7917 msg.wParam = wParam;
7918 msg.lParam = lParam;
7919 msg.descr = "combo";
7920 add_message(&msg);
7923 defwndproc_counter++;
7924 ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
7925 defwndproc_counter--;
7927 return ret;
7930 static void subclass_combobox(void)
7932 WNDCLASSA cls;
7934 if (!GetClassInfoA(0, "ComboBox", &cls)) assert(0);
7936 old_combobox_proc = cls.lpfnWndProc;
7938 cls.hInstance = GetModuleHandleA(NULL);
7939 cls.lpfnWndProc = combobox_hook_proc;
7940 cls.lpszClassName = "my_combobox_class";
7941 UnregisterClassA(cls.lpszClassName, cls.hInstance);
7942 if (!RegisterClassA(&cls)) assert(0);
7945 static void test_combobox_messages(void)
7947 HWND parent, combo, button, edit, lbox;
7948 LRESULT ret;
7949 COMBOBOXINFO cbInfo;
7950 BOOL res;
7952 subclass_combobox();
7954 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7955 100, 100, 200, 200, 0, 0, 0, NULL);
7956 ok(parent != 0, "Failed to create parent window\n");
7957 flush_sequence();
7959 combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
7960 0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
7961 ok(combo != 0, "Failed to create combobox window\n");
7963 UpdateWindow(combo);
7965 ret = SendMessageA(combo, WM_GETDLGCODE, 0, 0);
7966 ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08Ix\n", ret);
7968 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
7969 ok(ret == 0, "expected 0, got %Id\n", ret);
7970 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
7971 ok(ret == 1, "expected 1, got %Id\n", ret);
7972 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
7973 ok(ret == 2, "expected 2, got %Id\n", ret);
7975 SendMessageA(combo, CB_SETCURSEL, 0, 0);
7976 SetFocus(combo);
7977 flush_sequence();
7979 log_all_parent_messages++;
7980 SendMessageA(combo, WM_KEYDOWN, VK_DOWN, 0);
7981 SendMessageA(combo, WM_KEYUP, VK_DOWN, 0);
7982 log_all_parent_messages--;
7983 ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
7985 flush_sequence();
7986 SetWindowPos(combo, 0, 10, 10, 120, 130, SWP_NOZORDER);
7987 ok_sequence(WmSetPosComboSeq, "repositioning messages on a ComboBox", FALSE);
7989 DestroyWindow(combo);
7990 DestroyWindow(parent);
7992 /* Start again. Test combobox text selection when getting and losing focus */
7993 parent = CreateWindowExA(0, "TestParentClass", "Parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7994 10, 10, 300, 300, NULL, NULL, NULL, NULL);
7995 ok(parent != 0, "Failed to create parent window\n");
7997 combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWN,
7998 5, 5, 100, 100, parent, (HMENU)ID_COMBOBOX, NULL, NULL);
7999 ok(combo != 0, "Failed to create combobox window\n");
8001 cbInfo.cbSize = sizeof(COMBOBOXINFO);
8002 SetLastError(0xdeadbeef);
8003 res = GetComboBoxInfo(combo, &cbInfo);
8004 ok(res, "Failed to get COMBOBOXINFO structure; LastError: %lu\n", GetLastError());
8005 edit = cbInfo.hwndItem;
8007 edit_window_proc = (WNDPROC)SetWindowLongPtrA(edit, GWLP_WNDPROC,
8008 (ULONG_PTR)combobox_edit_subclass_proc);
8010 button = CreateWindowExA(0, "Button", "OK", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
8011 5, 50, 100, 20, parent, NULL,
8012 (HINSTANCE)GetWindowLongPtrA(parent, GWLP_HINSTANCE), NULL);
8013 ok(button != 0, "Failed to create button window\n");
8015 flush_sequence();
8016 log_all_parent_messages++;
8017 SendMessageA(combo, WM_SETFOCUS, 0, (LPARAM)edit);
8018 log_all_parent_messages--;
8019 ok_sequence(WMSetFocusComboBoxSeq, "WM_SETFOCUS on a ComboBox", TRUE);
8021 flush_sequence();
8022 log_all_parent_messages++;
8023 SetFocus(button);
8024 log_all_parent_messages--;
8025 ok_sequence(SetFocusButtonSeq, "SetFocus on a Button", TRUE);
8027 SendMessageA(combo, WM_SETTEXT, 0, (LPARAM)"Wine Test");
8029 flush_sequence();
8030 log_all_parent_messages++;
8031 SetFocus(combo);
8032 log_all_parent_messages--;
8033 ok_sequence(SetFocusComboBoxSeq, "SetFocus on a ComboBox", TRUE);
8035 flush_sequence();
8036 log_all_parent_messages++;
8037 SetFocus(button);
8038 log_all_parent_messages--;
8039 ok_sequence(SetFocusButtonSeq2, "SetFocus on a Button (2)", TRUE);
8041 SetFocus(combo);
8042 SendMessageA(combo, WM_SETREDRAW, FALSE, 0);
8043 flush_sequence();
8044 log_all_parent_messages++;
8045 SendMessageA(combo, CB_SETCURSEL, 0, 0);
8046 log_all_parent_messages--;
8047 ok_sequence(SetCurSelComboSeq_edit, "CB_SETCURSEL on a ComboBox with edit control", FALSE);
8049 DestroyWindow(button);
8050 DestroyWindow(combo);
8052 combo = CreateWindowExA(0, "my_combobox_class", "test",
8053 WS_CHILD | WS_VISIBLE | CBS_OWNERDRAWFIXED | CBS_DROPDOWNLIST,
8054 5, 5, 100, 100, parent, (HMENU)ID_COMBOBOX, NULL, NULL);
8055 ok(combo != 0, "Failed to create combobox window\n");
8057 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
8058 ok(ret == 0, "expected 0, got %Id\n", ret);
8060 cbInfo.cbSize = sizeof(COMBOBOXINFO);
8061 SetLastError(0xdeadbeef);
8062 res = GetComboBoxInfo(combo, &cbInfo);
8063 ok(res, "Failed to get COMBOBOXINFO structure; LastError: %lu\n", GetLastError());
8064 lbox = cbInfo.hwndList;
8065 lbox_window_proc = (WNDPROC)SetWindowLongPtrA(lbox, GWLP_WNDPROC,
8066 (ULONG_PTR)combobox_lbox_subclass_proc);
8067 flush_sequence();
8069 log_all_parent_messages++;
8070 SendMessageA(combo, CB_SETCURSEL, 0, 0);
8071 log_all_parent_messages--;
8072 ok_sequence(SetCurSelComboSeq, "CB_SETCURSEL on a ComboBox", FALSE);
8074 ShowWindow(combo, SW_HIDE);
8075 flush_sequence();
8076 log_all_parent_messages++;
8077 SendMessageA(combo, CB_SETCURSEL, 0, 0);
8078 log_all_parent_messages--;
8079 ok_sequence(SetCurSelComboSeq2, "CB_SETCURSEL on a ComboBox", FALSE);
8081 DestroyWindow(combo);
8082 DestroyWindow(parent);
8085 /****************** WM_IME_KEYDOWN message test *******************/
8087 static const struct message WmImeKeydownMsgSeq_0[] =
8089 { WM_IME_KEYDOWN, wparam, VK_RETURN },
8090 { WM_CHAR, wparam, 'A' },
8091 { 0 }
8094 static const struct message WmImeKeydownMsgSeq_1[] =
8096 { WM_KEYDOWN, optional|wparam, VK_RETURN },
8097 { WM_CHAR, optional|wparam, VK_RETURN },
8098 { 0 }
8101 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8103 struct recvd_message msg;
8105 msg.hwnd = hwnd;
8106 msg.message = message;
8107 msg.flags = wparam|lparam;
8108 msg.wParam = wParam;
8109 msg.lParam = lParam;
8110 msg.descr = "wmime_keydown";
8111 add_message(&msg);
8113 return DefWindowProcA(hwnd, message, wParam, lParam);
8116 static void register_wmime_keydown_class(void)
8118 WNDCLASSA cls;
8120 ZeroMemory(&cls, sizeof(WNDCLASSA));
8121 cls.lpfnWndProc = wmime_keydown_procA;
8122 cls.hInstance = GetModuleHandleA(0);
8123 cls.lpszClassName = "wmime_keydown_class";
8124 if (!RegisterClassA(&cls)) assert(0);
8127 static void test_wmime_keydown_message(void)
8129 HWND hwnd;
8130 MSG msg;
8132 trace("Message sequences by WM_IME_KEYDOWN\n");
8134 register_wmime_keydown_class();
8135 hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
8136 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
8137 NULL, NULL, 0);
8138 flush_events();
8139 flush_sequence();
8141 SendMessageA(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
8142 SendMessageA(hwnd, WM_CHAR, 'A', 1);
8143 ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
8145 while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
8147 TranslateMessage(&msg);
8148 DispatchMessageA(&msg);
8150 ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
8152 DestroyWindow(hwnd);
8155 /************* painting message test ********************/
8157 void dump_region(HRGN hrgn)
8159 DWORD i, size;
8160 RGNDATA *data = NULL;
8161 RECT *rect;
8163 if (!hrgn)
8165 printf( "null region\n" );
8166 return;
8168 if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
8169 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
8170 GetRegionData( hrgn, size, data );
8171 printf("%ld rects:", data->rdh.nCount );
8172 for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
8173 printf( " %s", wine_dbgstr_rect( rect ));
8174 printf("\n");
8175 HeapFree( GetProcessHeap(), 0, data );
8178 #define check_update_rgn( hwnd, hrgn ) check_update_rgn_( __LINE__, hwnd, hrgn )
8179 static void check_update_rgn_( int line, HWND hwnd, HRGN hrgn )
8181 INT ret;
8182 RECT r1, r2;
8183 HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
8184 HRGN update = CreateRectRgn( 0, 0, 0, 0 );
8186 ret = GetUpdateRgn( hwnd, update, FALSE );
8187 ok( ret != ERROR, "GetUpdateRgn failed\n" );
8188 if (ret == NULLREGION)
8190 ok_(__FILE__,line)( !hrgn, "Update region shouldn't be empty\n" );
8192 else
8194 if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
8196 ok_(__FILE__,line)( 0, "Regions are different\n" );
8197 if (winetest_debug > 0)
8199 printf( "Update region: " );
8200 dump_region( update );
8201 printf( "Wanted region: " );
8202 dump_region( hrgn );
8206 GetRgnBox( update, &r1 );
8207 GetUpdateRect( hwnd, &r2, FALSE );
8208 ok_(__FILE__,line)( EqualRect( &r1, &r2 ), "Rectangles are different: %s / %s\n",
8209 wine_dbgstr_rect( &r1 ), wine_dbgstr_rect( &r2 ));
8211 DeleteObject( tmp );
8212 DeleteObject( update );
8215 static const struct message WmInvalidateRgn[] = {
8216 { WM_NCPAINT, sent },
8217 { WM_GETTEXT, sent|defwinproc|optional },
8218 { 0 }
8221 static const struct message WmGetUpdateRect[] = {
8222 { WM_NCPAINT, sent },
8223 { WM_GETTEXT, sent|defwinproc|optional },
8224 { WM_PAINT, sent },
8225 { 0 }
8228 static const struct message WmInvalidateFull[] = {
8229 { WM_NCPAINT, sent|wparam, 1 },
8230 { WM_GETTEXT, sent|defwinproc|optional },
8231 { 0 }
8234 static const struct message WmInvalidateErase[] = {
8235 { WM_NCPAINT, sent|wparam, 1 },
8236 { WM_GETTEXT, sent|defwinproc|optional },
8237 { WM_ERASEBKGND, sent },
8238 { 0 }
8241 static const struct message WmInvalidatePaint[] = {
8242 { WM_PAINT, sent },
8243 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
8244 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8245 { 0 }
8248 static const struct message WmInvalidateErasePaint[] = {
8249 { WM_PAINT, sent },
8250 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
8251 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8252 { WM_ERASEBKGND, sent|beginpaint|optional },
8253 { 0 }
8256 static const struct message WmInvalidateErasePaint2[] = {
8257 { WM_PAINT, sent },
8258 { WM_NCPAINT, sent|beginpaint },
8259 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8260 { WM_ERASEBKGND, sent|beginpaint|optional },
8261 { 0 }
8264 static const struct message WmErase[] = {
8265 { WM_ERASEBKGND, sent },
8266 { 0 }
8269 static const struct message WmPaint[] = {
8270 { WM_PAINT, sent },
8271 { 0 }
8274 static const struct message WmParentOnlyPaint[] = {
8275 { WM_PAINT, sent|parent },
8276 { 0 }
8279 static const struct message WmInvalidateParent[] = {
8280 { WM_NCPAINT, sent|parent },
8281 { WM_GETTEXT, sent|defwinproc|parent|optional },
8282 { WM_ERASEBKGND, sent|parent },
8283 { 0 }
8286 static const struct message WmInvalidateParentChild[] = {
8287 { WM_NCPAINT, sent|parent },
8288 { WM_GETTEXT, sent|defwinproc|parent|optional },
8289 { WM_ERASEBKGND, sent|parent },
8290 { WM_NCPAINT, sent },
8291 { WM_GETTEXT, sent|defwinproc|optional },
8292 { WM_ERASEBKGND, sent },
8293 { 0 }
8296 static const struct message WmInvalidateParentChild2[] = {
8297 { WM_ERASEBKGND, sent|parent },
8298 { WM_NCPAINT, sent },
8299 { WM_GETTEXT, sent|defwinproc|optional },
8300 { WM_ERASEBKGND, sent },
8301 { 0 }
8304 static const struct message WmParentPaint[] = {
8305 { WM_PAINT, sent|parent },
8306 { WM_PAINT, sent },
8307 { 0 }
8310 static const struct message WmParentPaintNc[] = {
8311 { WM_PAINT, sent|parent },
8312 { WM_PAINT, sent },
8313 { WM_NCPAINT, sent|beginpaint },
8314 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8315 { WM_ERASEBKGND, sent|beginpaint|optional },
8316 { WM_GETMINMAXINFO, sent|optional },
8317 { 0 }
8320 static const struct message WmChildPaintNc[] = {
8321 { WM_PAINT, sent },
8322 { WM_NCPAINT, sent|beginpaint },
8323 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8324 { WM_ERASEBKGND, sent|beginpaint|optional },
8325 { 0 }
8328 static const struct message WmParentErasePaint[] = {
8329 { WM_PAINT, sent|parent },
8330 { WM_NCPAINT, sent|parent|beginpaint },
8331 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
8332 { WM_ERASEBKGND, sent|parent|beginpaint|optional },
8333 { WM_PAINT, sent },
8334 { WM_NCPAINT, sent|beginpaint },
8335 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8336 { WM_ERASEBKGND, sent|beginpaint|optional },
8337 { 0 }
8340 static const struct message WmParentOnlyNcPaint[] = {
8341 { WM_PAINT, sent|parent },
8342 { WM_NCPAINT, sent|parent|beginpaint },
8343 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
8344 { 0 }
8347 static const struct message WmSetParentStyle[] = {
8348 { WM_STYLECHANGING, sent|parent },
8349 { WM_STYLECHANGED, sent|parent },
8350 { 0 }
8353 static void test_paint_messages(void)
8355 BOOL ret;
8356 RECT rect, rect2;
8357 POINT pt;
8358 MSG msg;
8359 HWND hparent, hchild;
8360 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
8361 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
8362 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
8363 100, 100, 200, 200, 0, 0, 0, NULL);
8364 ok (hwnd != 0, "Failed to create overlapped window\n");
8366 ShowWindow( hwnd, SW_SHOW );
8367 UpdateWindow( hwnd );
8368 flush_events();
8369 flush_sequence();
8371 check_update_rgn( hwnd, 0 );
8372 SetRectRgn( hrgn, 10, 10, 20, 20 );
8373 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
8374 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8375 check_update_rgn( hwnd, hrgn );
8376 SetRectRgn( hrgn2, 20, 20, 30, 30 );
8377 ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
8378 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8379 CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
8380 check_update_rgn( hwnd, hrgn );
8381 /* validate everything */
8382 ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8383 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8384 check_update_rgn( hwnd, 0 );
8386 /* test empty region */
8387 SetRectRgn( hrgn, 10, 10, 10, 15 );
8388 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
8389 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8390 check_update_rgn( hwnd, 0 );
8391 /* test empty rect */
8392 SetRect( &rect, 10, 10, 10, 15 );
8393 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
8394 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8395 check_update_rgn( hwnd, 0 );
8397 /* test a zeroed rectangle */
8398 RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
8399 SetRect( &rect, 0, 0, 0, 0 );
8400 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
8401 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8402 check_update_rgn( hwnd, 0 );
8404 /* a well ordered rectangle */
8405 RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
8406 SetRect( &rect, 10, 5, 17, 21 );
8407 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
8408 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8409 SetRectRgn( hrgn, 10, 5, 17, 21 );
8410 check_update_rgn( hwnd, hrgn );
8412 /* empty rectangle, top and bottom are swapped but left and right have
8413 the same value */
8414 RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
8415 SetRect( &rect, 5, 30, 5, 10 );
8416 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
8417 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8418 check_update_rgn( hwnd, 0 );
8420 /* empty rectangle, left and right are swapped but top and bottom have
8421 the same value */
8422 RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
8423 SetRect( &rect, 17, 10, 5, 10 );
8424 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
8425 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8426 check_update_rgn( hwnd, 0 );
8428 /* Left and right are swapped */
8429 RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
8430 SetRect( &rect, 21, 12, 7, 30 );
8431 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
8432 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8433 SetRectRgn( hrgn, 7, 12, 21, 30 );
8434 check_update_rgn( hwnd, hrgn );
8436 /* Top and bottom are swapped */
8437 RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
8438 SetRect( &rect, 7, 30, 21, 12 );
8439 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
8440 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8441 SetRectRgn( hrgn, 7, 12, 21, 30 );
8442 check_update_rgn( hwnd, hrgn );
8444 /* both reference points are swapped */
8445 RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
8446 SetRect( &rect, 21, 30, 7, 12 );
8447 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
8448 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8449 SetRectRgn( hrgn, 7, 12, 21, 30 );
8450 check_update_rgn( hwnd, hrgn );
8452 /* flush pending messages */
8453 flush_events();
8454 flush_sequence();
8456 GetClientRect( hwnd, &rect );
8457 SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
8458 /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
8459 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
8461 SetRectEmpty( &rect );
8462 ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) failed\n");
8463 check_update_rgn( hwnd, hrgn );
8464 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8465 flush_events();
8466 ok_sequence( WmPaint, "Paint", FALSE );
8467 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8468 check_update_rgn( hwnd, 0 );
8470 SetRectEmpty( &rect );
8471 ok(RedrawWindow(0, &rect, 0, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
8472 "RedrawWindow failed\n");
8473 check_update_rgn( hwnd, 0 );
8475 SetRectEmpty( &rect );
8476 ok(RedrawWindow(0, &rect, 0, RDW_ALLCHILDREN | RDW_VALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
8477 "RedrawWindow failed\n");
8478 check_update_rgn( hwnd, 0 );
8480 GetWindowRect( hwnd, &rect );
8481 ok(RedrawWindow(0, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
8482 "RedrawWindow failed\n");
8483 check_update_rgn( hwnd, 0 );
8485 flush_events();
8486 ok(RedrawWindow(0, &rect, 0, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
8487 "RedrawWindow failed\n");
8488 check_update_rgn( hwnd, hrgn );
8489 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8490 flush_events();
8491 ok_sequence( WmPaint, "Paint", FALSE );
8492 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8493 check_update_rgn( hwnd, 0 );
8495 ok(RedrawWindow(GetDesktopWindow(), &rect, 0,
8496 RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
8497 "RedrawWindow failed\n");
8498 ret = GetUpdateRgn( hwnd, hrgn2, FALSE );
8499 ok( ret == NULLREGION || broken(ret == SIMPLEREGION), /* <= win7 */
8500 "region should be null (%d)\n", ret );
8501 if (ret == SIMPLEREGION) ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8502 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8503 flush_events();
8505 ok(RedrawWindow(GetDesktopWindow(), NULL, 0,
8506 RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
8507 "RedrawWindow failed\n");
8508 ret = GetUpdateRgn( hwnd, hrgn2, FALSE );
8509 ok( ret == NULLREGION || broken(ret == SIMPLEREGION), /* <= win7 */
8510 "region should be null (%d)\n", ret );
8511 if (ret == SIMPLEREGION) ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8512 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8513 flush_events();
8515 SetRectRgn( hrgn2, rect.left, rect.top, rect.right, rect.bottom );
8516 ok(RedrawWindow(0, NULL, hrgn2, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
8517 "RedrawWindow failed\n");
8518 check_update_rgn( hwnd, hrgn );
8519 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8520 flush_events();
8521 ok_sequence( WmPaint, "Paint", FALSE );
8522 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8523 check_update_rgn( hwnd, 0 );
8525 ok(RedrawWindow(0, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW ),
8526 "RedrawWindow failed\n");
8527 check_update_rgn( hwnd, 0 );
8529 ok(RedrawWindow(0, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW ),
8530 "RedrawWindow failed\n");
8531 check_update_rgn( hwnd, hrgn );
8532 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8533 flush_events();
8534 ok_sequence( WmPaint, "Paint", FALSE );
8535 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8536 check_update_rgn( hwnd, 0 );
8538 /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
8539 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
8541 SetRectEmpty( &rect );
8542 if (ValidateRect(0, &rect) && /* not supported on Win9x */
8543 GetUpdateRect(hwnd, NULL, FALSE)) /* or >= Win 8 */
8545 check_update_rgn( hwnd, hrgn );
8546 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8547 flush_events();
8548 ok_sequence( WmPaint, "Paint", FALSE );
8549 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8550 check_update_rgn( hwnd, 0 );
8553 SetLastError(0xdeadbeef);
8554 ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
8555 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
8556 "wrong error code %ld\n", GetLastError());
8557 check_update_rgn( hwnd, 0 );
8558 flush_events();
8559 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8561 SetLastError(0xdeadbeef);
8562 ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
8563 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
8564 broken( GetLastError() == 0xdeadbeef ) /* win9x */,
8565 "wrong error code %ld\n", GetLastError());
8566 check_update_rgn( hwnd, 0 );
8567 flush_events();
8568 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8570 SetLastError(0xdeadbeef);
8571 ok(!UpdateWindow(NULL), "UpdateWindow(NULL) should fail\n");
8572 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
8573 broken( GetLastError() == 0xdeadbeef ) /* win9x */,
8574 "wrong error code %ld\n", GetLastError());
8575 check_update_rgn( hwnd, 0 );
8576 flush_events();
8577 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8579 /* now with frame */
8580 SetRectRgn( hrgn, -5, -5, 20, 20 );
8582 /* flush pending messages */
8583 flush_events();
8584 flush_sequence();
8585 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8586 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
8588 SetRectRgn( hrgn, 0, 0, 20, 20 ); /* GetUpdateRgn clips to client area */
8589 check_update_rgn( hwnd, hrgn );
8591 flush_sequence();
8592 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
8593 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
8595 flush_sequence();
8596 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
8597 ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
8599 GetClientRect( hwnd, &rect );
8600 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8601 check_update_rgn( hwnd, hrgn );
8603 flush_sequence();
8604 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
8605 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8607 flush_sequence();
8608 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
8609 ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
8610 check_update_rgn( hwnd, 0 );
8612 flush_sequence();
8613 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
8614 ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
8615 check_update_rgn( hwnd, 0 );
8617 flush_sequence();
8618 SetRectRgn( hrgn, 0, 0, 100, 100 );
8619 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
8620 SetRectRgn( hrgn, 0, 0, 50, 100 );
8621 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
8622 SetRectRgn( hrgn, 50, 0, 100, 100 );
8623 check_update_rgn( hwnd, hrgn );
8624 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
8625 ok_sequence( WmEmptySeq, "EmptySeq", FALSE ); /* must not generate messages, everything is valid */
8626 check_update_rgn( hwnd, 0 );
8628 flush_sequence();
8629 SetRectRgn( hrgn, 0, 0, 100, 100 );
8630 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
8631 SetRectRgn( hrgn, 0, 0, 100, 50 );
8632 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
8633 ok_sequence( WmErase, "Erase", FALSE );
8634 SetRectRgn( hrgn, 0, 50, 100, 100 );
8635 check_update_rgn( hwnd, hrgn );
8637 flush_sequence();
8638 SetRectRgn( hrgn, 0, 0, 100, 100 );
8639 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
8640 SetRectRgn( hrgn, 0, 0, 50, 50 );
8641 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
8642 ok_sequence( WmPaint, "Paint", FALSE );
8644 flush_sequence();
8645 SetRectRgn( hrgn, -4, -4, -2, -2 );
8646 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8647 SetRectRgn( hrgn, -200, -200, -198, -198 );
8648 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
8649 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
8651 flush_sequence();
8652 SetRectRgn( hrgn, -4, -4, -2, -2 );
8653 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8654 SetRectRgn( hrgn, -4, -4, -3, -3 );
8655 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
8656 SetRectRgn( hrgn, 0, 0, 1, 1 );
8657 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
8658 ok_sequence( WmPaint, "Paint", FALSE );
8660 flush_sequence();
8661 SetRectRgn( hrgn, -4, -4, -1, -1 );
8662 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8663 RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
8664 /* make sure no WM_PAINT was generated */
8665 flush_events();
8666 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
8668 flush_sequence();
8669 SetRectRgn( hrgn, -4, -4, -1, -1 );
8670 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8671 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
8673 if (msg.hwnd == hwnd && msg.message == WM_PAINT)
8675 /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
8676 INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
8677 ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
8678 ret = GetUpdateRect( hwnd, &rect, FALSE );
8679 ok( ret, "Invalid GetUpdateRect result %d\n", ret );
8680 /* this will send WM_NCPAINT and validate the non client area */
8681 ret = GetUpdateRect( hwnd, &rect, TRUE );
8682 ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
8684 DispatchMessageA( &msg );
8686 ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
8688 DestroyWindow( hwnd );
8690 /* now test with a child window */
8692 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
8693 100, 100, 200, 200, 0, 0, 0, NULL);
8694 ok (hparent != 0, "Failed to create parent window\n");
8696 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
8697 10, 10, 100, 100, hparent, 0, 0, NULL);
8698 ok (hchild != 0, "Failed to create child window\n");
8700 ShowWindow( hparent, SW_SHOW );
8701 UpdateWindow( hparent );
8702 UpdateWindow( hchild );
8703 flush_events();
8704 flush_sequence();
8705 log_all_parent_messages++;
8707 SetRect( &rect, 0, 0, 50, 50 );
8708 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8709 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
8710 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
8712 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8713 pt.x = pt.y = 0;
8714 MapWindowPoints( hchild, hparent, &pt, 1 );
8715 SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
8716 check_update_rgn( hchild, hrgn );
8717 SetRectRgn( hrgn, 0, 0, 50, 50 );
8718 check_update_rgn( hparent, hrgn );
8719 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8720 ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
8721 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
8722 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
8724 flush_events();
8725 ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
8727 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
8728 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8729 ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
8730 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
8731 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
8733 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
8734 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
8735 ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
8737 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
8738 flush_sequence();
8739 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
8740 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8741 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
8743 /* flush all paint messages */
8744 flush_events();
8745 flush_sequence();
8747 /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
8748 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
8749 SetRectRgn( hrgn, 0, 0, 50, 50 );
8750 check_update_rgn( hparent, hrgn );
8751 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
8752 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8753 SetRectRgn( hrgn, 0, 0, 50, 50 );
8754 check_update_rgn( hparent, hrgn );
8756 /* flush all paint messages */
8757 flush_events();
8758 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
8759 flush_sequence();
8761 /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
8762 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8763 SetRectRgn( hrgn, 0, 0, 50, 50 );
8764 check_update_rgn( hparent, hrgn );
8765 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
8766 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8767 SetRectRgn( hrgn2, 10, 10, 50, 50 );
8768 CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
8769 check_update_rgn( hparent, hrgn );
8770 /* flush all paint messages */
8771 flush_events();
8772 flush_sequence();
8774 /* same as above but parent gets completely validated */
8775 SetRect( &rect, 20, 20, 30, 30 );
8776 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8777 SetRectRgn( hrgn, 20, 20, 30, 30 );
8778 check_update_rgn( hparent, hrgn );
8779 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
8780 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8781 check_update_rgn( hparent, 0 ); /* no update region */
8782 flush_events();
8783 ok_sequence( WmEmptySeq, "WmEmpty", FALSE ); /* and no paint messages */
8785 /* make sure RDW_VALIDATE on child doesn't have the same effect */
8786 flush_sequence();
8787 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8788 SetRectRgn( hrgn, 20, 20, 30, 30 );
8789 check_update_rgn( hparent, hrgn );
8790 RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
8791 SetRectRgn( hrgn, 20, 20, 30, 30 );
8792 check_update_rgn( hparent, hrgn );
8794 /* same as above but normal WM_PAINT doesn't validate parent */
8795 flush_sequence();
8796 SetRect( &rect, 20, 20, 30, 30 );
8797 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8798 SetRectRgn( hrgn, 20, 20, 30, 30 );
8799 check_update_rgn( hparent, hrgn );
8800 /* no WM_PAINT in child while parent still pending */
8801 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8802 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8803 while (PeekMessageA( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8804 ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
8806 flush_sequence();
8807 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8808 /* no WM_PAINT in child while parent still pending */
8809 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8810 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8811 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
8812 /* now that parent is valid child should get WM_PAINT */
8813 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8814 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8815 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8816 ok_sequence( WmEmptySeq, "No other message", FALSE );
8818 /* same thing with WS_CLIPCHILDREN in parent */
8819 flush_sequence();
8820 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
8821 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
8822 /* changing style invalidates non client area, but we need to invalidate something else to see it */
8823 RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
8824 ok_sequence( WmEmptySeq, "No message", FALSE );
8825 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
8826 ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
8828 flush_sequence();
8829 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
8830 SetRectRgn( hrgn, 20, 20, 30, 30 );
8831 check_update_rgn( hparent, hrgn );
8832 /* no WM_PAINT in child while parent still pending */
8833 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8834 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8835 /* WM_PAINT in parent first */
8836 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8837 ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
8839 /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
8840 flush_sequence();
8841 SetRect( &rect, 0, 0, 30, 30 );
8842 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
8843 SetRectRgn( hrgn, 0, 0, 30, 30 );
8844 check_update_rgn( hparent, hrgn );
8845 flush_events();
8846 ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
8848 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
8849 flush_sequence();
8850 SetRect( &rect, -10, 0, 30, 30 );
8851 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
8852 SetRect( &rect, 0, 0, 20, 20 );
8853 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
8854 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
8855 ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
8857 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
8858 flush_sequence();
8859 SetRect( &rect, -10, 0, 30, 30 );
8860 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
8861 SetRect( &rect, 0, 0, 100, 100 );
8862 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
8863 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
8864 ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
8865 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8866 ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
8868 /* WS_CLIPCHILDREN doesn't exclude children from update region */
8869 flush_sequence();
8870 RedrawWindow( hparent, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
8871 GetClientRect( hparent, &rect );
8872 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8873 check_update_rgn( hparent, hrgn );
8874 flush_events();
8876 RedrawWindow( hparent, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
8877 GetClientRect( hparent, &rect );
8878 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8879 check_update_rgn( hparent, hrgn );
8880 flush_events();
8882 /* test RDW_INTERNALPAINT behavior */
8884 flush_sequence();
8885 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
8886 flush_events();
8887 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
8889 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
8890 flush_events();
8891 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
8893 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
8894 flush_events();
8895 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
8897 assert( GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
8898 UpdateWindow( hparent );
8899 flush_events();
8900 flush_sequence();
8901 trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
8902 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8903 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
8904 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8905 flush_events();
8906 ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
8908 UpdateWindow( hparent );
8909 flush_events();
8910 flush_sequence();
8911 trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
8912 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8913 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
8914 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8915 flush_events();
8916 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
8918 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
8919 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
8920 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
8921 flush_events();
8922 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
8924 assert( !(GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
8925 UpdateWindow( hparent );
8926 flush_events();
8927 flush_sequence();
8928 trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
8929 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8930 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
8931 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8932 flush_events();
8933 ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
8935 UpdateWindow( hparent );
8936 flush_events();
8937 flush_sequence();
8938 trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
8939 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8940 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
8941 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8942 flush_events();
8943 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
8945 ok(GetWindowLongA( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
8946 ok(GetWindowLongA( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
8948 UpdateWindow( hparent );
8949 flush_events();
8950 flush_sequence();
8951 trace("testing SetWindowPos(-10000, -10000) on child\n");
8952 SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
8953 check_update_rgn( hchild, 0 );
8954 flush_events();
8956 #if 0 /* this one doesn't pass under Wine yet */
8957 UpdateWindow( hparent );
8958 flush_events();
8959 flush_sequence();
8960 trace("testing ShowWindow(SW_MINIMIZE) on child\n");
8961 ShowWindow( hchild, SW_MINIMIZE );
8962 check_update_rgn( hchild, 0 );
8963 flush_events();
8964 #endif
8966 UpdateWindow( hparent );
8967 flush_events();
8968 flush_sequence();
8969 trace("testing SetWindowPos(-10000, -10000) on parent\n");
8970 SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
8971 check_update_rgn( hparent, 0 );
8972 flush_events();
8974 log_all_parent_messages--;
8975 DestroyWindow( hparent );
8976 ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
8978 /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
8980 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
8981 100, 100, 200, 200, 0, 0, 0, NULL);
8982 ok (hparent != 0, "Failed to create parent window\n");
8984 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
8985 10, 10, 100, 100, hparent, 0, 0, NULL);
8986 ok (hchild != 0, "Failed to create child window\n");
8988 ShowWindow( hparent, SW_SHOW );
8989 UpdateWindow( hparent );
8990 UpdateWindow( hchild );
8991 flush_events();
8992 flush_sequence();
8994 /* moving child outside of parent boundaries changes update region */
8995 SetRect( &rect, 0, 0, 40, 40 );
8996 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
8997 SetRectRgn( hrgn, 0, 0, 40, 40 );
8998 check_update_rgn( hchild, hrgn );
8999 MoveWindow( hchild, -10, 10, 100, 100, FALSE );
9000 SetRectRgn( hrgn, 10, 0, 40, 40 );
9001 check_update_rgn( hchild, hrgn );
9002 MoveWindow( hchild, -10, -10, 100, 100, FALSE );
9003 SetRectRgn( hrgn, 10, 10, 40, 40 );
9004 check_update_rgn( hchild, hrgn );
9006 /* moving parent off-screen does too */
9007 SetRect( &rect, 0, 0, 100, 100 );
9008 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
9009 SetRectRgn( hrgn, 0, 0, 100, 100 );
9010 check_update_rgn( hparent, hrgn );
9011 SetRectRgn( hrgn, 10, 10, 40, 40 );
9012 check_update_rgn( hchild, hrgn );
9013 MoveWindow( hparent, -20, -20, 200, 200, FALSE );
9014 GetUpdateRect( hparent, &rect2, FALSE );
9015 if (!EqualRect( &rect2, &rect )) /* Win 8 and later don't crop update to screen */
9017 rect.left += 20;
9018 rect.top += 20;
9020 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
9021 check_update_rgn( hparent, hrgn );
9022 SetRectRgn( hrgn, rect.left + 10, rect.top + 10, 40, 40 );
9023 check_update_rgn( hchild, hrgn );
9025 /* invalidated region is cropped by the parent rects */
9026 SetRect( &rect, 0, 0, 50, 50 );
9027 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
9028 SetRectRgn( hrgn, rect2.left + 10, rect2.top + 10, 50, 50 );
9029 check_update_rgn( hchild, hrgn );
9031 DestroyWindow( hparent );
9032 ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
9033 flush_sequence();
9035 DeleteObject( hrgn );
9036 DeleteObject( hrgn2 );
9039 struct wnd_event
9041 HWND hwnd;
9042 HANDLE grand_child;
9043 HANDLE start_event;
9044 HANDLE stop_event;
9047 static DWORD WINAPI thread_proc(void *param)
9049 MSG msg;
9050 struct wnd_event *wnd_event = param;
9052 wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
9053 100, 100, 200, 200, 0, 0, 0, NULL);
9054 ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
9056 SetEvent(wnd_event->start_event);
9058 while (GetMessageA(&msg, 0, 0, 0))
9060 TranslateMessage(&msg);
9061 DispatchMessageA(&msg);
9064 ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
9066 return 0;
9069 static DWORD CALLBACK create_grand_child_thread( void *param )
9071 struct wnd_event *wnd_event = param;
9072 HWND hchild;
9073 MSG msg;
9075 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
9076 WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
9077 ok (hchild != 0, "Failed to create child window\n");
9078 flush_events();
9079 flush_sequence();
9080 SetEvent( wnd_event->start_event );
9082 for (;;)
9084 MsgWaitForMultipleObjects(0, NULL, FALSE, 1000, QS_ALLINPUT);
9085 if (!IsWindow( hchild )) break; /* will be destroyed when parent thread exits */
9086 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
9088 return 0;
9091 static DWORD CALLBACK create_child_thread( void *param )
9093 struct wnd_event *wnd_event = param;
9094 struct wnd_event child_event;
9095 DWORD ret, tid;
9096 MSG msg;
9098 child_event.hwnd = CreateWindowExA(0, "TestWindowClass", "Test child",
9099 WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
9100 ok (child_event.hwnd != 0, "Failed to create child window\n");
9101 SetFocus( child_event.hwnd );
9102 flush_events();
9103 flush_sequence();
9104 child_event.start_event = wnd_event->start_event;
9105 wnd_event->grand_child = CreateThread(NULL, 0, create_grand_child_thread, &child_event, 0, &tid);
9106 for (;;)
9108 DWORD ret = MsgWaitForMultipleObjects(1, &child_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
9109 if (ret != 1) break;
9110 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
9112 ret = WaitForSingleObject( wnd_event->stop_event, 5000 );
9113 ok( !ret, "WaitForSingleObject failed %lx\n", ret );
9114 return 0;
9117 static const char manifest_dep[] =
9118 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
9119 "<assemblyIdentity version=\"1.2.3.4\" name=\"testdep1\" type=\"win32\" processorArchitecture=\"" ARCH "\"/>"
9120 " <file name=\"testdep.dll\" />"
9121 "</assembly>";
9123 static const char manifest_main[] =
9124 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
9125 "<assemblyIdentity version=\"1.2.3.4\" name=\"Wine.Test\" type=\"win32\" />"
9126 "<dependency>"
9127 " <dependentAssembly>"
9128 " <assemblyIdentity type=\"win32\" name=\"testdep1\" version=\"1.2.3.4\" processorArchitecture=\"" ARCH "\" />"
9129 " </dependentAssembly>"
9130 "</dependency>"
9131 "</assembly>";
9133 static void create_manifest_file(const char *filename, const char *manifest)
9135 WCHAR path[MAX_PATH];
9136 HANDLE file;
9137 DWORD size;
9139 MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH );
9140 file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
9141 ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %lu\n", GetLastError());
9142 WriteFile(file, manifest, strlen(manifest), &size, NULL);
9143 CloseHandle(file);
9146 static HANDLE test_create(const char *file)
9148 WCHAR path[MAX_PATH];
9149 ACTCTXW actctx;
9150 HANDLE handle;
9152 MultiByteToWideChar(CP_ACP, 0, file, -1, path, MAX_PATH);
9153 memset(&actctx, 0, sizeof(ACTCTXW));
9154 actctx.cbSize = sizeof(ACTCTXW);
9155 actctx.lpSource = path;
9157 handle = CreateActCtxW(&actctx);
9158 ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %lu\n", GetLastError());
9160 ok(actctx.cbSize == sizeof(actctx), "cbSize=%ld\n", actctx.cbSize);
9161 ok(actctx.dwFlags == 0, "dwFlags=%ld\n", actctx.dwFlags);
9162 ok(actctx.lpSource == path, "lpSource=%p\n", actctx.lpSource);
9163 ok(actctx.wProcessorArchitecture == 0, "wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture);
9164 ok(actctx.wLangId == 0, "wLangId=%d\n", actctx.wLangId);
9165 ok(actctx.lpAssemblyDirectory == NULL, "lpAssemblyDirectory=%p\n", actctx.lpAssemblyDirectory);
9166 ok(actctx.lpResourceName == NULL, "lpResourceName=%p\n", actctx.lpResourceName);
9167 ok(actctx.lpApplicationName == NULL, "lpApplicationName=%p\n", actctx.lpApplicationName);
9168 ok(actctx.hModule == NULL, "hModule=%p\n", actctx.hModule);
9170 return handle;
9173 static void test_interthread_messages(void)
9175 HANDLE hThread, context, handle, event;
9176 ULONG_PTR cookie;
9177 DWORD tid;
9178 WNDPROC proc;
9179 MSG msg;
9180 char buf[256];
9181 int len, expected_len;
9182 struct wnd_event wnd_event;
9183 BOOL ret;
9185 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
9186 if (!wnd_event.start_event)
9188 win_skip("skipping interthread message test under win9x\n");
9189 return;
9192 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
9193 ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError());
9195 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
9197 CloseHandle(wnd_event.start_event);
9199 SetLastError(0xdeadbeef);
9200 ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeeded\n");
9201 ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
9202 "wrong error code %ld\n", GetLastError());
9204 proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
9205 ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %ld\n", GetLastError());
9207 expected_len = lstrlenA("window caption text");
9208 memset(buf, 0, sizeof(buf));
9209 SetLastError(0xdeadbeef);
9210 len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
9211 ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %ld, len %d, expected len %d\n", GetLastError(), len, expected_len);
9212 ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
9214 msg.hwnd = wnd_event.hwnd;
9215 msg.message = WM_GETTEXT;
9216 msg.wParam = sizeof(buf);
9217 msg.lParam = (LPARAM)buf;
9218 memset(buf, 0, sizeof(buf));
9219 SetLastError(0xdeadbeef);
9220 len = DispatchMessageA(&msg);
9221 ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */
9222 "DispatchMessageA(WM_GETTEXT) succeeded on another thread window: ret %d, error %ld\n", len, GetLastError());
9224 /* the following test causes an exception in user.exe under win9x */
9225 msg.hwnd = wnd_event.hwnd;
9226 msg.message = WM_TIMER;
9227 msg.wParam = 0;
9228 msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
9229 SetLastError(0xdeadbeef);
9230 len = DispatchMessageA(&msg);
9231 ok(!len && GetLastError() == 0xdeadbeef,
9232 "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %ld\n", len, GetLastError());
9234 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
9235 ok( ret, "PostMessageA(WM_QUIT) error %ld\n", GetLastError());
9237 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
9238 CloseHandle(hThread);
9240 ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
9242 wnd_event.hwnd = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9243 100, 100, 200, 200, 0, 0, 0, NULL);
9244 ok (wnd_event.hwnd != 0, "Failed to create parent window\n");
9245 flush_events();
9246 flush_sequence();
9247 log_all_parent_messages++;
9248 wnd_event.start_event = CreateEventA( NULL, TRUE, FALSE, NULL );
9249 wnd_event.stop_event = CreateEventA( NULL, TRUE, FALSE, NULL );
9250 hThread = CreateThread( NULL, 0, create_child_thread, &wnd_event, 0, &tid );
9251 for (;;)
9253 ret = MsgWaitForMultipleObjects(1, &wnd_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
9254 if (ret != 1) break;
9255 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
9257 ok( !ret, "MsgWaitForMultipleObjects failed %x\n", ret );
9258 /* now wait for the thread without processing messages; this shouldn't deadlock */
9259 SetEvent( wnd_event.stop_event );
9260 ret = WaitForSingleObject( hThread, 5000 );
9261 ok( !ret, "WaitForSingleObject failed %x\n", ret );
9262 CloseHandle( hThread );
9264 ret = WaitForSingleObject( wnd_event.grand_child, 5000 );
9265 ok( !ret, "WaitForSingleObject failed %x\n", ret );
9266 CloseHandle( wnd_event.grand_child );
9268 CloseHandle( wnd_event.start_event );
9269 CloseHandle( wnd_event.stop_event );
9270 flush_events();
9271 ok_sequence(WmExitThreadSeq, "destroy child on thread exit", FALSE);
9272 log_all_parent_messages--;
9273 DestroyWindow( wnd_event.hwnd );
9275 /* Activation context tests */
9276 create_manifest_file("testdep1.manifest", manifest_dep);
9277 create_manifest_file("main.manifest", manifest_main);
9279 context = test_create("main.manifest");
9280 DeleteFileA("testdep1.manifest");
9281 DeleteFileA("main.manifest");
9283 handle = (void*)0xdeadbeef;
9284 ret = GetCurrentActCtx(&handle);
9285 ok(ret, "GetCurrentActCtx failed: %lu\n", GetLastError());
9286 ok(handle == 0, "active context %p\n", handle);
9288 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
9289 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
9290 ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError());
9291 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
9292 CloseHandle(wnd_event.start_event);
9294 /* context is activated after thread creation, so it doesn't inherit it by default */
9295 ret = ActivateActCtx(context, &cookie);
9296 ok(ret, "activation failed: %lu\n", GetLastError());
9298 handle = 0;
9299 ret = GetCurrentActCtx(&handle);
9300 ok(ret, "GetCurrentActCtx failed: %lu\n", GetLastError());
9301 ok(handle != 0, "active context %p\n", handle);
9302 ReleaseActCtx(handle);
9304 /* destination window will test for active context */
9305 ret = SendMessageA(wnd_event.hwnd, WM_USER+10, 0, 0);
9306 ok(ret, "thread window returned %d\n", ret);
9308 event = CreateEventW(NULL, 0, 0, NULL);
9309 ret = PostMessageA(wnd_event.hwnd, WM_USER+10, 0, (LPARAM)event);
9310 ok(ret, "thread window returned %d\n", ret);
9311 ok(WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
9312 CloseHandle(event);
9314 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
9315 ok(ret, "PostMessageA(WM_QUIT) error %ld\n", GetLastError());
9317 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
9318 CloseHandle(hThread);
9320 ret = DeactivateActCtx(0, cookie);
9321 ok(ret, "DeactivateActCtx failed: %lu\n", GetLastError());
9322 ReleaseActCtx(context);
9326 static const struct message WmVkN[] = {
9327 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
9328 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
9329 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
9330 { WM_CHAR, wparam|lparam, 'n', 1 },
9331 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
9332 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9333 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
9334 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
9335 { 0 }
9337 static const struct message WmShiftVkN[] = {
9338 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
9339 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
9340 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
9341 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
9342 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
9343 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
9344 { WM_CHAR, wparam|lparam, 'N', 1 },
9345 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
9346 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9347 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
9348 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
9349 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
9350 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
9351 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
9352 { 0 }
9354 static const struct message WmCtrlVkN[] = {
9355 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
9356 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
9357 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
9358 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
9359 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
9360 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
9361 { WM_CHAR, wparam|lparam, 0x000e, 1 },
9362 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
9363 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9364 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
9365 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
9366 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
9367 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
9368 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
9369 { 0 }
9371 static const struct message WmCtrlVkN_2[] = {
9372 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
9373 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
9374 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
9375 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
9376 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
9377 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
9378 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9379 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
9380 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
9381 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
9382 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
9383 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
9384 { 0 }
9386 static const struct message WmAltVkN[] = {
9387 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
9388 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
9389 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
9390 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
9391 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
9392 { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
9393 { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
9394 { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
9395 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
9396 { HCBT_SYSCOMMAND, hook },
9397 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
9398 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
9399 { 0x00AE, sent|defwinproc|optional }, /* XP */
9400 { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
9401 { WM_INITMENU, sent|defwinproc },
9402 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_SYSMENU, 0 },
9403 { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
9404 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
9405 { WM_CAPTURECHANGED, sent|defwinproc },
9406 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
9407 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_SYSMENU, 0 },
9408 { WM_EXITMENULOOP, sent|defwinproc },
9409 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
9410 { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
9411 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
9412 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
9413 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
9414 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
9415 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
9416 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
9417 { 0 }
9419 static const struct message WmAltVkN_2[] = {
9420 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
9421 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
9422 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
9423 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
9424 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
9425 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
9426 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
9427 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
9428 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
9429 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
9430 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
9431 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
9432 { 0 }
9434 static const struct message WmCtrlAltVkN[] = {
9435 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
9436 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
9437 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
9438 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
9439 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
9440 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
9441 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
9442 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
9443 { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
9444 { WM_CHAR, optional },
9445 { WM_CHAR, sent|optional },
9446 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
9447 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
9448 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
9449 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
9450 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
9451 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
9452 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
9453 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
9454 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
9455 { 0 }
9457 static const struct message WmCtrlShiftVkN[] = {
9458 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
9459 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
9460 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
9461 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
9462 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
9463 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
9464 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
9465 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
9466 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
9467 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9468 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
9469 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
9470 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
9471 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
9472 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
9473 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
9474 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
9475 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
9476 { 0 }
9478 static const struct message WmCtrlAltShiftVkN[] = {
9479 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
9480 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
9481 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
9482 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
9483 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
9484 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
9485 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
9486 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
9487 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
9488 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
9489 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
9490 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
9491 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
9492 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
9493 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
9494 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
9495 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
9496 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
9497 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
9498 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
9499 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
9500 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
9501 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
9502 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
9503 { 0 }
9505 static const struct message WmAltPressRelease[] = {
9506 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
9507 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
9508 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
9509 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
9510 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
9511 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
9512 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
9513 { HCBT_SYSCOMMAND, hook },
9514 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
9515 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
9516 { WM_INITMENU, sent|defwinproc },
9517 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_SYSMENU, 0 },
9518 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
9519 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_SYSMENU, 1 },
9521 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
9523 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_SYSMENU, 0 },
9524 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0, },
9525 { WM_CAPTURECHANGED, sent|defwinproc },
9526 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
9527 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_SYSMENU, 0 },
9528 { WM_EXITMENULOOP, sent|defwinproc },
9529 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
9530 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
9531 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
9532 { 0 }
9534 static const struct message WmShiftMouseButton[] = {
9535 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
9536 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
9537 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
9538 { WM_MOUSEMOVE, wparam|optional, 0, 0 },
9539 { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
9540 { WM_LBUTTONDOWN, wparam, MK_LBUTTON|MK_SHIFT, 0 },
9541 { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON|MK_SHIFT, 0 },
9542 { WM_LBUTTONUP, wparam|optional, MK_SHIFT, 0 }, /* < w1064v1809 */
9543 { WM_LBUTTONUP, sent|wparam|optional, MK_SHIFT, 0 }, /* < w1064v1809 */
9544 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
9545 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
9546 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
9547 { WM_LBUTTONUP, optional, 0, 0 }, /* >= w1064v1809 */
9548 { WM_LBUTTONUP, sent|optional, 0, 0 }, /* >= w1064v1809 */
9549 { 0 }
9551 static const struct message WmF1Seq[] = {
9552 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
9553 { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
9554 { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
9555 { WM_KEYF1, wparam|lparam, 0, 0 },
9556 { WM_KEYF1, sent|wparam|lparam, 0, 0 },
9557 { WM_HELP, sent|defwinproc },
9558 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
9559 { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
9560 { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
9561 { 0 }
9563 static const struct message WmVkAppsSeq[] = {
9564 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
9565 { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
9566 { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
9567 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
9568 { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
9569 { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
9570 { WM_CONTEXTMENU, lparam, /*hwnd*/0, -1 },
9571 { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, -1 },
9572 { 0 }
9574 static const struct message WmVkF10Seq[] = {
9575 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
9576 { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
9577 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
9578 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
9579 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
9580 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
9581 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
9582 { HCBT_SYSCOMMAND, hook },
9583 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
9584 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
9585 { WM_INITMENU, sent|defwinproc },
9586 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_SYSMENU, 0 },
9587 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
9588 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_SYSMENU, 1 },
9590 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0x10000001 }, /* XP */
9592 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
9593 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_SYSMENU, 0 },
9594 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0, },
9595 { WM_CAPTURECHANGED, sent|defwinproc },
9596 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
9597 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_SYSMENU, 0 },
9598 { WM_EXITMENULOOP, sent|defwinproc },
9599 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
9600 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
9601 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
9602 { 0 }
9604 static const struct message WmShiftF10Seq[] = {
9605 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
9606 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
9607 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x00000001 },
9608 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
9609 { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
9610 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
9611 { WM_CONTEXTMENU, sent|defwinproc|lparam, /*hwnd*/0, -1 },
9612 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
9613 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
9614 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
9615 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
9616 { HCBT_SYSCOMMAND, hook },
9617 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
9618 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
9619 { WM_INITMENU, sent|defwinproc },
9620 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_SYSMENU, 0 },
9621 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
9622 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_SYSMENU, 1 },
9623 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xd0000001 }, /* XP */
9624 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0x10000001 }, /* XP */
9625 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_SYSMENU, 0 },
9626 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
9627 { WM_CAPTURECHANGED, sent|defwinproc|wparam|lparam, 0, 0 },
9628 { WM_MENUSELECT, sent|defwinproc|wparam|lparam, 0xffff0000, 0 },
9629 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_SYSMENU, 0 },
9630 { WM_EXITMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
9631 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 }, /* XP */
9632 { WM_KEYUP, wparam|lparam, VK_ESCAPE, 0xc0000001 },
9633 { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
9634 { 0 }
9637 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
9639 MSG msg;
9641 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
9643 struct recvd_message log_msg;
9645 /* ignore some unwanted messages */
9646 if (msg.message == WM_MOUSEMOVE ||
9647 msg.message == WM_TIMER ||
9648 ignore_message( msg.message ))
9649 continue;
9651 log_msg.hwnd = msg.hwnd;
9652 log_msg.message = msg.message;
9653 log_msg.flags = wparam|lparam;
9654 log_msg.wParam = msg.wParam;
9655 log_msg.lParam = msg.lParam;
9656 log_msg.descr = "accel";
9657 add_message(&log_msg);
9659 if (!hAccel || !TranslateAcceleratorA(hwnd, hAccel, &msg))
9661 TranslateMessage(&msg);
9662 DispatchMessageA(&msg);
9667 static void test_accelerators(void)
9669 RECT rc;
9670 POINT pt;
9671 SHORT state;
9672 HACCEL hAccel;
9673 HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9674 100, 100, 200, 200, 0, 0, 0, NULL);
9675 BOOL us_kbd = (GetKeyboardLayout(0) == (HKL)(ULONG_PTR)0x04090409);
9676 BOOL ret;
9678 assert(hwnd != 0);
9679 UpdateWindow(hwnd);
9680 flush_events();
9681 flush_sequence();
9683 SetFocus(hwnd);
9684 ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
9686 state = GetKeyState(VK_SHIFT);
9687 ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
9688 state = GetKeyState(VK_CAPITAL);
9689 ok(state == 0, "wrong CapsLock state %04x\n", state);
9691 hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
9692 assert(hAccel != 0);
9694 flush_events();
9695 pump_msg_loop(hwnd, 0);
9696 flush_sequence();
9698 if (!us_kbd)
9700 skip("skipping ascii VK events on non-us keyboard\n");
9701 goto done;
9704 trace("testing VK_N press/release\n");
9705 flush_sequence();
9706 keybd_event('N', 0, 0, 0);
9707 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9708 pump_msg_loop(hwnd, hAccel);
9709 if (!sequence_cnt) /* we didn't get any message */
9711 skip( "queuing key events not supported\n" );
9712 goto done;
9714 ok_sequence(WmVkN, "VK_N press/release", FALSE);
9716 trace("testing Shift+VK_N press/release\n");
9717 flush_sequence();
9718 keybd_event(VK_SHIFT, 0, 0, 0);
9719 keybd_event('N', 0, 0, 0);
9720 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9721 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9722 pump_msg_loop(hwnd, hAccel);
9723 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
9725 trace("testing Ctrl+VK_N press/release\n");
9726 flush_sequence();
9727 keybd_event(VK_CONTROL, 0, 0, 0);
9728 keybd_event('N', 0, 0, 0);
9729 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9730 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9731 pump_msg_loop(hwnd, hAccel);
9732 ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
9734 trace("testing Alt+VK_N press/release\n");
9735 flush_sequence();
9736 keybd_event(VK_MENU, 0, 0, 0);
9737 keybd_event('N', 0, 0, 0);
9738 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9739 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9740 pump_msg_loop(hwnd, hAccel);
9741 ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
9743 trace("testing Ctrl+Alt+VK_N press/release 1\n");
9744 flush_sequence();
9745 keybd_event(VK_CONTROL, 0, 0, 0);
9746 keybd_event(VK_MENU, 0, 0, 0);
9747 keybd_event('N', 0, 0, 0);
9748 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9749 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9750 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9751 pump_msg_loop(hwnd, hAccel);
9752 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
9754 ret = DestroyAcceleratorTable(hAccel);
9755 ok( ret, "DestroyAcceleratorTable error %ld\n", GetLastError());
9757 hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(2));
9758 assert(hAccel != 0);
9760 trace("testing VK_N press/release\n");
9761 flush_sequence();
9762 keybd_event('N', 0, 0, 0);
9763 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9764 pump_msg_loop(hwnd, hAccel);
9765 ok_sequence(WmVkN, "VK_N press/release", FALSE);
9767 trace("testing Shift+VK_N press/release\n");
9768 flush_sequence();
9769 keybd_event(VK_SHIFT, 0, 0, 0);
9770 keybd_event('N', 0, 0, 0);
9771 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9772 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9773 pump_msg_loop(hwnd, hAccel);
9774 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
9776 trace("testing Ctrl+VK_N press/release 2\n");
9777 flush_sequence();
9778 keybd_event(VK_CONTROL, 0, 0, 0);
9779 keybd_event('N', 0, 0, 0);
9780 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9781 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9782 pump_msg_loop(hwnd, hAccel);
9783 ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
9785 trace("testing Alt+VK_N press/release 2\n");
9786 flush_sequence();
9787 keybd_event(VK_MENU, 0, 0, 0);
9788 keybd_event('N', 0, 0, 0);
9789 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9790 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9791 pump_msg_loop(hwnd, hAccel);
9792 ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
9794 trace("testing Ctrl+Alt+VK_N press/release 2\n");
9795 flush_sequence();
9796 keybd_event(VK_CONTROL, 0, 0, 0);
9797 keybd_event(VK_MENU, 0, 0, 0);
9798 keybd_event('N', 0, 0, 0);
9799 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9800 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9801 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9802 pump_msg_loop(hwnd, hAccel);
9803 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
9805 trace("testing Ctrl+Shift+VK_N press/release\n");
9806 flush_sequence();
9807 keybd_event(VK_CONTROL, 0, 0, 0);
9808 keybd_event(VK_SHIFT, 0, 0, 0);
9809 keybd_event('N', 0, 0, 0);
9810 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9811 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9812 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9813 pump_msg_loop(hwnd, hAccel);
9814 ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
9816 trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
9817 flush_sequence();
9818 keybd_event(VK_CONTROL, 0, 0, 0);
9819 keybd_event(VK_MENU, 0, 0, 0);
9820 keybd_event(VK_SHIFT, 0, 0, 0);
9821 keybd_event('N', 0, 0, 0);
9822 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9823 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9824 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9825 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9826 pump_msg_loop(hwnd, hAccel);
9827 ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
9829 ret = DestroyAcceleratorTable(hAccel);
9830 ok( ret, "DestroyAcceleratorTable error %ld\n", GetLastError());
9831 hAccel = 0;
9833 trace("testing Alt press/release\n");
9834 flush_sequence();
9835 keybd_event(VK_MENU, 0, 0, 0);
9836 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9837 keybd_event(VK_MENU, 0, 0, 0);
9838 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9839 pump_msg_loop(hwnd, 0);
9840 /* this test doesn't pass in Wine for managed windows */
9841 ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
9843 trace("testing VK_F1 press/release\n");
9844 keybd_event(VK_F1, 0, 0, 0);
9845 keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
9846 pump_msg_loop(hwnd, 0);
9847 ok_sequence(WmF1Seq, "F1 press/release", FALSE);
9849 trace("testing VK_APPS press/release\n");
9850 keybd_event(VK_APPS, 0, 0, 0);
9851 keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
9852 pump_msg_loop(hwnd, 0);
9853 ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
9855 trace("testing VK_F10 press/release\n");
9856 keybd_event(VK_F10, 0, 0, 0);
9857 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
9858 keybd_event(VK_F10, 0, 0, 0);
9859 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
9860 pump_msg_loop(hwnd, 0);
9861 ok_sequence(WmVkF10Seq, "VK_F10 press/release", TRUE);
9863 trace("testing SHIFT+F10 press/release\n");
9864 keybd_event(VK_SHIFT, 0, 0, 0);
9865 keybd_event(VK_F10, 0, 0, 0);
9866 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
9867 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9868 keybd_event(VK_ESCAPE, 0, 0, 0);
9869 keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
9870 pump_msg_loop(hwnd, 0);
9871 ok_sequence(WmShiftF10Seq, "SHIFT+F10 press/release", TRUE);
9873 trace("testing Shift+MouseButton press/release\n");
9874 /* first, move mouse pointer inside of the window client area */
9875 GetClientRect(hwnd, &rc);
9876 MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
9877 rc.left += (rc.right - rc.left)/2;
9878 rc.top += (rc.bottom - rc.top)/2;
9879 SetCursorPos(rc.left, rc.top);
9880 SetActiveWindow(hwnd);
9882 flush_events();
9883 flush_sequence();
9884 GetCursorPos(&pt);
9885 if (pt.x == rc.left && pt.y == rc.top)
9887 int i;
9888 keybd_event(VK_SHIFT, 0, 0, 0);
9889 mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
9890 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
9891 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9892 pump_msg_loop(hwnd, 0);
9893 for (i = 0; i < sequence_cnt; i++) if (sequence[i].message == WM_LBUTTONDOWN) break;
9894 if (i < sequence_cnt)
9895 ok_sequence(WmShiftMouseButton, "Shift+MouseButton press/release", FALSE);
9896 else
9897 skip( "Shift+MouseButton event didn't get to the window\n" );
9900 done:
9901 if (hAccel) DestroyAcceleratorTable(hAccel);
9902 DestroyWindow(hwnd);
9905 /************* window procedures ********************/
9907 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message,
9908 WPARAM wParam, LPARAM lParam)
9910 static LONG defwndproc_counter = 0;
9911 static LONG beginpaint_counter = 0;
9912 LRESULT ret;
9913 struct recvd_message msg;
9915 if (ignore_message( message )) return 0;
9917 switch (message)
9919 case WM_ENABLE:
9921 LONG style = GetWindowLongA(hwnd, GWL_STYLE);
9922 ok((BOOL)wParam == !(style & WS_DISABLED),
9923 "wrong WS_DISABLED state: %Id != %d\n", wParam, !(style & WS_DISABLED));
9924 break;
9927 case WM_CAPTURECHANGED:
9928 if (test_DestroyWindow_flag)
9930 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
9931 if (style & WS_CHILD)
9932 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
9933 else if (style & WS_POPUP)
9934 lParam = WND_POPUP_ID;
9935 else
9936 lParam = WND_PARENT_ID;
9938 break;
9940 case WM_NCDESTROY:
9942 HWND capture;
9944 ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
9945 capture = GetCapture();
9946 if (capture)
9948 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
9949 trace("current capture %p, releasing...\n", capture);
9950 ReleaseCapture();
9953 /* fall through */
9954 case WM_DESTROY:
9955 ok(GetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
9956 if (test_DestroyWindow_flag)
9958 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
9959 if (style & WS_CHILD)
9960 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
9961 else if (style & WS_POPUP)
9962 lParam = WND_POPUP_ID;
9963 else
9964 lParam = WND_PARENT_ID;
9966 break;
9968 /* test_accelerators() depends on this */
9969 case WM_NCHITTEST:
9970 return HTCLIENT;
9972 case WM_USER+10:
9974 ACTIVATION_CONTEXT_BASIC_INFORMATION basicinfo;
9975 HANDLE handle, event = (HANDLE)lParam;
9976 BOOL ret;
9978 handle = (void*)0xdeadbeef;
9979 ret = GetCurrentActCtx(&handle);
9980 ok(ret, "failed to get current context, %lu\n", GetLastError());
9981 ok(handle == 0, "got active context %p\n", handle);
9983 memset(&basicinfo, 0xff, sizeof(basicinfo));
9984 ret = QueryActCtxW(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX, handle, 0, ActivationContextBasicInformation,
9985 &basicinfo, sizeof(basicinfo), NULL);
9986 ok(ret, "got %d, error %ld\n", ret, GetLastError());
9987 ok(basicinfo.hActCtx == NULL, "got %p\n", basicinfo.hActCtx);
9988 ok(basicinfo.dwFlags == 0, "got %lx\n", basicinfo.dwFlags);
9990 if (event) SetEvent(event);
9991 return 1;
9994 /* ignore */
9995 case WM_MOUSEMOVE:
9996 case WM_MOUSEACTIVATE:
9997 case WM_NCMOUSEMOVE:
9998 case WM_SETCURSOR:
9999 case WM_IME_SELECT:
10000 return 0;
10003 msg.hwnd = hwnd;
10004 msg.message = message;
10005 msg.flags = sent|wparam|lparam;
10006 if (defwndproc_counter) msg.flags |= defwinproc;
10007 if (beginpaint_counter) msg.flags |= beginpaint;
10008 msg.wParam = wParam;
10009 msg.lParam = lParam;
10010 msg.descr = "MsgCheckProc";
10011 add_message(&msg);
10013 if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
10015 HWND parent = GetParent(hwnd);
10016 RECT rc;
10017 MINMAXINFO *minmax = (MINMAXINFO *)lParam;
10019 GetClientRect(parent, &rc);
10020 trace("parent %p client size = (%ld x %ld)\n", parent, rc.right, rc.bottom);
10021 trace("Reserved=%ld,%ld MaxSize=%ld,%ld MaxPos=%ld,%ld MinTrack=%ld,%ld MaxTrack=%ld,%ld\n",
10022 minmax->ptReserved.x, minmax->ptReserved.y,
10023 minmax->ptMaxSize.x, minmax->ptMaxSize.y,
10024 minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
10025 minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
10026 minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
10028 ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %ld != %ld\n",
10029 minmax->ptMaxSize.x, rc.right);
10030 ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %ld != %ld\n",
10031 minmax->ptMaxSize.y, rc.bottom);
10034 if (message == WM_PAINT)
10036 PAINTSTRUCT ps;
10037 beginpaint_counter++;
10038 BeginPaint( hwnd, &ps );
10039 beginpaint_counter--;
10040 EndPaint( hwnd, &ps );
10041 return 0;
10044 if (!test_context_menu && message == WM_CONTEXTMENU)
10046 /* don't create context menu */
10047 return 0;
10050 defwndproc_counter++;
10051 ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam)
10052 : DefWindowProcA(hwnd, message, wParam, lParam);
10053 defwndproc_counter--;
10055 return ret;
10058 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10060 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
10063 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10065 return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
10068 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10070 static LONG defwndproc_counter = 0;
10071 LRESULT ret;
10072 struct recvd_message msg;
10074 if (ignore_message( message )) return 0;
10076 switch (message)
10078 case WM_QUERYENDSESSION:
10079 case WM_ENDSESSION:
10080 lParam &= ~0x01; /* Vista adds a 0x01 flag */
10081 break;
10084 msg.hwnd = hwnd;
10085 msg.message = message;
10086 msg.flags = sent|wparam|lparam;
10087 if (defwndproc_counter) msg.flags |= defwinproc;
10088 msg.wParam = wParam;
10089 msg.lParam = lParam;
10090 msg.descr = "popup";
10091 add_message(&msg);
10093 if (message == WM_CREATE)
10095 DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
10096 SetWindowLongA(hwnd, GWL_STYLE, style);
10099 defwndproc_counter++;
10100 ret = DefWindowProcA(hwnd, message, wParam, lParam);
10101 defwndproc_counter--;
10103 return ret;
10106 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10108 static LONG defwndproc_counter = 0;
10109 static LONG beginpaint_counter = 0;
10110 LRESULT ret;
10111 struct recvd_message msg;
10113 if (ignore_message( message )) return 0;
10115 if (log_all_parent_messages ||
10116 message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
10117 message == WM_SETFOCUS || message == WM_KILLFOCUS ||
10118 message == WM_ENABLE || message == WM_ENTERIDLE ||
10119 message == WM_DRAWITEM || message == WM_MEASUREITEM || message == WM_COMPAREITEM ||
10120 message == WM_COMMAND || message == WM_IME_SETCONTEXT)
10122 switch (message)
10124 /* ignore */
10125 case WM_NCHITTEST:
10126 return HTCLIENT;
10127 case WM_SETCURSOR:
10128 case WM_MOUSEMOVE:
10129 case WM_NCMOUSEMOVE:
10130 return 0;
10132 case WM_ERASEBKGND:
10134 RECT rc;
10135 INT ret = GetClipBox((HDC)wParam, &rc);
10137 trace("WM_ERASEBKGND: GetClipBox()=%d, %s\n", ret, wine_dbgstr_rect(&rc));
10138 break;
10142 msg.hwnd = hwnd;
10143 msg.message = message;
10144 msg.flags = sent|parent|wparam|lparam;
10145 if (defwndproc_counter) msg.flags |= defwinproc;
10146 if (beginpaint_counter) msg.flags |= beginpaint;
10147 msg.wParam = wParam;
10148 msg.lParam = lParam;
10149 msg.descr = "parent";
10150 add_message(&msg);
10153 if (message == WM_PAINT)
10155 PAINTSTRUCT ps;
10156 beginpaint_counter++;
10157 BeginPaint( hwnd, &ps );
10158 beginpaint_counter--;
10159 EndPaint( hwnd, &ps );
10160 return 0;
10163 defwndproc_counter++;
10164 ret = DefWindowProcA(hwnd, message, wParam, lParam);
10165 defwndproc_counter--;
10167 return message == WM_COMPAREITEM ? -1 : ret;
10170 static LRESULT CALLBACK StopQuitMsgCheckProcA(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
10172 if (message == WM_CREATE)
10173 PostMessageA(hwnd, WM_CLOSE, 0, 0);
10174 else if (message == WM_CLOSE)
10176 /* Only the first WM_QUIT will survive the window destruction */
10177 PostMessageA(hwnd, WM_USER, 0x1234, 0x5678);
10178 PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
10179 PostMessageA(hwnd, WM_QUIT, 0x4321, 0x8765);
10182 return DefWindowProcA(hwnd, message, wp, lp);
10185 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10187 static LONG defwndproc_counter = 0;
10188 LRESULT ret;
10189 struct recvd_message msg;
10191 if (ignore_message( message )) return 0;
10193 if (test_def_id)
10195 DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
10196 ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
10197 if (after_end_dialog)
10198 ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %Ix\n", ret );
10199 else
10200 ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %Ix\n", ret);
10203 msg.hwnd = hwnd;
10204 msg.message = message;
10205 msg.flags = sent|wparam|lparam;
10206 if (defwndproc_counter) msg.flags |= defwinproc;
10207 msg.wParam = wParam;
10208 msg.lParam = lParam;
10209 msg.descr = "dialog";
10210 add_message(&msg);
10212 defwndproc_counter++;
10213 ret = DefDlgProcA(hwnd, message, wParam, lParam);
10214 defwndproc_counter--;
10216 return ret;
10219 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10221 static LONG defwndproc_counter = 0;
10222 LRESULT ret;
10223 struct recvd_message msg;
10225 /* log only specific messages we are interested in */
10226 switch (message)
10228 #if 0 /* probably log these as well */
10229 case WM_ACTIVATE:
10230 case WM_SETFOCUS:
10231 case WM_KILLFOCUS:
10232 #endif
10233 case WM_SHOWWINDOW:
10234 case WM_SIZE:
10235 case WM_MOVE:
10236 case WM_GETMINMAXINFO:
10237 case WM_WINDOWPOSCHANGING:
10238 case WM_WINDOWPOSCHANGED:
10239 break;
10241 default: /* ignore */
10242 /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
10243 return DefWindowProcA(hwnd, message, wParam, lParam);
10246 msg.hwnd = hwnd;
10247 msg.message = message;
10248 msg.flags = sent|wparam|lparam;
10249 if (defwndproc_counter) msg.flags |= defwinproc;
10250 msg.wParam = wParam;
10251 msg.lParam = lParam;
10252 msg.descr = "show";
10253 add_message(&msg);
10255 defwndproc_counter++;
10256 ret = DefWindowProcA(hwnd, message, wParam, lParam);
10257 defwndproc_counter--;
10259 return ret;
10262 static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
10264 switch (msg)
10266 case WM_CREATE: return 0;
10267 case WM_PAINT:
10269 MSG msg2;
10270 static int i = 0;
10272 if (i < 256)
10274 i++;
10275 if (PeekMessageA(&msg2, 0, 0, 0, 1))
10277 TranslateMessage(&msg2);
10278 DispatchMessageA(&msg2);
10280 i--;
10282 else ok(broken(1), "infinite loop\n");
10283 if ( i == 0)
10284 paint_loop_done = TRUE;
10285 return DefWindowProcA(hWnd,msg,wParam,lParam);
10288 return DefWindowProcA(hWnd,msg,wParam,lParam);
10291 static LRESULT WINAPI HotkeyMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10293 static LONG defwndproc_counter = 0;
10294 LRESULT ret;
10295 struct recvd_message msg;
10296 DWORD queue_status;
10298 if (ignore_message( message )) return 0;
10300 if ((message >= WM_KEYFIRST && message <= WM_KEYLAST) ||
10301 message == WM_HOTKEY || message >= WM_APP)
10303 msg.hwnd = hwnd;
10304 msg.message = message;
10305 msg.flags = sent|wparam|lparam;
10306 if (defwndproc_counter) msg.flags |= defwinproc;
10307 msg.wParam = wParam;
10308 msg.lParam = lParam;
10309 msg.descr = "HotkeyMsgCheckProcA";
10310 add_message(&msg);
10313 defwndproc_counter++;
10314 ret = DefWindowProcA(hwnd, message, wParam, lParam);
10315 defwndproc_counter--;
10317 if (message == WM_APP)
10319 queue_status = GetQueueStatus(QS_HOTKEY);
10320 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %lx\n", queue_status);
10321 queue_status = GetQueueStatus(QS_POSTMESSAGE);
10322 ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %lx\n", queue_status);
10323 PostMessageA(hwnd, WM_APP+1, 0, 0);
10325 else if (message == WM_APP+1)
10327 queue_status = GetQueueStatus(QS_HOTKEY);
10328 ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %lx\n", queue_status);
10331 return ret;
10334 static BOOL RegisterWindowClasses(void)
10336 WNDCLASSA cls;
10337 WNDCLASSW clsW;
10339 cls.style = 0;
10340 cls.lpfnWndProc = MsgCheckProcA;
10341 cls.cbClsExtra = 0;
10342 cls.cbWndExtra = 0;
10343 cls.hInstance = GetModuleHandleA(0);
10344 cls.hIcon = 0;
10345 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
10346 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
10347 cls.lpszMenuName = NULL;
10348 cls.lpszClassName = "TestWindowClass";
10349 if(!RegisterClassA(&cls)) return FALSE;
10351 cls.lpfnWndProc = HotkeyMsgCheckProcA;
10352 cls.lpszClassName = "HotkeyWindowClass";
10353 if(!RegisterClassA(&cls)) return FALSE;
10355 cls.lpfnWndProc = ShowWindowProcA;
10356 cls.lpszClassName = "ShowWindowClass";
10357 if(!RegisterClassA(&cls)) return FALSE;
10359 cls.lpfnWndProc = PopupMsgCheckProcA;
10360 cls.lpszClassName = "TestPopupClass";
10361 if(!RegisterClassA(&cls)) return FALSE;
10363 cls.lpfnWndProc = ParentMsgCheckProcA;
10364 cls.lpszClassName = "TestParentClass";
10365 if(!RegisterClassA(&cls)) return FALSE;
10367 cls.lpfnWndProc = StopQuitMsgCheckProcA;
10368 cls.lpszClassName = "StopQuitClass";
10369 if(!RegisterClassA(&cls)) return FALSE;
10371 cls.lpfnWndProc = DefWindowProcA;
10372 cls.lpszClassName = "SimpleWindowClass";
10373 if(!RegisterClassA(&cls)) return FALSE;
10375 cls.lpfnWndProc = PaintLoopProcA;
10376 cls.lpszClassName = "PaintLoopWindowClass";
10377 if(!RegisterClassA(&cls)) return FALSE;
10379 cls.style = CS_NOCLOSE;
10380 cls.lpszClassName = "NoCloseWindowClass";
10381 if(!RegisterClassA(&cls)) return FALSE;
10383 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
10384 cls.style = 0;
10385 cls.hInstance = GetModuleHandleA(0);
10386 cls.hbrBackground = 0;
10387 cls.lpfnWndProc = TestDlgProcA;
10388 cls.lpszClassName = "TestDialogClass";
10389 if(!RegisterClassA(&cls)) return FALSE;
10391 clsW.style = 0;
10392 clsW.lpfnWndProc = MsgCheckProcW;
10393 clsW.cbClsExtra = 0;
10394 clsW.cbWndExtra = 0;
10395 clsW.hInstance = GetModuleHandleW(0);
10396 clsW.hIcon = 0;
10397 clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
10398 clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
10399 clsW.lpszMenuName = NULL;
10400 clsW.lpszClassName = testWindowClassW;
10401 RegisterClassW(&clsW); /* ignore error, this fails on Win9x */
10403 return TRUE;
10406 static BOOL is_our_logged_class(HWND hwnd)
10408 char buf[256];
10410 if (GetClassNameA(hwnd, buf, sizeof(buf)))
10412 if (!lstrcmpiA(buf, "TestWindowClass") ||
10413 !lstrcmpiA(buf, "ShowWindowClass") ||
10414 !lstrcmpiA(buf, "TestParentClass") ||
10415 !lstrcmpiA(buf, "TestPopupClass") ||
10416 !lstrcmpiA(buf, "SimpleWindowClass") ||
10417 !lstrcmpiA(buf, "TestDialogClass") ||
10418 !lstrcmpiA(buf, "MDI_frame_class") ||
10419 !lstrcmpiA(buf, "MDI_client_class") ||
10420 !lstrcmpiA(buf, "MDI_child_class") ||
10421 !lstrcmpiA(buf, "my_button_class") ||
10422 !lstrcmpiA(buf, "my_edit_class") ||
10423 !lstrcmpiA(buf, "static") ||
10424 !lstrcmpiA(buf, "ListBox") ||
10425 !lstrcmpiA(buf, "ComboBox") ||
10426 !lstrcmpiA(buf, "MyDialogClass") ||
10427 !lstrcmpiA(buf, "#32770") ||
10428 !lstrcmpiA(buf, "#32768"))
10429 return TRUE;
10431 return FALSE;
10434 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
10436 HWND hwnd;
10438 ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
10440 if (nCode == HCBT_CLICKSKIPPED)
10442 /* ignore this event, XP sends it a lot when switching focus between windows */
10443 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
10446 if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
10448 struct recvd_message msg;
10450 msg.hwnd = 0;
10451 msg.message = nCode;
10452 msg.flags = hook|wparam|lparam;
10453 msg.wParam = wParam;
10454 msg.lParam = lParam;
10455 msg.descr = "CBT";
10456 add_message(&msg);
10458 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
10461 if (nCode == HCBT_DESTROYWND)
10463 if (test_DestroyWindow_flag)
10465 DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
10466 if (style & WS_CHILD)
10467 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
10468 else if (style & WS_POPUP)
10469 lParam = WND_POPUP_ID;
10470 else
10471 lParam = WND_PARENT_ID;
10475 /* Log also SetFocus(0) calls */
10476 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
10478 if (is_our_logged_class(hwnd))
10480 struct recvd_message msg;
10482 msg.hwnd = hwnd;
10483 msg.message = nCode;
10484 msg.flags = hook|wparam|lparam;
10485 msg.wParam = wParam;
10486 msg.lParam = lParam;
10487 msg.descr = "CBT";
10488 add_message(&msg);
10490 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
10493 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
10494 DWORD event,
10495 HWND hwnd,
10496 LONG object_id,
10497 LONG child_id,
10498 DWORD thread_id,
10499 DWORD event_time)
10501 ok(thread_id == winevent_hook_thread_id, "we didn't ask for events from other threads\n");
10503 /* ignore mouse cursor events */
10504 if (object_id == OBJID_CURSOR) return;
10506 if (!hwnd || is_our_logged_class(hwnd))
10508 struct recvd_message msg;
10510 msg.hwnd = hwnd;
10511 msg.message = event;
10512 msg.flags = winevent_hook|wparam|lparam;
10513 msg.wParam = object_id;
10514 msg.lParam = child_id;
10515 msg.descr = "WEH";
10516 add_message(&msg);
10520 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
10521 static const WCHAR wszAnsi[] = {'U',0};
10523 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
10525 switch (uMsg)
10527 case CB_FINDSTRINGEXACT:
10528 trace("String: %p\n", (LPCWSTR)lParam);
10529 if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
10530 return 1;
10531 if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
10532 return 0;
10533 return -1;
10535 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
10538 static const struct message WmGetTextLengthAfromW[] = {
10539 { WM_GETTEXTLENGTH, sent },
10540 { WM_GETTEXT, sent|optional },
10541 { 0 }
10544 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
10546 /* dummy window proc for WM_GETTEXTLENGTH test */
10547 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
10549 switch(msg)
10551 case WM_GETTEXTLENGTH:
10552 return lstrlenW(dummy_window_text) + 37; /* some random length */
10553 case WM_GETTEXT:
10554 lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
10555 return lstrlenW( (LPWSTR)lp );
10556 default:
10557 return DefWindowProcW( hwnd, msg, wp, lp );
10561 static void test_message_conversion(void)
10563 static const WCHAR wszMsgConversionClass[] =
10564 {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
10565 WNDCLASSW cls;
10566 LRESULT lRes;
10567 HWND hwnd;
10568 WNDPROC wndproc, newproc;
10569 BOOL ret;
10571 cls.style = 0;
10572 cls.lpfnWndProc = MsgConversionProcW;
10573 cls.cbClsExtra = 0;
10574 cls.cbWndExtra = 0;
10575 cls.hInstance = GetModuleHandleW(NULL);
10576 cls.hIcon = NULL;
10577 cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
10578 cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
10579 cls.lpszMenuName = NULL;
10580 cls.lpszClassName = wszMsgConversionClass;
10581 /* this call will fail on Win9x, but that doesn't matter as this test is
10582 * meaningless on those platforms */
10583 if(!RegisterClassW(&cls)) return;
10585 hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
10586 100, 100, 200, 200, 0, 0, 0, NULL);
10587 ok(hwnd != NULL, "Window creation failed\n");
10589 /* {W, A} -> A */
10591 wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
10592 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10593 ok(lRes == 0, "String should have been converted\n");
10594 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10595 ok(lRes == 1, "String shouldn't have been converted\n");
10597 /* {W, A} -> W */
10599 wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
10600 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10601 ok(lRes == 1, "String shouldn't have been converted\n");
10602 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10603 ok(lRes == 1, "String shouldn't have been converted\n");
10605 /* Synchronous messages */
10607 lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10608 ok(lRes == 0, "String should have been converted\n");
10609 lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10610 ok(lRes == 1, "String shouldn't have been converted\n");
10612 /* Asynchronous messages */
10614 SetLastError(0);
10615 lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10616 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10617 "PostMessage on sync only message returned %Id, last error %ld\n", lRes, GetLastError());
10618 SetLastError(0);
10619 lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10620 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10621 "PostMessage on sync only message returned %Id, last error %ld\n", lRes, GetLastError());
10622 SetLastError(0);
10623 lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10624 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10625 "PosThreadtMessage on sync only message returned %Id, last error %ld\n", lRes, GetLastError());
10626 SetLastError(0);
10627 lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10628 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10629 "PosThreadtMessage on sync only message returned %Id, last error %ld\n", lRes, GetLastError());
10630 SetLastError(0);
10631 lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10632 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10633 "SendNotifyMessage on sync only message returned %Id, last error %ld\n", lRes, GetLastError());
10634 SetLastError(0);
10635 lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10636 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10637 "SendNotifyMessage on sync only message returned %Id, last error %ld\n", lRes, GetLastError());
10638 SetLastError(0);
10639 lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
10640 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10641 "SendMessageCallback on sync only message returned %Id, last error %ld\n", lRes, GetLastError());
10642 SetLastError(0);
10643 lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
10644 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10645 "SendMessageCallback on sync only message returned %Id, last error %ld\n", lRes, GetLastError());
10647 /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
10649 hwnd = CreateWindowW (testWindowClassW, wszUnicode,
10650 WS_OVERLAPPEDWINDOW,
10651 100, 100, 200, 200, 0, 0, 0, NULL);
10652 assert(hwnd);
10653 flush_sequence();
10654 lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
10655 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
10656 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
10657 "got bad length %Id\n", lRes );
10659 flush_sequence();
10660 lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
10661 hwnd, WM_GETTEXTLENGTH, 0, 0);
10662 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
10663 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
10664 "got bad length %Id\n", lRes );
10666 wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
10667 newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
10668 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
10669 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
10670 NULL, 0, NULL, NULL ) ||
10671 broken(lRes == lstrlenW(dummy_window_text) + 37),
10672 "got bad length %Id\n", lRes );
10674 SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc ); /* restore old wnd proc */
10675 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
10676 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
10677 NULL, 0, NULL, NULL ) ||
10678 broken(lRes == lstrlenW(dummy_window_text) + 37),
10679 "got bad length %Id\n", lRes );
10681 ret = DestroyWindow(hwnd);
10682 ok( ret, "DestroyWindow() error %ld\n", GetLastError());
10685 struct timer_info
10687 HWND hWnd;
10688 HANDLE handles[2];
10689 DWORD id;
10692 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
10696 #define TIMER_ID 0x19
10697 #define TIMER_COUNT_EXPECTED 100
10698 #define TIMER_COUNT_TOLERANCE 10
10700 static int count = 0;
10701 static void CALLBACK callback_count(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
10703 count++;
10706 static DWORD exception;
10707 static void CALLBACK callback_exception(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
10709 count++;
10710 RaiseException(exception, 0, 0, NULL);
10713 static DWORD WINAPI timer_thread_proc(LPVOID x)
10715 struct timer_info *info = x;
10716 DWORD r;
10718 r = KillTimer(info->hWnd, 0x19);
10719 ok(r,"KillTimer failed in thread\n");
10720 r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
10721 ok(r,"SetTimer failed in thread\n");
10722 ok(r==TIMER_ID,"SetTimer id different\n");
10723 r = SetEvent(info->handles[0]);
10724 ok(r,"SetEvent failed in thread\n");
10725 return 0;
10728 static void test_timers(void)
10730 struct timer_info info;
10731 DWORD start;
10732 DWORD id;
10733 MSG msg;
10735 info.hWnd = CreateWindowA("TestWindowClass", NULL,
10736 WS_OVERLAPPEDWINDOW ,
10737 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
10738 NULL, NULL, 0);
10740 info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
10741 ok(info.id, "SetTimer failed\n");
10742 ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
10743 info.handles[0] = CreateEventW(NULL,0,0,NULL);
10744 info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
10746 WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
10748 WaitForSingleObject(info.handles[1], INFINITE);
10750 CloseHandle(info.handles[0]);
10751 CloseHandle(info.handles[1]);
10753 ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
10755 /* Check the minimum allowed timeout for a timer. MSDN indicates that it should be 10.0 ms,
10756 * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to
10757 * 15.6 ms. Since there is some measurement error between test runs we are allowing for
10758 * ±9 counts (~4 ms) around the expected value.
10760 count = 0;
10761 id = SetTimer(info.hWnd, TIMER_ID, 0, callback_count);
10762 ok(id != 0, "did not get id from SetTimer.\n");
10763 ok(id==TIMER_ID, "SetTimer timer ID different\n");
10764 start = GetTickCount();
10765 while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
10766 DispatchMessageA(&msg);
10767 ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE /* xp */
10768 || broken(abs(count-64) <= TIMER_COUNT_TOLERANCE) /* most common */
10769 || broken(abs(count-43) <= TIMER_COUNT_TOLERANCE) /* w2k3, win8 */,
10770 "did not get expected count for minimum timeout (%d != ~%d).\n",
10771 count, TIMER_COUNT_EXPECTED);
10772 ok(KillTimer(info.hWnd, id), "KillTimer failed\n");
10773 /* Perform the same check on SetSystemTimer (only available on w2k3 and older) */
10774 if (pSetSystemTimer)
10776 int syscount = 0;
10778 count = 0;
10779 id = pSetSystemTimer(info.hWnd, TIMER_ID, 0, callback_count);
10780 ok(id != 0, "did not get id from SetSystemTimer.\n");
10781 ok(id==TIMER_ID, "SetTimer timer ID different\n");
10782 start = GetTickCount();
10783 while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
10785 if (msg.message == WM_SYSTIMER)
10786 syscount++;
10787 DispatchMessageA(&msg);
10789 ok(abs(syscount-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE
10790 || broken(abs(syscount-64) < TIMER_COUNT_TOLERANCE) /* most common */
10791 || broken(syscount > 4000 && syscount < 12000) /* win2k3sp0 */,
10792 "did not get expected count for minimum timeout (%d != ~%d).\n",
10793 syscount, TIMER_COUNT_EXPECTED);
10794 ok(count == 0, "did not get expected count for callback timeout (%d != 0).\n", count);
10795 ok(pKillSystemTimer(info.hWnd, id), "KillSystemTimer failed\n");
10798 ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
10801 static void test_timers_no_wnd(void)
10803 static UINT_PTR ids[0xffff];
10804 UINT_PTR id, id2;
10805 DWORD start;
10806 MSG msg;
10807 int i;
10809 count = 0;
10810 id = SetTimer(NULL, 0, 100, callback_count);
10811 ok(id != 0, "did not get id from SetTimer.\n");
10812 id2 = SetTimer(NULL, id, 200, callback_count);
10813 ok(id2 == id, "did not get same id from SetTimer when replacing (%Ii expected %Ii).\n", id2, id);
10814 Sleep(150);
10815 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10816 ok(count == 0, "did not get zero count as expected (%i).\n", count);
10817 Sleep(150);
10818 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10819 ok(count == 1, "did not get one count as expected (%i).\n", count);
10820 KillTimer(NULL, id);
10821 Sleep(250);
10822 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10823 ok(count == 1, "killing replaced timer did not work (%i).\n", count);
10825 /* Check the minimum allowed timeout for a timer. MSDN indicates that it should be 10.0 ms,
10826 * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to
10827 * 15.6 ms. Since there is some measurement error between test runs we are allowing for
10828 * ±9 counts (~4 ms) around the expected value.
10830 count = 0;
10831 id = SetTimer(NULL, 0, 0, callback_count);
10832 ok(id != 0, "did not get id from SetTimer.\n");
10833 start = GetTickCount();
10834 while (GetTickCount()-start < 1001 && GetMessageA(&msg, NULL, 0, 0))
10835 DispatchMessageA(&msg);
10836 ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE /* xp */
10837 || broken(abs(count-64) <= TIMER_COUNT_TOLERANCE) /* most common */
10838 || broken(abs(count-43) <= TIMER_COUNT_TOLERANCE) /* w1064v1809 */,
10839 "did not get expected count for minimum timeout (%d != ~%d).\n",
10840 count, TIMER_COUNT_EXPECTED);
10841 KillTimer(NULL, id);
10842 /* Note: SetSystemTimer doesn't support a NULL window, see test_timers */
10844 if (pSetCoalescableTimer)
10846 count = 0;
10847 id = pSetCoalescableTimer(NULL, 0, 0, callback_count, 0);
10848 ok(id != 0, "SetCoalescableTimer failed with %lu.\n", GetLastError());
10849 start = GetTickCount();
10850 while (GetTickCount()-start < 100 && GetMessageA(&msg, NULL, 0, 0))
10851 DispatchMessageA(&msg);
10852 ok(count > 1, "expected count > 1, got %d.\n", count);
10853 KillTimer(NULL, id);
10855 else
10856 win_skip("SetCoalescableTimer not available.\n");
10858 /* Check what happens when we're running out of timers */
10859 for (i = 0; i < ARRAY_SIZE(ids); i++)
10861 SetLastError(0xdeadbeef);
10862 ids[i] = SetTimer(NULL, 0, USER_TIMER_MAXIMUM, tfunc);
10863 if (!ids[i]) break;
10865 ok(i != ARRAY_SIZE(ids), "all timers were created successfully\n");
10866 ok(GetLastError()==ERROR_NO_MORE_USER_HANDLES || broken(GetLastError()==0xdeadbeef),
10867 "GetLastError() = %ld\n", GetLastError());
10868 while (i > 0) KillTimer(NULL, ids[--i]);
10871 static void test_timers_exception(DWORD code)
10873 UINT_PTR id;
10874 MSG msg;
10876 exception = code;
10877 id = SetTimer(NULL, 0, 1000, callback_exception);
10878 ok(id != 0, "did not get id from SetTimer.\n");
10880 memset(&msg, 0, sizeof(msg));
10881 msg.message = WM_TIMER;
10882 msg.wParam = id;
10883 msg.lParam = (LPARAM)callback_exception;
10885 count = 0;
10886 DispatchMessageA(&msg);
10887 ok(count == 1, "did not get one count as expected (%i).\n", count);
10889 KillTimer(NULL, id);
10892 static void test_timers_exceptions(void)
10894 test_timers_exception(EXCEPTION_ACCESS_VIOLATION);
10895 test_timers_exception(EXCEPTION_DATATYPE_MISALIGNMENT);
10896 test_timers_exception(EXCEPTION_BREAKPOINT);
10897 test_timers_exception(EXCEPTION_SINGLE_STEP);
10898 test_timers_exception(EXCEPTION_ARRAY_BOUNDS_EXCEEDED);
10899 test_timers_exception(EXCEPTION_FLT_DENORMAL_OPERAND);
10900 test_timers_exception(EXCEPTION_FLT_DIVIDE_BY_ZERO);
10901 test_timers_exception(EXCEPTION_FLT_INEXACT_RESULT);
10902 test_timers_exception(EXCEPTION_ILLEGAL_INSTRUCTION);
10903 test_timers_exception(0xE000BEEF); /* customer exception */
10906 /* Various win events with arbitrary parameters */
10907 static const struct message WmWinEventsSeq[] = {
10908 { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
10909 { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
10910 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
10911 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
10912 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
10913 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
10914 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
10915 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
10916 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
10917 /* our win event hook ignores OBJID_CURSOR events */
10918 /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
10919 { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
10920 { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
10921 { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
10922 { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
10923 { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
10924 { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
10925 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
10926 { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
10927 { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
10928 { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
10929 { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
10930 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
10931 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
10932 { 0 }
10934 static const struct message WmWinEventCaretSeq[] = {
10935 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
10936 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
10937 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
10938 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
10939 { 0 }
10941 static const struct message WmWinEventCaretSeq_2[] = {
10942 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
10943 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
10944 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
10945 { 0 }
10947 static const struct message WmWinEventAlertSeq[] = {
10948 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
10949 { 0 }
10951 static const struct message WmWinEventAlertSeq_2[] = {
10952 /* create window in the thread proc */
10953 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
10954 /* our test event */
10955 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
10956 { 0 }
10958 static const struct message WmGlobalHookSeq_1[] = {
10959 /* create window in the thread proc */
10960 { HCBT_CREATEWND, hook|lparam, 0, 2 },
10961 /* our test events */
10962 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
10963 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
10964 { 0 }
10966 static const struct message WmGlobalHookSeq_2[] = {
10967 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
10968 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
10969 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
10970 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
10971 { 0 }
10974 static const struct message WmMouseLLHookSeq[] = {
10975 { WM_MOUSEMOVE, hook },
10976 { WM_LBUTTONUP, hook },
10977 { WM_MOUSEMOVE, hook },
10978 { 0 }
10981 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
10982 DWORD event,
10983 HWND hwnd,
10984 LONG object_id,
10985 LONG child_id,
10986 DWORD thread_id,
10987 DWORD event_time)
10989 char buf[256];
10991 if (GetClassNameA(hwnd, buf, sizeof(buf)))
10993 if (!lstrcmpiA(buf, "TestWindowClass") ||
10994 !lstrcmpiA(buf, "static"))
10996 struct recvd_message msg;
10998 msg.hwnd = hwnd;
10999 msg.message = event;
11000 msg.flags = winevent_hook|wparam|lparam;
11001 msg.wParam = object_id;
11002 msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
11003 msg.descr = "WEH_2";
11004 add_message(&msg);
11009 static HHOOK hCBT_global_hook;
11010 static DWORD cbt_global_hook_thread_id;
11012 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
11014 HWND hwnd;
11015 char buf[256];
11017 if (nCode == HCBT_SYSCOMMAND)
11019 struct recvd_message msg;
11021 msg.hwnd = 0;
11022 msg.message = nCode;
11023 msg.flags = hook|wparam|lparam;
11024 msg.wParam = wParam;
11025 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
11026 msg.descr = "CBT_2";
11027 add_message(&msg);
11029 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
11031 /* WH_MOUSE_LL hook */
11032 if (nCode == HC_ACTION)
11034 MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
11036 /* we can't test for real mouse events */
11037 if (mhll->flags & LLMHF_INJECTED)
11039 struct recvd_message msg;
11041 memset (&msg, 0, sizeof (msg));
11042 msg.message = wParam;
11043 msg.flags = hook;
11044 msg.descr = "CBT_2";
11045 add_message(&msg);
11047 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
11050 /* Log also SetFocus(0) calls */
11051 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
11053 if (GetClassNameA(hwnd, buf, sizeof(buf)))
11055 if (!lstrcmpiA(buf, "TestWindowClass") ||
11056 !lstrcmpiA(buf, "static"))
11058 struct recvd_message msg;
11060 msg.hwnd = hwnd;
11061 msg.message = nCode;
11062 msg.flags = hook|wparam|lparam;
11063 msg.wParam = wParam;
11064 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
11065 msg.descr = "CBT_2";
11066 add_message(&msg);
11069 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
11072 static DWORD WINAPI win_event_global_thread_proc(void *param)
11074 HWND hwnd;
11075 MSG msg;
11076 HANDLE hevent = *(HANDLE *)param;
11078 assert(pNotifyWinEvent);
11080 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
11081 assert(hwnd);
11082 trace("created thread window %p\n", hwnd);
11084 *(HWND *)param = hwnd;
11086 flush_sequence();
11087 /* this event should be received only by our new hook proc,
11088 * an old one does not expect an event from another thread.
11090 pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
11091 SetEvent(hevent);
11093 while (GetMessageA(&msg, 0, 0, 0))
11095 TranslateMessage(&msg);
11096 DispatchMessageA(&msg);
11098 return 0;
11101 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
11103 HWND hwnd;
11104 MSG msg;
11105 HANDLE hevent = *(HANDLE *)param;
11107 flush_sequence();
11108 /* these events should be received only by our new hook proc,
11109 * an old one does not expect an event from another thread.
11112 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
11113 assert(hwnd);
11114 trace("created thread window %p\n", hwnd);
11116 *(HWND *)param = hwnd;
11118 /* Windows doesn't like when a thread plays games with the focus,
11119 that leads to all kinds of misbehaviours and failures to activate
11120 a window. So, better keep next lines commented out.
11121 SetFocus(0);
11122 SetFocus(hwnd);*/
11124 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
11125 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
11127 SetEvent(hevent);
11129 while (GetMessageA(&msg, 0, 0, 0))
11131 TranslateMessage(&msg);
11132 DispatchMessageA(&msg);
11134 return 0;
11137 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
11139 HWND hwnd;
11140 MSG msg;
11141 HANDLE hevent = *(HANDLE *)param;
11143 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
11144 assert(hwnd);
11145 trace("created thread window %p\n", hwnd);
11147 *(HWND *)param = hwnd;
11149 flush_sequence();
11151 /* Windows doesn't like when a thread plays games with the focus,
11152 * that leads to all kinds of misbehaviours and failures to activate
11153 * a window. So, better don't generate a mouse click message below.
11155 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
11156 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
11157 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
11159 SetEvent(hevent);
11160 while (GetMessageA(&msg, 0, 0, 0))
11162 TranslateMessage(&msg);
11163 DispatchMessageA(&msg);
11165 return 0;
11168 static void test_winevents(void)
11170 BOOL ret;
11171 MSG msg;
11172 HWND hwnd, hwnd2;
11173 UINT i;
11174 HANDLE hthread, hevent;
11175 DWORD tid;
11176 HWINEVENTHOOK hhook;
11177 const struct message *events = WmWinEventsSeq;
11179 hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
11180 WS_OVERLAPPEDWINDOW,
11181 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
11182 NULL, NULL, 0);
11183 assert(hwnd);
11185 /****** start of global hook test *************/
11186 hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
11187 if (!hCBT_global_hook)
11189 ok(DestroyWindow(hwnd), "failed to destroy window\n");
11190 skip( "cannot set global hook\n" );
11191 return;
11194 hevent = CreateEventA(NULL, 0, 0, NULL);
11195 assert(hevent);
11196 hwnd2 = hevent;
11198 hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
11199 ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError());
11201 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
11203 ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
11205 flush_sequence();
11206 /* this one should be received only by old hook proc */
11207 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
11208 /* this one should be received only by old hook proc */
11209 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
11211 ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
11213 ret = UnhookWindowsHookEx(hCBT_global_hook);
11214 ok( ret, "UnhookWindowsHookEx error %ld\n", GetLastError());
11216 PostThreadMessageA(tid, WM_QUIT, 0, 0);
11217 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
11218 CloseHandle(hthread);
11219 CloseHandle(hevent);
11220 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
11221 /****** end of global hook test *************/
11223 if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
11225 ok(DestroyWindow(hwnd), "failed to destroy window\n");
11226 return;
11229 flush_sequence();
11231 if (0)
11233 /* this test doesn't pass under Win9x */
11234 /* win2k ignores events with hwnd == 0 */
11235 SetLastError(0xdeadbeef);
11236 pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
11237 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
11238 GetLastError() == 0xdeadbeef, /* Win9x */
11239 "unexpected error %ld\n", GetLastError());
11240 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
11243 for (i = 0; i < ARRAY_SIZE(WmWinEventsSeq); i++)
11244 pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
11246 ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
11248 /****** start of event filtering test *************/
11249 hhook = pSetWinEventHook(
11250 EVENT_OBJECT_SHOW, /* 0x8002 */
11251 EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
11252 GetModuleHandleA(0), win_event_global_hook_proc,
11253 GetCurrentProcessId(), 0,
11254 WINEVENT_INCONTEXT);
11255 ok(hhook != 0, "SetWinEventHook error %ld\n", GetLastError());
11257 hevent = CreateEventA(NULL, 0, 0, NULL);
11258 assert(hevent);
11259 hwnd2 = hevent;
11261 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
11262 ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError());
11264 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
11266 ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
11268 flush_sequence();
11269 /* this one should be received only by old hook proc */
11270 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
11271 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
11272 /* this one should be received only by old hook proc */
11273 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
11275 ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
11277 ret = pUnhookWinEvent(hhook);
11278 ok( ret, "UnhookWinEvent error %ld\n", GetLastError());
11280 PostThreadMessageA(tid, WM_QUIT, 0, 0);
11281 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
11282 CloseHandle(hthread);
11283 CloseHandle(hevent);
11284 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
11285 /****** end of event filtering test *************/
11287 /****** start of out of context event test *************/
11288 hhook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0,
11289 win_event_global_hook_proc, GetCurrentProcessId(), 0,
11290 WINEVENT_OUTOFCONTEXT);
11291 ok(hhook != 0, "SetWinEventHook error %ld\n", GetLastError());
11293 hevent = CreateEventA(NULL, 0, 0, NULL);
11294 assert(hevent);
11295 hwnd2 = hevent;
11297 flush_sequence();
11299 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
11300 ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError());
11302 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
11304 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
11305 /* process pending winevent messages */
11306 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
11307 ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
11309 flush_sequence();
11310 /* this one should be received only by old hook proc */
11311 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
11312 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
11313 /* this one should be received only by old hook proc */
11314 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
11316 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
11317 /* process pending winevent messages */
11318 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
11319 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
11321 ret = pUnhookWinEvent(hhook);
11322 ok( ret, "UnhookWinEvent error %ld\n", GetLastError());
11324 PostThreadMessageA(tid, WM_QUIT, 0, 0);
11325 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
11326 CloseHandle(hthread);
11327 CloseHandle(hevent);
11328 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
11329 /****** end of out of context event test *************/
11331 /****** start of MOUSE_LL hook test *************/
11332 hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
11333 /* WH_MOUSE_LL is not supported on Win9x platforms */
11334 if (!hCBT_global_hook)
11336 win_skip("Skipping WH_MOUSE_LL test on this platform\n");
11337 goto skip_mouse_ll_hook_test;
11340 hevent = CreateEventA(NULL, 0, 0, NULL);
11341 assert(hevent);
11342 hwnd2 = hevent;
11344 hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
11345 ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError());
11347 while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
11348 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
11350 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
11351 flush_sequence();
11353 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
11354 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
11355 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
11357 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
11359 ret = UnhookWindowsHookEx(hCBT_global_hook);
11360 ok( ret, "UnhookWindowsHookEx error %ld\n", GetLastError());
11362 PostThreadMessageA(tid, WM_QUIT, 0, 0);
11363 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
11364 CloseHandle(hthread);
11365 CloseHandle(hevent);
11366 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
11367 /****** end of MOUSE_LL hook test *************/
11368 skip_mouse_ll_hook_test:
11370 ok(DestroyWindow(hwnd), "failed to destroy window\n");
11373 static void test_set_hook(void)
11375 BOOL ret;
11376 HHOOK hhook;
11377 HWINEVENTHOOK hwinevent_hook;
11379 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
11380 ok(hhook != 0, "local hook does not require hModule set to 0\n");
11381 UnhookWindowsHookEx(hhook);
11383 if (0)
11385 /* this test doesn't pass under Win9x: BUG! */
11386 SetLastError(0xdeadbeef);
11387 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
11388 ok(!hhook, "global hook requires hModule != 0\n");
11389 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %ld\n", GetLastError());
11392 SetLastError(0xdeadbeef);
11393 hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
11394 ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
11395 ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
11396 GetLastError() == 0xdeadbeef, /* Win9x */
11397 "unexpected error %ld\n", GetLastError());
11399 SetLastError(0xdeadbeef);
11400 ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
11401 ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
11402 GetLastError() == 0xdeadbeef, /* Win9x */
11403 "unexpected error %ld\n", GetLastError());
11405 if (!pSetWinEventHook || !pUnhookWinEvent) return;
11407 /* even process local incontext hooks require hmodule */
11408 SetLastError(0xdeadbeef);
11409 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
11410 GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
11411 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
11412 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
11413 GetLastError() == 0xdeadbeef, /* Win9x */
11414 "unexpected error %ld\n", GetLastError());
11416 /* even thread local incontext hooks require hmodule */
11417 SetLastError(0xdeadbeef);
11418 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
11419 GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
11420 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
11421 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
11422 GetLastError() == 0xdeadbeef, /* Win9x */
11423 "unexpected error %ld\n", GetLastError());
11425 if (0)
11427 /* these 3 tests don't pass under Win9x */
11428 SetLastError(0xdeadbeef);
11429 hwinevent_hook = pSetWinEventHook(1, 0, 0, win_event_proc,
11430 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
11431 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
11432 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %ld\n", GetLastError());
11434 SetLastError(0xdeadbeef);
11435 hwinevent_hook = pSetWinEventHook(-1, 1, 0, win_event_proc,
11436 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
11437 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
11438 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %ld\n", GetLastError());
11440 SetLastError(0xdeadbeef);
11441 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
11442 0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
11443 ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
11444 ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %ld\n", GetLastError());
11447 SetLastError(0xdeadbeef);
11448 hwinevent_hook = pSetWinEventHook(0, 0, 0, win_event_proc,
11449 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
11450 ok(hwinevent_hook != 0, "SetWinEventHook error %ld\n", GetLastError());
11451 ok(GetLastError() == 0xdeadbeef, "unexpected error %ld\n", GetLastError());
11452 ret = pUnhookWinEvent(hwinevent_hook);
11453 ok( ret, "UnhookWinEvent error %ld\n", GetLastError());
11455 todo_wine {
11456 /* This call succeeds under win2k SP4, but fails under Wine.
11457 Does win2k test/use passed process id? */
11458 SetLastError(0xdeadbeef);
11459 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
11460 0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
11461 ok(hwinevent_hook != 0, "SetWinEventHook error %ld\n", GetLastError());
11462 ok(GetLastError() == 0xdeadbeef, "unexpected error %ld\n", GetLastError());
11463 ret = pUnhookWinEvent(hwinevent_hook);
11464 ok( ret, "UnhookWinEvent error %ld\n", GetLastError());
11467 SetLastError(0xdeadbeef);
11468 ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
11469 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
11470 GetLastError() == 0xdeadbeef, /* Win9x */
11471 "unexpected error %ld\n", GetLastError());
11474 static HWND hook_hwnd;
11475 static HHOOK recursive_hook;
11476 static int hook_depth, max_hook_depth;
11478 static LRESULT WINAPI rec_get_message_hook(int code, WPARAM w, LPARAM l)
11480 LRESULT res;
11481 MSG msg;
11482 BOOL b;
11484 hook_depth++;
11485 if(hook_depth > max_hook_depth)
11486 max_hook_depth = hook_depth;
11488 b = PeekMessageW(&msg, hook_hwnd, 0, 0, PM_NOREMOVE);
11489 ok(b, "PeekMessage failed\n");
11491 res = CallNextHookEx(recursive_hook, code, w, l);
11493 hook_depth--;
11494 return res;
11497 static void test_recursive_hook(void)
11499 MSG msg;
11500 BOOL b;
11502 hook_hwnd = CreateWindowA("Static", NULL, WS_POPUP, 0, 0, 200, 60, NULL, NULL, NULL, NULL);
11503 ok(hook_hwnd != NULL, "CreateWindow failed\n");
11505 recursive_hook = SetWindowsHookExW(WH_GETMESSAGE, rec_get_message_hook, NULL, GetCurrentThreadId());
11506 ok(recursive_hook != NULL, "SetWindowsHookEx failed\n");
11508 PostMessageW(hook_hwnd, WM_USER, 0, 0);
11509 PostMessageW(hook_hwnd, WM_USER+1, 0, 0);
11511 hook_depth = 0;
11512 GetMessageW(&msg, hook_hwnd, 0, 0);
11513 ok(15 <= max_hook_depth && max_hook_depth < 45, "max_hook_depth = %d\n", max_hook_depth);
11514 trace("max_hook_depth = %d\n", max_hook_depth);
11516 b = UnhookWindowsHookEx(recursive_hook);
11517 ok(b, "UnhokWindowsHookEx failed\n");
11519 DestroyWindow(hook_hwnd);
11522 static const struct message ScrollWindowPaint1[] = {
11523 { WM_PAINT, sent },
11524 { WM_ERASEBKGND, sent|beginpaint },
11525 { WM_GETTEXTLENGTH, sent|optional },
11526 { WM_PAINT, sent|optional },
11527 { WM_NCPAINT, sent|beginpaint|optional },
11528 { WM_GETTEXT, sent|beginpaint|optional },
11529 { WM_GETTEXT, sent|beginpaint|optional },
11530 { WM_GETTEXT, sent|beginpaint|optional },
11531 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
11532 { WM_ERASEBKGND, sent|beginpaint|optional },
11533 { 0 }
11536 static const struct message ScrollWindowPaint2[] = {
11537 { WM_PAINT, sent },
11538 { 0 }
11541 static void test_scrollwindowex(void)
11543 HWND hwnd, hchild;
11544 RECT rect={0,0,130,130};
11546 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
11547 WS_VISIBLE|WS_OVERLAPPEDWINDOW,
11548 100, 100, 200, 200, 0, 0, 0, NULL);
11549 ok (hwnd != 0, "Failed to create overlapped window\n");
11550 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
11551 WS_VISIBLE|WS_CAPTION|WS_CHILD,
11552 10, 10, 150, 150, hwnd, 0, 0, NULL);
11553 ok (hchild != 0, "Failed to create child\n");
11554 UpdateWindow(hwnd);
11555 flush_events();
11556 flush_sequence();
11558 /* scroll without the child window */
11559 trace("start scroll\n");
11560 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
11561 SW_ERASE|SW_INVALIDATE);
11562 ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
11563 trace("end scroll\n");
11564 flush_sequence();
11565 flush_events();
11566 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
11567 flush_events();
11568 flush_sequence();
11570 /* Now without the SW_ERASE flag */
11571 trace("start scroll\n");
11572 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
11573 ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
11574 trace("end scroll\n");
11575 flush_sequence();
11576 flush_events();
11577 ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", FALSE);
11578 flush_events();
11579 flush_sequence();
11581 /* now scroll the child window as well */
11582 trace("start scroll\n");
11583 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
11584 SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
11585 /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
11586 /* windows sometimes a WM_MOVE */
11587 ok_sequence(WmEmptySeq, "ScrollWindowEx", TRUE);
11588 trace("end scroll\n");
11589 flush_sequence();
11590 flush_events();
11591 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
11592 flush_events();
11593 flush_sequence();
11595 /* now scroll with ScrollWindow() */
11596 trace("start scroll with ScrollWindow\n");
11597 ScrollWindow( hwnd, 5, 5, NULL, NULL);
11598 trace("end scroll\n");
11599 flush_sequence();
11600 flush_events();
11601 ok_sequence(ScrollWindowPaint1, "ScrollWindow", FALSE);
11603 ok(DestroyWindow(hchild), "failed to destroy window\n");
11604 ok(DestroyWindow(hwnd), "failed to destroy window\n");
11605 flush_sequence();
11608 static const struct message destroy_window_with_children[] = {
11609 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* popup */
11610 { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
11611 { 0x0090, sent|optional },
11612 { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
11613 { 0x0090, sent|optional },
11614 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* popup */
11615 { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
11616 { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
11617 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
11618 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* parent */
11619 { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
11620 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
11621 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
11622 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
11623 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
11624 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
11625 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
11626 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
11627 { 0 }
11630 static void test_DestroyWindow(void)
11632 BOOL ret;
11633 HWND parent, child1, child2, child3, child4, test;
11634 UINT_PTR child_id = WND_CHILD_ID + 1;
11636 parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11637 100, 100, 200, 200, 0, 0, 0, NULL);
11638 assert(parent != 0);
11639 child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
11640 0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
11641 assert(child1 != 0);
11642 child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
11643 0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
11644 assert(child2 != 0);
11645 child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
11646 0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
11647 assert(child3 != 0);
11648 child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
11649 0, 0, 50, 50, parent, 0, 0, NULL);
11650 assert(child4 != 0);
11652 /* test owner/parent of child2 */
11653 test = GetParent(child2);
11654 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
11655 ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
11656 test = GetAncestor(child2, GA_PARENT);
11657 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
11658 test = GetWindow(child2, GW_OWNER);
11659 ok(!test, "wrong owner %p\n", test);
11661 test = SetParent(child2, parent);
11662 ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
11664 /* test owner/parent of the parent */
11665 test = GetParent(parent);
11666 ok(!test, "wrong parent %p\n", test);
11667 ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
11668 test = GetAncestor(parent, GA_PARENT);
11669 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
11670 test = GetWindow(parent, GW_OWNER);
11671 ok(!test, "wrong owner %p\n", test);
11673 /* test owner/parent of child1 */
11674 test = GetParent(child1);
11675 ok(test == parent, "wrong parent %p\n", test);
11676 ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
11677 test = GetAncestor(child1, GA_PARENT);
11678 ok(test == parent, "wrong parent %p\n", test);
11679 test = GetWindow(child1, GW_OWNER);
11680 ok(!test, "wrong owner %p\n", test);
11682 /* test owner/parent of child2 */
11683 test = GetParent(child2);
11684 ok(test == parent, "wrong parent %p\n", test);
11685 ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
11686 test = GetAncestor(child2, GA_PARENT);
11687 ok(test == parent, "wrong parent %p\n", test);
11688 test = GetWindow(child2, GW_OWNER);
11689 ok(!test, "wrong owner %p\n", test);
11691 /* test owner/parent of child3 */
11692 test = GetParent(child3);
11693 ok(test == child1, "wrong parent %p\n", test);
11694 ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
11695 test = GetAncestor(child3, GA_PARENT);
11696 ok(test == child1, "wrong parent %p\n", test);
11697 test = GetWindow(child3, GW_OWNER);
11698 ok(!test, "wrong owner %p\n", test);
11700 /* test owner/parent of child4 */
11701 test = GetParent(child4);
11702 ok(test == parent, "wrong parent %p\n", test);
11703 ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
11704 test = GetAncestor(child4, GA_PARENT);
11705 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
11706 test = GetWindow(child4, GW_OWNER);
11707 ok(test == parent, "wrong owner %p\n", test);
11709 flush_sequence();
11711 trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
11712 parent, child1, child2, child3, child4);
11714 SetCapture(child4);
11715 test = GetCapture();
11716 ok(test == child4, "wrong capture window %p\n", test);
11718 test_DestroyWindow_flag = TRUE;
11719 ret = DestroyWindow(parent);
11720 ok( ret, "DestroyWindow() error %ld\n", GetLastError());
11721 test_DestroyWindow_flag = FALSE;
11722 ok_sequence(destroy_window_with_children, "destroy window with children", FALSE);
11724 ok(!IsWindow(parent), "parent still exists\n");
11725 ok(!IsWindow(child1), "child1 still exists\n");
11726 ok(!IsWindow(child2), "child2 still exists\n");
11727 ok(!IsWindow(child3), "child3 still exists\n");
11728 ok(!IsWindow(child4), "child4 still exists\n");
11730 test = GetCapture();
11731 ok(!test, "wrong capture window %p\n", test);
11735 static const struct message WmDispatchPaint[] = {
11736 { WM_NCPAINT, sent },
11737 { WM_GETTEXT, sent|defwinproc|optional },
11738 { WM_GETTEXT, sent|defwinproc|optional },
11739 { WM_ERASEBKGND, sent },
11740 { 0 }
11743 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11745 if (message == WM_PAINT) return 0;
11746 return MsgCheckProcA( hwnd, message, wParam, lParam );
11749 static void test_DispatchMessage(void)
11751 RECT rect;
11752 MSG msg;
11753 int count;
11754 HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11755 100, 100, 200, 200, 0, 0, 0, NULL);
11756 ShowWindow( hwnd, SW_SHOW );
11757 UpdateWindow( hwnd );
11758 flush_events();
11759 flush_sequence();
11760 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
11762 SetRect( &rect, -5, -5, 5, 5 );
11763 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
11764 count = 0;
11765 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
11767 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
11768 else
11770 flush_sequence();
11771 DispatchMessageA( &msg );
11772 /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
11773 if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
11774 else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
11775 if (++count > 10) break;
11778 ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
11780 trace("now without DispatchMessage\n");
11781 flush_sequence();
11782 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
11783 count = 0;
11784 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
11786 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
11787 else
11789 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
11790 flush_sequence();
11791 /* this will send WM_NCCPAINT just like DispatchMessage does */
11792 GetUpdateRgn( hwnd, hrgn, TRUE );
11793 ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
11794 DeleteObject( hrgn );
11795 GetClientRect( hwnd, &rect );
11796 ValidateRect( hwnd, &rect ); /* this will stop WM_PAINTs */
11797 ok( !count, "Got multiple WM_PAINTs\n" );
11798 if (++count > 10) break;
11802 flush_sequence();
11803 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
11804 count = 0;
11805 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
11807 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
11808 else
11810 HDC hdc;
11812 flush_sequence();
11813 hdc = BeginPaint( hwnd, NULL );
11814 ok( !hdc, "got valid hdc %p from BeginPaint\n", hdc );
11815 ok( !EndPaint( hwnd, NULL ), "EndPaint succeeded\n" );
11816 ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
11817 ok( !count, "Got multiple WM_PAINTs\n" );
11818 if (++count > 10) break;
11821 DestroyWindow(hwnd);
11825 static const struct message WmUser[] = {
11826 { WM_USER, sent },
11827 { 0 }
11830 struct sendmsg_info
11832 HWND hwnd;
11833 DWORD timeout;
11834 DWORD ret;
11835 HANDLE ready;
11838 static DWORD CALLBACK send_msg_thread( LPVOID arg )
11840 struct sendmsg_info *info = arg;
11841 SetLastError( 0xdeadbeef );
11842 SetEvent( info->ready );
11843 info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
11844 if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT ||
11845 broken(GetLastError() == 0), /* win9x */
11846 "unexpected error %ld\n", GetLastError());
11847 return 0;
11850 static void wait_for_thread( HANDLE thread )
11852 while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
11854 MSG msg;
11855 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA(&msg);
11859 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11861 if (message == WM_USER) Sleep(200);
11862 return MsgCheckProcA( hwnd, message, wParam, lParam );
11865 static void test_SendMessageTimeout(void)
11867 HANDLE thread;
11868 struct sendmsg_info info;
11869 DWORD tid;
11870 BOOL is_win9x;
11872 info.ready = CreateEventA( NULL, 0, 0, NULL );
11873 info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11874 100, 100, 200, 200, 0, 0, 0, NULL);
11875 flush_events();
11876 flush_sequence();
11878 info.timeout = 1000;
11879 info.ret = 0xdeadbeef;
11880 ResetEvent( info.ready );
11881 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11882 WaitForSingleObject( info.ready, INFINITE );
11883 wait_for_thread( thread );
11884 CloseHandle( thread );
11885 ok( info.ret == 1, "SendMessageTimeout failed\n" );
11886 ok_sequence( WmUser, "WmUser", FALSE );
11888 info.timeout = 1;
11889 info.ret = 0xdeadbeef;
11890 ResetEvent( info.ready );
11891 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11892 WaitForSingleObject( info.ready, INFINITE );
11893 Sleep(100); /* SendMessageTimeout should time out here */
11894 wait_for_thread( thread );
11895 CloseHandle( thread );
11896 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
11897 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
11899 /* 0 means infinite timeout (but not on win9x) */
11900 info.timeout = 0;
11901 info.ret = 0xdeadbeef;
11902 ResetEvent( info.ready );
11903 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11904 WaitForSingleObject( info.ready, INFINITE );
11905 Sleep(100);
11906 wait_for_thread( thread );
11907 CloseHandle( thread );
11908 is_win9x = !info.ret;
11909 if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
11910 else ok_sequence( WmUser, "WmUser", FALSE );
11912 /* timeout is treated as signed despite the prototype (but not on win9x) */
11913 info.timeout = 0x7fffffff;
11914 info.ret = 0xdeadbeef;
11915 ResetEvent( info.ready );
11916 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11917 WaitForSingleObject( info.ready, INFINITE );
11918 Sleep(100);
11919 wait_for_thread( thread );
11920 CloseHandle( thread );
11921 ok( info.ret == 1, "SendMessageTimeout failed\n" );
11922 ok_sequence( WmUser, "WmUser", FALSE );
11924 info.timeout = 0x80000000;
11925 info.ret = 0xdeadbeef;
11926 ResetEvent( info.ready );
11927 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11928 WaitForSingleObject( info.ready, INFINITE );
11929 Sleep(100);
11930 wait_for_thread( thread );
11931 CloseHandle( thread );
11932 if (is_win9x)
11934 ok( info.ret == 1, "SendMessageTimeout failed\n" );
11935 ok_sequence( WmUser, "WmUser", FALSE );
11937 else
11939 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
11940 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
11943 /* now check for timeout during message processing */
11944 SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
11945 info.timeout = 100;
11946 info.ret = 0xdeadbeef;
11947 ResetEvent( info.ready );
11948 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11949 WaitForSingleObject( info.ready, INFINITE );
11950 wait_for_thread( thread );
11951 CloseHandle( thread );
11952 /* we should time out but still get the message */
11953 ok( info.ret == 0, "SendMessageTimeout failed\n" );
11954 ok_sequence( WmUser, "WmUser", FALSE );
11956 DestroyWindow( info.hwnd );
11957 CloseHandle( info.ready );
11961 /****************** edit message test *************************/
11962 #define ID_EDIT 0x1234
11963 static const struct message sl_edit_setfocus[] =
11965 { HCBT_SETFOCUS, hook },
11966 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11967 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11968 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
11969 { WM_SETFOCUS, sent|wparam, 0 },
11970 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11971 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
11972 { WM_CTLCOLOREDIT, sent|parent },
11973 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11974 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
11975 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
11976 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11977 { 0 }
11979 static const struct message sl_edit_invisible[] =
11981 { HCBT_SETFOCUS, hook },
11982 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11983 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11984 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Sent for IME. */
11985 { WM_KILLFOCUS, sent|parent },
11986 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11987 { WM_SETFOCUS, sent },
11988 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
11989 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
11990 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11991 { 0 }
11993 static const struct message ml_edit_setfocus[] =
11995 { HCBT_SETFOCUS, hook },
11996 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11997 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11998 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
11999 { WM_SETFOCUS, sent|wparam, 0 },
12000 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
12001 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
12002 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
12003 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
12004 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CARET, 0 },
12005 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
12006 { 0 }
12008 static const struct message sl_edit_killfocus[] =
12010 { HCBT_SETFOCUS, hook },
12011 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
12012 { WM_KILLFOCUS, sent|wparam, 0 },
12013 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
12014 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
12015 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
12016 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
12017 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
12018 { 0 }
12020 static const struct message sl_edit_lbutton_dblclk[] =
12022 { WM_LBUTTONDBLCLK, sent },
12023 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
12024 { 0 }
12026 static const struct message sl_edit_lbutton_down[] =
12028 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
12029 { HCBT_SETFOCUS, hook },
12030 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
12031 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
12032 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
12033 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
12034 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
12035 { WM_CTLCOLOREDIT, sent|parent },
12036 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
12037 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
12038 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CARET, 0 },
12039 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
12040 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
12041 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
12042 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
12043 { WM_CTLCOLOREDIT, sent|parent|optional },
12044 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
12045 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CARET, 0 },
12046 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
12047 { 0 }
12049 static const struct message ml_edit_lbutton_down[] =
12051 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
12052 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
12053 { HCBT_SETFOCUS, hook },
12054 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
12055 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
12056 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
12057 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
12058 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
12059 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
12060 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
12061 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
12062 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
12063 { 0 }
12065 static const struct message sl_edit_lbutton_up[] =
12067 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
12068 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
12069 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
12070 { WM_CAPTURECHANGED, sent|defwinproc },
12071 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
12072 { 0 }
12074 static const struct message ml_edit_lbutton_up[] =
12076 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
12077 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
12078 { WM_CAPTURECHANGED, sent|defwinproc },
12079 { 0 }
12082 static WNDPROC old_edit_proc;
12084 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
12086 static LONG defwndproc_counter = 0;
12087 LRESULT ret;
12088 struct recvd_message msg;
12090 if (ignore_message( message )) return 0;
12092 msg.hwnd = hwnd;
12093 msg.message = message;
12094 msg.flags = sent|wparam|lparam;
12095 if (defwndproc_counter) msg.flags |= defwinproc;
12096 msg.wParam = wParam;
12097 msg.lParam = lParam;
12098 msg.descr = "edit";
12099 add_message(&msg);
12101 defwndproc_counter++;
12102 ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
12103 defwndproc_counter--;
12105 return ret;
12108 static const struct message edit_wm_ime_composition_seq[] =
12110 {WM_IME_STARTCOMPOSITION, sent},
12111 {WM_IME_COMPOSITION, sent | wparam, 'W'},
12112 {WM_IME_CHAR, sent | wparam | defwinproc, 'W'},
12113 {WM_IME_CHAR, sent | wparam | defwinproc, 'i'},
12114 {WM_IME_CHAR, sent | wparam | defwinproc, 'n'},
12115 {WM_IME_CHAR, sent | wparam | defwinproc, 'e'},
12116 {WM_IME_ENDCOMPOSITION, sent},
12117 {WM_CHAR, sent | wparam, 'W'},
12118 {WM_CHAR, sent | wparam, 'i'},
12119 {WM_CHAR, sent | wparam, 'n'},
12120 {WM_CHAR, sent | wparam, 'e'},
12124 static const struct message edit_wm_ime_char_seq[] =
12126 {WM_IME_CHAR, sent | wparam, '0'},
12127 {WM_CHAR, sent | wparam, '0'},
12131 static const struct message edit_eimes_getcompstratonce_seq[] =
12133 {WM_IME_STARTCOMPOSITION, sent},
12134 {WM_IME_COMPOSITION, sent | wparam, 'W'},
12135 {WM_IME_ENDCOMPOSITION, sent},
12139 static LRESULT CALLBACK edit_ime_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
12141 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
12142 static LONG defwndproc_counter = 0;
12143 struct recvd_message msg = {0};
12144 LRESULT ret;
12146 msg.message = message;
12147 msg.flags = sent | wparam;
12148 if (defwndproc_counter)
12149 msg.flags |= defwinproc;
12150 msg.wParam = wParam;
12152 if (message < 0xc000 &&
12153 message != WM_GETTEXTLENGTH &&
12154 message != WM_GETTEXT &&
12155 message != WM_GETFONT &&
12156 message != WM_GETICON &&
12157 message != WM_IME_SETCONTEXT &&
12158 message != WM_IME_NOTIFY &&
12159 message != WM_CTLCOLOREDIT &&
12160 message != WM_PAINT &&
12161 message != WM_ERASEBKGND &&
12162 message != WM_NCHITTEST &&
12163 message != WM_SETCURSOR &&
12164 message != WM_MOUSEMOVE &&
12165 message != WM_MOUSEACTIVATE &&
12166 message != WM_KEYUP &&
12167 (message < EM_GETSEL || message > EM_GETIMESTATUS))
12169 add_message(&msg);
12172 defwndproc_counter++;
12173 if (IsWindowUnicode(hwnd))
12174 ret = CallWindowProcW(oldproc, hwnd, message, wParam, lParam);
12175 else
12176 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
12177 defwndproc_counter--;
12179 return ret;
12182 static DWORD WINAPI test_edit_ime_messages(void *unused_arg)
12184 WNDPROC old_proc;
12185 LRESULT lr;
12186 HIMC himc;
12187 HWND hwnd;
12188 BOOL ret;
12189 MSG msg;
12191 hwnd = CreateWindowA(WC_EDITA, "Test", WS_POPUP | WS_VISIBLE, 10, 10, 300, 300, NULL, NULL,
12192 NULL, NULL);
12193 ok(hwnd != NULL, "CreateWindowA failed.\n");
12195 /* Test EM_{GET|SET}IMESTATUS */
12196 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
12197 ok(lr == 0, "Got unexpected lr %#Ix.\n", lr);
12199 /* Note that EM_SETIMESTATUS always return 1, which is contrary to what MSDN says about
12200 * returning the previous LPARAM value */
12201 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_GETCOMPSTRATONCE);
12202 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
12203 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
12204 ok(lr == EIMES_GETCOMPSTRATONCE, "Got unexpected lr %#Ix.\n", lr);
12206 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_CANCELCOMPSTRINFOCUS);
12207 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
12208 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
12209 ok(lr == EIMES_CANCELCOMPSTRINFOCUS, "Got unexpected lr %#Ix.\n", lr);
12211 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_COMPLETECOMPSTRKILLFOCUS);
12212 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
12213 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
12214 ok(lr == EIMES_COMPLETECOMPSTRKILLFOCUS, "Got unexpected lr %#Ix.\n", lr);
12216 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_GETCOMPSTRATONCE
12217 | EIMES_CANCELCOMPSTRINFOCUS | EIMES_COMPLETECOMPSTRKILLFOCUS);
12218 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
12219 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
12220 ok(lr == (EIMES_GETCOMPSTRATONCE | EIMES_CANCELCOMPSTRINFOCUS | EIMES_COMPLETECOMPSTRKILLFOCUS),
12221 "Got unexpected lr %#Ix.\n", lr);
12223 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
12224 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
12225 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
12226 ok(lr == 0, "Got unexpected lr %#Ix.\n", lr);
12228 /* Invalid EM_{GET|SET}IMESTATUS status types and flags */
12229 lr = SendMessageA(hwnd, EM_GETIMESTATUS, 0, 0);
12230 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
12232 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING + 1, 0);
12233 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
12235 lr = SendMessageA(hwnd, EM_SETIMESTATUS, 0, EIMES_GETCOMPSTRATONCE);
12236 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
12237 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
12238 ok(lr == 0, "Got unexpected lr %#Ix.\n", lr);
12240 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING + 1, EIMES_GETCOMPSTRATONCE);
12241 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
12242 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
12243 ok(lr == 0, "Got unexpected lr %#Ix.\n", lr);
12245 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0xFFFFFFFF);
12246 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
12247 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
12248 ok(lr == 0xFFFF, "Got unexpected lr %#Ix.\n", lr);
12250 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
12251 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
12252 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
12253 ok(lr == 0, "Got unexpected lr %#Ix.\n", lr);
12255 /* Test IME messages when EIMES_GETCOMPSTRATONCE is not set */
12256 old_proc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)edit_ime_subclass_proc);
12257 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)old_proc);
12259 himc = ImmGetContext(hwnd);
12260 ret = ImmSetCompositionStringA(himc, SCS_SETSTR, "Wine", 4, NULL, 0);
12261 ok(ret, "ImmSetCompositionStringA failed.\n");
12262 flush_sequence();
12263 ret = ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
12264 ok(ret, "ImmNotifyIME failed.\n");
12265 /* Note that the following message loop is necessary to get the WM_CHAR messages because they
12266 * are posted. Same for the later message loops in this function. */
12267 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
12268 ok_sequence(edit_wm_ime_composition_seq, "WM_IME_COMPOSITION", TRUE);
12270 /* Test that WM_IME_CHAR is passed to DefWindowProc() to get WM_CHAR */
12271 flush_sequence();
12272 SendMessageA(hwnd, WM_IME_CHAR, '0', 1);
12273 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
12274 ok_sequence(edit_wm_ime_char_seq, "WM_IME_CHAR", FALSE);
12276 /* Test IME messages when EIMES_GETCOMPSTRATONCE is set */
12277 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_GETCOMPSTRATONCE);
12278 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
12279 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
12280 ok(lr == EIMES_GETCOMPSTRATONCE, "Got unexpected lr %#Ix.\n", lr);
12282 ret = ImmSetCompositionStringA(himc, SCS_SETSTR, "Wine", 4, NULL, 0);
12283 ok(ret, "ImmSetCompositionStringA failed.\n");
12284 flush_sequence();
12285 ret = ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
12286 ok(ret, "ImmNotifyIME failed.\n");
12287 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
12288 ok_sequence(edit_eimes_getcompstratonce_seq,
12289 "WM_IME_COMPOSITION with EIMES_GETCOMPSTRATONCE", TRUE);
12291 /* Test that WM_IME_CHAR is passed to DefWindowProc() to get WM_CHAR with EIMES_GETCOMPSTRATONCE */
12292 flush_sequence();
12293 SendMessageA(hwnd, WM_IME_CHAR, '0', 1);
12294 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
12295 ok_sequence(edit_wm_ime_char_seq, "WM_IME_CHAR", FALSE);
12297 ImmReleaseContext(hwnd, himc);
12298 DestroyWindow(hwnd);
12299 return 0;
12302 static void subclass_edit(void)
12304 WNDCLASSA cls;
12306 if (!GetClassInfoA(0, "edit", &cls)) assert(0);
12308 old_edit_proc = cls.lpfnWndProc;
12310 cls.hInstance = GetModuleHandleA(NULL);
12311 cls.lpfnWndProc = edit_hook_proc;
12312 cls.lpszClassName = "my_edit_class";
12313 UnregisterClassA(cls.lpszClassName, cls.hInstance);
12314 if (!RegisterClassA(&cls)) assert(0);
12317 static void test_edit_messages(void)
12319 HWND hwnd, parent;
12320 DWORD dlg_code;
12321 HANDLE thread;
12323 subclass_edit();
12324 log_all_parent_messages++;
12326 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
12327 100, 100, 200, 200, 0, 0, 0, NULL);
12328 ok (parent != 0, "Failed to create parent window\n");
12330 /* test single line edit */
12331 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
12332 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
12333 ok(hwnd != 0, "Failed to create edit window\n");
12335 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
12336 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08lx\n", dlg_code);
12338 flush_sequence();
12339 SetFocus(hwnd);
12340 ok_sequence(sl_edit_invisible, "SetFocus(hwnd) on an invisible edit", FALSE);
12342 ShowWindow(hwnd, SW_SHOW);
12343 UpdateWindow(hwnd);
12344 SetFocus(0);
12345 flush_sequence();
12347 SetFocus(hwnd);
12348 ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
12350 SetFocus(0);
12351 ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
12353 SetFocus(0);
12354 ReleaseCapture();
12355 flush_sequence();
12357 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
12358 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
12360 SetFocus(0);
12361 ReleaseCapture();
12362 flush_sequence();
12364 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
12365 ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
12367 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
12368 ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
12370 DestroyWindow(hwnd);
12372 /* test multiline edit */
12373 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
12374 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
12375 ok(hwnd != 0, "Failed to create edit window\n");
12377 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
12378 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
12379 "wrong dlg_code %08lx\n", dlg_code);
12381 ShowWindow(hwnd, SW_SHOW);
12382 UpdateWindow(hwnd);
12383 SetFocus(0);
12384 flush_sequence();
12386 SetFocus(hwnd);
12387 ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
12389 SetFocus(0);
12390 ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
12392 SetFocus(0);
12393 ReleaseCapture();
12394 flush_sequence();
12396 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
12397 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
12399 SetFocus(0);
12400 ReleaseCapture();
12401 flush_sequence();
12403 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
12404 ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
12406 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
12407 ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
12409 DestroyWindow(hwnd);
12410 DestroyWindow(parent);
12412 log_all_parent_messages--;
12414 /* Test IME messages in another thread because IME is disabled in the current thread */
12415 thread = CreateThread(NULL, 0, test_edit_ime_messages, NULL, 0, NULL);
12416 WaitForSingleObject(thread, INFINITE);
12417 CloseHandle(thread);
12420 /**************************** End of Edit test ******************************/
12422 static const struct message WmKeyDownSkippedSeq[] =
12424 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
12425 { 0 }
12427 static const struct message WmKeyDownWasDownSkippedSeq[] =
12429 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x40000001 }, /* XP */
12430 { 0 }
12432 static const struct message WmKeyUpSkippedSeq[] =
12434 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
12435 { 0 }
12437 static const struct message WmUserKeyUpSkippedSeq[] =
12439 { WM_USER, sent },
12440 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
12441 { 0 }
12444 #define EV_STOP 0
12445 #define EV_SENDMSG 1
12446 #define EV_ACK 2
12448 struct peekmsg_info
12450 HWND hwnd;
12451 HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
12454 static DWORD CALLBACK send_msg_thread_2(void *param)
12456 DWORD ret;
12457 struct peekmsg_info *info = param;
12459 trace("thread: looping\n");
12460 SetEvent(info->hevent[EV_ACK]);
12462 while (1)
12464 ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
12466 switch (ret)
12468 case WAIT_OBJECT_0 + EV_STOP:
12469 trace("thread: exiting\n");
12470 return 0;
12472 case WAIT_OBJECT_0 + EV_SENDMSG:
12473 trace("thread: sending message\n");
12474 ret = SendNotifyMessageA(info->hwnd, WM_USER, 0, 0);
12475 ok(ret, "SendNotifyMessageA failed error %lu\n", GetLastError());
12476 SetEvent(info->hevent[EV_ACK]);
12477 break;
12479 default:
12480 trace("unexpected return: %04lx\n", ret);
12481 assert(0);
12482 break;
12485 return 0;
12488 static void test_PeekMessage(void)
12490 MSG msg;
12491 HANDLE hthread;
12492 DWORD tid, qstatus;
12493 UINT qs_all_input = QS_ALLINPUT;
12494 UINT qs_input = QS_INPUT;
12495 BOOL ret;
12496 struct peekmsg_info info;
12498 info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
12499 100, 100, 200, 200, 0, 0, 0, NULL);
12500 assert(info.hwnd);
12501 ShowWindow(info.hwnd, SW_SHOW);
12502 UpdateWindow(info.hwnd);
12503 SetFocus(info.hwnd);
12505 info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
12506 info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
12507 info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
12509 hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
12510 WaitForSingleObject(info.hevent[EV_ACK], 10000);
12512 flush_events();
12513 flush_sequence();
12515 SetLastError(0xdeadbeef);
12516 qstatus = GetQueueStatus(qs_all_input);
12517 if (GetLastError() == ERROR_INVALID_FLAGS)
12519 trace("QS_RAWINPUT not supported on this platform\n");
12520 qs_all_input &= ~QS_RAWINPUT;
12521 qs_input &= ~QS_RAWINPUT;
12523 if (qstatus & QS_POSTMESSAGE)
12525 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) /* nothing */ ;
12526 qstatus = GetQueueStatus(qs_all_input);
12528 ok(qstatus == 0, "wrong qstatus %08lx\n", qstatus);
12530 trace("signalling to send message\n");
12531 SetEvent(info.hevent[EV_SENDMSG]);
12532 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
12534 /* pass invalid QS_xxxx flags */
12535 SetLastError(0xdeadbeef);
12536 qstatus = GetQueueStatus(0xffffffff);
12537 ok(qstatus == 0 || broken(qstatus) /* win9x */, "GetQueueStatus should fail: %08lx\n", qstatus);
12538 if (!qstatus)
12540 ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %ld\n", GetLastError());
12541 qstatus = GetQueueStatus(qs_all_input);
12543 qstatus &= ~MAKELONG( 0x4000, 0x4000 ); /* sometimes set on Win95 */
12544 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
12545 "wrong qstatus %08lx\n", qstatus);
12547 msg.message = 0;
12548 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
12549 ok(!ret,
12550 "PeekMessageA should have returned FALSE instead of msg %04x\n",
12551 msg.message);
12552 ok_sequence(WmUser, "WmUser", FALSE);
12554 qstatus = GetQueueStatus(qs_all_input);
12555 ok(qstatus == 0, "wrong qstatus %08lx\n", qstatus);
12557 keybd_event('N', 0, 0, 0);
12558 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
12559 qstatus = GetQueueStatus(qs_all_input);
12560 if (!(qstatus & MAKELONG(QS_KEY, QS_KEY)))
12562 skip( "queuing key events not supported\n" );
12563 goto done;
12565 ok(qstatus == MAKELONG(QS_KEY, QS_KEY) ||
12566 /* keybd_event seems to trigger a sent message on NT4 */
12567 qstatus == MAKELONG(QS_KEY|QS_SENDMESSAGE, QS_KEY|QS_SENDMESSAGE),
12568 "wrong qstatus %08lx\n", qstatus);
12570 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
12571 qstatus = GetQueueStatus(qs_all_input);
12572 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY) ||
12573 qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
12574 "wrong qstatus %08lx\n", qstatus);
12576 InvalidateRect(info.hwnd, NULL, FALSE);
12577 qstatus = GetQueueStatus(qs_all_input);
12578 ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY) ||
12579 qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
12580 "wrong qstatus %08lx\n", qstatus);
12582 trace("signalling to send message\n");
12583 SetEvent(info.hevent[EV_SENDMSG]);
12584 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
12586 qstatus = GetQueueStatus(qs_all_input);
12587 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
12588 "wrong qstatus %08lx\n", qstatus);
12590 msg.message = 0;
12591 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
12592 if (ret && msg.message == WM_CHAR)
12594 win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
12595 goto done;
12597 ok(!ret,
12598 "PeekMessageA should have returned FALSE instead of msg %04x\n",
12599 msg.message);
12600 if (!sequence_cnt) /* nt4 doesn't fetch anything with PM_QS_* flags */
12602 win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
12603 goto done;
12605 ok_sequence(WmUser, "WmUser", FALSE);
12607 qstatus = GetQueueStatus(qs_all_input);
12608 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
12609 "wrong qstatus %08lx\n", qstatus);
12611 trace("signalling to send message\n");
12612 SetEvent(info.hevent[EV_SENDMSG]);
12613 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
12615 qstatus = GetQueueStatus(qs_all_input);
12616 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
12617 "wrong qstatus %08lx\n", qstatus);
12619 msg.message = 0;
12620 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE );
12621 ok(!ret,
12622 "PeekMessageA should have returned FALSE instead of msg %04x\n",
12623 msg.message);
12624 ok_sequence(WmUser, "WmUser", FALSE);
12626 qstatus = GetQueueStatus(qs_all_input);
12627 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
12628 "wrong qstatus %08lx\n", qstatus);
12630 msg.message = 0;
12631 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
12632 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12633 "got %d and %04x wParam %08Ix instead of TRUE and WM_CHAR wParam 'z'\n",
12634 ret, msg.message, msg.wParam);
12635 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12637 qstatus = GetQueueStatus(qs_all_input);
12638 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
12639 "wrong qstatus %08lx\n", qstatus);
12641 msg.message = 0;
12642 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
12643 ok(!ret,
12644 "PeekMessageA should have returned FALSE instead of msg %04x\n",
12645 msg.message);
12646 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12648 qstatus = GetQueueStatus(qs_all_input);
12649 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
12650 "wrong qstatus %08lx\n", qstatus);
12652 msg.message = 0;
12653 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
12654 ok(ret && msg.message == WM_PAINT,
12655 "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
12656 DispatchMessageA(&msg);
12657 ok_sequence(WmPaint, "WmPaint", FALSE);
12659 qstatus = GetQueueStatus(qs_all_input);
12660 ok(qstatus == MAKELONG(0, QS_KEY),
12661 "wrong qstatus %08lx\n", qstatus);
12663 msg.message = 0;
12664 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
12665 ok(!ret,
12666 "PeekMessageA should have returned FALSE instead of msg %04x\n",
12667 msg.message);
12668 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12670 qstatus = GetQueueStatus(qs_all_input);
12671 ok(qstatus == MAKELONG(0, QS_KEY),
12672 "wrong qstatus %08lx\n", qstatus);
12674 trace("signalling to send message\n");
12675 SetEvent(info.hevent[EV_SENDMSG]);
12676 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
12678 qstatus = GetQueueStatus(qs_all_input);
12679 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
12680 "wrong qstatus %08lx\n", qstatus);
12682 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
12684 qstatus = GetQueueStatus(qs_all_input);
12685 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
12686 "wrong qstatus %08lx\n", qstatus);
12688 msg.message = 0;
12689 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
12690 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12691 "got %d and %04x wParam %08Ix instead of TRUE and WM_CHAR wParam 'z'\n",
12692 ret, msg.message, msg.wParam);
12693 ok_sequence(WmUser, "WmUser", FALSE);
12695 qstatus = GetQueueStatus(qs_all_input);
12696 ok(qstatus == MAKELONG(0, QS_KEY),
12697 "wrong qstatus %08lx\n", qstatus);
12699 msg.message = 0;
12700 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
12701 ok(!ret,
12702 "PeekMessageA should have returned FALSE instead of msg %04x\n",
12703 msg.message);
12704 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12706 qstatus = GetQueueStatus(qs_all_input);
12707 ok(qstatus == MAKELONG(0, QS_KEY),
12708 "wrong qstatus %08lx\n", qstatus);
12710 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
12712 qstatus = GetQueueStatus(qs_all_input);
12713 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
12714 "wrong qstatus %08lx\n", qstatus);
12716 trace("signalling to send message\n");
12717 SetEvent(info.hevent[EV_SENDMSG]);
12718 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
12720 qstatus = GetQueueStatus(qs_all_input);
12721 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
12722 "wrong qstatus %08lx\n", qstatus);
12724 msg.message = 0;
12725 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
12726 ok(!ret,
12727 "PeekMessageA should have returned FALSE instead of msg %04x\n",
12728 msg.message);
12729 ok_sequence(WmUser, "WmUser", FALSE);
12731 qstatus = GetQueueStatus(qs_all_input);
12732 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
12733 "wrong qstatus %08lx\n", qstatus);
12735 msg.message = 0;
12736 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
12737 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
12738 else /* workaround for a missing QS_RAWINPUT support */
12739 ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
12740 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
12741 "got %d and %04x wParam %08Ix instead of TRUE and WM_KEYDOWN wParam 'N'\n",
12742 ret, msg.message, msg.wParam);
12743 ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
12745 qstatus = GetQueueStatus(qs_all_input);
12746 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
12747 "wrong qstatus %08lx\n", qstatus);
12749 msg.message = 0;
12750 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
12751 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
12752 else /* workaround for a missing QS_RAWINPUT support */
12753 ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
12754 ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
12755 "got %d and %04x wParam %08Ix instead of TRUE and WM_KEYUP wParam 'N'\n",
12756 ret, msg.message, msg.wParam);
12757 ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
12759 qstatus = GetQueueStatus(qs_all_input);
12760 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
12761 "wrong qstatus %08lx\n", qstatus);
12763 msg.message = 0;
12764 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
12765 ok(!ret,
12766 "PeekMessageA should have returned FALSE instead of msg %04x\n",
12767 msg.message);
12768 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12770 qstatus = GetQueueStatus(qs_all_input);
12771 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
12772 "wrong qstatus %08lx\n", qstatus);
12774 msg.message = 0;
12775 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
12776 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12777 "got %d and %04x wParam %08Ix instead of TRUE and WM_CHAR wParam 'z'\n",
12778 ret, msg.message, msg.wParam);
12779 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12781 qstatus = GetQueueStatus(qs_all_input);
12782 ok(qstatus == 0,
12783 "wrong qstatus %08lx\n", qstatus);
12785 msg.message = 0;
12786 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
12787 ok(!ret,
12788 "PeekMessageA should have returned FALSE instead of msg %04x\n",
12789 msg.message);
12790 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12792 qstatus = GetQueueStatus(qs_all_input);
12793 ok(qstatus == 0,
12794 "wrong qstatus %08lx\n", qstatus);
12796 /* test whether presence of the quit flag in the queue affects
12797 * the queue state
12799 PostQuitMessage(0x1234abcd);
12801 qstatus = GetQueueStatus(qs_all_input);
12802 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
12803 "wrong qstatus %08lx\n", qstatus);
12805 PostMessageA(info.hwnd, WM_USER, 0, 0);
12807 qstatus = GetQueueStatus(qs_all_input);
12808 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
12809 "wrong qstatus %08lx\n", qstatus);
12811 msg.message = 0;
12812 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
12813 ok(ret && msg.message == WM_USER,
12814 "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
12815 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12817 qstatus = GetQueueStatus(qs_all_input);
12818 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
12819 "wrong qstatus %08lx\n", qstatus);
12821 msg.message = 0;
12822 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
12823 ok(ret && msg.message == WM_QUIT,
12824 "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
12825 ok(msg.wParam == 0x1234abcd, "got wParam %08Ix instead of 0x1234abcd\n", msg.wParam);
12826 ok(msg.lParam == 0, "got lParam %08Ix instead of 0\n", msg.lParam);
12827 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12829 qstatus = GetQueueStatus(qs_all_input);
12830 todo_wine {
12831 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
12832 "wrong qstatus %08lx\n", qstatus);
12835 msg.message = 0;
12836 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
12837 ok(!ret,
12838 "PeekMessageA should have returned FALSE instead of msg %04x\n",
12839 msg.message);
12840 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12842 qstatus = GetQueueStatus(qs_all_input);
12843 ok(qstatus == 0,
12844 "wrong qstatus %08lx\n", qstatus);
12846 /* some GetMessage tests */
12848 keybd_event('N', 0, 0, 0);
12849 qstatus = GetQueueStatus(qs_all_input);
12850 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08lx\n", qstatus);
12852 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
12853 qstatus = GetQueueStatus(qs_all_input);
12854 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08lx\n", qstatus);
12856 if (qstatus)
12858 ret = GetMessageA( &msg, 0, 0, 0 );
12859 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12860 "got %d and %04x wParam %08Ix instead of TRUE and WM_CHAR wParam 'z'\n",
12861 ret, msg.message, msg.wParam);
12862 qstatus = GetQueueStatus(qs_all_input);
12863 ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08lx\n", qstatus);
12866 if (qstatus)
12868 ret = GetMessageA( &msg, 0, 0, 0 );
12869 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
12870 "got %d and %04x wParam %08Ix instead of TRUE and WM_KEYDOWN wParam 'N'\n",
12871 ret, msg.message, msg.wParam);
12872 ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
12873 qstatus = GetQueueStatus(qs_all_input);
12874 ok(qstatus == 0, "wrong qstatus %08lx\n", qstatus);
12877 keybd_event('N', 0, 0, 0);
12878 qstatus = GetQueueStatus(qs_all_input);
12879 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08lx\n", qstatus);
12881 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
12882 qstatus = GetQueueStatus(qs_all_input);
12883 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08lx\n", qstatus);
12885 if (qstatus & (QS_KEY << 16))
12887 ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
12888 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
12889 "got %d and %04x wParam %08Ix instead of TRUE and WM_KEYDOWN wParam 'N'\n",
12890 ret, msg.message, msg.wParam);
12891 ok_sequence(WmKeyDownWasDownSkippedSeq, "WmKeyDownWasDownSkippedSeq", FALSE);
12892 qstatus = GetQueueStatus(qs_all_input);
12893 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08lx\n", qstatus);
12896 if (qstatus)
12898 ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
12899 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12900 "got %d and %04x wParam %08Ix instead of TRUE and WM_CHAR wParam 'z'\n",
12901 ret, msg.message, msg.wParam);
12902 qstatus = GetQueueStatus(qs_all_input);
12903 ok(qstatus == 0, "wrong qstatus %08lx\n", qstatus);
12906 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
12907 qstatus = GetQueueStatus(qs_all_input);
12908 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08lx\n", qstatus);
12910 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
12911 qstatus = GetQueueStatus(qs_all_input);
12912 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08lx\n", qstatus);
12914 trace("signalling to send message\n");
12915 SetEvent(info.hevent[EV_SENDMSG]);
12916 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
12917 qstatus = GetQueueStatus(qs_all_input);
12918 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
12919 "wrong qstatus %08lx\n", qstatus);
12921 if (qstatus & (QS_KEY << 16))
12923 ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
12924 ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
12925 "got %d and %04x wParam %08Ix instead of TRUE and WM_KEYDOWN wParam 'N'\n",
12926 ret, msg.message, msg.wParam);
12927 ok_sequence(WmUserKeyUpSkippedSeq, "WmUserKeyUpSkippedSeq", FALSE);
12928 qstatus = GetQueueStatus(qs_all_input);
12929 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08lx\n", qstatus);
12932 if (qstatus)
12934 ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
12935 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12936 "got %d and %04x wParam %08Ix instead of TRUE and WM_CHAR wParam 'z'\n",
12937 ret, msg.message, msg.wParam);
12938 qstatus = GetQueueStatus(qs_all_input);
12939 ok(qstatus == 0, "wrong qstatus %08lx\n", qstatus);
12942 PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12943 ret = PeekMessageA(&msg, (HWND)-1, 0, 0, PM_NOREMOVE);
12944 ok(ret == TRUE, "wrong ret %d\n", ret);
12945 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12946 ret = GetMessageA(&msg, (HWND)-1, 0, 0);
12947 ok(ret == TRUE, "wrong ret %d\n", ret);
12948 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12950 PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12951 ret = PeekMessageA(&msg, (HWND)1, 0, 0, PM_NOREMOVE);
12952 ok(ret == TRUE, "wrong ret %d\n", ret);
12953 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12954 ret = GetMessageA(&msg, (HWND)1, 0, 0);
12955 ok(ret == TRUE, "wrong ret %d\n", ret);
12956 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12958 PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12959 ret = PeekMessageA(&msg, (HWND)0xffff, 0, 0, PM_NOREMOVE);
12960 ok(ret == TRUE, "wrong ret %d\n", ret);
12961 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12962 ret = GetMessageA(&msg, (HWND)0xffff, 0, 0);
12963 ok(ret == TRUE, "wrong ret %d\n", ret);
12964 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12966 done:
12967 trace("signalling to exit\n");
12968 SetEvent(info.hevent[EV_STOP]);
12970 WaitForSingleObject(hthread, INFINITE);
12972 CloseHandle(hthread);
12973 CloseHandle(info.hevent[0]);
12974 CloseHandle(info.hevent[1]);
12975 CloseHandle(info.hevent[2]);
12977 DestroyWindow(info.hwnd);
12980 static void wait_move_event(HWND hwnd, int x, int y)
12982 MSG msg;
12983 DWORD timeout = GetTickCount() + 500;
12984 BOOL ret;
12985 int delay;
12987 while ((delay = timeout - GetTickCount()) > 0)
12989 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12990 if (ret && msg.pt.x > x && msg.pt.y > y) break;
12991 if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, delay, QS_ALLINPUT );
12992 else Sleep( delay );
12996 #define STEP 5
12997 static void test_PeekMessage2(void)
12999 HWND hwnd;
13000 BOOL ret;
13001 MSG msg;
13002 UINT message;
13003 DWORD time1, time2, time3;
13004 int x1, y1, x2, y2, x3, y3;
13005 POINT pos;
13007 time1 = time2 = time3 = 0;
13008 x1 = y1 = x2 = y2 = x3 = y3 = 0;
13010 /* Initialise window and make sure it is ready for events */
13011 hwnd = CreateWindowA("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
13012 10, 10, 800, 800, NULL, NULL, NULL, NULL);
13013 assert(hwnd);
13014 trace("Window for test_PeekMessage2 %p\n", hwnd);
13015 ShowWindow(hwnd, SW_SHOW);
13016 UpdateWindow(hwnd);
13017 SetFocus(hwnd);
13018 GetCursorPos(&pos);
13019 SetCursorPos(100, 100);
13020 mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
13021 flush_events();
13023 /* Do initial mousemove, wait until we can see it
13024 and then do our test peek with PM_NOREMOVE. */
13025 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
13026 wait_move_event(hwnd, 100-STEP, 100-STEP);
13028 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
13029 if (!ret)
13031 skip( "queuing mouse events not supported\n" );
13032 goto done;
13034 else
13036 trace("1st move event: %04x %lx %ld %ld\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
13037 message = msg.message;
13038 time1 = msg.time;
13039 x1 = msg.pt.x;
13040 y1 = msg.pt.y;
13041 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
13044 /* Allow time to advance a bit, and then simulate the user moving their
13045 * mouse around. After that we peek again with PM_NOREMOVE.
13046 * Although the previous mousemove message was never removed, the
13047 * mousemove we now peek should reflect the recent mouse movements
13048 * because the input queue will merge the move events. */
13049 Sleep(100);
13050 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
13051 wait_move_event(hwnd, x1, y1);
13053 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
13054 ok(ret, "no message available\n");
13055 if (ret) {
13056 trace("2nd move event: %04x %lx %ld %ld\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
13057 message = msg.message;
13058 time2 = msg.time;
13059 x2 = msg.pt.x;
13060 y2 = msg.pt.y;
13061 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
13062 ok(time2 > time1, "message time not advanced: %lx %lx\n", time1, time2);
13063 ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
13066 /* Have another go, to drive the point home */
13067 Sleep(100);
13068 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
13069 wait_move_event(hwnd, x2, y2);
13071 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
13072 ok(ret, "no message available\n");
13073 if (ret) {
13074 trace("3rd move event: %04x %lx %ld %ld\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
13075 message = msg.message;
13076 time3 = msg.time;
13077 x3 = msg.pt.x;
13078 y3 = msg.pt.y;
13079 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
13080 ok(time3 > time2, "message time not advanced: %lx %lx\n", time2, time3);
13081 ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
13084 done:
13085 DestroyWindow(hwnd);
13086 SetCursorPos(pos.x, pos.y);
13087 flush_events();
13090 static void test_PeekMessage3(void)
13092 HWND hwnd;
13093 BOOL ret;
13094 MSG msg;
13096 hwnd = CreateWindowA("TestWindowClass", "PeekMessage3", WS_OVERLAPPEDWINDOW,
13097 10, 10, 800, 800, NULL, NULL, NULL, NULL);
13098 ok(hwnd != NULL, "expected hwnd != NULL\n");
13099 flush_events();
13101 /* GetMessage() and PeekMessage(..., PM_REMOVE) should prefer messages which
13102 * were already seen. */
13104 SetTimer(hwnd, 1, 100, NULL);
13105 while (!PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE));
13106 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
13107 PostMessageA(hwnd, WM_USER, 0, 0);
13108 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
13109 todo_wine
13110 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
13111 ret = GetMessageA(&msg, NULL, 0, 0);
13112 todo_wine
13113 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
13114 ret = GetMessageA(&msg, NULL, 0, 0);
13115 todo_wine
13116 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
13117 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
13118 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
13120 SetTimer(hwnd, 1, 100, NULL);
13121 while (!PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE));
13122 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
13123 PostMessageA(hwnd, WM_USER, 0, 0);
13124 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
13125 todo_wine
13126 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
13127 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
13128 todo_wine
13129 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
13130 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
13131 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
13133 /* It doesn't matter if a message range is specified or not. */
13135 SetTimer(hwnd, 1, 100, NULL);
13136 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
13137 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
13138 PostMessageA(hwnd, WM_USER, 0, 0);
13139 ret = GetMessageA(&msg, NULL, 0, 0);
13140 todo_wine
13141 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
13142 ret = GetMessageA(&msg, NULL, 0, 0);
13143 todo_wine
13144 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
13145 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
13146 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
13148 /* But not if the post messages were added before the PeekMessage() call. */
13150 PostMessageA(hwnd, WM_USER, 0, 0);
13151 SetTimer(hwnd, 1, 100, NULL);
13152 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
13153 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
13154 ret = GetMessageA(&msg, NULL, 0, 0);
13155 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
13156 ret = GetMessageA(&msg, NULL, 0, 0);
13157 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
13158 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
13159 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
13161 /* More complicated test with multiple messages. */
13163 PostMessageA(hwnd, WM_USER, 0, 0);
13164 SetTimer(hwnd, 1, 100, NULL);
13165 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
13166 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
13167 PostMessageA(hwnd, WM_USER + 1, 0, 0);
13168 ret = GetMessageA(&msg, NULL, 0, 0);
13169 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
13170 ret = GetMessageA(&msg, NULL, 0, 0);
13171 todo_wine
13172 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
13173 ret = GetMessageA(&msg, NULL, 0, 0);
13174 todo_wine
13175 ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message);
13176 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
13177 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
13179 /* Also works for posted messages, but the situation is a bit different,
13180 * because both messages are in the same queue. */
13182 PostMessageA(hwnd, WM_TIMER, 0, 0);
13183 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
13184 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
13185 PostMessageA(hwnd, WM_USER, 0, 0);
13186 ret = GetMessageA(&msg, NULL, 0, 0);
13187 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
13188 ret = GetMessageA(&msg, NULL, 0, 0);
13189 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
13190 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
13191 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
13193 PostMessageA(hwnd, WM_USER, 0, 0);
13194 PostMessageA(hwnd, WM_TIMER, 0, 0);
13195 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
13196 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
13197 ret = GetMessageA(&msg, NULL, 0, 0);
13198 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
13199 ret = GetMessageA(&msg, NULL, 0, 0);
13200 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
13201 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
13202 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
13204 DestroyWindow(hwnd);
13205 flush_events();
13208 static INT_PTR CALLBACK wm_quit_dlg_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
13210 struct recvd_message msg;
13212 if (ignore_message( message )) return 0;
13214 msg.hwnd = hwnd;
13215 msg.message = message;
13216 msg.flags = sent|wparam|lparam;
13217 msg.wParam = wp;
13218 msg.lParam = lp;
13219 msg.descr = "dialog";
13220 add_message(&msg);
13222 switch (message)
13224 case WM_INITDIALOG:
13225 PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
13226 PostMessageA(hwnd, WM_USER, 0xdead, 0xbeef);
13227 return 0;
13229 case WM_GETDLGCODE:
13230 return 0;
13232 case WM_USER:
13233 EndDialog(hwnd, 0);
13234 break;
13237 return 1;
13240 static const struct message WmQuitDialogSeq[] = {
13241 { HCBT_CREATEWND, hook },
13242 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13243 { WM_SETFONT, sent },
13244 { WM_INITDIALOG, sent },
13245 { WM_CHANGEUISTATE, sent|optional },
13246 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13247 { HCBT_DESTROYWND, hook },
13248 { 0x0090, sent|optional }, /* Vista */
13249 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13250 { WM_DESTROY, sent },
13251 { WM_NCDESTROY, sent },
13252 { 0 }
13255 static const struct message WmStopQuitSeq[] = {
13256 { WM_DWMNCRENDERINGCHANGED, posted|optional },
13257 { WM_CLOSE, posted },
13258 { WM_QUIT, posted|wparam|lparam, 0x1234, 0 },
13259 { 0 }
13262 static void test_quit_message(void)
13264 MSG msg;
13265 BOOL ret;
13267 /* test using PostQuitMessage */
13268 flush_events();
13269 PostQuitMessage(0xbeef);
13271 msg.message = 0;
13272 ret = PeekMessageA(&msg, 0, 0, 0, PM_QS_SENDMESSAGE);
13273 ok(!ret, "got %x message\n", msg.message);
13275 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
13276 ok(ret, "PeekMessage failed with error %ld\n", GetLastError());
13277 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
13278 ok(msg.wParam == 0xbeef, "wParam was 0x%Ix instead of 0xbeef\n", msg.wParam);
13280 ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
13281 ok(ret, "PostMessage failed with error %ld\n", GetLastError());
13283 ret = GetMessageA(&msg, NULL, 0, 0);
13284 ok(ret > 0, "GetMessage failed with error %ld\n", GetLastError());
13285 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
13287 /* note: WM_QUIT message received after WM_USER message */
13288 ret = GetMessageA(&msg, NULL, 0, 0);
13289 ok(!ret, "GetMessage return %d with error %ld instead of FALSE\n", ret, GetLastError());
13290 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
13291 ok(msg.wParam == 0xbeef, "wParam was 0x%Ix instead of 0xbeef\n", msg.wParam);
13293 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
13294 ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
13296 /* now test with PostThreadMessage - different behaviour! */
13297 PostThreadMessageA(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
13299 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
13300 ok(ret, "PeekMessage failed with error %ld\n", GetLastError());
13301 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
13302 ok(msg.wParam == 0xdead, "wParam was 0x%Ix instead of 0xdead\n", msg.wParam);
13304 ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
13305 ok(ret, "PostMessage failed with error %ld\n", GetLastError());
13307 /* note: we receive the WM_QUIT message first this time */
13308 ret = GetMessageA(&msg, NULL, 0, 0);
13309 ok(!ret, "GetMessage return %d with error %ld instead of FALSE\n", ret, GetLastError());
13310 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
13311 ok(msg.wParam == 0xdead, "wParam was 0x%Ix instead of 0xdead\n", msg.wParam);
13313 ret = GetMessageA(&msg, NULL, 0, 0);
13314 ok(ret > 0, "GetMessage failed with error %ld\n", GetLastError());
13315 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
13317 flush_events();
13318 flush_sequence();
13319 ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, wm_quit_dlg_proc, 0);
13320 ok(ret == 1, "expected 1, got %d\n", ret);
13321 ok_sequence(WmQuitDialogSeq, "WmQuitDialogSeq", FALSE);
13322 memset(&msg, 0xab, sizeof(msg));
13323 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
13324 ok(ret, "PeekMessage failed\n");
13325 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
13326 ok(msg.wParam == 0x1234, "wParam was 0x%Ix instead of 0x1234\n", msg.wParam);
13327 ok(msg.lParam == 0, "lParam was 0x%Ix instead of 0\n", msg.lParam);
13329 /* Check what happens to a WM_QUIT message posted to a window that gets
13330 * destroyed.
13332 CreateWindowExA(0, "StopQuitClass", "Stop Quit Test", WS_OVERLAPPEDWINDOW,
13333 0, 0, 100, 100, NULL, NULL, NULL, NULL);
13334 flush_sequence();
13335 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
13337 struct recvd_message rmsg;
13338 rmsg.hwnd = msg.hwnd;
13339 rmsg.message = msg.message;
13340 rmsg.flags = posted|wparam|lparam;
13341 rmsg.wParam = msg.wParam;
13342 rmsg.lParam = msg.lParam;
13343 rmsg.descr = "stop/quit";
13344 if (msg.message == WM_QUIT)
13345 /* The hwnd can only be checked here */
13346 ok(!msg.hwnd, "The WM_QUIT hwnd was %p instead of NULL\n", msg.hwnd);
13347 add_message(&rmsg);
13348 DispatchMessageA(&msg);
13350 ok_sequence(WmStopQuitSeq, "WmStopQuitSeq", FALSE);
13353 static const struct message WmNotifySeq[] = {
13354 { WM_NOTIFY, sent|wparam|lparam, 0x1234, 0xdeadbeef },
13355 { 0 }
13358 static void test_notify_message(void)
13360 HWND hwnd;
13361 BOOL ret;
13362 MSG msg;
13364 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
13365 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0, NULL, NULL, 0);
13366 ok(hwnd != 0, "Failed to create window\n");
13367 flush_events();
13368 flush_sequence();
13370 ret = SendNotifyMessageA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
13371 ok(ret == TRUE, "SendNotifyMessageA failed with error %lu\n", GetLastError());
13372 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
13374 ret = SendNotifyMessageW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
13375 ok(ret == TRUE, "SendNotifyMessageW failed with error %lu\n", GetLastError());
13376 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
13378 ret = SendMessageCallbackA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef, NULL, 0);
13379 ok(ret == TRUE, "SendMessageCallbackA failed with error %lu\n", GetLastError());
13380 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
13382 ret = SendMessageCallbackW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef, NULL, 0);
13383 ok(ret == TRUE, "SendMessageCallbackW failed with error %lu\n", GetLastError());
13384 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
13386 ret = PostMessageA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
13387 ok(ret == TRUE, "PostMessageA failed with error %lu\n", GetLastError());
13388 flush_events();
13389 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
13391 ret = PostMessageW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
13392 ok(ret == TRUE, "PostMessageW failed with error %lu\n", GetLastError());
13393 flush_events();
13394 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
13396 ret = PostThreadMessageA(GetCurrentThreadId(), WM_NOTIFY, 0x1234, 0xdeadbeef);
13397 ok(ret == TRUE, "PostThreadMessageA failed with error %lu\n", GetLastError());
13398 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
13400 msg.hwnd = hwnd;
13401 DispatchMessageA(&msg);
13403 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
13405 ret = PostThreadMessageW(GetCurrentThreadId(), WM_NOTIFY, 0x1234, 0xdeadbeef);
13406 ok(ret == TRUE, "PostThreadMessageW failed with error %lu\n", GetLastError());
13407 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
13409 msg.hwnd = hwnd;
13410 DispatchMessageA(&msg);
13412 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
13414 DestroyWindow(hwnd);
13417 static const struct message WmMouseHoverSeq[] = {
13418 { WM_GETMINMAXINFO, sent|optional }, /* sometimes seen on w1064v1809 */
13419 { WM_MOUSEACTIVATE, sent|optional }, /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
13420 { WM_MOUSEACTIVATE, sent|optional },
13421 { WM_TIMER, sent|optional }, /* XP sends it */
13422 { WM_SYSTIMER, sent },
13423 { WM_MOUSEHOVER, sent|wparam, 0 },
13424 { 0 }
13427 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
13429 MSG msg;
13430 DWORD start_ticks, end_ticks;
13432 start_ticks = GetTickCount();
13433 /* add some deviation (50%) to cover not expected delays */
13434 start_ticks += timeout / 2;
13438 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
13440 /* Timer proc messages are not dispatched to the window proc,
13441 * and therefore not logged.
13443 if ((msg.message == WM_TIMER || msg.message == WM_SYSTIMER) && msg.hwnd)
13445 struct recvd_message s_msg;
13447 s_msg.hwnd = msg.hwnd;
13448 s_msg.message = msg.message;
13449 s_msg.flags = sent|wparam|lparam;
13450 s_msg.wParam = msg.wParam;
13451 s_msg.lParam = msg.lParam;
13452 s_msg.descr = "msg_loop";
13453 add_message(&s_msg);
13455 DispatchMessageA(&msg);
13458 end_ticks = GetTickCount();
13460 /* inject WM_MOUSEMOVE to see how it changes tracking */
13461 if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
13463 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
13464 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
13466 inject_mouse_move = FALSE;
13468 } while (start_ticks + timeout >= end_ticks);
13471 static void test_TrackMouseEvent(void)
13473 TRACKMOUSEEVENT tme;
13474 BOOL ret;
13475 HWND hwnd, hchild;
13476 RECT rc_parent, rc_child;
13477 UINT default_hover_time, hover_width = 0, hover_height = 0;
13479 #define track_hover(track_hwnd, track_hover_time) \
13480 tme.cbSize = sizeof(tme); \
13481 tme.dwFlags = TME_HOVER; \
13482 tme.hwndTrack = track_hwnd; \
13483 tme.dwHoverTime = track_hover_time; \
13484 SetLastError(0xdeadbeef); \
13485 ret = pTrackMouseEvent(&tme); \
13486 ok(ret, "TrackMouseEvent(TME_HOVER) error %ld\n", GetLastError())
13488 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
13489 tme.cbSize = sizeof(tme); \
13490 tme.dwFlags = TME_QUERY; \
13491 tme.hwndTrack = (HWND)0xdeadbeef; \
13492 tme.dwHoverTime = 0xdeadbeef; \
13493 SetLastError(0xdeadbeef); \
13494 ret = pTrackMouseEvent(&tme); \
13495 ok(ret, "TrackMouseEvent(TME_QUERY) error %ld\n", GetLastError());\
13496 ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %lu\n", tme.cbSize); \
13497 ok(tme.dwFlags == (expected_track_flags), \
13498 "wrong tme.dwFlags %08lx, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
13499 ok(tme.hwndTrack == (expected_track_hwnd), \
13500 "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
13501 ok(tme.dwHoverTime == (expected_hover_time), \
13502 "wrong tme.dwHoverTime %lu, expected %u\n", tme.dwHoverTime, (expected_hover_time))
13504 #define track_hover_cancel(track_hwnd) \
13505 tme.cbSize = sizeof(tme); \
13506 tme.dwFlags = TME_HOVER | TME_CANCEL; \
13507 tme.hwndTrack = track_hwnd; \
13508 tme.dwHoverTime = 0xdeadbeef; \
13509 SetLastError(0xdeadbeef); \
13510 ret = pTrackMouseEvent(&tme); \
13511 ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %ld\n", GetLastError())
13513 default_hover_time = 0xdeadbeef;
13514 SetLastError(0xdeadbeef);
13515 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
13516 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
13517 "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %lu\n", GetLastError());
13518 if (!ret) default_hover_time = 400;
13519 trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
13521 SetLastError(0xdeadbeef);
13522 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
13523 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
13524 "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %lu\n", GetLastError());
13525 if (!ret) hover_width = 4;
13526 SetLastError(0xdeadbeef);
13527 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
13528 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
13529 "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %lu\n", GetLastError());
13530 if (!ret) hover_height = 4;
13531 trace("hover rect is %u x %d\n", hover_width, hover_height);
13533 hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
13534 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13535 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
13536 NULL, NULL, 0);
13537 assert(hwnd);
13539 hchild = CreateWindowExA(0, "TestWindowClass", NULL,
13540 WS_CHILD | WS_BORDER | WS_VISIBLE,
13541 50, 50, 200, 200, hwnd,
13542 NULL, NULL, 0);
13543 assert(hchild);
13545 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
13546 flush_events();
13547 flush_sequence();
13549 tme.cbSize = 0;
13550 tme.dwFlags = TME_QUERY;
13551 tme.hwndTrack = (HWND)0xdeadbeef;
13552 tme.dwHoverTime = 0xdeadbeef;
13553 SetLastError(0xdeadbeef);
13554 ret = pTrackMouseEvent(&tme);
13555 ok(!ret, "TrackMouseEvent should fail\n");
13556 ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
13557 "not expected error %lu\n", GetLastError());
13559 tme.cbSize = sizeof(tme);
13560 tme.dwFlags = TME_HOVER;
13561 tme.hwndTrack = (HWND)0xdeadbeef;
13562 tme.dwHoverTime = 0xdeadbeef;
13563 SetLastError(0xdeadbeef);
13564 ret = pTrackMouseEvent(&tme);
13565 ok(!ret, "TrackMouseEvent should fail\n");
13566 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
13567 "not expected error %lu\n", GetLastError());
13569 tme.cbSize = sizeof(tme);
13570 tme.dwFlags = TME_HOVER | TME_CANCEL;
13571 tme.hwndTrack = (HWND)0xdeadbeef;
13572 tme.dwHoverTime = 0xdeadbeef;
13573 SetLastError(0xdeadbeef);
13574 ret = pTrackMouseEvent(&tme);
13575 ok(!ret, "TrackMouseEvent should fail\n");
13576 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
13577 "not expected error %lu\n", GetLastError());
13579 GetWindowRect(hwnd, &rc_parent);
13580 GetWindowRect(hchild, &rc_child);
13581 SetCursorPos(rc_child.left - 10, rc_child.top - 10);
13583 /* Process messages so that the system updates its internal current
13584 * window and hittest, otherwise TrackMouseEvent calls don't have any
13585 * effect.
13587 flush_events();
13588 flush_sequence();
13590 track_query(0, NULL, 0);
13591 track_hover(hchild, 0);
13592 track_query(0, NULL, 0);
13594 flush_events();
13595 flush_sequence();
13597 track_hover(hwnd, 0);
13598 tme.cbSize = sizeof(tme);
13599 tme.dwFlags = TME_QUERY;
13600 tme.hwndTrack = (HWND)0xdeadbeef;
13601 tme.dwHoverTime = 0xdeadbeef;
13602 SetLastError(0xdeadbeef);
13603 ret = pTrackMouseEvent(&tme);
13604 ok(ret, "TrackMouseEvent(TME_QUERY) error %ld\n", GetLastError());
13605 ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %lu\n", tme.cbSize);
13606 if (!tme.dwFlags)
13608 skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" );
13609 DestroyWindow( hwnd );
13610 return;
13612 ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08lx, expected TME_HOVER\n", tme.dwFlags);
13613 ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd);
13614 ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %lu, expected %u\n",
13615 tme.dwHoverTime, default_hover_time);
13617 pump_msg_loop_timeout(default_hover_time, FALSE);
13618 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
13620 track_query(0, NULL, 0);
13622 track_hover(hwnd, HOVER_DEFAULT);
13623 track_query(TME_HOVER, hwnd, default_hover_time);
13625 Sleep(default_hover_time / 2);
13626 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
13627 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
13629 track_query(TME_HOVER, hwnd, default_hover_time);
13631 pump_msg_loop_timeout(default_hover_time, FALSE);
13632 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
13634 track_query(0, NULL, 0);
13636 track_hover(hwnd, HOVER_DEFAULT);
13637 track_query(TME_HOVER, hwnd, default_hover_time);
13639 pump_msg_loop_timeout(default_hover_time, TRUE);
13640 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
13642 track_query(0, NULL, 0);
13644 track_hover(hwnd, HOVER_DEFAULT);
13645 track_query(TME_HOVER, hwnd, default_hover_time);
13646 track_hover_cancel(hwnd);
13648 DestroyWindow(hwnd);
13650 #undef track_hover
13651 #undef track_query
13652 #undef track_hover_cancel
13656 static const struct message WmSetWindowRgn[] = {
13657 { WM_WINDOWPOSCHANGING, sent|wparam|lparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE
13658 |SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE, 0 },
13659 { WM_NCCALCSIZE, sent|wparam|lparam, 1, 0xf },
13660 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
13661 { WM_GETTEXT, sent|defwinproc|optional },
13662 { WM_ERASEBKGND, sent|optional },
13663 { WM_WINDOWPOSCHANGED, sent|wparam|lparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE, 0xf },
13664 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13665 { 0 }
13668 static const struct message WmSetWindowRgn_no_redraw[] = {
13669 { WM_WINDOWPOSCHANGING, sent|wparam|lparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE
13670 |SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW, 0 },
13671 { WM_NCCALCSIZE, sent|wparam|lparam, 1, 0xf },
13672 { WM_WINDOWPOSCHANGED, sent|wparam|lparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW, 0xf },
13673 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13674 { 0 }
13677 static const struct message WmSetWindowRgn_clear[] = {
13678 { WM_WINDOWPOSCHANGING, sent/*|wparam|lparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED
13679 |SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */, 0xf
13680 /* Some newer Windows versions set window coordinates instead of zeros in WINDOWPOS structure */},
13681 { WM_NCCALCSIZE, sent|wparam|lparam, 1, 0xf },
13682 { WM_NCPAINT, sent|optional },
13683 { WM_GETTEXT, sent|defwinproc|optional },
13684 { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
13685 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
13686 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
13687 { WM_NCPAINT, sent|optional },
13688 { WM_GETTEXT, sent|defwinproc|optional },
13689 { WM_ERASEBKGND, sent|optional },
13690 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13691 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13692 { WM_WINDOWPOSCHANGING, sent|optional },
13693 { WM_NCCALCSIZE, sent|optional|wparam, 1 },
13694 { WM_NCPAINT, sent|optional },
13695 { WM_GETTEXT, sent|defwinproc|optional },
13696 { WM_ERASEBKGND, sent|optional },
13697 { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
13698 { WM_NCCALCSIZE, sent|optional|wparam, 1 },
13699 { WM_NCPAINT, sent|optional },
13700 { WM_GETTEXT, sent|defwinproc|optional },
13701 { WM_ERASEBKGND, sent|optional },
13702 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13703 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not always sent. */
13704 { 0 }
13707 static void test_SetWindowRgn(void)
13709 HRGN hrgn;
13710 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
13711 100, 100, 200, 200, 0, 0, 0, NULL);
13712 ok( hwnd != 0, "Failed to create overlapped window\n" );
13714 ShowWindow( hwnd, SW_SHOW );
13715 UpdateWindow( hwnd );
13716 flush_events();
13717 flush_sequence();
13719 trace("testing SetWindowRgn\n");
13720 hrgn = CreateRectRgn( 0, 0, 150, 150 );
13721 SetWindowRgn( hwnd, hrgn, TRUE );
13722 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
13724 hrgn = CreateRectRgn( 30, 30, 160, 160 );
13725 SetWindowRgn( hwnd, hrgn, FALSE );
13726 ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
13728 hrgn = CreateRectRgn( 0, 0, 180, 180 );
13729 SetWindowRgn( hwnd, hrgn, TRUE );
13730 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
13732 SetWindowRgn( hwnd, 0, TRUE );
13733 ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
13735 DestroyWindow( hwnd );
13738 /*************************** ShowWindow() test ******************************/
13739 static const struct message WmShowNormal[] = {
13740 { WM_SHOWWINDOW, sent|wparam, 1 },
13741 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
13742 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13743 { HCBT_ACTIVATE, hook },
13744 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13745 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
13746 { HCBT_SETFOCUS, hook },
13747 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
13748 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13749 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends it, but Win8+ doesn't. */
13750 { 0 }
13752 static const struct message WmShow[] = {
13753 { WM_SHOWWINDOW, sent|wparam, 1 },
13754 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
13755 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13756 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13757 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13758 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13759 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13760 { 0 }
13762 static const struct message WmShowNoActivate_1[] = {
13763 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
13764 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13765 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13766 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13767 { WM_MOVE, sent|defwinproc|optional },
13768 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
13769 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13770 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
13771 { 0 }
13773 static const struct message WmShowNoActivate_2[] = {
13774 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
13775 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13776 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13777 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13778 { HCBT_ACTIVATE, hook|optional },
13779 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends this. */
13780 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13781 { WM_WINDOWPOSCHANGED, sent|optional }, /* Sometimes sent on Win8+. */
13782 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
13783 { HCBT_SETFOCUS, hook|optional },
13784 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Win7 sends this. */
13785 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13786 { WM_MOVE, sent|defwinproc },
13787 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
13788 { HCBT_SETFOCUS, hook|optional },
13789 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
13790 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
13791 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13792 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
13793 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13794 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
13795 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13796 { 0 }
13798 static const struct message WmShowNA_1[] = {
13799 { WM_SHOWWINDOW, sent|wparam, 1 },
13800 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13801 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13802 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13803 { 0 }
13805 static const struct message WmShowNA_2[] = {
13806 { WM_SHOWWINDOW, sent|wparam, 1 },
13807 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13808 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13809 { 0 }
13811 static const struct message WmRestore_1[] = {
13812 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
13813 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13814 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13815 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13816 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13817 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13818 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13819 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13820 { WM_MOVE, sent|defwinproc },
13821 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
13822 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13823 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
13824 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13825 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
13826 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
13827 { 0 }
13829 static const struct message WmRestore_2[] = {
13830 { WM_SHOWWINDOW, sent|wparam, 1 },
13831 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
13832 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13833 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13834 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13835 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13836 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13837 { 0 }
13839 static const struct message WmRestore_3[] = {
13840 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
13841 { WM_GETMINMAXINFO, sent },
13842 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13843 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13844 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
13845 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13846 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
13847 { WM_WINDOWPOSCHANGED, sent|optional }, /* Win8+ sometimes sends this. */
13848 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
13849 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
13850 { WM_WINDOWPOSCHANGED, sent|optional },
13851 { WM_MOVE, sent|defwinproc },
13852 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
13853 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
13854 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13855 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
13856 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13857 { 0 }
13859 static const struct message WmRestore_4[] = {
13860 { HCBT_MINMAX, hook|lparam|optional, 0, SW_RESTORE },
13861 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13862 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13863 { WM_MOVE, sent|defwinproc|optional },
13864 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
13865 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13866 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
13867 { 0 }
13869 static const struct message WmRestore_5[] = {
13870 { HCBT_MINMAX, hook|lparam|optional, 0, SW_SHOWNORMAL },
13871 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13872 { HCBT_ACTIVATE, hook|optional },
13873 { HCBT_SETFOCUS, hook|optional },
13874 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13875 { WM_MOVE, sent|defwinproc|optional },
13876 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
13877 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
13878 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
13879 { 0 }
13881 static const struct message WmHide_1[] = {
13882 { WM_SHOWWINDOW, sent|wparam, 0 },
13883 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOACTIVATE },
13884 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13885 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOACTIVATE },
13886 { HCBT_ACTIVATE, hook|optional },
13887 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
13888 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
13889 { 0 }
13891 static const struct message WmHide_2[] = {
13892 { WM_SHOWWINDOW, sent|wparam, 0 },
13893 { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
13894 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13895 { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
13896 { HCBT_ACTIVATE, hook|optional },
13897 { 0 }
13899 static const struct message WmHide_3[] = {
13900 { WM_SHOWWINDOW, sent|wparam, 0 },
13901 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
13902 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13903 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13904 { HCBT_SETFOCUS, hook|optional },
13905 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
13906 { 0 }
13908 static const struct message WmShowMinimized_1[] = {
13909 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
13910 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13911 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13912 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13913 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13914 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13915 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13916 { WM_MOVE, sent|defwinproc },
13917 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
13918 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13919 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
13920 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13921 { 0 }
13923 static const struct message WmMinimize_1[] = {
13924 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
13925 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13926 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
13927 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13928 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13929 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13930 { WM_MOVE, sent|defwinproc },
13931 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
13932 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13933 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
13934 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13935 { 0 }
13937 static const struct message WmMinimize_2[] = {
13938 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
13939 { HCBT_SETFOCUS, hook|optional },
13940 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13941 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13942 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13943 { WM_MOVE, sent|defwinproc },
13944 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
13945 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13946 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
13947 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13948 { 0 }
13950 static const struct message WmMinimize_3[] = {
13951 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
13952 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13953 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13954 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13955 { HCBT_ACTIVATE, hook|optional },
13956 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sometimes sent on Win8/10. */
13957 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13958 { WM_WINDOWPOSCHANGED, sent|optional },
13959 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sometimes sent on Win7. */
13960 { WM_WINDOWPOSCHANGED, sent|optional },
13961 { WM_MOVE, sent|defwinproc },
13962 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
13963 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13964 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
13965 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13966 { 0 }
13968 static const struct message WmShowMinNoActivate[] = {
13969 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
13970 { WM_WINDOWPOSCHANGING, sent },
13971 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13972 { WM_WINDOWPOSCHANGED, sent },
13973 { WM_MOVE, sent|defwinproc|optional },
13974 { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
13975 { 0 }
13977 static const struct message WmMinMax_1[] = {
13978 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
13979 { 0 }
13981 static const struct message WmMinMax_2[] = {
13982 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
13983 { WM_GETMINMAXINFO, sent|optional },
13984 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED },
13985 { HCBT_ACTIVATE, hook|optional },
13986 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13987 { HCBT_SETFOCUS, hook|optional },
13988 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13989 { WM_MOVE, sent|defwinproc|optional },
13990 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MAXIMIZED },
13991 { HCBT_SETFOCUS, hook|optional },
13992 { 0 }
13994 static const struct message WmMinMax_3[] = {
13995 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
13996 { HCBT_SETFOCUS, hook|optional },
13997 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13998 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13999 { WM_MOVE, sent|defwinproc|optional },
14000 { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
14001 { 0 }
14003 static const struct message WmMinMax_4[] = {
14004 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
14005 { 0 }
14007 static const struct message WmShowMaximized_1[] = {
14008 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
14009 { WM_GETMINMAXINFO, sent },
14010 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
14011 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14012 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14013 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
14014 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
14015 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
14016 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
14017 { WM_MOVE, sent|defwinproc },
14018 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
14019 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14020 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
14021 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14022 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
14023 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
14024 { 0 }
14026 static const struct message WmShowMaximized_2[] = {
14027 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
14028 { WM_GETMINMAXINFO, sent },
14029 { WM_WINDOWPOSCHANGING, sent|optional },
14030 { HCBT_ACTIVATE, hook|optional },
14031 { WM_WINDOWPOSCHANGED, sent|optional },
14032 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
14033 { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
14034 { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
14035 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends this. */
14036 { WM_WINDOWPOSCHANGING, sent|optional },
14037 { HCBT_SETFOCUS, hook|optional },
14038 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
14039 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
14040 { WM_MOVE, sent|defwinproc },
14041 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
14042 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14043 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
14044 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14045 { HCBT_SETFOCUS, hook|optional },
14046 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
14047 { 0 }
14049 static const struct message WmShowMaximized_3[] = {
14050 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
14051 { WM_GETMINMAXINFO, sent|optional },
14052 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
14053 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
14054 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
14055 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
14056 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
14057 { WM_MOVE, sent|defwinproc|optional },
14058 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
14059 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14060 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
14061 { 0 }
14064 static void test_ShowWindow(void)
14066 /* ShowWindow commands in random order */
14067 static const struct
14069 INT cmd; /* ShowWindow command */
14070 LPARAM ret; /* ShowWindow return value */
14071 DWORD style; /* window style after the command */
14072 const struct message *msg; /* message sequence the command produces */
14073 INT wp_cmd, wp_flags; /* window placement after the command */
14074 POINT wp_min, wp_max; /* window placement after the command */
14075 BOOL todo_msg; /* message sequence doesn't match what Wine does */
14076 } sw[] =
14078 /* 1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal,
14079 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
14080 /* 2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq,
14081 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
14082 /* 3 */ { SW_HIDE, TRUE, 0, WmHide_1,
14083 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
14084 /* 4 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
14085 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
14086 /* 5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1,
14087 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
14088 /* 6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1,
14089 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
14090 /* 7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1,
14091 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
14092 /* 8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
14093 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
14094 /* 9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1,
14095 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
14096 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
14097 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
14098 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1,
14099 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
14100 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq,
14101 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
14102 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1,
14103 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
14104 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
14105 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
14106 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2,
14107 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
14108 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
14109 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
14110 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow,
14111 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
14112 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
14113 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
14114 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
14115 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
14116 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
14117 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
14118 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
14119 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
14120 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate,
14121 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, TRUE },
14122 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4,
14123 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
14124 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
14125 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
14126 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
14127 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
14128 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1,
14129 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
14130 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2,
14131 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
14132 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
14133 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
14134 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
14135 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
14136 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1,
14137 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
14138 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
14139 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
14140 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3,
14141 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
14142 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
14143 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
14144 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, /* what does this mean?! */
14145 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
14146 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq,
14147 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
14148 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
14149 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
14150 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2,
14151 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
14152 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
14153 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
14154 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
14155 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
14156 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2,
14157 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
14158 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
14159 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
14160 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2,
14161 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
14162 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
14163 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
14164 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
14165 SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
14166 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
14167 SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
14168 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3,
14169 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
14170 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4,
14171 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
14172 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3,
14173 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
14174 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq,
14175 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
14176 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
14177 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
14178 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
14179 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
14180 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1,
14181 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
14182 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
14183 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
14184 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3,
14185 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
14186 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
14187 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
14188 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2,
14189 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
14190 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
14191 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE }
14193 HWND hwnd;
14194 DWORD style;
14195 LPARAM ret;
14196 INT i;
14197 WINDOWPLACEMENT wp;
14198 RECT win_rc, work_rc = {0, 0, 0, 0};
14199 HMONITOR hmon;
14200 MONITORINFO mi;
14201 POINT pt = {0, 0};
14203 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
14204 hwnd = CreateWindowExA(0, "ShowWindowClass", NULL, WS_BASE,
14205 120, 120, 90, 90,
14206 0, 0, 0, NULL);
14207 assert(hwnd);
14209 style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
14210 ok(style == 0, "expected style 0, got %08lx\n", style);
14212 flush_events();
14213 flush_sequence();
14215 SetLastError(0xdeadbeef);
14216 hmon = MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
14217 ok(hmon != 0, "MonitorFromPoint error %lu\n", GetLastError());
14219 mi.cbSize = sizeof(mi);
14220 SetLastError(0xdeadbeef);
14221 ret = GetMonitorInfoA(hmon, &mi);
14222 ok(ret, "GetMonitorInfo error %lu\n", GetLastError());
14223 trace("monitor %s, work %s\n", wine_dbgstr_rect(&mi.rcMonitor),
14224 wine_dbgstr_rect(&mi.rcWork));
14225 work_rc = mi.rcWork;
14227 GetWindowRect(hwnd, &win_rc);
14228 OffsetRect(&win_rc, -work_rc.left, -work_rc.top);
14230 wp.length = sizeof(wp);
14231 SetLastError(0xdeadbeaf);
14232 ret = GetWindowPlacement(hwnd, &wp);
14233 ok(ret, "GetWindowPlacement error %lu\n", GetLastError());
14234 ok(wp.flags == 0, "expected 0, got %#x\n", wp.flags);
14235 ok(wp.showCmd == SW_SHOWNORMAL, "expected SW_SHOWNORMAL, got %d\n", wp.showCmd);
14236 ok(wp.ptMinPosition.x == -1 && wp.ptMinPosition.y == -1,
14237 "expected -1,-1 got %ld,%ld\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
14238 ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
14239 "expected -1,-1 got %ld,%ld\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
14240 todo_wine_if (work_rc.left || work_rc.top) /* FIXME: remove once Wine is fixed */
14241 ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n", wine_dbgstr_rect(&win_rc),
14242 wine_dbgstr_rect(&wp.rcNormalPosition));
14244 for (i = 0; i < ARRAY_SIZE(sw); i++)
14246 static const char * const sw_cmd_name[13] =
14248 "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
14249 "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
14250 "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
14251 "SW_NORMALNA" /* 0xCC */
14253 char comment[64];
14254 INT idx; /* index into the above array of names */
14256 idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
14258 style = GetWindowLongA(hwnd, GWL_STYLE);
14259 trace("%d: sending %s, current window style %08lx\n", i+1, sw_cmd_name[idx], style);
14260 ret = ShowWindow(hwnd, sw[i].cmd);
14261 ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %Iu, got %Iu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
14262 style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
14263 ok(style == sw[i].style, "%d: expected style %08lx, got %08lx\n", i+1, sw[i].style, style);
14265 sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
14266 ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
14268 wp.length = sizeof(wp);
14269 SetLastError(0xdeadbeaf);
14270 ret = GetWindowPlacement(hwnd, &wp);
14271 ok(ret, "GetWindowPlacement error %lu\n", GetLastError());
14272 ok(wp.flags == sw[i].wp_flags, "expected %#x, got %#x\n", sw[i].wp_flags, wp.flags);
14273 ok(wp.showCmd == sw[i].wp_cmd, "expected %d, got %d\n", sw[i].wp_cmd, wp.showCmd);
14275 /* NT moves the minimized window to -32000,-32000, win9x to 3000,3000 */
14276 if ((wp.ptMinPosition.x + work_rc.left == -32000 && wp.ptMinPosition.y + work_rc.top == -32000) ||
14277 (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000))
14279 ok((wp.ptMinPosition.x + work_rc.left == sw[i].wp_min.x && wp.ptMinPosition.y + work_rc.top == sw[i].wp_min.y) ||
14280 (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000),
14281 "expected %ld,%ld got %ld,%ld\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
14283 else
14285 ok(wp.ptMinPosition.x == sw[i].wp_min.x && wp.ptMinPosition.y == sw[i].wp_min.y,
14286 "expected %ld,%ld got %ld,%ld\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
14289 todo_wine_if(wp.ptMaxPosition.x != sw[i].wp_max.x || wp.ptMaxPosition.y != sw[i].wp_max.y)
14290 ok(wp.ptMaxPosition.x == sw[i].wp_max.x && wp.ptMaxPosition.y == sw[i].wp_max.y,
14291 "expected %ld,%ld got %ld,%ld\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y);
14293 if (0) /* FIXME: Wine behaves completely different here */
14294 ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n",
14295 wine_dbgstr_rect(&win_rc), wine_dbgstr_rect(&wp.rcNormalPosition));
14297 DestroyWindow(hwnd);
14298 flush_events();
14301 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
14303 struct recvd_message msg;
14305 if (ignore_message( message )) return 0;
14307 msg.hwnd = hwnd;
14308 msg.message = message;
14309 msg.flags = sent|wparam|lparam;
14310 msg.wParam = wParam;
14311 msg.lParam = lParam;
14312 msg.descr = "dialog";
14313 add_message(&msg);
14315 /* calling DefDlgProc leads to a recursion under XP */
14317 switch (message)
14319 case WM_INITDIALOG:
14320 return lParam;
14322 case WM_GETDLGCODE:
14323 return 0;
14325 return 1;
14328 static WNDPROC orig_edit_proc;
14329 static LRESULT WINAPI dlg_creation_edit_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
14331 struct recvd_message msg;
14333 if (ignore_message( message )) return 0;
14335 msg.hwnd = hwnd;
14336 msg.message = message;
14337 msg.flags = sent|wparam|lparam;
14338 msg.wParam = wp;
14339 msg.lParam = lp;
14340 msg.descr = "edit";
14341 add_message(&msg);
14343 return CallWindowProcW(orig_edit_proc, hwnd, message, wp, lp);
14346 static INT_PTR WINAPI test_dlg_proc2(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
14348 struct recvd_message msg;
14350 if (ignore_message( message )) return 0;
14352 msg.hwnd = hwnd;
14353 msg.message = message;
14354 msg.flags = sent|wparam|lparam|parent;
14355 msg.wParam = wParam;
14356 msg.lParam = lParam;
14357 msg.descr = "dialog";
14358 add_message(&msg);
14360 if (message == WM_INITDIALOG)
14362 orig_edit_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwnd, 200),
14363 GWLP_WNDPROC, (LONG_PTR)dlg_creation_edit_proc);
14366 return 1;
14369 static INT_PTR WINAPI test_dlg_proc3(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
14371 ok( 0, "should not be called since DefDlgProc is not used\n" );
14372 return 0;
14375 static LRESULT WINAPI test_dlg_proc4(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
14377 struct recvd_message msg;
14379 if (!ignore_message( message ))
14381 msg.hwnd = hwnd;
14382 msg.message = message;
14383 msg.flags = sent|wparam|lparam|parent;
14384 msg.wParam = wParam;
14385 msg.lParam = lParam;
14386 msg.descr = "dialog";
14387 add_message(&msg);
14389 if (message == WM_INITDIALOG)
14391 orig_edit_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwnd, 200),
14392 GWLP_WNDPROC, (LONG_PTR)dlg_creation_edit_proc);
14393 return 1;
14395 return DefWindowProcW( hwnd, message, wParam, lParam );
14398 static const struct message WmDefDlgSetFocus_1[] = {
14399 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
14400 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
14401 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
14402 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
14403 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
14404 { HCBT_SETFOCUS, hook },
14405 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
14406 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
14407 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
14408 { WM_SETFOCUS, sent|wparam, 0 },
14409 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
14410 { WM_CTLCOLOREDIT, sent },
14411 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
14412 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
14413 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
14414 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
14415 { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
14416 { 0 }
14418 static const struct message WmDefDlgSetFocus_2[] = {
14419 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
14420 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
14421 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
14422 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
14423 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
14424 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
14425 { WM_CTLCOLOREDIT, sent|optional }, /* XP */
14426 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
14427 { 0 }
14429 /* Creation of a dialog */
14430 static const struct message WmCreateDialogParamSeq_0[] = {
14431 { HCBT_CREATEWND, hook },
14432 { WM_NCCREATE, sent },
14433 { WM_NCCALCSIZE, sent|wparam, 0 },
14434 { WM_CREATE, sent },
14435 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14436 { WM_SIZE, sent|wparam, SIZE_RESTORED },
14437 { WM_MOVE, sent },
14438 { WM_SETFONT, sent },
14439 { WM_INITDIALOG, sent },
14440 { WM_CHANGEUISTATE, sent|optional },
14441 { 0 }
14443 /* Creation of a dialog */
14444 static const struct message WmCreateDialogParamSeq_1[] = {
14445 { HCBT_CREATEWND, hook },
14446 { WM_NCCREATE, sent },
14447 { WM_NCCALCSIZE, sent|wparam, 0 },
14448 { WM_CREATE, sent },
14449 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14450 { WM_SIZE, sent|wparam, SIZE_RESTORED },
14451 { WM_MOVE, sent },
14452 { WM_SETFONT, sent },
14453 { WM_INITDIALOG, sent },
14454 { WM_GETDLGCODE, sent|wparam|lparam|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
14455 { HCBT_SETFOCUS, hook },
14456 { HCBT_ACTIVATE, hook },
14457 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14458 { WM_QUERYNEWPALETTE, sent|optional },
14459 { WM_PALETTEISCHANGING, sent|optional },
14460 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
14461 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOREDRAW },
14462 { WM_ACTIVATEAPP, sent|wparam, 1 },
14463 { WM_NCACTIVATE, sent },
14464 { WM_ACTIVATE, sent|wparam, 1 },
14465 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
14466 { WM_SETFOCUS, sent },
14467 { WM_CHANGEUISTATE, sent|optional },
14468 { 0 }
14470 /* Creation of a dialog */
14471 static const struct message WmCreateDialogParamSeq_2[] = {
14472 { HCBT_CREATEWND, hook },
14473 { WM_NCCREATE, sent },
14474 { WM_NCCALCSIZE, sent|wparam, 0 },
14475 { WM_CREATE, sent },
14476 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14477 { WM_SIZE, sent|wparam, SIZE_RESTORED },
14478 { WM_MOVE, sent },
14479 { WM_CHANGEUISTATE, sent|optional },
14480 { 0 }
14483 static const struct message WmCreateDialogParamSeq_3[] = {
14484 { HCBT_CREATEWND, hook },
14485 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14486 { WM_SETFONT, sent|parent },
14487 { WM_INITDIALOG, sent|parent },
14488 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
14489 { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
14490 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
14491 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
14492 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
14493 { HCBT_ACTIVATE, hook },
14494 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14495 { WM_QUERYNEWPALETTE, sent|parent|optional }, /* TODO: this message should not be sent */
14496 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
14497 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
14498 { WM_WINDOWPOSCHANGED, sent|parent|wparam|optional, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14499 { WM_WINDOWPOSCHANGED, sent|parent|wparam|optional, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14500 { WM_NCCALCSIZE, sent|parent|optional, 0 },
14501 { WM_MOVE, sent|parent|optional },
14502 { WM_SIZE, sent|parent|optional },
14503 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
14504 { WM_ACTIVATEAPP, sent|parent|wparam, 1 },
14505 { WM_NCACTIVATE, sent|parent },
14506 { WM_ACTIVATE, sent|parent|wparam, 1 },
14507 { WM_SETFOCUS, sent },
14508 { WM_COMMAND, sent|parent|wparam, MAKELONG(200, EN_SETFOCUS) },
14509 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
14510 { WM_USER, sent|parent },
14511 { WM_CHANGEUISTATE, sent|parent|optional },
14512 { 0 }
14515 static const struct message WmCreateDialogParamSeq_4[] = {
14516 { HCBT_CREATEWND, hook },
14517 { WM_NCCREATE, sent|parent },
14518 { WM_NCCALCSIZE, sent|parent|wparam, 0 },
14519 { WM_CREATE, sent|parent },
14520 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14521 { WM_SIZE, sent|parent|wparam, SIZE_RESTORED },
14522 { WM_MOVE, sent|parent },
14523 { WM_SETFONT, sent|parent },
14524 { WM_INITDIALOG, sent|parent },
14525 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
14526 { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
14527 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
14528 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
14529 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
14530 { HCBT_ACTIVATE, hook },
14531 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14532 { WM_QUERYNEWPALETTE, sent|parent|optional }, /* TODO: this message should not be sent */
14533 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
14534 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
14535 { WM_WINDOWPOSCHANGED, sent|parent|wparam|optional, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14536 { WM_NCCALCSIZE, sent|parent|optional, 0 },
14537 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
14538 { WM_ACTIVATEAPP, sent|parent|wparam, 1 },
14539 { WM_NCACTIVATE, sent|parent },
14540 { WM_ACTIVATE, sent|parent|wparam, 1 },
14541 { HCBT_SETFOCUS, hook },
14542 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
14543 { WM_SETFOCUS, sent|parent },
14544 { WM_KILLFOCUS, sent|parent },
14545 { WM_SETFOCUS, sent },
14546 { WM_COMMAND, sent|parent|wparam, MAKELONG(200, EN_SETFOCUS) },
14547 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
14548 { WM_USER, sent|parent },
14549 { WM_CHANGEUISTATE, sent|parent|optional },
14550 { WM_UPDATEUISTATE, sent|parent|optional },
14551 { WM_UPDATEUISTATE, sent|optional },
14552 { 0 }
14555 static void test_dialog_messages(void)
14557 WNDCLASSA cls;
14558 HWND hdlg, hedit1, hedit2, hfocus, parent, child, child2;
14559 LRESULT ret;
14561 #define set_selection(hctl, start, end) \
14562 ret = SendMessageA(hctl, EM_SETSEL, start, end); \
14563 ok(ret == 1, "EM_SETSEL returned %Id\n", ret);
14565 #define check_selection(hctl, start, end) \
14566 ret = SendMessageA(hctl, EM_GETSEL, 0, 0); \
14567 ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
14569 subclass_edit();
14571 hdlg = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
14572 WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
14573 0, 0, 100, 100, 0, 0, 0, NULL);
14574 ok(hdlg != 0, "Failed to create custom dialog window\n");
14576 hedit1 = CreateWindowExA(0, "my_edit_class", NULL,
14577 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
14578 0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
14579 ok(hedit1 != 0, "Failed to create edit control\n");
14580 hedit2 = CreateWindowExA(0, "my_edit_class", NULL,
14581 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
14582 0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
14583 ok(hedit2 != 0, "Failed to create edit control\n");
14585 SendMessageA(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
14586 SendMessageA(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
14588 hfocus = GetFocus();
14589 ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
14591 SetFocus(hedit2);
14592 hfocus = GetFocus();
14593 ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
14595 check_selection(hedit1, 0, 0);
14596 check_selection(hedit2, 0, 0);
14598 set_selection(hedit2, 0, -1);
14599 check_selection(hedit2, 0, 3);
14601 SetFocus(0);
14602 hfocus = GetFocus();
14603 ok(hfocus == 0, "wrong focus %p\n", hfocus);
14605 flush_sequence();
14606 ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
14607 ok(ret == 0, "WM_SETFOCUS returned %Id\n", ret);
14608 ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
14610 hfocus = GetFocus();
14611 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
14613 check_selection(hedit1, 0, 5);
14614 check_selection(hedit2, 0, 3);
14616 flush_sequence();
14617 ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
14618 ok(ret == 0, "WM_SETFOCUS returned %Id\n", ret);
14619 ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
14621 hfocus = GetFocus();
14622 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
14624 check_selection(hedit1, 0, 5);
14625 check_selection(hedit2, 0, 3);
14627 EndDialog(hdlg, 0);
14628 DestroyWindow(hedit1);
14629 DestroyWindow(hedit2);
14630 DestroyWindow(hdlg);
14631 flush_sequence();
14633 #undef set_selection
14634 #undef check_selection
14636 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
14637 cls.lpszClassName = "MyDialogClass";
14638 cls.hInstance = GetModuleHandleA(NULL);
14639 /* need a cast since a dlgproc is used as a wndproc */
14640 cls.lpfnWndProc = (WNDPROC)test_dlg_proc;
14641 if (!RegisterClassA(&cls)) assert(0);
14643 SetFocus(0);
14644 flush_sequence();
14645 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
14646 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14647 ok_sequence(WmCreateDialogParamSeq_0, "CreateDialogParam_0", FALSE);
14648 hfocus = GetFocus();
14649 ok(hfocus == 0, "wrong focus %p\n", hfocus);
14650 EndDialog(hdlg, 0);
14651 DestroyWindow(hdlg);
14652 flush_sequence();
14654 SetFocus(0);
14655 flush_sequence();
14656 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 1);
14657 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14658 ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
14659 hfocus = GetFocus();
14660 ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
14661 EndDialog(hdlg, 0);
14662 DestroyWindow(hdlg);
14663 flush_sequence();
14665 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
14666 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14667 ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
14668 EndDialog(hdlg, 0);
14669 DestroyWindow(hdlg);
14670 flush_sequence();
14672 hdlg = CreateDialogParamA(0, "FOCUS_TEST_DIALOG_3", 0, test_dlg_proc2, 0);
14673 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14674 ok_sequence(WmCreateDialogParamSeq_3, "CreateDialogParam_3", TRUE);
14675 EndDialog(hdlg, 0);
14676 DestroyWindow(hdlg);
14677 flush_sequence();
14679 UnregisterClassA( cls.lpszClassName, cls.hInstance );
14680 cls.lpfnWndProc = test_dlg_proc4;
14681 ok( RegisterClassA(&cls), "failed to register class again\n" );
14682 hdlg = CreateDialogParamA(0, "FOCUS_TEST_DIALOG_4", 0, test_dlg_proc3, 0);
14683 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14684 ok_sequence(WmCreateDialogParamSeq_4, "CreateDialogParam_4", TRUE);
14685 EndDialog(hdlg, 0);
14686 DestroyWindow(hdlg);
14687 flush_sequence();
14689 UnregisterClassA(cls.lpszClassName, cls.hInstance);
14691 parent = CreateWindowExA(0, "TestParentClass", "Test parent",
14692 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14693 100, 100, 200, 200, 0, 0, 0, NULL);
14694 ok (parent != 0, "Failed to create parent window\n");
14696 /* This child has no parent set. We will later call SetParent on it,
14697 * so that it will have a parent set, but no WS_CHILD style. */
14698 child = CreateWindowExA(0, "TestWindowClass", "Test child",
14699 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14700 100, 100, 200, 200, 0, 0, 0, NULL);
14701 ok (child != 0, "Failed to create child window\n");
14703 /* This is a regular child window. When used as an owner, the other
14704 * child window will be used. */
14705 child2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2",
14706 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CHILD,
14707 100, 100, 200, 200, child, 0, 0, NULL);
14708 ok (child2 != 0, "Failed to create child window\n");
14710 SetParent(child, parent);
14711 SetFocus(child);
14713 flush_sequence();
14714 DialogBoxA( 0, "TEST_DIALOG", child2, TestModalDlgProc2 );
14715 ok_sequence(WmModalDialogSeq_2, "ModalDialog2", TRUE);
14717 DestroyWindow(child2);
14718 DestroyWindow(child);
14719 DestroyWindow(parent);
14720 flush_sequence();
14723 static void test_enddialog_seq(HWND dialog, HWND owner)
14725 const struct message seq[] = {
14726 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14727 { WM_ENABLE, sent },
14728 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
14729 { HCBT_ACTIVATE, hook|wparam, (WPARAM)owner },
14730 { WM_NCACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
14731 { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
14732 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14733 /* FIXME: Following two are optional because Wine sends WM_QUERYNEWPALETTE instead of WM_WINDOWPOSCHANGING */
14734 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
14735 { WM_QUERYNEWPALETTE, sent|optional },
14736 { WM_NCACTIVATE, sent|wparam|lparam, WA_ACTIVE, (LPARAM)dialog },
14737 { WM_GETTEXT, sent|optional|defwinproc },
14738 { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, (LPARAM)dialog },
14739 { HCBT_SETFOCUS, hook|wparam, (WPARAM)owner },
14740 { WM_KILLFOCUS, sent|wparam, (WPARAM)owner },
14741 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
14742 { WM_SETFOCUS, sent|defwinproc|wparam, (WPARAM)dialog },
14743 { 0 }
14746 flush_sequence();
14747 EndDialog(dialog, 0);
14748 ok_sequence(seq, "EndDialog", FALSE);
14751 static void test_enddialog_seq2(HWND dialog, HWND owner)
14753 const struct message seq[] = {
14754 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14755 { WM_ENABLE, parent|sent },
14756 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
14757 { HCBT_ACTIVATE, hook|wparam, (WPARAM)owner },
14758 { WM_NCACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
14759 { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
14760 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14761 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
14762 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
14763 { HCBT_SETFOCUS, hook|wparam, (WPARAM)owner },
14764 { WM_KILLFOCUS, sent|wparam, (WPARAM)owner },
14765 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
14766 { WM_SETFOCUS, sent|parent|defwinproc|wparam, (WPARAM)dialog },
14767 { 0 }
14770 flush_sequence();
14771 EndDialog(dialog, 0);
14772 ok_sequence(seq, "EndDialog2", FALSE);
14775 static void test_EndDialog(void)
14777 HWND hparent, hother, hactive, hdlg, hchild;
14778 WNDCLASSA cls;
14780 hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
14781 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
14782 100, 100, 200, 200, 0, 0, 0, NULL);
14783 ok (hparent != 0, "Failed to create parent window\n");
14785 hother = CreateWindowExA(0, "TestParentClass", "Test parent 2",
14786 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14787 200, 100, 200, 200, 0, 0, 0, NULL);
14788 ok (hother != 0, "Failed to create parent window\n");
14790 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
14791 cls.lpszClassName = "MyDialogClass";
14792 cls.hInstance = GetModuleHandleA(NULL);
14793 cls.lpfnWndProc = (WNDPROC)test_dlg_proc;
14794 if (!RegisterClassA(&cls)) assert(0);
14796 flush_sequence();
14797 SetForegroundWindow(hother);
14798 hactive = GetForegroundWindow();
14799 ok(hother == hactive, "Wrong window has focus (%p != %p)\n", hother, hactive);
14801 /* create a dialog where the parent is disabled, this parent should be
14802 * enabled and receive focus when dialog exits */
14803 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hparent, test_dlg_proc, 0);
14804 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14805 SetForegroundWindow(hdlg);
14806 hactive = GetForegroundWindow();
14807 ok(hdlg == hactive, "Wrong window has focus (%p != %p)\n", hdlg, hactive);
14808 EndDialog(hdlg, 0);
14809 ok(IsWindowEnabled(hparent), "parent is not enabled\n");
14810 hactive = GetForegroundWindow();
14811 ok(hparent == hactive, "Wrong window has focus (parent != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
14812 DestroyWindow(hdlg);
14813 flush_sequence();
14815 /* create a dialog where the parent is disabled and set active window to other window before calling EndDialog */
14816 EnableWindow(hparent, FALSE);
14817 hdlg = CreateWindowExA(0, "TestDialogClass", NULL,
14818 WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
14819 0, 0, 100, 100, hparent, 0, 0, NULL);
14820 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14821 flush_sequence();
14822 SetForegroundWindow(hother);
14823 flush_sequence();
14824 hactive = GetForegroundWindow();
14825 ok(hactive == hother, "Wrong foreground (%p != %p)\n", hactive, hother);
14826 hactive = GetActiveWindow();
14827 ok(hactive == hother, "Wrong active window (%p != %p)\n", hactive, hother);
14828 EndDialog(hdlg, 0);
14829 ok(IsWindowEnabled(hparent), "parent is not enabled\n");
14830 hactive = GetForegroundWindow();
14831 ok(hother == hactive, "Wrong window has focus (other != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
14832 DestroyWindow(hdlg);
14833 flush_sequence();
14835 DestroyWindow( hparent );
14837 hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
14838 WS_POPUP | WS_VISIBLE | WS_DISABLED,
14839 100, 100, 200, 200, 0, 0, 0, NULL);
14840 ok (hparent != 0, "Failed to create parent window\n");
14842 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
14843 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
14844 0, 0, 0, 0, 0, 0, 0, NULL);
14845 ok (hchild != 0, "Failed to create child window\n");
14847 SetParent(hchild, hparent);
14849 flush_sequence();
14850 SetForegroundWindow(hother);
14851 hactive = GetForegroundWindow();
14852 ok(hother == hactive, "Wrong foreground window (%p != %p)\n", hother, hactive);
14854 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hchild, test_dlg_proc, 0);
14855 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14857 SetForegroundWindow(hdlg);
14858 test_enddialog_seq(hdlg, hchild);
14860 hactive = GetForegroundWindow();
14861 ok(hactive == hchild, "Wrong foreground window (active: %p, parent: %p, dlg: %p, other: %p child: %p)\n", hactive, hparent, hdlg, hother, hchild);
14863 DestroyWindow(hdlg);
14865 /* Now set WS_CHILD style flag so that it's a real child and its parent will be dialog's owner. */
14866 SetWindowLongW(hchild, GWL_STYLE, GetWindowLongW(hchild, GWL_STYLE) | WS_CHILD);
14868 SetForegroundWindow(hother);
14869 hactive = GetForegroundWindow();
14870 ok(hother == hactive, "Wrong foreground window (%p != %p)\n", hother, hactive);
14872 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hchild, test_dlg_proc, 0);
14873 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14875 SetForegroundWindow(hdlg);
14876 test_enddialog_seq2(hdlg, hparent);
14878 hactive = GetForegroundWindow();
14879 ok(hactive == hparent, "Wrong foreground window (active: %p, parent: %p, dlg: %p, other: %p child: %p)\n", hactive, hparent, hdlg, hother, hchild);
14880 DestroyWindow(hdlg);
14881 DestroyWindow(hchild);
14882 DestroyWindow(hparent);
14883 DestroyWindow(hother);
14884 flush_sequence();
14886 UnregisterClassA(cls.lpszClassName, cls.hInstance);
14889 static void test_nullCallback(void)
14891 HWND hwnd;
14893 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
14894 100, 100, 200, 200, 0, 0, 0, NULL);
14895 ok (hwnd != 0, "Failed to create overlapped window\n");
14897 SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
14898 flush_events();
14899 DestroyWindow(hwnd);
14902 /* SetActiveWindow( 0 ) hwnd visible */
14903 static const struct message SetActiveWindowSeq0[] =
14905 { HCBT_ACTIVATE, hook|optional },
14906 { WM_NCACTIVATE, sent|wparam, 0 },
14907 { WM_GETTEXT, sent|defwinproc|optional },
14908 { WM_ACTIVATE, sent|wparam, 0 },
14909 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14910 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
14911 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
14912 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
14913 { WM_KILLFOCUS, sent|optional },
14914 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
14915 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
14916 { WM_NCACTIVATE, sent|wparam|optional, 1 },
14917 { WM_GETTEXT, sent|defwinproc|optional },
14918 { WM_ACTIVATE, sent|wparam|optional, 1 },
14919 { HCBT_SETFOCUS, hook|optional },
14920 { WM_KILLFOCUS, sent|defwinproc|optional },
14921 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
14922 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
14923 { WM_IME_SETCONTEXT, sent|optional },
14924 { WM_IME_SETCONTEXT, sent|optional },
14925 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
14926 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
14927 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
14928 { WM_SETFOCUS, sent|defwinproc|optional },
14929 { WM_GETTEXT, sent|optional },
14930 { 0 }
14932 /* SetActiveWindow( hwnd ) hwnd visible */
14933 static const struct message SetActiveWindowSeq1[] =
14935 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
14936 { 0 }
14938 /* SetActiveWindow( popup ) hwnd visible, popup visible */
14939 static const struct message SetActiveWindowSeq2[] =
14941 { HCBT_ACTIVATE, hook },
14942 { WM_NCACTIVATE, sent|wparam, 0 },
14943 { WM_GETTEXT, sent|defwinproc|optional },
14944 { WM_ACTIVATE, sent|wparam, 0 },
14945 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14946 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
14947 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
14948 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
14949 { WM_NCPAINT, sent|optional },
14950 { WM_GETTEXT, sent|defwinproc|optional },
14951 { WM_ERASEBKGND, sent|optional },
14952 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14953 { WM_NCACTIVATE, sent|wparam, 1 },
14954 { WM_GETTEXT, sent|defwinproc|optional },
14955 { WM_ACTIVATE, sent|wparam, 1 },
14956 { HCBT_SETFOCUS, hook },
14957 { WM_KILLFOCUS, sent|defwinproc },
14958 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
14959 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
14960 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
14961 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
14962 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
14963 { WM_SETFOCUS, sent|defwinproc },
14964 { WM_GETTEXT, sent|optional },
14965 { 0 }
14968 /* SetActiveWindow( hwnd ) hwnd not visible */
14969 static const struct message SetActiveWindowSeq3[] =
14971 { HCBT_ACTIVATE, hook },
14972 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14973 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
14974 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
14975 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
14976 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14977 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14978 { WM_ACTIVATEAPP, sent|wparam, 1 },
14979 { WM_ACTIVATEAPP, sent|wparam, 1 },
14980 { WM_NCACTIVATE, sent|wparam, 1 },
14981 { WM_ACTIVATE, sent|wparam, 1 },
14982 { HCBT_SETFOCUS, hook },
14983 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
14984 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
14985 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
14986 { WM_SETFOCUS, sent|defwinproc },
14987 { 0 }
14989 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
14990 static const struct message SetActiveWindowSeq4[] =
14992 { HCBT_ACTIVATE, hook },
14993 { WM_NCACTIVATE, sent|wparam, 0 },
14994 { WM_GETTEXT, sent|defwinproc|optional },
14995 { WM_ACTIVATE, sent|wparam, 0 },
14996 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14997 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
14998 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
14999 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
15000 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15001 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15002 { WM_NCACTIVATE, sent|wparam, 1 },
15003 { WM_GETTEXT, sent|defwinproc|optional },
15004 { WM_ACTIVATE, sent|wparam, 1 },
15005 { HCBT_SETFOCUS, hook },
15006 { WM_KILLFOCUS, sent|defwinproc },
15007 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
15008 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
15009 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
15010 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
15011 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
15012 { WM_SETFOCUS, sent|defwinproc },
15013 { 0 }
15017 static void test_SetActiveWindow(void)
15019 HWND hwnd, popup, ret;
15021 hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
15022 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
15023 100, 100, 200, 200, 0, 0, 0, NULL);
15025 popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
15026 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
15027 100, 100, 200, 200, hwnd, 0, 0, NULL);
15029 ok(hwnd != 0, "Failed to create overlapped window\n");
15030 ok(popup != 0, "Failed to create popup window\n");
15031 SetForegroundWindow( popup );
15032 flush_sequence();
15034 trace("SetActiveWindow(0)\n");
15035 ret = SetActiveWindow(0);
15036 ok( ret == popup || broken(ret == 0) /* w1064v1809 */, "Failed to SetActiveWindow(0), ret:%p\n", ret);
15037 if (ret == popup) ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", FALSE);
15038 flush_sequence();
15040 trace("SetActiveWindow(hwnd), hwnd visible\n");
15041 ret = SetActiveWindow(hwnd);
15042 if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
15043 flush_sequence();
15045 trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
15046 ret = SetActiveWindow(popup);
15047 ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
15048 ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
15049 flush_sequence();
15051 ShowWindow(hwnd, SW_HIDE);
15052 ShowWindow(popup, SW_HIDE);
15053 flush_sequence();
15055 trace("SetActiveWindow(hwnd), hwnd not visible\n");
15056 ret = SetActiveWindow(hwnd);
15057 ok( ret == NULL, "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret );
15058 ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
15059 flush_sequence();
15061 trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
15062 ret = SetActiveWindow(popup);
15063 ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
15064 ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
15065 flush_sequence();
15067 trace("done\n");
15069 DestroyWindow(hwnd);
15072 static const struct message SetForegroundWindowSeq[] =
15074 { WM_NCACTIVATE, sent|wparam, 0 },
15075 { WM_GETTEXT, sent|defwinproc|optional },
15076 { WM_ACTIVATE, sent|wparam, 0 },
15077 { WM_ACTIVATEAPP, sent|wparam, 0 },
15078 { WM_KILLFOCUS, sent },
15079 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
15080 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
15081 { 0 }
15084 static void test_SetForegroundWindow(void)
15086 HWND hwnd;
15088 hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
15089 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
15090 100, 100, 200, 200, 0, 0, 0, NULL);
15091 ok (hwnd != 0, "Failed to create overlapped window\n");
15092 SetForegroundWindow( hwnd );
15093 flush_sequence();
15095 trace("SetForegroundWindow( 0 )\n");
15096 SetForegroundWindow( 0 );
15097 ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
15098 trace("SetForegroundWindow( GetDesktopWindow() )\n");
15099 SetForegroundWindow( GetDesktopWindow() );
15100 ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
15101 "foreground top level window", FALSE);
15102 trace("done\n");
15104 DestroyWindow(hwnd);
15107 static DWORD get_input_codepage( void )
15109 DWORD cp;
15110 int ret;
15111 HKL hkl = GetKeyboardLayout( 0 );
15113 ret = GetLocaleInfoW( LOWORD(hkl), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
15114 (WCHAR *)&cp, sizeof(cp) / sizeof(WCHAR) );
15115 if (!ret) cp = CP_ACP;
15116 return cp;
15119 static void test_dbcs_wm_char(void)
15121 BYTE dbch[2];
15122 WCHAR wch, bad_wch;
15123 HWND hwnd, hwnd2;
15124 MSG msg;
15125 DWORD time;
15126 POINT pt;
15127 DWORD_PTR res;
15128 CPINFOEXA cpinfo;
15129 UINT i, j, k;
15130 struct message wmCharSeq[2];
15131 BOOL ret;
15132 DWORD cp = get_input_codepage();
15134 if (!pGetCPInfoExA)
15136 win_skip("GetCPInfoExA is not available\n");
15137 return;
15140 pGetCPInfoExA( cp, 0, &cpinfo );
15141 if (cpinfo.MaxCharSize != 2)
15143 skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
15144 return;
15147 dbch[0] = dbch[1] = 0;
15148 wch = 0;
15149 bad_wch = cpinfo.UnicodeDefaultChar;
15150 for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
15151 for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
15152 for (k = 128; k <= 255; k++)
15154 char str[2];
15155 WCHAR wstr[2];
15156 str[0] = j;
15157 str[1] = k;
15158 if (MultiByteToWideChar( cp, 0, str, 2, wstr, 2 ) == 1 &&
15159 WideCharToMultiByte( cp, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
15160 (BYTE)str[0] == j && (BYTE)str[1] == k &&
15161 HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
15163 dbch[0] = j;
15164 dbch[1] = k;
15165 wch = wstr[0];
15166 break;
15170 if (!wch)
15172 skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
15173 return;
15175 trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
15176 dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
15178 hwnd = CreateWindowExW(0, testWindowClassW, NULL,
15179 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
15180 hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
15181 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
15182 ok (hwnd != 0, "Failed to create overlapped window\n");
15183 ok (hwnd2 != 0, "Failed to create overlapped window\n");
15184 flush_events();
15185 flush_sequence();
15187 memset( wmCharSeq, 0, sizeof(wmCharSeq) );
15188 wmCharSeq[0].message = WM_CHAR;
15189 wmCharSeq[0].flags = sent|wparam;
15190 wmCharSeq[0].wParam = wch;
15192 /* posted message */
15193 PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
15194 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
15195 ok( !ret, "got message %x\n", msg.message );
15196 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
15197 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
15198 ok( ret, "no message\n" );
15199 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
15200 ok( msg.wParam == wch, "bad wparam %Ix/%x\n", msg.wParam, wch );
15201 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
15202 ok( !ret, "got message %x\n", msg.message );
15204 /* posted thread message */
15205 PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
15206 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
15207 ok( !ret, "got message %x\n", msg.message );
15208 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
15209 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
15210 ok( ret, "no message\n" );
15211 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
15212 ok( msg.wParam == wch, "bad wparam %Ix/%x\n", msg.wParam, wch );
15213 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
15214 ok( !ret, "got message %x\n", msg.message );
15216 /* sent message */
15217 flush_sequence();
15218 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
15219 ok_sequence( WmEmptySeq, "no messages", FALSE );
15220 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
15221 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
15222 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
15223 ok( !ret, "got message %x\n", msg.message );
15225 /* sent message with timeout */
15226 flush_sequence();
15227 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
15228 ok_sequence( WmEmptySeq, "no messages", FALSE );
15229 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
15230 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
15231 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
15232 ok( !ret, "got message %x\n", msg.message );
15234 /* sent message with timeout and callback */
15235 flush_sequence();
15236 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
15237 ok_sequence( WmEmptySeq, "no messages", FALSE );
15238 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
15239 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
15240 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
15241 ok( !ret, "got message %x\n", msg.message );
15243 /* sent message with callback */
15244 flush_sequence();
15245 SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
15246 ok_sequence( WmEmptySeq, "no messages", FALSE );
15247 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
15248 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
15249 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
15250 ok( !ret, "got message %x\n", msg.message );
15252 /* direct window proc call */
15253 flush_sequence();
15254 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
15255 ok_sequence( WmEmptySeq, "no messages", FALSE );
15256 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
15257 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
15259 /* dispatch message */
15260 msg.hwnd = hwnd;
15261 msg.message = WM_CHAR;
15262 msg.wParam = dbch[0];
15263 msg.lParam = 0;
15264 DispatchMessageA( &msg );
15265 ok_sequence( WmEmptySeq, "no messages", FALSE );
15266 msg.wParam = dbch[1];
15267 DispatchMessageA( &msg );
15268 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
15270 /* window handle is irrelevant */
15271 flush_sequence();
15272 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
15273 ok_sequence( WmEmptySeq, "no messages", FALSE );
15274 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
15275 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
15276 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
15277 ok( !ret, "got message %x\n", msg.message );
15279 /* interleaved post and send */
15280 flush_sequence();
15281 PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
15282 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
15283 ok_sequence( WmEmptySeq, "no messages", FALSE );
15284 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
15285 ok( !ret, "got message %x\n", msg.message );
15286 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
15287 ok_sequence( WmEmptySeq, "no messages", FALSE );
15288 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
15289 ok( ret, "no message\n" );
15290 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
15291 ok( msg.wParam == wch, "bad wparam %Ix/%x\n", msg.wParam, wch );
15292 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
15293 ok( !ret, "got message %x\n", msg.message );
15294 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
15295 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
15296 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
15297 ok( !ret, "got message %x\n", msg.message );
15299 /* interleaved sent message and winproc */
15300 flush_sequence();
15301 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
15302 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
15303 ok_sequence( WmEmptySeq, "no messages", FALSE );
15304 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
15305 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
15306 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
15307 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
15309 /* interleaved winproc and dispatch */
15310 msg.hwnd = hwnd;
15311 msg.message = WM_CHAR;
15312 msg.wParam = dbch[0];
15313 msg.lParam = 0;
15314 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
15315 DispatchMessageA( &msg );
15316 ok_sequence( WmEmptySeq, "no messages", FALSE );
15317 msg.wParam = dbch[1];
15318 DispatchMessageA( &msg );
15319 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
15320 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
15321 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
15323 /* interleaved sends */
15324 flush_sequence();
15325 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
15326 SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
15327 ok_sequence( WmEmptySeq, "no messages", FALSE );
15328 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
15329 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
15330 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
15331 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
15333 /* dbcs WM_CHAR */
15334 flush_sequence();
15335 SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
15336 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
15337 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
15338 ok( !ret, "got message %x\n", msg.message );
15340 /* other char messages are not magic */
15341 PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
15342 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
15343 ok( ret, "no message\n" );
15344 ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
15345 ok( msg.wParam == bad_wch, "bad wparam %Ix/%x\n", msg.wParam, bad_wch );
15346 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
15347 ok( !ret, "got message %x\n", msg.message );
15348 PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
15349 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
15350 ok( ret, "no message\n" );
15351 ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
15352 ok( msg.wParam == bad_wch, "bad wparam %Ix/%x\n", msg.wParam, bad_wch );
15353 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
15354 ok( !ret, "got message %x\n", msg.message );
15356 /* test retrieving messages */
15358 PostMessageW( hwnd, WM_CHAR, wch, 0 );
15359 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
15360 ok( ret, "no message\n" );
15361 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
15362 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
15363 ok( msg.wParam == dbch[0], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
15364 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
15365 ok( ret, "no message\n" );
15366 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
15367 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
15368 ok( msg.wParam == dbch[1], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
15369 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
15370 ok( !ret, "got message %x\n", msg.message );
15372 /* message filters */
15373 PostMessageW( hwnd, WM_CHAR, wch, 0 );
15374 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
15375 ok( ret, "no message\n" );
15376 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
15377 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
15378 ok( msg.wParam == dbch[0], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
15379 /* message id is filtered, hwnd is not */
15380 ret = PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE );
15381 ok( !ret, "no message\n" );
15382 ret = PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE );
15383 ok( ret, "no message\n" );
15384 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
15385 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
15386 ok( msg.wParam == dbch[1], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
15387 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
15388 ok( !ret, "got message %x\n", msg.message );
15390 /* mixing GetMessage and PostMessage */
15391 PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
15392 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
15393 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
15394 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
15395 ok( msg.wParam == dbch[0], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
15396 ok( msg.lParam == 0xbeef, "bad lparam %Ix\n", msg.lParam );
15397 time = msg.time;
15398 pt = msg.pt;
15399 ok( time - GetTickCount() <= 100, "bad time %lx\n", msg.time );
15400 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
15401 ok( ret, "no message\n" );
15402 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
15403 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
15404 ok( msg.wParam == dbch[1], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
15405 ok( msg.lParam == 0xbeef, "bad lparam %Ix\n", msg.lParam );
15406 ok( msg.time == time, "bad time %lx/%lx\n", msg.time, time );
15407 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 );
15408 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
15409 ok( !ret, "got message %x\n", msg.message );
15411 /* without PM_REMOVE */
15412 PostMessageW( hwnd, WM_CHAR, wch, 0 );
15413 ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
15414 ok( ret, "no message\n" );
15415 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
15416 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
15417 ok( msg.wParam == dbch[0], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
15418 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
15419 ok( ret, "no message\n" );
15420 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
15421 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
15422 ok( msg.wParam == dbch[0], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
15423 ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
15424 ok( ret, "no message\n" );
15425 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
15426 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
15427 ok( msg.wParam == dbch[1], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
15428 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
15429 ok( ret, "no message\n" );
15430 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
15431 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
15432 ok( msg.wParam == dbch[1], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
15433 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
15434 ok( !ret, "got message %x\n", msg.message );
15436 DestroyWindow(hwnd);
15437 DestroyWindow(hwnd2);
15440 static void test_unicode_wm_char(void)
15442 HWND hwnd;
15443 MSG msg;
15444 struct message seq[2];
15445 HKL hkl_orig, hkl_greek;
15446 DWORD cp;
15447 LCID thread_locale;
15449 hkl_orig = GetKeyboardLayout( 0 );
15450 GetLocaleInfoW( LOWORD( hkl_orig ), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, (WCHAR*)&cp, sizeof(cp) / sizeof(WCHAR) );
15451 if (cp != 1252)
15453 skip( "Default codepage %ld\n", cp );
15454 return;
15457 hkl_greek = LoadKeyboardLayoutA( "00000408", 0 );
15458 if (!hkl_greek || hkl_greek == hkl_orig /* win2k */)
15460 skip( "Unable to load Greek keyboard layout\n" );
15461 return;
15464 hwnd = CreateWindowExW( 0, testWindowClassW, NULL, WS_OVERLAPPEDWINDOW,
15465 100, 100, 200, 200, 0, 0, 0, NULL );
15466 flush_sequence();
15468 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
15470 while (GetMessageW( &msg, hwnd, 0, 0 ))
15472 if (!ignore_message( msg.message )) break;
15475 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
15476 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
15477 ok( msg.wParam == 0x3b1, "bad wparam %Ix\n", msg.wParam );
15478 ok( msg.lParam == 0, "bad lparam %Ix\n", msg.lParam );
15480 DispatchMessageW( &msg );
15482 memset( seq, 0, sizeof(seq) );
15483 seq[0].message = WM_CHAR;
15484 seq[0].flags = sent|wparam;
15485 seq[0].wParam = 0x3b1;
15487 ok_sequence( seq, "unicode WM_CHAR", FALSE );
15489 flush_sequence();
15491 /* greek alpha -> 'a' in cp1252 */
15492 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
15494 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
15495 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
15496 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
15497 ok( msg.wParam == 0x61, "bad wparam %Ix\n", msg.wParam );
15498 ok( msg.lParam == 0, "bad lparam %Ix\n", msg.lParam );
15500 DispatchMessageA( &msg );
15502 seq[0].wParam = 0x61;
15503 ok_sequence( seq, "unicode WM_CHAR", FALSE );
15505 thread_locale = GetThreadLocale();
15506 ActivateKeyboardLayout( hkl_greek, 0 );
15507 ok( GetThreadLocale() == thread_locale, "locale changed from %08lx to %08lx\n",
15508 thread_locale, GetThreadLocale() );
15510 flush_sequence();
15512 /* greek alpha -> 0xe1 in cp1253 */
15513 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
15515 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
15516 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
15517 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
15518 ok( msg.wParam == 0xe1, "bad wparam %Ix\n", msg.wParam );
15519 ok( msg.lParam == 0, "bad lparam %Ix\n", msg.lParam );
15521 DispatchMessageA( &msg );
15523 seq[0].wParam = 0x3b1;
15524 ok_sequence( seq, "unicode WM_CHAR", FALSE );
15526 DestroyWindow( hwnd );
15527 ActivateKeyboardLayout( hkl_orig, 0 );
15528 UnloadKeyboardLayout( hkl_greek );
15531 #define ID_LISTBOX 0x000f
15533 static const struct message wm_lb_setcursel_0[] =
15535 { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
15536 { WM_CTLCOLORLISTBOX, sent|parent },
15537 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
15538 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 1 },
15539 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 1 },
15540 { 0 }
15542 static const struct message wm_lb_setcursel_1[] =
15544 { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
15545 { WM_CTLCOLORLISTBOX, sent|parent },
15546 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
15547 { WM_CTLCOLORLISTBOX, sent|parent },
15548 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
15549 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 2 },
15550 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 2 },
15551 { 0 }
15553 static const struct message wm_lb_setcursel_2[] =
15555 { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
15556 { WM_CTLCOLORLISTBOX, sent|parent },
15557 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
15558 { WM_CTLCOLORLISTBOX, sent|parent },
15559 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
15560 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 3 },
15561 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 3 },
15562 { 0 }
15564 static const struct message wm_lb_click_0[] =
15566 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
15567 { HCBT_SETFOCUS, hook },
15568 { WM_KILLFOCUS, sent|parent },
15569 { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
15570 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
15571 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
15572 { WM_SETFOCUS, sent|defwinproc },
15574 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
15575 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
15576 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 3 },
15577 { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
15578 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15580 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
15581 { WM_CTLCOLORLISTBOX, sent|parent },
15582 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
15583 { WM_CTLCOLORLISTBOX, sent|parent },
15584 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
15585 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
15587 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 1 },
15588 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 1 },
15590 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
15591 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15592 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
15593 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
15594 { 0 }
15596 static const struct message wm_lb_deletestring[] =
15598 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
15599 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 1 },
15600 { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
15601 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
15602 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
15603 { 0 }
15605 static const struct message wm_lb_deletestring_reset[] =
15607 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
15608 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 1 },
15609 { LB_RESETCONTENT, sent|wparam|lparam|defwinproc|optional, 0, 0 },
15610 { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
15611 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
15612 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
15613 { 0 }
15615 static const struct message wm_lb_addstring[] =
15617 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
15618 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 1 },
15619 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
15620 /* Child ID changes each test, don't test lparam. */
15621 { EVENT_OBJECT_CREATE, winevent_hook|wparam|winevent_hook_todo, OBJID_CLIENT, 0 },
15622 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
15623 { EVENT_OBJECT_CREATE, winevent_hook|wparam|winevent_hook_todo, OBJID_CLIENT, 0 },
15624 { 0 }
15626 static const struct message wm_lb_addstring_ownerdraw[] =
15628 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
15629 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf0f2, 0xf30604ed },
15630 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 1 },
15631 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
15632 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf1f2, 0xf30604ee },
15633 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 2 },
15634 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
15635 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf2f2, 0xf30604ef },
15636 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 3 },
15637 { 0 }
15639 static const struct message wm_lb_addstring_sort_ownerdraw[] =
15641 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
15642 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf0f2, 0xf30604ed },
15643 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 1 },
15644 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
15645 { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ed, 0xf30604ee },
15646 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf1f2, 0xf30604ee },
15647 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 2 },
15648 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
15649 { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ed, 0xf30604ef },
15650 { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ee, 0xf30604ef },
15651 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf2f2, 0xf30604ef },
15652 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 3 },
15653 { 0 }
15656 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
15658 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
15660 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
15662 static LONG defwndproc_counter = 0;
15663 LRESULT ret;
15664 struct recvd_message msg;
15666 /* do not log painting messages */
15667 if (message != WM_PAINT &&
15668 message != WM_NCPAINT &&
15669 message != WM_SYNCPAINT &&
15670 message != WM_ERASEBKGND &&
15671 message != WM_NCHITTEST &&
15672 message != WM_GETTEXT &&
15673 !ignore_message( message ))
15675 msg.hwnd = hwnd;
15676 msg.message = message;
15677 msg.flags = sent|wparam|lparam;
15678 if (defwndproc_counter) msg.flags |= defwinproc;
15679 msg.wParam = wp;
15680 if (message == LB_ADDSTRING)
15681 msg.lParam = lp ? hash_Ly((const char *)lp) : 0;
15682 else
15683 msg.lParam = lp;
15684 msg.descr = "listbox";
15685 add_message(&msg);
15688 defwndproc_counter++;
15689 ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
15690 defwndproc_counter--;
15692 return ret;
15695 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
15696 int caret_index, int top_index, int line)
15698 LRESULT ret;
15700 /* calling an orig proc helps to avoid unnecessary message logging */
15701 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
15702 ok_(__FILE__, line)(ret == count, "expected count %d, got %Id\n", count, ret);
15703 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
15704 ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %Id\n", cur_sel, ret);
15705 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
15706 ok_(__FILE__, line)(ret == caret_index ||
15707 broken(cur_sel == -1 && caret_index == 0 && ret == -1), /* nt4 */
15708 "expected caret index %d, got %Id\n", caret_index, ret);
15709 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
15710 ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %Id\n", top_index, ret);
15713 static void test_listbox_messages(void)
15715 HWND parent, listbox;
15716 LRESULT ret;
15718 parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
15719 100, 100, 200, 200, 0, 0, 0, NULL);
15720 /* with LBS_HASSTRINGS */
15721 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
15722 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
15723 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
15724 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
15726 check_lb_state(listbox, 0, LB_ERR, 0, 0);
15728 flush_sequence();
15730 log_all_parent_messages++;
15732 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
15733 ok(ret == 0, "expected 0, got %Id\n", ret);
15734 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
15735 ok(ret == 1, "expected 1, got %Id\n", ret);
15736 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
15737 ok(ret == 2, "expected 2, got %Id\n", ret);
15739 ok_sequence(wm_lb_addstring_ownerdraw, "LB_ADDSTRING", FALSE);
15740 check_lb_state(listbox, 3, LB_ERR, 0, 0);
15742 flush_sequence();
15744 trace("selecting item 0\n");
15745 ret = SendMessageA(listbox, LB_SETCURSEL, 0, 0);
15746 ok(ret == 0, "expected 0, got %Id\n", ret);
15747 ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
15748 check_lb_state(listbox, 3, 0, 0, 0);
15749 flush_sequence();
15751 trace("selecting item 1\n");
15752 ret = SendMessageA(listbox, LB_SETCURSEL, 1, 0);
15753 ok(ret == 1, "expected 1, got %Id\n", ret);
15754 ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
15755 check_lb_state(listbox, 3, 1, 1, 0);
15757 trace("selecting item 2\n");
15758 ret = SendMessageA(listbox, LB_SETCURSEL, 2, 0);
15759 ok(ret == 2, "expected 2, got %Id\n", ret);
15760 ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
15761 check_lb_state(listbox, 3, 2, 2, 0);
15763 trace("clicking on item 0\n");
15764 ret = SendMessageA(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
15765 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
15766 ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0);
15767 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
15768 ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
15769 check_lb_state(listbox, 3, 0, 0, 0);
15770 flush_sequence();
15772 trace("deleting item 0\n");
15773 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
15774 ok(ret == 2, "expected 2, got %Id\n", ret);
15775 ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
15776 check_lb_state(listbox, 2, -1, 0, 0);
15777 flush_sequence();
15779 trace("deleting item 0\n");
15780 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
15781 ok(ret == 1, "expected 1, got %Id\n", ret);
15782 ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
15783 check_lb_state(listbox, 1, -1, 0, 0);
15784 flush_sequence();
15786 trace("deleting item 0\n");
15787 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
15788 ok(ret == 0, "expected 0, got %Id\n", ret);
15789 ok_sequence(wm_lb_deletestring_reset, "LB_DELETESTRING 0", FALSE );
15790 check_lb_state(listbox, 0, -1, 0, 0);
15791 flush_sequence();
15793 trace("deleting item 0\n");
15794 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
15795 ok(ret == LB_ERR, "expected LB_ERR, got %Id\n", ret);
15796 check_lb_state(listbox, 0, -1, 0, 0);
15797 flush_sequence();
15799 log_all_parent_messages--;
15801 DestroyWindow(listbox);
15803 /* with LBS_SORT and without LBS_HASSTRINGS */
15804 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
15805 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_SORT | WS_VISIBLE,
15806 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
15807 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
15809 check_lb_state(listbox, 0, LB_ERR, 0, 0);
15811 flush_sequence();
15813 log_all_parent_messages++;
15815 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
15816 ok(ret == 0, "expected 0, got %Id\n", ret);
15817 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
15818 ok(ret == 1, "expected 1, got %Id\n", ret);
15819 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
15820 ok(ret == 2, "expected 2, got %Id\n", ret);
15822 ok_sequence(wm_lb_addstring_sort_ownerdraw, "LB_ADDSTRING", FALSE);
15823 check_lb_state(listbox, 3, LB_ERR, 0, 0);
15825 log_all_parent_messages--;
15827 DestroyWindow(listbox);
15829 /* with LBS_HASSTRINGS */
15830 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
15831 WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | WS_VISIBLE,
15832 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
15833 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
15835 check_lb_state(listbox, 0, LB_ERR, 0, 0);
15837 flush_sequence();
15839 log_all_parent_messages++;
15841 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
15842 ok(ret == 0, "expected 0, got %Id\n", ret);
15843 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
15844 ok(ret == 1, "expected 1, got %Id\n", ret);
15845 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
15846 ok(ret == 2, "expected 2, got %Id\n", ret);
15848 ok_sequence(wm_lb_addstring, "LB_ADDSTRING", FALSE);
15849 check_lb_state(listbox, 3, LB_ERR, 0, 0);
15851 log_all_parent_messages--;
15853 DestroyWindow(listbox);
15855 /* with LBS_HASSTRINGS and LBS_SORT */
15856 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
15857 WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | LBS_SORT | WS_VISIBLE,
15858 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
15859 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
15861 check_lb_state(listbox, 0, LB_ERR, 0, 0);
15863 flush_sequence();
15865 log_all_parent_messages++;
15867 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
15868 ok(ret == 0, "expected 0, got %Id\n", ret);
15869 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
15870 ok(ret == 0, "expected 0, got %Id\n", ret);
15871 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
15872 ok(ret == 1, "expected 1, got %Id\n", ret);
15874 ok_sequence(wm_lb_addstring, "LB_ADDSTRING", FALSE);
15875 check_lb_state(listbox, 3, LB_ERR, 0, 0);
15877 log_all_parent_messages--;
15879 DestroyWindow(listbox);
15880 DestroyWindow(parent);
15883 /*************************** Menu test ******************************/
15884 static const struct message wm_popup_menu_1[] =
15886 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
15887 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
15888 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
15889 { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
15890 { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
15891 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
15892 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
15893 { WM_INITMENU, sent|lparam, 0, 0 },
15894 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
15895 { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
15896 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
15897 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15898 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15899 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15900 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15901 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
15902 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
15903 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 1 },
15904 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
15905 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
15906 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001, 0, 0x40000000 },
15907 { EVENT_OBJECT_INVOKED, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_MENU, 0 },
15908 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
15909 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
15910 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15911 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15912 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
15913 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
15914 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
15915 { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
15916 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
15917 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
15918 { 0 }
15920 static const struct message wm_popup_menu_2[] =
15922 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
15923 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
15924 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
15925 { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
15926 { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
15927 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
15928 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
15929 { WM_INITMENU, sent|lparam, 0, 0 },
15930 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
15931 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
15932 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
15933 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
15934 { HCBT_CREATEWND, hook },
15935 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15936 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15937 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15938 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15939 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
15940 { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
15941 |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
15942 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 1 },
15943 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
15944 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
15945 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
15946 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
15947 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
15948 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15949 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15950 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15951 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15952 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
15953 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
15954 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 1 },
15955 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
15956 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
15957 { EVENT_OBJECT_INVOKED, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_MENU, 0 },
15958 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
15959 { HCBT_DESTROYWND, hook },
15960 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15961 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15962 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
15963 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
15964 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
15965 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15966 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15967 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
15968 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
15969 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
15970 { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
15971 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
15972 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
15973 { 0 }
15975 static const struct message wm_popup_menu_3[] =
15977 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
15978 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
15979 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
15980 { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
15981 { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
15982 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
15983 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
15984 { WM_INITMENU, sent|lparam, 0, 0 },
15985 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
15986 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
15987 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
15988 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
15989 { HCBT_CREATEWND, hook },
15990 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15991 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15992 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15993 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15994 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
15995 { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
15996 |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
15997 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 1 },
15998 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
15999 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
16000 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
16001 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
16002 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
16003 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
16004 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
16005 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
16006 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
16007 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
16008 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
16009 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 1 },
16010 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
16011 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
16012 { EVENT_OBJECT_INVOKED, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_MENU, 100 },
16013 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
16014 { HCBT_DESTROYWND, hook },
16015 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
16016 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
16017 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
16018 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
16019 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
16020 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
16021 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
16022 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
16023 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
16024 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
16025 { WM_COMMAND, sent|wparam|lparam, 100, 0 },
16026 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
16027 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
16028 { 0 }
16031 static const struct message wm_single_menu_item[] =
16033 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
16034 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
16035 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0x20000001 },
16036 { WM_SYSKEYDOWN, sent|wparam|lparam, 'Q', 0x20000001 },
16037 { WM_SYSCHAR, sent|wparam|lparam, 'q', 0x20000001 },
16038 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'q' },
16039 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
16040 { WM_INITMENU, sent|lparam, 0, 0 },
16041 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(300,MF_HILITE) },
16042 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
16043 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
16044 { WM_MENUCOMMAND, sent },
16045 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0xe0000001 },
16046 { WM_SYSKEYUP, sent|wparam|lparam, 'Q', 0xe0000001 },
16047 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 },
16048 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
16050 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 1 },
16051 { WM_KEYDOWN, sent|wparam|lparam, VK_ESCAPE, 1 },
16052 { WM_CHAR, sent|wparam|lparam, VK_ESCAPE, 0x00000001 },
16053 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 },
16054 { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
16055 { 0 }
16058 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
16060 if (message == WM_ENTERIDLE ||
16061 message == WM_INITMENU ||
16062 message == WM_INITMENUPOPUP ||
16063 message == WM_MENUSELECT ||
16064 message == WM_PARENTNOTIFY ||
16065 message == WM_ENTERMENULOOP ||
16066 message == WM_EXITMENULOOP ||
16067 message == WM_UNINITMENUPOPUP ||
16068 message == WM_KEYDOWN ||
16069 message == WM_KEYUP ||
16070 message == WM_CHAR ||
16071 message == WM_SYSKEYDOWN ||
16072 message == WM_SYSKEYUP ||
16073 message == WM_SYSCHAR ||
16074 message == WM_COMMAND ||
16075 message == WM_MENUCOMMAND)
16077 struct recvd_message msg;
16079 msg.hwnd = hwnd;
16080 msg.message = message;
16081 msg.flags = sent|wparam|lparam;
16082 msg.wParam = wp;
16083 msg.lParam = lp;
16084 msg.descr = "parent_menu_proc";
16085 add_message(&msg);
16088 return DefWindowProcA(hwnd, message, wp, lp);
16091 static void set_menu_style(HMENU hmenu, DWORD style)
16093 MENUINFO mi;
16094 BOOL ret;
16096 mi.cbSize = sizeof(mi);
16097 mi.fMask = MIM_STYLE;
16098 mi.dwStyle = style;
16099 SetLastError(0xdeadbeef);
16100 ret = SetMenuInfo(hmenu, &mi);
16101 ok(ret, "SetMenuInfo error %lu\n", GetLastError());
16104 static DWORD get_menu_style(HMENU hmenu)
16106 MENUINFO mi;
16107 BOOL ret;
16109 mi.cbSize = sizeof(mi);
16110 mi.fMask = MIM_STYLE;
16111 mi.dwStyle = 0;
16112 SetLastError(0xdeadbeef);
16113 ret = GetMenuInfo(hmenu, &mi);
16114 ok(ret, "GetMenuInfo error %lu\n", GetLastError());
16116 return mi.dwStyle;
16119 static void test_menu_messages(void)
16121 MSG msg;
16122 WNDCLASSA cls;
16123 HMENU hmenu, hmenu_popup;
16124 HWND hwnd;
16125 DWORD style;
16126 BOOL us_kbd = (GetKeyboardLayout(0) == (HKL)(ULONG_PTR)0x04090409);
16128 cls.style = 0;
16129 cls.lpfnWndProc = parent_menu_proc;
16130 cls.cbClsExtra = 0;
16131 cls.cbWndExtra = 0;
16132 cls.hInstance = GetModuleHandleA(0);
16133 cls.hIcon = 0;
16134 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
16135 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
16136 cls.lpszMenuName = NULL;
16137 cls.lpszClassName = "TestMenuClass";
16138 UnregisterClassA(cls.lpszClassName, cls.hInstance);
16139 if (!RegisterClassA(&cls)) assert(0);
16141 SetLastError(0xdeadbeef);
16142 hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
16143 100, 100, 200, 200, 0, 0, 0, NULL);
16144 ok(hwnd != 0, "LoadMenuA error %lu\n", GetLastError());
16146 SetLastError(0xdeadbeef);
16147 hmenu = LoadMenuA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
16148 ok(hmenu != 0, "LoadMenuA error %lu\n", GetLastError());
16150 SetMenu(hwnd, hmenu);
16151 SetForegroundWindow( hwnd );
16152 flush_events();
16154 set_menu_style(hmenu, MNS_NOTIFYBYPOS);
16155 style = get_menu_style(hmenu);
16156 ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %lu\n", style);
16158 hmenu_popup = GetSubMenu(hmenu, 0);
16159 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
16160 style = get_menu_style(hmenu_popup);
16161 ok(style == 0, "expected 0, got %lu\n", style);
16163 hmenu_popup = GetSubMenu(hmenu_popup, 0);
16164 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
16165 style = get_menu_style(hmenu_popup);
16166 ok(style == 0, "expected 0, got %lu\n", style);
16168 if (!us_kbd)
16170 skip("skipping ascii VK events on non-us keyboard\n");
16171 goto done;
16174 /* Alt+E, Enter */
16175 trace("testing a popup menu command\n");
16176 flush_sequence();
16177 keybd_event(VK_MENU, 0, 0, 0);
16178 keybd_event('E', 0, 0, 0);
16179 keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
16180 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
16181 keybd_event(VK_RETURN, 0, 0, 0);
16182 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
16183 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
16185 TranslateMessage(&msg);
16186 DispatchMessageA(&msg);
16188 if (!sequence_cnt) /* we didn't get any message */
16190 skip( "queuing key events not supported\n" );
16191 goto done;
16193 /* win98 queues only a WM_KEYUP and doesn't start menu tracking */
16194 if (sequence[0].message == WM_KEYUP && sequence[0].wParam == VK_MENU)
16196 win_skip( "menu tracking through VK_MENU not supported\n" );
16197 goto done;
16199 ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
16201 /* Alt+F, Right, Enter */
16202 trace("testing submenu of a popup menu command\n");
16203 flush_sequence();
16204 keybd_event(VK_MENU, 0, 0, 0);
16205 keybd_event('F', 0, 0, 0);
16206 keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
16207 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
16208 keybd_event(VK_RIGHT, 0, 0, 0);
16209 keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
16210 keybd_event(VK_RETURN, 0, 0, 0);
16211 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
16212 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
16214 TranslateMessage(&msg);
16215 DispatchMessageA(&msg);
16217 ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
16219 trace("testing single menu item command\n");
16220 flush_sequence();
16221 keybd_event(VK_MENU, 0, 0, 0);
16222 keybd_event('Q', 0, 0, 0);
16223 keybd_event('Q', 0, KEYEVENTF_KEYUP, 0);
16224 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
16225 keybd_event(VK_ESCAPE, 0, 0, 0);
16226 keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
16227 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
16229 TranslateMessage(&msg);
16230 DispatchMessageA(&msg);
16232 ok_sequence(wm_single_menu_item, "single menu item command", FALSE);
16234 set_menu_style(hmenu, 0);
16235 style = get_menu_style(hmenu);
16236 ok(style == 0, "expected 0, got %lu\n", style);
16238 hmenu_popup = GetSubMenu(hmenu, 0);
16239 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
16240 set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
16241 style = get_menu_style(hmenu_popup);
16242 ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %lu\n", style);
16244 hmenu_popup = GetSubMenu(hmenu_popup, 0);
16245 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
16246 style = get_menu_style(hmenu_popup);
16247 ok(style == 0, "expected 0, got %lu\n", style);
16249 /* Alt+F, Right, Enter */
16250 trace("testing submenu of a popup menu command\n");
16251 flush_sequence();
16252 keybd_event(VK_MENU, 0, 0, 0);
16253 keybd_event('F', 0, 0, 0);
16254 keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
16255 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
16256 keybd_event(VK_RIGHT, 0, 0, 0);
16257 keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
16258 keybd_event(VK_RETURN, 0, 0, 0);
16259 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
16260 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
16262 TranslateMessage(&msg);
16263 DispatchMessageA(&msg);
16265 ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
16267 done:
16268 DestroyWindow(hwnd);
16269 DestroyMenu(hmenu);
16273 static void test_paintingloop(void)
16275 HWND hwnd;
16277 paint_loop_done = FALSE;
16278 hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
16279 "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
16280 100, 100, 100, 100, 0, 0, 0, NULL );
16281 ok(hwnd != 0, "PaintLoop window error %lu\n", GetLastError());
16282 ShowWindow(hwnd,SW_NORMAL);
16283 SetFocus(hwnd);
16285 while (!paint_loop_done)
16287 MSG msg;
16288 if (PeekMessageA(&msg, 0, 0, 0, 1))
16290 TranslateMessage(&msg);
16291 DispatchMessageA(&msg);
16294 DestroyWindow(hwnd);
16297 static const struct message NCRBUTTONDOWNSeq[] =
16299 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
16300 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
16301 { WM_CAPTURECHANGED, sent },
16302 { WM_CONTEXTMENU, sent, /*hwnd*/0, -1 },
16303 { 0 }
16306 static const struct message NCXBUTTONUPSeq1[] =
16308 { WM_APPCOMMAND, sent|lparam, /*hwnd*/0, MAKELPARAM(0, FAPPCOMMAND_MOUSE | APPCOMMAND_BROWSER_BACKWARD) },
16309 { 0 }
16312 static const struct message NCXBUTTONUPSeq2[] =
16314 { WM_APPCOMMAND, sent|lparam, /*hwnd*/0, MAKELPARAM(0, FAPPCOMMAND_MOUSE | APPCOMMAND_BROWSER_FORWARD) },
16315 { 0 }
16318 /* DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0) to minimized visible window */
16319 static const struct message WmRestoreMinimizedOverlappedSeq[] =
16321 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_RESTORE, 0 },
16322 { HCBT_MINMAX, hook },
16323 { WM_QUERYOPEN, sent },
16324 { WM_GETTEXT, sent|optional },
16325 { WM_NCACTIVATE, sent|optional },
16326 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
16327 { WM_WINDOWPOSCHANGED, sent|optional },
16328 { WM_WINDOWPOSCHANGING, sent|optional },
16329 { WM_GETMINMAXINFO, sent|defwinproc },
16330 { WM_NCCALCSIZE, sent|optional },
16331 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
16332 { WM_NCPAINT, sent|optional },
16333 { WM_GETTEXT, sent|defwinproc|optional },
16334 { WM_ERASEBKGND, sent|optional },
16335 { WM_WINDOWPOSCHANGED, sent|optional },
16336 { HCBT_ACTIVATE, hook },
16337 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
16338 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
16339 { WM_ACTIVATEAPP, sent|wparam, TRUE },
16340 { WM_NCACTIVATE, sent|wparam, TRUE },
16341 { WM_GETTEXT, sent|defwinproc|optional },
16342 { WM_ACTIVATE, sent|wparam, TRUE },
16343 { HCBT_SETFOCUS, hook },
16344 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
16345 { WM_SETFOCUS, sent|defwinproc },
16346 { WM_NCPAINT, sent },
16347 { WM_GETTEXT, sent|defwinproc|optional },
16348 { WM_ERASEBKGND, sent },
16349 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_FRAMECHANGED|SWP_STATECHANGED },
16350 { WM_MOVE, sent|defwinproc },
16351 { WM_SIZE, sent|defwinproc },
16352 { WM_NCCALCSIZE, sent|optional },
16353 { WM_NCPAINT, sent|optional },
16354 { WM_ERASEBKGND, sent|optional },
16355 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
16356 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
16357 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
16358 { WM_ACTIVATE, sent|wparam, TRUE },
16359 { WM_SYNCPAINT, sent|optional },
16360 { WM_PAINT, sent },
16361 { 0 }
16364 /* DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0) to an active minimized window */
16365 static const struct message WmRestoreActiveMinimizedOverlappedSeq[] =
16367 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_RESTORE, 0 },
16368 { HCBT_MINMAX, hook },
16369 { WM_QUERYOPEN, sent },
16370 { WM_GETTEXT, sent|optional },
16371 { WM_NCACTIVATE, sent },
16372 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
16373 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
16374 { WM_NCCALCSIZE, sent|optional },
16375 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sent on Win7. */
16376 { WM_MOVE, sent|optional },
16377 { WM_SIZE, sent|optional },
16378 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sent on Win7. */
16379 { WM_GETTEXT, sent|optional },
16380 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
16381 { WM_GETMINMAXINFO, sent|defwinproc },
16382 { WM_NCCALCSIZE, sent },
16383 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sent on Win8+. */
16384 { WM_NCPAINT, sent },
16385 { WM_GETTEXT, sent|defwinproc|optional },
16386 { WM_ERASEBKGND, sent },
16387 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
16388 { WM_MOVE, sent|defwinproc },
16389 { WM_SIZE, sent|defwinproc },
16390 { WM_NCCALCSIZE, sent|optional },
16391 { WM_NCPAINT, sent|optional },
16392 { WM_ERASEBKGND, sent|optional },
16393 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
16394 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
16395 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
16396 { HCBT_SETFOCUS, hook },
16397 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
16398 { WM_SETFOCUS, sent },
16399 /* Note this WM_ACTIVATE messages even if the window is already active */
16400 { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, 0 },
16401 { WM_SYNCPAINT, sent|optional },
16402 { WM_PAINT, sent },
16403 { WM_GETMINMAXINFO, sent|optional },
16404 { 0 }
16407 static struct message WmContextMenuSeq[] = {
16408 { WM_CONTEXTMENU, sent|wparam, 0 }, /* wparams set in the code */
16409 { WM_CONTEXTMENU, sent|wparam|defwinproc, 0 },
16410 { WM_CONTEXTMENU, sent|wparam|defwinproc, 0 },
16411 { 0 }
16414 struct rbuttonup_thread_data
16416 HWND hwnd;
16417 HANDLE wndproc_finished;
16420 static DWORD CALLBACK post_rbuttonup_msg( void *arg )
16422 struct rbuttonup_thread_data *data = arg;
16423 DWORD ret;
16425 ret = WaitForSingleObject( data->wndproc_finished, 500 );
16426 todo_wine ok( ret == WAIT_OBJECT_0, "WaitForSingleObject returned %lx\n", ret );
16427 if( ret == WAIT_OBJECT_0 ) return 0;
16429 PostMessageA( data->hwnd, WM_RBUTTONUP, 0, 0 );
16430 return 0;
16433 static void test_defwinproc(void)
16435 HWND hwnd, child[3];
16436 MSG msg;
16437 BOOL gotwmquit = FALSE;
16438 POINT pos;
16439 RECT rect;
16440 INT x, y;
16441 LRESULT res;
16442 struct rbuttonup_thread_data data;
16443 char buffA[64];
16444 HANDLE thread;
16446 hwnd = CreateWindowExA(0, "TestWindowClass", "test_defwndproc",
16447 WS_VISIBLE | WS_CAPTION | WS_OVERLAPPEDWINDOW, 0,0,500,100,0,0,0, NULL);
16448 assert(hwnd);
16449 flush_events();
16451 buffA[0] = 0;
16452 GetWindowTextA(hwnd, buffA, ARRAY_SIZE(buffA));
16453 ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
16455 /* Zero high word of the lParam */
16456 res = DefWindowProcA(hwnd, WM_SETTEXT, 0, 0x1234);
16457 ok(res == 0, "WM_SETTEXT was expected to fail, %Id\n", res);
16459 GetWindowTextA(hwnd, buffA, ARRAY_SIZE(buffA));
16460 ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
16462 res = DefWindowProcW(hwnd, WM_SETTEXT, 0, 0x1234);
16463 ok(res == 0, "WM_SETTEXT was expected to fail, %Id\n", res);
16465 GetWindowTextA(hwnd, buffA, ARRAY_SIZE(buffA));
16466 ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
16468 ShowWindow(hwnd, SW_MINIMIZE);
16469 flush_events();
16470 flush_sequence();
16472 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
16473 flush_events();
16474 ok_sequence(WmRestoreMinimizedOverlappedSeq, "DefWindowProcA(SC_RESTORE):overlapped", TRUE);
16476 ShowWindow(hwnd, SW_MINIMIZE);
16477 SetActiveWindow(hwnd);
16478 ok(GetActiveWindow() == hwnd, "Unexpected active window\n");
16479 flush_events();
16480 flush_sequence();
16481 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
16482 flush_events();
16483 ok_sequence(WmRestoreActiveMinimizedOverlappedSeq, "DefWindowProcA(SC_RESTORE):active minimized overlapped", TRUE);
16485 child[0] = CreateWindowExA(0, "TestWindowClass", "1st child",
16486 WS_VISIBLE | WS_CHILD, 0,0,500,100, hwnd, 0, 0, NULL);
16487 child[1] = CreateWindowExA(0, "TestWindowClass", "2nd child",
16488 WS_VISIBLE | WS_CHILD, 0,0,500,100, child[0], 0, 0, NULL);
16489 child[2] = CreateWindowExA(0, "TestWindowClass", "3rd child",
16490 WS_VISIBLE | WS_CHILD, 0,0,500,100, child[1], 0, 0, NULL);
16491 flush_events();
16492 flush_sequence();
16493 test_context_menu = TRUE;
16494 DefWindowProcA(child[2], WM_CONTEXTMENU, 0xcafe, 0);
16495 test_context_menu = FALSE;
16496 WmContextMenuSeq[0].wParam = (WPARAM)child[2];
16497 WmContextMenuSeq[1].wParam = (WPARAM)child[1];
16498 WmContextMenuSeq[2].wParam = (WPARAM)child[0];
16499 ok_sequence(WmContextMenuSeq, "DefWindowProcA(WM_CONTEXTMENU)", FALSE);
16500 DestroyWindow(child[0]);
16502 GetCursorPos(&pos);
16503 GetWindowRect(hwnd, &rect);
16504 x = (rect.left+rect.right) / 2;
16505 y = rect.top + GetSystemMetrics(SM_CYFRAME) + 1;
16506 SetCursorPos(x, y);
16507 flush_events();
16508 res = DefWindowProcA( hwnd, WM_NCHITTEST, 0, MAKELPARAM(x, y));
16509 ok(res == HTCAPTION, "WM_NCHITTEST returned %Id\n", res);
16511 mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 );
16512 mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 );
16513 flush_events();
16515 flush_sequence();
16516 mouse_event( MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0 );
16517 /* workaround for missing support for clicking on window frame */
16518 data.hwnd = hwnd;
16519 data.wndproc_finished = CreateEventA( NULL, FALSE, FALSE, NULL );
16520 thread = CreateThread( NULL, 0, post_rbuttonup_msg, (void*)&data, 0, NULL );
16522 DefWindowProcA( hwnd, WM_NCRBUTTONDOWN, HTCAPTION, MAKELPARAM(x, y));
16523 ok_sequence(NCRBUTTONDOWNSeq, "WM_NCRBUTTONDOWN on caption", FALSE);
16525 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, 0, MAKELPARAM(x, y));
16526 ok(!res, "WM_NCXBUTTONUP returned %Id\n", res);
16527 ok_sequence(WmEmptySeq, "WM_NCXBUTTONUP without button", FALSE);
16529 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, XBUTTON1), MAKELPARAM(x, y));
16530 ok(!res, "WM_NCXBUTTONUP returned %Id\n", res);
16531 ok_sequence(NCXBUTTONUPSeq1, "WM_NCXBUTTONUP with XBUTTON1", FALSE);
16533 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, XBUTTON2), MAKELPARAM(x, y));
16534 ok(!res, "WM_NCXBUTTONUP returned %Id\n", res);
16535 ok_sequence(NCXBUTTONUPSeq2, "WM_NCXBUTTONUP with XBUTTON2", FALSE);
16537 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, 3), MAKELPARAM(x, y));
16538 ok(!res, "WM_NCXBUTTONUP returned %Id\n", res);
16539 ok_sequence(WmEmptySeq, "WM_NCXBUTTONUP with invalid button", FALSE);
16541 /* Test WM_MOUSEACTIVATE */
16542 #define TEST_MOUSEACTIVATE(A,B,C) \
16543 res = DefWindowProcA(hwnd, WM_MOUSEACTIVATE, (WPARAM)hwnd, (LPARAM)MAKELRESULT(A,0)); \
16544 ok(res == B, "WM_MOUSEACTIVATE for %s returned %Id\n", #A, res); \
16545 res = DefWindowProcA(hwnd, WM_MOUSEACTIVATE, (WPARAM)hwnd, (LPARAM)MAKELRESULT(A,WM_LBUTTONDOWN)); \
16546 ok(res == C, "WM_MOUSEACTIVATE for %s returned %Id\n", #A, res);
16548 TEST_MOUSEACTIVATE(HTERROR, MA_ACTIVATE, MA_ACTIVATE);
16549 TEST_MOUSEACTIVATE(HTTRANSPARENT, MA_ACTIVATE, MA_ACTIVATE);
16550 TEST_MOUSEACTIVATE(HTNOWHERE, MA_ACTIVATE, MA_ACTIVATE);
16551 TEST_MOUSEACTIVATE(HTCLIENT, MA_ACTIVATE, MA_ACTIVATE);
16552 TEST_MOUSEACTIVATE(HTCAPTION, MA_ACTIVATE, MA_NOACTIVATE);
16553 TEST_MOUSEACTIVATE(HTSYSMENU, MA_ACTIVATE, MA_ACTIVATE);
16554 TEST_MOUSEACTIVATE(HTSIZE, MA_ACTIVATE, MA_ACTIVATE);
16555 TEST_MOUSEACTIVATE(HTMENU, MA_ACTIVATE, MA_ACTIVATE);
16556 TEST_MOUSEACTIVATE(HTHSCROLL, MA_ACTIVATE, MA_ACTIVATE);
16557 TEST_MOUSEACTIVATE(HTVSCROLL, MA_ACTIVATE, MA_ACTIVATE);
16558 TEST_MOUSEACTIVATE(HTMINBUTTON, MA_ACTIVATE, MA_ACTIVATE);
16559 TEST_MOUSEACTIVATE(HTMAXBUTTON, MA_ACTIVATE, MA_ACTIVATE);
16560 TEST_MOUSEACTIVATE(HTLEFT, MA_ACTIVATE, MA_ACTIVATE);
16561 TEST_MOUSEACTIVATE(HTRIGHT, MA_ACTIVATE, MA_ACTIVATE);
16562 TEST_MOUSEACTIVATE(HTTOP, MA_ACTIVATE, MA_ACTIVATE);
16563 TEST_MOUSEACTIVATE(HTTOPLEFT, MA_ACTIVATE, MA_ACTIVATE);
16564 TEST_MOUSEACTIVATE(HTTOPRIGHT, MA_ACTIVATE, MA_ACTIVATE);
16565 TEST_MOUSEACTIVATE(HTBOTTOM, MA_ACTIVATE, MA_ACTIVATE);
16566 TEST_MOUSEACTIVATE(HTBOTTOMLEFT, MA_ACTIVATE, MA_ACTIVATE);
16567 TEST_MOUSEACTIVATE(HTBOTTOMRIGHT, MA_ACTIVATE, MA_ACTIVATE);
16568 TEST_MOUSEACTIVATE(HTBORDER, MA_ACTIVATE, MA_ACTIVATE);
16569 TEST_MOUSEACTIVATE(HTOBJECT, MA_ACTIVATE, MA_ACTIVATE);
16570 TEST_MOUSEACTIVATE(HTCLOSE, MA_ACTIVATE, MA_ACTIVATE);
16571 TEST_MOUSEACTIVATE(HTHELP, MA_ACTIVATE, MA_ACTIVATE);
16573 SetEvent( data.wndproc_finished );
16574 WaitForSingleObject( thread, 1000 );
16575 CloseHandle( data.wndproc_finished );
16576 CloseHandle( thread );
16578 SetCursorPos(pos.x, pos.y);
16580 DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0);
16581 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) {
16582 if( msg.message == WM_QUIT) gotwmquit = TRUE;
16583 DispatchMessageA( &msg );
16585 ok(!gotwmquit, "Unexpected WM_QUIT message!\n");
16586 DestroyWindow( hwnd);
16589 static void test_desktop_winproc(void)
16591 HINSTANCE instance = GetModuleHandleA(NULL);
16592 RECT rect, default_rect;
16593 WNDPROC desktop_proc;
16594 char buffer[256];
16595 WNDCLASSA cls;
16596 LRESULT res;
16597 HWND hwnd;
16598 BOOL ret;
16600 ret = GetClassInfoA(instance, (const CHAR *)MAKEINTATOM(32769), &cls);
16601 ok(ret, "Failed to get desktop class.\n");
16602 desktop_proc = cls.lpfnWndProc;
16604 memset(&cls, 0, sizeof(cls));
16605 cls.lpfnWndProc = desktop_proc;
16606 cls.hInstance = instance;
16607 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
16608 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
16609 cls.lpszClassName = "TestDesktopClass";
16610 ret = !!RegisterClassA(&cls);
16611 ok(ret, "Failed to register class.\n");
16613 hwnd = CreateWindowExA(0, cls.lpszClassName, "test_desktop_wndproc",
16614 WS_VISIBLE | WS_CAPTION | WS_OVERLAPPEDWINDOW, 0, 0, 500, 100, 0, 0, 0, NULL);
16615 if (!hwnd) /* win2003 */
16617 skip("Failed to create window with desktop window procedure.\n");
16618 goto out_unregister;
16621 memset(&cls, 0, sizeof(cls));
16622 ret = GetClassInfoA(instance, "TestDesktopClass", &cls);
16623 ok(ret, "Failed to get class info.\n");
16624 ok(cls.lpfnWndProc == desktop_proc, "Got %p, expected %p.\n", cls.lpfnWndProc, desktop_proc);
16626 GetWindowTextA(hwnd, buffer, ARRAY_SIZE(buffer));
16627 todo_wine ok(!strcmp(buffer, "test_desktop_wndproc"), "Got unexpected window text: %s.\n", buffer);
16629 res = CallWindowProcA(desktop_proc, hwnd, WM_SETTEXT, 0, (LPARAM)"test");
16630 ok(res == TRUE, "Failed to set text, %Id.\n", res);
16631 GetWindowTextA(hwnd, buffer, ARRAY_SIZE(buffer));
16632 ok(!strcmp(buffer, "test"), "Got unexpected window text: %s.\n", buffer);
16634 SetRect(&default_rect, 0, 0, 100, 100);
16635 res = DefWindowProcW(hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&default_rect);
16636 ok(!res, "Got unexpected result %Id.\n", res);
16638 SetRect(&rect, 0, 0, 100, 100);
16639 res = CallWindowProcA(desktop_proc, hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rect);
16640 ok(!res, "Got unexpected result %Id.\n", res);
16641 todo_wine ok(EqualRect(&rect, &default_rect), "rect Got %s, expected %s.\n",
16642 wine_dbgstr_rect(&rect), wine_dbgstr_rect(&default_rect));
16644 DestroyWindow(hwnd);
16646 out_unregister:
16647 UnregisterClassA("TestDesktopClass", instance);
16650 #define clear_clipboard(hwnd) clear_clipboard_(__LINE__, (hwnd))
16651 static void clear_clipboard_(int line, HWND hWnd)
16653 BOOL succ;
16654 succ = OpenClipboard(hWnd);
16655 ok_(__FILE__, line)(succ, "OpenClipboard failed, err=%lu\n", GetLastError());
16656 succ = EmptyClipboard();
16657 ok_(__FILE__, line)(succ, "EmptyClipboard failed, err=%lu\n", GetLastError());
16658 succ = CloseClipboard();
16659 ok_(__FILE__, line)(succ, "CloseClipboard failed, err=%lu\n", GetLastError());
16662 #define expect_HWND(expected, got) expect_HWND_(__LINE__, (expected), (got))
16663 static void expect_HWND_(int line, HWND expected, HWND got)
16665 ok_(__FILE__, line)(got==expected, "Expected %p, got %p\n", expected, got);
16668 static WNDPROC pOldViewerProc;
16670 static LRESULT CALLBACK recursive_viewer_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
16672 static BOOL recursion_guard;
16674 if (message == WM_DRAWCLIPBOARD && !recursion_guard)
16676 recursion_guard = TRUE;
16677 clear_clipboard(hWnd);
16678 recursion_guard = FALSE;
16680 return CallWindowProcA(pOldViewerProc, hWnd, message, wParam, lParam);
16683 static void test_clipboard_viewers(void)
16685 static struct message wm_change_cb_chain[] =
16687 { WM_CHANGECBCHAIN, sent|wparam|lparam, 0, 0 },
16688 { 0 }
16690 static const struct message wm_clipboard_destroyed[] =
16692 { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
16693 { 0 }
16695 static struct message wm_clipboard_changed[] =
16697 { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
16698 { 0 }
16700 static struct message wm_clipboard_changed_and_owned[] =
16702 { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
16703 { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
16704 { 0 }
16707 HINSTANCE hInst = GetModuleHandleA(NULL);
16708 HWND hWnd1, hWnd2, hWnd3;
16709 HWND hOrigViewer;
16710 HWND hRet;
16712 hWnd1 = CreateWindowExA(0, "TestWindowClass", "Clipboard viewer test wnd 1",
16713 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
16714 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
16715 GetDesktopWindow(), NULL, hInst, NULL);
16716 hWnd2 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 2",
16717 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
16718 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
16719 GetDesktopWindow(), NULL, hInst, NULL);
16720 hWnd3 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 3",
16721 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
16722 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
16723 GetDesktopWindow(), NULL, hInst, NULL);
16724 trace("clipbd viewers: hWnd1=%p, hWnd2=%p, hWnd3=%p\n", hWnd1, hWnd2, hWnd3);
16725 assert(hWnd1 && hWnd2 && hWnd3);
16727 CountClipboardFormats(); /* Ensure that we do not have an X11 update to the clipboard */
16728 flush_sequence();
16730 /* Test getting the clipboard viewer and setting the viewer to NULL. */
16731 hOrigViewer = GetClipboardViewer();
16732 hRet = SetClipboardViewer(NULL);
16733 ok_sequence(WmEmptySeq, "set viewer to NULL", FALSE);
16734 expect_HWND(hOrigViewer, hRet);
16735 expect_HWND(NULL, GetClipboardViewer());
16737 /* Test registering hWnd1 as a viewer. */
16738 hRet = SetClipboardViewer(hWnd1);
16739 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
16740 ok_sequence(wm_clipboard_changed, "set viewer NULL->1", FALSE);
16741 expect_HWND(NULL, hRet);
16742 expect_HWND(hWnd1, GetClipboardViewer());
16744 /* Test that changing the clipboard actually refreshes the registered viewer. */
16745 clear_clipboard(hWnd1);
16746 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
16747 ok_sequence(wm_clipboard_changed, "clear clipbd (viewer=owner=1)", FALSE);
16749 /* Again, but with different owner. */
16750 clear_clipboard(hWnd2);
16751 wm_clipboard_changed_and_owned[1].wParam = (WPARAM) GetClipboardOwner();
16752 ok_sequence(wm_clipboard_changed_and_owned, "clear clipbd (viewer=1, owner=2)", FALSE);
16754 /* Test re-registering same window. */
16755 hRet = SetClipboardViewer(hWnd1);
16756 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
16757 ok_sequence(wm_clipboard_changed, "set viewer 1->1", FALSE);
16758 expect_HWND(hWnd1, hRet);
16759 expect_HWND(hWnd1, GetClipboardViewer());
16761 /* Test ChangeClipboardChain. */
16762 ChangeClipboardChain(hWnd2, hWnd3);
16763 wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
16764 wm_change_cb_chain[0].lParam = (LPARAM) hWnd3;
16765 ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=3)", FALSE);
16766 expect_HWND(hWnd1, GetClipboardViewer());
16768 ChangeClipboardChain(hWnd2, NULL);
16769 wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
16770 wm_change_cb_chain[0].lParam = 0;
16771 ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=NULL)", FALSE);
16772 expect_HWND(hWnd1, GetClipboardViewer());
16774 ChangeClipboardChain(NULL, hWnd2);
16775 ok_sequence(WmEmptySeq, "change chain (viewer=1, remove=NULL, next=2)", FALSE);
16776 expect_HWND(hWnd1, GetClipboardViewer());
16778 /* Actually change clipboard viewer with ChangeClipboardChain. */
16779 ChangeClipboardChain(hWnd1, hWnd2);
16780 ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=2)", FALSE);
16781 expect_HWND(hWnd2, GetClipboardViewer());
16783 /* Test that no refresh messages are sent when viewer has unregistered. */
16784 clear_clipboard(hWnd2);
16785 ok_sequence(WmEmptySeq, "clear clipd (viewer=2, owner=1)", FALSE);
16787 /* Register hWnd1 again. */
16788 ChangeClipboardChain(hWnd2, hWnd1);
16789 ok_sequence(WmEmptySeq, "change chain (viewer=remove=2, next=1)", FALSE);
16790 expect_HWND(hWnd1, GetClipboardViewer());
16792 /* Subclass hWnd1 so that when it receives a WM_DRAWCLIPBOARD message, it
16793 * changes the clipboard. When this happens, the system shouldn't send
16794 * another WM_DRAWCLIPBOARD (as this could cause an infinite loop).
16796 pOldViewerProc = (WNDPROC) SetWindowLongPtrA(hWnd1, GWLP_WNDPROC, (LONG_PTR) recursive_viewer_proc);
16797 clear_clipboard(hWnd2);
16798 /* The clipboard owner is changed in recursive_viewer_proc: */
16799 wm_clipboard_changed[0].wParam = (WPARAM) hWnd2;
16800 ok_sequence(wm_clipboard_changed, "recursive clear clipbd (viewer=1, owner=2)", TRUE);
16802 /* Test unregistering. */
16803 ChangeClipboardChain(hWnd1, NULL);
16804 ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=NULL)", FALSE);
16805 expect_HWND(NULL, GetClipboardViewer());
16807 clear_clipboard(hWnd1);
16808 ok_sequence(wm_clipboard_destroyed, "clear clipbd (no viewer, owner=1)", FALSE);
16810 DestroyWindow(hWnd1);
16811 DestroyWindow(hWnd2);
16812 DestroyWindow(hWnd3);
16813 SetClipboardViewer(hOrigViewer);
16816 static void test_PostMessage(void)
16818 static const struct
16820 HWND hwnd;
16821 BOOL ret;
16822 } data[] =
16824 { HWND_TOP /* 0 */, TRUE },
16825 { HWND_BROADCAST, TRUE },
16826 { HWND_BOTTOM, TRUE },
16827 { HWND_TOPMOST, TRUE },
16828 { HWND_NOTOPMOST, FALSE },
16829 { HWND_MESSAGE, FALSE },
16830 { (HWND)0xdeadbeef, FALSE }
16832 int i;
16833 HWND hwnd;
16834 BOOL ret;
16835 MSG msg;
16836 static const WCHAR staticW[] = {'s','t','a','t','i','c',0};
16838 SetLastError(0xdeadbeef);
16839 hwnd = CreateWindowExW(0, staticW, NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
16840 if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
16842 win_skip("Skipping some PostMessage tests on Win9x/WinMe\n");
16843 return;
16845 assert(hwnd);
16847 flush_events();
16849 PostMessageA(hwnd, WM_USER+1, 0x1234, 0x5678);
16850 PostMessageA(0, WM_USER+2, 0x5678, 0x1234);
16852 for (i = 0; i < ARRAY_SIZE(data); i++)
16854 memset(&msg, 0xab, sizeof(msg));
16855 ret = PeekMessageA(&msg, data[i].hwnd, 0, 0, PM_NOREMOVE);
16856 ok(ret == data[i].ret, "%d: hwnd %p expected %d, got %d\n", i, data[i].hwnd, data[i].ret, ret);
16857 if (data[i].ret)
16859 if (data[i].hwnd)
16860 ok(ret && msg.hwnd == 0 && msg.message == WM_USER+2 &&
16861 msg.wParam == 0x5678 && msg.lParam == 0x1234,
16862 "%d: got ret %d hwnd %p msg %04x wParam %08Ix lParam %08Ix instead of TRUE/0/WM_USER+2/0x5678/0x1234\n",
16863 i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam);
16864 else
16865 ok(ret && msg.hwnd == hwnd && msg.message == WM_USER+1 &&
16866 msg.wParam == 0x1234 && msg.lParam == 0x5678,
16867 "%d: got ret %d hwnd %p msg %04x wParam %08Ix lParam %08Ix instead of TRUE/%p/WM_USER+1/0x1234/0x5678\n",
16868 i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam, msg.hwnd);
16872 DestroyWindow(hwnd);
16873 flush_events();
16876 static WPARAM g_broadcast_wparam;
16877 static LRESULT WINAPI broadcast_test_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
16879 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
16881 if (wParam == 0xbaadbeef)
16882 g_broadcast_wparam = wParam;
16883 else
16884 g_broadcast_wparam = 0;
16886 return CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
16888 static WNDPROC *g_oldproc_sub;
16889 static WPARAM *g_broadcast_sub_wparam;
16890 static LRESULT WINAPI broadcast_test_sub_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
16892 int sub_index = GetWindowLongPtrA(hwnd, GWLP_USERDATA);
16894 g_broadcast_sub_wparam[sub_index] = (wParam == 0xbaadbeef) ? wParam : 0;
16896 return CallWindowProcA(g_oldproc_sub[sub_index], hwnd, message, wParam, lParam);
16899 static void test_broadcast(void)
16901 static const UINT messages[] =
16903 WM_USER-1,
16904 WM_USER,
16905 WM_USER+1,
16906 0xc000-1,
16907 0xc000, /* lowest possible atom returned by RegisterWindowMessage */
16908 0xffff,
16910 static const struct
16912 LONG style;
16913 BOOL receive;
16914 } bcast_expect[] =
16916 {WS_OVERLAPPED, TRUE},
16917 {WS_OVERLAPPED|WS_DLGFRAME, TRUE},
16918 {WS_OVERLAPPED|WS_BORDER, TRUE},
16919 {WS_OVERLAPPED|WS_CAPTION, TRUE},
16920 {WS_CHILD, FALSE},
16921 {WS_CHILD|WS_DLGFRAME, FALSE},
16922 {WS_CHILD|WS_BORDER, FALSE},
16923 {WS_CHILD|WS_CAPTION, FALSE},
16924 {WS_CHILD|WS_POPUP, TRUE},
16925 {WS_POPUP, TRUE},
16926 {WS_POPUP|WS_DLGFRAME, TRUE},
16927 {WS_POPUP|WS_BORDER, TRUE},
16928 {WS_POPUP|WS_CAPTION, TRUE},
16930 WNDPROC oldproc;
16931 unsigned int i, j;
16932 HWND hwnd;
16933 HWND *hwnd_sub;
16935 hwnd_sub = HeapAlloc( GetProcessHeap(), 0, ARRAY_SIZE(bcast_expect) * sizeof(*hwnd_sub) );
16936 g_oldproc_sub = HeapAlloc( GetProcessHeap(), 0, ARRAY_SIZE(bcast_expect) * sizeof(*g_oldproc_sub) );
16937 g_broadcast_sub_wparam = HeapAlloc( GetProcessHeap(), 0, ARRAY_SIZE(bcast_expect) * sizeof(*g_broadcast_sub_wparam) );
16939 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, NULL);
16940 ok(hwnd != NULL, "got %p\n", hwnd);
16942 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)broadcast_test_proc);
16943 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
16945 for (i = 0; i < ARRAY_SIZE(messages); i++)
16947 BOOL ret;
16948 BOOL msg_expected = (messages[i] < WM_USER || messages[i] >= 0xc000);
16949 MSG msg;
16951 flush_events();
16952 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
16955 /* post, broadcast */
16956 ret = PostMessageA(HWND_BROADCAST, messages[i], 0, 0);
16957 ok(ret, "%d: got %d, error %ld\n", i, ret, GetLastError());
16959 memset(&msg, 0xab, sizeof(msg));
16960 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
16961 ok(ret == msg_expected, "%d: message %04x, got %d, error %ld\n", i, messages[i], ret, GetLastError());
16962 if (msg_expected)
16963 ok(msg.hwnd == hwnd, "%d: got %p\n", i, msg.hwnd);
16965 /* post, topmost */
16966 ret = PostMessageA(HWND_TOPMOST, messages[i], 0, 0);
16967 ok(ret, "%d: got %d, error %ld\n", i, ret, GetLastError());
16969 memset(&msg, 0xab, sizeof(msg));
16970 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
16971 ok(ret == msg_expected, "%d: message %04x, got %d, error %ld\n", i, messages[i], ret, GetLastError());
16972 if (msg_expected)
16973 ok(msg.hwnd == hwnd, "%d: got %p\n", i, msg.hwnd);
16976 for (j = 0; j < ARRAY_SIZE(bcast_expect); j++)
16978 hwnd_sub[j] = CreateWindowA("static", NULL, bcast_expect[j].style, 0, 0, 0, 0, hwnd, 0, 0, NULL);
16979 ok(hwnd_sub[j] != NULL, "got %p\n", hwnd_sub[j]);
16980 /* CreateWindow adds extra style flags, so call SetWindowLong to clear some of those. */
16981 SetWindowLongA(hwnd_sub[j], GWL_STYLE, bcast_expect[j].style);
16983 g_oldproc_sub[j] = (WNDPROC)SetWindowLongPtrA(hwnd_sub[j], GWLP_WNDPROC, (LONG_PTR)broadcast_test_sub_proc);
16984 SetWindowLongPtrA(hwnd_sub[j], GWLP_USERDATA, (LONG_PTR)j);
16987 for (i = 0; i < ARRAY_SIZE(messages); i++)
16989 BOOL ret;
16990 BOOL msg_expected = (messages[i] < WM_USER || messages[i] >= 0xc000);
16992 /* send, broadcast */
16993 g_broadcast_wparam = 0xdead;
16994 for (j = 0; j < ARRAY_SIZE(bcast_expect); j++)
16995 g_broadcast_sub_wparam[j] = 0xdead;
16996 ret = SendMessageTimeoutA(HWND_BROADCAST, messages[i], 0xbaadbeef, 0, SMTO_NORMAL, 2000, NULL);
16997 if (!ret && GetLastError() == ERROR_TIMEOUT)
16998 win_skip("broadcasting test %d, timeout\n", i);
16999 else
17001 WPARAM wparam_expected = msg_expected ? 0xbaadbeef : 0xdead;
17002 ok(g_broadcast_wparam == wparam_expected, "%d: message %04x, got %#Ix, error %ld\n",
17003 i, messages[i], g_broadcast_wparam, GetLastError());
17004 for (j = 0; j < ARRAY_SIZE(bcast_expect); j++)
17006 wparam_expected = (msg_expected && bcast_expect[j].receive) ? 0xbaadbeef : 0xdead;
17007 ok(g_broadcast_sub_wparam[j] == wparam_expected,
17008 "%d,%d: message %04x, got %#Ix, error %ld\n", i, j, messages[i],
17009 g_broadcast_sub_wparam[j], GetLastError());
17013 /* send, topmost */
17014 g_broadcast_wparam = 0xdead;
17015 for (j = 0; j < ARRAY_SIZE(bcast_expect); j++)
17016 g_broadcast_sub_wparam[j] = 0xdead;
17017 ret = SendMessageTimeoutA(HWND_TOPMOST, messages[i], 0xbaadbeef, 0, SMTO_NORMAL, 2000, NULL);
17018 if (!ret && GetLastError() == ERROR_TIMEOUT)
17019 win_skip("broadcasting test %d, timeout\n", i);
17020 else
17022 WPARAM wparam_expected = msg_expected ? 0xbaadbeef : 0xdead;
17023 ok(g_broadcast_wparam == wparam_expected, "%d: message %04x, got %#Ix, error %ld\n",
17024 i, messages[i], g_broadcast_wparam, GetLastError());
17025 for (j = 0; j < ARRAY_SIZE(bcast_expect); j++)
17027 wparam_expected = (msg_expected && bcast_expect[j].receive) ? 0xbaadbeef : 0xdead;
17028 ok(g_broadcast_sub_wparam[j] == wparam_expected,
17029 "%d,%d: message %04x, got %#Ix, error %ld\n", i, j, messages[i],
17030 g_broadcast_sub_wparam[j], GetLastError());
17035 for (j = 0; j < ARRAY_SIZE(bcast_expect); j++)
17036 DestroyWindow(hwnd_sub[j]);
17038 HeapFree(GetProcessHeap(), 0, g_broadcast_sub_wparam);
17039 HeapFree(GetProcessHeap(), 0, g_oldproc_sub);
17040 HeapFree(GetProcessHeap(), 0, hwnd_sub);
17042 DestroyWindow(hwnd);
17045 static const struct
17047 DWORD exp, broken;
17048 BOOL todo;
17049 } wait_idle_expect[] =
17051 /* 0 */ { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
17052 { WAIT_TIMEOUT, 0, FALSE },
17053 { WAIT_TIMEOUT, 0, FALSE },
17054 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
17055 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
17056 /* 5 */ { WAIT_TIMEOUT, 0, FALSE },
17057 { WAIT_TIMEOUT, 0, FALSE },
17058 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
17059 { 0, 0, FALSE },
17060 { 0, 0, FALSE },
17061 /* 10 */ { 0, 0, FALSE },
17062 { 0, 0, FALSE },
17063 { 0, WAIT_TIMEOUT, FALSE },
17064 { 0, 0, FALSE },
17065 { 0, 0, FALSE },
17066 /* 15 */ { 0, 0, FALSE },
17067 { WAIT_TIMEOUT, 0, FALSE },
17068 { WAIT_TIMEOUT, 0, FALSE },
17069 { WAIT_TIMEOUT, 0, FALSE },
17070 { WAIT_TIMEOUT, 0, FALSE },
17071 /* 20 */ { WAIT_TIMEOUT, 0, FALSE },
17074 static DWORD CALLBACK do_wait_idle_child_thread( void *arg )
17076 MSG msg;
17078 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
17079 Sleep( 200 );
17080 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
17081 return 0;
17084 static void do_wait_idle_child( int arg )
17086 WNDCLASSA cls;
17087 MSG msg;
17088 HWND hwnd = 0;
17089 HANDLE thread;
17090 DWORD id;
17091 HANDLE start_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_start" );
17092 HANDLE end_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_end" );
17094 memset( &cls, 0, sizeof(cls) );
17095 cls.lpfnWndProc = DefWindowProcA;
17096 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
17097 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
17098 cls.lpszClassName = "TestClass";
17099 RegisterClassA( &cls );
17101 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ); /* create the msg queue */
17103 ok( start_event != 0, "failed to create start event, error %lu\n", GetLastError() );
17104 ok( end_event != 0, "failed to create end event, error %lu\n", GetLastError() );
17106 switch (arg)
17108 case 0:
17109 SetEvent( start_event );
17110 break;
17111 case 1:
17112 SetEvent( start_event );
17113 Sleep( 200 );
17114 PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
17115 break;
17116 case 2:
17117 SetEvent( start_event );
17118 Sleep( 200 );
17119 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
17120 PostThreadMessageA( GetCurrentThreadId(), WM_COMMAND, 0x1234, 0xabcd );
17121 PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
17122 break;
17123 case 3:
17124 SetEvent( start_event );
17125 Sleep( 200 );
17126 SendMessageA( HWND_BROADCAST, WM_WININICHANGE, 0, 0 );
17127 break;
17128 case 4:
17129 SetEvent( start_event );
17130 Sleep( 200 );
17131 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
17132 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
17133 break;
17134 case 5:
17135 SetEvent( start_event );
17136 Sleep( 200 );
17137 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
17138 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
17139 break;
17140 case 6:
17141 SetEvent( start_event );
17142 Sleep( 200 );
17143 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
17144 while (PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ))
17146 GetMessageA( &msg, 0, 0, 0 );
17147 DispatchMessageA( &msg );
17149 break;
17150 case 7:
17151 SetEvent( start_event );
17152 Sleep( 200 );
17153 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
17154 SetTimer( hwnd, 3, 1, NULL );
17155 Sleep( 200 );
17156 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
17157 break;
17158 case 8:
17159 SetEvent( start_event );
17160 Sleep( 200 );
17161 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
17162 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
17163 break;
17164 case 9:
17165 SetEvent( start_event );
17166 Sleep( 200 );
17167 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
17168 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
17169 for (;;) GetMessageA( &msg, 0, 0, 0 );
17170 break;
17171 case 10:
17172 SetEvent( start_event );
17173 Sleep( 200 );
17174 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
17175 SetTimer( hwnd, 3, 1, NULL );
17176 Sleep( 200 );
17177 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
17178 break;
17179 case 11:
17180 SetEvent( start_event );
17181 Sleep( 200 );
17182 return; /* exiting the process makes WaitForInputIdle return success too */
17183 case 12:
17184 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
17185 Sleep( 200 );
17186 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
17187 SetEvent( start_event );
17188 break;
17189 case 13:
17190 SetEvent( start_event );
17191 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
17192 Sleep( 200 );
17193 thread = CreateThread( NULL, 0, do_wait_idle_child_thread, NULL, 0, &id );
17194 WaitForSingleObject( thread, 10000 );
17195 CloseHandle( thread );
17196 break;
17197 case 14:
17198 SetEvent( start_event );
17199 Sleep( 200 );
17200 PeekMessageA( &msg, HWND_TOPMOST, 0, 0, PM_NOREMOVE );
17201 break;
17202 case 15:
17203 SetEvent( start_event );
17204 Sleep( 200 );
17205 PeekMessageA( &msg, HWND_BROADCAST, 0, 0, PM_NOREMOVE );
17206 break;
17207 case 16:
17208 SetEvent( start_event );
17209 Sleep( 200 );
17210 PeekMessageA( &msg, HWND_BOTTOM, 0, 0, PM_NOREMOVE );
17211 break;
17212 case 17:
17213 SetEvent( start_event );
17214 Sleep( 200 );
17215 PeekMessageA( &msg, (HWND)0xdeadbeef, 0, 0, PM_NOREMOVE );
17216 break;
17217 case 18:
17218 SetEvent( start_event );
17219 Sleep( 200 );
17220 PeekMessageA( &msg, HWND_NOTOPMOST, 0, 0, PM_NOREMOVE );
17221 break;
17222 case 19:
17223 SetEvent( start_event );
17224 Sleep( 200 );
17225 PeekMessageA( &msg, HWND_MESSAGE, 0, 0, PM_NOREMOVE );
17226 break;
17227 case 20:
17228 SetEvent( start_event );
17229 Sleep( 200 );
17230 PeekMessageA( &msg, GetDesktopWindow(), 0, 0, PM_NOREMOVE );
17231 break;
17233 WaitForSingleObject( end_event, 2000 );
17234 CloseHandle( start_event );
17235 CloseHandle( end_event );
17236 if (hwnd) DestroyWindow( hwnd );
17239 static LRESULT CALLBACK wait_idle_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
17241 if (msg == WM_WININICHANGE) Sleep( 200 ); /* make sure the child waits */
17242 return DefWindowProcA( hwnd, msg, wp, lp );
17245 static DWORD CALLBACK wait_idle_thread( void *arg )
17247 WNDCLASSA cls;
17248 MSG msg;
17249 HWND hwnd;
17251 memset( &cls, 0, sizeof(cls) );
17252 cls.lpfnWndProc = wait_idle_proc;
17253 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
17254 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
17255 cls.lpszClassName = "TestClass";
17256 RegisterClassA( &cls );
17258 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL);
17259 while (GetMessageA( &msg, 0, 0, 0 )) DispatchMessageA( &msg );
17260 DestroyWindow(hwnd);
17261 return 0;
17264 static void test_WaitForInputIdle( char *argv0 )
17266 char path[MAX_PATH];
17267 PROCESS_INFORMATION pi;
17268 STARTUPINFOA startup;
17269 BOOL ret;
17270 HANDLE start_event, end_event, thread;
17271 unsigned int i;
17272 DWORD id;
17273 const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)GetModuleHandleA(0);
17274 const IMAGE_NT_HEADERS *nt = (const IMAGE_NT_HEADERS *)((const char *)dos + dos->e_lfanew);
17275 BOOL console_app = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI);
17277 if (console_app) /* build the test with -mwindows for better coverage */
17278 trace( "not built as a GUI app, WaitForInputIdle may not be fully tested\n" );
17280 start_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_start");
17281 end_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_end");
17282 ok(start_event != 0, "failed to create start event, error %lu\n", GetLastError());
17283 ok(end_event != 0, "failed to create end event, error %lu\n", GetLastError());
17285 memset( &startup, 0, sizeof(startup) );
17286 startup.cb = sizeof(startup);
17287 startup.dwFlags = STARTF_USESHOWWINDOW;
17288 startup.wShowWindow = SW_SHOWNORMAL;
17290 thread = CreateThread( NULL, 0, wait_idle_thread, NULL, 0, &id );
17292 for (i = 0; i < ARRAY_SIZE(wait_idle_expect); i++)
17294 ResetEvent( start_event );
17295 ResetEvent( end_event );
17296 sprintf( path, "%s msg %u", argv0, i );
17297 ret = CreateProcessA( NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &pi );
17298 ok( ret, "CreateProcess '%s' failed err %lu.\n", path, GetLastError() );
17299 if (ret)
17301 ret = WaitForSingleObject( start_event, 5000 );
17302 ok( ret == WAIT_OBJECT_0, "%u: WaitForSingleObject failed\n", i );
17303 if (ret == WAIT_OBJECT_0)
17305 ret = WaitForInputIdle( pi.hProcess, 1000 );
17306 if (ret == WAIT_FAILED)
17307 ok( console_app ||
17308 ret == wait_idle_expect[i].exp ||
17309 broken(ret == wait_idle_expect[i].broken),
17310 "%u: WaitForInputIdle error %08x expected %08lx\n",
17311 i, ret, wait_idle_expect[i].exp );
17312 else todo_wine_if (wait_idle_expect[i].todo)
17313 ok( ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken),
17314 "%u: WaitForInputIdle error %08x expected %08lx\n",
17315 i, ret, wait_idle_expect[i].exp );
17316 SetEvent( end_event );
17317 WaitForSingleObject( pi.hProcess, 1000 ); /* give it a chance to exit on its own */
17319 TerminateProcess( pi.hProcess, 0 ); /* just in case */
17320 wait_child_process( pi.hProcess );
17321 ret = WaitForInputIdle( pi.hProcess, 100 );
17322 ok( ret == WAIT_FAILED, "%u: WaitForInputIdle after exit error %08x\n", i, ret );
17323 CloseHandle( pi.hProcess );
17324 CloseHandle( pi.hThread );
17327 CloseHandle( end_event );
17328 CloseHandle( start_event );
17329 PostThreadMessageA( id, WM_QUIT, 0, 0 );
17330 WaitForSingleObject( thread, 10000 );
17331 CloseHandle( thread );
17334 static const struct message WmSetParentSeq_1[] = {
17335 { WM_SHOWWINDOW, sent|wparam, 0 },
17336 { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
17337 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
17338 { WM_CHILDACTIVATE, sent },
17339 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE },
17340 { WM_MOVE, sent|defwinproc|wparam, 0 },
17341 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
17342 { WM_SHOWWINDOW, sent|wparam, 1 },
17343 { 0 }
17346 static const struct message WmSetParentSeq_2[] = {
17347 { WM_SHOWWINDOW, sent|wparam, 0 },
17348 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
17349 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
17350 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
17351 { HCBT_SETFOCUS, hook|optional },
17352 { WM_NCACTIVATE, sent|wparam|optional, 0 },
17353 { WM_ACTIVATE, sent|wparam|optional, 0 },
17354 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
17355 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
17356 { WM_KILLFOCUS, sent|wparam, 0 },
17357 { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
17358 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
17359 { HCBT_ACTIVATE, hook|optional },
17360 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|optional, 0, 0 },
17361 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
17362 { WM_NCACTIVATE, sent|wparam|optional, 1 },
17363 { WM_ACTIVATE, sent|wparam|optional, 1 },
17364 { HCBT_SETFOCUS, hook|optional },
17365 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
17366 { WM_SETFOCUS, sent|optional|defwinproc },
17367 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOCLIENTSIZE },
17368 { WM_MOVE, sent|defwinproc|wparam, 0 },
17369 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
17370 { WM_SHOWWINDOW, sent|wparam, 1 },
17371 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
17372 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
17373 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
17374 { 0 }
17378 static void test_SetParent(void)
17380 HWND parent1, parent2, child, popup;
17381 RECT rc, rc_old;
17383 parent1 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
17384 100, 100, 200, 200, 0, 0, 0, NULL);
17385 ok(parent1 != 0, "Failed to create parent1 window\n");
17387 parent2 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
17388 400, 100, 200, 200, 0, 0, 0, NULL);
17389 ok(parent2 != 0, "Failed to create parent2 window\n");
17391 /* WS_CHILD window */
17392 child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD | WS_VISIBLE,
17393 10, 10, 150, 150, parent1, 0, 0, NULL);
17394 ok(child != 0, "Failed to create child window\n");
17396 GetWindowRect(parent1, &rc);
17397 trace("parent1 %s\n", wine_dbgstr_rect(&rc));
17398 GetWindowRect(child, &rc_old);
17399 MapWindowPoints(0, parent1, (POINT *)&rc_old, 2);
17400 trace("child %s\n", wine_dbgstr_rect(&rc_old));
17402 flush_sequence();
17404 SetParent(child, parent2);
17405 flush_events();
17406 ok_sequence(WmSetParentSeq_1, "SetParent() visible WS_CHILD", FALSE);
17408 ok(GetWindowLongA(child, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
17409 ok(!IsWindowVisible(child), "IsWindowVisible() should return FALSE\n");
17411 GetWindowRect(parent2, &rc);
17412 trace("parent2 %s\n", wine_dbgstr_rect(&rc));
17413 GetWindowRect(child, &rc);
17414 MapWindowPoints(0, parent2, (POINT *)&rc, 2);
17415 trace("child %s\n", wine_dbgstr_rect(&rc));
17417 ok(EqualRect(&rc_old, &rc), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc_old),
17418 wine_dbgstr_rect(&rc));
17420 /* WS_POPUP window */
17421 popup = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP | WS_VISIBLE,
17422 20, 20, 100, 100, 0, 0, 0, NULL);
17423 ok(popup != 0, "Failed to create popup window\n");
17425 GetWindowRect(popup, &rc_old);
17426 trace("popup %s\n", wine_dbgstr_rect(&rc_old));
17428 flush_sequence();
17430 SetParent(popup, child);
17431 flush_events();
17432 ok_sequence(WmSetParentSeq_2, "SetParent() visible WS_POPUP", TRUE);
17434 ok(GetWindowLongA(popup, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
17435 ok(!IsWindowVisible(popup), "IsWindowVisible() should return FALSE\n");
17437 GetWindowRect(child, &rc);
17438 trace("parent2 %s\n", wine_dbgstr_rect(&rc));
17439 GetWindowRect(popup, &rc);
17440 MapWindowPoints(0, child, (POINT *)&rc, 2);
17441 trace("popup %s\n", wine_dbgstr_rect(&rc));
17443 ok(EqualRect(&rc_old, &rc), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc_old),
17444 wine_dbgstr_rect(&rc));
17446 DestroyWindow(popup);
17447 DestroyWindow(child);
17448 DestroyWindow(parent1);
17449 DestroyWindow(parent2);
17451 flush_sequence();
17454 static const struct message WmKeyReleaseOnly[] = {
17455 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x80000001 },
17456 { WM_KEYUP, sent|wparam|lparam, 0x41, 0x80000001 },
17457 { 0 }
17459 static const struct message WmKeyPressNormal[] = {
17460 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x1 },
17461 { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x1 },
17462 { 0 }
17464 static const struct message WmKeyPressRepeat[] = {
17465 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x40000001 },
17466 { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x40000001 },
17467 { 0 }
17469 static const struct message WmKeyReleaseNormal[] = {
17470 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0xc0000001 },
17471 { WM_KEYUP, sent|wparam|lparam, 0x41, 0xc0000001 },
17472 { 0 }
17475 static void test_keyflags(void)
17477 HWND test_window;
17478 SHORT key_state;
17479 BYTE keyboard_state[256];
17480 MSG msg;
17482 test_window = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
17483 100, 100, 200, 200, 0, 0, 0, NULL);
17485 flush_events();
17486 flush_sequence();
17488 /* keyup without a keydown */
17489 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
17490 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
17491 DispatchMessageA(&msg);
17492 ok_sequence(WmKeyReleaseOnly, "key release only", TRUE);
17494 key_state = GetAsyncKeyState(0x41);
17495 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
17497 key_state = GetKeyState(0x41);
17498 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
17500 /* keydown */
17501 keybd_event(0x41, 0, 0, 0);
17502 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
17503 DispatchMessageA(&msg);
17504 ok_sequence(WmKeyPressNormal, "key press only", FALSE);
17506 key_state = GetAsyncKeyState(0x41);
17507 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
17509 key_state = GetKeyState(0x41);
17510 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
17512 /* keydown repeat */
17513 keybd_event(0x41, 0, 0, 0);
17514 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
17515 DispatchMessageA(&msg);
17516 ok_sequence(WmKeyPressRepeat, "key press repeat", FALSE);
17518 key_state = GetAsyncKeyState(0x41);
17519 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
17521 key_state = GetKeyState(0x41);
17522 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
17524 /* keyup */
17525 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
17526 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
17527 DispatchMessageA(&msg);
17528 ok_sequence(WmKeyReleaseNormal, "key release repeat", FALSE);
17530 key_state = GetAsyncKeyState(0x41);
17531 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
17533 key_state = GetKeyState(0x41);
17534 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
17536 /* set the key state in this thread */
17537 GetKeyboardState(keyboard_state);
17538 keyboard_state[0x41] = 0x80;
17539 SetKeyboardState(keyboard_state);
17541 key_state = GetAsyncKeyState(0x41);
17542 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
17544 /* keydown */
17545 keybd_event(0x41, 0, 0, 0);
17546 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
17547 DispatchMessageA(&msg);
17548 ok_sequence(WmKeyPressRepeat, "key press after setkeyboardstate", TRUE);
17550 key_state = GetAsyncKeyState(0x41);
17551 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
17553 key_state = GetKeyState(0x41);
17554 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
17556 /* clear the key state in this thread */
17557 GetKeyboardState(keyboard_state);
17558 keyboard_state[0x41] = 0;
17559 SetKeyboardState(keyboard_state);
17561 key_state = GetAsyncKeyState(0x41);
17562 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
17564 /* keyup */
17565 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
17566 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
17567 DispatchMessageA(&msg);
17568 ok_sequence(WmKeyReleaseOnly, "key release after setkeyboardstate", TRUE);
17570 key_state = GetAsyncKeyState(0x41);
17571 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
17573 key_state = GetKeyState(0x41);
17574 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
17576 DestroyWindow(test_window);
17577 flush_sequence();
17580 static const struct message WmHotkeyPressLWIN[] = {
17581 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
17582 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
17583 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
17584 { 0 }
17586 static const struct message WmHotkeyPress[] = {
17587 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
17588 { WM_HOTKEY, sent|wparam, 5 },
17589 { 0 }
17591 static const struct message WmHotkeyRelease[] = {
17592 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
17593 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 0x80000001 },
17594 { WM_KEYUP, sent|lparam, 0, 0x80000001 },
17595 { 0 }
17597 static const struct message WmHotkeyReleaseLWIN[] = {
17598 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
17599 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
17600 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
17601 { 0 }
17603 static const struct message WmHotkeyCombined[] = {
17604 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
17605 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
17606 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
17607 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
17608 { WM_APP, sent, 0, 0 },
17609 { WM_HOTKEY, sent|wparam, 5 },
17610 { WM_APP+1, sent, 0, 0 },
17611 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
17612 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
17613 { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
17614 { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
17615 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
17616 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
17617 { 0 }
17619 static const struct message WmHotkeyPrevious[] = {
17620 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
17621 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
17622 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
17623 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
17624 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
17625 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
17626 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 1 },
17627 { WM_KEYDOWN, sent|lparam, 0, 1 },
17628 { HCBT_KEYSKIPPED, hook|optional|lparam, 0, 0xc0000001 },
17629 { WM_KEYUP, sent|lparam, 0, 0xc0000001 },
17630 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
17631 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
17632 { 0 }
17634 static const struct message WmHotkeyNew[] = {
17635 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
17636 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
17637 { WM_HOTKEY, sent|wparam, 5 },
17638 { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
17639 { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
17640 { 0 }
17642 static const struct message WmHotkeyPressALT[] = {
17643 { WM_SYSKEYDOWN, kbd_hook|wparam|lparam, VK_LMENU, LLKHF_INJECTED|LLKHF_ALTDOWN },
17644 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
17645 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
17646 { 0 }
17648 static const struct message WmHotkeyPressWithALT[] = {
17649 { WM_SYSKEYDOWN, kbd_hook, 0, LLKHF_INJECTED|LLKHF_ALTDOWN }, /* lparam not checked */
17650 { WM_HOTKEY, sent|wparam, 6 },
17651 { 0 }
17653 static const struct message WmHotkeyReleaseWithALT[] = {
17654 { WM_SYSKEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP|LLKHF_ALTDOWN },
17655 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 0xa0000001 },
17656 { WM_SYSKEYUP, sent|lparam, 0, 0xa0000001 },
17657 { 0 }
17659 static const struct message WmHotkeyReleaseALT[] = {
17660 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LMENU, LLKHF_INJECTED|LLKHF_UP },
17661 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 },
17662 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
17663 { 0 }
17666 static int hotkey_letter;
17668 static LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
17670 struct recvd_message msg;
17672 if (nCode == HC_ACTION)
17674 KBDLLHOOKSTRUCT *kdbhookstruct = (KBDLLHOOKSTRUCT*)lParam;
17676 msg.hwnd = 0;
17677 msg.message = wParam;
17678 msg.flags = kbd_hook|wparam|lparam;
17679 msg.wParam = kdbhookstruct->vkCode;
17680 msg.lParam = kdbhookstruct->flags;
17681 msg.descr = "KeyboardHookProc";
17682 add_message(&msg);
17684 if (wParam == WM_KEYUP || wParam == WM_KEYDOWN ||
17685 wParam == WM_SYSKEYUP || wParam == WM_SYSKEYDOWN)
17687 ok(kdbhookstruct->vkCode == VK_LWIN ||
17688 kdbhookstruct->vkCode == VK_LMENU ||
17689 kdbhookstruct->vkCode == hotkey_letter,
17690 "unexpected keycode %lx\n", kdbhookstruct->vkCode);
17694 return CallNextHookEx(hKBD_hook, nCode, wParam, lParam);
17697 static void test_hotkey(void)
17699 HWND test_window, taskbar_window;
17700 BOOL ret;
17701 MSG msg;
17702 DWORD queue_status;
17703 SHORT key_state;
17705 SetLastError(0xdeadbeef);
17706 ret = UnregisterHotKey(NULL, 0);
17707 if (ret == TRUE)
17709 skip("hotkeys not supported\n");
17710 return;
17713 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
17714 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
17715 "unexpected error %ld\n", GetLastError());
17717 test_window = CreateWindowExA(0, "HotkeyWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
17718 100, 100, 200, 200, 0, 0, 0, NULL);
17720 flush_sequence();
17722 SetLastError(0xdeadbeef);
17723 ret = UnregisterHotKey(test_window, 0);
17724 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
17725 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
17726 "unexpected error %ld\n", GetLastError());
17728 /* Search for a Windows Key + letter combination that hasn't been registered */
17729 for (hotkey_letter = 0x41; hotkey_letter <= 0x51; hotkey_letter ++)
17731 SetLastError(0xdeadbeef);
17732 ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
17734 if (ret == TRUE)
17736 break;
17738 else
17740 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
17741 "unexpected error %ld\n", GetLastError());
17745 if (hotkey_letter == 0x52)
17747 ok(0, "Couldn't find any free Windows Key + letter combination\n");
17748 goto end;
17751 hKBD_hook = SetWindowsHookExA(WH_KEYBOARD_LL, KeyboardHookProc, GetModuleHandleA(NULL), 0);
17752 if (!hKBD_hook) win_skip("WH_KEYBOARD_LL is not supported\n");
17754 /* Same key combination, different id */
17755 SetLastError(0xdeadbeef);
17756 ret = RegisterHotKey(test_window, 4, MOD_WIN, hotkey_letter);
17757 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
17758 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
17759 "unexpected error %ld\n", GetLastError());
17761 /* Same key combination, different window */
17762 SetLastError(0xdeadbeef);
17763 ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
17764 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
17765 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
17766 "unexpected error %ld\n", GetLastError());
17768 /* Register the same hotkey twice */
17769 SetLastError(0xdeadbeef);
17770 ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
17771 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
17772 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
17773 "unexpected error %ld\n", GetLastError());
17775 /* Window on another thread */
17776 taskbar_window = FindWindowA("Shell_TrayWnd", NULL);
17777 if (!taskbar_window)
17779 skip("no taskbar?\n");
17781 else
17783 SetLastError(0xdeadbeef);
17784 ret = RegisterHotKey(taskbar_window, 5, 0, hotkey_letter);
17785 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
17786 ok(GetLastError() == ERROR_WINDOW_OF_OTHER_THREAD || broken(GetLastError() == 0xdeadbeef),
17787 "unexpected error %ld\n", GetLastError());
17790 /* Inject the appropriate key sequence */
17791 keybd_event(VK_LWIN, 0, 0, 0);
17792 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
17793 DispatchMessageA(&msg);
17794 ok_sequence(WmHotkeyPressLWIN, "window hotkey press LWIN", FALSE);
17796 keybd_event(hotkey_letter, 0, 0, 0);
17797 queue_status = GetQueueStatus(QS_HOTKEY);
17798 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %lx\n", queue_status);
17799 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
17801 if (msg.message == WM_HOTKEY)
17803 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
17804 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %Ix\n", msg.lParam);
17806 DispatchMessageA(&msg);
17808 ok_sequence(WmHotkeyPress, "window hotkey press", FALSE);
17810 queue_status = GetQueueStatus(QS_HOTKEY);
17811 ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %lx\n", queue_status);
17813 key_state = GetAsyncKeyState(hotkey_letter);
17814 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
17816 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
17817 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
17818 DispatchMessageA(&msg);
17819 ok_sequence(WmHotkeyRelease, "window hotkey release", TRUE);
17821 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
17822 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
17823 DispatchMessageA(&msg);
17824 ok_sequence(WmHotkeyReleaseLWIN, "window hotkey release LWIN", FALSE);
17826 /* normal posted WM_HOTKEY messages set QS_HOTKEY */
17827 PostMessageA(test_window, WM_HOTKEY, 0, 0);
17828 queue_status = GetQueueStatus(QS_HOTKEY);
17829 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %lx\n", queue_status);
17830 queue_status = GetQueueStatus(QS_POSTMESSAGE);
17831 ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %lx\n", queue_status);
17832 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
17833 DispatchMessageA(&msg);
17834 flush_sequence();
17836 /* Send and process all messages at once */
17837 PostMessageA(test_window, WM_APP, 0, 0);
17838 keybd_event(VK_LWIN, 0, 0, 0);
17839 keybd_event(hotkey_letter, 0, 0, 0);
17840 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
17841 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
17843 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
17845 if (msg.message == WM_HOTKEY)
17847 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
17848 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %Ix\n", msg.lParam);
17850 DispatchMessageA(&msg);
17852 ok_sequence(WmHotkeyCombined, "window hotkey combined", FALSE);
17854 /* Register same hwnd/id with different key combination */
17855 ret = RegisterHotKey(test_window, 5, 0, hotkey_letter);
17856 ok(ret == TRUE, "expected TRUE, got %i, err=%ld\n", ret, GetLastError());
17858 /* Previous key combination does not work */
17859 keybd_event(VK_LWIN, 0, 0, 0);
17860 keybd_event(hotkey_letter, 0, 0, 0);
17861 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
17862 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
17864 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
17865 DispatchMessageA(&msg);
17866 ok_sequence(WmHotkeyPrevious, "window hotkey previous", FALSE);
17868 /* New key combination works */
17869 keybd_event(hotkey_letter, 0, 0, 0);
17870 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
17872 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
17874 if (msg.message == WM_HOTKEY)
17876 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
17877 ok(msg.lParam == MAKELPARAM(0, hotkey_letter), "unexpected WM_HOTKEY lparam %Ix\n", msg.lParam);
17879 DispatchMessageA(&msg);
17881 ok_sequence(WmHotkeyNew, "window hotkey new", FALSE);
17883 /* Unregister hotkey properly */
17884 ret = UnregisterHotKey(test_window, 5);
17885 ok(ret == TRUE, "expected TRUE, got %i, err=%ld\n", ret, GetLastError());
17887 /* Unregister hotkey again */
17888 SetLastError(0xdeadbeef);
17889 ret = UnregisterHotKey(test_window, 5);
17890 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
17891 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
17892 "unexpected error %ld\n", GetLastError());
17894 /* Register thread hotkey */
17895 ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
17896 ok(ret == TRUE, "expected TRUE, got %i, err=%ld\n", ret, GetLastError());
17898 /* Inject the appropriate key sequence */
17899 keybd_event(VK_LWIN, 0, 0, 0);
17900 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
17902 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
17903 DispatchMessageA(&msg);
17905 ok_sequence(WmHotkeyPressLWIN, "thread hotkey press LWIN", FALSE);
17907 keybd_event(hotkey_letter, 0, 0, 0);
17908 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
17910 if (msg.message == WM_HOTKEY)
17912 struct recvd_message message;
17913 ok(msg.hwnd == NULL, "unexpected hwnd %p\n", msg.hwnd);
17914 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %Ix\n", msg.lParam);
17915 message.message = msg.message;
17916 message.flags = sent|wparam|lparam;
17917 message.wParam = msg.wParam;
17918 message.lParam = msg.lParam;
17919 message.descr = "test_hotkey thread message";
17920 add_message(&message);
17922 else
17923 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
17924 DispatchMessageA(&msg);
17926 ok_sequence(WmHotkeyPress, "thread hotkey press", FALSE);
17928 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
17929 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
17931 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
17932 DispatchMessageA(&msg);
17934 ok_sequence(WmHotkeyRelease, "thread hotkey release", TRUE);
17936 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
17937 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
17939 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
17940 DispatchMessageA(&msg);
17942 ok_sequence(WmHotkeyReleaseLWIN, "thread hotkey release LWIN", FALSE);
17944 /* Search for an ALT + letter combination that hasn't been registered */
17945 for (hotkey_letter = 0x41; hotkey_letter <= 0x51; hotkey_letter ++)
17947 SetLastError(0xdeadbeef);
17948 ret = RegisterHotKey(test_window, 6, MOD_ALT, hotkey_letter);
17950 if (ret == TRUE)
17952 break;
17954 else
17956 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
17957 "unexpected error %ld\n", GetLastError());
17961 if (hotkey_letter == 0x52)
17963 ok(0, "Couldn't find any free ALT + letter combination\n");
17964 goto end;
17967 keybd_event(VK_LMENU, 0, 0, 0);
17968 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
17969 DispatchMessageA(&msg);
17970 ok_sequence(WmHotkeyPressALT, "window hotkey press ALT", TRUE);
17972 keybd_event(hotkey_letter, 0, 0, 0);
17973 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
17975 if (msg.message == WM_HOTKEY)
17977 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
17978 ok(msg.lParam == MAKELPARAM(MOD_ALT, hotkey_letter), "unexpected WM_HOTKEY lparam %Ix\n", msg.lParam);
17980 DispatchMessageA(&msg);
17982 ok_sequence(WmHotkeyPressWithALT, "window hotkey press with ALT", FALSE);
17984 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
17985 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
17986 DispatchMessageA(&msg);
17987 ok_sequence(WmHotkeyReleaseWithALT, "window hotkey release with ALT", TRUE);
17989 keybd_event(VK_LMENU, 0, KEYEVENTF_KEYUP, 0);
17990 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
17991 DispatchMessageA(&msg);
17992 ok_sequence(WmHotkeyReleaseALT, "window hotkey release ALT", FALSE);
17994 /* Unregister thread hotkey */
17995 ret = UnregisterHotKey(NULL, 5);
17996 ok(ret == TRUE, "expected TRUE, got %i, err=%ld\n", ret, GetLastError());
17998 if (hKBD_hook) UnhookWindowsHookEx(hKBD_hook);
17999 hKBD_hook = NULL;
18001 end:
18002 UnregisterHotKey(NULL, 5);
18003 UnregisterHotKey(test_window, 5);
18004 UnregisterHotKey(test_window, 6);
18005 DestroyWindow(test_window);
18006 flush_sequence();
18010 static const struct message WmSetFocus_1[] = {
18011 { HCBT_SETFOCUS, hook }, /* child */
18012 { HCBT_ACTIVATE, hook }, /* parent */
18013 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
18014 { WM_QUERYNEWPALETTE, sent|wparam|lparam|parent|optional, 0, 0 },
18015 { WM_WINDOWPOSCHANGING, sent|parent, 0, SWP_NOSIZE|SWP_NOMOVE },
18016 { WM_ACTIVATEAPP, sent|wparam|parent, 1 },
18017 { WM_NCACTIVATE, sent|parent },
18018 { WM_GETTEXT, sent|defwinproc|parent|optional },
18019 { WM_GETTEXT, sent|defwinproc|parent|optional },
18020 { WM_ACTIVATE, sent|wparam|parent, 1 },
18021 { HCBT_SETFOCUS, hook }, /* parent */
18022 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
18023 { WM_SETFOCUS, sent|defwinproc|parent },
18024 { WM_KILLFOCUS, sent|parent },
18025 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
18026 { WM_SETFOCUS, sent },
18027 { 0 }
18029 static const struct message WmSetFocus_2[] = {
18030 { HCBT_SETFOCUS, hook }, /* parent */
18031 { WM_KILLFOCUS, sent },
18032 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
18033 { WM_SETFOCUS, sent|parent },
18034 { 0 }
18036 static const struct message WmSetFocus_3[] = {
18037 { HCBT_SETFOCUS, hook }, /* child */
18038 { 0 }
18041 static void test_SetFocus(void)
18043 HWND parent, old_parent, child, old_focus, old_active;
18044 MSG msg;
18045 struct wnd_event wnd_event;
18046 HANDLE hthread;
18047 DWORD ret, tid;
18049 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
18050 ok(wnd_event.start_event != 0, "CreateEvent error %ld\n", GetLastError());
18051 hthread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
18052 ok(hthread != 0, "CreateThread error %ld\n", GetLastError());
18053 ret = WaitForSingleObject(wnd_event.start_event, INFINITE);
18054 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
18055 CloseHandle(wnd_event.start_event);
18057 parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
18058 0, 0, 0, 0, 0, 0, 0, NULL);
18059 ok(parent != 0, "failed to create parent window\n");
18060 child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
18061 0, 0, 0, 0, parent, 0, 0, NULL);
18062 ok(child != 0, "failed to create child window\n");
18064 trace("parent %p, child %p, thread window %p\n", parent, child, wnd_event.hwnd);
18066 SetFocus(0);
18067 SetActiveWindow(0);
18069 flush_events();
18070 flush_sequence();
18072 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
18073 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
18075 log_all_parent_messages++;
18077 old_focus = SetFocus(child);
18078 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
18079 ok_sequence(WmSetFocus_1, "SetFocus on a child window", TRUE);
18080 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
18081 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
18082 ok(GetFocus() == child, "expected focus %p, got %p\n", child, GetFocus());
18084 old_focus = SetFocus(parent);
18085 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
18086 ok_sequence(WmSetFocus_2, "SetFocus on a parent window", FALSE);
18087 ok(old_focus == child, "expected old focus %p, got %p\n", child, old_focus);
18088 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
18089 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
18091 SetLastError(0xdeadbeef);
18092 old_focus = SetFocus((HWND)0xdeadbeef);
18093 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
18094 "expected ERROR_INVALID_WINDOW_HANDLE, got %ld\n", GetLastError());
18095 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
18096 ok_sequence(WmEmptySeq, "SetFocus on an invalid window", FALSE);
18097 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
18098 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
18099 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
18101 SetLastError(0xdeadbeef);
18102 old_focus = SetFocus(GetDesktopWindow());
18103 ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
18104 broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
18105 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
18106 ok_sequence(WmEmptySeq, "SetFocus on a desktop window", TRUE);
18107 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
18108 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
18109 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
18111 SetLastError(0xdeadbeef);
18112 old_focus = SetFocus(wnd_event.hwnd);
18113 ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
18114 broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
18115 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
18116 ok_sequence(WmEmptySeq, "SetFocus on another thread window", TRUE);
18117 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
18118 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
18119 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
18121 SetLastError(0xdeadbeef);
18122 old_active = SetActiveWindow((HWND)0xdeadbeef);
18123 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
18124 "expected ERROR_INVALID_WINDOW_HANDLE, got %ld\n", GetLastError());
18125 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
18126 ok_sequence(WmEmptySeq, "SetActiveWindow on an invalid window", FALSE);
18127 ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
18128 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
18129 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
18131 SetLastError(0xdeadbeef);
18132 old_active = SetActiveWindow(GetDesktopWindow());
18133 todo_wine
18134 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
18135 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
18136 ok_sequence(WmEmptySeq, "SetActiveWindow on a desktop window", TRUE);
18137 ok(old_active == 0, "expected old focus 0, got %p\n", old_focus);
18138 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
18139 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
18141 SetLastError(0xdeadbeef);
18142 old_active = SetActiveWindow(wnd_event.hwnd);
18143 todo_wine
18144 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
18145 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
18146 ok_sequence(WmEmptySeq, "SetActiveWindow on another thread window", TRUE);
18147 ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
18148 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
18149 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
18151 SetLastError(0xdeadbeef);
18152 ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE);
18153 ok(ret, "AttachThreadInput error %ld\n", GetLastError());
18155 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
18156 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
18158 flush_events();
18159 flush_sequence();
18161 old_focus = SetFocus(wnd_event.hwnd);
18162 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
18163 ok(old_focus == wnd_event.hwnd, "expected old focus %p, got %p\n", wnd_event.hwnd, old_focus);
18164 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
18165 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
18167 old_focus = SetFocus(parent);
18168 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
18169 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
18170 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
18171 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
18173 flush_events();
18174 flush_sequence();
18176 old_active = SetActiveWindow(wnd_event.hwnd);
18177 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
18178 ok(old_active == parent, "expected old focus %p, got %p\n", parent, old_active);
18179 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
18180 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
18182 SetLastError(0xdeadbeef);
18183 ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE);
18184 ok(ret, "AttachThreadInput error %ld\n", GetLastError());
18186 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
18187 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
18189 old_parent = SetParent(child, GetDesktopWindow());
18190 ok(old_parent == parent, "expected old parent %p, got %p\n", parent, old_parent);
18192 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
18193 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
18195 old_focus = SetFocus(parent);
18196 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
18197 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
18198 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
18199 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
18201 flush_events();
18202 flush_sequence();
18204 SetLastError(0xdeadbeef);
18205 old_focus = SetFocus(child);
18206 todo_wine
18207 ok(GetLastError() == ERROR_INVALID_PARAMETER /* Vista+ */ ||
18208 broken(GetLastError() == 0) /* XP */ ||
18209 broken(GetLastError() == 0xdeadbeef), "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
18210 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
18211 ok_sequence(WmSetFocus_3, "SetFocus on a child window", TRUE);
18212 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
18213 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
18214 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
18216 SetLastError(0xdeadbeef);
18217 old_active = SetActiveWindow(child);
18218 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
18219 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
18220 ok_sequence(WmEmptySeq, "SetActiveWindow on a child window", FALSE);
18221 ok(old_active == parent, "expected old active %p, got %p\n", parent, old_active);
18222 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
18223 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
18225 log_all_parent_messages--;
18227 DestroyWindow(child);
18228 DestroyWindow(parent);
18230 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
18231 ok(ret, "PostMessage(WM_QUIT) error %ld\n", GetLastError());
18232 ret = WaitForSingleObject(hthread, INFINITE);
18233 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
18234 CloseHandle(hthread);
18237 static const struct message WmSetLayeredStyle[] = {
18238 { WM_STYLECHANGING, sent },
18239 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
18240 { WM_STYLECHANGED, sent },
18241 { WM_GETTEXT, sent|defwinproc|optional },
18242 { 0 }
18245 static const struct message WmSetLayeredStyle2[] = {
18246 { WM_STYLECHANGING, sent },
18247 { WM_STYLECHANGED, sent },
18248 { WM_WINDOWPOSCHANGING, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
18249 { WM_NCCALCSIZE, sent|optional|wparam|defwinproc, 1 },
18250 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
18251 { WM_WINDOWPOSCHANGED, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
18252 { WM_MOVE, sent|optional|defwinproc|wparam, 0 },
18253 { WM_SIZE, sent|optional|defwinproc|wparam, SIZE_RESTORED },
18254 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
18255 { 0 }
18258 static const struct message WmLayeredWinEmptySeq[] = {
18259 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
18260 { 0 }
18263 struct layered_window_info
18265 HWND hwnd;
18266 HDC hdc;
18267 SIZE size;
18268 HANDLE event;
18269 BOOL ret;
18272 static DWORD CALLBACK update_layered_proc( void *param )
18274 struct layered_window_info *info = param;
18275 POINT src = { 0, 0 };
18277 info->ret = pUpdateLayeredWindow( info->hwnd, 0, NULL, &info->size,
18278 info->hdc, &src, 0, NULL, ULW_OPAQUE );
18279 ok( info->ret, "failed\n");
18280 SetEvent( info->event );
18281 return 0;
18284 static void test_layered_window(void)
18286 HWND hwnd;
18287 HDC hdc;
18288 HBITMAP bmp;
18289 BOOL ret;
18290 SIZE size;
18291 POINT pos, src;
18292 RECT rect, client;
18293 HANDLE thread;
18294 DWORD tid;
18295 struct layered_window_info info;
18297 if (!pUpdateLayeredWindow)
18299 win_skip( "UpdateLayeredWindow not supported\n" );
18300 return;
18303 hdc = CreateCompatibleDC( 0 );
18304 bmp = CreateCompatibleBitmap( hdc, 300, 300 );
18305 SelectObject( hdc, bmp );
18307 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_CAPTION | WS_THICKFRAME | WS_SYSMENU,
18308 100, 100, 300, 300, 0, 0, 0, NULL);
18309 ok( hwnd != 0, "failed to create window\n" );
18310 ShowWindow( hwnd, SW_SHOWNORMAL );
18311 UpdateWindow( hwnd );
18312 flush_events();
18313 flush_sequence();
18315 GetWindowRect( hwnd, &rect );
18316 GetClientRect( hwnd, &client );
18317 ok( client.right < rect.right - rect.left, "wrong client area\n" );
18318 ok( client.bottom < rect.bottom - rect.top, "wrong client area\n" );
18320 src.x = src.y = 0;
18321 pos.x = pos.y = 300;
18322 size.cx = size.cy = 250;
18323 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
18324 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
18325 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() );
18326 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
18327 ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
18329 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
18330 ok( ret, "UpdateLayeredWindow failed err %lu\n", GetLastError() );
18331 ok_sequence( WmLayeredWinEmptySeq, "UpdateLayeredWindow", FALSE );
18332 GetWindowRect( hwnd, &rect );
18333 ok( rect.left == 300 && rect.top == 300 && rect.right == 550 && rect.bottom == 550,
18334 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
18335 GetClientRect( hwnd, &rect );
18336 ok( rect.right == client.right - 50 && rect.bottom == client.bottom - 50,
18337 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
18339 size.cx = 150;
18340 pos.y = 200;
18341 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
18342 ok( ret, "UpdateLayeredWindow failed err %lu\n", GetLastError() );
18343 ok_sequence( WmLayeredWinEmptySeq, "UpdateLayeredWindow", FALSE );
18344 GetWindowRect( hwnd, &rect );
18345 ok( rect.left == 300 && rect.top == 200 && rect.right == 450 && rect.bottom == 450,
18346 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
18347 GetClientRect( hwnd, &rect );
18348 ok( rect.right == client.right - 150 && rect.bottom == client.bottom - 50,
18349 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
18351 SetWindowLongA( hwnd, GWL_STYLE,
18352 GetWindowLongA(hwnd, GWL_STYLE) & ~(WS_CAPTION | WS_THICKFRAME | WS_SYSMENU) );
18353 ok_sequence( WmSetLayeredStyle2, "WmSetLayeredStyle2", FALSE );
18355 size.cx = 200;
18356 pos.x = 200;
18357 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
18358 ok( ret, "UpdateLayeredWindow failed err %lu\n", GetLastError() );
18359 ok_sequence( WmLayeredWinEmptySeq, "UpdateLayeredWindow", FALSE );
18360 GetWindowRect( hwnd, &rect );
18361 ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
18362 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
18363 GetClientRect( hwnd, &rect );
18364 ok( (rect.right == 200 && rect.bottom == 250) ||
18365 broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
18366 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
18368 size.cx = 0;
18369 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
18370 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
18371 ok( GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == ERROR_MR_MID_NOT_FOUND) ||
18372 broken(GetLastError() == ERROR_GEN_FAILURE) /* win7 */, "wrong error %lu\n", GetLastError() );
18373 size.cx = 1;
18374 size.cy = -1;
18375 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
18376 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
18377 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() );
18379 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED );
18380 ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
18381 GetWindowRect( hwnd, &rect );
18382 ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
18383 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
18384 GetClientRect( hwnd, &rect );
18385 ok( (rect.right == 200 && rect.bottom == 250) ||
18386 broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
18387 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
18389 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
18390 info.hwnd = hwnd;
18391 info.hdc = hdc;
18392 info.size.cx = 250;
18393 info.size.cy = 300;
18394 info.event = CreateEventA( NULL, TRUE, FALSE, NULL );
18395 info.ret = FALSE;
18396 thread = CreateThread( NULL, 0, update_layered_proc, &info, 0, &tid );
18397 ok( WaitForSingleObject( info.event, 1000 ) == 0, "wait failed\n" );
18398 ok( info.ret, "UpdateLayeredWindow failed in other thread\n" );
18399 WaitForSingleObject( thread, 1000 );
18400 CloseHandle( thread );
18401 GetWindowRect( hwnd, &rect );
18402 ok( rect.left == 200 && rect.top == 200 && rect.right == 450 && rect.bottom == 500,
18403 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
18404 GetClientRect( hwnd, &rect );
18405 ok( (rect.right == 250 && rect.bottom == 300) ||
18406 broken(rect.right == client.right - 50 && rect.bottom == client.bottom),
18407 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
18409 DestroyWindow( hwnd );
18410 DeleteDC( hdc );
18411 DeleteObject( bmp );
18414 static HMENU hpopupmenu;
18416 static LRESULT WINAPI minimize_popup_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
18418 LRESULT ret;
18420 if (ignore_message( message )) return 0;
18421 ret = MsgCheckProc( FALSE, hwnd, message, wParam, lParam );
18423 switch (message) {
18424 case WM_ENTERIDLE:
18425 ShowWindow(hwnd, SW_MINIMIZE);
18426 break;
18427 case WM_TIMER:
18428 EndMenu();
18429 break;
18432 return ret;
18435 static LRESULT WINAPI cancel_popup_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
18437 if (ignore_message( message )) return 0;
18439 switch (message) {
18440 case WM_ENTERIDLE:
18441 todo_wine ok(GetCapture() == hwnd, "expected %p, got %p\n", hwnd, GetCapture());
18442 EndMenu();
18443 break;
18444 case WM_INITMENU:
18445 case WM_INITMENUPOPUP:
18446 case WM_UNINITMENUPOPUP:
18447 ok((HMENU)wParam == hpopupmenu, "expected %p, got %Ix\n", hpopupmenu, wParam);
18448 break;
18449 case WM_CAPTURECHANGED:
18450 todo_wine ok(!lParam || (HWND)lParam == hwnd, "lost capture to %Ix\n", lParam);
18451 break;
18454 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
18457 static LRESULT WINAPI cancel_init_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
18459 if (ignore_message( message )) return 0;
18461 switch (message) {
18462 case WM_ENTERMENULOOP:
18463 ok(EndMenu() == TRUE, "EndMenu() failed\n");
18464 break;
18467 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
18470 static void test_TrackPopupMenu(void)
18472 MSG msg;
18473 HWND hwnd;
18474 BOOL ret;
18476 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
18477 0, 0, 1, 1, 0,
18478 NULL, NULL, 0);
18479 ok(hwnd != NULL, "CreateWindowEx failed with error %ld\n", GetLastError());
18481 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
18483 hpopupmenu = CreatePopupMenu();
18484 ok(hpopupmenu != NULL, "CreateMenu failed with error %ld\n", GetLastError());
18486 AppendMenuA(hpopupmenu, MF_STRING, 100, "item 1");
18487 AppendMenuA(hpopupmenu, MF_STRING, 100, "item 2");
18489 flush_events();
18490 flush_sequence();
18491 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
18492 ok_sequence(WmTrackPopupMenu, "TrackPopupMenu", TRUE);
18493 ok(ret == 1, "TrackPopupMenu failed with error %li\n", GetLastError());
18495 /* Test popup closing with an ESC-press */
18496 flush_events();
18497 PostMessageW(hwnd, WM_KEYDOWN, VK_ESCAPE, 0);
18498 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
18499 ok(ret == 1, "TrackPopupMenu failed with error %li\n", GetLastError());
18500 PostQuitMessage(0);
18501 flush_sequence();
18502 while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
18504 TranslateMessage(&msg);
18505 DispatchMessageA(&msg);
18507 ok_sequence(WmTrackPopupMenuEsc, "TrackPopupMenuEsc", FALSE); /* Shouldn't get any message */
18509 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_init_proc);
18511 flush_events();
18512 flush_sequence();
18513 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
18514 ok_sequence(WmTrackPopupMenuAbort, "WmTrackPopupMenuAbort", TRUE);
18515 ok(ret == TRUE, "TrackPopupMenu failed\n");
18517 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)minimize_popup_proc);
18519 /* set cursor over the window, otherwise the WM_CANCELMODE message may not always be sent */
18520 SetCursorPos( 0, 0 );
18521 ShowWindow( hwnd, SW_SHOW );
18523 flush_events();
18524 flush_sequence();
18525 SetTimer( hwnd, TIMER_ID, 500, NULL );
18526 ret = TrackPopupMenu( hpopupmenu, 0, 100,100, 0, hwnd, NULL );
18527 ok_sequence( WmTrackPopupMenuMinimizeWindow, "TrackPopupMenuMinimizeWindow", TRUE );
18528 ok( ret == 1, "TrackPopupMenu failed with error %li\n", GetLastError() );
18529 KillTimer( hwnd, TIMER_ID );
18530 ShowWindow( hwnd, SW_RESTORE );
18532 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
18534 SetCapture(hwnd);
18536 flush_events();
18537 flush_sequence();
18538 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
18539 ok_sequence(WmTrackPopupMenuCapture, "TrackPopupMenuCapture", TRUE);
18540 ok(ret == 1, "TrackPopupMenuCapture failed with error %li\n", GetLastError());
18542 DestroyMenu(hpopupmenu);
18543 DestroyWindow(hwnd);
18546 static void test_TrackPopupMenuEmpty(void)
18548 HWND hwnd;
18549 BOOL ret;
18551 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
18552 0, 0, 1, 1, 0,
18553 NULL, NULL, 0);
18554 ok(hwnd != NULL, "CreateWindowEx failed with error %ld\n", GetLastError());
18556 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
18558 hpopupmenu = CreatePopupMenu();
18559 ok(hpopupmenu != NULL, "CreateMenu failed with error %ld\n", GetLastError());
18561 flush_events();
18562 flush_sequence();
18563 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
18564 ok_sequence(WmTrackPopupMenuEmpty, "TrackPopupMenuEmpty", TRUE);
18565 ok(ret == 0, "TrackPopupMenu succeeded\n");
18567 DestroyMenu(hpopupmenu);
18568 DestroyWindow(hwnd);
18571 static const struct message send_message_1[] = {
18572 { WM_USER+2, sent|wparam|lparam, 0, 0 },
18573 { WM_USER, sent|wparam|lparam, 0, 0 },
18574 { 0 }
18576 static const struct message send_message_2[] = {
18577 { WM_USER+4, sent|wparam|lparam, 0, 0 },
18578 { 0 }
18580 static const struct message send_message_3[] = {
18581 { WM_USER+3, sent|wparam|lparam, 0, 0 },
18582 { WM_USER+1, sent|wparam|lparam, 0, 0 },
18583 { 0 }
18586 static DWORD WINAPI SendMessage_thread_1(void *param)
18588 struct wnd_event *wnd_event = param;
18590 trace("thread: starting\n");
18591 WaitForSingleObject(wnd_event->start_event, INFINITE);
18593 trace("thread: call PostMessage\n");
18594 PostMessageA(wnd_event->hwnd, WM_USER, 0, 0);
18596 trace("thread: call PostMessage\n");
18597 PostMessageA(wnd_event->hwnd, WM_USER+1, 0, 0);
18599 trace("thread: call SendMessage\n");
18600 SendMessageA(wnd_event->hwnd, WM_USER+2, 0, 0);
18601 SetEvent(wnd_event->stop_event);
18603 trace("thread: call SendMessage\n");
18604 SendMessageA(wnd_event->hwnd, WM_USER+3, 0, 0);
18606 return 0;
18609 static DWORD WINAPI SendMessage_thread_2(void *param)
18611 struct wnd_event *wnd_event = param;
18613 trace("thread: starting\n");
18614 WaitForSingleObject(wnd_event->start_event, INFINITE);
18616 trace("thread: call PostMessage\n");
18617 PostMessageA(wnd_event->hwnd, WM_USER, 0, 0);
18619 trace("thread: call PostMessage\n");
18620 PostMessageA(wnd_event->hwnd, WM_USER+1, 0, 0);
18622 /* this leads to sending an internal message under Wine */
18623 trace("thread: call SetParent\n");
18624 SetParent(wnd_event->hwnd, wnd_event->hwnd);
18626 trace("thread: call SendMessage\n");
18627 SendMessageA(wnd_event->hwnd, WM_USER+2, 0, 0);
18628 SetEvent(wnd_event->stop_event);
18630 trace("thread: call SendMessage\n");
18631 SendMessageA(wnd_event->hwnd, WM_USER+3, 0, 0);
18633 return 0;
18636 static void test_SendMessage_other_thread(int thread_n)
18638 DWORD qs_all_input = QS_ALLINPUT & ~QS_RAWINPUT;
18639 HANDLE hthread;
18640 struct wnd_event wnd_event;
18641 DWORD tid, ret;
18642 MSG msg;
18644 wnd_event.start_event = CreateEventA(NULL, 0, 0, NULL);
18645 wnd_event.stop_event = CreateEventA(NULL, 0, 0, NULL);
18647 wnd_event.hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
18648 100, 100, 200, 200, 0, 0, 0, NULL);
18649 ok(wnd_event.hwnd != 0, "CreateWindowEx failed\n");
18651 hthread = CreateThread(NULL, 0, thread_n == 1 ? SendMessage_thread_1 : SendMessage_thread_2, &wnd_event, 0, &tid);
18652 ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError());
18653 CloseHandle(hthread);
18655 flush_events();
18656 flush_sequence();
18658 ret = GetQueueStatus(QS_SENDMESSAGE);
18659 ok(ret == 0, "wrong status %08lx\n", ret);
18661 SetEvent(wnd_event.start_event);
18663 /* wait for other thread's SendMessage */
18664 for (;;)
18666 ret = GetQueueStatus(QS_SENDMESSAGE);
18667 if (ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE)) break;
18668 Sleep(50);
18671 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
18672 ok(ret == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08lx\n", ret);
18674 trace("main: call GetMessage\n");
18675 GetMessageA(&msg, 0, 0, 0);
18676 ok(msg.message == WM_USER, "expected WM_USER, got %04x\n", msg.message);
18677 DispatchMessageA(&msg);
18678 ok_sequence(send_message_1, "SendMessage from other thread 1", thread_n == 2);
18680 ret = WaitForSingleObject(wnd_event.stop_event, 100);
18681 todo_wine_if (thread_n == 2)
18682 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed, ret:%lx\n", ret);
18684 /* intentionally yield */
18685 MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input);
18687 trace("main: call SendMessage\n");
18688 SendMessageA(wnd_event.hwnd, WM_USER+4, 0, 0);
18689 ok_sequence(send_message_2, "SendMessage from other thread 2", FALSE);
18691 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
18692 ok(ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08lx\n", ret);
18694 trace("main: call PeekMessage\n");
18695 ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should not fail\n");
18696 ok(msg.message == WM_USER+1, "expected WM_USER+1, got %04x\n", msg.message);
18697 DispatchMessageA(&msg);
18698 ok_sequence(send_message_3, "SendMessage from other thread 3", thread_n == 2);
18700 /* intentionally yield */
18701 MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input);
18703 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
18704 /* FIXME: remove once Wine is fixed */
18705 todo_wine_if (thread_n == 2)
18706 ok(ret == 0, "wrong status %08lx\n", ret);
18708 trace("main: call PeekMessage\n");
18709 ok(!PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should fail\n");
18710 ok_sequence(WmEmptySeq, "SendMessage from other thread 5", thread_n == 2);
18712 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
18713 ok(ret == 0, "wrong status %08lx\n", ret);
18715 trace("main: call DestroyWindow\n");
18716 DestroyWindow(msg.hwnd);
18718 flush_events();
18719 flush_sequence();
18721 CloseHandle(wnd_event.start_event);
18722 CloseHandle(wnd_event.stop_event);
18725 static LRESULT CALLBACK insendmessage_wnd_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
18727 DWORD flags = InSendMessageEx( NULL );
18728 BOOL ret;
18730 switch (msg)
18732 case WM_USER:
18733 ok( flags == ISMEX_SEND, "wrong flags %lx\n", flags );
18734 ok( InSendMessage(), "InSendMessage returned false\n" );
18735 ret = ReplyMessage( msg );
18736 ok( ret, "ReplyMessage failed err %lu\n", GetLastError() );
18737 flags = InSendMessageEx( NULL );
18738 ok( flags == (ISMEX_SEND | ISMEX_REPLIED), "wrong flags %lx\n", flags );
18739 ok( InSendMessage(), "InSendMessage returned false\n" );
18740 break;
18741 case WM_USER + 1:
18742 ok( flags == ISMEX_NOTIFY, "wrong flags %lx\n", flags );
18743 ok( InSendMessage(), "InSendMessage returned false\n" );
18744 ret = ReplyMessage( msg );
18745 ok( ret, "ReplyMessage failed err %lu\n", GetLastError() );
18746 flags = InSendMessageEx( NULL );
18747 ok( flags == ISMEX_NOTIFY, "wrong flags %lx\n", flags );
18748 ok( InSendMessage(), "InSendMessage returned false\n" );
18749 break;
18750 case WM_USER + 2:
18751 ok( flags == ISMEX_CALLBACK, "wrong flags %lx\n", flags );
18752 ok( InSendMessage(), "InSendMessage returned false\n" );
18753 ret = ReplyMessage( msg );
18754 ok( ret, "ReplyMessage failed err %lu\n", GetLastError() );
18755 flags = InSendMessageEx( NULL );
18756 ok( flags == (ISMEX_CALLBACK | ISMEX_REPLIED) || flags == ISMEX_SEND, "wrong flags %lx\n", flags );
18757 ok( InSendMessage(), "InSendMessage returned false\n" );
18758 break;
18759 case WM_USER + 3:
18760 ok( flags == ISMEX_NOSEND, "wrong flags %lx\n", flags );
18761 ok( !InSendMessage(), "InSendMessage returned true\n" );
18762 ret = ReplyMessage( msg );
18763 ok( !ret, "ReplyMessage succeeded\n" );
18764 break;
18767 return DefWindowProcA( hwnd, msg, wp, lp );
18770 static void CALLBACK msg_callback( HWND hwnd, UINT msg, ULONG_PTR arg, LRESULT result )
18772 ok( msg == WM_USER + 2, "wrong msg %x\n", msg );
18773 ok( result == WM_USER + 2, "wrong result %Ix\n", result );
18776 static DWORD WINAPI send_message_thread( void *arg )
18778 HWND win = arg;
18780 SendMessageA( win, WM_USER, 0, 0 );
18781 SendNotifyMessageA( win, WM_USER + 1, 0, 0 );
18782 SendMessageCallbackA( win, WM_USER + 2, 0, 0, msg_callback, 0 );
18783 PostMessageA( win, WM_USER + 3, 0, 0 );
18784 PostMessageA( win, WM_QUIT, 0, 0 );
18785 return 0;
18788 static void test_InSendMessage(void)
18790 WNDCLASSA cls;
18791 HWND win;
18792 MSG msg;
18793 HANDLE thread;
18794 DWORD tid;
18796 memset(&cls, 0, sizeof(cls));
18797 cls.lpfnWndProc = insendmessage_wnd_proc;
18798 cls.hInstance = GetModuleHandleA(NULL);
18799 cls.lpszClassName = "InSendMessage_test";
18800 RegisterClassA(&cls);
18802 win = CreateWindowA( "InSendMessage_test", NULL, 0, 0, 0, 0, 0, NULL, 0, NULL, 0 );
18803 ok( win != NULL, "CreateWindow failed: %ld\n", GetLastError() );
18805 thread = CreateThread( NULL, 0, send_message_thread, win, 0, &tid );
18806 ok( thread != NULL, "CreateThread failed: %ld\n", GetLastError() );
18808 while (GetMessageA(&msg, NULL, 0, 0)) DispatchMessageA( &msg );
18810 ok( WaitForSingleObject( thread, 30000 ) == WAIT_OBJECT_0, "WaitForSingleObject failed\n" );
18811 CloseHandle( thread );
18813 DestroyWindow( win );
18814 UnregisterClassA( "InSendMessage_test", GetModuleHandleA(NULL) );
18817 static const struct message DoubleSetCaptureSeq[] =
18819 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
18820 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
18821 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
18822 { WM_CAPTURECHANGED, sent },
18823 { 0 }
18826 static void test_DoubleSetCapture(void)
18828 HWND hwnd;
18830 hwnd = CreateWindowExA(0, "TestWindowClass", "Test DoubleSetCapture",
18831 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
18832 100, 100, 200, 200, 0, 0, 0, NULL);
18833 ok (hwnd != 0, "Failed to create overlapped window\n");
18835 ShowWindow( hwnd, SW_SHOW );
18836 UpdateWindow( hwnd );
18837 flush_events();
18838 flush_sequence();
18840 SetCapture( hwnd );
18841 SetCapture( hwnd );
18842 ok_sequence(DoubleSetCaptureSeq, "SetCapture( hwnd ) twice", FALSE);
18844 DestroyWindow(hwnd);
18847 static const struct message WmRestoreMinimizedSeq[] =
18849 { HCBT_ACTIVATE, hook },
18850 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
18851 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
18852 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
18853 { WM_ACTIVATEAPP, sent|wparam, 1 },
18854 { WM_NCACTIVATE, sent|wparam, 0x200001 },
18855 { WM_GETTEXT, sent|defwinproc|optional },
18856 { WM_ACTIVATE, sent|wparam, 0x200001 }, /* Note that activate messages are after WM_WINDOWPOSCHANGED and before WM_SYSCOMMAND */
18857 { HCBT_KEYSKIPPED, hook|optional },
18858 { WM_SYSKEYUP, sent|optional },
18859 { WM_SYSCOMMAND, sent|wparam, SC_RESTORE },
18860 { HCBT_SYSCOMMAND, hook|wparam, SC_RESTORE },
18861 { HCBT_SYSCOMMAND, hook|wparam|optional, SC_RESTORE },
18862 { HCBT_MINMAX, hook },
18863 { HCBT_MINMAX, hook|optional },
18864 { WM_QUERYOPEN, sent|defwinproc },
18865 { WM_QUERYOPEN, sent|optional },
18866 { WM_GETTEXT, sent|defwinproc|optional },
18867 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
18868 { WM_GETMINMAXINFO, sent|defwinproc },
18869 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
18870 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
18871 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
18872 { WM_GETTEXT, sent|defwinproc|optional },
18873 { WM_ERASEBKGND, sent|defwinproc },
18874 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
18875 { WM_MOVE, sent|defwinproc },
18876 { WM_SIZE, sent|defwinproc },
18877 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
18878 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
18879 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
18880 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
18881 { WM_ERASEBKGND, sent|defwinproc|optional },
18882 { HCBT_SETFOCUS, hook },
18883 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
18884 { WM_SETFOCUS, sent|defwinproc },
18885 { WM_ACTIVATE, sent|wparam|defwinproc, 1 },
18886 { WM_PAINT, sent| optional },
18887 { WM_SETFOCUS, sent|defwinproc|optional },
18888 { HCBT_KEYSKIPPED, hook|optional },
18889 { WM_KEYUP, sent|optional },
18890 { HCBT_KEYSKIPPED, hook|optional },
18891 { WM_SYSKEYUP, sent|optional },
18892 { HCBT_KEYSKIPPED, hook|optional },
18893 { WM_KEYUP, sent|optional },
18894 { HCBT_KEYSKIPPED, hook|optional },
18895 { WM_SYSKEYUP, sent|optional },
18896 { HCBT_KEYSKIPPED, hook|optional },
18897 { WM_KEYUP, sent|optional },
18898 { WM_PAINT, sent| optional },
18899 { 0 }
18902 static void test_restore_messages(void)
18904 INPUT ip = {0};
18905 HWND hwnd;
18906 INT i;
18908 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100,
18909 100, 200, 200, 0, 0, 0, NULL);
18910 ok (hwnd != 0, "Failed to create overlapped window\n");
18911 SetForegroundWindow(hwnd);
18912 ShowWindow(hwnd, SW_MINIMIZE);
18913 flush_events();
18914 flush_sequence();
18916 for (i = 0; i < 5; i++)
18918 /* Send Alt+Tab to restore test window from minimized state */
18919 ip.type = INPUT_KEYBOARD;
18920 ip.ki.wVk = VK_MENU;
18921 SendInput(1, &ip, sizeof(INPUT));
18922 ip.ki.wVk = VK_TAB;
18923 SendInput(1, &ip, sizeof(INPUT));
18924 ip.ki.wVk = VK_MENU;
18925 ip.ki.dwFlags = KEYEVENTF_KEYUP;
18926 SendInput(1, &ip, sizeof(INPUT));
18927 ip.ki.wVk = VK_TAB;
18928 ip.ki.dwFlags = KEYEVENTF_KEYUP;
18929 SendInput(1, &ip, sizeof(INPUT));
18930 flush_events();
18931 if (!IsIconic(hwnd))
18932 break;
18935 if (IsIconic(hwnd))
18937 skip("Alt+Tab failed to bring up test window.\n");
18938 goto done;
18940 ok_sequence(WmRestoreMinimizedSeq, "Restore minimized window", TRUE);
18942 done:
18943 DestroyWindow(hwnd);
18946 static void test_invalid_window(void)
18948 MSG msg;
18949 BOOL ret;
18951 SetLastError(0xdeadbeef);
18952 ret = GetMessageA(&msg, (HWND)0xdeadbeef, 0, 0);
18953 ok(ret == -1, "wrong ret %d\n", ret);
18954 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %lu\n", GetLastError());
18956 SetLastError(0xdeadbeef);
18957 ret = PeekMessageA(&msg, (HWND)0xdeadbeef, 0, 0, PM_REMOVE);
18958 ok(!ret, "wrong ret %d\n", ret);
18959 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %lu\n", GetLastError());
18962 static void test_button_style(void)
18964 DWORD type, expected_type;
18965 HWND button;
18966 LRESULT ret;
18967 DWORD i, j;
18969 for (i = BS_PUSHBUTTON; i <= BS_DEFCOMMANDLINK; ++i)
18971 button = CreateWindowA(WC_BUTTONA, "test", i, 0, 0, 50, 50, NULL, 0, 0, NULL);
18972 ok(button != NULL, "Expected button not null.\n");
18974 type = GetWindowLongW(button, GWL_STYLE) & BS_TYPEMASK;
18975 expected_type = (i == BS_USERBUTTON ? BS_PUSHBUTTON : i);
18976 ok(type == expected_type, "Expected type %#lx, got %#lx.\n", expected_type, type);
18978 for (j = BS_PUSHBUTTON; j <= BS_DEFCOMMANDLINK; ++j)
18980 ret = SendMessageA(button, BM_SETSTYLE, j, FALSE);
18981 ok(ret == 0, "Expected %#x, got %#Ix.\n", 0, ret);
18983 type = GetWindowLongW(button, GWL_STYLE) & BS_TYPEMASK;
18984 expected_type = j;
18986 ok(type == expected_type, "Original type %#lx, expected new type %#lx, got %#lx.\n", i,
18987 expected_type, type);
18989 DestroyWindow(button);
18993 START_TEST(msg)
18995 char **test_argv;
18996 BOOL ret;
18997 BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
18998 int argc;
19000 argc = winetest_get_mainargs( &test_argv );
19001 if (argc >= 3)
19003 unsigned int arg;
19004 /* Child process. */
19005 sscanf (test_argv[2], "%d", (unsigned int *) &arg);
19006 do_wait_idle_child( arg );
19007 return;
19010 InitializeCriticalSection( &sequence_cs );
19011 init_procs();
19012 ImmDisableIME(0);
19014 if (!RegisterWindowClasses()) assert(0);
19016 if (pSetWinEventHook)
19018 hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
19019 GetModuleHandleA(0), win_event_proc,
19020 0, GetCurrentThreadId(),
19021 WINEVENT_INCONTEXT);
19022 if (pIsWinEventHookInstalled && hEvent_hook)
19024 UINT event;
19025 for (event = EVENT_MIN; event <= EVENT_MAX; event++)
19026 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
19029 if (!hEvent_hook) win_skip( "no win event hook support\n" );
19031 cbt_hook_thread_id = winevent_hook_thread_id = GetCurrentThreadId();
19032 hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
19033 if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
19035 test_winevents();
19036 test_SendMessage_other_thread(1);
19037 test_SendMessage_other_thread(2);
19038 test_InSendMessage();
19039 test_SetFocus();
19040 test_SetParent();
19041 test_PostMessage();
19042 test_broadcast();
19043 test_ShowWindow();
19044 test_PeekMessage();
19045 test_PeekMessage2();
19046 test_PeekMessage3();
19047 test_WaitForInputIdle( test_argv[0] );
19048 test_scrollwindowex();
19049 test_messages();
19050 test_setwindowpos();
19051 test_showwindow();
19052 invisible_parent_tests();
19053 test_mdi_messages();
19054 test_button_messages();
19055 test_button_bm_get_set_image();
19056 test_button_style();
19057 test_autoradio_BM_CLICK();
19058 test_autoradio_kbd_move();
19059 test_static_messages();
19060 test_listbox_messages();
19061 test_combobox_messages();
19062 test_wmime_keydown_message();
19063 test_paint_messages();
19064 test_interthread_messages();
19065 test_message_conversion();
19066 test_accelerators();
19067 test_timers();
19068 test_timers_no_wnd();
19069 test_timers_exceptions();
19070 if (hCBT_hook)
19072 test_set_hook();
19073 test_recursive_hook();
19075 test_DestroyWindow();
19076 test_DispatchMessage();
19077 test_SendMessageTimeout();
19078 test_edit_messages();
19079 test_quit_message();
19080 test_notify_message();
19081 test_SetActiveWindow();
19082 test_restore_messages();
19083 test_invalid_window();
19084 test_menu_messages();
19085 test_paintingloop();
19087 if (!pTrackMouseEvent)
19088 win_skip("TrackMouseEvent is not available\n");
19089 else
19090 test_TrackMouseEvent();
19092 test_SetWindowRgn();
19093 test_sys_menu();
19094 test_dialog_messages();
19095 test_EndDialog();
19096 test_nullCallback();
19097 test_dbcs_wm_char();
19098 test_unicode_wm_char();
19099 test_defwinproc();
19100 test_desktop_winproc();
19101 test_clipboard_viewers();
19102 test_keyflags();
19103 test_hotkey();
19104 test_layered_window();
19105 test_TrackPopupMenu();
19106 test_TrackPopupMenuEmpty();
19107 test_DoubleSetCapture();
19108 /* keep it the last test, under Windows it tends to break the tests
19109 * which rely on active/foreground windows being correct.
19111 test_SetForegroundWindow();
19113 UnhookWindowsHookEx(hCBT_hook);
19114 if (pUnhookWinEvent && hEvent_hook)
19116 ret = pUnhookWinEvent(hEvent_hook);
19117 ok( ret, "UnhookWinEvent error %ld\n", GetLastError());
19118 SetLastError(0xdeadbeef);
19119 ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
19120 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
19121 GetLastError() == 0xdeadbeef, /* Win9x */
19122 "unexpected error %ld\n", GetLastError());
19124 DeleteCriticalSection( &sequence_cs );