user32/tests: Accept another variation in send_message_5.
[wine.git] / dlls / user32 / tests / msg.c
blob8517ede31dd4aa9d7685aa8d9f750d348ff082e1
1 /*
2 * Unit tests for window message handling
4 * Copyright 1999 Ove Kaaven
5 * Copyright 2003 Dimitrie O. Paun
6 * Copyright 2004,2005,2016 Dmitry Timoshkov
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <limits.h>
24 #include <stdarg.h>
25 #include <stdbool.h>
26 #include <stdio.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "winuser.h"
32 #include "winnls.h"
33 #include "dbt.h"
34 #include "commctrl.h"
35 #include "imm.h"
37 #include "wine/test.h"
39 #define MDI_FIRST_CHILD_ID 2004
41 /* undocumented SWP flags - from SDK 3.1 */
42 #define SWP_NOCLIENTSIZE 0x0800
43 #define SWP_NOCLIENTMOVE 0x1000
44 #define SWP_STATECHANGED 0x8000
46 #define SW_NORMALNA 0xCC /* undoc. flag in MinMaximize */
48 #ifndef WM_KEYF1
49 #define WM_KEYF1 0x004d
50 #endif
52 #ifndef WM_SYSTIMER
53 #define WM_SYSTIMER 0x0118
54 #endif
56 #define WND_PARENT_ID 1
57 #define WND_POPUP_ID 2
58 #define WND_CHILD_ID 3
60 #ifndef WM_LBTRACKPOINT
61 #define WM_LBTRACKPOINT 0x0131
62 #endif
64 #ifdef __i386__
65 #define ARCH "x86"
66 #elif defined __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);
122 static void register_class(const WNDCLASSA *class)
124 BOOL ret = RegisterClassA(class);
125 ok(ret, "Failed to register class %s, error %lu.\n",
126 debugstr_a(class->lpszClassName), GetLastError());
130 FIXME: add tests for these
131 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
132 WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
133 WS_THICKFRAME: thick border
134 WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
135 WS_BORDER (default for overlapped windows): single black border
136 none (default for child (and popup?) windows): no border
139 typedef enum {
140 sent=0x1,
141 posted=0x2,
142 parent=0x4,
143 wparam=0x8,
144 lparam=0x10,
145 defwinproc=0x20,
146 beginpaint=0x40,
147 optional=0x80,
148 hook=0x100,
149 winevent_hook=0x200,
150 kbd_hook=0x400,
151 winevent_hook_todo=0x800
152 } msg_flags_t;
154 struct message {
155 UINT message; /* the WM_* code */
156 msg_flags_t flags; /* message props */
157 WPARAM wParam; /* expected value of wParam */
158 LPARAM lParam; /* expected value of lParam */
159 WPARAM wp_mask; /* mask for wParam checks */
160 LPARAM lp_mask; /* mask for lParam checks */
163 struct recvd_message {
164 UINT message; /* the WM_* code */
165 msg_flags_t flags; /* message props */
166 HWND hwnd; /* window that received the message */
167 WPARAM wParam; /* expected value of wParam */
168 LPARAM lParam; /* expected value of lParam */
169 int line; /* source line where logged */
170 const char *descr; /* description for trace output */
171 char output[512]; /* trace output */
174 /* Empty message sequence */
175 static const struct message WmEmptySeq[] =
177 { 0 }
179 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
180 static const struct message WmCreateOverlappedSeq[] = {
181 { HCBT_CREATEWND, hook },
182 { WM_GETMINMAXINFO, sent },
183 { WM_NCCREATE, sent },
184 { WM_NCCALCSIZE, sent|wparam, 0 },
185 { 0x0093, sent|defwinproc|optional },
186 { 0x0094, sent|defwinproc|optional },
187 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on win10. */
188 { WM_CREATE, sent },
189 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
190 { 0 }
192 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
193 * for a not visible overlapped window.
195 static const struct message WmSWP_ShowOverlappedSeq[] = {
196 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
197 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
198 { WM_NCPAINT, sent|wparam|optional, 1 },
199 { WM_GETTEXT, sent|defwinproc|optional },
200 { WM_ERASEBKGND, sent|optional },
201 { HCBT_ACTIVATE, hook },
202 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
203 { WM_NOTIFYFORMAT, sent|optional },
204 { WM_QUERYUISTATE, sent|optional },
205 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
206 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
207 { WM_ACTIVATEAPP, sent|wparam, 1 },
208 { WM_NCACTIVATE, sent },
209 { WM_GETTEXT, sent|defwinproc|optional },
210 { WM_ACTIVATE, sent|wparam, 1 },
211 { HCBT_SETFOCUS, hook },
212 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
213 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
214 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
215 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
216 { WM_GETTEXT, sent|optional },
217 { WM_NCPAINT, sent|wparam|optional, 1 },
218 { WM_GETTEXT, sent|defwinproc|optional },
219 { WM_ERASEBKGND, sent|optional },
220 /* Win9x adds SWP_NOZORDER below */
221 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
222 { WM_GETTEXT, sent|optional },
223 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
224 { WM_NCPAINT, sent|wparam|optional, 1 },
225 { WM_ERASEBKGND, sent|optional },
226 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on win10 */
227 { WM_SYNCPAINT, sent|optional },
228 { WM_GETTITLEBARINFOEX, sent|optional },
229 { WM_PAINT, sent|optional },
230 { WM_NCPAINT, sent|beginpaint|optional },
231 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
232 { WM_ERASEBKGND, sent|beginpaint|optional },
233 { 0 }
235 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
236 * for a visible overlapped window.
238 static const struct message WmSWP_HideOverlappedSeq[] = {
239 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
240 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
241 { HCBT_ACTIVATE, hook|optional },
242 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
243 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
244 { WM_NCACTIVATE, sent|optional },
245 { WM_ACTIVATE, sent|optional },
246 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
247 { 0 }
250 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
251 * for a visible overlapped window.
253 static const struct message WmSWP_ResizeSeq[] = {
254 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
255 { WM_GETMINMAXINFO, sent|defwinproc },
256 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
257 { WM_NCPAINT, sent|optional },
258 { WM_GETTEXT, sent|defwinproc|optional },
259 { WM_ERASEBKGND, sent|optional },
260 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
261 { WM_SIZE, sent|defwinproc|optional },
262 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
263 { WM_NCPAINT, sent|optional },
264 { WM_GETTEXT, sent|defwinproc|optional },
265 { WM_ERASEBKGND, sent|optional },
266 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
267 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
268 { 0 }
271 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
272 * for a visible popup window.
274 static const struct message WmSWP_ResizePopupSeq[] = {
275 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
276 { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */
277 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
278 { WM_NCPAINT, sent|optional },
279 { WM_GETTEXT, sent|defwinproc|optional },
280 { WM_ERASEBKGND, sent|optional },
281 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
282 { WM_SIZE, sent|defwinproc|wparam|optional, SIZE_RESTORED },
283 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
284 { WM_NCPAINT, sent|optional },
285 { WM_GETTEXT, sent|defwinproc|optional },
286 { WM_ERASEBKGND, sent|optional },
287 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
288 { 0 }
291 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
292 * for a visible overlapped window.
294 static const struct message WmSWP_MoveSeq[] = {
295 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
296 { WM_NCPAINT, sent|optional },
297 { WM_GETTEXT, sent|defwinproc|optional },
298 { WM_ERASEBKGND, sent|optional },
299 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
300 { WM_MOVE, sent|defwinproc|wparam, 0 },
301 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
302 { 0 }
304 /* Resize with SetWindowPos(SWP_NOZORDER)
305 * for a visible overlapped window
306 * SWP_NOZORDER is stripped by the logging code
308 static const struct message WmSWP_ResizeNoZOrder[] = {
309 { WM_WINDOWPOSCHANGING, sent|wparam, /*SWP_NOZORDER|*/SWP_NOACTIVATE },
310 { WM_GETMINMAXINFO, sent|defwinproc },
311 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
312 { WM_NCPAINT, sent|optional },
313 { WM_GETTEXT, sent|defwinproc|optional },
314 { WM_ERASEBKGND, sent|optional },
315 { WM_WINDOWPOSCHANGED, sent|wparam|optional, /*SWP_NOZORDER|*/SWP_NOACTIVATE, 0,
316 SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
317 { WM_MOVE, sent|defwinproc|optional },
318 { WM_SIZE, sent|defwinproc|optional },
319 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
320 { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
321 { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */
322 { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */
323 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
324 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on win10. */
325 { 0 }
328 /* Switch visible mdi children */
329 static const struct message WmSwitchChild[] = {
330 /* Switch MDI child */
331 { WM_MDIACTIVATE, sent },/* in the MDI client */
332 { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 1st MDI child */
333 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
334 { WM_CHILDACTIVATE, sent },/* in the 1st MDI child */
335 /* Deactivate 2nd MDI child */
336 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
337 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
338 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
339 /* Preparing for maximize and maximize the 1st MDI child */
340 { WM_GETMINMAXINFO, sent|defwinproc }, /* in the 1st MDI child */
341 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED }, /* in the 1st MDI child */
342 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
343 { WM_CHILDACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
344 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 1st MDI child */
345 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, /* in the 1st MDI child */
346 /* Lock redraw 2nd MDI child */
347 { WM_SETREDRAW, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
348 { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
349 /* Restore 2nd MDI child */
350 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },/* in the 2nd MDI child */
351 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
352 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
353 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 2nd MDI child */
354 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, /* in the 2nd MDI child */
355 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
356 /* Redraw 2nd MDI child */
357 { WM_SETREDRAW, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
358 /* Redraw MDI frame */
359 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },/* in MDI frame */
360 { WM_NCCALCSIZE, sent|wparam, 1 },/* in MDI frame */
361 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in MDI frame */
362 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in MDI frame */
363 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
364 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
365 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
366 { HCBT_SETFOCUS, hook },
367 { WM_KILLFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
368 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },/* in the 1st MDI child */
369 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
370 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
371 { WM_SETFOCUS, sent },/* in the MDI client */
372 { HCBT_SETFOCUS, hook },
373 { WM_KILLFOCUS, sent },/* in the MDI client */
374 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
375 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, /* in the 1st MDI child */
376 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
377 { WM_SETFOCUS, sent|defwinproc }, /* in the 1st MDI child */
378 { WM_MDIACTIVATE, sent|defwinproc },/* in the 1st MDI child */
379 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* in the 1st MDI child */
380 { 0 }
383 /* Switch visible not maximized mdi children */
384 static const struct message WmSwitchNotMaximizedChild[] = {
385 /* Switch not maximized MDI child */
386 { WM_MDIACTIVATE, sent },/* in the MDI client */
387 { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 2nd MDI child */
388 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
389 { WM_CHILDACTIVATE, sent },/* in the 2nd MDI child */
390 /* Deactivate 1st MDI child */
391 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
392 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
393 /* Activate 2nd MDI child */
394 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE}, /* in the 2nd MDI child */
395 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 2nd MDI child */
396 { HCBT_SETFOCUS, hook }, /* in the 1st MDI child */
397 { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
398 { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
399 { WM_IME_SETCONTEXT, sent|optional }, /* in the MDI client */
400 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
401 { WM_SETFOCUS, sent, 0 }, /* in the MDI client */
402 { HCBT_SETFOCUS, hook },
403 { WM_KILLFOCUS, sent }, /* in the MDI client */
404 { WM_IME_SETCONTEXT, sent|optional }, /* in the MDI client */
405 { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
406 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
407 { WM_SETFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
408 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
409 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in the 2nd MDI child */
410 { 0 }
414 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
415 SWP_NOZORDER|SWP_FRAMECHANGED)
416 * for a visible overlapped window with WS_CLIPCHILDREN style set.
418 static const struct message WmSWP_FrameChanged_clip[] = {
419 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
420 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
421 { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
422 { WM_GETTEXT, sent|parent|defwinproc|optional },
423 { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
424 { WM_NCPAINT, sent }, /* wparam != 1 */
425 { WM_ERASEBKGND, sent },
426 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
427 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
428 { WM_PAINT, sent },
429 { 0 }
431 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
432 SWP_NOZORDER|SWP_FRAMECHANGED)
433 * for a visible overlapped window.
435 static const struct message WmSWP_FrameChangedDeferErase[] = {
436 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
437 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
438 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
439 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
440 { WM_PAINT, sent|parent|optional },
441 { WM_NCPAINT, sent|beginpaint|parent|optional }, /* wparam != 1 */
442 { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
443 { WM_PAINT, sent },
444 { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
445 { WM_ERASEBKGND, sent|beginpaint|optional },
446 { 0 }
449 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
450 SWP_NOZORDER|SWP_FRAMECHANGED)
451 * for a visible overlapped window without WS_CLIPCHILDREN style set.
453 static const struct message WmSWP_FrameChanged_noclip[] = {
454 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
455 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
456 { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
457 { WM_GETTEXT, sent|parent|defwinproc|optional },
458 { WM_ERASEBKGND, sent|parent|optional },
459 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
460 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
461 { WM_PAINT, sent },
462 { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
463 { WM_ERASEBKGND, sent|beginpaint|optional },
464 { 0 }
467 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
468 static const struct message WmShowOverlappedSeq[] = {
469 { WM_SHOWWINDOW, sent|wparam, 1 },
470 { WM_NCPAINT, sent|wparam|optional, 1 },
471 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
472 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
473 { WM_NCPAINT, sent|wparam|optional, 1 },
474 { WM_GETTEXT, sent|defwinproc|optional },
475 { WM_ERASEBKGND, sent|optional },
476 { HCBT_ACTIVATE, hook|optional },
477 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|optional, 0, 0 },
478 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
479 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
480 { WM_NCPAINT, sent|wparam|optional, 1 },
481 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
482 { WM_NCACTIVATE, sent|wparam|optional, 1 },
483 { WM_GETTEXT, sent|defwinproc|optional },
484 { WM_ACTIVATE, sent|wparam|optional, 1 },
485 { HCBT_SETFOCUS, hook|optional },
486 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
487 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
488 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
489 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
490 { WM_GETTEXT, sent|optional },
491 { WM_NCPAINT, sent|wparam|optional, 1 },
492 { WM_GETTEXT, sent|defwinproc|optional },
493 { WM_ERASEBKGND, sent|optional },
494 /* Win9x adds SWP_NOZORDER below */
495 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
496 { WM_NCCALCSIZE, sent|optional },
497 { WM_GETTEXT, sent|optional },
498 { WM_NCPAINT, sent|optional },
499 { WM_ERASEBKGND, sent|optional },
500 { WM_SYNCPAINT, sent|optional },
501 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
502 * messages. Does that mean that CreateWindow doesn't set initial
503 * window dimensions for overlapped windows?
505 { WM_SIZE, sent },
506 { WM_MOVE, sent },
507 #endif
508 { WM_PAINT, sent|optional },
509 { WM_NCPAINT, sent|beginpaint|optional },
510 { 0 }
512 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
513 static const struct message WmShowMaxOverlappedSeq[] = {
514 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
515 { WM_GETMINMAXINFO, sent },
516 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
517 { WM_GETMINMAXINFO, sent|defwinproc },
518 { WM_NCCALCSIZE, sent|wparam, TRUE },
519 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
520 { HCBT_ACTIVATE, hook|optional },
521 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|optional, 0, 0 },
522 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
523 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
524 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
525 { WM_NCACTIVATE, sent|wparam|optional, 1 },
526 { WM_GETTEXT, sent|defwinproc|optional },
527 { WM_ACTIVATE, sent|wparam|optional, 1 },
528 { HCBT_SETFOCUS, hook|optional },
529 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
530 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
531 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
532 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
533 { WM_GETTEXT, sent|optional },
534 { WM_NCPAINT, sent|wparam|optional, 1 },
535 { WM_GETTEXT, sent|defwinproc|optional },
536 { WM_ERASEBKGND, sent|optional },
537 /* Win9x adds SWP_NOZORDER below */
538 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
539 { WM_MOVE, sent|defwinproc },
540 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
541 { WM_GETTEXT, sent|optional },
542 { WM_NCCALCSIZE, sent|optional },
543 { WM_NCPAINT, sent|optional },
544 { WM_ERASEBKGND, sent|optional },
545 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
546 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on win10. */
547 { WM_SYNCPAINT, sent|optional },
548 { WM_GETTITLEBARINFOEX, sent|optional },
549 { WM_PAINT, sent|optional },
550 { WM_NCPAINT, sent|beginpaint|optional },
551 { WM_ERASEBKGND, sent|beginpaint|optional },
552 { 0 }
554 /* ShowWindow(SW_RESTORE) for a not visible maximized overlapped window */
555 static const struct message WmShowRestoreMaxOverlappedSeq[] = {
556 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
557 { WM_GETTEXT, sent|optional },
558 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
559 { WM_GETMINMAXINFO, sent|defwinproc },
560 { WM_NCCALCSIZE, sent|wparam, TRUE },
561 { WM_NCPAINT, sent|optional },
562 { WM_GETTEXT, sent|defwinproc|optional },
563 { WM_ERASEBKGND, sent|optional },
564 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
565 { WM_MOVE, sent|defwinproc|optional },
566 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
567 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
568 { WM_NCPAINT, sent|optional },
569 { WM_ERASEBKGND, sent|optional },
570 { WM_PAINT, sent|optional },
571 { WM_GETTITLEBARINFOEX, sent|optional },
572 { WM_NCPAINT, sent|beginpaint|optional },
573 { WM_ERASEBKGND, sent|beginpaint|optional },
574 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
575 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
576 { WM_SYNCPAINT, sent|optional },
577 { 0 }
579 /* ShowWindow(SW_RESTORE) for a not visible minimized overlapped window */
580 static const struct message WmShowRestoreMinOverlappedSeq[] = {
581 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
582 { WM_QUERYOPEN, sent|optional },
583 { WM_GETTEXT, sent|optional },
584 { WM_NCACTIVATE, sent|wparam|optional, 1 },
585 { WM_WINDOWPOSCHANGING, sent|optional }, /* SWP_NOSIZE|SWP_NOMOVE */
586 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
587 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
588 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sent on Win7. */
589 { WM_MOVE, sent|optional },
590 { WM_SIZE, sent|wparam|optional, SIZE_RESTORED },
591 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sent on Win7. */
592 { WM_GETTEXT, sent|optional },
593 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED|SWP_NOCOPYBITS },
594 { WM_GETMINMAXINFO, sent|defwinproc|optional },
595 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
596 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sent on Win10. */
597 { HCBT_ACTIVATE, hook|optional },
598 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|optional, 0, 0 },
599 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
600 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
601 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
602 { WM_NCACTIVATE, sent|wparam|optional, 1 },
603 { WM_GETTEXT, sent|defwinproc|optional },
604 { WM_ACTIVATE, sent|wparam|optional, 1 },
605 { HCBT_SETFOCUS, hook|optional },
606 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
607 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
608 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
609 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
610 { WM_GETTEXT, sent|optional },
611 { WM_NCPAINT, sent|wparam|optional, 1 },
612 { WM_GETTEXT, sent|defwinproc|optional },
613 { WM_ERASEBKGND, sent },
614 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_STATECHANGED|SWP_FRAMECHANGED|SWP_NOCOPYBITS },
615 { WM_MOVE, sent|defwinproc },
616 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
617 { HCBT_SETFOCUS, hook|optional },
618 { WM_SETFOCUS, sent|wparam|optional, 0 },
619 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
620 { WM_NCPAINT, sent|wparam|optional, 1 },
621 { WM_ERASEBKGND, sent|optional },
622 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
623 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
624 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
625 { HCBT_SETFOCUS, hook|optional },
626 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
627 { WM_SETFOCUS, sent|wparam|optional, 0 },
628 { WM_ACTIVATE, sent|wparam, 1 },
629 { WM_GETTEXT, sent|optional },
630 { WM_PAINT, sent|optional },
631 { WM_GETTITLEBARINFOEX, sent|optional },
632 { WM_NCPAINT, sent|beginpaint|optional },
633 { WM_ERASEBKGND, sent|beginpaint|optional },
634 { 0 }
636 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
637 static const struct message WmShowMinOverlappedSeq[] = {
638 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
639 { HCBT_SETFOCUS, hook|optional },
640 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
641 { WM_KILLFOCUS, sent|optional },
642 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
643 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
644 { WM_GETTEXT, sent|optional },
645 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
646 { WM_GETMINMAXINFO, sent|defwinproc },
647 { WM_NCCALCSIZE, sent|wparam, TRUE },
648 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
649 { WM_NCPAINT, sent|optional },
650 { WM_GETTEXT, sent|defwinproc|optional },
651 { WM_WINDOWPOSCHANGED, sent },
652 { WM_MOVE, sent|defwinproc },
653 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
654 { WM_NCCALCSIZE, sent|optional },
655 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
656 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on win10. */
657 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
658 { WM_NCACTIVATE, sent|wparam|optional, 0 },
659 { WM_GETTEXT, sent|defwinproc|optional },
660 { WM_ACTIVATE, sent|optional },
661 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
663 /* Vista sometimes restores the window right away... */
664 { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
665 { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
666 { HCBT_MINMAX, hook|optional|lparam, 0, SW_RESTORE },
667 { WM_QUERYOPEN, sent|optional },
668 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
669 { WM_GETMINMAXINFO, sent|optional|defwinproc },
670 { WM_NCCALCSIZE, sent|optional|wparam, TRUE },
671 { HCBT_ACTIVATE, hook|optional },
672 { WM_ACTIVATEAPP, sent|optional|wparam, 1 },
673 { WM_NCACTIVATE, sent|optional },
674 { WM_GETTEXT, sent|optional },
675 { WM_ACTIVATE, sent|optional|wparam, 1 },
676 { HCBT_SETFOCUS, hook|optional },
677 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
678 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
679 { WM_SETFOCUS, sent|optional },
680 { WM_NCPAINT, sent|optional },
681 { WM_GETTEXT, sent|defwinproc|optional },
682 { WM_ERASEBKGND, sent|optional },
683 { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
684 { WM_MOVE, sent|defwinproc|optional },
685 { WM_SIZE, sent|defwinproc|optional|wparam, SIZE_RESTORED },
686 { WM_ACTIVATE, sent|optional|wparam, 1 },
687 { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
688 { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
690 { WM_PAINT, sent|optional },
691 { WM_NCPAINT, sent|beginpaint|optional },
692 { WM_ERASEBKGND, sent|beginpaint|optional },
693 { 0 }
695 /* ShowWindow(SW_HIDE) for a visible overlapped window */
696 static const struct message WmHideOverlappedSeq[] = {
697 { WM_SHOWWINDOW, sent|wparam, 0 },
698 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
699 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
700 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
701 { WM_SIZE, sent|optional }, /* XP doesn't send it */
702 { WM_MOVE, sent|optional }, /* XP doesn't send it */
703 { WM_NCACTIVATE, sent|wparam|optional, 0 },
704 { WM_ACTIVATE, sent|wparam|optional, 0 },
705 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
706 { HCBT_SETFOCUS, hook|optional },
707 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
708 { WM_KILLFOCUS, sent|wparam|optional, 0 },
709 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
710 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
711 { 0 }
713 /* DestroyWindow for a visible overlapped window */
714 static const struct message WmDestroyOverlappedSeq[] = {
715 { HCBT_DESTROYWND, hook },
716 { 0x0090, sent|optional },
717 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
718 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
719 { 0x0090, sent|optional },
720 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
721 { WM_NCACTIVATE, sent|optional|wparam, 0 },
722 { WM_ACTIVATE, sent|optional },
723 { WM_ACTIVATEAPP, sent|optional|wparam, 0 },
724 { WM_KILLFOCUS, sent|optional|wparam, 0 },
725 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
726 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
727 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
728 { WM_DESTROY, sent },
729 { WM_NCDESTROY, sent },
730 { 0 }
732 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
733 static const struct message WmCreateMaxPopupSeq[] = {
734 { HCBT_CREATEWND, hook },
735 { WM_NCCREATE, sent },
736 { WM_NCCALCSIZE, sent|wparam, 0 },
737 { WM_CREATE, sent },
738 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
739 { WM_SIZE, sent|wparam, SIZE_RESTORED },
740 { WM_MOVE, sent },
741 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
742 { WM_GETMINMAXINFO, sent },
743 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
744 { WM_NCCALCSIZE, sent|wparam, TRUE },
745 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
746 { WM_MOVE, sent|defwinproc },
747 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
748 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
749 { WM_SHOWWINDOW, sent|wparam, 1 },
750 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
751 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
752 { HCBT_ACTIVATE, hook },
753 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
754 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
755 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
756 { WM_NCPAINT, sent|wparam|optional, 1 },
757 { WM_ERASEBKGND, sent|optional },
758 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_NOMOVE|SWP_NOSIZE },
759 { WM_ACTIVATEAPP, sent|wparam, 1 },
760 { WM_NCACTIVATE, sent },
761 { WM_ACTIVATE, sent|wparam, 1 },
762 { HCBT_SETFOCUS, hook },
763 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
764 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
765 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
766 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
767 { WM_GETTEXT, sent|optional },
768 { WM_SYNCPAINT, sent|wparam|optional, 4 },
769 { WM_NCPAINT, sent|wparam|optional, 1 },
770 { WM_ERASEBKGND, sent|optional },
771 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
772 { WM_ERASEBKGND, sent|defwinproc|optional },
773 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
774 { 0 }
776 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
777 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
778 { HCBT_CREATEWND, hook },
779 { WM_NCCREATE, sent },
780 { WM_NCCALCSIZE, sent|wparam, 0 },
781 { WM_CREATE, sent },
782 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
783 { WM_SIZE, sent|wparam, SIZE_RESTORED },
784 { WM_MOVE, sent },
785 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
786 { WM_GETMINMAXINFO, sent },
787 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
788 { WM_NCCALCSIZE, sent|wparam, TRUE },
789 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
790 { WM_MOVE, sent|defwinproc },
791 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
792 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
793 { 0 }
795 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
796 static const struct message WmShowMaxPopupResizedSeq[] = {
797 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
798 { WM_GETMINMAXINFO, sent },
799 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED, 0, SWP_STATECHANGED /* w1064v1809 */ },
800 { WM_NCCALCSIZE, sent|wparam, TRUE },
801 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
802 { HCBT_ACTIVATE, hook },
803 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
804 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
805 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
806 { WM_NCPAINT, sent|wparam|optional, 1 },
807 { WM_ERASEBKGND, sent|optional },
808 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
809 { WM_ACTIVATEAPP, sent|wparam, 1 },
810 { WM_NCACTIVATE, sent },
811 { WM_ACTIVATE, sent|wparam, 1 },
812 { HCBT_SETFOCUS, hook },
813 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
814 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
815 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
816 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
817 { WM_GETTEXT, sent|optional },
818 { WM_NCPAINT, sent|wparam|optional, 1 },
819 { WM_ERASEBKGND, sent|optional },
820 { WM_WINDOWPOSCHANGED, sent },
821 /* WinNT4.0 sends WM_MOVE */
822 { WM_MOVE, sent|defwinproc|optional },
823 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
824 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
825 { 0 }
827 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
828 static const struct message WmShowMaxPopupSeq[] = {
829 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
830 { WM_GETMINMAXINFO, sent },
831 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED, 0, SWP_STATECHANGED /* w1064v1809 */ },
832 { WM_NCCALCSIZE, sent|wparam, TRUE },
833 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
834 { HCBT_ACTIVATE, hook },
835 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
836 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
837 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
838 { WM_NCPAINT, sent|wparam|optional, 1 },
839 { WM_ERASEBKGND, sent|optional },
840 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOMOVE|SWP_NOSIZE },
841 { WM_ACTIVATEAPP, sent|wparam, 1 },
842 { WM_NCACTIVATE, sent },
843 { WM_ACTIVATE, sent|wparam, 1 },
844 { HCBT_SETFOCUS, hook },
845 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
846 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
847 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
848 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
849 { WM_GETTEXT, sent|optional },
850 { WM_SYNCPAINT, sent|wparam|optional, 4 },
851 { WM_NCPAINT, sent|wparam|optional, 1 },
852 { WM_ERASEBKGND, sent|optional },
853 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
854 { WM_ERASEBKGND, sent|defwinproc|optional },
855 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE, 0, SWP_STATECHANGED /* w1064v1809 */ },
856 { WM_SIZE, sent|defwinproc|optional },
857 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
858 { 0 }
860 /* CreateWindow(WS_VISIBLE) for popup window */
861 static const struct message WmCreatePopupSeq[] = {
862 { HCBT_CREATEWND, hook },
863 { WM_NCCREATE, sent },
864 { WM_NCCALCSIZE, sent|wparam, 0 },
865 { WM_CREATE, sent },
866 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
867 { WM_SIZE, sent|wparam, SIZE_RESTORED },
868 { WM_MOVE, sent },
869 { WM_SHOWWINDOW, sent|wparam, 1 },
870 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
871 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
872 { HCBT_ACTIVATE, hook },
873 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
874 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
875 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
876 { WM_NCPAINT, sent|wparam|optional, 1 },
877 { WM_ERASEBKGND, sent|optional },
878 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
879 { WM_ACTIVATEAPP, sent|wparam, 1 },
880 { WM_NCACTIVATE, sent },
881 { WM_ACTIVATE, sent|wparam, 1 },
882 { HCBT_SETFOCUS, hook },
883 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
884 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
885 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
886 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
887 { WM_GETTEXT, sent|optional },
888 { WM_SYNCPAINT, sent|wparam|optional, 4 },
889 { WM_NCPAINT, sent|wparam|optional, 1 },
890 { WM_ERASEBKGND, sent|optional },
891 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
892 { 0 }
894 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
895 static const struct message WmShowVisMaxPopupSeq[] = {
896 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
897 { WM_GETMINMAXINFO, sent },
898 { WM_GETTEXT, sent|optional },
899 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
900 { WM_GETTEXT, sent|optional },
901 { WM_NCCALCSIZE, sent|wparam, TRUE },
902 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
903 { WM_NCPAINT, sent|wparam|optional, 1 },
904 { WM_ERASEBKGND, sent|optional },
905 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
906 { WM_MOVE, sent|defwinproc },
907 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
908 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
909 { 0 }
911 /* ShowWindow(hwnd, SW_RESTORE) to a minimized window */
912 static const struct message WmShowRestoreMinimizedOverlappedSeq[] =
914 { HCBT_MINMAX, hook },
915 { WM_QUERYOPEN, sent },
916 { WM_GETTEXT, sent|optional },
917 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
918 { WM_GETMINMAXINFO, sent|defwinproc },
919 { WM_NCCALCSIZE, sent },
920 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
921 { HCBT_ACTIVATE, hook },
922 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
923 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
924 { WM_NCACTIVATE, sent },
925 { WM_GETTEXT, sent|defwinproc|optional },
926 { WM_ACTIVATE, sent|wparam, WA_ACTIVE },
927 { HCBT_SETFOCUS, hook },
928 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
929 { WM_SETFOCUS, sent|defwinproc },
930 { WM_NCPAINT, sent },
931 { WM_GETTEXT, sent|defwinproc|optional },
932 { WM_GETTEXT, sent|defwinproc|optional },
933 { WM_ERASEBKGND, sent },
934 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
935 { WM_MOVE, sent|defwinproc },
936 { WM_SIZE, sent|defwinproc },
937 { WM_NCCALCSIZE, sent|optional },
938 { WM_NCPAINT, sent|optional },
939 { WM_ERASEBKGND, sent|optional },
940 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
941 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
942 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
943 /* Note this WM_ACTIVATE message even if the window is already active and focused */
944 { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, 0 },
945 { WM_SYNCPAINT, sent|optional },
946 { WM_PAINT, sent },
947 { WM_GETMINMAXINFO, sent|optional },
948 { 0 }
950 /* ShowWindow(hwnd, SW_SHOWNOACTIVATE) to a minimized window */
951 static const struct message WmShowNoActivateMinimizedOverlappedSeq[] =
953 { HCBT_MINMAX, hook },
954 { WM_QUERYOPEN, sent },
955 { WM_GETTEXT, sent|optional },
956 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
957 { WM_GETMINMAXINFO, sent|defwinproc },
958 { WM_NCCALCSIZE, sent },
959 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
960 { WM_NCPAINT, sent },
961 { WM_GETTEXT, sent|defwinproc|optional },
962 { WM_ERASEBKGND, sent },
963 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
964 { WM_MOVE, sent|defwinproc },
965 { WM_SIZE, sent|defwinproc },
966 /* Following optional messages are on XP/2003 */
967 { WM_NCCALCSIZE, sent|optional },
968 { WM_NCPAINT, sent|optional },
969 { WM_ERASEBKGND, sent|optional },
970 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
971 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
972 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
973 { HCBT_SETFOCUS, hook|optional },
974 { WM_SETFOCUS, sent|optional },
975 { HCBT_ACTIVATE, hook|optional },
976 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
977 { WM_NCACTIVATE, sent|optional },
978 { WM_GETTEXT, sent|defwinproc|optional },
979 { WM_ACTIVATE, sent|wparam|optional, WA_ACTIVE },
980 { HCBT_SETFOCUS, hook|optional },
981 { WM_SETFOCUS, sent|defwinproc|optional },
982 { WM_KILLFOCUS, sent|optional },
983 { WM_SETFOCUS, sent|optional },
984 /* Note this WM_ACTIVATE message on XP even if the window is already active and focused */
985 { WM_ACTIVATE, sent|wparam|lparam|optional, WA_ACTIVE, 0 },
986 { WM_SYNCPAINT, sent|optional },
987 { WM_PAINT, sent },
988 { WM_GETMINMAXINFO, sent|optional },
989 { 0 }
991 /* ShowWindow(hwnd, SW_RESTORE) to an active minimized window */
992 static const struct message WmShowRestoreActiveMinimizedOverlappedSeq[] =
994 { HCBT_MINMAX, hook },
995 { WM_QUERYOPEN, sent },
996 { WM_GETTEXT, sent|optional },
997 { WM_NCACTIVATE, sent },
998 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
999 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1000 { WM_NCCALCSIZE, sent|optional },
1001 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends this. */
1002 { WM_MOVE, sent|optional },
1003 { WM_SIZE, sent|optional },
1004 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends this. */
1005 { WM_GETTEXT, sent|optional },
1006 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1007 { WM_GETMINMAXINFO, sent|defwinproc },
1008 { WM_NCCALCSIZE, sent },
1009 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win8+ sends this. */
1010 { WM_NCPAINT, sent },
1011 { WM_GETTEXT, sent|defwinproc|optional },
1012 { WM_ERASEBKGND, sent },
1013 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1014 { WM_MOVE, sent|defwinproc },
1015 { WM_SIZE, sent|defwinproc },
1016 { WM_NCCALCSIZE, sent|optional },
1017 { WM_NCPAINT, sent|optional },
1018 { WM_ERASEBKGND, sent|optional },
1019 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1020 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
1021 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1022 { HCBT_SETFOCUS, hook },
1023 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1024 { WM_SETFOCUS, sent },
1025 /* Note this WM_ACTIVATE message even if the window is already active */
1026 { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, 0 },
1027 { WM_SYNCPAINT, sent|optional },
1028 { WM_PAINT, sent },
1029 { WM_GETMINMAXINFO, sent|optional },
1030 { 0 }
1032 /* ShowWindow(hwnd, SW_SHOWNOACTIVATE) to an active minimized window */
1033 static const struct message WmShowNoActivateActiveMinimizedOverlappedSeq[] =
1035 { HCBT_MINMAX, hook },
1036 { WM_QUERYOPEN, sent },
1037 { WM_GETTEXT, sent|optional },
1038 { WM_NCACTIVATE, sent },
1039 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1040 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1041 { WM_NCCALCSIZE, sent|optional },
1042 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends this. */
1043 { WM_MOVE, sent|optional },
1044 { WM_SIZE, sent|optional },
1045 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends this. */
1046 { WM_GETTEXT, sent|optional },
1047 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1048 { WM_GETMINMAXINFO, sent|defwinproc },
1049 { WM_NCCALCSIZE, sent },
1050 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win8+ sends this. */
1051 { WM_NCPAINT, sent },
1052 { WM_GETTEXT, sent|defwinproc|optional },
1053 { WM_ERASEBKGND, sent },
1054 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1055 { WM_MOVE, sent|defwinproc },
1056 { WM_SIZE, sent|defwinproc },
1057 { WM_NCCALCSIZE, sent|optional },
1058 { WM_NCPAINT, sent|optional },
1059 { WM_ERASEBKGND, sent|optional },
1060 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1061 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
1062 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1063 /* Following optional messages are present on XP */
1064 { HCBT_SETFOCUS, hook|optional },
1065 { WM_SETFOCUS, sent|optional },
1066 /* Note this WM_ACTIVATE message even if the window is already active and with flag SW_SHOWNOACTIVATE */
1067 { WM_ACTIVATE, sent|wparam|lparam|optional, WA_ACTIVE, 0 },
1068 { WM_SYNCPAINT, sent|optional },
1069 { WM_PAINT, sent },
1070 { WM_GETMINMAXINFO, sent|optional },
1071 { 0 }
1073 /* CreateWindow (for a child popup window, not initially visible) */
1074 static const struct message WmCreateChildPopupSeq[] = {
1075 { HCBT_CREATEWND, hook },
1076 { WM_NCCREATE, sent },
1077 { WM_NCCALCSIZE, sent|wparam, 0 },
1078 { WM_CREATE, sent },
1079 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1080 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1081 { WM_MOVE, sent },
1082 { 0 }
1084 /* CreateWindow (for a popup window, not initially visible,
1085 * which sets WS_VISIBLE in WM_CREATE handler)
1087 static const struct message WmCreateInvisiblePopupSeq[] = {
1088 { HCBT_CREATEWND, hook },
1089 { WM_NCCREATE, sent },
1090 { WM_NCCALCSIZE, sent|wparam, 0 },
1091 { WM_CREATE, sent },
1092 { WM_STYLECHANGING, sent },
1093 { WM_STYLECHANGED, sent },
1094 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1095 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1096 { WM_MOVE, sent },
1097 { 0 }
1099 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
1100 * for a popup window with WS_VISIBLE style set
1102 static const struct message WmShowVisiblePopupSeq_2[] = {
1103 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1104 { 0 }
1106 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1107 * for a popup window with WS_VISIBLE style set
1109 static const struct message WmShowVisiblePopupSeq_3[] = {
1110 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1111 { HCBT_ACTIVATE, hook },
1112 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1113 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1114 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1115 { WM_NCACTIVATE, sent },
1116 { WM_ACTIVATE, sent|wparam, 1 },
1117 { HCBT_SETFOCUS, hook },
1118 { WM_KILLFOCUS, sent|parent },
1119 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1120 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1121 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1122 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1123 { WM_SETFOCUS, sent|defwinproc },
1124 { WM_GETTEXT, sent|optional },
1125 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_SHOWWINDOW },
1126 { 0 }
1128 /* CreateWindow (for a popup window with WS_VISIBLE style set and extreme location)
1130 static const struct message WmShowPopupExtremeLocationSeq[] = {
1131 { HCBT_CREATEWND, hook },
1132 { WM_NCCREATE, sent },
1133 { WM_NCCALCSIZE, sent|wparam, 0 },
1134 { WM_CREATE, sent },
1135 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1136 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1137 { WM_MOVE, sent },
1138 { WM_SHOWWINDOW, sent|wparam, 1 },
1139 { WM_WINDOWPOSCHANGING, sent },
1140 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1141 { HCBT_ACTIVATE, hook },
1142 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1143 { WM_WINDOWPOSCHANGING, sent|optional },
1144 { WM_QUERYNEWPALETTE, sent|optional },
1146 /* occasionally received on test machines */
1147 { WM_NCPAINT, sent|optional },
1148 { WM_ERASEBKGND, sent|optional },
1149 { WM_WINDOWPOSCHANGED, sent|optional },
1151 { WM_ACTIVATEAPP, sent },
1152 { WM_NCACTIVATE, sent },
1153 { WM_ACTIVATE, sent },
1154 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1155 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1156 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1157 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Not sent on Win10. */
1158 { HCBT_SETFOCUS, hook },
1159 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
1160 { WM_SETFOCUS, sent|defwinproc },
1161 { WM_NCPAINT, sent|wparam|optional, 1 }, /* Not always sent on Win8+ */
1162 { WM_ERASEBKGND, sent|optional }, /* Not always sent on Win8+ */
1163 { WM_WINDOWPOSCHANGED, sent },
1164 /* occasionally received on test machines */
1165 { WM_NCPAINT, sent|optional },
1166 { WM_ERASEBKGND, sent|optional },
1167 { 0 }
1169 /* CreateWindow (for a popup window with WS_VISIBLE style set)
1171 static const struct message WmShowPopupFirstDrawSeq_1[] = {
1172 { HCBT_CREATEWND, hook },
1173 { WM_NCCREATE, sent },
1174 { WM_NCCALCSIZE, sent|wparam, 0 },
1175 { WM_CREATE, sent },
1176 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1177 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1178 { WM_MOVE, sent },
1179 { WM_SHOWWINDOW, sent|wparam, 1 },
1180 { WM_WINDOWPOSCHANGING, sent },
1181 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1182 { HCBT_ACTIVATE, hook },
1183 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1184 { WM_WINDOWPOSCHANGING, sent|optional },
1185 { WM_QUERYNEWPALETTE, sent|optional },
1186 { WM_ACTIVATEAPP, sent },
1187 { WM_NCACTIVATE, sent },
1188 { WM_ACTIVATE, sent },
1189 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1190 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1191 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1192 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Not sent on Win10. */
1193 { HCBT_SETFOCUS, hook },
1194 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
1195 { WM_SETFOCUS, sent|defwinproc },
1196 { WM_NCPAINT, sent|wparam, 1 },
1197 { WM_ERASEBKGND, sent },
1198 { WM_WINDOWPOSCHANGED, sent },
1199 { WM_PAINT, sent },
1200 /* occasionally received on test machines */
1201 { WM_NCPAINT, sent|beginpaint|optional },
1202 { WM_ERASEBKGND, sent|beginpaint|optional },
1203 { 0 }
1205 /* CreateWindow (for a popup window that is shown with ShowWindow(SW_SHOWMAXIMIZED))
1207 static const struct message WmShowPopupFirstDrawSeq_2[] = {
1208 { HCBT_CREATEWND, hook },
1209 { WM_NCCREATE, sent },
1210 { WM_NCCALCSIZE, sent|wparam, 0 },
1211 { WM_CREATE, sent },
1212 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1213 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1214 { WM_MOVE, sent },
1215 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1216 { WM_GETMINMAXINFO, sent },
1217 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_STATECHANGED|SWP_SHOWWINDOW|SWP_FRAMECHANGED },
1218 { WM_NCCALCSIZE, sent|wparam, TRUE },
1219 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1220 { HCBT_ACTIVATE, hook },
1221 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1222 { WM_WINDOWPOSCHANGING, sent|optional },
1223 { WM_NCPAINT, sent|optional|wparam, 1 },
1224 { WM_ERASEBKGND, sent|optional },
1225 { WM_WINDOWPOSCHANGED, sent|optional },
1226 { WM_QUERYNEWPALETTE, sent|optional },
1227 { WM_ACTIVATEAPP, sent },
1228 { WM_NCACTIVATE, sent },
1229 { WM_ACTIVATE, sent },
1230 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1231 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1232 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1233 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Not sent on Win10. */
1234 { HCBT_SETFOCUS, hook },
1235 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
1236 { WM_SETFOCUS, sent|defwinproc },
1237 { WM_NCPAINT, sent|wparam, 1 },
1238 { WM_ERASEBKGND, sent },
1239 { WM_WINDOWPOSCHANGED, sent|optional },
1240 { WM_MOVE, sent|defwinproc },
1241 { WM_SIZE, sent|defwinproc, 0 },
1242 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1243 { WM_PAINT, sent},
1244 /* occasionally received on test machines */
1245 { WM_NCPAINT, sent|beginpaint|optional },
1246 { WM_ERASEBKGND, sent|beginpaint|optional },
1247 { 0 }
1249 static const struct message WmFirstDrawSetWindowPosSeq1[] = {
1250 { HCBT_CREATEWND, hook },
1251 { WM_NCCREATE, sent },
1252 { WM_NCCALCSIZE, sent|wparam, 0 },
1253 { WM_CREATE, sent },
1254 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1255 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1256 { WM_MOVE, sent },
1257 { WM_WINDOWPOSCHANGING, sent },
1258 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1259 { HCBT_ACTIVATE, hook },
1260 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1261 { WM_WINDOWPOSCHANGING, sent|optional },
1262 { WM_QUERYNEWPALETTE, sent|optional },
1263 { WM_ACTIVATEAPP, sent },
1264 { WM_NCACTIVATE, sent },
1265 { WM_ACTIVATE, sent },
1266 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1267 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1268 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1269 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Not sent on Win10. */
1270 { HCBT_SETFOCUS, hook },
1271 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
1272 { WM_SETFOCUS, sent|defwinproc },
1273 { WM_NCPAINT, sent|wparam, 1 },
1274 { WM_ERASEBKGND, sent },
1275 { WM_WINDOWPOSCHANGED, sent },
1276 { WM_MOVE, sent|defwinproc },
1277 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1278 { 0 }
1280 static const struct message WmFirstDrawSetWindowPosSeq2[] = {
1281 { HCBT_CREATEWND, hook },
1282 { WM_NCCREATE, sent },
1283 { WM_NCCALCSIZE, sent|wparam, 0 },
1284 { WM_CREATE, sent },
1285 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1286 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1287 { WM_MOVE, sent },
1288 { WM_WINDOWPOSCHANGING, sent },
1289 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not always sent. */
1290 { HCBT_ACTIVATE, hook },
1291 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1292 { WM_QUERYNEWPALETTE, sent|optional },
1293 { WM_WINDOWPOSCHANGING, sent|optional },
1294 { WM_ACTIVATEAPP, sent },
1295 { WM_NCACTIVATE, sent },
1296 { WM_ACTIVATE, sent },
1297 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1298 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1299 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1300 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Not sent on Win10. */
1301 { HCBT_SETFOCUS, hook },
1302 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
1303 { WM_SETFOCUS, sent|defwinproc },
1304 { WM_WINDOWPOSCHANGED, sent },
1305 { WM_MOVE, sent|defwinproc },
1306 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1307 { 0 }
1309 static const struct message WmFirstDrawSetWindowPosSeq3[] = {
1310 { HCBT_CREATEWND, hook },
1311 { WM_NCCREATE, sent },
1312 { WM_NCCALCSIZE, sent|wparam, 0 },
1313 { WM_CREATE, sent },
1314 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1315 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1316 { WM_MOVE, sent },
1317 /* These happen only on Wine: */
1318 { EVENT_OBJECT_SHOW, winevent_hook|optional },
1319 { HCBT_ACTIVATE, hook|optional },
1320 { WM_QUERYNEWPALETTE, sent|optional },
1321 { WM_ACTIVATEAPP, sent|optional },
1322 { WM_NCACTIVATE, sent|optional },
1323 { WM_ACTIVATE, sent|optional },
1324 { HCBT_SETFOCUS, hook|optional },
1325 { WM_SETFOCUS, sent|defwinproc|optional },
1326 { 0 }
1328 static const struct message WmFirstDrawSetWindowPosSeq4[] = {
1329 { HCBT_CREATEWND, hook },
1330 { WM_NCCREATE, sent },
1331 { WM_NCCALCSIZE, sent|wparam, 0 },
1332 { WM_CREATE, sent },
1333 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1334 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1335 { WM_MOVE, sent },
1336 { WM_WINDOWPOSCHANGING, sent },
1337 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1338 { HCBT_ACTIVATE, hook },
1339 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1340 { WM_WINDOWPOSCHANGING, sent|optional },
1341 { WM_QUERYNEWPALETTE, sent|optional },
1342 { WM_ACTIVATEAPP, sent },
1343 { WM_NCACTIVATE, sent },
1344 { WM_ACTIVATE, sent },
1345 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1346 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1347 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1348 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Not sent on Win10. */
1349 { HCBT_SETFOCUS, hook },
1350 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
1351 { WM_SETFOCUS, sent|defwinproc },
1352 { WM_NCPAINT, sent|wparam, 1 },
1353 { WM_ERASEBKGND, sent },
1354 { WM_WINDOWPOSCHANGED, sent },
1355 { 0 }
1357 static const struct message WmFirstDrawSetWindowPosSeq5[] = {
1358 { HCBT_CREATEWND, hook },
1359 { WM_NCCREATE, sent },
1360 { WM_NCCALCSIZE, sent|wparam, 0 },
1361 { WM_CREATE, sent },
1362 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1363 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1364 { WM_MOVE, sent },
1365 { WM_WINDOWPOSCHANGING, sent },
1366 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1367 { HCBT_ACTIVATE, hook },
1368 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1369 { WM_WINDOWPOSCHANGING, sent|optional },
1370 { WM_QUERYNEWPALETTE, sent|optional },
1371 { WM_ACTIVATEAPP, sent },
1372 { WM_NCACTIVATE, sent },
1373 { WM_ACTIVATE, sent },
1374 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1375 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1376 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1377 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Not sent on Win10. */
1378 { HCBT_SETFOCUS, hook },
1379 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
1380 { WM_SETFOCUS, sent|defwinproc },
1381 { WM_WINDOWPOSCHANGED, sent },
1382 { 0 }
1384 static const struct message WmFirstDrawChildSeq1[] = {
1385 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1386 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
1387 { 0 }
1389 static const struct message WmFirstDrawChildSeq2[] = {
1390 { WM_NCPAINT, sent|wparam, 1 },
1391 { WM_ERASEBKGND, sent },
1392 /* occasionally received on test machines */
1393 { WM_NCPAINT, sent|optional },
1394 { WM_ERASEBKGND, sent|optional },
1395 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1396 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
1397 { 0 }
1399 /* CreateWindow (for child window, not initially visible) */
1400 static const struct message WmCreateChildSeq[] = {
1401 { HCBT_CREATEWND, hook },
1402 { WM_NCCREATE, sent },
1403 /* child is inserted into parent's child list after WM_NCCREATE returns */
1404 { WM_NCCALCSIZE, sent|wparam, 0 },
1405 { WM_CREATE, sent },
1406 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1407 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1408 { WM_MOVE, sent },
1409 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1410 { 0 }
1412 /* CreateWindow (for maximized child window, not initially visible) */
1413 static const struct message WmCreateMaximizedChildSeq[] = {
1414 { HCBT_CREATEWND, hook },
1415 { WM_NCCREATE, sent },
1416 { WM_NCCALCSIZE, sent|wparam, 0 },
1417 { WM_CREATE, sent },
1418 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1419 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1420 { WM_MOVE, sent },
1421 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1422 { WM_GETMINMAXINFO, sent },
1423 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
1424 { WM_NCCALCSIZE, sent|wparam, 1 },
1425 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1426 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1427 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1428 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1429 { 0 }
1431 /* CreateWindow (for a child window, initially visible) */
1432 static const struct message WmCreateVisibleChildSeq[] = {
1433 { HCBT_CREATEWND, hook },
1434 { WM_NCCREATE, sent },
1435 /* child is inserted into parent's child list after WM_NCCREATE returns */
1436 { WM_NCCALCSIZE, sent|wparam, 0 },
1437 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win10. */
1438 { WM_CREATE, sent },
1439 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1440 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1441 { WM_MOVE, sent },
1442 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1443 { WM_SHOWWINDOW, sent|wparam, 1 },
1444 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1445 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1446 { WM_ERASEBKGND, sent|parent|optional },
1447 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1448 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
1449 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1450 { 0 }
1452 /* ShowWindow(SW_SHOW) for a not visible child window */
1453 static const struct message WmShowChildSeq[] = {
1454 { WM_SHOWWINDOW, sent|wparam, 1 },
1455 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1456 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1457 { WM_ERASEBKGND, sent|parent|optional },
1458 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1459 { 0 }
1461 /* ShowWindow(SW_HIDE) for a visible child window */
1462 static const struct message WmHideChildSeq[] = {
1463 { WM_SHOWWINDOW, sent|wparam, 0 },
1464 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1465 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1466 { WM_ERASEBKGND, sent|parent|optional },
1467 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1468 { 0 }
1470 /* ShowWindow(SW_HIDE) for a visible child window checking all parent events*/
1471 static const struct message WmHideChildSeq2[] = {
1472 { WM_SHOWWINDOW, sent|wparam, 0 },
1473 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1474 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1475 { WM_ERASEBKGND, sent|parent|optional },
1476 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1477 { 0 }
1479 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1480 * for a not visible child window
1482 static const struct message WmShowChildSeq_2[] = {
1483 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1484 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1485 { WM_CHILDACTIVATE, sent },
1486 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1487 { 0 }
1489 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
1490 * for a not visible child window
1492 static const struct message WmShowChildSeq_3[] = {
1493 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1494 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1495 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1496 { 0 }
1498 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1499 * for a visible child window with a caption
1501 static const struct message WmShowChildSeq_4[] = {
1502 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1503 { WM_CHILDACTIVATE, sent },
1504 { 0 }
1506 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
1507 static const struct message WmShowChildInvisibleParentSeq_1[] = {
1508 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1509 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1510 { WM_NCCALCSIZE, sent|wparam, 1 },
1511 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1512 { WM_CHILDACTIVATE, sent|optional },
1513 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1514 { WM_MOVE, sent|defwinproc },
1515 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1516 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1517 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1518 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1519 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1520 { WM_GETTEXT, sent|optional },
1521 { 0 }
1523 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
1524 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
1525 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1526 { 0 }
1528 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1529 static const struct message WmShowChildInvisibleParentSeq_2[] = {
1530 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1531 { WM_GETMINMAXINFO, sent },
1532 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
1533 { WM_NCCALCSIZE, sent|wparam, 1 },
1534 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1535 { WM_CHILDACTIVATE, sent },
1536 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1537 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1538 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1539 { 0 }
1541 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1542 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
1543 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1544 { 0 }
1546 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1547 static const struct message WmShowChildInvisibleParentSeq_3[] = {
1548 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1549 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1550 { WM_NCCALCSIZE, sent|wparam, 1 },
1551 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1552 { WM_CHILDACTIVATE, sent },
1553 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1554 { WM_MOVE, sent|defwinproc },
1555 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1556 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1557 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1558 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1559 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1560 { WM_GETTEXT, sent|optional },
1561 { 0 }
1563 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1564 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
1565 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1566 { 0 }
1568 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1569 static const struct message WmShowChildInvisibleParentSeq_4[] = {
1570 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1571 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
1572 { WM_NCCALCSIZE, sent|wparam, 1 },
1573 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1574 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1575 { WM_MOVE, sent|defwinproc },
1576 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1577 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1578 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1579 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1580 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1581 { WM_GETTEXT, sent|optional },
1582 { 0 }
1584 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1585 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
1586 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1587 { 0 }
1589 /* ShowWindow(SW_SHOW) for child with invisible parent */
1590 static const struct message WmShowChildInvisibleParentSeq_5[] = {
1591 { WM_SHOWWINDOW, sent|wparam, 1 },
1592 { 0 }
1594 /* ShowWindow(SW_HIDE) for child with invisible parent */
1595 static const struct message WmHideChildInvisibleParentSeq[] = {
1596 { WM_SHOWWINDOW, sent|wparam, 0 },
1597 { 0 }
1599 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
1600 static const struct message WmShowChildInvisibleParentSeq_6[] = {
1601 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1602 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1603 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1604 { 0 }
1606 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
1607 static const struct message WmHideChildInvisibleParentSeq_2[] = {
1608 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1609 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1610 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1611 { 0 }
1613 /* DestroyWindow for a visible child window */
1614 static const struct message WmDestroyChildSeq[] = {
1615 { HCBT_DESTROYWND, hook },
1616 { 0x0090, sent|optional },
1617 { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1618 { WM_SHOWWINDOW, sent|wparam, 0 },
1619 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1620 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1621 { WM_ERASEBKGND, sent|parent|optional },
1622 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1623 { HCBT_SETFOCUS, hook }, /* set focus to a parent */
1624 { WM_KILLFOCUS, sent },
1625 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1626 { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
1627 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1628 { WM_SETFOCUS, sent|parent },
1629 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1630 { WM_DESTROY, sent },
1631 { WM_DESTROY, sent|optional }, /* some other (IME?) window */
1632 { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
1633 { WM_NCDESTROY, sent },
1634 { 0 }
1636 /* visible child window destroyed by thread exit */
1637 static const struct message WmExitThreadSeq[] = {
1638 { WM_NCDESTROY, sent }, /* actually in grandchild */
1639 { WM_PAINT, sent|parent },
1640 { WM_ERASEBKGND, sent|parent|beginpaint },
1641 { 0 }
1643 /* DestroyWindow for a visible child window with invisible parent */
1644 static const struct message WmDestroyInvisibleChildSeq[] = {
1645 { HCBT_DESTROYWND, hook },
1646 { 0x0090, sent|optional },
1647 { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1648 { WM_SHOWWINDOW, sent|wparam, 0 },
1649 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1650 { WM_DESTROY, sent },
1651 { WM_NCDESTROY, sent },
1652 { 0 }
1654 /* Resizing child window with MoveWindow (32) */
1655 static const struct message WmResizingChildWithMoveWindowSeq[] = {
1656 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
1657 { WM_NCCALCSIZE, sent|wparam, 1 },
1658 { WM_ERASEBKGND, sent|parent|optional },
1659 { WM_ERASEBKGND, sent|optional },
1660 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
1661 { WM_MOVE, sent|defwinproc },
1662 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1663 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1664 { 0 }
1666 /* Creation of a custom dialog (32) */
1667 static const struct message WmCreateCustomDialogSeq[] = {
1668 { HCBT_CREATEWND, hook },
1669 { WM_GETMINMAXINFO, sent },
1670 { WM_NCCREATE, sent },
1671 { WM_NCCALCSIZE, sent|wparam, 0 },
1672 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win10. */
1673 { WM_CREATE, sent },
1674 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1675 { WM_NOTIFYFORMAT, sent|optional },
1676 { WM_QUERYUISTATE, sent|optional },
1677 { WM_WINDOWPOSCHANGING, sent|optional },
1678 { WM_GETMINMAXINFO, sent|optional },
1679 { WM_NCCALCSIZE, sent|optional },
1680 { WM_WINDOWPOSCHANGED, sent|optional },
1681 { WM_SHOWWINDOW, sent|wparam, 1 },
1682 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1683 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1684 { HCBT_ACTIVATE, hook },
1685 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1688 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1690 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1692 { WM_NCACTIVATE, sent },
1693 { WM_GETTEXT, sent|optional|defwinproc },
1694 { WM_GETTEXT, sent|optional|defwinproc },
1695 { WM_GETTEXT, sent|optional|defwinproc },
1696 { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1697 { WM_ACTIVATE, sent|wparam, 1 },
1698 { WM_GETTEXT, sent|optional },
1699 { WM_KILLFOCUS, sent|parent },
1700 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1701 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1702 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1703 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1704 { WM_SETFOCUS, sent },
1705 { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1706 { WM_NCPAINT, sent|wparam, 1 },
1707 { WM_GETTEXT, sent|optional|defwinproc },
1708 { WM_GETTEXT, sent|optional|defwinproc },
1709 { WM_ERASEBKGND, sent },
1710 { WM_CTLCOLORDLG, sent|optional|defwinproc },
1711 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1712 { WM_GETTEXT, sent|optional },
1713 { WM_GETTEXT, sent|optional },
1714 { WM_NCCALCSIZE, sent|optional },
1715 { WM_NCPAINT, sent|optional },
1716 { WM_GETTEXT, sent|optional|defwinproc },
1717 { WM_GETTEXT, sent|optional|defwinproc },
1718 { WM_ERASEBKGND, sent|optional },
1719 { WM_CTLCOLORDLG, sent|optional|defwinproc },
1720 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win10. */
1721 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1722 { WM_MOVE, sent },
1723 { 0 }
1725 /* Calling EndDialog for a custom dialog (32) */
1726 static const struct message WmEndCustomDialogSeq[] = {
1727 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1728 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1729 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1730 { WM_GETTEXT, sent|optional },
1731 { HCBT_ACTIVATE, hook },
1732 { WM_NCACTIVATE, sent|wparam, 0 },
1733 { WM_GETTEXT, sent|optional|defwinproc },
1734 { WM_GETTEXT, sent|optional|defwinproc },
1735 { WM_ACTIVATE, sent|wparam, 0 },
1736 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1737 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1738 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1739 { WM_GETTEXT, sent|optional|defwinproc },
1740 { WM_GETTEXT, sent|optional|defwinproc },
1741 { HCBT_SETFOCUS, hook },
1742 { WM_KILLFOCUS, sent },
1743 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1744 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1745 { WM_IME_NOTIFY, sent|wparam|optional, 1 },
1746 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1747 { WM_SETFOCUS, sent|parent|defwinproc },
1748 { 0 }
1750 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
1751 static const struct message WmShowCustomDialogSeq[] = {
1752 { WM_SHOWWINDOW, sent|wparam, 1 },
1753 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1754 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1755 { HCBT_ACTIVATE, hook },
1756 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1758 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1760 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1761 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1762 { WM_NCACTIVATE, sent },
1763 { WM_ACTIVATE, sent|wparam, 1 },
1764 { WM_GETTEXT, sent|optional },
1766 { WM_KILLFOCUS, sent|parent },
1767 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1768 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1769 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1770 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1771 { WM_SETFOCUS, sent },
1772 { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1773 { WM_NCPAINT, sent|wparam, 1 },
1774 { WM_ERASEBKGND, sent },
1775 { WM_CTLCOLORDLG, sent|defwinproc },
1776 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1777 { 0 }
1779 /* Creation and destruction of a modal dialog (32) */
1780 static const struct message WmModalDialogSeq[] = {
1781 { WM_CANCELMODE, sent|parent },
1782 { HCBT_SETFOCUS, hook },
1783 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1784 { WM_KILLFOCUS, sent|parent },
1785 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1786 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1787 { WM_ENABLE, sent|parent|wparam, 0 },
1788 { HCBT_CREATEWND, hook },
1789 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win10. */
1790 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1791 { WM_SETFONT, sent },
1792 { WM_INITDIALOG, sent },
1793 { WM_CHANGEUISTATE, sent|optional },
1794 { WM_UPDATEUISTATE, sent|optional },
1795 { WM_SHOWWINDOW, sent },
1796 { HCBT_ACTIVATE, hook },
1797 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1798 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1799 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1800 { WM_NCACTIVATE, sent },
1801 { WM_GETTEXT, sent|optional },
1802 { WM_ACTIVATE, sent|wparam, 1 },
1803 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1804 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1805 { WM_NCPAINT, sent|optional },
1806 { WM_GETTEXT, sent|optional },
1807 { WM_ERASEBKGND, sent|optional },
1808 { WM_CTLCOLORDLG, sent|optional },
1809 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1810 { WM_GETTEXT, sent|optional },
1811 { WM_NCCALCSIZE, sent|optional },
1812 { WM_NCPAINT, sent|optional },
1813 { WM_GETTEXT, sent|optional },
1814 { WM_ERASEBKGND, sent|optional },
1815 { WM_CTLCOLORDLG, sent|optional },
1816 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win10. */
1817 { WM_PAINT, sent|optional },
1818 { WM_CTLCOLORBTN, sent|optional },
1819 { WM_GETTITLEBARINFOEX, sent|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_ENTERIDLE, sent|parent|optional },
1833 { WM_ENTERIDLE, sent|parent|optional },
1834 { WM_ENTERIDLE, sent|parent|optional },
1835 { WM_ENTERIDLE, sent|parent|optional },
1836 { WM_ENTERIDLE, sent|parent|optional },
1837 { WM_ENTERIDLE, sent|parent|optional },
1838 { WM_ENTERIDLE, sent|parent|optional },
1839 { WM_ENTERIDLE, sent|parent|optional },
1840 { WM_TIMER, sent },
1841 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1842 { WM_ENABLE, sent|parent|wparam, 1 },
1843 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1844 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1845 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1846 { WM_GETTEXT, sent|optional },
1847 { HCBT_ACTIVATE, hook },
1848 { WM_NCACTIVATE, sent|wparam, 0 },
1849 { WM_GETTEXT, sent|optional },
1850 { WM_ACTIVATE, sent|wparam, 0 },
1851 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1852 { WM_WINDOWPOSCHANGING, sent|optional },
1853 { WM_WINDOWPOSCHANGED, sent|optional },
1854 { HCBT_SETFOCUS, hook },
1855 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1856 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1857 { WM_SETFOCUS, sent|parent|defwinproc },
1858 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1859 { HCBT_DESTROYWND, hook },
1860 { 0x0090, sent|optional },
1861 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1862 { WM_DESTROY, sent },
1863 { WM_NCDESTROY, sent },
1864 { 0 }
1866 static const struct message WmModalDialogSeq_2[] = {
1867 { WM_CANCELMODE, sent },
1868 { HCBT_SETFOCUS, hook },
1869 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1870 { WM_KILLFOCUS, sent },
1871 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1872 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1873 { WM_ENABLE, sent|wparam, 0 },
1874 { HCBT_CREATEWND, hook },
1875 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
1876 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1877 { WM_SETFONT, sent },
1878 { WM_INITDIALOG, sent },
1879 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1880 { WM_CHANGEUISTATE, sent|optional },
1881 { WM_UPDATEUISTATE, sent|optional },
1882 { WM_ENABLE, sent|wparam, 1 },
1883 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1884 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 },
1885 { WM_CHANGEUISTATE, sent|optional },
1886 { WM_UPDATEUISTATE, sent|optional },
1887 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1888 { HCBT_DESTROYWND, hook },
1889 { 0x0090, sent|optional },
1890 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1891 { WM_DESTROY, sent },
1892 { WM_NCDESTROY, sent },
1893 { 0 }
1895 /* SetMenu for NonVisible windows with size change*/
1896 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1897 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1898 { WM_NCCALCSIZE, sent|wparam, 1 },
1899 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1900 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1901 { WM_MOVE, sent|defwinproc },
1902 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1903 { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1904 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1905 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1906 { WM_GETTEXT, sent|optional },
1907 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1908 { 0 }
1910 /* SetMenu for NonVisible windows with no size change */
1911 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1912 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1913 { WM_NCCALCSIZE, sent|wparam, 1 },
1914 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1915 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1916 { 0 }
1918 /* SetMenu for Visible windows with size change */
1919 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1920 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1921 { WM_NCCALCSIZE, sent|wparam, 1 },
1922 { 0x0093, sent|defwinproc|optional },
1923 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1924 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1925 { 0x0093, sent|defwinproc|optional },
1926 { 0x0093, sent|defwinproc|optional },
1927 { 0x0091, sent|defwinproc|optional },
1928 { 0x0092, sent|defwinproc|optional },
1929 { WM_GETTEXT, sent|defwinproc|optional },
1930 { WM_ERASEBKGND, sent|optional },
1931 { WM_ACTIVATE, sent|optional },
1932 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1933 { WM_MOVE, sent|defwinproc },
1934 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1935 { 0x0093, sent|optional },
1936 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1937 { 0x0093, sent|defwinproc|optional },
1938 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1939 { 0x0093, sent|defwinproc|optional },
1940 { 0x0093, sent|defwinproc|optional },
1941 { 0x0091, sent|defwinproc|optional },
1942 { 0x0092, sent|defwinproc|optional },
1943 { WM_ERASEBKGND, sent|optional },
1944 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1945 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1946 { 0 }
1948 /* SetMenu for Visible windows with no size change */
1949 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1950 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1951 { WM_NCCALCSIZE, sent|wparam, 1 },
1952 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1953 { WM_GETTEXT, sent|defwinproc|optional },
1954 { WM_ERASEBKGND, sent|optional },
1955 { WM_ACTIVATE, sent|optional },
1956 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1957 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1958 { 0 }
1960 /* DrawMenuBar for a visible window */
1961 static const struct message WmDrawMenuBarSeq[] =
1963 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1964 { WM_NCCALCSIZE, sent|wparam, 1 },
1965 { 0x0093, sent|defwinproc|optional },
1966 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1967 { 0x0093, sent|defwinproc|optional },
1968 { 0x0093, sent|defwinproc|optional },
1969 { 0x0091, sent|defwinproc|optional },
1970 { 0x0092, sent|defwinproc|optional },
1971 { WM_GETTEXT, sent|defwinproc|optional },
1972 { WM_ERASEBKGND, sent|optional },
1973 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1974 { 0x0093, sent|optional },
1975 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1976 { 0 }
1979 static const struct message WmSetRedrawFalseSeq[] =
1981 { WM_SETREDRAW, sent|wparam, 0 },
1982 { 0 }
1985 static const struct message WmSetRedrawTrueSeq[] =
1987 { WM_SETREDRAW, sent|wparam, 1 },
1988 { 0 }
1991 static const struct message WmEnableWindowSeq_1[] =
1993 { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1994 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
1995 { HCBT_SETFOCUS, hook|optional },
1996 { WM_KILLFOCUS, sent|optional },
1997 { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1998 { 0 }
2001 static const struct message WmEnableWindowSeq_2[] =
2003 { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
2004 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win10. */
2005 { 0 }
2008 static const struct message WmEnableWindowSeq_3[] =
2010 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2011 { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
2012 { 0 }
2015 static const struct message WmEnableWindowSeq_4[] =
2017 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win10. */
2018 { 0 }
2021 static const struct message WmGetScrollRangeSeq[] =
2023 { SBM_GETRANGE, sent },
2024 { 0 }
2026 static const struct message WmGetScrollInfoSeq[] =
2028 { SBM_GETSCROLLINFO, sent },
2029 { 0 }
2031 static const struct message WmSetScrollRangeSeq[] =
2033 /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
2034 sends SBM_SETSCROLLINFO.
2036 { SBM_SETSCROLLINFO, sent },
2037 { 0 }
2039 /* SetScrollRange for a window without a non-client area */
2040 static const struct message WmSetScrollRangeHSeq_empty[] =
2042 { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_HSCROLL, 0 },
2043 { 0 }
2045 static const struct message WmSetScrollRangeVSeq_empty[] =
2047 { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_VSCROLL, 0 },
2048 { 0 }
2050 static const struct message WmSetScrollRangeHVSeq[] =
2052 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
2053 { WM_NCCALCSIZE, sent|wparam, 1 },
2054 { WM_GETTEXT, sent|defwinproc|optional },
2055 { WM_ERASEBKGND, sent|optional },
2056 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2057 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2058 { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
2059 { 0 }
2061 /* SetScrollRange for a window with a non-client area */
2062 static const struct message WmSetScrollRangeHV_NC_Seq[] =
2064 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
2065 { WM_NCCALCSIZE, sent|wparam, 1 },
2066 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2067 { WM_NCPAINT, sent|optional },
2068 { WM_STYLECHANGING, sent|defwinproc|optional },
2069 { WM_STYLECHANGED, sent|defwinproc|optional },
2070 { WM_STYLECHANGING, sent|defwinproc|optional },
2071 { WM_STYLECHANGED, sent|defwinproc|optional },
2072 { WM_STYLECHANGING, sent|defwinproc|optional },
2073 { WM_STYLECHANGED, sent|defwinproc|optional },
2074 { WM_STYLECHANGING, sent|defwinproc|optional },
2075 { WM_STYLECHANGED, sent|defwinproc|optional },
2076 { WM_GETTEXT, sent|defwinproc|optional },
2077 { WM_GETTEXT, sent|defwinproc|optional },
2078 { WM_ERASEBKGND, sent|optional },
2079 { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
2080 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOCLIENTSIZE },
2081 { WM_SIZE, sent|defwinproc|optional },
2082 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2083 { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
2084 { WM_GETTEXT, sent|optional },
2085 { WM_GETTEXT, sent|optional },
2086 { WM_GETTEXT, sent|optional },
2087 { WM_GETTEXT, sent|optional },
2088 { 0 }
2090 /* test if we receive the right sequence of messages */
2091 /* after calling ShowWindow( SW_SHOWNA) */
2092 static const struct message WmSHOWNAChildInvisParInvis[] = {
2093 { WM_SHOWWINDOW, sent|wparam, 1 },
2094 { 0 }
2096 static const struct message WmSHOWNAChildVisParInvis[] = {
2097 { WM_SHOWWINDOW, sent|wparam, 1 },
2098 { 0 }
2100 static const struct message WmSHOWNAChildVisParVis[] = {
2101 { WM_SHOWWINDOW, sent|wparam, 1 },
2102 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
2103 { 0 }
2105 static const struct message WmSHOWNAChildInvisParVis[] = {
2106 { WM_SHOWWINDOW, sent|wparam, 1 },
2107 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2108 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2109 { WM_ERASEBKGND, sent|optional },
2110 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
2111 { 0 }
2113 static const struct message WmSHOWNATopVisible[] = {
2114 { WM_SHOWWINDOW, sent|wparam, 1 },
2115 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
2116 { WM_NCPAINT, sent|wparam|optional, 1 },
2117 { WM_GETTEXT, sent|defwinproc|optional },
2118 { WM_ERASEBKGND, sent|optional },
2119 { WM_WINDOWPOSCHANGED, sent|optional },
2120 { 0 }
2122 static const struct message WmSHOWNATopInvisible[] = {
2123 { WM_NOTIFYFORMAT, sent|optional },
2124 { WM_QUERYUISTATE, sent|optional },
2125 { WM_WINDOWPOSCHANGING, sent|optional },
2126 { WM_GETMINMAXINFO, sent|optional },
2127 { WM_NCCALCSIZE, sent|optional },
2128 { WM_WINDOWPOSCHANGED, sent|optional },
2129 { WM_SHOWWINDOW, sent|wparam, 1 },
2130 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2131 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2132 { WM_NCPAINT, sent|wparam|optional, 1 },
2133 { WM_GETTEXT, sent|defwinproc|optional },
2134 { WM_ERASEBKGND, sent|optional },
2135 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2136 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2137 { WM_NCPAINT, sent|wparam|optional, 1 },
2138 { WM_ERASEBKGND, sent|optional },
2139 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends it, but Win8+ doesn't. */
2140 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2141 { WM_MOVE, sent },
2142 { 0 }
2145 static const struct message WmTrackPopupMenuMinimizeWindow[] = {
2146 { HCBT_CREATEWND, hook },
2147 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2148 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
2149 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2150 { WM_INITMENU, sent|lparam, 0, 0 },
2151 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2152 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
2153 { 0x0093, sent|optional },
2154 { 0x0094, sent|optional },
2155 { 0x0094, sent|optional },
2156 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2157 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2158 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
2159 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
2160 { WM_ENTERIDLE, sent|wparam, 2 },
2161 { HCBT_MINMAX, hook },
2162 { HCBT_SETFOCUS, hook },
2163 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2164 { WM_KILLFOCUS, sent|wparam, 0 },
2165 { WM_GETTEXT, sent|optional },
2166 { WM_WINDOWPOSCHANGING, sent },
2167 { WM_GETMINMAXINFO, sent|defwinproc },
2168 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2169 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2170 { WM_WINDOWPOSCHANGED, sent },
2171 { WM_MOVE, sent|defwinproc },
2172 { WM_SIZE, sent|defwinproc },
2173 { WM_GETTEXT, sent|optional },
2174 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2175 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2176 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
2177 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2178 { WM_CANCELMODE, sent },
2179 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2180 { WM_CAPTURECHANGED, sent|defwinproc },
2181 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
2182 { HCBT_DESTROYWND, hook },
2183 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2184 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2185 { WM_UNINITMENUPOPUP, sent|defwinproc|lparam, 0, 0 },
2186 { WM_MENUSELECT, sent|defwinproc|wparam|lparam, 0xffff0000, 0 },
2187 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2188 { WM_EXITMENULOOP, sent|defwinproc|wparam|lparam, 1, 0 },
2189 { WM_NCACTIVATE, sent },
2190 { WM_GETTEXT, sent|defwinproc|optional },
2191 { WM_GETTEXT, sent|defwinproc|optional },
2192 { WM_ACTIVATE, sent },
2193 { WM_ACTIVATEAPP, sent|wparam, 0 },
2194 { 0 }
2197 static const struct message WmTrackPopupMenu[] = {
2198 { HCBT_CREATEWND, hook },
2199 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2200 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
2201 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2202 { WM_INITMENU, sent|lparam, 0, 0 },
2203 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2204 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
2205 { 0x0093, sent|optional },
2206 { 0x0094, sent|optional },
2207 { 0x0094, sent|optional },
2208 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2209 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2210 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
2211 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
2212 { WM_ENTERIDLE, sent|wparam, 2 },
2213 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2214 { WM_CAPTURECHANGED, sent },
2215 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
2216 { HCBT_DESTROYWND, hook },
2217 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2218 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2219 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
2220 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
2221 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2222 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
2223 { 0 }
2226 static const struct message WmTrackPopupMenuEsc[] = {
2227 { 0 }
2230 static const struct message WmTrackPopupMenuCapture[] = {
2231 { HCBT_CREATEWND, hook },
2232 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2233 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
2234 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2235 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2236 { WM_CAPTURECHANGED, sent },
2237 { WM_INITMENU, sent|lparam, 0, 0 },
2238 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2239 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
2240 { 0x0093, sent|optional },
2241 { 0x0094, sent|optional },
2242 { 0x0094, sent|optional },
2243 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2244 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2245 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
2246 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
2247 { WM_ENTERIDLE, sent|wparam, 2 },
2248 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2249 { WM_CAPTURECHANGED, sent },
2250 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
2251 { HCBT_DESTROYWND, hook },
2252 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2253 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2254 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
2255 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
2256 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2257 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
2258 { 0 }
2261 static const struct message WmTrackPopupMenuEmpty[] = {
2262 { HCBT_CREATEWND, hook },
2263 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2264 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
2265 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2266 { WM_INITMENU, sent|lparam, 0, 0 },
2267 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2268 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
2269 { 0x0093, sent|optional },
2270 { 0x0094, sent|optional },
2271 { 0x0094, sent|optional },
2272 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2273 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2274 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2275 { WM_CAPTURECHANGED, sent },
2276 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
2277 { HCBT_DESTROYWND, hook },
2278 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2279 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
2280 { 0 }
2283 static const struct message WmTrackPopupMenuAbort[] = {
2284 { HCBT_CREATEWND, hook },
2285 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2286 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
2287 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2288 { WM_INITMENU, sent|lparam, 0, 0 },
2289 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2290 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
2291 { 0x0093, sent|optional },
2292 { 0x0094, sent|optional },
2293 { 0x0094, sent|optional },
2294 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2295 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2296 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
2297 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
2298 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2299 { WM_CAPTURECHANGED, sent },
2300 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
2301 { HCBT_DESTROYWND, hook },
2302 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2303 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2304 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
2305 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
2306 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2307 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
2308 { 0 }
2311 static BOOL after_end_dialog, test_def_id, paint_loop_done;
2312 static int sequence_cnt, sequence_size;
2313 static struct recvd_message* sequence;
2314 static int log_all_parent_messages;
2315 static CRITICAL_SECTION sequence_cs;
2317 /* user32 functions */
2318 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
2319 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
2320 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
2321 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
2322 static BOOL (WINAPI *pUpdateLayeredWindow)(HWND,HDC,POINT*,SIZE*,HDC,POINT*,COLORREF,BLENDFUNCTION*,DWORD);
2323 static UINT_PTR (WINAPI *pSetSystemTimer)(HWND, UINT_PTR, UINT, TIMERPROC);
2324 static UINT_PTR (WINAPI *pKillSystemTimer)(HWND, UINT_PTR);
2325 static UINT_PTR (WINAPI *pSetCoalescableTimer)(HWND, UINT_PTR, UINT, TIMERPROC, ULONG);
2326 /* kernel32 functions */
2327 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
2329 static void init_procs(void)
2331 HMODULE user32 = GetModuleHandleA("user32.dll");
2332 HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
2334 #define GET_PROC(dll, func) \
2335 p ## func = (void*)GetProcAddress(dll, #func); \
2336 if(!p ## func) { \
2337 trace("GetProcAddress(%s) failed\n", #func); \
2340 GET_PROC(user32, NotifyWinEvent)
2341 GET_PROC(user32, SetWinEventHook)
2342 GET_PROC(user32, TrackMouseEvent)
2343 GET_PROC(user32, UnhookWinEvent)
2344 GET_PROC(user32, UpdateLayeredWindow)
2345 GET_PROC(user32, SetSystemTimer)
2346 GET_PROC(user32, KillSystemTimer)
2347 GET_PROC(user32, SetCoalescableTimer)
2349 GET_PROC(kernel32, GetCPInfoExA)
2351 #undef GET_PROC
2354 static const char *get_winpos_flags(UINT flags)
2356 static char buffer[300];
2358 buffer[0] = 0;
2359 #define DUMP(flag) do { if (flags & flag) { strcat( buffer, "|" #flag ); flags &= ~flag; } } while(0)
2360 DUMP( SWP_SHOWWINDOW );
2361 DUMP( SWP_HIDEWINDOW );
2362 DUMP( SWP_NOACTIVATE );
2363 DUMP( SWP_FRAMECHANGED );
2364 DUMP( SWP_NOCOPYBITS );
2365 DUMP( SWP_NOOWNERZORDER );
2366 DUMP( SWP_NOSENDCHANGING );
2367 DUMP( SWP_DEFERERASE );
2368 DUMP( SWP_ASYNCWINDOWPOS );
2369 DUMP( SWP_NOZORDER );
2370 DUMP( SWP_NOREDRAW );
2371 DUMP( SWP_NOSIZE );
2372 DUMP( SWP_NOMOVE );
2373 DUMP( SWP_NOCLIENTSIZE );
2374 DUMP( SWP_NOCLIENTMOVE );
2375 if (flags) sprintf(buffer + strlen(buffer),"|0x%04x", flags);
2376 return buffer + 1;
2377 #undef DUMP
2380 static BOOL ignore_message( UINT message )
2382 /* these are always ignored */
2383 return (message >= 0xc000 ||
2384 message == WM_GETICON ||
2385 message == WM_GETOBJECT ||
2386 message == WM_TIMECHANGE ||
2387 message == WM_DISPLAYCHANGE ||
2388 message == WM_DEVICECHANGE ||
2389 message == WM_DWMNCRENDERINGCHANGED ||
2390 message == WM_WININICHANGE);
2393 static unsigned hash_Ly_W(const WCHAR *str)
2395 unsigned hash = 0;
2397 for (; *str; str++)
2398 hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u;
2400 return hash;
2403 static unsigned hash_Ly(const char *str)
2405 unsigned hash = 0;
2407 for (; *str; str++)
2408 hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u;
2410 return hash;
2413 #define add_message(msg) add_message_(__LINE__,msg);
2414 static void add_message_(int line, const struct recvd_message *msg)
2416 struct recvd_message *seq;
2418 EnterCriticalSection( &sequence_cs );
2419 if (!sequence)
2421 sequence_size = 10;
2422 sequence = malloc( sequence_size * sizeof(*sequence) );
2424 if (sequence_cnt == sequence_size)
2426 sequence_size *= 2;
2427 sequence = realloc( sequence, sequence_size * sizeof(*sequence) );
2430 seq = &sequence[sequence_cnt++];
2431 seq->hwnd = msg->hwnd;
2432 seq->message = msg->message;
2433 seq->flags = msg->flags;
2434 seq->wParam = msg->wParam;
2435 seq->lParam = msg->lParam;
2436 seq->line = line;
2437 seq->descr = msg->descr;
2438 seq->output[0] = 0;
2439 LeaveCriticalSection( &sequence_cs );
2441 if (msg->descr)
2443 if (msg->flags & hook)
2445 static const char * const CBT_code_name[10] =
2447 "HCBT_MOVESIZE",
2448 "HCBT_MINMAX",
2449 "HCBT_QS",
2450 "HCBT_CREATEWND",
2451 "HCBT_DESTROYWND",
2452 "HCBT_ACTIVATE",
2453 "HCBT_CLICKSKIPPED",
2454 "HCBT_KEYSKIPPED",
2455 "HCBT_SYSCOMMAND",
2456 "HCBT_SETFOCUS"
2458 const char *code_name = (msg->message <= HCBT_SETFOCUS) ? CBT_code_name[msg->message] : "Unknown";
2460 sprintf( seq->output, "%s: hook %d (%s) wp %08Ix lp %08Ix",
2461 msg->descr, msg->message, code_name, msg->wParam, msg->lParam );
2463 else if (msg->flags & winevent_hook)
2465 sprintf( seq->output, "%s: winevent %p %08x %08Ix %08Ix",
2466 msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
2468 else
2470 switch (msg->message)
2472 case WM_WINDOWPOSCHANGING:
2473 case WM_WINDOWPOSCHANGED:
2475 WINDOWPOS *winpos = (WINDOWPOS *)msg->lParam;
2477 sprintf( seq->output, "%s: %p WM_WINDOWPOS%s wp %08Ix lp %08Ix after %p x %d y %d cx %d cy %d flags %s",
2478 msg->descr, msg->hwnd,
2479 (msg->message == WM_WINDOWPOSCHANGING) ? "CHANGING" : "CHANGED",
2480 msg->wParam, msg->lParam, winpos->hwndInsertAfter,
2481 winpos->x, winpos->y, winpos->cx, winpos->cy,
2482 get_winpos_flags(winpos->flags) );
2484 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2485 * in the high word for internal purposes
2487 seq->wParam = winpos->flags & 0xffff;
2488 /* We are not interested in the flags that don't match under XP and Win9x */
2489 seq->wParam &= ~SWP_NOZORDER;
2490 seq->lParam = (!!winpos->cx) | ((!!winpos->cy) << 1)
2491 | ((!!winpos->x) << 2) | ((!!winpos->y) << 3);
2492 break;
2495 case WM_NCCALCSIZE:
2496 if (msg->wParam)
2498 NCCALCSIZE_PARAMS *p = (NCCALCSIZE_PARAMS *)msg->lParam;
2499 WINDOWPOS *winpos = p->lppos;
2501 sprintf(seq->output, "%s: %p WM_NCCALCSIZE: winpos->cx %u, winpos->cy %u",
2502 msg->descr, msg->hwnd, winpos->cx, winpos->cy);
2503 seq->lParam = (!!winpos->cx) | ((!!winpos->cy) << 1)
2504 | ((!!winpos->x) << 2) | ((!!winpos->y) << 3);
2506 else
2508 RECT *rect = (RECT*)msg->lParam;
2510 sprintf(seq->output, "%s: %p WM_NCCALCSIZE: %s",
2511 msg->descr, msg->hwnd, wine_dbgstr_rect(rect));
2512 seq->lParam = 0;
2514 break;
2515 case WM_DRAWITEM:
2517 DRAW_ITEM_STRUCT di;
2518 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)msg->lParam;
2520 sprintf( seq->output, "%s: %p WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x",
2521 msg->descr, msg->hwnd, dis->CtlType, dis->CtlID,
2522 dis->itemID, dis->itemAction, dis->itemState);
2524 di.u.lp = 0;
2525 di.u.item.type = dis->CtlType;
2526 di.u.item.ctl_id = dis->CtlID;
2527 if (dis->CtlType == ODT_LISTBOX ||
2528 dis->CtlType == ODT_COMBOBOX ||
2529 dis->CtlType == ODT_MENU)
2530 di.u.item.item_id = dis->itemID;
2531 di.u.item.action = dis->itemAction;
2532 di.u.item.state = dis->itemState;
2534 seq->lParam = di.u.lp;
2535 break;
2538 case WM_MEASUREITEM:
2540 MEASURE_ITEM_STRUCT mi;
2541 MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)msg->lParam;
2542 BOOL is_unicode_data = TRUE;
2544 sprintf( seq->output, "%s: %p WM_MEASUREITEM: CtlType %#x, CtlID %#x, itemID %#x, itemData %#Ix",
2545 msg->descr, msg->hwnd, mis->CtlType, mis->CtlID,
2546 mis->itemID, mis->itemData);
2548 if (mis->CtlType == ODT_LISTBOX)
2550 HWND ctrl = GetDlgItem(msg->hwnd, mis->CtlID);
2551 is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
2554 mi.u.wp = 0;
2555 mi.u.item.CtlType = mis->CtlType;
2556 mi.u.item.CtlID = mis->CtlID;
2557 mi.u.item.itemID = mis->itemID;
2558 mi.u.item.wParam = msg->wParam;
2559 seq->wParam = mi.u.wp;
2560 if (is_unicode_data)
2561 seq->lParam = mis->itemData ? hash_Ly_W((const WCHAR *)mis->itemData) : 0;
2562 else
2563 seq->lParam = mis->itemData ? hash_Ly((const char *)mis->itemData) : 0;
2564 break;
2567 case WM_COMPAREITEM:
2569 COMPAREITEMSTRUCT *cis = (COMPAREITEMSTRUCT *)msg->lParam;
2570 HWND ctrl = GetDlgItem(msg->hwnd, cis->CtlID);
2571 BOOL is_unicode_data = TRUE;
2573 ok(msg->wParam == cis->CtlID, "expected %#x, got %#Ix\n", cis->CtlID, msg->wParam);
2574 ok(cis->hwndItem == ctrl, "expected %p, got %p\n", ctrl, cis->hwndItem);
2575 ok((int)cis->itemID1 >= 0, "expected >= 0, got %d\n", cis->itemID1);
2576 ok((int)cis->itemID2 == -1, "expected -1, got %d\n", cis->itemID2);
2578 sprintf( seq->output, "%s: %p WM_COMPAREITEM: CtlType %#x, CtlID %#x, itemID1 %#x, itemData1 %#Ix, itemID2 %#x, itemData2 %#Ix",
2579 msg->descr, msg->hwnd, cis->CtlType, cis->CtlID,
2580 cis->itemID1, cis->itemData1, cis->itemID2, cis->itemData2);
2582 if (cis->CtlType == ODT_LISTBOX)
2583 is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
2585 if (is_unicode_data)
2587 seq->wParam = cis->itemData1 ? hash_Ly_W((const WCHAR *)cis->itemData1) : 0;
2588 seq->lParam = cis->itemData2 ? hash_Ly_W((const WCHAR *)cis->itemData2) : 0;
2590 else
2592 seq->wParam = cis->itemData1 ? hash_Ly((const char *)cis->itemData1) : 0;
2593 seq->lParam = cis->itemData2 ? hash_Ly((const char *)cis->itemData2) : 0;
2595 break;
2598 default:
2599 if (msg->message >= 0xc000) return; /* ignore registered messages */
2600 sprintf( seq->output, "%s: %p %04x wp %08Ix lp %08Ix",
2601 msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
2603 if (msg->flags & (sent|posted|parent|defwinproc|beginpaint))
2604 sprintf( seq->output + strlen(seq->output), " (flags %x)", msg->flags );
2609 /* try to make sure pending X events have been processed before continuing */
2610 static void flush_events(void)
2612 MSG msg;
2613 int diff = 200;
2614 int min_timeout = 100;
2615 DWORD time = GetTickCount() + diff;
2617 while (diff > 0)
2619 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
2620 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
2621 diff = time - GetTickCount();
2625 static void flush_sequence(void)
2627 EnterCriticalSection( &sequence_cs );
2628 free( sequence );
2629 sequence = 0;
2630 sequence_cnt = sequence_size = 0;
2631 LeaveCriticalSection( &sequence_cs );
2634 static const char* message_type_name(int flags) {
2635 if (flags & hook) return "hook";
2636 if (flags & kbd_hook) return "kbd_hook";
2637 if (flags & winevent_hook) return "winevent_hook";
2638 return "msg";
2641 static BOOL can_skip_message(const struct message *expected)
2643 if (expected->flags & optional) return TRUE;
2645 if ((expected->flags & winevent_hook) && !hEvent_hook) return TRUE;
2646 if ((expected->flags & kbd_hook) && !hKBD_hook) return TRUE;
2647 if ((expected->flags & hook) && !hCBT_hook) return TRUE;
2649 if ((expected->flags & winevent_hook_todo) && !strcmp(winetest_platform, "wine")) return TRUE;
2651 return FALSE;
2654 static BOOL messages_equal(const struct message *expected, const struct recvd_message *actual,
2655 BOOL expect_equal, const char* file, int line)
2657 int todo = (expected->flags & winevent_hook_todo) != 0;
2658 const int message_type_flags = hook|winevent_hook|kbd_hook;
2659 static int todo_reported;
2661 if (!todo && can_skip_message(expected))
2662 expect_equal = FALSE;
2664 if (!expected->message || !actual->message) {
2665 if (expect_equal && (!todo || !todo_reported++))
2666 todo_wine_if(todo)
2667 ok_( file, line) (FALSE, "the msg sequence is not complete: expected %s %04x - actual %s %04x\n",
2668 message_type_name(expected->flags), expected->message, message_type_name(actual->flags), actual->message);
2669 return FALSE;
2672 if (expected->message != actual->message ||
2673 (expected->flags & message_type_flags) != (actual->flags & message_type_flags))
2675 if (expect_equal && (!todo || !todo_reported++))
2676 todo_wine_if(todo)
2677 ok_( file, line) (FALSE, "the %s 0x%04x was expected, but got %s 0x%04x instead\n",
2678 message_type_name(expected->flags), expected->message, message_type_name(actual->flags), actual->message);
2679 return FALSE;
2682 if (expected->flags & optional)
2684 /* If a message can be sent in 2 different ways at the same time, we may need to treat
2685 * them as unequal so that the optional message can be properly skipped. */
2686 if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) {
2687 /* don't match messages if their defwinproc status differs */
2688 return FALSE;
2692 if (expect_equal)
2693 todo_wine_if(todo)
2694 ok_( file, line) (TRUE, "got %s 0x%04x as expected\n",
2695 message_type_name(expected->flags), expected->message);
2697 return TRUE;
2700 static BOOL sequence_contains_message(const struct message *expected, const struct recvd_message *actual)
2702 while (expected->message)
2704 if (messages_equal(expected, actual, FALSE, __FILE__, __LINE__))
2705 return TRUE;
2706 expected++;
2708 return FALSE;
2711 static void dump_sequence(const struct message *expected, const char *context, const char *file, int line)
2713 const struct recvd_message *actual = sequence;
2714 unsigned int count = 0;
2716 trace_(file, line)("Failed sequence %s:\n", context );
2717 while (expected->message && actual->message)
2719 if (actual->output[0])
2721 trace_(file, line)( " %u: expected: %s %04x - actual: %s\n",
2722 count, message_type_name(expected->flags), expected->message, actual->output );
2725 if (messages_equal(expected, actual, FALSE, file, line))
2727 expected++;
2728 actual++;
2729 count++;
2731 else if (can_skip_message(expected) || sequence_contains_message(expected, actual))
2733 expected++;
2734 count++;
2736 else
2738 actual++;
2742 /* optional trailing messages */
2743 while (can_skip_message(expected))
2745 trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2746 expected++;
2747 count++;
2750 if (expected->message)
2752 trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2753 return;
2756 while (actual->message && actual->output[0])
2758 trace_(file, line)( " %u: expected: nothing - actual: %s\n", count, actual->output );
2759 actual++;
2760 count++;
2764 #define ok_sequence( exp, contx, todo) \
2765 ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
2768 static void ok_sequence_(const struct message *expected_list, const char *context, BOOL todo,
2769 const char *file, int line)
2771 static const struct recvd_message end_of_sequence;
2772 const struct message *expected = expected_list;
2773 const struct recvd_message *actual;
2774 int failcount = 0, dump = 0;
2775 unsigned int count = 0;
2776 BOOL is_wine = !strcmp(winetest_platform, "wine");
2778 add_message(&end_of_sequence);
2780 actual = sequence;
2782 winetest_push_context("%s: %u", context, count);
2784 while (expected->message && actual->message)
2786 if (messages_equal(expected, actual, !todo, file, line))
2788 if (expected->flags & wparam)
2790 if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && todo)
2792 todo_wine {
2793 failcount ++;
2794 dump++;
2795 ok_( file, line) (FALSE,
2796 "in msg 0x%04x expecting wParam 0x%Ix got 0x%Ix\n",
2797 expected->message, expected->wParam, actual->wParam);
2799 if (is_wine) goto done;
2801 else
2803 ok_( file, line)( ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) == 0,
2804 "in msg 0x%04x expecting wParam 0x%Ix got 0x%Ix\n",
2805 expected->message, expected->wParam, actual->wParam);
2806 if ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) dump++;
2810 if (expected->flags & lparam)
2812 if (((expected->lParam ^ actual->lParam) & ~expected->lp_mask) && todo)
2814 todo_wine {
2815 failcount ++;
2816 dump++;
2817 ok_( file, line) (FALSE,
2818 "in msg 0x%04x expecting lParam 0x%Ix got 0x%Ix\n",
2819 expected->message, expected->lParam, actual->lParam);
2821 if (is_wine) goto done;
2823 else
2825 ok_( file, line)(((expected->lParam ^ actual->lParam) & ~expected->lp_mask) == 0,
2826 "in msg 0x%04x expecting lParam 0x%Ix got 0x%Ix\n",
2827 expected->message, expected->lParam, actual->lParam);
2828 if ((expected->lParam ^ actual->lParam) & ~expected->lp_mask) dump++;
2831 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
2833 todo_wine {
2834 failcount ++;
2835 dump++;
2836 ok_( file, line) (FALSE,
2837 "the msg 0x%04x should %shave been sent by DefWindowProc\n",
2838 expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2840 if (is_wine) goto done;
2842 else
2844 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
2845 "the msg 0x%04x should %shave been sent by DefWindowProc\n",
2846 expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2847 if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++;
2850 ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
2851 "the msg 0x%04x should %shave been sent by BeginPaint\n",
2852 expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
2853 if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++;
2855 ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
2856 "the msg 0x%04x should have been %s\n",
2857 expected->message, (expected->flags & posted) ? "posted" : "sent");
2858 if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++;
2860 ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
2861 "the msg 0x%04x was expected in %s\n",
2862 expected->message, (expected->flags & parent) ? "parent" : "child");
2863 if ((expected->flags & parent) != (actual->flags & parent)) dump++;
2865 expected++;
2866 count++;
2867 actual++;
2870 * silently drop hook messages if there is no support for them
2872 else if (can_skip_message(expected))
2874 expected++;
2875 count++;
2877 else if (todo)
2879 todo_wine messages_equal(expected, actual, TRUE, file, line);
2880 failcount++;
2881 dump++;
2882 goto done;
2884 else if (sequence_contains_message(expected, actual))
2886 dump++;
2887 expected++;
2888 count++;
2890 else
2892 dump++;
2893 actual++;
2896 winetest_pop_context();
2897 winetest_push_context("%s: %u", context, count);
2900 /* skip all optional trailing messages */
2901 while (can_skip_message(expected))
2903 messages_equal(expected, actual, TRUE, file, line); /* check for message todo's */
2904 expected++;
2907 if (todo)
2909 todo_wine {
2910 if (expected->message || actual->message) {
2911 failcount++;
2912 dump++;
2913 messages_equal(expected, actual, TRUE, file, line);
2916 if (is_wine) goto done;
2918 else
2920 if (expected->message || actual->message)
2922 dump++;
2923 messages_equal(expected, actual, TRUE, file, line);
2926 if (todo && !failcount && !strcmp(winetest_platform, "wine")) /* succeeded yet marked todo */
2927 todo_wine {
2928 dump++;
2929 ok_( file, line)( TRUE, "marked \"todo_wine\" but succeeds\n");
2932 done:
2933 winetest_pop_context();
2934 if (dump && (!is_wine || winetest_debug > 1)) dump_sequence(expected_list, context, file, line);
2935 flush_sequence();
2938 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %ld\n", (EXPECTED), (GOT))
2940 /******************************** MDI test **********************************/
2942 /* CreateWindow for MDI frame window, initially visible */
2943 static const struct message WmCreateMDIframeSeq[] = {
2944 { HCBT_CREATEWND, hook },
2945 { WM_GETMINMAXINFO, sent },
2946 { WM_NCCREATE, sent },
2947 { WM_NCCALCSIZE, sent|wparam, 0 },
2948 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win8+. */
2949 { WM_CREATE, sent },
2950 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2951 { WM_NOTIFYFORMAT, sent|optional },
2952 { WM_QUERYUISTATE, sent|optional },
2953 { WM_WINDOWPOSCHANGING, sent|optional },
2954 { WM_GETMINMAXINFO, sent|optional },
2955 { WM_NCCALCSIZE, sent|optional },
2956 { WM_WINDOWPOSCHANGED, sent|optional },
2957 { WM_SHOWWINDOW, sent|wparam, 1 },
2958 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2959 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2960 { HCBT_ACTIVATE, hook },
2961 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2962 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
2963 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
2964 { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
2965 { WM_NCACTIVATE, sent },
2966 { WM_GETTEXT, sent|defwinproc|optional },
2967 { WM_ACTIVATE, sent|wparam, 1 },
2968 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
2969 { HCBT_SETFOCUS, hook },
2970 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2971 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2972 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
2973 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
2974 /* Win9x adds SWP_NOZORDER below */
2975 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2976 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2977 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win8+. */
2978 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2979 { WM_MOVE, sent },
2980 { 0 }
2982 /* DestroyWindow for MDI frame window, initially visible */
2983 static const struct message WmDestroyMDIframeSeq[] = {
2984 { HCBT_DESTROYWND, hook },
2985 { 0x0090, sent|optional },
2986 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2987 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2988 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2989 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2990 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
2991 { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2992 { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
2993 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
2994 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
2995 { WM_DESTROY, sent },
2996 { WM_NCDESTROY, sent },
2997 { 0 }
2999 /* CreateWindow for MDI client window, initially visible */
3000 static const struct message WmCreateMDIclientSeq[] = {
3001 { HCBT_CREATEWND, hook },
3002 { WM_NCCREATE, sent },
3003 { WM_NCCALCSIZE, sent|wparam, 0 },
3004 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
3005 { WM_CREATE, sent },
3006 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
3007 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3008 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3009 { WM_MOVE, sent },
3010 { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
3011 { WM_SHOWWINDOW, sent|wparam, 1 },
3012 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3013 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3014 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3015 { 0 }
3017 /* ShowWindow(SW_SHOW) for MDI client window */
3018 static const struct message WmShowMDIclientSeq[] = {
3019 { WM_SHOWWINDOW, sent|wparam, 1 },
3020 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3021 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3022 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3023 { 0 }
3025 /* ShowWindow(SW_HIDE) for MDI client window */
3026 static const struct message WmHideMDIclientSeq[] = {
3027 { WM_SHOWWINDOW, sent|wparam, 0 },
3028 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3029 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
3030 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
3031 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3032 { 0 }
3034 /* DestroyWindow for MDI client window, initially visible */
3035 static const struct message WmDestroyMDIclientSeq[] = {
3036 { HCBT_DESTROYWND, hook },
3037 { 0x0090, sent|optional },
3038 { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
3039 { WM_SHOWWINDOW, sent|wparam, 0 },
3040 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3041 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3042 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3043 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3044 { WM_DESTROY, sent },
3045 { WM_NCDESTROY, sent },
3046 { 0 }
3048 /* CreateWindow for MDI child window, initially visible */
3049 static const struct message WmCreateMDIchildVisibleSeq[] = {
3050 { HCBT_CREATEWND, hook },
3051 { WM_NCCREATE, sent },
3052 { WM_NCCALCSIZE, sent|wparam, 0 },
3053 { WM_CREATE, sent },
3054 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3055 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3056 { WM_MOVE, sent },
3057 /* Win2k sends wparam set to
3058 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3059 * while Win9x doesn't bother to set child window id according to
3060 * CLIENTCREATESTRUCT.idFirstChild
3062 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3063 { WM_SHOWWINDOW, sent|wparam, 1 },
3064 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3065 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3066 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3067 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
3068 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3069 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3070 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3072 /* Win9x: message sequence terminates here. */
3074 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3075 { HCBT_SETFOCUS, hook }, /* in MDI client */
3076 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3077 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
3078 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
3079 { WM_SETFOCUS, sent }, /* in MDI client */
3080 { HCBT_SETFOCUS, hook },
3081 { WM_KILLFOCUS, sent }, /* in MDI client */
3082 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3083 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3084 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3085 { WM_SETFOCUS, sent|defwinproc },
3086 { WM_MDIACTIVATE, sent|defwinproc },
3087 { 0 }
3089 /* WM_CHILDACTIVATE sent to disabled window */
3090 static const struct message WmChildActivateDisabledWindowSeq[] = {
3091 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3092 { 0 }
3094 /* WM_CHILDACTIVATE sent to enabled window */
3095 static const struct message WmChildActivateWindowSeq[] = {
3096 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3097 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 },
3098 { WM_MDIACTIVATE, sent|defwinproc },
3099 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3100 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
3101 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3102 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3103 { HCBT_SETFOCUS, hook },
3104 { WM_KILLFOCUS, sent|defwinproc },
3105 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3106 { WM_SETFOCUS, sent },
3107 { HCBT_SETFOCUS, hook },
3108 { WM_KILLFOCUS, sent },
3109 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3110 { WM_SETFOCUS, sent|defwinproc },
3111 { WM_MDIACTIVATE, sent|defwinproc },
3112 { 0 }
3114 /* CreateWindow for MDI child window with invisible parent */
3115 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
3116 { HCBT_CREATEWND, hook },
3117 { WM_GETMINMAXINFO, sent },
3118 { WM_NCCREATE, sent },
3119 { WM_NCCALCSIZE, sent|wparam, 0 },
3120 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
3121 { WM_CREATE, sent },
3122 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3123 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3124 { WM_MOVE, sent },
3125 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3126 { WM_SHOWWINDOW, sent|wparam, 1 },
3127 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
3128 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3129 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3130 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3132 /* Win9x: message sequence terminates here. */
3134 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3135 { HCBT_SETFOCUS, hook }, /* in MDI client */
3136 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3137 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
3138 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
3139 { WM_SETFOCUS, sent }, /* in MDI client */
3140 { HCBT_SETFOCUS, hook },
3141 { WM_KILLFOCUS, sent }, /* in MDI client */
3142 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3143 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3144 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3145 { WM_SETFOCUS, sent|defwinproc },
3146 { WM_MDIACTIVATE, sent|defwinproc },
3147 { 0 }
3149 /* DestroyWindow for MDI child window, initially visible */
3150 static const struct message WmDestroyMDIchildVisibleSeq[] = {
3151 { HCBT_DESTROYWND, hook },
3152 /* Win2k sends wparam set to
3153 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3154 * while Win9x doesn't bother to set child window id according to
3155 * CLIENTCREATESTRUCT.idFirstChild
3157 { 0x0090, sent|optional },
3158 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3159 { WM_SHOWWINDOW, sent|wparam, 0 },
3160 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3161 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3162 { WM_ERASEBKGND, sent|parent|optional },
3163 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3165 /* { WM_DESTROY, sent }
3166 * Win9x: message sequence terminates here.
3169 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
3170 { WM_KILLFOCUS, sent },
3171 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3172 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3173 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3174 { WM_SETFOCUS, sent }, /* in MDI client */
3176 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
3177 { WM_KILLFOCUS, sent }, /* in MDI client */
3178 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3179 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3180 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3181 { WM_SETFOCUS, sent }, /* in MDI client */
3183 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3185 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
3186 { WM_KILLFOCUS, sent },
3187 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3188 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3189 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3190 { WM_SETFOCUS, sent }, /* in MDI client */
3192 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
3193 { WM_KILLFOCUS, sent }, /* in MDI client */
3194 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3195 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3196 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3197 { WM_SETFOCUS, sent }, /* in MDI client */
3199 { WM_DESTROY, sent },
3201 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
3202 { WM_KILLFOCUS, sent },
3203 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3204 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3205 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3206 { WM_SETFOCUS, sent }, /* in MDI client */
3208 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
3209 { WM_KILLFOCUS, sent }, /* in MDI client */
3210 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3211 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3212 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3213 { WM_SETFOCUS, sent }, /* in MDI client */
3215 { WM_NCDESTROY, sent },
3216 { 0 }
3218 /* CreateWindow for MDI child window, initially invisible */
3219 static const struct message WmCreateMDIchildInvisibleSeq[] = {
3220 { HCBT_CREATEWND, hook },
3221 { WM_NCCREATE, sent },
3222 { WM_NCCALCSIZE, sent|wparam, 0 },
3223 { WM_CREATE, sent },
3224 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3225 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3226 { WM_MOVE, sent },
3227 /* Win2k sends wparam set to
3228 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3229 * while Win9x doesn't bother to set child window id according to
3230 * CLIENTCREATESTRUCT.idFirstChild
3232 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3233 { 0 }
3235 /* DestroyWindow for MDI child window, initially invisible */
3236 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
3237 { HCBT_DESTROYWND, hook },
3238 /* Win2k sends wparam set to
3239 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3240 * while Win9x doesn't bother to set child window id according to
3241 * CLIENTCREATESTRUCT.idFirstChild
3243 { 0x0090, sent|optional },
3244 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3245 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3246 { WM_DESTROY, sent },
3247 { WM_NCDESTROY, sent },
3248 /* FIXME: Wine destroys an icon/title window while Windows doesn't */
3249 { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
3250 { 0 }
3252 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
3253 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
3254 { HCBT_CREATEWND, hook },
3255 { WM_NCCREATE, sent },
3256 { WM_NCCALCSIZE, sent|wparam, 0 },
3257 { WM_CREATE, sent },
3258 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3259 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3260 { WM_MOVE, sent },
3261 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3262 { WM_GETMINMAXINFO, sent },
3263 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3264 { WM_NCCALCSIZE, sent|wparam, 1 },
3265 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3266 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3267 /* in MDI frame */
3268 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3269 { WM_NCCALCSIZE, sent|wparam, 1 },
3270 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3271 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3272 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3273 /* Win2k sends wparam set to
3274 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3275 * while Win9x doesn't bother to set child window id according to
3276 * CLIENTCREATESTRUCT.idFirstChild
3278 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3279 { WM_SHOWWINDOW, sent|wparam, 1 },
3280 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3281 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3282 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3283 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
3284 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3285 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3286 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_FRAMECHANGED },
3288 /* Win9x: message sequence terminates here. */
3290 { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
3291 { HCBT_SETFOCUS, hook|optional }, /* in MDI client */
3292 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3293 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
3294 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3295 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3296 { HCBT_SETFOCUS, hook|optional },
3297 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3298 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3299 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3300 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3301 { WM_SETFOCUS, sent|defwinproc|optional },
3302 { WM_MDIACTIVATE, sent|defwinproc|optional },
3303 /* in MDI frame */
3304 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3305 { WM_NCCALCSIZE, sent|wparam, 1 },
3306 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3307 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3308 { 0 }
3310 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
3311 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
3312 /* restore the 1st MDI child */
3313 { WM_SETREDRAW, sent|wparam, 0 },
3314 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
3315 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3316 { WM_NCCALCSIZE, sent|wparam, 1 },
3317 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3318 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3319 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3320 /* in MDI frame */
3321 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3322 { WM_NCCALCSIZE, sent|wparam, 1 },
3323 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3324 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3325 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3326 { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
3327 /* create the 2nd MDI child */
3328 { HCBT_CREATEWND, hook },
3329 { WM_NCCREATE, sent },
3330 { WM_NCCALCSIZE, sent|wparam, 0 },
3331 { WM_CREATE, sent },
3332 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3333 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3334 { WM_MOVE, sent },
3335 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3336 { WM_GETMINMAXINFO, sent },
3337 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3338 { WM_NCCALCSIZE, sent|wparam, 1 },
3339 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
3340 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3341 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3342 /* in MDI frame */
3343 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3344 { WM_NCCALCSIZE, sent|wparam, 1 },
3345 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3346 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3347 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3348 /* Win2k sends wparam set to
3349 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3350 * while Win9x doesn't bother to set child window id according to
3351 * CLIENTCREATESTRUCT.idFirstChild
3353 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3354 { WM_SHOWWINDOW, sent|wparam, 1 },
3355 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3356 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3357 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3358 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
3359 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3360 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3362 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
3363 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
3365 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3367 /* Win9x: message sequence terminates here. */
3369 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3370 { HCBT_SETFOCUS, hook },
3371 { WM_KILLFOCUS, sent|defwinproc|optional }, /* in the 1st MDI child */
3372 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
3373 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3374 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3375 { WM_SETFOCUS, sent }, /* in MDI client */
3376 { HCBT_SETFOCUS, hook },
3377 { WM_KILLFOCUS, sent }, /* in MDI client */
3378 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3379 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3380 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3381 { WM_SETFOCUS, sent|defwinproc },
3383 { WM_MDIACTIVATE, sent|defwinproc },
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 { 0 }
3391 /* WM_MDICREATE MDI child window, initially visible and maximized */
3392 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
3393 { WM_MDICREATE, sent },
3394 { HCBT_CREATEWND, hook },
3395 { WM_NCCREATE, sent },
3396 { WM_NCCALCSIZE, sent|wparam, 0 },
3397 { WM_CREATE, sent },
3398 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3399 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3400 { WM_MOVE, sent },
3401 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3402 { WM_GETMINMAXINFO, sent },
3403 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3404 { WM_NCCALCSIZE, sent|wparam, 1 },
3405 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3406 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3408 /* in MDI frame */
3409 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3410 { WM_NCCALCSIZE, sent|wparam, 1 },
3411 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3412 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3413 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3415 /* Win2k sends wparam set to
3416 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3417 * while Win9x doesn't bother to set child window id according to
3418 * CLIENTCREATESTRUCT.idFirstChild
3420 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3421 { WM_SHOWWINDOW, sent|wparam, 1 },
3422 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3424 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3426 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3427 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
3428 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3430 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3431 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3433 /* Win9x: message sequence terminates here. */
3435 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3436 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3437 { HCBT_SETFOCUS, hook }, /* in MDI client */
3438 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3439 { WM_IME_NOTIFY, sent|wparam|optional, 2 },
3440 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
3441 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3442 { HCBT_SETFOCUS, hook|optional },
3443 { WM_KILLFOCUS, sent }, /* in MDI client */
3444 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3445 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3446 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3447 { WM_SETFOCUS, sent|defwinproc },
3449 { WM_MDIACTIVATE, sent|defwinproc },
3451 /* in MDI child */
3452 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3453 { WM_NCCALCSIZE, sent|wparam, 1 },
3454 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3455 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3457 /* in MDI frame */
3458 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3459 { WM_NCCALCSIZE, sent|wparam, 1 },
3460 { 0x0093, sent|defwinproc|optional },
3461 { 0x0093, sent|defwinproc|optional },
3462 { 0x0093, sent|defwinproc|optional },
3463 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3464 { WM_MOVE, sent|defwinproc },
3465 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3467 /* in MDI client */
3468 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3469 { WM_NCCALCSIZE, sent|wparam, 1 },
3470 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3471 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3473 /* in MDI child */
3474 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3475 { WM_NCCALCSIZE, sent|wparam, 1 },
3476 { 0x0093, sent|optional },
3477 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3478 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3480 { 0x0093, sent|optional },
3481 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3482 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client, not sent on Win7. */
3483 { 0x0093, sent|optional }, /* Win8+ sends an extra. */
3484 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
3485 { 0x0093, sent|defwinproc|optional },
3486 { 0x0093, sent|defwinproc|optional },
3487 { 0x0093, sent|defwinproc|optional },
3488 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3489 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
3491 { 0 }
3493 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
3494 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
3495 { HCBT_CREATEWND, hook },
3496 { WM_GETMINMAXINFO, sent },
3497 { WM_NCCREATE, sent },
3498 { WM_NCCALCSIZE, sent|wparam, 0 },
3499 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win8+. */
3500 { WM_CREATE, sent },
3501 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3502 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3503 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOZORDER }, /* MDI frame */
3504 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI frame */
3505 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOZORDER }, /* MDI frame */
3506 { WM_MOVE, sent },
3507 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3508 { WM_GETMINMAXINFO, sent },
3509 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3510 { WM_GETMINMAXINFO, sent|defwinproc },
3511 { WM_NCCALCSIZE, sent|wparam, 1 },
3512 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_STATECHANGED },
3513 { WM_MOVE, sent|defwinproc },
3514 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3515 /* in MDI frame */
3516 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3517 { WM_NCCALCSIZE, sent|wparam, 1 },
3518 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3519 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3520 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
3521 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3522 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3523 /* Win2k sends wparam set to
3524 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3525 * while Win9x doesn't bother to set child window id according to
3526 * CLIENTCREATESTRUCT.idFirstChild
3528 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3529 { 0 }
3531 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
3532 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
3533 { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
3534 { HCBT_SYSCOMMAND, hook },
3535 { WM_CLOSE, sent|defwinproc },
3536 { WM_MDIDESTROY, sent }, /* in MDI client */
3538 /* bring the 1st MDI child to top */
3539 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
3540 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
3542 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
3544 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
3545 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
3546 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
3548 /* maximize the 1st MDI child */
3549 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3550 { WM_GETMINMAXINFO, sent|defwinproc },
3551 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED },
3552 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
3553 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
3554 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3555 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3557 /* restore the 2nd MDI child */
3558 { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
3559 { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
3560 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
3561 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
3563 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3565 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3566 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3568 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3570 { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
3571 /* in MDI frame */
3572 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3573 { WM_NCCALCSIZE, sent|wparam, 1 },
3574 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3575 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3576 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3578 /* bring the 1st MDI child to top */
3579 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3580 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3581 { HCBT_SETFOCUS, hook },
3582 { WM_KILLFOCUS, sent|defwinproc },
3583 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
3584 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3585 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3586 { WM_SETFOCUS, sent }, /* in MDI client */
3587 { HCBT_SETFOCUS, hook },
3588 { WM_KILLFOCUS, sent }, /* in MDI client */
3589 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3590 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3591 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3592 { WM_SETFOCUS, sent|defwinproc },
3593 { WM_MDIACTIVATE, sent|defwinproc },
3594 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3596 /* apparently ShowWindow(SW_SHOW) on an MDI client */
3597 { WM_SHOWWINDOW, sent|wparam, 1 },
3598 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3599 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3600 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3601 { WM_MDIREFRESHMENU, sent },
3603 { HCBT_DESTROYWND, hook },
3604 /* Win2k sends wparam set to
3605 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3606 * while Win9x doesn't bother to set child window id according to
3607 * CLIENTCREATESTRUCT.idFirstChild
3609 { 0x0090, sent|defwinproc|optional },
3610 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3611 { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
3612 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3613 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3614 { WM_ERASEBKGND, sent|parent|optional },
3615 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3617 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3618 { WM_DESTROY, sent|defwinproc },
3619 { WM_NCDESTROY, sent|defwinproc },
3620 { 0 }
3622 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
3623 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
3624 { WM_MDIDESTROY, sent }, /* in MDI client */
3625 { WM_SHOWWINDOW, sent|wparam, 0 },
3626 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3627 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3628 { WM_ERASEBKGND, sent|parent|optional },
3629 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3631 { HCBT_SETFOCUS, hook },
3632 { WM_KILLFOCUS, sent },
3633 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3634 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3635 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3636 { WM_SETFOCUS, sent }, /* in MDI client */
3637 { HCBT_SETFOCUS, hook },
3638 { WM_KILLFOCUS, sent }, /* in MDI client */
3639 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3640 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3641 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3642 { WM_SETFOCUS, sent },
3644 /* in MDI child */
3645 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3646 { WM_NCCALCSIZE, sent|wparam, 1 },
3647 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3648 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3650 /* in MDI frame */
3651 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3652 { WM_NCCALCSIZE, sent|wparam, 1 },
3653 { 0x0093, sent|defwinproc|optional },
3654 { 0x0093, sent|defwinproc|optional },
3655 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3656 { WM_MOVE, sent|defwinproc },
3657 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3659 /* in MDI client */
3660 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3661 { WM_NCCALCSIZE, sent|wparam, 1 },
3662 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3663 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3665 /* in MDI child */
3666 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3667 { WM_NCCALCSIZE, sent|wparam, 1 },
3668 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3669 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3671 /* in MDI child */
3672 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3673 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3674 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3675 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3677 /* in MDI frame */
3678 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3679 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3680 { 0x0093, sent|defwinproc|optional },
3681 { 0x0093, sent|defwinproc|optional },
3682 { 0x0093, sent|defwinproc|optional },
3683 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3684 { WM_MOVE, sent|defwinproc },
3685 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3687 /* in MDI client */
3688 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3689 { WM_NCCALCSIZE, sent|wparam, 1 },
3690 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3691 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3693 /* in MDI child */
3694 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3695 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3696 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3697 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3698 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3699 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI client */
3701 { 0x0093, sent|defwinproc|optional },
3702 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
3703 { 0x0093, sent|defwinproc|optional },
3704 { 0x0093, sent|defwinproc|optional },
3705 { 0x0093, sent|defwinproc|optional },
3706 { 0x0093, sent|optional },
3708 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3709 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3710 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI client */
3711 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame */
3712 { 0x0093, sent|optional }, /* Win8+ sends an extra. */
3713 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
3715 /* in MDI frame */
3716 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3717 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3718 { 0x0093, sent|defwinproc|optional },
3719 { 0x0093, sent|defwinproc|optional },
3720 { 0x0093, sent|defwinproc|optional },
3721 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3722 { 0x0093, sent|optional }, /* Win8+ sends an extra. */
3723 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3724 { 0x0093, sent|optional },
3726 { WM_NCACTIVATE, sent|wparam, 0 },
3727 { WM_MDIACTIVATE, sent },
3729 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
3730 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
3731 { WM_NCCALCSIZE, sent|wparam, 1 },
3733 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3735 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3736 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3737 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3739 /* in MDI child */
3740 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3741 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3742 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3743 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3745 /* in MDI frame */
3746 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3747 { WM_NCCALCSIZE, sent|wparam, 1 },
3748 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3749 { WM_MOVE, sent|defwinproc },
3750 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3752 /* in MDI client */
3753 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3754 { WM_NCCALCSIZE, sent|wparam, 1 },
3755 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3756 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3757 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3758 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
3759 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI client */
3760 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3761 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
3763 { HCBT_SETFOCUS, hook },
3764 { WM_KILLFOCUS, sent },
3765 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3766 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3767 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3768 { WM_SETFOCUS, sent }, /* in MDI client */
3770 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
3772 { HCBT_DESTROYWND, hook },
3773 /* Win2k sends wparam set to
3774 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3775 * while Win9x doesn't bother to set child window id according to
3776 * CLIENTCREATESTRUCT.idFirstChild
3778 { 0x0090, sent|optional },
3779 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3781 { WM_SHOWWINDOW, sent|wparam, 0 },
3782 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3783 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3784 { WM_ERASEBKGND, sent|parent|optional },
3785 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3787 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
3788 { WM_DESTROY, sent },
3789 { WM_NCDESTROY, sent },
3790 { 0 }
3792 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
3793 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
3794 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3795 { WM_GETMINMAXINFO, sent },
3796 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3797 { WM_NCCALCSIZE, sent|wparam, 1 },
3798 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3799 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3801 { WM_WINDOWPOSCHANGING, sent|wparam|optional|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3802 { WM_NCACTIVATE, sent|wparam|optional|defwinproc, 1 },
3803 { HCBT_SETFOCUS, hook|optional },
3804 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3805 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
3806 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3807 { HCBT_SETFOCUS, hook|optional },
3808 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3809 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3810 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3811 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3812 { WM_SETFOCUS, sent|optional|defwinproc },
3813 { WM_MDIACTIVATE, sent|optional|defwinproc },
3814 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3815 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3816 /* in MDI frame */
3817 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3818 { WM_NCCALCSIZE, sent|wparam, 1 },
3819 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3820 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3821 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3822 { 0 }
3824 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
3825 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
3826 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3827 { WM_GETMINMAXINFO, sent },
3828 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED, 0, SWP_STATECHANGED /* w1064v1809 */ },
3829 { WM_GETMINMAXINFO, sent|defwinproc },
3830 { WM_NCCALCSIZE, sent|wparam, 1 },
3831 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3832 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3834 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3835 { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
3836 { HCBT_SETFOCUS, hook|optional },
3837 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3838 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
3839 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3840 { HCBT_SETFOCUS, hook|optional },
3841 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3842 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3843 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3844 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3845 { WM_SETFOCUS, sent|defwinproc|optional },
3846 { WM_MDIACTIVATE, sent|defwinproc|optional },
3847 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_STATECHANGED /* w1064v1809 */ },
3848 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child, not sent on Win8+. */
3849 { WM_SIZE, sent|defwinproc|optional },
3850 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* w1064v1809. */
3851 { 0 }
3853 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
3854 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
3855 { WM_MDIMAXIMIZE, sent }, /* in MDI client */
3856 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3857 { WM_GETMINMAXINFO, sent },
3858 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3859 { WM_GETMINMAXINFO, sent|defwinproc },
3860 { WM_NCCALCSIZE, sent|wparam, 1 },
3861 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
3862 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3863 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
3864 { WM_MOVE, sent|defwinproc },
3865 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3867 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3868 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3869 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3870 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3871 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3872 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3873 /* in MDI frame */
3874 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3875 { WM_NCCALCSIZE, sent|wparam, 1 },
3876 { 0x0093, sent|defwinproc|optional },
3877 { 0x0094, sent|defwinproc|optional },
3878 { 0x0094, sent|defwinproc|optional },
3879 { 0x0094, sent|defwinproc|optional },
3880 { 0x0094, sent|defwinproc|optional },
3881 { 0x0093, sent|defwinproc|optional },
3882 { 0x0093, sent|defwinproc|optional },
3883 { 0x0091, sent|defwinproc|optional },
3884 { 0x0092, sent|defwinproc|optional },
3885 { 0x0092, sent|defwinproc|optional },
3886 { 0x0092, sent|defwinproc|optional },
3887 { 0x0092, sent|defwinproc|optional },
3888 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3889 { WM_MOVE, sent|defwinproc },
3890 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3891 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
3892 /* in MDI client */
3893 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3894 { WM_NCCALCSIZE, sent|wparam, 1 },
3895 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3896 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3897 /* in MDI child */
3898 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3899 { WM_GETMINMAXINFO, sent|defwinproc },
3900 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3901 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3902 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3903 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
3904 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3905 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3906 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3907 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3908 /* in MDI frame */
3909 { 0x0093, sent|optional },
3910 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3911 { 0x0093, sent|defwinproc|optional },
3912 { 0x0093, sent|defwinproc|optional },
3913 { 0x0093, sent|defwinproc|optional },
3914 { 0x0091, sent|defwinproc|optional },
3915 { 0x0092, sent|defwinproc|optional },
3916 { 0x0092, sent|defwinproc|optional },
3917 { 0x0092, sent|defwinproc|optional },
3918 { 0x0092, sent|defwinproc|optional },
3919 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3920 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3921 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3922 { 0 }
3924 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
3925 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
3926 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3927 { WM_GETMINMAXINFO, sent },
3928 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3929 { WM_NCCALCSIZE, sent|wparam, 1 },
3930 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3931 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3932 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3933 /* in MDI frame */
3934 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3935 { WM_NCCALCSIZE, sent|wparam, 1 },
3936 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3937 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3938 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3939 { 0 }
3941 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
3942 static const struct message WmRestoreMDIchildVisibleSeq[] = {
3943 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3944 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3945 { WM_NCCALCSIZE, sent|wparam, 1 },
3946 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3947 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3948 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3949 /* in MDI frame */
3950 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3951 { WM_NCCALCSIZE, sent|wparam, 1 },
3952 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3953 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
3954 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3955 { 0 }
3957 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
3958 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
3959 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3960 { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
3961 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3962 { WM_NCCALCSIZE, sent|wparam, 1 },
3963 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3964 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3965 { WM_MOVE, sent|defwinproc },
3966 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3967 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3968 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3969 { HCBT_SETFOCUS, hook },
3970 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3971 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
3972 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
3973 { WM_SETFOCUS, sent },
3974 { 0 }
3976 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
3977 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
3978 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
3979 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3980 { WM_NCCALCSIZE, sent|wparam, 1 },
3981 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3982 { WM_MOVE, sent|defwinproc },
3983 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
3984 { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
3985 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3986 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
3987 /* FIXME: Wine creates an icon/title window while Windows doesn't */
3988 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
3989 { 0 }
3991 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
3992 static const struct message WmRestoreMDIchildInvisibleSeq[] = {
3993 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3994 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3995 { WM_NCCALCSIZE, sent|wparam, 1 },
3996 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3997 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3998 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3999 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
4000 /* in MDI frame */
4001 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
4002 { WM_NCCALCSIZE, sent|wparam, 1 },
4003 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
4004 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI frame */
4005 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* MDI child */
4006 { 0 }
4009 static HWND mdi_client;
4010 static WNDPROC old_mdi_client_proc;
4012 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4014 struct recvd_message msg;
4016 /* do not log painting messages */
4017 if (message != WM_PAINT &&
4018 message != WM_NCPAINT &&
4019 message != WM_SYNCPAINT &&
4020 message != WM_ERASEBKGND &&
4021 message != WM_NCHITTEST &&
4022 message != WM_GETTEXT &&
4023 message != WM_MDIGETACTIVE &&
4024 !ignore_message( message ))
4026 msg.hwnd = hwnd;
4027 msg.message = message;
4028 msg.flags = sent|wparam|lparam;
4029 msg.wParam = wParam;
4030 msg.lParam = lParam;
4031 msg.descr = "mdi client";
4032 add_message(&msg);
4035 return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
4038 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4040 static LONG defwndproc_counter = 0;
4041 LRESULT ret;
4042 struct recvd_message msg;
4044 /* do not log painting messages */
4045 if (message != WM_PAINT &&
4046 message != WM_NCPAINT &&
4047 message != WM_SYNCPAINT &&
4048 message != WM_ERASEBKGND &&
4049 message != WM_NCHITTEST &&
4050 message != WM_GETTEXT &&
4051 !ignore_message( message ))
4053 switch (message)
4055 case WM_MDIACTIVATE:
4057 HWND active, client = GetParent(hwnd);
4059 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
4061 if (hwnd == (HWND)lParam) /* if we are being activated */
4062 ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
4063 else
4064 ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
4065 break;
4069 msg.hwnd = hwnd;
4070 msg.message = message;
4071 msg.flags = sent|wparam|lparam;
4072 if (defwndproc_counter) msg.flags |= defwinproc;
4073 msg.wParam = wParam;
4074 msg.lParam = lParam;
4075 msg.descr = "mdi child";
4076 add_message(&msg);
4079 defwndproc_counter++;
4080 ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
4081 defwndproc_counter--;
4083 return ret;
4086 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4088 static LONG defwndproc_counter = 0;
4089 LRESULT ret;
4090 struct recvd_message msg;
4092 /* do not log painting messages */
4093 if (message != WM_PAINT &&
4094 message != WM_NCPAINT &&
4095 message != WM_SYNCPAINT &&
4096 message != WM_ERASEBKGND &&
4097 message != WM_NCHITTEST &&
4098 message != WM_GETTEXT &&
4099 !ignore_message( message ))
4101 msg.hwnd = hwnd;
4102 msg.message = message;
4103 msg.flags = sent|wparam|lparam;
4104 if (defwndproc_counter) msg.flags |= defwinproc;
4105 msg.wParam = wParam;
4106 msg.lParam = lParam;
4107 msg.descr = "mdi frame";
4108 add_message(&msg);
4111 defwndproc_counter++;
4112 ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
4113 defwndproc_counter--;
4115 return ret;
4118 static void mdi_register_classes(void)
4120 WNDCLASSA cls;
4121 BOOL ret;
4123 cls.style = 0;
4124 cls.lpfnWndProc = mdi_frame_wnd_proc;
4125 cls.cbClsExtra = 0;
4126 cls.cbWndExtra = 0;
4127 cls.hInstance = GetModuleHandleA(0);
4128 cls.hIcon = 0;
4129 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
4130 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
4131 cls.lpszMenuName = NULL;
4132 cls.lpszClassName = "MDI_frame_class";
4133 register_class(&cls);
4135 cls.lpfnWndProc = mdi_child_wnd_proc;
4136 cls.lpszClassName = "MDI_child_class";
4137 register_class(&cls);
4139 ret = GetClassInfoA(0, "MDIClient", &cls);
4140 ok(ret, "Failed to get class info, error %lu.\n", GetLastError());
4141 old_mdi_client_proc = cls.lpfnWndProc;
4142 cls.hInstance = GetModuleHandleA(0);
4143 cls.lpfnWndProc = mdi_client_hook_proc;
4144 cls.lpszClassName = "MDI_client_class";
4145 register_class(&cls);
4148 static void test_mdi_messages(void)
4150 MDICREATESTRUCTA mdi_cs;
4151 CLIENTCREATESTRUCT client_cs;
4152 HWND mdi_frame, mdi_child, mdi_child2, active_child;
4153 BOOL zoomed;
4154 RECT rc;
4155 HMENU hMenu = CreateMenu();
4156 LONG val;
4158 mdi_register_classes();
4160 flush_sequence();
4162 if (winetest_debug > 1) trace("creating MDI frame window\n");
4163 mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
4164 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
4165 WS_MAXIMIZEBOX | WS_VISIBLE,
4166 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
4167 GetDesktopWindow(), hMenu,
4168 GetModuleHandleA(0), NULL);
4169 ok(!!mdi_frame, "Failed to create window, error %lu.\n", GetLastError());
4170 ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
4172 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4173 ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
4175 if (winetest_debug > 1) trace("creating MDI client window\n");
4176 GetClientRect(mdi_frame, &rc);
4177 client_cs.hWindowMenu = 0;
4178 client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
4179 mdi_client = CreateWindowExA(0, "MDI_client_class",
4180 NULL,
4181 WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
4182 rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
4183 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
4184 ok(!!mdi_client, "Failed to create window, error %lu.\n", GetLastError());
4185 SetWindowLongA(mdi_client, 0, 0xdeadbeef);
4187 ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
4188 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4189 ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %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 SetFocus(0);
4196 flush_sequence();
4198 if (winetest_debug > 1) trace("creating invisible MDI child window\n");
4199 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4200 WS_CHILD,
4201 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4202 mdi_client, 0, GetModuleHandleA(0), NULL);
4203 ok(!!mdi_child, "Failed to create window, error %lu.\n", GetLastError());
4205 flush_sequence();
4206 ShowWindow(mdi_child, SW_SHOWNORMAL);
4207 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
4209 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4210 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
4212 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4213 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4215 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4216 ok(!active_child, "wrong active MDI child %p\n", active_child);
4217 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4219 ShowWindow(mdi_child, SW_HIDE);
4220 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
4221 flush_sequence();
4223 ShowWindow(mdi_child, SW_SHOW);
4224 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
4226 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4227 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
4229 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4230 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4232 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4233 ok(!active_child, "wrong active MDI child %p\n", active_child);
4234 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4236 DestroyWindow(mdi_child);
4237 flush_sequence();
4239 if (winetest_debug > 1) trace("creating visible MDI child window\n");
4240 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4241 WS_CHILD | WS_VISIBLE,
4242 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4243 mdi_client, 0, GetModuleHandleA(0), NULL);
4244 ok(!!mdi_child, "Failed to create window, error %lu.\n", GetLastError());
4245 ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
4247 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4248 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
4250 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4251 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4253 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4254 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4255 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4256 flush_sequence();
4258 DestroyWindow(mdi_child);
4259 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4261 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4262 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4264 /* Win2k: MDI client still returns a just destroyed child as active
4265 * Win9x: MDI client returns 0
4267 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4268 ok(active_child == mdi_child || /* win2k */
4269 !active_child, /* win9x */
4270 "wrong active MDI child %p\n", active_child);
4271 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4273 flush_sequence();
4275 if (winetest_debug > 1) trace("creating invisible MDI child window\n");
4276 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4277 WS_CHILD,
4278 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4279 mdi_client, 0, GetModuleHandleA(0), NULL);
4280 ok(!!mdi_child2, "Failed to create window, error %lu.\n", GetLastError());
4281 ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
4283 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
4284 ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
4286 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4287 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4289 /* Win2k: MDI client still returns a just destroyed child as active
4290 * Win9x: MDI client returns mdi_child2
4292 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4293 ok(active_child == mdi_child || /* win2k */
4294 active_child == mdi_child2, /* win9x */
4295 "wrong active MDI child %p\n", active_child);
4296 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4297 flush_sequence();
4299 ShowWindow(mdi_child2, SW_MAXIMIZE);
4300 ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
4302 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4303 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
4305 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4306 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4307 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4308 flush_sequence();
4310 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4311 ok(GetFocus() == mdi_child2 || /* win2k */
4312 GetFocus() == 0, /* win9x */
4313 "wrong focus window %p\n", GetFocus());
4315 SetFocus(0);
4316 flush_sequence();
4318 ShowWindow(mdi_child2, SW_HIDE);
4319 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
4321 ShowWindow(mdi_child2, SW_RESTORE);
4322 ok_sequence(WmRestoreMDIchildInvisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
4323 flush_sequence();
4325 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4326 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
4328 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4329 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4330 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4331 flush_sequence();
4333 SetFocus(0);
4334 flush_sequence();
4336 ShowWindow(mdi_child2, SW_HIDE);
4337 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
4339 ShowWindow(mdi_child2, SW_SHOW);
4340 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
4342 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4343 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4345 ShowWindow(mdi_child2, SW_MAXIMIZE);
4346 ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
4348 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4349 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4351 ShowWindow(mdi_child2, SW_RESTORE);
4352 ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
4354 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4355 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4357 ShowWindow(mdi_child2, SW_MINIMIZE);
4358 ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", FALSE);
4360 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4361 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4363 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4364 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4365 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4366 flush_sequence();
4368 ShowWindow(mdi_child2, SW_RESTORE);
4369 ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", FALSE);
4371 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4372 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4374 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4375 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4376 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4377 flush_sequence();
4379 SetFocus(0);
4380 flush_sequence();
4382 ShowWindow(mdi_child2, SW_HIDE);
4383 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
4385 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4386 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4388 DestroyWindow(mdi_child2);
4389 ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
4391 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4392 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4394 if (winetest_debug > 1) trace("Testing WM_CHILDACTIVATE\n");
4396 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4397 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_DISABLED,
4398 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4399 mdi_client, 0, GetModuleHandleA(0), NULL);
4401 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4402 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX,
4403 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4404 mdi_client, 0, GetModuleHandleA(0), NULL);
4406 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4407 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4408 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4410 flush_sequence();
4411 SendMessageW(mdi_child, WM_CHILDACTIVATE, 0, 0);
4412 ok_sequence(WmChildActivateDisabledWindowSeq, "WM_CHILDACTIVATE sent to disabled window", FALSE);
4414 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4415 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4416 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4417 flush_sequence();
4419 EnableWindow(mdi_child, TRUE);
4421 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4422 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4423 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4425 flush_sequence();
4426 SendMessageW(mdi_child, WM_CHILDACTIVATE, 0, 0);
4427 ok_sequence(WmChildActivateWindowSeq, "WM_CHILDACTIVATE sent to enabled window", FALSE);
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 DestroyWindow(mdi_child);
4435 DestroyWindow(mdi_child2);
4436 flush_sequence();
4438 /* test for maximized MDI children */
4439 if (winetest_debug > 1) trace("creating maximized visible MDI child window 1\n");
4440 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4441 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4442 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4443 mdi_client, 0, GetModuleHandleA(0), NULL);
4444 ok(!!mdi_child, "Failed to create window, error %lu.\n", GetLastError());
4445 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
4446 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4448 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4449 ok(GetFocus() == mdi_child || /* win2k */
4450 GetFocus() == 0, /* win9x */
4451 "wrong focus window %p\n", GetFocus());
4453 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4454 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4455 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4456 flush_sequence();
4458 if (winetest_debug > 1) trace("creating maximized visible MDI child window 2\n");
4459 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4460 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4461 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4462 mdi_client, 0, GetModuleHandleA(0), NULL);
4463 ok(!!mdi_child2, "Failed to create window, error %lu.\n", GetLastError());
4464 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
4465 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
4466 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4468 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4469 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4471 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4472 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4473 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4474 flush_sequence();
4476 if (winetest_debug > 1) trace("destroying maximized visible MDI child window 2\n");
4477 DestroyWindow(mdi_child2);
4478 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4480 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4482 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4483 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4485 /* Win2k: MDI client still returns a just destroyed child as active
4486 * Win9x: MDI client returns 0
4488 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4489 ok(active_child == mdi_child2 || /* win2k */
4490 !active_child, /* win9x */
4491 "wrong active MDI child %p\n", active_child);
4492 flush_sequence();
4494 ShowWindow(mdi_child, SW_MAXIMIZE);
4495 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4496 flush_sequence();
4498 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4499 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4501 if (winetest_debug > 1) trace("re-creating maximized visible MDI child window 2\n");
4502 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4503 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4504 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4505 mdi_client, 0, GetModuleHandleA(0), NULL);
4506 ok(!!mdi_child2, "Failed to create window, error %lu.\n", GetLastError());
4507 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
4508 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
4509 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4511 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4512 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4514 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4515 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4516 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4517 flush_sequence();
4519 SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
4520 ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
4521 ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
4523 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4524 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4525 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4527 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4528 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4529 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4530 flush_sequence();
4532 DestroyWindow(mdi_child);
4533 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4535 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4536 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4538 /* Win2k: MDI client still returns a just destroyed child as active
4539 * Win9x: MDI client returns 0
4541 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4542 ok(active_child == mdi_child || /* win2k */
4543 !active_child, /* win9x */
4544 "wrong active MDI child %p\n", active_child);
4545 flush_sequence();
4547 if (winetest_debug > 1) trace("creating maximized invisible MDI child window\n");
4548 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4549 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
4550 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4551 mdi_client, 0, GetModuleHandleA(0), NULL);
4552 ok(!!mdi_child2, "Failed to create window, error %lu.\n", GetLastError());
4553 ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE);
4554 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
4555 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
4556 ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
4558 /* Win2k: MDI client still returns a just destroyed child as active
4559 * Win9x: MDI client returns 0
4561 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4562 ok(active_child == mdi_child || /* win2k */
4563 !active_child || active_child == mdi_child2, /* win9x */
4564 "wrong active MDI child %p\n", active_child);
4565 flush_sequence();
4567 if (winetest_debug > 1) trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
4568 ShowWindow(mdi_child2, SW_MAXIMIZE);
4569 ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
4570 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
4571 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4572 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
4574 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4575 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4576 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4577 flush_sequence();
4579 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
4580 flush_sequence();
4582 /* end of test for maximized MDI children */
4583 SetFocus(0);
4584 flush_sequence();
4585 if (winetest_debug > 1) trace("creating maximized visible MDI child window 1(Switch test)\n");
4586 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4587 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4588 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4589 mdi_client, 0, GetModuleHandleA(0), NULL);
4590 ok(!!mdi_child, "Failed to create window, error %lu.\n", GetLastError());
4591 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
4592 ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
4594 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
4595 ok(GetFocus() == mdi_child || /* win2k */
4596 GetFocus() == 0, /* win9x */
4597 "wrong focus window %p(Switch test)\n", GetFocus());
4599 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4600 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
4601 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
4602 flush_sequence();
4604 if (winetest_debug > 1) trace("creating maximized visible MDI child window 2(Switch test)\n");
4605 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4606 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4607 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4608 mdi_client, 0, GetModuleHandleA(0), NULL);
4609 ok(!!mdi_child2, "Failed to create window, error %lu.\n", GetLastError());
4610 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
4612 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
4613 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
4615 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
4616 ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
4618 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4619 ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
4620 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
4621 flush_sequence();
4623 if (winetest_debug > 1) trace("Switch child window.\n");
4624 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
4625 ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
4626 if (winetest_debug > 1) trace("end of test for switch maximized MDI children\n");
4627 flush_sequence();
4629 /* Prepare for switching test of not maximized MDI children */
4630 ShowWindow( mdi_child, SW_NORMAL );
4631 ok(!IsZoomed(mdi_child), "wrong zoomed state for %p(Switch test)\n", mdi_child);
4632 ok(!IsZoomed(mdi_child2), "wrong zoomed state for %p(Switch test)\n", mdi_child2);
4633 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
4634 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
4635 flush_sequence();
4637 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0);
4638 ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE);
4639 if (winetest_debug > 1) trace("end of test for switch not maximized MDI children\n");
4640 flush_sequence();
4642 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
4643 flush_sequence();
4645 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
4646 flush_sequence();
4648 SetFocus(0);
4649 flush_sequence();
4650 /* end of tests for switch maximized/not maximized MDI children */
4652 mdi_cs.szClass = "MDI_child_Class";
4653 mdi_cs.szTitle = "MDI child";
4654 mdi_cs.hOwner = GetModuleHandleA(0);
4655 mdi_cs.x = 0;
4656 mdi_cs.y = 0;
4657 mdi_cs.cx = CW_USEDEFAULT;
4658 mdi_cs.cy = CW_USEDEFAULT;
4659 mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
4660 mdi_cs.lParam = 0;
4661 mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
4662 ok(mdi_child != 0, "MDI child creation failed\n");
4663 ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
4665 ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
4667 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4668 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4670 ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
4671 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4672 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4674 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4675 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4676 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4677 flush_sequence();
4679 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
4680 ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
4682 ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
4683 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4684 ok(!active_child, "wrong active MDI child %p\n", active_child);
4686 SetFocus(0);
4687 flush_sequence();
4689 val = GetWindowLongA(mdi_client, 0);
4690 ok(val == 0xdeadbeef || broken(val == 0) /* >= Win Vista */, "Expected 0xdeadbeef, got 0x%lx\n", val);
4691 DestroyWindow(mdi_client);
4692 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
4694 /* test maximization of MDI child with invisible parent */
4695 client_cs.hWindowMenu = 0;
4696 mdi_client = CreateWindowA("MDI_client_class",
4697 NULL,
4698 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
4699 0, 0, 660, 430,
4700 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
4701 ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
4703 ShowWindow(mdi_client, SW_HIDE);
4704 ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
4706 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4707 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
4708 0, 0, 650, 440,
4709 mdi_client, 0, GetModuleHandleA(0), NULL);
4710 ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
4712 SendMessageA(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
4713 ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
4714 zoomed = IsZoomed(mdi_child);
4715 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4717 ShowWindow(mdi_client, SW_SHOW);
4718 ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
4720 DestroyWindow(mdi_child);
4721 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
4723 /* end of test for maximization of MDI child with invisible parent */
4725 DestroyWindow(mdi_client);
4726 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
4728 DestroyWindow(mdi_frame);
4729 ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
4731 /************************* End of MDI test **********************************/
4733 static void test_WM_SETREDRAW(HWND hwnd)
4735 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
4737 flush_events();
4738 flush_sequence();
4740 SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
4741 ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
4743 ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
4744 ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
4746 flush_sequence();
4747 SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
4748 ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
4750 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4751 ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
4753 /* restore original WS_VISIBLE state */
4754 SetWindowLongA(hwnd, GWL_STYLE, style);
4756 flush_events();
4757 flush_sequence();
4760 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4762 struct recvd_message msg;
4764 if (ignore_message( message )) return 0;
4766 switch (message)
4768 /* ignore */
4769 case WM_MOUSEMOVE:
4770 case WM_NCMOUSEMOVE:
4771 case WM_NCMOUSELEAVE:
4772 case WM_SETCURSOR:
4773 return 0;
4774 case WM_NCHITTEST:
4775 return HTCLIENT;
4778 msg.hwnd = hwnd;
4779 msg.message = message;
4780 msg.flags = sent|wparam|lparam;
4781 msg.wParam = wParam;
4782 msg.lParam = lParam;
4783 msg.descr = "dialog";
4784 add_message(&msg);
4786 if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
4787 if (message == WM_TIMER) EndDialog( hwnd, 0 );
4788 return 0;
4791 static INT_PTR CALLBACK TestModalDlgProc2(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4793 struct recvd_message msg;
4795 if (ignore_message( message )) return 0;
4797 switch (message)
4799 /* ignore */
4800 case WM_MOUSEMOVE:
4801 case WM_NCMOUSEMOVE:
4802 case WM_NCMOUSELEAVE:
4803 case WM_SETCURSOR:
4804 return 0;
4805 case WM_NCHITTEST:
4806 return HTCLIENT;
4809 msg.hwnd = hwnd;
4810 msg.message = message;
4811 msg.flags = sent|wparam|lparam;
4812 msg.wParam = wParam;
4813 msg.lParam = lParam;
4814 msg.descr = "dialog";
4815 add_message(&msg);
4817 if (message == WM_INITDIALOG) EndDialog( hwnd, 0 );
4818 return 0;
4821 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4823 DWORD style, exstyle;
4824 INT xmin, xmax;
4825 BOOL ret;
4827 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4828 style = GetWindowLongA(hwnd, GWL_STYLE);
4829 /* do not be confused by WS_DLGFRAME set */
4830 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4832 if (clear) ok(style & clear, "style %08lx should be set\n", clear);
4833 if (set) ok(!(style & set), "style %08lx should not be set\n", set);
4835 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4836 ok( ret, "SetScrollRange(%d) error %ld\n", ctl, GetLastError());
4837 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4838 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
4839 else
4840 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
4842 style = GetWindowLongA(hwnd, GWL_STYLE);
4843 if (set) ok(style & set, "style %08lx should be set\n", set);
4844 if (clear) ok(!(style & clear), "style %08lx should not be set\n", clear);
4846 /* a subsequent call should do nothing */
4847 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4848 ok( ret, "SetScrollRange(%d) error %ld\n", ctl, GetLastError());
4849 ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4851 xmin = 0xdeadbeef;
4852 xmax = 0xdeadbeef;
4853 ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
4854 ok( ret, "GetScrollRange(%d) error %ld\n", ctl, GetLastError());
4855 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4856 ok(xmin == min, "unexpected min scroll value %d\n", xmin);
4857 ok(xmax == max, "unexpected max scroll value %d\n", xmax);
4860 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4862 DWORD style, exstyle;
4863 SCROLLINFO si;
4864 BOOL ret;
4866 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4867 style = GetWindowLongA(hwnd, GWL_STYLE);
4868 /* do not be confused by WS_DLGFRAME set */
4869 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4871 if (clear) ok(style & clear, "style %08lx should be set\n", clear);
4872 if (set) ok(!(style & set), "style %08lx should not be set\n", set);
4874 si.cbSize = sizeof(si);
4875 si.fMask = SIF_RANGE;
4876 si.nMin = min;
4877 si.nMax = max;
4878 SetScrollInfo(hwnd, ctl, &si, TRUE);
4879 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4880 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
4881 else
4882 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
4884 style = GetWindowLongA(hwnd, GWL_STYLE);
4885 if (set) ok(style & set, "style %08lx should be set\n", set);
4886 if (clear) ok(!(style & clear), "style %08lx should not be set\n", clear);
4888 /* a subsequent call should do nothing */
4889 SetScrollInfo(hwnd, ctl, &si, TRUE);
4890 if (style & WS_HSCROLL)
4891 ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4892 else if (style & WS_VSCROLL)
4893 ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4894 else
4895 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4897 si.fMask = SIF_PAGE;
4898 si.nPage = 5;
4899 SetScrollInfo(hwnd, ctl, &si, FALSE);
4900 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4902 si.fMask = SIF_POS;
4903 si.nPos = max - 1;
4904 SetScrollInfo(hwnd, ctl, &si, FALSE);
4905 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4907 si.fMask = SIF_RANGE;
4908 si.nMin = 0xdeadbeef;
4909 si.nMax = 0xdeadbeef;
4910 ret = GetScrollInfo(hwnd, ctl, &si);
4911 ok( ret, "GetScrollInfo error %ld\n", GetLastError());
4912 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4913 ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
4914 ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
4917 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
4918 static void test_scroll_messages(HWND hwnd)
4920 SCROLLINFO si;
4921 INT min, max;
4922 BOOL ret;
4924 flush_events();
4925 flush_sequence();
4927 min = 0xdeadbeef;
4928 max = 0xdeadbeef;
4929 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4930 ok( ret, "GetScrollRange error %ld\n", GetLastError());
4931 if (sequence->message != WmGetScrollRangeSeq[0].message)
4932 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4933 /* values of min and max are undefined */
4934 flush_sequence();
4936 ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
4937 ok( ret, "SetScrollRange error %ld\n", GetLastError());
4938 if (sequence->message != WmSetScrollRangeSeq[0].message)
4939 trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4940 flush_sequence();
4942 min = 0xdeadbeef;
4943 max = 0xdeadbeef;
4944 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4945 ok( ret, "GetScrollRange error %ld\n", GetLastError());
4946 if (sequence->message != WmGetScrollRangeSeq[0].message)
4947 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4948 /* values of min and max are undefined */
4949 flush_sequence();
4951 si.cbSize = sizeof(si);
4952 si.fMask = SIF_RANGE;
4953 si.nMin = 20;
4954 si.nMax = 160;
4955 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4956 if (sequence->message != WmSetScrollRangeSeq[0].message)
4957 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4958 flush_sequence();
4960 si.fMask = SIF_PAGE;
4961 si.nPage = 10;
4962 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4963 if (sequence->message != WmSetScrollRangeSeq[0].message)
4964 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4965 flush_sequence();
4967 si.fMask = SIF_POS;
4968 si.nPos = 20;
4969 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4970 if (sequence->message != WmSetScrollRangeSeq[0].message)
4971 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4972 flush_sequence();
4974 si.fMask = SIF_RANGE;
4975 si.nMin = 0xdeadbeef;
4976 si.nMax = 0xdeadbeef;
4977 ret = GetScrollInfo(hwnd, SB_CTL, &si);
4978 ok( ret, "GetScrollInfo error %ld\n", GetLastError());
4979 if (sequence->message != WmGetScrollInfoSeq[0].message)
4980 trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4981 /* values of min and max are undefined */
4982 flush_sequence();
4984 /* set WS_HSCROLL */
4985 test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4986 /* clear WS_HSCROLL */
4987 test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4989 /* set WS_HSCROLL */
4990 test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4991 /* clear WS_HSCROLL */
4992 test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4994 /* set WS_VSCROLL */
4995 test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4996 /* clear WS_VSCROLL */
4997 test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4999 /* set WS_VSCROLL */
5000 test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
5001 /* clear WS_VSCROLL */
5002 test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
5005 static void test_showwindow(void)
5007 HWND hwnd, hwnd2, hchild;
5008 RECT rc;
5010 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5011 100, 100, 200, 200, 0, 0, 0, NULL);
5012 ok (hwnd != 0, "Failed to create overlapped window\n");
5013 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5014 0, 0, 10, 10, hwnd, 0, 0, NULL);
5015 ok (hchild != 0, "Failed to create child\n");
5016 flush_sequence();
5018 /* ShowWindow( SW_SHOWNA) for invisible top level window */
5019 if (winetest_debug > 1) trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
5020 ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
5021 ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", FALSE);
5023 /* ShowWindow( SW_SHOWNA) for now visible top level window */
5024 if (winetest_debug > 1) trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
5025 ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
5026 ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
5027 /* back to invisible */
5028 ShowWindow(hchild, SW_HIDE);
5029 ShowWindow(hwnd, SW_HIDE);
5030 flush_sequence();
5031 /* ShowWindow(SW_SHOWNA) with child and parent invisible */
5032 if (winetest_debug > 1) trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
5033 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
5034 ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
5035 /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */
5036 ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
5037 flush_sequence();
5038 if (winetest_debug > 1) trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
5039 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
5040 ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
5041 /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
5042 ShowWindow( hwnd, SW_SHOW);
5043 flush_sequence();
5044 if (winetest_debug > 1) trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
5045 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
5046 ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
5048 /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
5049 ShowWindow( hchild, SW_HIDE);
5050 flush_sequence();
5051 if (winetest_debug > 1) trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
5052 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
5053 ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
5055 SetCapture(hchild);
5056 ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
5057 DestroyWindow(hchild);
5058 ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
5060 DestroyWindow(hwnd);
5061 flush_sequence();
5063 /* Popup windows */
5064 /* Test 1:
5065 * 1. Create invisible maximized popup window.
5066 * 2. Move and resize it.
5067 * 3. Show it maximized.
5069 if (winetest_debug > 1) trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
5070 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
5071 100, 100, 200, 200, 0, 0, 0, NULL);
5072 ok (hwnd != 0, "Failed to create popup window\n");
5073 ok(IsZoomed(hwnd), "window should be maximized\n");
5074 ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
5076 GetWindowRect(hwnd, &rc);
5077 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
5078 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
5079 "Invalid maximized size before ShowWindow %s\n", wine_dbgstr_rect( &rc ));
5080 /* Reset window's size & position */
5081 SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
5082 ok(IsZoomed(hwnd), "window should be maximized\n");
5083 flush_sequence();
5085 if (winetest_debug > 1) trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
5086 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5087 ok(IsZoomed(hwnd), "window should be maximized\n");
5088 ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
5090 GetWindowRect(hwnd, &rc);
5091 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
5092 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
5093 "Invalid maximized size after ShowWindow %s\n", wine_dbgstr_rect( &rc ));
5094 DestroyWindow(hwnd);
5095 flush_sequence();
5097 /* Test 2:
5098 * 1. Create invisible maximized popup window.
5099 * 2. Show it maximized.
5101 if (winetest_debug > 1) trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
5102 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
5103 100, 100, 200, 200, 0, 0, 0, NULL);
5104 ok (hwnd != 0, "Failed to create popup window\n");
5105 ok(IsZoomed(hwnd), "window should be maximized\n");
5106 ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
5108 if (winetest_debug > 1) trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
5109 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5110 ok(IsZoomed(hwnd), "window should be maximized\n");
5111 ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
5112 DestroyWindow(hwnd);
5113 flush_sequence();
5115 /* Test 3:
5116 * 1. Create visible maximized popup window.
5118 if (winetest_debug > 1) trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
5119 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
5120 100, 100, 200, 200, 0, 0, 0, NULL);
5121 ok (hwnd != 0, "Failed to create popup window\n");
5122 ok(IsZoomed(hwnd), "window should be maximized\n");
5123 ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
5124 DestroyWindow(hwnd);
5125 flush_sequence();
5127 /* Test 4:
5128 * 1. Create visible popup window.
5129 * 2. Maximize it.
5131 if (winetest_debug > 1) trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
5132 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
5133 100, 100, 200, 200, 0, 0, 0, NULL);
5134 ok (hwnd != 0, "Failed to create popup window\n");
5135 ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
5136 ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
5138 if (winetest_debug > 1) trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
5139 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5140 ok(IsZoomed(hwnd), "window should be maximized\n");
5141 ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
5142 DestroyWindow(hwnd);
5143 flush_sequence();
5145 /* Test 5:
5146 * 1. Restoring a minimized window.
5148 hwnd = CreateWindowA("TestWindowClass", "window1", WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 0, 0, 0, 0);
5149 ok(hwnd != NULL, "Failed to create window\n");
5151 hwnd2 = CreateWindowA("static", "window2", WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 0, 0, 0, 0);
5152 ok(hwnd2 != NULL, "Failed to create window\n");
5154 ShowWindow(hwnd, SW_MINIMIZE);
5155 SetActiveWindow(hwnd2);
5156 ok(GetActiveWindow() == hwnd2, "Unexpected active window\n");
5157 flush_events();
5158 flush_sequence();
5159 ShowWindow(hwnd, SW_RESTORE);
5160 flush_events();
5161 ok_sequence(WmShowRestoreMinimizedOverlappedSeq,
5162 "ShowWindow(hwnd, SW_RESTORE): minimized overlapped", TRUE);
5164 ShowWindow(hwnd, SW_MINIMIZE);
5165 SetActiveWindow(hwnd2);
5166 ok(GetActiveWindow() == hwnd2, "Unexpected active window\n");
5167 flush_events();
5168 flush_sequence();
5169 ShowWindow(hwnd, SW_SHOWNOACTIVATE);
5170 flush_events();
5171 ok_sequence(WmShowNoActivateMinimizedOverlappedSeq,
5172 "ShowWindow(hwnd, SW_SHOWNOACTIVATE): minimized overlapped", TRUE);
5174 DestroyWindow(hwnd2);
5175 DestroyWindow(hwnd);
5176 flush_sequence();
5178 /* Test 6:
5179 * 1. Restoring a minimized but active window.
5181 hwnd = CreateWindowA("TestWindowClass", "parent", WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 0, 0, 0, 0);
5182 ok(hwnd != NULL, "Failed to create window\n");
5184 ShowWindow(hwnd, SW_MINIMIZE);
5185 SetActiveWindow(hwnd);
5186 ok(GetActiveWindow() == hwnd, "Unexpected active window\n");
5187 flush_events();
5188 flush_sequence();
5189 ShowWindow(hwnd, SW_RESTORE);
5190 flush_events();
5191 ok_sequence(WmShowRestoreActiveMinimizedOverlappedSeq,
5192 "ShowWindow(hwnd, SW_RESTORE): active minimized overlapped", TRUE);
5194 ShowWindow(hwnd, SW_MINIMIZE);
5195 SetActiveWindow(hwnd);
5196 ok(GetActiveWindow() == hwnd, "Unexpected active window\n");
5197 flush_events();
5198 flush_sequence();
5199 ShowWindow(hwnd, SW_SHOWNOACTIVATE);
5200 flush_events();
5201 ok_sequence(WmShowNoActivateActiveMinimizedOverlappedSeq,
5202 "ShowWindow(hwnd, SW_SHOWNOACTIVATE): active minimized overlapped", TRUE);
5204 DestroyWindow(hwnd);
5205 flush_sequence();
5208 static void test_sys_menu(void)
5210 HWND hwnd;
5211 HMENU hmenu;
5212 UINT state;
5214 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
5215 100, 100, 200, 200, 0, 0, 0, NULL);
5216 ok (hwnd != 0, "Failed to create overlapped window\n");
5218 flush_sequence();
5220 /* test existing window without CS_NOCLOSE style */
5221 hmenu = GetSystemMenu(hwnd, FALSE);
5222 ok(hmenu != 0, "GetSystemMenu error %ld\n", GetLastError());
5224 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
5225 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
5226 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
5228 EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
5229 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
5231 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
5232 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
5233 ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
5235 EnableMenuItem(hmenu, SC_CLOSE, 0);
5236 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
5238 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
5239 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
5240 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
5242 /* test whether removing WS_SYSMENU destroys a system menu */
5243 SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
5244 SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
5245 flush_sequence();
5246 hmenu = GetSystemMenu(hwnd, FALSE);
5247 ok(hmenu != 0, "GetSystemMenu error %ld\n", GetLastError());
5249 DestroyWindow(hwnd);
5251 /* test new window with CS_NOCLOSE style */
5252 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
5253 100, 100, 200, 200, 0, 0, 0, NULL);
5254 ok (hwnd != 0, "Failed to create overlapped window\n");
5256 hmenu = GetSystemMenu(hwnd, FALSE);
5257 ok(hmenu != 0, "GetSystemMenu error %ld\n", GetLastError());
5259 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
5260 ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
5262 DestroyWindow(hwnd);
5264 /* test new window without WS_SYSMENU style */
5265 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
5266 100, 100, 200, 200, 0, 0, 0, NULL);
5267 ok(hwnd != 0, "Failed to create overlapped window\n");
5269 hmenu = GetSystemMenu(hwnd, FALSE);
5270 ok(!hmenu, "GetSystemMenu error %ld\n", GetLastError());
5272 DestroyWindow(hwnd);
5275 /* For shown WS_OVERLAPPEDWINDOW */
5276 static const struct message WmSetIcon_1[] = {
5277 { WM_SETICON, sent },
5278 { 0x00AE, sent|defwinproc|optional }, /* XP */
5279 { WM_GETTEXT, sent|defwinproc|optional },
5280 { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
5281 { 0 }
5284 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
5285 static const struct message WmSetIcon_2[] = {
5286 { WM_SETICON, sent },
5287 { 0 }
5290 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
5291 static const struct message WmInitEndSession[] = {
5292 { 0x003B, sent },
5293 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
5294 { 0 }
5297 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
5298 static const struct message WmInitEndSession_2[] = {
5299 { 0x003B, sent },
5300 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
5301 { 0 }
5304 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
5305 static const struct message WmInitEndSession_3[] = {
5306 { 0x003B, sent },
5307 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
5308 { 0 }
5311 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
5312 static const struct message WmInitEndSession_4[] = {
5313 { 0x003B, sent },
5314 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
5315 { 0 }
5318 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
5319 static const struct message WmInitEndSession_5[] = {
5320 { 0x003B, sent },
5321 { WM_ENDSESSION, sent|defwinproc/*|wparam*/|lparam, 1, ENDSESSION_LOGOFF },
5322 { 0 }
5325 static const struct message WmOptionalPaint[] = {
5326 { WM_PAINT, sent|optional },
5327 { WM_NCPAINT, sent|beginpaint|optional },
5328 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5329 { WM_ERASEBKGND, sent|beginpaint|optional },
5330 { 0 }
5333 static const struct message WmZOrder[] = {
5334 { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 },
5335 { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 },
5336 { HCBT_ACTIVATE, hook },
5337 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
5338 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
5339 { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 },
5340 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 },
5341 { WM_GETTEXT, sent|optional },
5342 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
5343 { WM_ACTIVATEAPP, sent|wparam, 1, 0 },
5344 { WM_NCACTIVATE, sent|lparam, 1, 0 },
5345 { WM_GETTEXT, sent|defwinproc|optional },
5346 { WM_GETTEXT, sent|defwinproc|optional },
5347 { WM_ACTIVATE, sent|wparam|lparam, 1, 0 },
5348 { HCBT_SETFOCUS, hook },
5349 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5350 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5351 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5352 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
5353 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
5354 { WM_GETTEXT, sent|optional },
5355 { WM_NCCALCSIZE, sent|optional },
5356 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends it, but Win8+ doesn't. */
5357 { 0 }
5360 static void CALLBACK apc_test_proc(ULONG_PTR param)
5362 /* nothing */
5365 static void test_MsgWaitForMultipleObjects(HWND hwnd)
5367 DWORD ret;
5368 MSG msg;
5370 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5371 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %lx\n", ret);
5373 PostMessageA(hwnd, WM_USER, 0, 0);
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);
5381 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5382 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %lx\n", ret);
5384 PostMessageA(hwnd, WM_USER, 0, 0);
5386 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5387 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %lx\n", ret);
5389 ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
5390 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5392 /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
5393 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5394 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %lx\n", ret);
5396 PostMessageA(hwnd, WM_USER, 0, 0);
5398 /* new incoming message causes it to become signaled again */
5399 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5400 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %lx\n", ret);
5402 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5403 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5404 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5405 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5407 /* MWMO_INPUTAVAILABLE should succeed even if the message was already seen */
5408 PostMessageA( hwnd, WM_USER, 0, 0 );
5409 ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
5410 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5412 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_INPUTAVAILABLE );
5413 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %lx\n", ret);
5415 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5416 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5418 /* without MWMO_ALERTABLE the result is never WAIT_IO_COMPLETION */
5419 ret = QueueUserAPC( apc_test_proc, GetCurrentThread(), 0 );
5420 ok(ret, "QueueUserAPC failed %lu\n", GetLastError());
5422 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, 0 );
5423 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjectsEx returned %lx\n", ret);
5425 /* but even with MWMO_ALERTABLE window events are preferred */
5426 PostMessageA( hwnd, WM_USER, 0, 0 );
5428 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_ALERTABLE );
5429 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %lx\n", ret);
5431 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5432 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5434 /* the APC call is still queued */
5435 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_ALERTABLE );
5436 ok(ret == WAIT_IO_COMPLETION, "MsgWaitForMultipleObjectsEx returned %lx\n", ret);
5439 static void test_WM_DEVICECHANGE(HWND hwnd)
5441 DWORD ret;
5442 MSG msg;
5443 int i;
5444 static const WPARAM wparams[] = {0,
5445 DBT_DEVNODES_CHANGED,
5446 DBT_QUERYCHANGECONFIG,
5447 DBT_CONFIGCHANGED,
5448 DBT_CONFIGCHANGECANCELED,
5449 DBT_NO_DISK_SPACE,
5450 DBT_LOW_DISK_SPACE,
5451 DBT_CONFIGMGPRIVATE, /* 0x7fff */
5452 DBT_DEVICEARRIVAL, /* 0x8000 */
5453 DBT_DEVICEQUERYREMOVE,
5454 DBT_DEVICEQUERYREMOVEFAILED,
5455 DBT_DEVICEREMOVEPENDING,
5456 DBT_DEVICEREMOVECOMPLETE,
5457 DBT_DEVICETYPESPECIFIC,
5458 DBT_CUSTOMEVENT};
5460 for (i = 0; i < ARRAY_SIZE(wparams); i++)
5462 SetLastError(0xdeadbeef);
5463 ret = PostMessageA(hwnd, WM_DEVICECHANGE, wparams[i], 0);
5464 if (wparams[i] & 0x8000)
5466 ok(ret == FALSE, "PostMessage returned %ld\n", ret);
5467 ok(GetLastError() == ERROR_MESSAGE_SYNC_ONLY, "PostMessage error %08lx\n", GetLastError());
5469 else
5471 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5472 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %lx\n", ret);
5473 memset(&msg, 0, sizeof(msg));
5474 ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should succeed\n");
5475 ok(msg.message == WM_DEVICECHANGE, "got %04x instead of WM_DEVICECHANGE\n", msg.message);
5480 static DWORD CALLBACK hide_window_thread( LPVOID arg )
5482 HWND hwnd = arg;
5484 /* function will not return if ShowWindow(SW_HIDE) calls SendMessage() */
5485 ok(ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow(SW_HIDE) expected FALSE\n");
5487 return 0;
5490 static DWORD CALLBACK show_window_thread( LPVOID arg )
5492 HWND hwnd = arg;
5494 /* function will not return if ShowWindow(SW_SHOW) calls SendMessage() */
5495 ok( ShowWindow( hwnd, SW_SHOW ), "ShowWindow(SW_SHOW) expected TRUE\n" ); /* actually it's 24... */
5497 return 0;
5500 /* Helper function to easier test SetWindowPos messages */
5501 #define test_msg_setpos( expected_list, flags, todo ) \
5502 test_msg_setpos_( (expected_list), (flags), (todo), __FILE__, __LINE__)
5503 static void test_msg_setpos_(const struct message *expected_list, UINT flags, BOOL todo, const char *file, int line)
5505 HWND hwnd;
5507 flush_events();
5508 flush_sequence();
5509 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5510 10, 10, 100, 100, NULL, 0, 0, NULL );
5511 ok (hwnd != 0, "Failed to create popup window\n");
5512 SetWindowPos(hwnd, NULL, 0, 0, 100, 100, flags);
5513 ok_sequence_(expected_list, "SetWindowPos:show_popup_first_show_window", todo, file, line);
5514 DestroyWindow(hwnd);
5517 /* test if we receive the right sequence of messages */
5518 static void test_messages(void)
5520 DWORD tid;
5521 HANDLE hthread;
5522 HWND hwnd, hparent, hchild;
5523 HWND hchild2, hbutton;
5524 HMENU hmenu;
5525 MSG msg;
5526 LRESULT res;
5527 POINT pos;
5528 BOOL ret;
5530 flush_sequence();
5532 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5533 100, 100, 200, 200, 0, 0, 0, NULL);
5534 ok (hwnd != 0, "Failed to create overlapped window\n");
5535 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
5537 /* test ShowWindow(SW_HIDE) on a newly created invisible window */
5538 ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
5539 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
5541 /* test WM_SETREDRAW on a not visible top level window */
5542 test_WM_SETREDRAW(hwnd);
5544 SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5545 flush_events();
5546 ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
5547 ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
5549 ok(GetActiveWindow() == hwnd, "window should be active\n");
5550 ok(GetFocus() == hwnd, "window should have input focus\n");
5551 ShowWindow(hwnd, SW_HIDE);
5552 flush_events();
5553 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5555 /* test ShowWindow(SW_HIDE) on a hidden window - single threaded */
5556 ok(ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow(SW_HIDE) expected FALSE\n");
5557 flush_events();
5558 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5560 /* test ShowWindow(SW_HIDE) on a hidden window - multi-threaded */
5561 hthread = CreateThread( NULL, 0, hide_window_thread, hwnd, 0, &tid );
5562 ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError());
5563 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5564 CloseHandle(hthread);
5565 flush_events();
5566 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5568 ShowWindow(hwnd, SW_SHOW);
5569 flush_events();
5570 ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
5572 /* test ShowWindow(SW_SHOW) on a visible window - multi-threaded */
5573 hthread = CreateThread( NULL, 0, show_window_thread, hwnd, 0, &tid );
5574 ok( hthread != NULL, "CreateThread failed, error %ld\n", GetLastError() );
5575 ok( WaitForSingleObject( hthread, INFINITE ) == WAIT_OBJECT_0, "WaitForSingleObject failed\n" );
5576 CloseHandle( hthread );
5577 flush_events();
5578 ok_sequence( WmEmptySeq, "ShowWindow(SW_SHOW):overlapped", FALSE );
5580 ShowWindow(hwnd, SW_HIDE);
5581 flush_events();
5582 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5584 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5585 flush_events();
5586 ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
5587 flush_sequence();
5589 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZE)
5591 ShowWindow(hwnd, SW_RESTORE);
5592 flush_events();
5593 ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
5594 flush_sequence();
5597 ShowWindow(hwnd, SW_MINIMIZE);
5598 flush_events();
5599 ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", FALSE);
5600 flush_sequence();
5602 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)
5604 ShowWindow(hwnd, SW_RESTORE);
5605 flush_events();
5606 ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", FALSE);
5607 flush_sequence();
5610 ShowWindow(hwnd, SW_SHOW);
5611 flush_events();
5612 ok_sequence(WmOptionalPaint, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
5614 SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5615 ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
5616 ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
5617 ok(GetActiveWindow() == hwnd, "window should still be active\n");
5619 /* test WM_SETREDRAW on a visible top level window */
5620 ShowWindow(hwnd, SW_SHOW);
5621 flush_events();
5622 test_WM_SETREDRAW(hwnd);
5624 if (winetest_debug > 1) trace("testing scroll APIs on a visible top level window %p\n", hwnd);
5625 test_scroll_messages(hwnd);
5627 /* test resizing and moving */
5628 SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
5629 ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
5630 flush_events();
5631 flush_sequence();
5632 SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
5633 ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
5634 flush_events();
5635 flush_sequence();
5636 SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER|SWP_NOACTIVATE );
5637 ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
5638 flush_events();
5639 flush_sequence();
5641 /* popups don't get WM_GETMINMAXINFO */
5642 SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
5643 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
5644 flush_sequence();
5645 SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
5646 ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
5648 DestroyWindow(hwnd);
5649 ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
5651 /* Test if windows are correctly drawn when first shown */
5653 /* Visible, redraw */
5654 flush_events();
5655 flush_sequence();
5656 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5657 10, 10, 100, 100, NULL, 0, 0, NULL );
5658 ok (hwnd != 0, "Failed to create popup window\n");
5659 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
5660 ok_sequence(WmShowPopupFirstDrawSeq_1, "RedrawWindow:show_popup_first_draw_visible", FALSE);
5661 DestroyWindow(hwnd);
5663 /* Invisible, show, message */
5664 flush_events();
5665 flush_sequence();
5666 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5667 10, 10, 100, 100, NULL, 0, 0, NULL );
5668 ok (hwnd != 0, "Failed to create popup window\n");
5669 ShowWindow(hwnd, SW_SHOW);
5670 SendMessageW(hwnd, WM_PAINT, 0, 0);
5671 ok_sequence(WmShowPopupFirstDrawSeq_1, "RedrawWindow:show_popup_first_draw_show", FALSE);
5672 DestroyWindow(hwnd);
5674 /* Invisible, show maximized, redraw */
5675 flush_events();
5676 flush_sequence();
5677 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5678 10, 10, 100, 100, NULL, 0, 0, NULL );
5679 ok (hwnd != 0, "Failed to create popup window\n");
5680 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5681 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
5682 ok_sequence(WmShowPopupFirstDrawSeq_2, "RedrawWindow:show_popup_first_draw_show_maximized", FALSE);
5683 DestroyWindow(hwnd);
5685 /* Test SetWindowPos */
5686 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW, FALSE);
5687 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, 0, FALSE);
5688 test_msg_setpos(WmFirstDrawSetWindowPosSeq3,
5689 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER, FALSE);
5691 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOSIZE, FALSE);
5692 test_msg_setpos(WmFirstDrawSetWindowPosSeq4, SWP_SHOWWINDOW | SWP_NOMOVE, FALSE);
5693 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCLIENTSIZE, FALSE);
5694 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCLIENTMOVE, FALSE);
5695 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOZORDER, FALSE);
5697 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE, FALSE);
5698 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOCLIENTMOVE, FALSE);
5699 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOCLIENTSIZE, FALSE);
5700 test_msg_setpos(WmFirstDrawSetWindowPosSeq5, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOMOVE, FALSE);
5701 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOSIZE, FALSE);
5702 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOZORDER, FALSE);
5704 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS, FALSE);
5705 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOCLIENTMOVE, FALSE);
5706 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOCLIENTSIZE, FALSE);
5707 test_msg_setpos(WmFirstDrawSetWindowPosSeq4, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOMOVE, FALSE);
5708 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOSIZE, FALSE);
5709 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOZORDER, FALSE);
5711 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW, FALSE);
5712 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCLIENTMOVE, FALSE);
5713 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCLIENTSIZE, FALSE);
5714 test_msg_setpos(WmFirstDrawSetWindowPosSeq5, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOMOVE, FALSE);
5715 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOSIZE, FALSE);
5716 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOZORDER, FALSE);
5718 /* Test SetWindowPos with child windows */
5719 flush_events();
5720 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5721 100, 100, 200, 200, 0, 0, 0, NULL);
5722 ok (hparent != 0, "Failed to create parent window\n");
5724 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5725 0, 0, 10, 10, hparent, 0, 0, NULL);
5726 ok (hchild != 0, "Failed to create child window\n");
5727 flush_sequence();
5728 SetWindowPos(hparent, NULL, 0, 0, 100, 100, SWP_SHOWWINDOW);
5729 ok_sequence(WmFirstDrawChildSeq1, /* Expect no messages for the child */
5730 "SetWindowPos:show_popup_first_show_window_child1", FALSE);
5731 DestroyWindow(hchild);
5732 DestroyWindow(hparent);
5734 flush_events();
5735 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN,
5736 100, 100, 200, 200, 0, 0, 0, NULL);
5737 ok (hparent != 0, "Failed to create parent window\n");
5739 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5740 0, 0, 10, 10, hparent, 0, 0, NULL);
5741 ok (hchild != 0, "Failed to create child window\n");
5742 flush_sequence();
5743 SetWindowPos(hparent, NULL, 0, 0, 100, 100, SWP_SHOWWINDOW);
5744 ok_sequence(WmFirstDrawChildSeq2, /* Expect child to be redrawn */
5745 "SetWindowPos:show_popup_first_show_window_child2", FALSE);
5746 DestroyWindow(hchild);
5747 DestroyWindow(hparent);
5749 /* Test message sequence for extreme position and size */
5751 flush_sequence();
5752 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5753 -10, -10, 10000, 10000, NULL, 0, 0, NULL );
5754 ok (hwnd != 0, "Failed to create popup window\n");
5755 ok_sequence(WmShowPopupExtremeLocationSeq, "RedrawWindow:show_popup_extreme_location", FALSE);
5756 DestroyWindow(hwnd);
5759 /* Test child windows */
5761 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5762 100, 100, 200, 200, 0, 0, 0, NULL);
5763 ok (hparent != 0, "Failed to create parent window\n");
5764 flush_sequence();
5766 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
5767 0, 0, 10, 10, hparent, 0, 0, NULL);
5768 ok (hchild != 0, "Failed to create child window\n");
5769 ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
5770 DestroyWindow(hchild);
5771 flush_sequence();
5773 /* visible child window with a caption */
5774 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
5775 WS_CHILD | WS_VISIBLE | WS_CAPTION,
5776 0, 0, 10, 10, hparent, 0, 0, NULL);
5777 ok (hchild != 0, "Failed to create child window\n");
5778 ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
5780 if (winetest_debug > 1) trace("testing scroll APIs on a visible child window %p\n", hchild);
5781 test_scroll_messages(hchild);
5783 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5784 ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
5786 DestroyWindow(hchild);
5787 flush_sequence();
5789 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5790 0, 0, 10, 10, hparent, 0, 0, NULL);
5791 ok (hchild != 0, "Failed to create child window\n");
5792 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
5794 hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
5795 100, 100, 50, 50, hparent, 0, 0, NULL);
5796 ok (hchild2 != 0, "Failed to create child2 window\n");
5797 flush_sequence();
5799 hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
5800 0, 100, 50, 50, hchild, 0, 0, NULL);
5801 ok (hbutton != 0, "Failed to create button window\n");
5803 /* test WM_SETREDRAW on a not visible child window */
5804 test_WM_SETREDRAW(hchild);
5806 ShowWindow(hchild, SW_SHOW);
5807 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5809 /* check parent messages too */
5810 log_all_parent_messages++;
5811 ShowWindow(hchild, SW_HIDE);
5812 ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
5813 log_all_parent_messages--;
5815 ShowWindow(hchild, SW_SHOW);
5816 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5818 ShowWindow(hchild, SW_HIDE);
5819 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
5821 ShowWindow(hchild, SW_SHOW);
5822 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5824 /* test WM_SETREDRAW on a visible child window */
5825 test_WM_SETREDRAW(hchild);
5827 log_all_parent_messages++;
5828 MoveWindow(hchild, 10, 10, 20, 20, TRUE);
5829 ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
5830 log_all_parent_messages--;
5832 ShowWindow(hchild, SW_HIDE);
5833 flush_sequence();
5834 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5835 ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
5837 ShowWindow(hchild, SW_HIDE);
5838 flush_sequence();
5839 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
5840 ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
5842 /* DestroyWindow sequence below expects that a child has focus */
5843 SetFocus(hchild);
5844 flush_sequence();
5846 DestroyWindow(hchild);
5847 ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
5848 DestroyWindow(hchild2);
5849 DestroyWindow(hbutton);
5851 flush_sequence();
5852 hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
5853 0, 0, 100, 100, hparent, 0, 0, NULL);
5854 ok (hchild != 0, "Failed to create child popup window\n");
5855 ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
5856 DestroyWindow(hchild);
5858 /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
5859 flush_sequence();
5860 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
5861 0, 0, 100, 100, hparent, 0, 0, NULL);
5862 ok (hchild != 0, "Failed to create popup window\n");
5863 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
5864 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5865 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
5866 flush_sequence();
5867 ShowWindow(hchild, SW_SHOW);
5868 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
5869 flush_sequence();
5870 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5871 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
5872 flush_sequence();
5873 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5874 ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
5875 DestroyWindow(hchild);
5877 /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
5878 * changes nothing in message sequences.
5880 flush_sequence();
5881 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5882 0, 0, 100, 100, hparent, 0, 0, NULL);
5883 ok (hchild != 0, "Failed to create popup window\n");
5884 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
5885 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5886 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
5887 flush_sequence();
5888 ShowWindow(hchild, SW_SHOW);
5889 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
5890 flush_sequence();
5891 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5892 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
5893 DestroyWindow(hchild);
5895 flush_sequence();
5896 hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
5897 0, 0, 100, 100, hparent, 0, 0, NULL);
5898 ok(hwnd != 0, "Failed to create custom dialog window\n");
5899 ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
5901 if(0) {
5902 if (winetest_debug > 1) trace("testing scroll APIs on a visible dialog %p\n", hwnd);
5903 test_scroll_messages(hwnd);
5906 flush_sequence();
5908 test_def_id = TRUE;
5909 SendMessageA(hwnd, WM_NULL, 0, 0);
5911 flush_sequence();
5912 after_end_dialog = TRUE;
5913 EndDialog( hwnd, 0 );
5914 ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
5916 DestroyWindow(hwnd);
5917 after_end_dialog = FALSE;
5918 test_def_id = FALSE;
5920 ok(GetCursorPos(&pos), "GetCursorPos failed\n");
5921 ok(SetCursorPos(109, 109), "SetCursorPos failed\n");
5923 hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP|WS_CHILD,
5924 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
5925 ok(hwnd != 0, "Failed to create custom dialog window\n");
5926 flush_sequence();
5927 if (winetest_debug > 1) trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
5928 ShowWindow(hwnd, SW_SHOW);
5929 ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
5931 flush_events();
5932 flush_sequence();
5933 ret = DrawMenuBar(hwnd);
5934 ok(ret, "DrawMenuBar failed: %ld\n", GetLastError());
5935 flush_events();
5936 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
5937 ok(SetCursorPos(pos.x, pos.y), "SetCursorPos failed\n");
5939 DestroyWindow(hwnd);
5941 hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_CHILD|WS_VISIBLE,
5942 0, 0, 100, 100, hparent, 0, GetModuleHandleA(0), NULL);
5943 ok(hwnd != 0, "Failed to create custom dialog window\n");
5944 flush_events();
5945 flush_sequence();
5946 ret = DrawMenuBar(hwnd);
5947 ok(ret, "DrawMenuBar failed: %ld\n", GetLastError());
5948 flush_events();
5949 ok_sequence(WmEmptySeq, "DrawMenuBar for a child window", FALSE);
5951 DestroyWindow(hwnd);
5953 flush_sequence();
5954 DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
5955 ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
5957 DestroyWindow(hparent);
5958 flush_sequence();
5960 /* Message sequence for SetMenu */
5961 ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a destroyed window\n");
5962 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "last error is %ld\n", GetLastError());
5963 ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
5965 hmenu = CreateMenu();
5966 ok (hmenu != 0, "Failed to create menu\n");
5967 ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
5968 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5969 100, 100, 200, 200, 0, hmenu, 0, NULL);
5970 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
5971 ok (SetMenu(hwnd, 0), "SetMenu\n");
5972 ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
5973 ok (SetMenu(hwnd, 0), "SetMenu\n");
5974 ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
5975 ShowWindow(hwnd, SW_SHOW);
5976 UpdateWindow( hwnd );
5977 flush_events();
5978 flush_sequence();
5979 ok (SetMenu(hwnd, 0), "SetMenu\n");
5980 ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
5981 ok (SetMenu(hwnd, hmenu), "SetMenu\n");
5982 ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
5984 UpdateWindow( hwnd );
5985 flush_events();
5986 flush_sequence();
5987 ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
5988 flush_events();
5989 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
5991 DestroyWindow(hwnd);
5992 flush_sequence();
5994 /* Message sequence for EnableWindow */
5995 hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5996 100, 100, 200, 200, 0, 0, 0, NULL);
5997 ok (hparent != 0, "Failed to create parent window\n");
5998 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5999 0, 0, 10, 10, hparent, 0, 0, NULL);
6000 ok (hchild != 0, "Failed to create child window\n");
6002 SetFocus(hchild);
6003 flush_events();
6004 flush_sequence();
6006 EnableWindow(hparent, FALSE);
6007 ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
6009 EnableWindow(hparent, FALSE);
6010 ok_sequence(WmEnableWindowSeq_2, "EnableWindow(FALSE)", FALSE);
6012 EnableWindow(hparent, TRUE);
6013 ok_sequence(WmEnableWindowSeq_3, "EnableWindow(TRUE)", FALSE);
6015 EnableWindow(hparent, TRUE);
6016 ok_sequence(WmEnableWindowSeq_4, "EnableWindow(TRUE)", FALSE);
6018 flush_events();
6019 flush_sequence();
6021 test_MsgWaitForMultipleObjects(hparent);
6022 test_WM_DEVICECHANGE(hparent);
6024 /* the following test causes an exception in user.exe under win9x */
6025 if (!PostMessageW( hparent, WM_USER, 0, 0 ))
6027 DestroyWindow(hparent);
6028 flush_sequence();
6029 return;
6031 PostMessageW( hparent, WM_USER+1, 0, 0 );
6032 /* PeekMessage(NULL) fails, but still removes the message */
6033 SetLastError(0xdeadbeef);
6034 ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
6035 ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
6036 GetLastError() == 0xdeadbeef, /* NT4 */
6037 "last error is %ld\n", GetLastError() );
6038 ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
6039 ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
6041 DestroyWindow(hchild);
6042 DestroyWindow(hparent);
6043 flush_sequence();
6045 /* Message sequences for WM_SETICON */
6046 if (winetest_debug > 1) trace("testing WM_SETICON\n");
6047 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
6048 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
6049 NULL, NULL, 0);
6050 ShowWindow(hwnd, SW_SHOW);
6051 UpdateWindow(hwnd);
6052 flush_events();
6053 flush_sequence();
6054 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
6055 ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
6057 ShowWindow(hwnd, SW_HIDE);
6058 flush_events();
6059 flush_sequence();
6060 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
6061 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
6062 DestroyWindow(hwnd);
6063 flush_sequence();
6065 hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
6066 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
6067 NULL, NULL, 0);
6068 ShowWindow(hwnd, SW_SHOW);
6069 UpdateWindow(hwnd);
6070 flush_events();
6071 flush_sequence();
6072 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
6073 ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
6075 ShowWindow(hwnd, SW_HIDE);
6076 flush_events();
6077 flush_sequence();
6078 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
6079 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
6081 flush_sequence();
6082 res = SendMessageA(hwnd, 0x3B, 0x8000000b, 0);
6083 if (!res)
6085 todo_wine win_skip( "Message 0x3b not supported\n" );
6086 goto done;
6088 ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
6089 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %Id\n", res);
6090 res = SendMessageA(hwnd, 0x3B, 0x0000000b, 0);
6091 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
6092 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %Id\n", res);
6093 res = SendMessageA(hwnd, 0x3B, 0x0000000f, 0);
6094 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
6095 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %Id\n", res);
6097 flush_sequence();
6098 res = SendMessageA(hwnd, 0x3B, 0x80000008, 0);
6099 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
6100 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %Id\n", res);
6101 res = SendMessageA(hwnd, 0x3B, 0x00000008, 0);
6102 ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
6103 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %Id\n", res);
6105 res = SendMessageA(hwnd, 0x3B, 0x80000004, 0);
6106 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
6107 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %Id\n", res);
6109 res = SendMessageA(hwnd, 0x3B, 0x80000001, 0);
6110 ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
6111 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %Id\n", res);
6113 done:
6114 DestroyWindow(hwnd);
6115 flush_sequence();
6118 static const struct message WmFrameChanged[] = {
6119 { WM_WINDOWPOSCHANGING, sent|wparam|lparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE, 0 },
6120 { WM_NCCALCSIZE, sent|wparam|lparam, 1, 0xf },
6121 { WM_WINDOWPOSCHANGED, sent|wparam|lparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW
6122 |SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0xf },
6123 { WM_GETTEXT, sent|optional },
6124 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
6125 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
6126 { 0 }
6129 static const struct message WmFrameChanged_move[] = {
6130 { WM_WINDOWPOSCHANGING, sent|wparam|lparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE, 0 },
6131 { WM_NCCALCSIZE, sent|wparam|lparam, 1, 0x3 },
6132 { WM_WINDOWPOSCHANGED, sent|wparam|lparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW
6133 |SWP_NOSIZE|SWP_NOCLIENTSIZE, 0x3 },
6134 { WM_MOVE, sent|defwinproc, 0 },
6135 { WM_GETTEXT, sent|optional },
6136 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
6137 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
6138 { 0 }
6141 static void test_setwindowpos(void)
6143 HWND hwnd;
6144 RECT rc;
6145 LRESULT res;
6146 const INT X = 50;
6147 const INT Y = 50;
6148 const INT winX = 100;
6149 const INT winY = 100;
6150 const INT sysX = GetSystemMetrics(SM_CXMINTRACK);
6152 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
6153 X, Y, winX, winY, 0,
6154 NULL, NULL, 0);
6156 GetWindowRect(hwnd, &rc);
6157 expect(sysX + X, rc.right);
6158 expect(winY + Y, rc.bottom);
6160 flush_events();
6161 flush_sequence();
6162 res = SetWindowPos(hwnd, HWND_TOPMOST, 50, 50, winX, winY, 0);
6163 ok_sequence(WmZOrder, "Z-Order", TRUE);
6164 ok(res == TRUE, "SetWindowPos expected TRUE, got %Id\n", res);
6166 GetWindowRect(hwnd, &rc);
6167 expect(sysX + X, rc.right);
6168 expect(winY + Y, rc.bottom);
6170 res = SetWindowPos( hwnd, 0, 0, 0, 0, 0,
6171 SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
6172 ok_sequence(WmFrameChanged, "FrameChanged", FALSE);
6173 ok(res == TRUE, "SetWindowPos expected TRUE, got %Id.\n", res);
6175 GetWindowRect(hwnd, &rc);
6176 expect(sysX + X, rc.right);
6177 expect(winY + Y, rc.bottom);
6179 res = SetWindowPos( hwnd, 0, 0, 0, 0, 0,
6180 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
6181 ok_sequence(WmFrameChanged_move, "FrameChanged", FALSE);
6182 ok(res == TRUE, "SetWindowPos expected TRUE, got %Id.\n", res);
6184 GetWindowRect(hwnd, &rc);
6185 expect(sysX, rc.right);
6186 expect(winY, rc.bottom);
6188 DestroyWindow(hwnd);
6191 static void invisible_parent_tests(void)
6193 HWND hparent, hchild;
6195 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
6196 100, 100, 200, 200, 0, 0, 0, NULL);
6197 ok (hparent != 0, "Failed to create parent window\n");
6198 flush_sequence();
6200 /* test showing child with hidden parent */
6202 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6203 0, 0, 10, 10, hparent, 0, 0, NULL);
6204 ok (hchild != 0, "Failed to create child window\n");
6205 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
6207 ShowWindow( hchild, SW_MINIMIZE );
6208 ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
6209 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6210 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6212 /* repeat */
6213 flush_events();
6214 flush_sequence();
6215 ShowWindow( hchild, SW_MINIMIZE );
6216 ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
6218 DestroyWindow(hchild);
6219 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6220 0, 0, 10, 10, hparent, 0, 0, NULL);
6221 flush_sequence();
6223 ShowWindow( hchild, SW_MAXIMIZE );
6224 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
6225 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6226 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6228 /* repeat */
6229 flush_events();
6230 flush_sequence();
6231 ShowWindow( hchild, SW_MAXIMIZE );
6232 ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
6234 DestroyWindow(hchild);
6235 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6236 0, 0, 10, 10, hparent, 0, 0, NULL);
6237 flush_sequence();
6239 ShowWindow( hchild, SW_RESTORE );
6240 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
6241 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6242 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6244 DestroyWindow(hchild);
6245 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6246 0, 0, 10, 10, hparent, 0, 0, NULL);
6247 flush_sequence();
6249 ShowWindow( hchild, SW_SHOWMINIMIZED );
6250 ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
6251 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6252 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6254 /* repeat */
6255 flush_events();
6256 flush_sequence();
6257 ShowWindow( hchild, SW_SHOWMINIMIZED );
6258 ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
6260 DestroyWindow(hchild);
6261 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6262 0, 0, 10, 10, hparent, 0, 0, NULL);
6263 flush_sequence();
6265 /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
6266 ShowWindow( hchild, SW_SHOWMAXIMIZED );
6267 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
6268 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6269 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6271 DestroyWindow(hchild);
6272 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6273 0, 0, 10, 10, hparent, 0, 0, NULL);
6274 flush_sequence();
6276 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
6277 ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
6278 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6279 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6281 /* repeat */
6282 flush_events();
6283 flush_sequence();
6284 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
6285 ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
6287 DestroyWindow(hchild);
6288 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6289 0, 0, 10, 10, hparent, 0, 0, NULL);
6290 flush_sequence();
6292 /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
6293 ShowWindow( hchild, SW_FORCEMINIMIZE );
6294 ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
6295 todo_wine {
6296 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
6298 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6300 DestroyWindow(hchild);
6301 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6302 0, 0, 10, 10, hparent, 0, 0, NULL);
6303 flush_sequence();
6305 ShowWindow( hchild, SW_SHOWNA );
6306 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
6307 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6308 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6310 /* repeat */
6311 flush_events();
6312 flush_sequence();
6313 ShowWindow( hchild, SW_SHOWNA );
6314 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
6316 DestroyWindow(hchild);
6317 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6318 0, 0, 10, 10, hparent, 0, 0, NULL);
6319 flush_sequence();
6321 ShowWindow( hchild, SW_SHOW );
6322 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
6323 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6324 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6326 /* repeat */
6327 flush_events();
6328 flush_sequence();
6329 ShowWindow( hchild, SW_SHOW );
6330 ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
6332 ShowWindow( hchild, SW_HIDE );
6333 ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
6334 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
6335 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6337 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
6338 ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
6339 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6340 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6342 SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
6343 ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
6344 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
6345 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6347 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
6348 flush_sequence();
6349 DestroyWindow(hchild);
6350 ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
6352 DestroyWindow(hparent);
6353 flush_sequence();
6356 /****************** button message test *************************/
6357 #define ID_BUTTON 0x000e
6359 static const struct message WmSetFocusButtonSeq[] =
6361 { HCBT_SETFOCUS, hook },
6362 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
6363 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
6364 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6365 { WM_SETFOCUS, sent|wparam, 0 },
6366 { WM_CTLCOLORBTN, sent|parent },
6367 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
6368 { WM_APP, sent|wparam|lparam, 0, 0 },
6369 { 0 }
6371 static const struct message WmKillFocusButtonSeq[] =
6373 { HCBT_SETFOCUS, hook },
6374 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6375 { WM_KILLFOCUS, sent|wparam, 0 },
6376 { WM_CTLCOLORBTN, sent|parent },
6377 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
6378 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
6379 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
6380 { WM_APP, sent|wparam|lparam, 0, 0 },
6381 { WM_PAINT, sent },
6382 { WM_CTLCOLORBTN, sent|parent },
6383 { 0 }
6385 static const struct message WmSetFocusStaticSeq[] =
6387 { HCBT_SETFOCUS, hook },
6388 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
6389 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
6390 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6391 { WM_SETFOCUS, sent|wparam, 0 },
6392 { WM_CTLCOLORSTATIC, sent|parent },
6393 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
6394 { WM_COMMAND, sent|wparam|parent|optional, MAKEWPARAM(ID_BUTTON, BN_CLICKED) }, /* radio button */
6395 { WM_APP, sent|wparam|lparam, 0, 0 },
6396 { 0 }
6398 static const struct message WmKillFocusStaticSeq[] =
6400 { HCBT_SETFOCUS, hook },
6401 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6402 { WM_KILLFOCUS, sent|wparam, 0 },
6403 { WM_CTLCOLORSTATIC, sent|parent },
6404 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
6405 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
6406 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
6407 { WM_APP, sent|wparam|lparam, 0, 0 },
6408 { WM_PAINT, sent },
6409 { WM_CTLCOLORSTATIC, sent|parent },
6410 { 0 }
6412 static const struct message WmSetFocusOwnerdrawSeq[] =
6414 { HCBT_SETFOCUS, hook },
6415 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
6416 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
6417 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6418 { WM_SETFOCUS, sent|wparam, 0 },
6419 { WM_CTLCOLORBTN, sent|parent },
6420 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x001040e4 },
6421 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
6422 { WM_APP, sent|wparam|lparam, 0, 0 },
6423 { 0 }
6425 static const struct message WmKillFocusOwnerdrawSeq[] =
6427 { HCBT_SETFOCUS, hook },
6428 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6429 { WM_KILLFOCUS, sent|wparam, 0 },
6430 { WM_CTLCOLORBTN, sent|parent },
6431 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000040e4 },
6432 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
6433 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
6434 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
6435 { WM_APP, sent|wparam|lparam, 0, 0 },
6436 { WM_PAINT, sent },
6437 { WM_CTLCOLORBTN, sent|parent },
6438 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
6439 { 0 }
6441 static const struct message WmLButtonDownSeq[] =
6443 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
6444 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
6445 { HCBT_SETFOCUS, hook },
6446 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
6447 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
6448 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6449 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
6450 { WM_CTLCOLORBTN, sent|defwinproc },
6451 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
6452 { WM_CTLCOLORBTN, sent|defwinproc },
6453 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6454 { 0 }
6456 static const struct message WmLButtonDownStaticSeq[] =
6458 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
6459 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
6460 { HCBT_SETFOCUS, hook },
6461 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
6462 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
6463 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6464 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
6465 { WM_CTLCOLORSTATIC, sent|defwinproc },
6466 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
6467 { WM_CTLCOLORSTATIC, sent|defwinproc },
6468 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6469 { 0 }
6471 static const struct message WmLButtonUpSeq[] =
6473 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6474 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6475 { WM_CTLCOLORBTN, sent|defwinproc },
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_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6479 { 0 }
6481 static const struct message WmLButtonUpStaticSeq[] =
6483 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6484 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6485 { WM_CTLCOLORSTATIC, sent|defwinproc },
6486 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6487 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
6488 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6489 { 0 }
6491 static const struct message WmLButtonUpAutoSeq[] =
6493 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6494 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6495 { WM_CTLCOLORSTATIC, sent|defwinproc },
6496 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6497 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|optional, 0, 0 },
6498 { BM_SETCHECK, sent|defwinproc },
6499 { WM_CTLCOLORSTATIC, sent|defwinproc|optional, 0, 0 }, /* Sent here on Win7. */
6500 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6501 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
6502 { WM_CTLCOLORSTATIC, sent|defwinproc|optional, 0, 0 }, /* Sent here on Win8+. */
6503 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6504 { 0 }
6506 static const struct message WmLButtonUpBrokenSeq[] =
6508 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6509 { 0 }
6511 static const struct message WmSetFontButtonSeq[] =
6513 { WM_SETFONT, sent },
6514 { WM_PAINT, sent },
6515 { WM_ERASEBKGND, sent|defwinproc|optional },
6516 { WM_CTLCOLORBTN, sent|defwinproc },
6517 { WM_CTLCOLORBTN, sent|defwinproc|optional }, /* FIXME: Wine sends it twice for BS_OWNERDRAW */
6518 { 0 }
6520 static const struct message WmSetFontStaticSeq[] =
6522 { WM_SETFONT, sent },
6523 { WM_PAINT, sent },
6524 { WM_ERASEBKGND, sent|defwinproc|optional },
6525 { WM_CTLCOLORSTATIC, sent|defwinproc },
6526 { 0 }
6528 static const struct message WmSetTextButtonSeq[] =
6530 { WM_SETTEXT, sent },
6531 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
6532 { WM_CTLCOLORBTN, sent|parent },
6533 { WM_CTLCOLORBTN, sent|parent },
6534 { WM_COMMAND, sent|parent|optional },
6535 { WM_DRAWITEM, sent|parent|optional },
6536 { 0 }
6538 static const struct message WmSetTextStaticSeq[] =
6540 { WM_SETTEXT, sent },
6541 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
6542 { WM_CTLCOLORSTATIC, sent|parent },
6543 { WM_CTLCOLORSTATIC, sent|parent },
6544 { 0 }
6546 static const struct message WmSetTextGroupSeq[] =
6548 { WM_SETTEXT, sent },
6549 { WM_CTLCOLORSTATIC, sent|parent },
6550 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
6551 { WM_CTLCOLORSTATIC, sent|parent|optional }, /* FIXME: Missing in Wine */
6552 { WM_CTLCOLORSTATIC, sent|parent|optional }, /* FIXME: Missing in Wine */
6553 { 0 }
6555 static const struct message WmSetTextInvisibleSeq[] =
6557 { WM_SETTEXT, sent },
6558 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
6559 { 0 }
6561 static const struct message WmSetStyleButtonSeq[] =
6563 { BM_SETSTYLE, sent },
6564 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6565 { WM_APP, sent|wparam|lparam, 0, 0 },
6566 { WM_PAINT, sent },
6567 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6568 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6569 { WM_CTLCOLORBTN, sent|parent },
6570 { 0 }
6572 static const struct message WmSetStyleStaticSeq[] =
6574 { BM_SETSTYLE, sent },
6575 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6576 { WM_APP, sent|wparam|lparam, 0, 0 },
6577 { WM_PAINT, sent },
6578 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6579 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6580 { WM_CTLCOLORSTATIC, sent|parent },
6581 { 0 }
6583 static const struct message WmSetStyleUserSeq[] =
6585 { BM_SETSTYLE, sent },
6586 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6587 { WM_APP, sent|wparam|lparam, 0, 0 },
6588 { WM_PAINT, sent },
6589 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6590 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6591 { WM_CTLCOLORBTN, sent|parent },
6592 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_PAINT) },
6593 { 0 }
6595 static const struct message WmSetStyleOwnerdrawSeq[] =
6597 { BM_SETSTYLE, sent },
6598 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6599 { WM_APP, sent|wparam|lparam, 0, 0 },
6600 { WM_PAINT, sent },
6601 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
6602 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6603 { WM_CTLCOLORBTN, sent|parent },
6604 { WM_CTLCOLORBTN, sent|parent|optional }, /* Win9x doesn't send it */
6605 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
6606 { 0 }
6608 static const struct message WmSetStateButtonSeq[] =
6610 { BM_SETSTATE, sent },
6611 { WM_CTLCOLORBTN, sent|parent },
6612 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6613 { WM_APP, sent|wparam|lparam, 0, 0 },
6614 { 0 }
6616 static const struct message WmSetStateStaticSeq[] =
6618 { BM_SETSTATE, sent },
6619 { WM_CTLCOLORSTATIC, sent|parent },
6620 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6621 { WM_APP, sent|wparam|lparam, 0, 0 },
6622 { 0 }
6624 static const struct message WmSetStateUserSeq[] =
6626 { BM_SETSTATE, sent },
6627 { WM_CTLCOLORBTN, sent|parent },
6628 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_HILITE) },
6629 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6630 { WM_APP, sent|wparam|lparam, 0, 0 },
6631 { 0 }
6633 static const struct message WmSetStateOwnerdrawSeq[] =
6635 { BM_SETSTATE, sent },
6636 { WM_CTLCOLORBTN, sent|parent },
6637 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000120e4 },
6638 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6639 { WM_APP, sent|wparam|lparam, 0, 0 },
6640 { 0 }
6642 static const struct message WmClearStateButtonSeq[] =
6644 { BM_SETSTATE, sent },
6645 { WM_CTLCOLORBTN, sent|parent },
6646 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_UNHILITE) },
6647 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6648 { WM_APP, sent|wparam|lparam, 0, 0 },
6649 { 0 }
6651 static const struct message WmDisableButtonSeq[] =
6653 { WM_LBUTTONDOWN, sent },
6654 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
6655 { BM_SETSTATE, sent|defwinproc },
6656 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6657 { WM_CTLCOLORBTN, sent|optional },
6658 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6659 { WM_LBUTTONUP, sent },
6660 { BM_SETSTATE, sent|defwinproc },
6661 { WM_CTLCOLORBTN, sent|defwinproc|optional },
6662 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6663 { BM_SETCHECK, sent|defwinproc|optional },
6664 { WM_CTLCOLORBTN, sent|optional },
6665 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6666 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
6667 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6668 { WM_CAPTURECHANGED, sent|defwinproc },
6669 { WM_COMMAND, sent },
6670 { 0 }
6672 static const struct message WmClearStateOwnerdrawSeq[] =
6674 { BM_SETSTATE, sent },
6675 { WM_CTLCOLORBTN, sent|parent },
6676 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000020e4 },
6677 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
6678 { WM_APP, sent|wparam|lparam, 0, 0 },
6679 { 0 }
6681 static const struct message WmSetCheckIgnoredSeq[] =
6683 { BM_SETCHECK, sent },
6684 { WM_APP, sent|wparam|lparam, 0, 0 },
6685 { 0 }
6687 static const struct message WmSetCheckStaticSeq[] =
6689 { BM_SETCHECK, sent },
6690 { WM_CTLCOLORSTATIC, sent|parent },
6691 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
6692 { WM_APP, sent|wparam|lparam, 0, 0 },
6693 { 0 }
6696 static WNDPROC old_button_proc;
6698 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6700 static LONG defwndproc_counter = 0;
6701 LRESULT ret;
6702 struct recvd_message msg;
6704 if (ignore_message( message )) return 0;
6706 switch (message)
6708 case WM_SYNCPAINT:
6709 break;
6710 case BM_SETSTATE:
6711 if (GetCapture())
6712 ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
6714 lParam = (ULONG_PTR)GetMenu(hwnd);
6715 goto log_it;
6717 case WM_GETDLGCODE:
6718 if (lParam)
6720 MSG *msg = (MSG *)lParam;
6721 lParam = MAKELPARAM(msg->message, msg->wParam);
6723 wParam = (ULONG_PTR)GetMenu(hwnd);
6724 goto log_it;
6726 case BM_SETCHECK:
6727 case BM_GETCHECK:
6728 lParam = (ULONG_PTR)GetMenu(hwnd);
6729 /* fall through */
6730 log_it:
6731 default:
6732 msg.hwnd = hwnd;
6733 msg.message = message;
6734 msg.flags = sent|wparam|lparam;
6735 if (defwndproc_counter) msg.flags |= defwinproc;
6736 msg.wParam = wParam;
6737 msg.lParam = lParam;
6738 msg.descr = "button";
6739 add_message(&msg);
6742 defwndproc_counter++;
6743 ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
6744 defwndproc_counter--;
6746 return ret;
6749 static void subclass_button(void)
6751 WNDCLASSA cls;
6752 BOOL ret;
6754 ret = GetClassInfoA(0, "button", &cls);
6755 ok(ret, "Failed to get class info, error %lu.\n", GetLastError());
6757 old_button_proc = cls.lpfnWndProc;
6759 cls.hInstance = GetModuleHandleA(NULL);
6760 cls.lpfnWndProc = button_hook_proc;
6761 cls.lpszClassName = "my_button_class";
6762 UnregisterClassA(cls.lpszClassName, cls.hInstance);
6763 register_class(&cls);
6766 static void test_button_messages(void)
6768 static const struct
6770 DWORD style;
6771 DWORD dlg_code;
6772 const struct message *setfocus;
6773 const struct message *killfocus;
6774 const struct message *setstyle;
6775 const struct message *setstate;
6776 const struct message *clearstate;
6777 const struct message *setcheck;
6778 const struct message *lbuttondown;
6779 const struct message *lbuttonup;
6780 const struct message *setfont;
6781 const struct message *settext;
6782 } button[] = {
6783 { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
6784 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
6785 WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq,
6786 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6787 WmSetTextButtonSeq },
6788 { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
6789 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
6790 WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq,
6791 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6792 WmSetTextButtonSeq },
6793 { BS_CHECKBOX, DLGC_BUTTON,
6794 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6795 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6796 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6797 WmSetTextStaticSeq },
6798 { BS_AUTOCHECKBOX, DLGC_BUTTON,
6799 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6800 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6801 WmLButtonDownStaticSeq, WmLButtonUpAutoSeq, WmSetFontStaticSeq,
6802 WmSetTextStaticSeq },
6803 { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
6804 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6805 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6806 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6807 WmSetTextStaticSeq },
6808 { BS_3STATE, DLGC_BUTTON,
6809 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6810 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6811 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6812 WmSetTextStaticSeq },
6813 { BS_AUTO3STATE, DLGC_BUTTON,
6814 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6815 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6816 WmLButtonDownStaticSeq, WmLButtonUpAutoSeq, WmSetFontStaticSeq,
6817 WmSetTextStaticSeq },
6818 { BS_GROUPBOX, DLGC_STATIC,
6819 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6820 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckIgnoredSeq,
6821 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6822 WmSetTextGroupSeq },
6823 { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
6824 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleUserSeq,
6825 WmSetStateUserSeq, WmClearStateButtonSeq, WmSetCheckIgnoredSeq,
6826 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6827 WmSetTextButtonSeq },
6828 { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
6829 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6830 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6831 NULL /* avoid infinite loop */, WmLButtonUpBrokenSeq, WmSetFontStaticSeq,
6832 WmSetTextStaticSeq },
6833 { BS_OWNERDRAW, DLGC_BUTTON,
6834 WmSetFocusOwnerdrawSeq, WmKillFocusOwnerdrawSeq, WmSetStyleOwnerdrawSeq,
6835 WmSetStateOwnerdrawSeq, WmClearStateOwnerdrawSeq, WmSetCheckIgnoredSeq,
6836 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6837 WmSetTextButtonSeq },
6839 LOGFONTA logfont = { 0 };
6840 HFONT zfont, hfont2;
6841 unsigned int i;
6842 HWND hwnd, parent;
6843 DWORD dlg_code;
6845 /* selection with VK_SPACE should capture button window */
6846 hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
6847 0, 0, 50, 14, 0, 0, 0, NULL);
6848 ok(hwnd != 0, "Failed to create button window\n");
6849 ReleaseCapture();
6850 SetFocus(hwnd);
6851 SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
6852 ok(GetCapture() == hwnd, "Should be captured on VK_SPACE WM_KEYDOWN\n");
6853 SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
6854 DestroyWindow(hwnd);
6856 subclass_button();
6858 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6859 100, 100, 200, 200, 0, 0, 0, NULL);
6860 ok(parent != 0, "Failed to create parent window\n");
6862 memset(&logfont, 0, sizeof(logfont));
6863 logfont.lfHeight = -12;
6864 logfont.lfWeight = FW_NORMAL;
6865 strcpy(logfont.lfFaceName, "Tahoma");
6867 hfont2 = CreateFontIndirectA(&logfont);
6868 ok(hfont2 != NULL, "Failed to create Tahoma font\n");
6870 for (i = 0; i < ARRAY_SIZE(button); i++)
6872 MSG msg;
6873 DWORD style, state;
6874 HFONT prevfont;
6875 char desc[64];
6876 HDC hdc;
6878 if (winetest_debug > 1) trace("button style %08lx\n", button[i].style);
6880 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_CHILD | BS_NOTIFY,
6881 0, 0, 50, 14, parent, (HMENU)ID_BUTTON, 0, NULL);
6882 ok(hwnd != 0, "Failed to create button window\n");
6884 style = GetWindowLongA(hwnd, GWL_STYLE);
6885 style &= ~(WS_CHILD | BS_NOTIFY);
6886 /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
6887 if (button[i].style == BS_USERBUTTON)
6888 ok(style == BS_PUSHBUTTON, "expected style BS_PUSHBUTTON got %lx\n", style);
6889 else
6890 ok(style == button[i].style, "expected style %lx got %lx\n", button[i].style, style);
6892 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
6893 ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08lx\n", i, dlg_code);
6895 ShowWindow(hwnd, SW_SHOW);
6896 UpdateWindow(hwnd);
6897 SetFocus(0);
6898 flush_events();
6899 SetFocus(0);
6900 flush_sequence();
6902 log_all_parent_messages++;
6904 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
6905 SetFocus(hwnd);
6906 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6907 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6908 ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
6910 SetFocus(0);
6911 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6912 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6913 ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
6915 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
6917 SendMessageA(hwnd, BM_SETSTYLE, button[i].style | BS_BOTTOM, TRUE);
6918 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6919 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6920 ok_sequence(button[i].setstyle, "BM_SETSTYLE on a button", FALSE);
6922 style = GetWindowLongA(hwnd, GWL_STYLE);
6923 style &= ~(WS_VISIBLE | WS_CHILD | BS_NOTIFY);
6924 /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */
6925 ok(style == button[i].style, "expected style %04lx got %04lx\n", button[i].style, style);
6927 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6928 ok(state == 0, "expected state 0, got %04lx\n", state);
6930 flush_sequence();
6932 SendMessageA(hwnd, BM_SETSTATE, TRUE, 0);
6933 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6934 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6935 ok_sequence(button[i].setstate, "BM_SETSTATE/TRUE on a button", FALSE);
6937 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6938 ok(state == 0x0004, "expected state 0x0004, got %04lx\n", state);
6940 style = GetWindowLongA(hwnd, GWL_STYLE);
6941 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6942 ok(style == button[i].style, "expected style %04lx got %04lx\n", button[i].style, style);
6944 flush_sequence();
6946 SendMessageA(hwnd, BM_SETSTATE, FALSE, 0);
6947 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6948 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6949 ok_sequence(button[i].clearstate, "BM_SETSTATE/FALSE on a button", FALSE);
6951 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6952 ok(state == 0, "expected state 0, got %04lx\n", state);
6954 style = GetWindowLongA(hwnd, GWL_STYLE);
6955 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6956 ok(style == button[i].style, "expected style %04lx got %04lx\n", button[i].style, style);
6958 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6959 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04lx\n", state);
6961 flush_sequence();
6963 SendMessageA(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
6964 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6965 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6966 ok_sequence(WmSetCheckIgnoredSeq, "BM_SETCHECK on a button", FALSE);
6968 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6969 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04lx\n", state);
6971 style = GetWindowLongA(hwnd, GWL_STYLE);
6972 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6973 ok(style == button[i].style, "expected style %04lx got %04lx\n", button[i].style, style);
6975 flush_sequence();
6977 SendMessageA(hwnd, BM_SETCHECK, BST_CHECKED, 0);
6978 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6979 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6980 ok_sequence(button[i].setcheck, "BM_SETCHECK on a button", FALSE);
6982 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 1");
6983 sprintf(desc, "button[%i]: WM_SETTEXT on a visible button", i);
6984 ok_sequence(button[i].settext, desc, FALSE);
6986 ShowWindow(hwnd, SW_HIDE);
6987 flush_events();
6988 flush_sequence();
6990 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 2");
6991 sprintf(desc, "button[%i]: WM_SETTEXT on an invisible button", i);
6992 ok_sequence(WmSetTextInvisibleSeq, desc, FALSE);
6994 ShowWindow(hwnd, SW_SHOW);
6995 ShowWindow(parent, SW_HIDE);
6996 flush_events();
6997 flush_sequence();
6999 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 3");
7000 sprintf(desc, "button[%i]: WM_SETTEXT on an invisible button", i);
7001 ok_sequence(WmSetTextInvisibleSeq, desc, FALSE);
7003 ShowWindow(parent, SW_SHOW);
7004 flush_events();
7006 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
7007 if (button[i].style == BS_PUSHBUTTON ||
7008 button[i].style == BS_DEFPUSHBUTTON ||
7009 button[i].style == BS_GROUPBOX ||
7010 button[i].style == BS_USERBUTTON ||
7011 button[i].style == BS_OWNERDRAW)
7012 ok(state == BST_UNCHECKED, "expected check 0, got %04lx\n", state);
7013 else
7014 ok(state == BST_CHECKED, "expected check 1, got %04lx\n", state);
7016 style = GetWindowLongA(hwnd, GWL_STYLE);
7017 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
7018 if (button[i].style == BS_RADIOBUTTON ||
7019 button[i].style == BS_AUTORADIOBUTTON)
7020 ok(style == (button[i].style | WS_TABSTOP), "expected style %04lx | WS_TABSTOP got %04lx\n", button[i].style, style);
7021 else
7022 ok(style == button[i].style, "expected style %04lx got %04lx\n", button[i].style, style);
7024 log_all_parent_messages--;
7026 DestroyWindow(hwnd);
7028 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP | WS_VISIBLE,
7029 0, 0, 50, 14, 0, 0, 0, NULL);
7030 ok(hwnd != 0, "Failed to create button window\n");
7032 SetForegroundWindow(hwnd);
7033 flush_events();
7035 SetActiveWindow(hwnd);
7036 SetFocus(0);
7037 flush_sequence();
7039 if (button[i].lbuttondown)
7041 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
7042 sprintf(desc, "button[%i]: WM_LBUTTONDOWN on a button", i);
7043 ok_sequence(button[i].lbuttondown, desc, FALSE);
7046 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
7047 sprintf(desc, "button[%i]: WM_LBUTTONUP on a button", i);
7048 ok_sequence(button[i].lbuttonup, desc, FALSE);
7050 flush_sequence();
7051 zfont = GetStockObject(DEFAULT_GUI_FONT);
7052 SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
7053 UpdateWindow(hwnd);
7054 sprintf(desc, "button[%i]: WM_SETFONT on a button", i);
7055 ok_sequence(button[i].setfont, desc, FALSE);
7057 /* Test that original font is not selected back after painting */
7058 hdc = CreateCompatibleDC(0);
7060 prevfont = SelectObject(hdc, hfont2);
7061 ok(prevfont == GetStockObject(SYSTEM_FONT), "Unexpected default font\n");
7062 SendMessageA(hwnd, WM_PRINTCLIENT, (WPARAM)hdc, 0);
7063 ok(hfont2 != GetCurrentObject(hdc, OBJ_FONT), "button[%u]: unexpected font selected after WM_PRINTCLIENT\n", i);
7064 SelectObject(hdc, prevfont);
7066 prevfont = SelectObject(hdc, hfont2);
7067 ok(prevfont == GetStockObject(SYSTEM_FONT), "Unexpected default font\n");
7068 SendMessageA(hwnd, WM_PAINT, (WPARAM)hdc, 0);
7069 ok(hfont2 != GetCurrentObject(hdc, OBJ_FONT), "button[%u]: unexpected font selected after WM_PAINT\n", i);
7070 SelectObject(hdc, prevfont);
7072 DeleteDC(hdc);
7074 DestroyWindow(hwnd);
7077 DeleteObject(hfont2);
7078 DestroyWindow(parent);
7080 /* Test if WM_LBUTTONDOWN and WM_LBUTTONUP to a disabled button leads to a WM_COMMAND for the parent */
7082 parent = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7083 100, 100, 200, 200, 0, 0, 0, NULL);
7084 ok (hwnd != 0, "Failed to create overlapped window\n");
7086 hwnd = CreateWindowExA(0, "my_button_class", "test", BS_DEFPUSHBUTTON | WS_VISIBLE | WS_CHILD,
7087 0, 0, 50, 14, parent, 0, 0, NULL);
7089 EnableWindow(hwnd, FALSE);
7090 flush_sequence();
7091 SendMessageA(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, 0);
7092 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
7093 ok_sequence(WmDisableButtonSeq, "Mouseclick on a disabled button", FALSE);
7095 DestroyWindow(hwnd);
7096 DestroyWindow(parent);
7099 static void test_button_bm_get_set_image(void)
7101 HWND hwnd;
7102 HDC hdc;
7103 HBITMAP hbmp1x1;
7104 HBITMAP hbmp2x2;
7105 HBITMAP hmask2x2;
7106 ICONINFO icon_info2x2;
7107 HICON hicon2x2;
7108 HBITMAP hbmp;
7109 HICON hicon;
7110 ICONINFO icon_info;
7111 BITMAP bm;
7112 DWORD default_style = BS_PUSHBUTTON | WS_TABSTOP | WS_POPUP | WS_VISIBLE;
7113 LRESULT ret;
7115 hdc = GetDC(0);
7116 hbmp1x1 = CreateCompatibleBitmap(hdc, 1, 1);
7117 hbmp2x2 = CreateCompatibleBitmap(hdc, 2, 2);
7118 ZeroMemory(&bm, sizeof(bm));
7119 ok(GetObjectW(hbmp1x1, sizeof(bm), &bm), "Expect GetObjectW() success\n");
7120 ok(bm.bmWidth == 1 && bm.bmHeight == 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
7121 bm.bmWidth, bm.bmHeight);
7122 ZeroMemory(&bm, sizeof(bm));
7123 ok(GetObjectW(hbmp2x2, sizeof(bm), &bm), "Expect GetObjectW() success\n");
7124 ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
7125 bm.bmWidth, bm.bmHeight);
7127 hmask2x2 = CreateCompatibleBitmap(hdc, 2, 2);
7128 ZeroMemory(&icon_info2x2, sizeof(icon_info2x2));
7129 icon_info2x2.fIcon = TRUE;
7130 icon_info2x2.hbmMask = hmask2x2;
7131 icon_info2x2.hbmColor = hbmp2x2;
7132 hicon2x2 = CreateIconIndirect(&icon_info2x2);
7134 ZeroMemory(&icon_info, sizeof(icon_info));
7135 ok(GetIconInfo(hicon2x2, &icon_info), "Expect GetIconInfo() success\n");
7136 ZeroMemory(&bm, sizeof(bm));
7137 ok(GetObjectW(icon_info.hbmColor, sizeof(bm), &bm), "Expect GetObjectW() success\n");
7138 ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
7139 bm.bmWidth, bm.bmHeight);
7140 DeleteObject(icon_info.hbmColor);
7141 DeleteObject(icon_info.hbmMask);
7143 /* Set bitmap with BS_BITMAP */
7144 hwnd = CreateWindowA("Button", "test", default_style | BS_BITMAP, 0, 0, 100, 100, 0, 0, 0, 0);
7145 ok(hwnd != NULL, "Expect hwnd not NULL\n");
7146 SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp1x1);
7147 hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_BITMAP, 0);
7148 ok(hbmp != 0, "Expect hbmp not 0\n");
7149 ZeroMemory(&bm, sizeof(bm));
7150 ok(GetObjectW(hbmp, sizeof(bm), &bm), "Expect GetObjectW() success\n");
7151 ok(bm.bmWidth == 1 && bm.bmHeight == 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
7152 bm.bmWidth, bm.bmHeight);
7153 DestroyWindow(hwnd);
7155 /* Set bitmap without BS_BITMAP */
7156 hwnd = CreateWindowA("Button", "test", default_style, 0, 0, 100, 100, 0, 0, 0, 0);
7157 ok(hwnd != NULL, "Expect hwnd not NULL\n");
7158 ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp1x1);
7159 ok(ret == 0, "Expect ret to be 0\n");
7160 hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_BITMAP, 0);
7161 ok(hbmp == NULL, "Expect hbmp to be NULL\n");
7162 DestroyWindow(hwnd);
7164 /* Set icon with BS_ICON */
7165 hwnd = CreateWindowA("Button", "test", default_style | BS_ICON, 0, 0, 100, 100, 0, 0, 0, 0);
7166 ok(hwnd != NULL, "Expect hwnd not NULL\n");
7167 SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicon2x2);
7168 hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_ICON, 0);
7169 ok(hicon != NULL, "Expect hicon not NULL\n");
7170 ZeroMemory(&icon_info, sizeof(icon_info));
7171 ok(GetIconInfo(hicon, &icon_info), "Expect GetIconInfo() success\n");
7172 ZeroMemory(&bm, sizeof(bm));
7173 ok(GetObjectW(icon_info.hbmColor, sizeof(bm), &bm), "Expect GetObjectW() success\n");
7174 ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
7175 bm.bmWidth, bm.bmHeight);
7176 DeleteObject(icon_info.hbmColor);
7177 DeleteObject(icon_info.hbmMask);
7178 DestroyWindow(hwnd);
7180 /* Set icon without BS_ICON */
7181 hwnd = CreateWindowA("Button", "test", default_style, 0, 0, 100, 100, 0, 0, 0, 0);
7182 ok(hwnd != NULL, "Expect hwnd not NULL\n");
7183 ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicon2x2);
7184 ok(ret == 0, "Expect ret to be 0\n");
7185 hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_ICON, 0);
7186 ok(hicon == NULL, "Expect hicon to be NULL\n");
7187 DestroyWindow(hwnd);
7189 /* Set icon with BS_BITMAP */
7190 hwnd = CreateWindowA("Button", "test", default_style | BS_BITMAP, 0, 0, 100, 100, 0, 0, 0, 0);
7191 ok(hwnd != NULL, "Expect hwnd to be not NULL\n");
7192 ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicon2x2);
7193 ok(ret == 0, "Expect ret to be 0\n");
7194 hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_ICON, 0);
7195 ok(hicon == NULL, "Expect hicon to be NULL\n");
7196 DestroyWindow(hwnd);
7198 /* Set bitmap with BS_ICON */
7199 hwnd = CreateWindowA("Button", "test", default_style | BS_ICON, 0, 0, 100, 100, 0, 0, 0, 0);
7200 ok(hwnd != NULL, "Expect hwnd to be not NULL\n");
7201 ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp1x1);
7202 ok(ret == 0, "Expect ret to be 0\n");
7203 hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_BITMAP, 0);
7204 ok(hbmp == NULL, "Expect hbmp to be NULL\n");
7205 DestroyWindow(hwnd);
7207 DestroyIcon(hicon2x2);
7208 DeleteObject(hmask2x2);
7209 DeleteObject(hbmp2x2);
7210 DeleteObject(hbmp1x1);
7211 ReleaseDC(0, hdc);
7214 #define ID_RADIO1 501
7215 #define ID_RADIO2 502
7216 #define ID_RADIO3 503
7217 #define ID_TEXT 504
7219 static const struct message auto_radio_button_BM_CLICK[] =
7221 { BM_CLICK, sent|wparam|lparam, 0, 0 },
7222 { WM_LBUTTONDOWN, sent|wparam|lparam|defwinproc, 0, 0 },
7223 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
7224 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO2 },
7225 { WM_CTLCOLORSTATIC, sent|parent },
7226 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
7227 { WM_LBUTTONUP, sent|wparam|lparam|defwinproc, 0, 0 },
7228 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO2 },
7229 { WM_CTLCOLORSTATIC, sent|parent },
7230 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
7231 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO2, 0 },
7232 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO2 },
7233 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO1, 0 },
7234 { BM_SETCHECK, sent|wparam|lparam|defwinproc, 0, ID_RADIO1 },
7235 { WM_CTLCOLORSTATIC, sent|parent },
7236 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
7237 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO3, 0 },
7238 { BM_SETCHECK, sent|wparam|lparam|defwinproc, 0, ID_RADIO3 },
7239 { WM_CTLCOLORSTATIC, sent|parent },
7240 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
7241 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_TEXT, 0 },
7242 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
7243 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
7244 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO2, BN_CLICKED) },
7245 { WM_NCHITTEST, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
7246 { WM_SETCURSOR, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
7247 { WM_MOUSEMOVE, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
7248 { 0 }
7251 static const struct message auto_radio_button_VK_UP_child[] =
7253 { WM_KEYDOWN, sent|wparam|lparam, VK_UP, 0 },
7254 { WM_KEYUP, sent|wparam|lparam, VK_UP, 0 },
7255 { 0 }
7258 static const struct message auto_radio_button_VK_UP_parent[] =
7260 { WM_KEYDOWN, sent|wparam|lparam|parent, VK_UP, 0 },
7261 { WM_KEYUP, sent|wparam|lparam|parent, VK_UP, 0 },
7262 { 0 }
7265 static const struct message auto_radio_button_VK_UP_dialog[] =
7267 { WM_GETDLGCODE, sent|parent, 0, 0 },
7269 /* optional trailer seen on some windows setups */
7270 { WM_CHANGEUISTATE, sent|optional },
7271 { WM_UPDATEUISTATE, sent|optional },
7272 { WM_UPDATEUISTATE, sent|optional },
7273 { WM_UPDATEUISTATE, sent|optional },
7274 { WM_UPDATEUISTATE, sent|optional },
7275 { WM_UPDATEUISTATE, sent|optional },
7276 { WM_UPDATEUISTATE, sent|optional },
7277 { WM_UPDATEUISTATE, sent|optional },
7278 { WM_UPDATEUISTATE, sent|optional },
7279 { WM_UPDATEUISTATE, sent|optional },
7280 { WM_UPDATEUISTATE, sent|optional },
7281 { WM_UPDATEUISTATE, sent|optional },
7282 { WM_UPDATEUISTATE, sent|optional },
7283 { WM_UPDATEUISTATE, sent|optional },
7284 { WM_UPDATEUISTATE, sent|optional },
7285 { WM_UPDATEUISTATE, sent|optional },
7286 { WM_UPDATEUISTATE, sent|optional },
7287 { WM_UPDATEUISTATE, sent|optional },
7288 { WM_UPDATEUISTATE, sent|optional },
7289 { WM_CTLCOLORSTATIC, sent|parent|optional },
7290 { WM_CTLCOLORSTATIC, sent|parent|optional },
7291 { WM_CTLCOLORSTATIC, sent|parent|optional },
7292 { WM_UPDATEUISTATE, sent|optional },
7293 { WM_CTLCOLORSTATIC, sent|parent|optional },
7294 { WM_CTLCOLORSTATIC, sent|parent|optional },
7295 { WM_UPDATEUISTATE, sent|optional },
7296 { WM_CTLCOLORBTN, sent|parent|optional },
7297 { WM_CTLCOLORBTN, sent|parent|optional },
7298 { WM_UPDATEUISTATE, sent|optional },
7299 { WM_CTLCOLORSTATIC, sent|parent|optional },
7300 { WM_CTLCOLORSTATIC, sent|parent|optional },
7301 { 0 }
7304 static const struct message auto_radio_button_VK_DOWN_dialog[] =
7306 { WM_GETDLGCODE, sent|parent, 0, 0 },
7307 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, MAKELPARAM(WM_KEYDOWN, VK_DOWN) },
7308 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
7309 { HCBT_SETFOCUS, hook },
7310 { WM_KILLFOCUS, sent, 0, 0 },
7311 { WM_CTLCOLORSTATIC, sent|parent },
7312 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO3, BN_KILLFOCUS) },
7313 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7314 { WM_SETFOCUS, sent, 0, 0 },
7315 { WM_CTLCOLORSTATIC, sent|parent },
7316 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_SETFOCUS) },
7317 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_CLICKED) },
7318 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
7319 { WM_GETDLGCODE, sent|parent, 0, 0 },
7320 { DM_GETDEFID, sent|parent, 0, 0 },
7321 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
7322 { BM_CLICK, sent|wparam|lparam, 1, 0 },
7323 { WM_LBUTTONDOWN, sent|wparam|lparam|defwinproc, 0, 0 },
7324 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
7325 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO1 },
7326 { WM_CTLCOLORSTATIC, sent|parent },
7327 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
7328 { WM_LBUTTONUP, sent|wparam|lparam|defwinproc, 0, 0 },
7329 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO1 },
7330 { WM_CTLCOLORSTATIC, sent|parent },
7331 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
7332 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO1, 0 },
7333 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO1 },
7334 { WM_CTLCOLORSTATIC, sent|parent },
7335 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
7336 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO3, 0 },
7337 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO3 },
7338 { WM_CTLCOLORSTATIC, sent|parent },
7339 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
7340 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_TEXT, 0 },
7341 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO2, 0 },
7342 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO2 },
7343 { WM_CTLCOLORSTATIC, sent|parent },
7344 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
7345 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
7346 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
7347 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_CLICKED) },
7348 { WM_NCHITTEST, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
7349 { WM_SETCURSOR, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
7350 { WM_MOUSEMOVE, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
7351 { WM_PAINT, sent },
7352 { WM_CTLCOLORSTATIC, sent|parent },
7353 { 0 }
7356 static const struct message auto_radio_button_VK_DOWN_radio3[] =
7358 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
7359 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO2 },
7360 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO3 },
7361 { WM_GETDLGCODE, sent|parent, 0, 0 },
7362 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, MAKELPARAM(WM_KEYDOWN, VK_DOWN) },
7363 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
7364 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
7365 { WM_GETDLGCODE, sent|wparam|lparam|parent, 0, 0 },
7366 { WM_USER, sent|parent, 0, 0 },
7367 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
7368 { 0 }
7371 static const struct message auto_radio_button_VK_UP_radio1[] =
7373 { WM_GETDLGCODE, sent|parent, 0, 0 },
7374 { 0 }
7377 static INT_PTR WINAPI radio_test_dlg_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
7379 ParentMsgCheckProcA(hwnd, msg, wp, lp);
7380 return 1;
7383 static void test_autoradio_BM_CLICK(void)
7385 HWND parent, radio1, radio2, radio3;
7386 RECT rc;
7387 MSG msg;
7388 DWORD ret;
7390 subclass_button();
7392 parent = CreateDialogParamA(0, "AUTORADIO_TEST_DIALOG_1", 0, radio_test_dlg_proc, 0);
7393 ok(parent != 0, "failed to create parent window\n");
7395 radio1 = GetDlgItem(parent, ID_RADIO1);
7396 radio2 = GetDlgItem(parent, ID_RADIO2);
7397 radio3 = GetDlgItem(parent, ID_RADIO3);
7399 /* this avoids focus messages in the generated sequence */
7400 SetFocus(radio2);
7402 flush_events();
7403 flush_sequence();
7405 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
7406 ok(ret == BST_UNCHECKED, "got %08lx\n", ret);
7407 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
7408 ok(ret == BST_UNCHECKED, "got %08lx\n", ret);
7409 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
7410 ok(ret == BST_UNCHECKED, "got %08lx\n", ret);
7412 SendMessageA(radio1, BM_SETCHECK, BST_CHECKED, 0);
7414 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
7415 ok(ret == BST_CHECKED, "got %08lx\n", ret);
7416 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
7417 ok(ret == BST_UNCHECKED, "got %08lx\n", ret);
7418 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
7419 ok(ret == BST_UNCHECKED, "got %08lx\n", ret);
7421 SendMessageA(radio2, BM_SETCHECK, BST_CHECKED, 0);
7423 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
7424 ok(ret == BST_CHECKED, "got %08lx\n", ret);
7425 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
7426 ok(ret == BST_CHECKED, "got %08lx\n", ret);
7427 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
7428 ok(ret == BST_UNCHECKED, "got %08lx\n", ret);
7430 SendMessageA(radio3, BM_SETCHECK, BST_CHECKED, 0);
7432 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
7433 ok(ret == BST_CHECKED, "got %08lx\n", ret);
7434 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
7435 ok(ret == BST_CHECKED, "got %08lx\n", ret);
7436 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
7437 ok(ret == BST_CHECKED, "got %08lx\n", ret);
7439 GetWindowRect(radio2, &rc);
7440 SetCursorPos(rc.left+1, rc.top+1);
7442 flush_events();
7443 flush_sequence();
7445 log_all_parent_messages++;
7447 SendMessageA(radio2, BM_CLICK, 0, 0);
7448 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7449 ok_sequence(auto_radio_button_BM_CLICK, "BM_CLICK on auto-radio button", FALSE);
7451 log_all_parent_messages--;
7453 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
7454 ok(ret == BST_UNCHECKED, "got %08lx\n", ret);
7455 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
7456 ok(ret == BST_CHECKED, "got %08lx\n", ret);
7457 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
7458 ok(ret == BST_UNCHECKED, "got %08lx\n", ret);
7460 DestroyWindow(parent);
7463 #define test_radio(r1, s1, r2, s2, r3, s3) test_radio_dbg(r1, s1, r2, s2, r3, s3, __LINE__)
7464 static void test_radio_dbg(HWND radio1, int state1, HWND radio2, int state2, HWND radio3, int state3, int line)
7466 DWORD ret;
7468 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
7469 ok_(__FILE__,line)(ret == state1 ? BST_CHECKED : BST_UNCHECKED, "got %08lx\n", ret);
7470 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
7471 ok_(__FILE__,line)(ret == state2 ? BST_CHECKED : BST_UNCHECKED, "got %08lx\n", ret);
7472 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
7473 ok_(__FILE__,line)(ret == state3 ? BST_CHECKED : BST_UNCHECKED, "got %08lx\n", ret);
7476 static void set_radio(HWND radio1, int state1, HWND radio2, int state2, HWND radio3, int state3)
7478 SendMessageA(radio1, BM_SETCHECK, state1 ? BST_CHECKED : BST_UNCHECKED, 0);
7479 SendMessageA(radio2, BM_SETCHECK, state2 ? BST_CHECKED : BST_UNCHECKED, 0);
7480 SendMessageA(radio3, BM_SETCHECK, state3 ? BST_CHECKED : BST_UNCHECKED, 0);
7483 static void test_autoradio_kbd_move(void)
7485 HWND parent, radio1, radio2, radio3, hwnd;
7486 RECT rc;
7487 MSG msg;
7488 DWORD ret;
7490 subclass_button();
7492 parent = CreateDialogParamA(0, "AUTORADIO_TEST_DIALOG_2", 0, radio_test_dlg_proc, 0);
7493 ok(parent != 0, "failed to create parent window\n");
7495 radio1 = GetDlgItem(parent, ID_RADIO1);
7496 radio2 = GetDlgItem(parent, ID_RADIO2);
7497 radio3 = GetDlgItem(parent, ID_RADIO3);
7499 flush_events();
7500 flush_sequence();
7502 test_radio(radio1, 0, radio2, 0, radio3, 0);
7503 set_radio(radio1, 1, radio2, 1, radio3, 1);
7504 test_radio(radio1, 1, radio2, 1, radio3, 1);
7506 SetFocus(radio3);
7508 flush_events();
7509 flush_sequence();
7511 log_all_parent_messages++;
7513 SendMessageA(radio3, WM_KEYDOWN, VK_UP, 0);
7514 SendMessageA(radio3, WM_KEYUP, VK_UP, 0);
7515 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7516 ok_sequence(auto_radio_button_VK_UP_child, "press/release VK_UP on auto-radio button", FALSE);
7518 test_radio(radio1, 1, radio2, 1, radio3, 1);
7520 flush_events();
7521 flush_sequence();
7523 DefDlgProcA(parent, WM_KEYDOWN, VK_UP, 0);
7524 DefDlgProcA(parent, WM_KEYUP, VK_UP, 0);
7525 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7526 ok_sequence(auto_radio_button_VK_UP_parent, "press/release VK_UP on dialog", FALSE);
7528 test_radio(radio1, 1, radio2, 1, radio3, 1);
7530 SetFocus(radio3);
7531 GetWindowRect(radio3, &rc);
7533 flush_events();
7534 flush_sequence();
7536 msg.hwnd = parent;
7537 msg.message = WM_KEYDOWN;
7538 msg.wParam = VK_UP;
7539 msg.lParam = 0;
7540 msg.pt.x = rc.left + 1;
7541 msg.pt.y = rc.top + 1;
7542 ret = IsDialogMessageA(parent, &msg);
7543 ok(ret, "IsDialogMessage should return TRUE\n");
7544 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7545 if (0) /* actual message sequence is different on every run in some Windows setups */
7546 ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #1", FALSE);
7547 /* what really matters is that nothing has changed */
7548 test_radio(radio1, 1, radio2, 1, radio3, 1);
7550 set_radio(radio1, 0, radio2, 1, radio3, 1);
7551 test_radio(radio1, 0, radio2, 1, radio3, 1);
7553 flush_events();
7554 flush_sequence();
7556 ret = IsDialogMessageA(parent, &msg);
7557 ok(ret, "IsDialogMessage should return TRUE\n");
7558 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7559 if (0) /* actual message sequence is different on every run in some Windows setups */
7560 ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #2", FALSE);
7561 /* what really matters is that nothing has changed */
7562 test_radio(radio1, 0, radio2, 1, radio3, 1);
7564 /* switch from radio3 ro radio1 */
7565 SetFocus(radio3);
7566 GetWindowRect(radio3, &rc);
7568 flush_events();
7569 flush_sequence();
7571 msg.hwnd = parent;
7572 msg.message = WM_KEYDOWN;
7573 msg.wParam = VK_DOWN;
7574 msg.lParam = 0;
7575 msg.pt.x = rc.left + 1;
7576 msg.pt.y = rc.top + 1;
7577 ret = IsDialogMessageA(parent, &msg);
7578 ok(ret, "IsDialogMessage should return TRUE\n");
7579 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7580 ok_sequence(auto_radio_button_VK_DOWN_dialog, "IsDialogMessage(VK_DOWN)", TRUE);
7582 test_radio(radio1, 1, radio2, 0, radio3, 0);
7584 hwnd = GetFocus();
7585 ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
7586 GetWindowRect(radio1, &rc);
7588 msg.hwnd = parent;
7589 msg.message = WM_KEYDOWN;
7590 msg.wParam = VK_DOWN;
7591 msg.lParam = 0;
7592 msg.pt.x = rc.left + 1;
7593 msg.pt.y = rc.top + 1;
7594 ret = IsDialogMessageA(parent, &msg);
7595 ok(ret, "IsDialogMessage should return TRUE\n");
7596 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7597 ok_sequence(auto_radio_button_VK_DOWN_radio3, "down to radio3", TRUE);
7599 test_radio(radio1, 1, radio2, 0, radio3, 0);
7601 hwnd = GetFocus();
7602 ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
7604 flush_events();
7605 flush_sequence();
7607 msg.hwnd = parent;
7608 msg.message = WM_KEYDOWN;
7609 msg.wParam = VK_UP;
7610 msg.lParam = 0;
7611 msg.pt.x = rc.left + 1;
7612 msg.pt.y = rc.top + 1;
7613 ret = IsDialogMessageA(parent, &msg);
7614 ok(ret, "IsDialogMessage should return TRUE\n");
7615 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7616 ok_sequence(auto_radio_button_VK_UP_radio1, "up to radio1", TRUE);
7618 test_radio(radio1, 1, radio2, 0, radio3, 0);
7620 hwnd = GetFocus();
7621 ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
7623 flush_events();
7624 flush_sequence();
7626 msg.hwnd = parent;
7627 msg.message = WM_KEYDOWN;
7628 msg.wParam = VK_UP;
7629 msg.lParam = 0;
7630 msg.pt.x = rc.left + 1;
7631 msg.pt.y = rc.top + 1;
7632 ret = IsDialogMessageA(parent, &msg);
7633 ok(ret, "IsDialogMessage should return TRUE\n");
7634 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7635 if (0) /* actual message sequence is different on every run in some Windows setups */
7636 ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #3", FALSE);
7637 /* what really matters is that nothing has changed */
7638 test_radio(radio1, 1, radio2, 0, radio3, 0);
7640 log_all_parent_messages--;
7642 DestroyWindow(parent);
7645 /****************** static message test *************************/
7646 static const struct message WmSetFontStaticSeq2[] =
7648 { WM_SETFONT, sent },
7649 { WM_PAINT, sent|defwinproc|optional },
7650 { WM_ERASEBKGND, sent|defwinproc|optional },
7651 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
7652 { 0 }
7655 static WNDPROC old_static_proc;
7657 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7659 static LONG defwndproc_counter = 0;
7660 LRESULT ret;
7661 struct recvd_message msg;
7663 if (ignore_message( message )) return 0;
7665 msg.hwnd = hwnd;
7666 msg.message = message;
7667 msg.flags = sent|wparam|lparam;
7668 if (defwndproc_counter) msg.flags |= defwinproc;
7669 msg.wParam = wParam;
7670 msg.lParam = lParam;
7671 msg.descr = "static";
7672 add_message(&msg);
7674 defwndproc_counter++;
7675 ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
7676 defwndproc_counter--;
7678 return ret;
7681 static void subclass_static(void)
7683 WNDCLASSA cls;
7684 BOOL ret;
7686 ret = GetClassInfoA(0, "static", &cls);
7687 ok(ret, "Failed to get class info, error %lu.\n", GetLastError());
7689 old_static_proc = cls.lpfnWndProc;
7691 cls.hInstance = GetModuleHandleA(NULL);
7692 cls.lpfnWndProc = static_hook_proc;
7693 cls.lpszClassName = "my_static_class";
7694 UnregisterClassA(cls.lpszClassName, cls.hInstance);
7695 register_class(&cls);
7698 static void test_static_messages(void)
7700 /* FIXME: make as comprehensive as the button message test */
7701 static const struct
7703 DWORD style;
7704 DWORD dlg_code;
7705 const struct message *setfont;
7706 } static_ctrl[] = {
7707 { SS_LEFT, DLGC_STATIC,
7708 WmSetFontStaticSeq2 }
7710 unsigned int i;
7711 HWND hwnd;
7712 DWORD dlg_code;
7714 subclass_static();
7716 for (i = 0; i < ARRAY_SIZE(static_ctrl); i++)
7718 hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
7719 0, 0, 50, 14, 0, 0, 0, NULL);
7720 ok(hwnd != 0, "Failed to create static window\n");
7722 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
7723 ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08lx\n", i, dlg_code);
7725 ShowWindow(hwnd, SW_SHOW);
7726 UpdateWindow(hwnd);
7727 SetFocus(0);
7728 flush_sequence();
7730 if (winetest_debug > 1) trace("static style %08lx\n", static_ctrl[i].style);
7731 SendMessageA(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
7732 ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
7734 DestroyWindow(hwnd);
7738 /****************** ComboBox message test *************************/
7739 #define ID_COMBOBOX 0x000f
7741 static const struct message SetCurSelComboSeq[] =
7743 { CB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7744 { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7745 { LB_SETTOPINDEX, sent|wparam|lparam, 0, 0 },
7746 { LB_GETCURSEL, sent|wparam|lparam, 0, 0 },
7747 { LB_GETTEXTLEN, sent|wparam|lparam, 0, 0 },
7748 { LB_GETTEXTLEN, sent|wparam|lparam|optional, 0, 0 }, /* TODO: it's sent on all Windows versions */
7749 { LB_GETTEXT, sent|wparam, 0 },
7750 { WM_CTLCOLOREDIT, sent|parent },
7751 { LB_GETITEMDATA, sent|wparam|lparam, 0, 0 },
7752 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_COMBOBOX, 0x100010f3 },
7753 { 0 }
7756 static const struct message SetCurSelComboSeq2[] =
7758 { CB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7759 { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7760 { LB_SETTOPINDEX, sent|wparam|lparam, 0, 0 },
7761 { LB_GETCURSEL, sent|wparam|lparam, 0, 0 },
7762 { LB_GETTEXTLEN, sent|wparam|lparam, 0, 0 },
7763 { LB_GETTEXTLEN, sent|wparam|lparam|optional, 0, 0 }, /* TODO: it's sent on all Windows versions */
7764 { LB_GETTEXT, sent|wparam, 0 },
7765 { 0 }
7768 static const struct message SetCurSelComboSeq_edit[] =
7770 { CB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7771 { WM_SETTEXT, sent|wparam, 0 },
7772 { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
7773 { 0 }
7776 static const struct message WmKeyDownComboSeq[] =
7778 { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
7779 { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
7780 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
7781 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
7782 { WM_CTLCOLOREDIT, sent|parent },
7783 { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
7784 { 0 }
7787 static const struct message WmSetPosComboSeq[] =
7789 { WM_WINDOWPOSCHANGING, sent },
7790 { WM_NCCALCSIZE, sent|wparam, TRUE },
7791 { WM_CHILDACTIVATE, sent },
7792 { WM_WINDOWPOSCHANGED, sent },
7793 { WM_MOVE, sent|defwinproc },
7794 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
7795 { WM_WINDOWPOSCHANGING, sent|defwinproc },
7796 { WM_NCCALCSIZE, sent|defwinproc|wparam, TRUE },
7797 { WM_WINDOWPOSCHANGED, sent|defwinproc },
7798 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
7799 { 0 }
7802 static const struct message WMSetFocusComboBoxSeq[] =
7804 { WM_SETFOCUS, sent },
7805 { WM_KILLFOCUS, sent|parent },
7806 { WM_SETFOCUS, sent },
7807 { WM_COMMAND, sent|defwinproc|wparam, MAKEWPARAM(1001, EN_SETFOCUS) },
7808 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, INT_MAX },
7809 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7810 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7811 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SETFOCUS) },
7812 { 0 }
7815 static const struct message SetFocusButtonSeq[] =
7817 { WM_KILLFOCUS, sent },
7818 { CB_GETCOMBOBOXINFO, sent|optional },/* Windows 2000 */
7819 { 0x0167, sent|optional },/* Undocumented message. Sent on all versions except Windows 2000 */
7820 { WM_LBUTTONUP, sent|defwinproc },
7821 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDCANCEL) },
7822 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, 0 },
7823 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7824 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7825 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_KILLFOCUS) },
7826 { WM_CTLCOLORBTN, sent|parent },
7827 { 0 }
7830 static const struct message SetFocusComboBoxSeq[] =
7832 { WM_CTLCOLORBTN, sent|parent },
7833 { WM_SETFOCUS, sent },
7834 { WM_KILLFOCUS, sent|defwinproc },
7835 { WM_SETFOCUS, sent },
7836 { WM_COMMAND, sent|defwinproc|wparam, MAKEWPARAM(1001, EN_SETFOCUS) },
7837 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, INT_MAX },
7838 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7839 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7840 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SETFOCUS) },
7841 { 0 }
7844 static const struct message SetFocusButtonSeq2[] =
7846 { WM_KILLFOCUS, sent },
7847 { CB_GETCOMBOBOXINFO, sent|optional },/* Windows 2000 */
7848 { 0x0167, sent|optional },/* Undocumented message. Sent on all versions except Windows 2000 */
7849 { WM_LBUTTONUP, sent|defwinproc },
7850 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDCANCEL) },
7851 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, 0 },
7852 { WM_CTLCOLOREDIT, sent|defwinproc },
7853 { WM_CTLCOLOREDIT, sent|parent },
7854 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_KILLFOCUS) },
7855 { WM_CTLCOLORBTN, sent|parent },
7856 { 0 }
7859 static WNDPROC old_combobox_proc, edit_window_proc, lbox_window_proc;
7861 static LRESULT CALLBACK combobox_edit_subclass_proc(HWND hwnd, UINT message,
7862 WPARAM wParam, LPARAM lParam)
7864 static LONG defwndproc_counter = 0;
7865 LRESULT ret;
7866 struct recvd_message msg;
7868 /* do not log painting messages */
7869 if (message != WM_PAINT &&
7870 message != WM_NCPAINT &&
7871 message != WM_SYNCPAINT &&
7872 message != WM_ERASEBKGND &&
7873 message != WM_NCHITTEST &&
7874 message != WM_GETTEXT &&
7875 !ignore_message( message ))
7877 msg.hwnd = hwnd;
7878 msg.message = message;
7879 msg.flags = sent|wparam|lparam;
7880 if (defwndproc_counter) msg.flags |= defwinproc;
7881 msg.wParam = wParam;
7882 msg.lParam = lParam;
7883 msg.descr = "combo edit";
7884 add_message(&msg);
7887 defwndproc_counter++;
7888 ret = CallWindowProcA(edit_window_proc, hwnd, message, wParam, lParam);
7889 defwndproc_counter--;
7891 return ret;
7894 static LRESULT CALLBACK combobox_lbox_subclass_proc(HWND hwnd, UINT message,
7895 WPARAM wParam, LPARAM lParam)
7897 static LONG defwndproc_counter = 0;
7898 LRESULT ret;
7899 struct recvd_message msg;
7901 /* do not log painting messages */
7902 if (message != WM_PAINT &&
7903 message != WM_NCPAINT &&
7904 message != WM_SYNCPAINT &&
7905 message != WM_ERASEBKGND &&
7906 message != WM_NCHITTEST &&
7907 !ignore_message( message ))
7909 msg.hwnd = hwnd;
7910 msg.message = message;
7911 msg.flags = sent|wparam|lparam;
7912 if (defwndproc_counter) msg.flags |= defwinproc;
7913 msg.wParam = wParam;
7914 msg.lParam = lParam;
7915 msg.descr = "combo lbox";
7916 add_message(&msg);
7919 defwndproc_counter++;
7920 ret = CallWindowProcA(lbox_window_proc, hwnd, message, wParam, lParam);
7921 defwndproc_counter--;
7923 return ret;
7926 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7928 static LONG defwndproc_counter = 0;
7929 LRESULT ret;
7930 struct recvd_message msg;
7932 /* do not log painting messages */
7933 if (message != WM_PAINT &&
7934 message != WM_NCPAINT &&
7935 message != WM_SYNCPAINT &&
7936 message != WM_ERASEBKGND &&
7937 message != WM_NCHITTEST &&
7938 message != WM_GETTEXT &&
7939 !ignore_message( message ))
7941 msg.hwnd = hwnd;
7942 msg.message = message;
7943 msg.flags = sent|wparam|lparam;
7944 if (defwndproc_counter) msg.flags |= defwinproc;
7945 msg.wParam = wParam;
7946 msg.lParam = lParam;
7947 msg.descr = "combo";
7948 add_message(&msg);
7951 defwndproc_counter++;
7952 ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
7953 defwndproc_counter--;
7955 return ret;
7958 static void subclass_combobox(void)
7960 WNDCLASSA cls;
7961 BOOL ret;
7963 ret = GetClassInfoA(0, "ComboBox", &cls);
7964 ok(ret, "Failed to get class info, error %lu.\n", GetLastError());
7966 old_combobox_proc = cls.lpfnWndProc;
7968 cls.hInstance = GetModuleHandleA(NULL);
7969 cls.lpfnWndProc = combobox_hook_proc;
7970 cls.lpszClassName = "my_combobox_class";
7971 UnregisterClassA(cls.lpszClassName, cls.hInstance);
7972 register_class(&cls);
7975 static void test_combobox_messages(void)
7977 HWND parent, combo, button, edit, lbox;
7978 LRESULT ret;
7979 COMBOBOXINFO cbInfo;
7980 BOOL res;
7982 subclass_combobox();
7984 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7985 100, 100, 200, 200, 0, 0, 0, NULL);
7986 ok(parent != 0, "Failed to create parent window\n");
7987 flush_sequence();
7989 combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
7990 0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
7991 ok(combo != 0, "Failed to create combobox window\n");
7993 UpdateWindow(combo);
7995 ret = SendMessageA(combo, WM_GETDLGCODE, 0, 0);
7996 ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08Ix\n", ret);
7998 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
7999 ok(ret == 0, "expected 0, got %Id\n", ret);
8000 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
8001 ok(ret == 1, "expected 1, got %Id\n", ret);
8002 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
8003 ok(ret == 2, "expected 2, got %Id\n", ret);
8005 SendMessageA(combo, CB_SETCURSEL, 0, 0);
8006 SetFocus(combo);
8007 flush_sequence();
8009 log_all_parent_messages++;
8010 SendMessageA(combo, WM_KEYDOWN, VK_DOWN, 0);
8011 SendMessageA(combo, WM_KEYUP, VK_DOWN, 0);
8012 log_all_parent_messages--;
8013 ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
8015 flush_sequence();
8016 SetWindowPos(combo, 0, 10, 10, 120, 130, SWP_NOZORDER);
8017 ok_sequence(WmSetPosComboSeq, "repositioning messages on a ComboBox", FALSE);
8019 DestroyWindow(combo);
8020 DestroyWindow(parent);
8022 /* Start again. Test combobox text selection when getting and losing focus */
8023 parent = CreateWindowExA(0, "TestParentClass", "Parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8024 10, 10, 300, 300, NULL, NULL, NULL, NULL);
8025 ok(parent != 0, "Failed to create parent window\n");
8027 combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWN,
8028 5, 5, 100, 100, parent, (HMENU)ID_COMBOBOX, NULL, NULL);
8029 ok(combo != 0, "Failed to create combobox window\n");
8031 cbInfo.cbSize = sizeof(COMBOBOXINFO);
8032 SetLastError(0xdeadbeef);
8033 res = GetComboBoxInfo(combo, &cbInfo);
8034 ok(res, "Failed to get COMBOBOXINFO structure; LastError: %lu\n", GetLastError());
8035 edit = cbInfo.hwndItem;
8037 edit_window_proc = (WNDPROC)SetWindowLongPtrA(edit, GWLP_WNDPROC,
8038 (ULONG_PTR)combobox_edit_subclass_proc);
8040 button = CreateWindowExA(0, "Button", "OK", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
8041 5, 50, 100, 20, parent, NULL,
8042 (HINSTANCE)GetWindowLongPtrA(parent, GWLP_HINSTANCE), NULL);
8043 ok(button != 0, "Failed to create button window\n");
8045 flush_sequence();
8046 log_all_parent_messages++;
8047 SendMessageA(combo, WM_SETFOCUS, 0, (LPARAM)edit);
8048 log_all_parent_messages--;
8049 ok_sequence(WMSetFocusComboBoxSeq, "WM_SETFOCUS on a ComboBox", TRUE);
8051 flush_sequence();
8052 log_all_parent_messages++;
8053 SetFocus(button);
8054 log_all_parent_messages--;
8055 ok_sequence(SetFocusButtonSeq, "SetFocus on a Button", TRUE);
8057 SendMessageA(combo, WM_SETTEXT, 0, (LPARAM)"Wine Test");
8059 flush_sequence();
8060 log_all_parent_messages++;
8061 SetFocus(combo);
8062 log_all_parent_messages--;
8063 ok_sequence(SetFocusComboBoxSeq, "SetFocus on a ComboBox", TRUE);
8065 flush_sequence();
8066 log_all_parent_messages++;
8067 SetFocus(button);
8068 log_all_parent_messages--;
8069 ok_sequence(SetFocusButtonSeq2, "SetFocus on a Button (2)", TRUE);
8071 SetFocus(combo);
8072 SendMessageA(combo, WM_SETREDRAW, FALSE, 0);
8073 flush_sequence();
8074 log_all_parent_messages++;
8075 SendMessageA(combo, CB_SETCURSEL, 0, 0);
8076 log_all_parent_messages--;
8077 ok_sequence(SetCurSelComboSeq_edit, "CB_SETCURSEL on a ComboBox with edit control", FALSE);
8079 DestroyWindow(button);
8080 DestroyWindow(combo);
8082 combo = CreateWindowExA(0, "my_combobox_class", "test",
8083 WS_CHILD | WS_VISIBLE | CBS_OWNERDRAWFIXED | CBS_DROPDOWNLIST,
8084 5, 5, 100, 100, parent, (HMENU)ID_COMBOBOX, NULL, NULL);
8085 ok(combo != 0, "Failed to create combobox window\n");
8087 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
8088 ok(ret == 0, "expected 0, got %Id\n", ret);
8090 cbInfo.cbSize = sizeof(COMBOBOXINFO);
8091 SetLastError(0xdeadbeef);
8092 res = GetComboBoxInfo(combo, &cbInfo);
8093 ok(res, "Failed to get COMBOBOXINFO structure; LastError: %lu\n", GetLastError());
8094 lbox = cbInfo.hwndList;
8095 lbox_window_proc = (WNDPROC)SetWindowLongPtrA(lbox, GWLP_WNDPROC,
8096 (ULONG_PTR)combobox_lbox_subclass_proc);
8097 flush_sequence();
8099 log_all_parent_messages++;
8100 SendMessageA(combo, CB_SETCURSEL, 0, 0);
8101 log_all_parent_messages--;
8102 ok_sequence(SetCurSelComboSeq, "CB_SETCURSEL on a ComboBox", FALSE);
8104 ShowWindow(combo, SW_HIDE);
8105 flush_sequence();
8106 log_all_parent_messages++;
8107 SendMessageA(combo, CB_SETCURSEL, 0, 0);
8108 log_all_parent_messages--;
8109 ok_sequence(SetCurSelComboSeq2, "CB_SETCURSEL on a ComboBox", FALSE);
8111 DestroyWindow(combo);
8112 DestroyWindow(parent);
8115 /****************** WM_IME_KEYDOWN message test *******************/
8117 static const struct message WmImeKeydownMsgSeq_0[] =
8119 { WM_IME_KEYDOWN, wparam, VK_RETURN },
8120 { WM_CHAR, wparam, 'A' },
8121 { 0 }
8124 static const struct message WmImeKeydownMsgSeq_1[] =
8126 { WM_KEYDOWN, optional|wparam, VK_RETURN },
8127 { WM_CHAR, optional|wparam, VK_RETURN },
8128 { 0 }
8131 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8133 struct recvd_message msg;
8135 msg.hwnd = hwnd;
8136 msg.message = message;
8137 msg.flags = wparam|lparam;
8138 msg.wParam = wParam;
8139 msg.lParam = lParam;
8140 msg.descr = "wmime_keydown";
8141 add_message(&msg);
8143 return DefWindowProcA(hwnd, message, wParam, lParam);
8146 static void register_wmime_keydown_class(void)
8148 WNDCLASSA cls;
8150 ZeroMemory(&cls, sizeof(WNDCLASSA));
8151 cls.lpfnWndProc = wmime_keydown_procA;
8152 cls.hInstance = GetModuleHandleA(0);
8153 cls.lpszClassName = "wmime_keydown_class";
8154 register_class(&cls);
8157 static void test_wmime_keydown_message(void)
8159 HWND hwnd;
8160 MSG msg;
8162 if (winetest_debug > 1) trace("Message sequences by WM_IME_KEYDOWN\n");
8164 register_wmime_keydown_class();
8165 hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
8166 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
8167 NULL, NULL, 0);
8168 flush_events();
8169 flush_sequence();
8171 SendMessageA(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
8172 SendMessageA(hwnd, WM_CHAR, 'A', 1);
8173 ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
8175 while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
8177 TranslateMessage(&msg);
8178 DispatchMessageA(&msg);
8180 ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
8182 DestroyWindow(hwnd);
8185 /************* painting message test ********************/
8187 void dump_region(HRGN hrgn)
8189 DWORD i, size;
8190 RGNDATA *data = NULL;
8191 RECT *rect;
8193 if (!hrgn)
8195 printf( "null region\n" );
8196 return;
8198 if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
8199 if (!(data = malloc( size ))) return;
8200 GetRegionData( hrgn, size, data );
8201 printf("%ld rects:", data->rdh.nCount );
8202 for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
8203 printf( " %s", wine_dbgstr_rect( rect ));
8204 printf("\n");
8205 free( data );
8208 #define check_update_rgn( hwnd, hrgn ) check_update_rgn_( __LINE__, hwnd, hrgn )
8209 static void check_update_rgn_( int line, HWND hwnd, HRGN hrgn )
8211 INT ret;
8212 RECT r1, r2;
8213 HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
8214 HRGN update = CreateRectRgn( 0, 0, 0, 0 );
8216 ret = GetUpdateRgn( hwnd, update, FALSE );
8217 ok( ret != ERROR, "GetUpdateRgn failed\n" );
8218 if (ret == NULLREGION)
8220 ok_(__FILE__,line)( !hrgn, "Update region shouldn't be empty\n" );
8222 else
8224 if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
8226 ok_(__FILE__,line)( 0, "Regions are different\n" );
8227 if (winetest_debug > 0)
8229 printf( "Update region: " );
8230 dump_region( update );
8231 printf( "Wanted region: " );
8232 dump_region( hrgn );
8236 GetRgnBox( update, &r1 );
8237 GetUpdateRect( hwnd, &r2, FALSE );
8238 ok_(__FILE__,line)( EqualRect( &r1, &r2 ), "Rectangles are different: %s / %s\n",
8239 wine_dbgstr_rect( &r1 ), wine_dbgstr_rect( &r2 ));
8241 DeleteObject( tmp );
8242 DeleteObject( update );
8245 static const struct message WmInvalidateRgn[] = {
8246 { WM_NCPAINT, sent },
8247 { WM_GETTEXT, sent|defwinproc|optional },
8248 { 0 }
8251 static const struct message WmGetUpdateRect[] = {
8252 { WM_NCPAINT, sent },
8253 { WM_GETTEXT, sent|defwinproc|optional },
8254 { WM_PAINT, sent },
8255 { 0 }
8258 static const struct message WmInvalidateFull[] = {
8259 { WM_NCPAINT, sent|wparam, 1 },
8260 { WM_GETTEXT, sent|defwinproc|optional },
8261 { 0 }
8264 static const struct message WmInvalidateErase[] = {
8265 { WM_NCPAINT, sent|wparam, 1 },
8266 { WM_GETTEXT, sent|defwinproc|optional },
8267 { WM_ERASEBKGND, sent },
8268 { 0 }
8271 static const struct message WmInvalidatePaint[] = {
8272 { WM_PAINT, sent },
8273 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
8274 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8275 { 0 }
8278 static const struct message WmInvalidateErasePaint[] = {
8279 { WM_PAINT, sent },
8280 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
8281 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8282 { WM_ERASEBKGND, sent|beginpaint|optional },
8283 { 0 }
8286 static const struct message WmInvalidateErasePaint2[] = {
8287 { WM_PAINT, sent },
8288 { WM_NCPAINT, sent|beginpaint },
8289 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8290 { WM_ERASEBKGND, sent|beginpaint|optional },
8291 { 0 }
8294 static const struct message WmErase[] = {
8295 { WM_ERASEBKGND, sent },
8296 { 0 }
8299 static const struct message WmPaint[] = {
8300 { WM_PAINT, sent },
8301 { 0 }
8304 static const struct message WmParentOnlyPaint[] = {
8305 { WM_PAINT, sent|parent },
8306 { 0 }
8309 static const struct message WmInvalidateParent[] = {
8310 { WM_NCPAINT, sent|parent },
8311 { WM_GETTEXT, sent|defwinproc|parent|optional },
8312 { WM_ERASEBKGND, sent|parent },
8313 { 0 }
8316 static const struct message WmInvalidateParentChild[] = {
8317 { WM_NCPAINT, sent|parent },
8318 { WM_GETTEXT, sent|defwinproc|parent|optional },
8319 { WM_ERASEBKGND, sent|parent },
8320 { WM_NCPAINT, sent },
8321 { WM_GETTEXT, sent|defwinproc|optional },
8322 { WM_ERASEBKGND, sent },
8323 { 0 }
8326 static const struct message WmInvalidateParentChild2[] = {
8327 { WM_ERASEBKGND, sent|parent },
8328 { WM_NCPAINT, sent },
8329 { WM_GETTEXT, sent|defwinproc|optional },
8330 { WM_ERASEBKGND, sent },
8331 { 0 }
8334 static const struct message WmParentPaint[] = {
8335 { WM_PAINT, sent|parent },
8336 { WM_PAINT, sent },
8337 { 0 }
8340 static const struct message WmParentPaintNc[] = {
8341 { WM_PAINT, sent|parent },
8342 { WM_PAINT, sent },
8343 { WM_NCPAINT, sent|beginpaint },
8344 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8345 { WM_ERASEBKGND, sent|beginpaint|optional },
8346 { WM_GETMINMAXINFO, sent|optional },
8347 { 0 }
8350 static const struct message WmChildPaintNc[] = {
8351 { WM_PAINT, sent },
8352 { WM_NCPAINT, sent|beginpaint },
8353 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8354 { WM_ERASEBKGND, sent|beginpaint|optional },
8355 { 0 }
8358 static const struct message WmParentErasePaint[] = {
8359 { WM_PAINT, sent|parent },
8360 { WM_NCPAINT, sent|parent|beginpaint },
8361 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
8362 { WM_ERASEBKGND, sent|parent|beginpaint|optional },
8363 { WM_PAINT, sent },
8364 { WM_NCPAINT, sent|beginpaint },
8365 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8366 { WM_ERASEBKGND, sent|beginpaint|optional },
8367 { 0 }
8370 static const struct message WmParentOnlyNcPaint[] = {
8371 { WM_PAINT, sent|parent },
8372 { WM_NCPAINT, sent|parent|beginpaint },
8373 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
8374 { 0 }
8377 static const struct message WmSetParentStyle[] = {
8378 { WM_STYLECHANGING, sent|parent },
8379 { WM_STYLECHANGED, sent|parent },
8380 { 0 }
8383 static void test_paint_messages(void)
8385 BOOL ret;
8386 RECT rect, rect2;
8387 DWORD style;
8388 POINT pt;
8389 MSG msg;
8390 HWND hparent, hchild;
8391 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
8392 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
8393 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
8394 100, 100, 200, 200, 0, 0, 0, NULL);
8395 ok (hwnd != 0, "Failed to create overlapped window\n");
8397 ShowWindow( hwnd, SW_SHOW );
8398 UpdateWindow( hwnd );
8399 flush_events();
8400 flush_sequence();
8402 check_update_rgn( hwnd, 0 );
8403 SetRectRgn( hrgn, 10, 10, 20, 20 );
8404 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
8405 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8406 check_update_rgn( hwnd, hrgn );
8407 SetRectRgn( hrgn2, 20, 20, 30, 30 );
8408 ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
8409 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8410 CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
8411 check_update_rgn( hwnd, hrgn );
8412 /* validate everything */
8413 ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8414 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8415 check_update_rgn( hwnd, 0 );
8417 /* test empty region */
8418 SetRectRgn( hrgn, 10, 10, 10, 15 );
8419 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
8420 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8421 check_update_rgn( hwnd, 0 );
8422 /* test empty rect */
8423 SetRect( &rect, 10, 10, 10, 15 );
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 /* test a zeroed rectangle */
8429 RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
8430 SetRect( &rect, 0, 0, 0, 0 );
8431 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
8432 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8433 check_update_rgn( hwnd, 0 );
8435 /* a well ordered rectangle */
8436 RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
8437 SetRect( &rect, 10, 5, 17, 21 );
8438 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
8439 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8440 SetRectRgn( hrgn, 10, 5, 17, 21 );
8441 check_update_rgn( hwnd, hrgn );
8443 /* empty rectangle, top and bottom are swapped but left and right have
8444 the same value */
8445 RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
8446 SetRect( &rect, 5, 30, 5, 10 );
8447 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
8448 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8449 check_update_rgn( hwnd, 0 );
8451 /* empty rectangle, left and right are swapped but top and bottom have
8452 the same value */
8453 RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
8454 SetRect( &rect, 17, 10, 5, 10 );
8455 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
8456 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8457 check_update_rgn( hwnd, 0 );
8459 /* Left and right are swapped */
8460 RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
8461 SetRect( &rect, 21, 12, 7, 30 );
8462 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
8463 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8464 SetRectRgn( hrgn, 7, 12, 21, 30 );
8465 check_update_rgn( hwnd, hrgn );
8467 /* Top and bottom are swapped */
8468 RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
8469 SetRect( &rect, 7, 30, 21, 12 );
8470 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
8471 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8472 SetRectRgn( hrgn, 7, 12, 21, 30 );
8473 check_update_rgn( hwnd, hrgn );
8475 /* both reference points are swapped */
8476 RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
8477 SetRect( &rect, 21, 30, 7, 12 );
8478 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
8479 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8480 SetRectRgn( hrgn, 7, 12, 21, 30 );
8481 check_update_rgn( hwnd, hrgn );
8483 /* flush pending messages */
8484 flush_events();
8485 flush_sequence();
8487 GetClientRect( hwnd, &rect );
8488 SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
8489 /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
8490 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
8492 SetRectEmpty( &rect );
8493 ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) failed\n");
8494 check_update_rgn( hwnd, hrgn );
8495 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8496 flush_events();
8497 ok_sequence( WmPaint, "Paint", FALSE );
8498 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8499 check_update_rgn( hwnd, 0 );
8501 SetRectEmpty( &rect );
8502 ok(RedrawWindow(0, &rect, 0, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
8503 "RedrawWindow failed\n");
8504 check_update_rgn( hwnd, 0 );
8506 SetRectEmpty( &rect );
8507 ok(RedrawWindow(0, &rect, 0, RDW_ALLCHILDREN | RDW_VALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
8508 "RedrawWindow failed\n");
8509 check_update_rgn( hwnd, 0 );
8511 GetWindowRect( hwnd, &rect );
8512 ok(RedrawWindow(0, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
8513 "RedrawWindow failed\n");
8514 check_update_rgn( hwnd, 0 );
8516 flush_events();
8517 ok(RedrawWindow(0, &rect, 0, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
8518 "RedrawWindow failed\n");
8519 check_update_rgn( hwnd, hrgn );
8520 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8521 flush_events();
8522 ok_sequence( WmPaint, "Paint", FALSE );
8523 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8524 check_update_rgn( hwnd, 0 );
8526 ok(RedrawWindow(GetDesktopWindow(), &rect, 0,
8527 RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
8528 "RedrawWindow failed\n");
8529 ret = GetUpdateRgn( hwnd, hrgn2, FALSE );
8530 ok( ret == NULLREGION || broken(ret == SIMPLEREGION), /* <= win7 */
8531 "region should be null (%d)\n", ret );
8532 if (ret == SIMPLEREGION) ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8533 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8534 flush_events();
8536 ok(RedrawWindow(GetDesktopWindow(), NULL, 0,
8537 RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
8538 "RedrawWindow failed\n");
8539 ret = GetUpdateRgn( hwnd, hrgn2, FALSE );
8540 ok( ret == NULLREGION || broken(ret == SIMPLEREGION), /* <= win7 */
8541 "region should be null (%d)\n", ret );
8542 if (ret == SIMPLEREGION) ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8543 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8544 flush_events();
8546 SetRectRgn( hrgn2, rect.left, rect.top, rect.right, rect.bottom );
8547 ok(RedrawWindow(0, NULL, hrgn2, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
8548 "RedrawWindow failed\n");
8549 check_update_rgn( hwnd, hrgn );
8550 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8551 flush_events();
8552 ok_sequence( WmPaint, "Paint", FALSE );
8553 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8554 check_update_rgn( hwnd, 0 );
8556 ok(RedrawWindow(0, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW ),
8557 "RedrawWindow failed\n");
8558 check_update_rgn( hwnd, 0 );
8560 ok(RedrawWindow(0, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW ),
8561 "RedrawWindow failed\n");
8562 check_update_rgn( hwnd, hrgn );
8563 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8564 flush_events();
8565 ok_sequence( WmPaint, "Paint", FALSE );
8566 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8567 check_update_rgn( hwnd, 0 );
8569 /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
8570 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
8572 SetRectEmpty( &rect );
8573 if (ValidateRect(0, &rect) && /* not supported on Win9x */
8574 GetUpdateRect(hwnd, NULL, FALSE)) /* or >= Win 8 */
8576 check_update_rgn( hwnd, hrgn );
8577 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8578 flush_events();
8579 ok_sequence( WmPaint, "Paint", FALSE );
8580 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8581 check_update_rgn( hwnd, 0 );
8584 SetLastError(0xdeadbeef);
8585 ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
8586 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
8587 "wrong error code %ld\n", GetLastError());
8588 check_update_rgn( hwnd, 0 );
8589 flush_events();
8590 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8592 SetLastError(0xdeadbeef);
8593 ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
8594 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
8595 broken( GetLastError() == 0xdeadbeef ) /* win9x */,
8596 "wrong error code %ld\n", GetLastError());
8597 check_update_rgn( hwnd, 0 );
8598 flush_events();
8599 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8601 SetLastError(0xdeadbeef);
8602 ok(!UpdateWindow(NULL), "UpdateWindow(NULL) should fail\n");
8603 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
8604 broken( GetLastError() == 0xdeadbeef ) /* win9x */,
8605 "wrong error code %ld\n", GetLastError());
8606 check_update_rgn( hwnd, 0 );
8607 flush_events();
8608 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8610 /* now with frame */
8611 SetRectRgn( hrgn, -5, -5, 20, 20 );
8613 /* flush pending messages */
8614 flush_events();
8615 flush_sequence();
8616 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8617 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
8619 SetRectRgn( hrgn, 0, 0, 20, 20 ); /* GetUpdateRgn clips to client area */
8620 check_update_rgn( hwnd, hrgn );
8622 flush_sequence();
8623 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
8624 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
8626 flush_sequence();
8627 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
8628 ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
8630 GetClientRect( hwnd, &rect );
8631 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8632 check_update_rgn( hwnd, hrgn );
8634 flush_sequence();
8635 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
8636 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8638 flush_sequence();
8639 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
8640 ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
8641 check_update_rgn( hwnd, 0 );
8643 flush_sequence();
8644 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
8645 ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
8646 check_update_rgn( hwnd, 0 );
8648 flush_sequence();
8649 SetRectRgn( hrgn, 0, 0, 100, 100 );
8650 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
8651 SetRectRgn( hrgn, 0, 0, 50, 100 );
8652 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
8653 SetRectRgn( hrgn, 50, 0, 100, 100 );
8654 check_update_rgn( hwnd, hrgn );
8655 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
8656 ok_sequence( WmEmptySeq, "EmptySeq", FALSE ); /* must not generate messages, everything is valid */
8657 check_update_rgn( hwnd, 0 );
8659 flush_sequence();
8660 SetRectRgn( hrgn, 0, 0, 100, 100 );
8661 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
8662 SetRectRgn( hrgn, 0, 0, 100, 50 );
8663 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
8664 ok_sequence( WmErase, "Erase", FALSE );
8665 SetRectRgn( hrgn, 0, 50, 100, 100 );
8666 check_update_rgn( hwnd, hrgn );
8668 flush_sequence();
8669 SetRectRgn( hrgn, 0, 0, 100, 100 );
8670 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
8671 SetRectRgn( hrgn, 0, 0, 50, 50 );
8672 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
8673 ok_sequence( WmPaint, "Paint", FALSE );
8675 flush_sequence();
8676 SetRectRgn( hrgn, -4, -4, -2, -2 );
8677 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8678 SetRectRgn( hrgn, -200, -200, -198, -198 );
8679 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
8680 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
8682 flush_sequence();
8683 SetRectRgn( hrgn, -4, -4, -2, -2 );
8684 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8685 SetRectRgn( hrgn, -4, -4, -3, -3 );
8686 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
8687 SetRectRgn( hrgn, 0, 0, 1, 1 );
8688 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
8689 ok_sequence( WmPaint, "Paint", FALSE );
8691 flush_sequence();
8692 SetRectRgn( hrgn, -4, -4, -1, -1 );
8693 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8694 RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
8695 /* make sure no WM_PAINT was generated */
8696 flush_events();
8697 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
8699 flush_sequence();
8700 SetRectRgn( hrgn, -4, -4, -1, -1 );
8701 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8702 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
8704 if (msg.hwnd == hwnd && msg.message == WM_PAINT)
8706 /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
8707 INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
8708 ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
8709 ret = GetUpdateRect( hwnd, &rect, FALSE );
8710 ok( ret, "Invalid GetUpdateRect result %d\n", ret );
8711 /* this will send WM_NCPAINT and validate the non client area */
8712 ret = GetUpdateRect( hwnd, &rect, TRUE );
8713 ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
8715 DispatchMessageA( &msg );
8717 ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
8719 DestroyWindow( hwnd );
8721 /* now test with a child window */
8723 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
8724 100, 100, 200, 200, 0, 0, 0, NULL);
8725 ok (hparent != 0, "Failed to create parent window\n");
8727 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
8728 10, 10, 100, 100, hparent, 0, 0, NULL);
8729 ok (hchild != 0, "Failed to create child window\n");
8731 ShowWindow( hparent, SW_SHOW );
8732 UpdateWindow( hparent );
8733 UpdateWindow( hchild );
8734 flush_events();
8735 flush_sequence();
8736 log_all_parent_messages++;
8738 SetRect( &rect, 0, 0, 50, 50 );
8739 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8740 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
8741 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
8743 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8744 pt.x = pt.y = 0;
8745 MapWindowPoints( hchild, hparent, &pt, 1 );
8746 SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
8747 check_update_rgn( hchild, hrgn );
8748 SetRectRgn( hrgn, 0, 0, 50, 50 );
8749 check_update_rgn( hparent, hrgn );
8750 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8751 ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
8752 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
8753 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
8755 flush_events();
8756 ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
8758 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
8759 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8760 ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
8761 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
8762 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
8764 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
8765 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
8766 ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
8768 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
8769 flush_sequence();
8770 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
8771 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8772 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
8774 /* flush all paint messages */
8775 flush_events();
8776 flush_sequence();
8778 /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
8779 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
8780 SetRectRgn( hrgn, 0, 0, 50, 50 );
8781 check_update_rgn( hparent, hrgn );
8782 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
8783 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8784 SetRectRgn( hrgn, 0, 0, 50, 50 );
8785 check_update_rgn( hparent, hrgn );
8787 /* flush all paint messages */
8788 flush_events();
8789 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
8790 flush_sequence();
8792 /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
8793 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8794 SetRectRgn( hrgn, 0, 0, 50, 50 );
8795 check_update_rgn( hparent, hrgn );
8796 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
8797 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8798 SetRectRgn( hrgn2, 10, 10, 50, 50 );
8799 CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
8800 check_update_rgn( hparent, hrgn );
8801 /* flush all paint messages */
8802 flush_events();
8803 flush_sequence();
8805 /* same as above but parent gets completely validated */
8806 SetRect( &rect, 20, 20, 30, 30 );
8807 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8808 SetRectRgn( hrgn, 20, 20, 30, 30 );
8809 check_update_rgn( hparent, hrgn );
8810 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
8811 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8812 check_update_rgn( hparent, 0 ); /* no update region */
8813 flush_events();
8814 ok_sequence( WmEmptySeq, "WmEmpty", FALSE ); /* and no paint messages */
8816 /* make sure RDW_VALIDATE on child doesn't have the same effect */
8817 flush_sequence();
8818 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8819 SetRectRgn( hrgn, 20, 20, 30, 30 );
8820 check_update_rgn( hparent, hrgn );
8821 RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
8822 SetRectRgn( hrgn, 20, 20, 30, 30 );
8823 check_update_rgn( hparent, hrgn );
8825 /* same as above but normal WM_PAINT doesn't validate parent */
8826 flush_sequence();
8827 SetRect( &rect, 20, 20, 30, 30 );
8828 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8829 SetRectRgn( hrgn, 20, 20, 30, 30 );
8830 check_update_rgn( hparent, hrgn );
8831 /* no WM_PAINT in child while parent still pending */
8832 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8833 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8834 while (PeekMessageA( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8835 ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
8837 flush_sequence();
8838 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8839 /* no WM_PAINT in child while parent still pending */
8840 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8841 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8842 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
8843 /* now that parent is valid child should get WM_PAINT */
8844 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8845 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8846 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8847 ok_sequence( WmEmptySeq, "No other message", FALSE );
8849 /* same thing with WS_CLIPCHILDREN in parent */
8850 flush_sequence();
8851 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
8852 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
8853 /* changing style invalidates non client area, but we need to invalidate something else to see it */
8854 RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
8855 ok_sequence( WmEmptySeq, "No message", FALSE );
8856 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
8857 ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
8859 flush_sequence();
8860 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
8861 SetRectRgn( hrgn, 20, 20, 30, 30 );
8862 check_update_rgn( hparent, hrgn );
8863 /* no WM_PAINT in child while parent still pending */
8864 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8865 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8866 /* WM_PAINT in parent first */
8867 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8868 ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
8870 /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
8871 flush_sequence();
8872 SetRect( &rect, 0, 0, 30, 30 );
8873 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
8874 SetRectRgn( hrgn, 0, 0, 30, 30 );
8875 check_update_rgn( hparent, hrgn );
8876 flush_events();
8877 ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
8879 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
8880 flush_sequence();
8881 SetRect( &rect, -10, 0, 30, 30 );
8882 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
8883 SetRect( &rect, 0, 0, 20, 20 );
8884 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
8885 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
8886 ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
8888 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
8889 flush_sequence();
8890 SetRect( &rect, -10, 0, 30, 30 );
8891 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
8892 SetRect( &rect, 0, 0, 100, 100 );
8893 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
8894 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
8895 ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
8896 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8897 ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
8899 /* WS_CLIPCHILDREN doesn't exclude children from update region */
8900 flush_sequence();
8901 RedrawWindow( hparent, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
8902 GetClientRect( hparent, &rect );
8903 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8904 check_update_rgn( hparent, hrgn );
8905 flush_events();
8907 RedrawWindow( hparent, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
8908 GetClientRect( hparent, &rect );
8909 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8910 check_update_rgn( hparent, hrgn );
8911 flush_events();
8913 /* test RDW_INTERNALPAINT behavior */
8915 flush_sequence();
8916 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
8917 flush_events();
8918 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
8920 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
8921 flush_events();
8922 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
8924 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
8925 flush_events();
8926 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
8928 style = GetWindowLongA(hparent, GWL_STYLE);
8929 ok(style & WS_CLIPCHILDREN, "Got unexpected style %#lx.\n", style);
8930 UpdateWindow( hparent );
8931 flush_events();
8932 flush_sequence();
8933 if (winetest_debug > 1) trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
8934 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8935 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
8936 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8937 flush_events();
8938 ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
8940 UpdateWindow( hparent );
8941 flush_events();
8942 flush_sequence();
8943 if (winetest_debug > 1) trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
8944 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8945 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
8946 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8947 flush_events();
8948 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
8950 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
8951 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
8952 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
8953 flush_events();
8954 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
8956 style = GetWindowLongA(hparent, GWL_STYLE);
8957 ok(!(style & WS_CLIPCHILDREN), "Got unexpected style %#lx.\n", style);
8958 UpdateWindow( hparent );
8959 flush_events();
8960 flush_sequence();
8961 if (winetest_debug > 1) trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
8962 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8963 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
8964 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8965 flush_events();
8966 ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
8968 UpdateWindow( hparent );
8969 flush_events();
8970 flush_sequence();
8971 if (winetest_debug > 1) trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
8972 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8973 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
8974 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8975 flush_events();
8976 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
8978 ok(GetWindowLongA( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
8979 ok(GetWindowLongA( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
8981 UpdateWindow( hparent );
8982 flush_events();
8983 flush_sequence();
8984 if (winetest_debug > 1) trace("testing SetWindowPos(-10000, -10000) on child\n");
8985 SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
8986 check_update_rgn( hchild, 0 );
8987 flush_events();
8989 #if 0 /* this one doesn't pass under Wine yet */
8990 UpdateWindow( hparent );
8991 flush_events();
8992 flush_sequence();
8993 if (winetest_debug > 1) trace("testing ShowWindow(SW_MINIMIZE) on child\n");
8994 ShowWindow( hchild, SW_MINIMIZE );
8995 check_update_rgn( hchild, 0 );
8996 flush_events();
8997 #endif
8999 UpdateWindow( hparent );
9000 flush_events();
9001 flush_sequence();
9002 if (winetest_debug > 1) trace("testing SetWindowPos(-10000, -10000) on parent\n");
9003 SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
9004 check_update_rgn( hparent, 0 );
9005 flush_events();
9007 log_all_parent_messages--;
9008 DestroyWindow( hparent );
9009 ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
9011 /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
9013 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
9014 100, 100, 200, 200, 0, 0, 0, NULL);
9015 ok (hparent != 0, "Failed to create parent window\n");
9017 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
9018 10, 10, 100, 100, hparent, 0, 0, NULL);
9019 ok (hchild != 0, "Failed to create child window\n");
9021 ShowWindow( hparent, SW_SHOW );
9022 UpdateWindow( hparent );
9023 UpdateWindow( hchild );
9024 flush_events();
9025 flush_sequence();
9027 /* moving child outside of parent boundaries changes update region */
9028 SetRect( &rect, 0, 0, 40, 40 );
9029 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
9030 SetRectRgn( hrgn, 0, 0, 40, 40 );
9031 check_update_rgn( hchild, hrgn );
9032 MoveWindow( hchild, -10, 10, 100, 100, FALSE );
9033 SetRectRgn( hrgn, 10, 0, 40, 40 );
9034 check_update_rgn( hchild, hrgn );
9035 MoveWindow( hchild, -10, -10, 100, 100, FALSE );
9036 SetRectRgn( hrgn, 10, 10, 40, 40 );
9037 check_update_rgn( hchild, hrgn );
9039 /* moving parent off-screen does too */
9040 SetRect( &rect, 0, 0, 100, 100 );
9041 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
9042 SetRectRgn( hrgn, 0, 0, 100, 100 );
9043 check_update_rgn( hparent, hrgn );
9044 SetRectRgn( hrgn, 10, 10, 40, 40 );
9045 check_update_rgn( hchild, hrgn );
9046 MoveWindow( hparent, -20, -20, 200, 200, FALSE );
9047 GetUpdateRect( hparent, &rect2, FALSE );
9048 if (!EqualRect( &rect2, &rect )) /* Win 8 and later don't crop update to screen */
9050 rect.left += 20;
9051 rect.top += 20;
9053 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
9054 check_update_rgn( hparent, hrgn );
9055 SetRectRgn( hrgn, rect.left + 10, rect.top + 10, 40, 40 );
9056 check_update_rgn( hchild, hrgn );
9058 /* invalidated region is cropped by the parent rects */
9059 SetRect( &rect, 0, 0, 50, 50 );
9060 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
9061 SetRectRgn( hrgn, rect2.left + 10, rect2.top + 10, 50, 50 );
9062 check_update_rgn( hchild, hrgn );
9064 DestroyWindow( hparent );
9065 ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
9066 flush_sequence();
9068 DeleteObject( hrgn );
9069 DeleteObject( hrgn2 );
9072 static void visualize_region_differences( HWND hwnd, HWND hother, HRGN hrgn_expect, HRGN hrgn_actual )
9074 HBRUSH b_expectonly, b_actualonly, b_intersect;
9075 HRGN hrgn_intersect;
9076 HWND hstatic, hshow, hhide;
9077 HDC hdc, hdctmp;
9078 HBITMAP hbitmap;
9079 MSG msg;
9080 RECT rect;
9081 DWORD start_time, elapsed, timeout = 60 * 1000;
9082 BOOL toggle = TRUE, stop = FALSE;
9084 start_time = GetTickCount();
9086 b_expectonly = CreateSolidBrush( RGB( 64, 64, 255 ));
9087 b_actualonly = CreateSolidBrush( RGB( 255, 64, 64 ));
9088 b_intersect = CreateSolidBrush( RGB( 159, 64, 159 ));
9090 hrgn_intersect = CreateRectRgn( 0, 0, 0, 0 );
9091 CombineRgn( hrgn_intersect, hrgn_expect, hrgn_actual, RGN_AND );
9093 GetClientRect( hwnd, &rect );
9094 hdc = GetDC( hwnd );
9095 hbitmap = CreateCompatibleBitmap( hdc, rect.right, rect.bottom );
9096 hdctmp = CreateCompatibleDC( hdc );
9097 ReleaseDC( hwnd, hdc );
9099 SelectObject( hdctmp, hbitmap );
9100 FillRgn( hdctmp, hrgn_expect, b_expectonly );
9101 FillRgn( hdctmp, hrgn_actual, b_actualonly );
9102 FillRgn( hdctmp, hrgn_intersect, b_intersect );
9104 DeleteObject( hdctmp );
9105 DeleteObject( hrgn_intersect );
9106 DeleteObject( b_intersect );
9107 DeleteObject( b_actualonly );
9108 DeleteObject( b_expectonly );
9110 hstatic = CreateWindowExA( 0, WC_STATICA, "", WS_CHILD | SS_BITMAP,
9111 0, 0, rect.right, rect.bottom, hwnd, 0, 0, NULL );
9112 SendMessageA( hstatic, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbitmap );
9114 hshow = hstatic;
9115 hhide = hother;
9117 for (;;)
9119 if (stop) toggle = hshow == hother;
9120 if (toggle)
9122 HWND htmp;
9123 HDWP hdwp;
9125 hdwp = BeginDeferWindowPos( !!hhide + !!hshow );
9126 if (hhide)
9128 DeferWindowPos( hdwp, hhide, NULL, 0, 0, 0, 0,
9129 SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER );
9131 if (hshow)
9133 DeferWindowPos( hdwp, hshow, HWND_TOP, 0, 0, 0, 0,
9134 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE );
9136 EndDeferWindowPos( hdwp );
9138 htmp = hshow;
9139 hshow = hhide;
9140 hhide = htmp;
9141 toggle = FALSE;
9143 if (stop) break;
9144 if ((elapsed = GetTickCount() - start_time) >= timeout)
9146 stop = TRUE;
9147 continue;
9149 MsgWaitForMultipleObjects( 0, NULL, FALSE, timeout - elapsed, QS_ALLINPUT );
9150 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
9152 TranslateMessage( &msg );
9153 DispatchMessageA( &msg );
9154 if (msg.message == WM_MOUSEMOVE)
9156 start_time = GetTickCount();
9158 else if (msg.message == WM_LBUTTONUP || (msg.message == WM_CHAR && msg.wParam == VK_SPACE))
9160 toggle = !toggle;
9162 else if (msg.message == WM_RBUTTONUP || (msg.message == WM_CHAR && msg.wParam == VK_RETURN))
9164 stop = TRUE;
9169 DestroyWindow( hstatic );
9170 DeleteObject( hbitmap );
9173 #define subtest_swp_paint_regions(w,p,c) subtest_swp_paint_regions_(__LINE__,w,p,c)
9175 static void subtest_swp_paint_regions_( int line, int wrap_toplevel, LPCSTR parent_class, LPCSTR child_class )
9177 static const struct exposure_test {
9178 int ex_style, style;
9179 BOOL shuffle_zorder;
9180 } exposure_tests[] = {
9181 { 0, WS_CLIPCHILDREN, FALSE },
9182 { 0, 0, FALSE },
9183 { WS_EX_COMPOSITED, WS_CLIPCHILDREN, TRUE },
9184 { WS_EX_COMPOSITED, 0, FALSE },
9185 { WS_EX_COMPOSITED, 0, TRUE },
9187 size_t i;
9188 HWND htoplevel = NULL, hparent, hchild, hauxchild;
9189 const RECT rect_old = { 10, 10, 100, 100 };
9190 HRGN hrgn_old_vis = CreateRectRgn( 0, 0, 0, 0 );
9191 HRGN hrgn_new_vis = CreateRectRgn( 0, 0, 0, 0 );
9192 HRGN hrgn_expect = CreateRectRgn( 0, 0, 0, 0 );
9193 HRGN hrgn_actual = CreateRectRgn( 0, 0, 0, 0 );
9194 HRGN hrgn_old_vis_child = CreateRectRgn( 0, 0, 0, 0 );
9195 HRGN hrgn_new_vis_child = CreateRectRgn( 0, 0, 0, 0 );
9196 HRGN hrgn_expect_child = CreateRectRgn( 0, 0, 0, 0 );
9197 HRGN hrgn_actual_child = CreateRectRgn( 0, 0, 0, 0 );
9198 int base_style;
9199 BOOL is_composition_possible, has_parentdc_anomaly;
9200 WNDCLASSA parent_wc;
9202 if (wrap_toplevel)
9204 htoplevel = CreateWindowExA( 0, "SimpleWindowClass", "Test toplevel", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9205 100, 100, 400, 400, 0, 0, 0, NULL );
9206 ok( htoplevel != 0, "Failed to create top-level window: %lu\n", GetLastError() );
9207 base_style = WS_CHILD | WS_VISIBLE;
9209 else
9211 base_style = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
9214 ok( GetClassInfoA( GetModuleHandleA( NULL ), parent_class, &parent_wc ),
9215 "GetClassInfoA failed\n" );
9217 is_composition_possible = (base_style & (WS_POPUP|WS_CHILD)) != WS_CHILD ||
9218 (parent_wc.style & CS_PARENTDC) == 0;
9220 has_parentdc_anomaly = (base_style & (WS_POPUP|WS_CHILD)) != WS_CHILD &&
9221 (parent_wc.style & CS_PARENTDC) != 0;
9223 hparent = CreateWindowExA( 0, parent_class, "Test parent", base_style,
9224 80, 80, 200, 200, htoplevel, 0, 0, NULL );
9225 ok( hparent != 0, "Creating parent window (%s) returned error %lu\n",
9226 debugstr_a( parent_class ), GetLastError() );
9228 hchild = CreateWindowExA( 0, child_class, "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
9229 rect_old.left, rect_old.top,
9230 rect_old.right - rect_old.left, rect_old.bottom - rect_old.top,
9231 hparent, 0, 0, NULL );
9232 ok( hchild != 0, "Creating child window (%s) returned error %lu\n",
9233 debugstr_a( child_class ), GetLastError() );
9235 hauxchild = CreateWindowExA( 0, child_class, "Auxiliary child for z order test", WS_CHILD | WS_VISIBLE,
9236 110, 0, 0, 0, hparent, 0, 0, NULL );
9237 ok( hauxchild != 0, "Creating child window (%s) returned error %lu\n",
9238 debugstr_a( child_class ), GetLastError() );
9240 for (i = 0; i < ARRAY_SIZE(exposure_tests); i++)
9242 const struct exposure_test *extest = &exposure_tests[i];
9243 BOOL has_ws_ex_composited = (extest->ex_style & WS_EX_COMPOSITED) != 0;
9244 BOOL is_composited = is_composition_possible && has_ws_ex_composited;
9245 BOOL is_zorder_redraw = is_composited && extest->shuffle_zorder;
9246 int delta;
9248 winetest_push_context( "%d: SetWindowPos redraw #%Id (ex_style = %#x, style = %#x, shuffle_zorder = %d)",
9249 line, i, extest->ex_style, extest->style, extest->shuffle_zorder );
9251 SetWindowLongA( hparent, GWL_EXSTYLE, extest->ex_style );
9252 SetWindowLongA( hparent, GWL_STYLE, base_style | extest->style );
9253 RedrawWindow( hparent, NULL, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
9255 for (delta = -20; delta <= 0; delta += 20)
9257 RECT rect_old_vis, rect_new, rect_new_vis;
9258 RECT rect_parent_clip, rect_child_clip;
9259 RECT rect_old_vis_child, rect_new_vis_child;
9260 BOOL rgn_ok;
9262 winetest_push_context( "delta = %+d", delta );
9264 SetWindowPos( hchild, HWND_TOP,
9265 rect_old.left,
9266 rect_old.top,
9267 rect_old.right - rect_old.left,
9268 rect_old.bottom - rect_old.top,
9269 SWP_NOACTIVATE );
9271 rect_new = rect_old;
9272 OffsetRect( &rect_new, delta, delta );
9274 rect_old_vis_child = rect_old;
9275 MapWindowPoints( hparent, hchild, (POINT *)&rect_old_vis_child, 2 );
9277 SetRectRgn( hrgn_actual, 0, 0, 0, 0 );
9278 SetRectRgn( hrgn_actual_child, 0, 0, 0, 0 );
9280 UpdateWindow( hparent );
9281 flush_events();
9283 if (extest->shuffle_zorder)
9285 /* bring sibling to top/bottom first so we can trigger z-order change */
9286 SetWindowPos( hauxchild, HWND_TOP, 0, 0, 0, 0,
9287 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
9290 SetWindowPos( hchild, HWND_TOP,
9291 rect_new.left,
9292 rect_new.top,
9293 rect_new.right - rect_new.left,
9294 rect_new.bottom - rect_new.top,
9295 SWP_NOACTIVATE |
9296 (extest->shuffle_zorder ? 0 : SWP_NOZORDER) );
9298 ok( GetUpdateRgn( hparent, hrgn_actual, FALSE ) != ERROR,
9299 "GetUpdateRgn on parentshall succeed\n" );
9300 ok( GetUpdateRgn( hchild, hrgn_actual_child, FALSE ) != ERROR,
9301 "GetUpdateRgn on child shall succeed\n" );
9303 /* Compute parent window expose region */
9304 GetClientRect( hparent, &rect_parent_clip );
9305 IntersectRect( &rect_old_vis, &rect_old, &rect_parent_clip );
9306 SetRectRgn( hrgn_old_vis, rect_old_vis.left, rect_old_vis.top, rect_old_vis.right, rect_old_vis.bottom );
9307 IntersectRect( &rect_new_vis, &rect_new, &rect_parent_clip );
9308 SetRectRgn( hrgn_new_vis, rect_new_vis.left, rect_new_vis.top, rect_new_vis.right, rect_new_vis.bottom );
9310 if (!EqualRect( &rect_old, &rect_new ) || is_zorder_redraw)
9312 CombineRgn( hrgn_expect, hrgn_old_vis, hrgn_new_vis, is_composited ? RGN_OR : RGN_DIFF );
9314 else
9316 SetRectRgn( hrgn_expect, 0, 0, 0, 0 );
9319 rgn_ok = EqualRgn( hrgn_expect, hrgn_actual );
9320 if (!rgn_ok && broken( has_parentdc_anomaly && is_composited /* Win7 */ ))
9322 if (winetest_debug > 1)
9324 trace( "Forcing non-composited update region (broken)\n" );
9326 rgn_ok = 1;
9328 else
9330 ok( !!rgn_ok, "Parent update region shall match expected region\n" );
9333 if (!rgn_ok && winetest_debug > 1)
9335 trace( "Expected parent update region: " );
9336 dump_region( hrgn_expect );
9337 trace( "Actual parent update region: " );
9338 dump_region( hrgn_actual );
9339 trace( "Old child window visible area: %s\n", wine_dbgstr_rect( &rect_old_vis ) );
9340 trace( "New child window visible area: %s\n", wine_dbgstr_rect( &rect_new_vis ) );
9343 if (winetest_interactive)
9345 if (!rgn_ok)
9347 visualize_region_differences( hparent, hchild, hrgn_expect, hrgn_actual );
9350 /* Let the position change be visible to the user */
9351 flush_events();
9354 rect_new_vis_child = rect_new;
9355 MapWindowPoints( hparent, hchild, (POINT *)&rect_new_vis_child, 2 );
9357 /* Compute child window expose region */
9358 GetClientRect( hchild, &rect_child_clip );
9359 if (is_composited)
9361 RECT rect_outer_clip;
9362 GetClientRect( hparent, &rect_outer_clip );
9363 MapWindowPoints( hparent, hchild, (POINT *)&rect_outer_clip, 2 );
9364 IntersectRect( &rect_child_clip, &rect_child_clip, &rect_outer_clip );
9366 IntersectRect( &rect_old_vis_child, &rect_old_vis_child, &rect_child_clip );
9367 SetRectRgn( hrgn_old_vis_child, rect_old_vis_child.left, rect_old_vis_child.top, rect_old_vis_child.right, rect_old_vis_child.bottom );
9368 IntersectRect( &rect_new_vis_child, &rect_new_vis_child, &rect_child_clip );
9369 SetRectRgn( hrgn_new_vis_child, rect_new_vis_child.left, rect_new_vis_child.top, rect_new_vis_child.right, rect_new_vis_child.bottom );
9371 if (!EqualRect( &rect_old, &rect_new ) || is_zorder_redraw)
9373 CombineRgn( hrgn_expect_child, hrgn_new_vis_child, hrgn_old_vis_child, is_composited ? RGN_OR : RGN_DIFF );
9375 else
9377 SetRectRgn( hrgn_expect_child, 0, 0, 0, 0 );
9380 rgn_ok = EqualRgn( hrgn_expect_child, hrgn_actual_child );
9381 if (!rgn_ok && broken( has_parentdc_anomaly && is_composited /* Win7 */ ))
9383 if (winetest_debug > 1)
9385 trace( "Forcing non-composited update region (broken)\n" );
9387 rgn_ok = 1;
9389 else
9391 ok( !!rgn_ok, "Child update region shall match expected region\n" );
9394 if (!rgn_ok && winetest_debug > 1)
9396 trace( "Expected child update region: " );
9397 dump_region( hrgn_expect_child );
9398 trace( "Actual child update region: " );
9399 dump_region( hrgn_actual_child );
9400 trace( "Old child window client visible area: %s\n", wine_dbgstr_rect( &rect_old_vis_child ) );
9401 trace( "New child window client visible area: %s\n", wine_dbgstr_rect( &rect_new_vis_child ) );
9404 if (winetest_interactive)
9406 if (!rgn_ok)
9408 visualize_region_differences( hchild, NULL, hrgn_expect_child, hrgn_actual_child );
9411 /* Let the position change be visible to the user */
9412 flush_events();
9415 winetest_pop_context();
9418 winetest_pop_context();
9421 DestroyWindow( hauxchild );
9422 DestroyWindow( hchild );
9423 DestroyWindow( hparent );
9424 if (htoplevel) DestroyWindow( htoplevel );
9426 DeleteObject( hrgn_actual_child );
9427 DeleteObject( hrgn_expect_child );
9428 DeleteObject( hrgn_new_vis_child );
9429 DeleteObject( hrgn_old_vis_child );
9430 DeleteObject( hrgn_actual );
9431 DeleteObject( hrgn_expect );
9432 DeleteObject( hrgn_new_vis );
9433 DeleteObject( hrgn_old_vis );
9436 static void test_swp_paint_regions(void)
9438 subtest_swp_paint_regions( 1, "SimpleWindowClass", "SimpleWindowClass" );
9439 subtest_swp_paint_regions( 0, "SimpleWindowClass", "SimpleWindowClass" );
9440 subtest_swp_paint_regions( 0, "SimpleWindowClass", "SimpleWindowClassWithParentDC" );
9441 subtest_swp_paint_regions( 0, "SimpleWindowClassWithParentDC", "SimpleWindowClass" );
9444 static void test_swp_paint_region_on_show(void)
9446 HRGN hrgn_actual_child = CreateRectRgn( 0, 0, 0, 0 );
9447 HRGN hrgn_actual = CreateRectRgn( 0, 0, 0, 0 );
9448 const RECT rect_1 = { 10, 10, 100, 100 };
9449 const RECT rect_2 = { 20, 20, 120, 120 };
9450 RECT rect_expect_child, rect_expect;
9451 RECT rect_actual_child, rect_actual;
9452 HWND hparent, hchild;
9453 int result;
9455 hparent = CreateWindowExA( 0, "SimpleWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9456 80, 80, 200, 200, NULL, 0, 0, NULL );
9457 ok( hparent != 0, "Creating parent window returned error %lu\n", GetLastError() );
9459 hchild = CreateWindowExA( 0, "SimpleWindowClass", "Test child", WS_CHILD | WS_BORDER,
9460 0, 0, 100, 100, hparent, 0, 0, NULL );
9461 ok( hchild != 0, "Creating child window returned error %lu\n", GetLastError() );
9463 if (winetest_debug > 1) trace("testing show window (no move / size)\n");
9465 SetWindowPos( hchild, HWND_TOP,
9466 rect_1.left, rect_1.top, rect_1.right - rect_1.left, rect_1.bottom - rect_1.top,
9467 SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOZORDER );
9469 UpdateWindow( hparent );
9470 flush_events();
9472 SetWindowPos( hchild, HWND_TOP, 0, 0, 0, 0,
9473 SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE );
9475 ok( GetUpdateRgn( hparent, hrgn_actual, FALSE ) != ERROR,
9476 "GetUpdateRgn on parent shall succeed\n" );
9477 ok( GetUpdateRgn( hchild, hrgn_actual_child, FALSE ) != ERROR,
9478 "GetUpdateRgn on child shall succeed\n" );
9480 result = GetRgnBox( hrgn_actual, &rect_actual );
9481 ok( result == SIMPLEREGION, "GetRgnBox (on parent) returned %d\n", result );
9482 if (result == COMPLEXREGION) dump_region( hrgn_actual );
9484 rect_expect = rect_1;
9485 ok( EqualRect( &rect_actual, &rect_expect ), "parent update region: got %s, expected %s\n",
9486 wine_dbgstr_rect( &rect_actual ), wine_dbgstr_rect( &rect_expect ) );
9488 result = GetRgnBox( hrgn_actual_child, &rect_actual_child );
9489 ok( result == SIMPLEREGION, "GetRgnBox (on child) returned %d\n", result );
9490 if (result == COMPLEXREGION) dump_region( hrgn_actual_child );
9492 ok( GetClientRect( hchild, &rect_expect_child ), "GetClientRect failed\n" );
9493 ok( EqualRect( &rect_actual_child, &rect_expect_child ), "child update region: got %s, expected %s\n",
9494 wine_dbgstr_rect( &rect_actual_child ), wine_dbgstr_rect( &rect_expect_child ) );
9496 if (winetest_debug > 1) trace("testing show window (with move / resize)\n");
9498 SetWindowPos( hchild, HWND_TOP,
9499 rect_1.left, rect_1.top, rect_1.right - rect_1.left, rect_1.bottom - rect_1.top,
9500 SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOZORDER );
9502 UpdateWindow( hparent );
9503 flush_events();
9505 SetWindowPos( hchild, HWND_TOP,
9506 rect_2.left,
9507 rect_2.top,
9508 rect_2.right - rect_2.left,
9509 rect_2.bottom - rect_2.top,
9510 SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER );
9512 ok( GetUpdateRgn( hparent, hrgn_actual, FALSE ) != ERROR,
9513 "GetUpdateRgn on parent shall succeed\n" );
9514 ok( GetUpdateRgn( hchild, hrgn_actual_child, FALSE ) != ERROR,
9515 "GetUpdateRgn on child shall succeed\n" );
9517 result = GetRgnBox( hrgn_actual, &rect_actual );
9518 ok( result == SIMPLEREGION, "GetRgnBox (on parent) returned %d\n", result );
9519 if (result == COMPLEXREGION) dump_region( hrgn_actual );
9521 rect_expect = rect_2;
9522 ok( EqualRect( &rect_actual, &rect_expect ), "parent update region: got %s, expected %s\n",
9523 wine_dbgstr_rect( &rect_actual ), wine_dbgstr_rect( &rect_expect ) );
9525 result = GetRgnBox( hrgn_actual_child, &rect_actual_child );
9526 ok( result == SIMPLEREGION, "GetRgnBox (on child) returned %d\n", result );
9527 if (result == COMPLEXREGION) dump_region( hrgn_actual_child );
9529 ok( GetClientRect( hchild, &rect_expect_child ), "GetClientRect failed\n" );
9530 ok( EqualRect( &rect_actual_child, &rect_expect_child ), "child update region: got %s, expected %s\n",
9531 wine_dbgstr_rect( &rect_actual_child ), wine_dbgstr_rect( &rect_expect_child ) );
9533 DestroyWindow( hchild );
9534 DestroyWindow( hparent );
9535 DeleteObject( hrgn_actual_child );
9536 DeleteObject( hrgn_actual );
9539 static void test_swp_paint_region_on_extend_zerosize(void)
9541 HRGN hrgn_actual_child = CreateRectRgn( 0, 0, 0, 0 );
9542 HRGN hrgn_actual = CreateRectRgn( 0, 0, 0, 0 );
9543 const RECT rect_1 = { 10, 10, 100, 100 };
9544 RECT rect_expect_child, rect_expect;
9545 RECT rect_actual_child, rect_actual;
9546 HWND hparent, hchild;
9547 int result;
9549 hparent = CreateWindowExA( 0, "SimpleWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9550 80, 80, 200, 200, NULL, 0, 0, NULL );
9551 ok( hparent != 0, "Creating parent window returned error %lu\n", GetLastError() );
9553 hchild = CreateWindowExA( 0, "SimpleWindowClass", "Test child (no border)", WS_CHILD | WS_VISIBLE,
9554 10, 10, 0, 0, hparent, 0, 0, NULL );
9555 ok( hchild != 0, "Creating child window returned error %lu\n", GetLastError() );
9557 if (winetest_debug > 1) trace("testing extending zero-size window\n");
9559 UpdateWindow( hparent );
9560 flush_events();
9562 SetWindowPos( hchild, HWND_TOP,
9563 rect_1.left,
9564 rect_1.top,
9565 rect_1.right - rect_1.left,
9566 rect_1.bottom - rect_1.top,
9567 SWP_NOACTIVATE | SWP_NOZORDER );
9569 ok( GetUpdateRgn( hparent, hrgn_actual, FALSE ) != ERROR,
9570 "GetUpdateRgn on parent shall succeed\n" );
9571 ok( GetUpdateRgn( hchild, hrgn_actual_child, FALSE ) != ERROR,
9572 "GetUpdateRgn on child shall succeed\n" );
9574 result = GetRgnBox( hrgn_actual, &rect_actual );
9575 ok( result == SIMPLEREGION, "GetRgnBox (on parent) returned %d\n", result );
9576 if (result == COMPLEXREGION) dump_region( hrgn_actual );
9578 rect_expect = rect_1;
9579 ok( EqualRect( &rect_actual, &rect_expect ), "parent update region: got %s, expected %s\n",
9580 wine_dbgstr_rect( &rect_actual ), wine_dbgstr_rect( &rect_expect ) );
9582 result = GetRgnBox( hrgn_actual_child, &rect_actual_child );
9583 ok( result == SIMPLEREGION, "GetRgnBox (on child) returned %d\n", result );
9584 if (result == COMPLEXREGION) dump_region( hrgn_actual_child );
9586 ok( GetClientRect( hchild, &rect_expect_child ), "GetClientRect failed\n" );
9587 ok( EqualRect( &rect_actual_child, &rect_expect_child ), "child update region: got %s, expected %s\n",
9588 wine_dbgstr_rect( &rect_actual_child ), wine_dbgstr_rect( &rect_expect_child ) );
9590 DestroyWindow( hchild );
9591 DestroyWindow( hparent );
9592 DeleteObject( hrgn_actual_child );
9593 DeleteObject( hrgn_actual );
9596 static void subtest_hvredraw(HWND hparent, UINT class_style, DWORD style)
9598 static const struct movesize_test {
9599 int dx, dy, dw, dh;
9600 } movesize_tests[] = {
9601 { 0, 0, 0, 5 },
9602 { 0, 0, 5, 0 },
9603 { 0, 0, 5, 5 },
9604 { 0, 0, -5, -5 },
9605 { -5, -5, 0, 5 },
9606 { -5, -5, 5, 0 },
9607 { -5, -5, 5, 5 },
9609 HRGN hrgn_old_vis = CreateRectRgn( 0, 0, 0, 0 );
9610 HRGN hrgn_new_vis = CreateRectRgn( 0, 0, 0, 0 );
9611 HRGN hrgn_expect = CreateRectRgn( 0, 0, 0, 0 );
9612 HRGN hrgn_actual = CreateRectRgn( 0, 0, 0, 0 );
9613 const int x0 = 100, y0 = 100, w0 = 150, h0 = 150;
9614 size_t i;
9615 HWND hwnd;
9616 WNDCLASSA cls = {
9617 .style = class_style,
9618 .lpfnWndProc = DefWindowProcA,
9619 .hInstance = GetModuleHandleA(0),
9620 .hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW),
9621 .hbrBackground = GetStockObject(WHITE_BRUSH),
9622 .lpszClassName = "TestHVRedrawClass"
9625 register_class(&cls);
9627 hwnd = CreateWindowExA( 0, cls.lpszClassName, "Test window", style, x0, y0, w0, h0, hparent, 0, 0, NULL );
9628 ok(hwnd != NULL, "Failed to create the window\n");
9630 ShowWindow( hwnd, SW_SHOW );
9631 UpdateWindow( hwnd );
9633 for (i = 0; i < ARRAY_SIZE(movesize_tests); i++)
9635 const struct movesize_test *test = &movesize_tests[i];
9636 int is_redraw = (test->dw != 0 && (class_style & CS_HREDRAW)) ||
9637 (test->dh != 0 && (class_style & CS_VREDRAW));
9638 RECT rect_old_vis, rect_new_vis;
9639 BOOL rgn_ok;
9641 winetest_push_context( "%x %08lx SetWindowPos redraw #%Id (%d, %d, %d, %d)",
9642 class_style, style, i, test->dx, test->dy, test->dw, test->dh );
9644 SetWindowPos( hwnd, HWND_TOP, x0, y0, w0, h0, SWP_NOACTIVATE );
9646 GetClientRect( hwnd, &rect_old_vis );
9647 SetRectRgn( hrgn_old_vis, rect_old_vis.left, rect_old_vis.top, rect_old_vis.right, rect_old_vis.bottom );
9649 UpdateWindow( hparent );
9650 flush_events();
9652 SetWindowPos( hwnd, HWND_TOP,
9653 x0 + test->dx, y0 + test->dy,
9654 w0 + test->dw, h0 + test->dh, SWP_NOACTIVATE );
9655 ok( GetUpdateRgn( hwnd, hrgn_actual, FALSE ) != ERROR, "GetUpdateRgn shall succeed\n" );
9657 GetClientRect( hwnd, &rect_new_vis );
9658 SetRectRgn( hrgn_new_vis, rect_new_vis.left, rect_new_vis.top, rect_new_vis.right, rect_new_vis.bottom );
9659 CombineRgn( hrgn_expect, hrgn_new_vis, hrgn_old_vis, is_redraw ? RGN_COPY : RGN_DIFF );
9661 rgn_ok = EqualRgn( hrgn_expect, hrgn_actual );
9662 ok( !!rgn_ok, "Update region shall match expected region\n" );
9664 if (!rgn_ok)
9666 trace( "Expected update region: " );
9667 dump_region( hrgn_expect );
9668 trace( "Actual update region: " );
9669 dump_region( hrgn_actual );
9670 trace( "Old window visible area: %s\n", wine_dbgstr_rect( &rect_old_vis ) );
9671 trace( "New window visible area: %s\n", wine_dbgstr_rect( &rect_new_vis ) );
9674 if (winetest_interactive)
9676 if (!rgn_ok)
9678 visualize_region_differences( hwnd, NULL, hrgn_expect, hrgn_actual );
9681 /* Let the position change be visible to the user */
9682 flush_events();
9685 winetest_pop_context();
9688 DestroyWindow( hwnd );
9689 DeleteObject( hrgn_actual );
9690 DeleteObject( hrgn_expect );
9691 DeleteObject( hrgn_new_vis );
9692 DeleteObject( hrgn_old_vis );
9693 UnregisterClassA( cls.lpszClassName, cls.hInstance );
9697 static void test_hvredraw(void)
9699 HWND htoplevel;
9701 subtest_hvredraw( NULL, CS_HREDRAW, WS_OVERLAPPEDWINDOW );
9702 subtest_hvredraw( NULL, CS_VREDRAW, WS_OVERLAPPEDWINDOW );
9703 subtest_hvredraw( NULL, CS_HREDRAW|CS_VREDRAW, WS_OVERLAPPEDWINDOW );
9705 htoplevel = CreateWindowExA( 0, "SimpleWindowClass", "Test toplevel",
9706 WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_VISIBLE,
9707 100, 100, 400, 400, 0, 0, 0, NULL );
9708 ok( htoplevel != 0, "Failed to create top-level window: %lu\n", GetLastError() );
9710 subtest_hvredraw( htoplevel, CS_HREDRAW, WS_CHILD | WS_BORDER );
9711 subtest_hvredraw( htoplevel, CS_VREDRAW, WS_CHILD | WS_BORDER );
9712 subtest_hvredraw( htoplevel, CS_HREDRAW|CS_VREDRAW, WS_CHILD | WS_BORDER );
9714 DestroyWindow( htoplevel );
9717 struct run_in_temp_desktop_args
9719 const char *file;
9720 int line;
9721 const char *name;
9722 void (*test_func)(void);
9725 static DWORD WINAPI run_in_temp_desktop_thread_func(LPVOID param)
9727 HDESK prev_thr_desktop, prev_inp_desktop, post_inp_desktop, temp_desktop;
9728 char temp_desktop_name[1024], curr_desktop_name[1024];
9729 struct run_in_temp_desktop_args *args = param;
9730 const char *file = args->file;
9731 int line = args->line;
9732 LARGE_INTEGER qpc;
9733 DWORD length;
9734 int result;
9736 result = QueryPerformanceCounter( &qpc );
9737 ok_(file, line)( result, "QueryPerformanceCounter error %lu\n", GetLastError() );
9740 * Temporary desktops from previous runs may leak due to a Windows bug.
9741 * Generate a unique name that is unlikely to collide with previous runs.
9743 result = snprintf( temp_desktop_name, ARRAY_SIZE(temp_desktop_name),
9744 "WineTest-%08lX-%08lX-%08lX%08lX-%s",
9745 GetCurrentProcessId(), GetCurrentThreadId(),
9746 qpc.HighPart, qpc.LowPart, args->name );
9747 ok_(file, line)( result > 0 && result < ARRAY_SIZE(temp_desktop_name),
9748 "sprintf returned %d (out of memory, or name too long?)\n", result );
9750 if (winetest_debug > 1)
9751 trace_(file, line)( "creating desktop: %s\n", debugstr_a( temp_desktop_name ) );
9753 temp_desktop = CreateDesktopA( temp_desktop_name, NULL, NULL, 0, GENERIC_ALL, NULL );
9754 ok_(file, line)( temp_desktop != NULL, "CreateDesktopA(%s, ..) error %lu\n",
9755 debugstr_a( temp_desktop_name ), GetLastError() );
9757 prev_inp_desktop = OpenInputDesktop( 0, FALSE, DESKTOP_SWITCHDESKTOP );
9758 ok_(file, line)( prev_inp_desktop != NULL, "OpenInputDesktop [prev] error %lu\n", GetLastError() );
9760 if (winetest_debug > 1)
9761 trace_(file, line)( "sanity check: no concurrent WineTest desktop\n" );
9764 * Check if the desktop has not been properly restored. This is done to
9765 * avoid any possible hard-to-debug failures due to unexpected desktop.
9767 result = GetUserObjectInformationA( prev_inp_desktop, UOI_NAME,
9768 curr_desktop_name, sizeof(curr_desktop_name), &length );
9769 ok_(file, line)( result, "GetUserObjectInformationA error %lu [rl = %lu]\n",
9770 GetLastError(), length );
9771 ok_(file, line)( _strnicmp( curr_desktop_name, temp_desktop_name, 8 ) != 0,
9772 "unexpected input desktop name %s (concurrent WineTest run?)\n",
9773 debugstr_a( curr_desktop_name ) );
9775 if (winetest_debug > 1)
9776 trace_(file, line)( "switching desktop to: %s (%p)\n", debugstr_a( temp_desktop_name ), temp_desktop );
9778 result = SwitchDesktop( temp_desktop );
9779 ok_(file, line)( result, "SwitchDesktop(temp_desktop=%p) error %lu\n",
9780 temp_desktop, GetLastError() );
9782 prev_thr_desktop = GetThreadDesktop( GetCurrentThreadId() );
9783 ok_(file, line)( prev_thr_desktop != NULL, "GetThreadDesktop error %lu\n", GetLastError() );
9785 result = SetThreadDesktop( temp_desktop );
9786 ok_(file, line)( result, "SetThreadDesktop(temp_desktop=%p) error %lu\n",
9787 temp_desktop, GetLastError() );
9789 if (winetest_debug > 1)
9790 trace_(file, line)( "running test function %s()\n", args->name );
9792 args->test_func();
9794 if (winetest_debug > 1)
9795 trace_(file, line)( "sanity check: input desktop has not been changed\n" );
9798 * Check if the input desktop has been tampered with. This is done to
9799 * avoid any possible hard-to-debug failures due to unexpected desktop.
9801 post_inp_desktop = OpenInputDesktop( 0, FALSE, DESKTOP_ENUMERATE );
9802 ok_(file, line)( post_inp_desktop != NULL, "OpenInputDesktop [post] error %lu\n", GetLastError() );
9804 result = GetUserObjectInformationA( post_inp_desktop, UOI_NAME,
9805 curr_desktop_name, sizeof(curr_desktop_name), &length );
9806 ok_(file, line)( result, "GetUserObjectInformationA(post_inp_desktop=%p) error %lu [rl = %lu]\n",
9807 post_inp_desktop, GetLastError(), length );
9808 todo_wine
9809 ok_(file, line)( strcmp( curr_desktop_name, temp_desktop_name ) == 0,
9810 "different desktop name: %s != %s (no switch or concurrent WineTest run?)\n",
9811 debugstr_a( curr_desktop_name ), debugstr_a( temp_desktop_name ) );
9813 result = CloseDesktop( post_inp_desktop );
9814 ok_(file, line)( result, "CloseDesktop(post_inp_desktop=%p) error %lu\n",
9815 post_inp_desktop, GetLastError() );
9817 if (winetest_debug > 1)
9818 trace_(file, line)( "restoring previous desktop\n" );
9820 result = SetThreadDesktop( prev_thr_desktop );
9821 ok_(file, line)( result || broken( GetLastError() == ERROR_BUSY ) /* == W10 */,
9822 "SetThreadDesktop(prev_thr_desktop=%p) error %lu\n",
9823 prev_thr_desktop, GetLastError() );
9825 result = SwitchDesktop( prev_inp_desktop );
9826 ok_(file, line)( result, "SwitchDesktop(prev_inp_desktop=%p) error %lu\n",
9827 prev_inp_desktop, GetLastError() );
9829 result = CloseDesktop( prev_inp_desktop );
9830 ok_(file, line)( result, "CloseDesktop(prev_inp_desktop=%p) error %lu\n",
9831 prev_inp_desktop, GetLastError() );
9833 if (winetest_debug > 1)
9834 trace_(file, line)( "closing desktop: %s (%p)\n", debugstr_a( temp_desktop_name ), temp_desktop );
9836 result = CloseDesktop( temp_desktop );
9837 ok_(file, line)( result || broken( GetLastError() == ERROR_BUSY ) /* == W10 */,
9838 "CloseDesktop(temp_desktop=%p) error %lu\n",
9839 temp_desktop, GetLastError() );
9841 return 0;
9844 #define run_in_temp_desktop(f) run_in_temp_desktop_(__FILE__, __LINE__, #f, f)
9845 static void run_in_temp_desktop_(const char *file, int line, const char *name, void (*test_func)(void))
9847 struct run_in_temp_desktop_args args;
9848 HANDLE thread;
9849 DWORD result;
9851 args.file = file;
9852 args.line = line;
9853 args.name = name;
9854 args.test_func = test_func;
9856 thread = CreateThread( NULL, 0, run_in_temp_desktop_thread_func, &args, 0, NULL );
9857 ok_(file, line)( thread != NULL, "CreateThread error %lu\n", GetLastError() );
9859 result = WaitForSingleObject( thread, INFINITE );
9860 ok_(file, line)( result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu, error %lu\n",
9861 result, GetLastError() );
9863 CloseHandle( thread );
9866 struct wnd_event
9868 HWND hwnd;
9869 HANDLE grand_child;
9870 HANDLE start_event;
9871 HANDLE stop_event;
9872 HANDLE getmessage_complete;
9875 static DWORD WINAPI thread_proc(void *param)
9877 MSG msg;
9878 struct wnd_event *wnd_event = param;
9880 wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
9881 100, 100, 200, 200, 0, 0, 0, NULL);
9882 ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
9884 SetEvent(wnd_event->start_event);
9886 while (GetMessageA(&msg, 0, 0, 0))
9888 TranslateMessage(&msg);
9889 DispatchMessageA(&msg);
9892 ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
9894 return 0;
9897 static DWORD CALLBACK create_grand_child_thread( void *param )
9899 struct wnd_event *wnd_event = param;
9900 HWND hchild;
9901 MSG msg;
9903 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
9904 WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
9905 ok (hchild != 0, "Failed to create child window\n");
9906 flush_events();
9907 flush_sequence();
9908 SetEvent( wnd_event->start_event );
9910 for (;;)
9912 MsgWaitForMultipleObjects(0, NULL, FALSE, 1000, QS_ALLINPUT);
9913 if (!IsWindow( hchild )) break; /* will be destroyed when parent thread exits */
9914 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
9916 return 0;
9919 static DWORD CALLBACK create_child_thread( void *param )
9921 struct wnd_event *wnd_event = param;
9922 struct wnd_event child_event;
9923 DWORD ret, tid;
9924 MSG msg;
9926 child_event.hwnd = CreateWindowExA(0, "TestWindowClass", "Test child",
9927 WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
9928 ok (child_event.hwnd != 0, "Failed to create child window\n");
9929 SetFocus( child_event.hwnd );
9930 flush_events();
9931 flush_sequence();
9932 child_event.start_event = wnd_event->start_event;
9933 wnd_event->grand_child = CreateThread(NULL, 0, create_grand_child_thread, &child_event, 0, &tid);
9934 for (;;)
9936 DWORD ret = MsgWaitForMultipleObjects(1, &child_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
9937 if (ret != 1) break;
9938 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
9940 ret = WaitForSingleObject( wnd_event->stop_event, 5000 );
9941 ok( !ret, "WaitForSingleObject failed %lx\n", ret );
9942 return 0;
9945 static const char manifest_dep[] =
9946 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
9947 "<assemblyIdentity version=\"1.2.3.4\" name=\"testdep1\" type=\"win32\" processorArchitecture=\"" ARCH "\"/>"
9948 " <file name=\"testdep.dll\" />"
9949 "</assembly>";
9951 static const char manifest_main[] =
9952 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
9953 "<assemblyIdentity version=\"1.2.3.4\" name=\"Wine.Test\" type=\"win32\" />"
9954 "<dependency>"
9955 " <dependentAssembly>"
9956 " <assemblyIdentity type=\"win32\" name=\"testdep1\" version=\"1.2.3.4\" processorArchitecture=\"" ARCH "\" />"
9957 " </dependentAssembly>"
9958 "</dependency>"
9959 "</assembly>";
9961 static void create_manifest_file(const char *filename, const char *manifest)
9963 WCHAR path[MAX_PATH];
9964 HANDLE file;
9965 DWORD size;
9967 MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH );
9968 file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
9969 ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %lu\n", GetLastError());
9970 WriteFile(file, manifest, strlen(manifest), &size, NULL);
9971 CloseHandle(file);
9974 static HANDLE test_create(const char *file)
9976 WCHAR path[MAX_PATH];
9977 ACTCTXW actctx;
9978 HANDLE handle;
9980 MultiByteToWideChar(CP_ACP, 0, file, -1, path, MAX_PATH);
9981 memset(&actctx, 0, sizeof(ACTCTXW));
9982 actctx.cbSize = sizeof(ACTCTXW);
9983 actctx.lpSource = path;
9985 handle = CreateActCtxW(&actctx);
9986 ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %lu\n", GetLastError());
9988 ok(actctx.cbSize == sizeof(actctx), "cbSize=%ld\n", actctx.cbSize);
9989 ok(actctx.dwFlags == 0, "dwFlags=%ld\n", actctx.dwFlags);
9990 ok(actctx.lpSource == path, "lpSource=%p\n", actctx.lpSource);
9991 ok(actctx.wProcessorArchitecture == 0, "wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture);
9992 ok(actctx.wLangId == 0, "wLangId=%d\n", actctx.wLangId);
9993 ok(actctx.lpAssemblyDirectory == NULL, "lpAssemblyDirectory=%p\n", actctx.lpAssemblyDirectory);
9994 ok(actctx.lpResourceName == NULL, "lpResourceName=%p\n", actctx.lpResourceName);
9995 ok(actctx.lpApplicationName == NULL, "lpApplicationName=%p\n", actctx.lpApplicationName);
9996 ok(actctx.hModule == NULL, "hModule=%p\n", actctx.hModule);
9998 return handle;
10001 static void test_interthread_messages(void)
10003 HANDLE hThread, context, handle, event;
10004 ULONG_PTR cookie;
10005 DWORD tid;
10006 WNDPROC proc;
10007 MSG msg;
10008 char buf[256];
10009 int len, expected_len;
10010 struct wnd_event wnd_event;
10011 BOOL ret;
10013 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
10014 if (!wnd_event.start_event)
10016 win_skip("skipping interthread message test under win9x\n");
10017 return;
10020 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
10021 ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError());
10023 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10025 CloseHandle(wnd_event.start_event);
10027 SetLastError(0xdeadbeef);
10028 ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeeded\n");
10029 ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
10030 "wrong error code %ld\n", GetLastError());
10032 proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
10033 ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %ld\n", GetLastError());
10035 expected_len = lstrlenA("window caption text");
10036 memset(buf, 0, sizeof(buf));
10037 SetLastError(0xdeadbeef);
10038 len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
10039 ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %ld, len %d, expected len %d\n", GetLastError(), len, expected_len);
10040 ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
10042 msg.hwnd = wnd_event.hwnd;
10043 msg.message = WM_GETTEXT;
10044 msg.wParam = sizeof(buf);
10045 msg.lParam = (LPARAM)buf;
10046 memset(buf, 0, sizeof(buf));
10047 SetLastError(0xdeadbeef);
10048 len = DispatchMessageA(&msg);
10049 ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */
10050 "DispatchMessageA(WM_GETTEXT) succeeded on another thread window: ret %d, error %ld\n", len, GetLastError());
10052 /* the following test causes an exception in user.exe under win9x */
10053 msg.hwnd = wnd_event.hwnd;
10054 msg.message = WM_TIMER;
10055 msg.wParam = 0;
10056 msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
10057 SetLastError(0xdeadbeef);
10058 len = DispatchMessageA(&msg);
10059 ok(!len && GetLastError() == 0xdeadbeef,
10060 "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %ld\n", len, GetLastError());
10062 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
10063 ok( ret, "PostMessageA(WM_QUIT) error %ld\n", GetLastError());
10065 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10066 CloseHandle(hThread);
10068 ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
10070 wnd_event.hwnd = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10071 100, 100, 200, 200, 0, 0, 0, NULL);
10072 ok (wnd_event.hwnd != 0, "Failed to create parent window\n");
10073 flush_events();
10074 flush_sequence();
10075 log_all_parent_messages++;
10076 wnd_event.start_event = CreateEventA( NULL, TRUE, FALSE, NULL );
10077 wnd_event.stop_event = CreateEventA( NULL, TRUE, FALSE, NULL );
10078 hThread = CreateThread( NULL, 0, create_child_thread, &wnd_event, 0, &tid );
10079 for (;;)
10081 ret = MsgWaitForMultipleObjects(1, &wnd_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
10082 if (ret != 1) break;
10083 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10085 ok( !ret, "MsgWaitForMultipleObjects failed %x\n", ret );
10086 /* now wait for the thread without processing messages; this shouldn't deadlock */
10087 SetEvent( wnd_event.stop_event );
10088 ret = WaitForSingleObject( hThread, 5000 );
10089 ok( !ret, "WaitForSingleObject failed %x\n", ret );
10090 CloseHandle( hThread );
10092 ret = WaitForSingleObject( wnd_event.grand_child, 5000 );
10093 ok( !ret, "WaitForSingleObject failed %x\n", ret );
10094 CloseHandle( wnd_event.grand_child );
10096 CloseHandle( wnd_event.start_event );
10097 CloseHandle( wnd_event.stop_event );
10098 flush_events();
10099 ok_sequence(WmExitThreadSeq, "destroy child on thread exit", FALSE);
10100 log_all_parent_messages--;
10101 DestroyWindow( wnd_event.hwnd );
10103 /* Activation context tests */
10104 create_manifest_file("testdep1.manifest", manifest_dep);
10105 create_manifest_file("main.manifest", manifest_main);
10107 context = test_create("main.manifest");
10108 DeleteFileA("testdep1.manifest");
10109 DeleteFileA("main.manifest");
10111 handle = (void*)0xdeadbeef;
10112 ret = GetCurrentActCtx(&handle);
10113 ok(ret, "GetCurrentActCtx failed: %lu\n", GetLastError());
10114 ok(handle == 0, "active context %p\n", handle);
10116 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
10117 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
10118 ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError());
10119 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10120 CloseHandle(wnd_event.start_event);
10122 /* context is activated after thread creation, so it doesn't inherit it by default */
10123 ret = ActivateActCtx(context, &cookie);
10124 ok(ret, "activation failed: %lu\n", GetLastError());
10126 handle = 0;
10127 ret = GetCurrentActCtx(&handle);
10128 ok(ret, "GetCurrentActCtx failed: %lu\n", GetLastError());
10129 ok(handle != 0, "active context %p\n", handle);
10130 ReleaseActCtx(handle);
10132 /* destination window will test for active context */
10133 ret = SendMessageA(wnd_event.hwnd, WM_USER+10, 0, 0);
10134 ok(ret, "thread window returned %d\n", ret);
10136 event = CreateEventW(NULL, 0, 0, NULL);
10137 ret = PostMessageA(wnd_event.hwnd, WM_USER+10, 0, (LPARAM)event);
10138 ok(ret, "thread window returned %d\n", ret);
10139 ok(WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10140 CloseHandle(event);
10142 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
10143 ok(ret, "PostMessageA(WM_QUIT) error %ld\n", GetLastError());
10145 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10146 CloseHandle(hThread);
10148 ret = DeactivateActCtx(0, cookie);
10149 ok(ret, "DeactivateActCtx failed: %lu\n", GetLastError());
10150 ReleaseActCtx(context);
10154 static const struct message WmVkN[] = {
10155 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
10156 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
10157 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
10158 { WM_CHAR, wparam|lparam, 'n', 1 },
10159 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
10160 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
10161 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
10162 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
10163 { 0 }
10165 static const struct message WmShiftVkN[] = {
10166 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
10167 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
10168 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
10169 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
10170 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
10171 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
10172 { WM_CHAR, wparam|lparam, 'N', 1 },
10173 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
10174 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
10175 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
10176 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
10177 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
10178 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
10179 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
10180 { 0 }
10182 static const struct message WmCtrlVkN[] = {
10183 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
10184 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
10185 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
10186 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
10187 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
10188 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
10189 { WM_CHAR, wparam|lparam, 0x000e, 1 },
10190 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
10191 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
10192 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
10193 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
10194 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
10195 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
10196 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
10197 { 0 }
10199 static const struct message WmCtrlVkN_2[] = {
10200 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
10201 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
10202 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
10203 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
10204 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
10205 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
10206 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
10207 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
10208 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
10209 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
10210 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
10211 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
10212 { 0 }
10214 static const struct message WmAltVkN[] = {
10215 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
10216 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
10217 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
10218 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
10219 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
10220 { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
10221 { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
10222 { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
10223 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
10224 { HCBT_SYSCOMMAND, hook },
10225 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
10226 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
10227 { 0x00AE, sent|defwinproc|optional }, /* XP */
10228 { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
10229 { WM_INITMENU, sent|defwinproc },
10230 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_SYSMENU, 0 },
10231 { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
10232 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
10233 { WM_CAPTURECHANGED, sent|defwinproc },
10234 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
10235 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_SYSMENU, 0 },
10236 { WM_EXITMENULOOP, sent|defwinproc },
10237 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
10238 { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
10239 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
10240 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
10241 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
10242 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
10243 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
10244 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
10245 { 0 }
10247 static const struct message WmAltVkN_2[] = {
10248 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
10249 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
10250 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
10251 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
10252 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
10253 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
10254 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
10255 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
10256 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
10257 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
10258 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
10259 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
10260 { 0 }
10262 static const struct message WmCtrlAltVkN[] = {
10263 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
10264 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
10265 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
10266 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
10267 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
10268 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
10269 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
10270 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
10271 { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
10272 { WM_CHAR, optional },
10273 { WM_CHAR, sent|optional },
10274 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
10275 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
10276 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
10277 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
10278 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
10279 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
10280 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
10281 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
10282 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
10283 { 0 }
10285 static const struct message WmCtrlShiftVkN[] = {
10286 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
10287 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
10288 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
10289 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
10290 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
10291 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
10292 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
10293 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
10294 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
10295 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
10296 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
10297 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
10298 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
10299 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
10300 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
10301 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
10302 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
10303 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
10304 { 0 }
10306 static const struct message WmCtrlAltShiftVkN[] = {
10307 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
10308 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
10309 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
10310 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
10311 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
10312 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
10313 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
10314 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
10315 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
10316 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
10317 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
10318 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
10319 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
10320 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
10321 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
10322 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
10323 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
10324 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
10325 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
10326 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
10327 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
10328 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
10329 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
10330 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
10331 { 0 }
10333 static const struct message WmAltPressRelease[] = {
10334 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
10335 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
10336 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
10337 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
10338 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
10339 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
10340 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
10341 { HCBT_SYSCOMMAND, hook },
10342 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
10343 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
10344 { WM_INITMENU, sent|defwinproc },
10345 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_SYSMENU, 0 },
10346 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
10347 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_SYSMENU, 1 },
10349 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
10351 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_SYSMENU, 0 },
10352 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0, },
10353 { WM_CAPTURECHANGED, sent|defwinproc },
10354 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
10355 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_SYSMENU, 0 },
10356 { WM_EXITMENULOOP, sent|defwinproc },
10357 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
10358 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
10359 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
10360 { 0 }
10362 static const struct message WmShiftMouseButton[] = {
10363 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
10364 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
10365 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
10366 { WM_MOUSEMOVE, wparam|optional, 0, 0 },
10367 { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
10368 { WM_LBUTTONDOWN, wparam, MK_LBUTTON|MK_SHIFT, 0 },
10369 { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON|MK_SHIFT, 0 },
10370 { WM_LBUTTONUP, wparam|optional, MK_SHIFT, 0 }, /* < w1064v1809 */
10371 { WM_LBUTTONUP, sent|wparam|optional, MK_SHIFT, 0 }, /* < w1064v1809 */
10372 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
10373 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
10374 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
10375 { WM_LBUTTONUP, optional, 0, 0 }, /* >= w1064v1809 */
10376 { WM_LBUTTONUP, sent|optional, 0, 0 }, /* >= w1064v1809 */
10377 { 0 }
10379 static const struct message WmF1Seq[] = {
10380 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
10381 { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
10382 { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
10383 { WM_KEYF1, wparam|lparam, 0, 0 },
10384 { WM_KEYF1, sent|wparam|lparam, 0, 0 },
10385 { WM_HELP, sent|defwinproc },
10386 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
10387 { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
10388 { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
10389 { 0 }
10391 static const struct message WmVkAppsSeq[] = {
10392 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
10393 { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
10394 { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
10395 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
10396 { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
10397 { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
10398 { WM_CONTEXTMENU, lparam, /*hwnd*/0, -1 },
10399 { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, -1 },
10400 { 0 }
10402 static const struct message WmVkF10Seq[] = {
10403 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
10404 { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
10405 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
10406 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
10407 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
10408 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
10409 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
10410 { HCBT_SYSCOMMAND, hook },
10411 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
10412 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
10413 { WM_INITMENU, sent|defwinproc },
10414 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_SYSMENU, 0 },
10415 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
10416 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_SYSMENU, 1 },
10418 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0x10000001 }, /* XP */
10420 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
10421 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_SYSMENU, 0 },
10422 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0, },
10423 { WM_CAPTURECHANGED, sent|defwinproc },
10424 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
10425 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_SYSMENU, 0 },
10426 { WM_EXITMENULOOP, sent|defwinproc },
10427 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
10428 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
10429 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
10430 { 0 }
10432 static const struct message WmShiftF10Seq[] = {
10433 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
10434 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
10435 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x00000001 },
10436 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
10437 { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
10438 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
10439 { WM_CONTEXTMENU, sent|defwinproc|lparam, /*hwnd*/0, -1 },
10440 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
10441 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
10442 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
10443 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
10444 { HCBT_SYSCOMMAND, hook },
10445 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
10446 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
10447 { WM_INITMENU, sent|defwinproc },
10448 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_SYSMENU, 0 },
10449 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
10450 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_SYSMENU, 1 },
10451 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xd0000001 }, /* XP */
10452 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0x10000001 }, /* XP */
10453 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_SYSMENU, 0 },
10454 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
10455 { WM_CAPTURECHANGED, sent|defwinproc|wparam|lparam, 0, 0 },
10456 { WM_MENUSELECT, sent|defwinproc|wparam|lparam, 0xffff0000, 0 },
10457 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_SYSMENU, 0 },
10458 { WM_EXITMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
10459 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 }, /* XP */
10460 { WM_KEYUP, wparam|lparam, VK_ESCAPE, 0xc0000001 },
10461 { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
10462 { 0 }
10465 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
10467 MSG msg;
10469 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
10471 struct recvd_message log_msg;
10473 /* ignore some unwanted messages */
10474 if (msg.message == WM_MOUSEMOVE ||
10475 msg.message == WM_TIMER ||
10476 ignore_message( msg.message ))
10477 continue;
10479 log_msg.hwnd = msg.hwnd;
10480 log_msg.message = msg.message;
10481 log_msg.flags = wparam|lparam;
10482 log_msg.wParam = msg.wParam;
10483 log_msg.lParam = msg.lParam;
10484 log_msg.descr = "accel";
10485 add_message(&log_msg);
10487 if (!hAccel || !TranslateAcceleratorA(hwnd, hAccel, &msg))
10489 TranslateMessage(&msg);
10490 DispatchMessageA(&msg);
10495 static void test_accelerators(void)
10497 RECT rc;
10498 POINT pt;
10499 SHORT state;
10500 HACCEL hAccel;
10501 HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10502 100, 100, 200, 200, 0, 0, 0, NULL);
10503 BOOL us_kbd = (GetKeyboardLayout(0) == (HKL)(ULONG_PTR)0x04090409);
10504 BOOL ret;
10506 ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError());
10507 UpdateWindow(hwnd);
10508 flush_events();
10509 flush_sequence();
10511 SetFocus(hwnd);
10512 ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
10514 state = GetKeyState(VK_SHIFT);
10515 ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
10516 state = GetKeyState(VK_CAPITAL);
10517 ok(state == 0, "wrong CapsLock state %04x\n", state);
10519 hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
10520 ok(!!hAccel, "Failed to load accelerators, error %lu.\n", GetLastError());
10522 flush_events();
10523 pump_msg_loop(hwnd, 0);
10524 flush_sequence();
10526 if (!us_kbd)
10528 skip("skipping ascii VK events on non-us keyboard\n");
10529 goto done;
10532 if (winetest_debug > 1) trace("testing VK_N press/release\n");
10533 flush_sequence();
10534 keybd_event('N', 0, 0, 0);
10535 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
10536 pump_msg_loop(hwnd, hAccel);
10537 if (!sequence_cnt) /* we didn't get any message */
10539 skip( "queuing key events not supported\n" );
10540 goto done;
10542 ok_sequence(WmVkN, "VK_N press/release", FALSE);
10544 if (winetest_debug > 1) trace("testing Shift+VK_N press/release\n");
10545 flush_sequence();
10546 keybd_event(VK_SHIFT, 0, 0, 0);
10547 keybd_event('N', 0, 0, 0);
10548 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
10549 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
10550 pump_msg_loop(hwnd, hAccel);
10551 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
10553 if (winetest_debug > 1) trace("testing Ctrl+VK_N press/release\n");
10554 flush_sequence();
10555 keybd_event(VK_CONTROL, 0, 0, 0);
10556 keybd_event('N', 0, 0, 0);
10557 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
10558 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
10559 pump_msg_loop(hwnd, hAccel);
10560 ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
10562 if (winetest_debug > 1) trace("testing Alt+VK_N press/release\n");
10563 flush_sequence();
10564 keybd_event(VK_MENU, 0, 0, 0);
10565 keybd_event('N', 0, 0, 0);
10566 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
10567 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
10568 pump_msg_loop(hwnd, hAccel);
10569 ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
10571 if (winetest_debug > 1) trace("testing Ctrl+Alt+VK_N press/release 1\n");
10572 flush_sequence();
10573 keybd_event(VK_CONTROL, 0, 0, 0);
10574 keybd_event(VK_MENU, 0, 0, 0);
10575 keybd_event('N', 0, 0, 0);
10576 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
10577 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
10578 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
10579 pump_msg_loop(hwnd, hAccel);
10580 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
10582 ret = DestroyAcceleratorTable(hAccel);
10583 ok( ret, "DestroyAcceleratorTable error %ld\n", GetLastError());
10585 hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(2));
10586 ok(!!hAccel, "Failed to load accelerators, error %lu.\n", GetLastError());
10588 if (winetest_debug > 1) trace("testing VK_N press/release\n");
10589 flush_sequence();
10590 keybd_event('N', 0, 0, 0);
10591 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
10592 pump_msg_loop(hwnd, hAccel);
10593 ok_sequence(WmVkN, "VK_N press/release", FALSE);
10595 if (winetest_debug > 1) trace("testing Shift+VK_N press/release\n");
10596 flush_sequence();
10597 keybd_event(VK_SHIFT, 0, 0, 0);
10598 keybd_event('N', 0, 0, 0);
10599 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
10600 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
10601 pump_msg_loop(hwnd, hAccel);
10602 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
10604 if (winetest_debug > 1) trace("testing Ctrl+VK_N press/release 2\n");
10605 flush_sequence();
10606 keybd_event(VK_CONTROL, 0, 0, 0);
10607 keybd_event('N', 0, 0, 0);
10608 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
10609 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
10610 pump_msg_loop(hwnd, hAccel);
10611 ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
10613 if (winetest_debug > 1) trace("testing Alt+VK_N press/release 2\n");
10614 flush_sequence();
10615 keybd_event(VK_MENU, 0, 0, 0);
10616 keybd_event('N', 0, 0, 0);
10617 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
10618 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
10619 pump_msg_loop(hwnd, hAccel);
10620 ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
10622 if (winetest_debug > 1) trace("testing Ctrl+Alt+VK_N press/release 2\n");
10623 flush_sequence();
10624 keybd_event(VK_CONTROL, 0, 0, 0);
10625 keybd_event(VK_MENU, 0, 0, 0);
10626 keybd_event('N', 0, 0, 0);
10627 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
10628 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
10629 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
10630 pump_msg_loop(hwnd, hAccel);
10631 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
10633 if (winetest_debug > 1) trace("testing Ctrl+Shift+VK_N press/release\n");
10634 flush_sequence();
10635 keybd_event(VK_CONTROL, 0, 0, 0);
10636 keybd_event(VK_SHIFT, 0, 0, 0);
10637 keybd_event('N', 0, 0, 0);
10638 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
10639 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
10640 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
10641 pump_msg_loop(hwnd, hAccel);
10642 ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
10644 if (winetest_debug > 1) trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
10645 flush_sequence();
10646 keybd_event(VK_CONTROL, 0, 0, 0);
10647 keybd_event(VK_MENU, 0, 0, 0);
10648 keybd_event(VK_SHIFT, 0, 0, 0);
10649 keybd_event('N', 0, 0, 0);
10650 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
10651 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
10652 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
10653 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
10654 pump_msg_loop(hwnd, hAccel);
10655 ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
10657 ret = DestroyAcceleratorTable(hAccel);
10658 ok( ret, "DestroyAcceleratorTable error %ld\n", GetLastError());
10659 hAccel = 0;
10661 if (winetest_debug > 1) trace("testing Alt press/release\n");
10662 flush_sequence();
10663 keybd_event(VK_MENU, 0, 0, 0);
10664 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
10665 keybd_event(VK_MENU, 0, 0, 0);
10666 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
10667 pump_msg_loop(hwnd, 0);
10668 /* this test doesn't pass in Wine for managed windows */
10669 ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
10671 if (winetest_debug > 1) trace("testing VK_F1 press/release\n");
10672 keybd_event(VK_F1, 0, 0, 0);
10673 keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
10674 pump_msg_loop(hwnd, 0);
10675 ok_sequence(WmF1Seq, "F1 press/release", FALSE);
10677 if (winetest_debug > 1) trace("testing VK_APPS press/release\n");
10678 keybd_event(VK_APPS, 0, 0, 0);
10679 keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
10680 pump_msg_loop(hwnd, 0);
10681 ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
10683 if (winetest_debug > 1) trace("testing VK_F10 press/release\n");
10684 keybd_event(VK_F10, 0, 0, 0);
10685 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
10686 keybd_event(VK_F10, 0, 0, 0);
10687 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
10688 pump_msg_loop(hwnd, 0);
10689 ok_sequence(WmVkF10Seq, "VK_F10 press/release", TRUE);
10691 if (winetest_debug > 1) trace("testing SHIFT+F10 press/release\n");
10692 keybd_event(VK_SHIFT, 0, 0, 0);
10693 keybd_event(VK_F10, 0, 0, 0);
10694 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
10695 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
10696 keybd_event(VK_ESCAPE, 0, 0, 0);
10697 keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
10698 pump_msg_loop(hwnd, 0);
10699 ok_sequence(WmShiftF10Seq, "SHIFT+F10 press/release", TRUE);
10701 if (winetest_debug > 1) trace("testing Shift+MouseButton press/release\n");
10702 /* first, move mouse pointer inside of the window client area */
10703 GetClientRect(hwnd, &rc);
10704 MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
10705 rc.left += (rc.right - rc.left)/2;
10706 rc.top += (rc.bottom - rc.top)/2;
10707 SetCursorPos(rc.left, rc.top);
10708 SetActiveWindow(hwnd);
10710 flush_events();
10711 flush_sequence();
10712 GetCursorPos(&pt);
10713 if (pt.x == rc.left && pt.y == rc.top)
10715 int i;
10716 keybd_event(VK_SHIFT, 0, 0, 0);
10717 mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
10718 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
10719 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
10720 pump_msg_loop(hwnd, 0);
10721 for (i = 0; i < sequence_cnt; i++) if (sequence[i].message == WM_LBUTTONDOWN) break;
10722 if (i < sequence_cnt)
10723 ok_sequence(WmShiftMouseButton, "Shift+MouseButton press/release", FALSE);
10724 else
10725 skip( "Shift+MouseButton event didn't get to the window\n" );
10728 done:
10729 if (hAccel) DestroyAcceleratorTable(hAccel);
10730 DestroyWindow(hwnd);
10733 /************* window procedures ********************/
10735 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message,
10736 WPARAM wParam, LPARAM lParam)
10738 static LONG defwndproc_counter = 0;
10739 static LONG beginpaint_counter = 0;
10740 LRESULT ret;
10741 struct recvd_message msg;
10743 if (ignore_message( message )) return 0;
10745 switch (message)
10747 case WM_ENABLE:
10749 LONG style = GetWindowLongA(hwnd, GWL_STYLE);
10750 ok((BOOL)wParam == !(style & WS_DISABLED),
10751 "wrong WS_DISABLED state: %Id != %d\n", wParam, !(style & WS_DISABLED));
10752 break;
10755 case WM_CAPTURECHANGED:
10756 if (test_DestroyWindow_flag)
10758 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
10759 if (style & WS_CHILD)
10760 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
10761 else if (style & WS_POPUP)
10762 lParam = WND_POPUP_ID;
10763 else
10764 lParam = WND_PARENT_ID;
10766 break;
10768 case WM_NCDESTROY:
10770 HWND capture;
10772 ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
10773 capture = GetCapture();
10774 if (capture)
10776 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
10777 if (winetest_debug > 1) trace("current capture %p, releasing...\n", capture);
10778 ReleaseCapture();
10781 /* fall through */
10782 case WM_DESTROY:
10783 ok(GetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
10784 if (test_DestroyWindow_flag)
10786 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
10787 if (style & WS_CHILD)
10788 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
10789 else if (style & WS_POPUP)
10790 lParam = WND_POPUP_ID;
10791 else
10792 lParam = WND_PARENT_ID;
10794 break;
10796 /* test_accelerators() depends on this */
10797 case WM_NCHITTEST:
10798 return HTCLIENT;
10800 case WM_USER+10:
10802 ACTIVATION_CONTEXT_BASIC_INFORMATION basicinfo;
10803 HANDLE handle, event = (HANDLE)lParam;
10804 BOOL ret;
10806 handle = (void*)0xdeadbeef;
10807 ret = GetCurrentActCtx(&handle);
10808 ok(ret, "failed to get current context, %lu\n", GetLastError());
10809 ok(handle == 0, "got active context %p\n", handle);
10811 memset(&basicinfo, 0xff, sizeof(basicinfo));
10812 ret = QueryActCtxW(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX, handle, 0, ActivationContextBasicInformation,
10813 &basicinfo, sizeof(basicinfo), NULL);
10814 ok(ret, "got %d, error %ld\n", ret, GetLastError());
10815 ok(basicinfo.hActCtx == NULL, "got %p\n", basicinfo.hActCtx);
10816 ok(basicinfo.dwFlags == 0, "got %lx\n", basicinfo.dwFlags);
10818 if (event) SetEvent(event);
10819 return 1;
10822 /* ignore */
10823 case WM_MOUSEMOVE:
10824 case WM_MOUSEACTIVATE:
10825 case WM_NCMOUSEMOVE:
10826 case WM_SETCURSOR:
10827 case WM_IME_SELECT:
10828 return 0;
10831 msg.hwnd = hwnd;
10832 msg.message = message;
10833 msg.flags = sent|wparam|lparam;
10834 if (defwndproc_counter) msg.flags |= defwinproc;
10835 if (beginpaint_counter) msg.flags |= beginpaint;
10836 msg.wParam = wParam;
10837 msg.lParam = lParam;
10838 msg.descr = "MsgCheckProc";
10839 add_message(&msg);
10841 if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
10843 HWND parent = GetParent(hwnd);
10844 RECT rc;
10845 MINMAXINFO *minmax = (MINMAXINFO *)lParam;
10847 GetClientRect(parent, &rc);
10848 if (winetest_debug > 1)
10850 trace("parent %p client size = (%ld x %ld)\n", parent, rc.right, rc.bottom);
10851 trace("Reserved=%ld,%ld MaxSize=%ld,%ld MaxPos=%ld,%ld MinTrack=%ld,%ld MaxTrack=%ld,%ld\n",
10852 minmax->ptReserved.x, minmax->ptReserved.y,
10853 minmax->ptMaxSize.x, minmax->ptMaxSize.y,
10854 minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
10855 minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
10856 minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
10858 ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %ld != %ld\n",
10859 minmax->ptMaxSize.x, rc.right);
10860 ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %ld != %ld\n",
10861 minmax->ptMaxSize.y, rc.bottom);
10864 if (message == WM_PAINT)
10866 PAINTSTRUCT ps;
10867 beginpaint_counter++;
10868 BeginPaint( hwnd, &ps );
10869 beginpaint_counter--;
10870 EndPaint( hwnd, &ps );
10871 return 0;
10874 if (!test_context_menu && message == WM_CONTEXTMENU)
10876 /* don't create context menu */
10877 return 0;
10880 defwndproc_counter++;
10881 ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam)
10882 : DefWindowProcA(hwnd, message, wParam, lParam);
10883 defwndproc_counter--;
10885 return ret;
10888 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10890 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
10893 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10895 return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
10898 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10900 static LONG defwndproc_counter = 0;
10901 LRESULT ret;
10902 struct recvd_message msg;
10904 if (ignore_message( message )) return 0;
10906 switch (message)
10908 case WM_QUERYENDSESSION:
10909 case WM_ENDSESSION:
10910 lParam &= ~0x01; /* Vista adds a 0x01 flag */
10911 break;
10914 msg.hwnd = hwnd;
10915 msg.message = message;
10916 msg.flags = sent|wparam|lparam;
10917 if (defwndproc_counter) msg.flags |= defwinproc;
10918 msg.wParam = wParam;
10919 msg.lParam = lParam;
10920 msg.descr = "popup";
10921 add_message(&msg);
10923 if (message == WM_CREATE)
10925 DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
10926 SetWindowLongA(hwnd, GWL_STYLE, style);
10929 defwndproc_counter++;
10930 ret = DefWindowProcA(hwnd, message, wParam, lParam);
10931 defwndproc_counter--;
10933 return ret;
10936 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10938 static LONG defwndproc_counter = 0;
10939 static LONG beginpaint_counter = 0;
10940 LRESULT ret;
10941 struct recvd_message msg;
10943 if (ignore_message( message )) return 0;
10945 if (log_all_parent_messages ||
10946 message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
10947 message == WM_SETFOCUS || message == WM_KILLFOCUS ||
10948 message == WM_ENABLE || message == WM_ENTERIDLE ||
10949 message == WM_DRAWITEM || message == WM_MEASUREITEM || message == WM_COMPAREITEM ||
10950 message == WM_COMMAND || message == WM_IME_SETCONTEXT)
10952 switch (message)
10954 /* ignore */
10955 case WM_NCHITTEST:
10956 return HTCLIENT;
10957 case WM_SETCURSOR:
10958 case WM_MOUSEMOVE:
10959 case WM_NCMOUSEMOVE:
10960 return 0;
10963 msg.hwnd = hwnd;
10964 msg.message = message;
10965 msg.flags = sent|parent|wparam|lparam;
10966 if (defwndproc_counter) msg.flags |= defwinproc;
10967 if (beginpaint_counter) msg.flags |= beginpaint;
10968 msg.wParam = wParam;
10969 msg.lParam = lParam;
10970 msg.descr = "parent";
10971 add_message(&msg);
10974 if (message == WM_PAINT)
10976 PAINTSTRUCT ps;
10977 beginpaint_counter++;
10978 BeginPaint( hwnd, &ps );
10979 beginpaint_counter--;
10980 EndPaint( hwnd, &ps );
10981 return 0;
10984 defwndproc_counter++;
10985 ret = DefWindowProcA(hwnd, message, wParam, lParam);
10986 defwndproc_counter--;
10988 return message == WM_COMPAREITEM ? -1 : ret;
10991 static LRESULT CALLBACK StopQuitMsgCheckProcA(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
10993 if (message == WM_CREATE)
10994 PostMessageA(hwnd, WM_CLOSE, 0, 0);
10995 else if (message == WM_CLOSE)
10997 /* Only the first WM_QUIT will survive the window destruction */
10998 PostMessageA(hwnd, WM_USER, 0x1234, 0x5678);
10999 PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
11000 PostMessageA(hwnd, WM_QUIT, 0x4321, 0x8765);
11003 return DefWindowProcA(hwnd, message, wp, lp);
11006 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11008 static LONG defwndproc_counter = 0;
11009 LRESULT ret;
11010 struct recvd_message msg;
11012 if (ignore_message( message )) return 0;
11014 if (test_def_id)
11016 DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
11017 ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
11018 if (after_end_dialog)
11019 ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %Ix\n", ret );
11020 else
11021 ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %Ix\n", ret);
11024 msg.hwnd = hwnd;
11025 msg.message = message;
11026 msg.flags = sent|wparam|lparam;
11027 if (defwndproc_counter) msg.flags |= defwinproc;
11028 msg.wParam = wParam;
11029 msg.lParam = lParam;
11030 msg.descr = "dialog";
11031 add_message(&msg);
11033 defwndproc_counter++;
11034 ret = DefDlgProcA(hwnd, message, wParam, lParam);
11035 defwndproc_counter--;
11037 return ret;
11040 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11042 static LONG defwndproc_counter = 0;
11043 LRESULT ret;
11044 struct recvd_message msg;
11046 /* log only specific messages we are interested in */
11047 switch (message)
11049 #if 0 /* probably log these as well */
11050 case WM_ACTIVATE:
11051 case WM_SETFOCUS:
11052 case WM_KILLFOCUS:
11053 #endif
11054 case WM_SHOWWINDOW:
11055 case WM_SIZE:
11056 case WM_MOVE:
11057 case WM_GETMINMAXINFO:
11058 case WM_WINDOWPOSCHANGING:
11059 case WM_WINDOWPOSCHANGED:
11060 break;
11062 default: /* ignore */
11063 /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
11064 return DefWindowProcA(hwnd, message, wParam, lParam);
11067 msg.hwnd = hwnd;
11068 msg.message = message;
11069 msg.flags = sent|wparam|lparam;
11070 if (defwndproc_counter) msg.flags |= defwinproc;
11071 msg.wParam = wParam;
11072 msg.lParam = lParam;
11073 msg.descr = "show";
11074 add_message(&msg);
11076 defwndproc_counter++;
11077 ret = DefWindowProcA(hwnd, message, wParam, lParam);
11078 defwndproc_counter--;
11080 return ret;
11083 static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
11085 switch (msg)
11087 case WM_CREATE: return 0;
11088 case WM_PAINT:
11090 MSG msg2;
11091 static int i = 0;
11093 if (i < 256)
11095 i++;
11096 if (PeekMessageA(&msg2, 0, 0, 0, 1))
11098 TranslateMessage(&msg2);
11099 DispatchMessageA(&msg2);
11101 i--;
11103 else ok(broken(1), "infinite loop\n");
11104 if ( i == 0)
11105 paint_loop_done = TRUE;
11106 return DefWindowProcA(hWnd,msg,wParam,lParam);
11109 return DefWindowProcA(hWnd,msg,wParam,lParam);
11112 static LRESULT WINAPI HotkeyMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11114 static LONG defwndproc_counter = 0;
11115 LRESULT ret;
11116 struct recvd_message msg;
11117 DWORD queue_status;
11119 if (ignore_message( message )) return 0;
11121 if ((message >= WM_KEYFIRST && message <= WM_KEYLAST) ||
11122 message == WM_HOTKEY || message >= WM_APP)
11124 msg.hwnd = hwnd;
11125 msg.message = message;
11126 msg.flags = sent|wparam|lparam;
11127 if (defwndproc_counter) msg.flags |= defwinproc;
11128 msg.wParam = wParam;
11129 msg.lParam = lParam;
11130 msg.descr = "HotkeyMsgCheckProcA";
11131 add_message(&msg);
11134 defwndproc_counter++;
11135 ret = DefWindowProcA(hwnd, message, wParam, lParam);
11136 defwndproc_counter--;
11138 if (message == WM_APP)
11140 queue_status = GetQueueStatus(QS_HOTKEY);
11141 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %lx\n", queue_status);
11142 queue_status = GetQueueStatus(QS_POSTMESSAGE);
11143 ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %lx\n", queue_status);
11144 PostMessageA(hwnd, WM_APP+1, 0, 0);
11146 else if (message == WM_APP+1)
11148 queue_status = GetQueueStatus(QS_HOTKEY);
11149 ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %lx\n", queue_status);
11152 return ret;
11155 static void register_classes(void)
11157 WNDCLASSA cls;
11158 WNDCLASSW clsW;
11160 cls.style = 0;
11161 cls.lpfnWndProc = MsgCheckProcA;
11162 cls.cbClsExtra = 0;
11163 cls.cbWndExtra = 0;
11164 cls.hInstance = GetModuleHandleA(0);
11165 cls.hIcon = 0;
11166 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
11167 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
11168 cls.lpszMenuName = NULL;
11169 cls.lpszClassName = "TestWindowClass";
11170 register_class(&cls);
11172 cls.lpfnWndProc = HotkeyMsgCheckProcA;
11173 cls.lpszClassName = "HotkeyWindowClass";
11174 register_class(&cls);
11176 cls.lpfnWndProc = ShowWindowProcA;
11177 cls.lpszClassName = "ShowWindowClass";
11178 register_class(&cls);
11180 cls.lpfnWndProc = PopupMsgCheckProcA;
11181 cls.lpszClassName = "TestPopupClass";
11182 register_class(&cls);
11184 cls.lpfnWndProc = ParentMsgCheckProcA;
11185 cls.lpszClassName = "TestParentClass";
11186 register_class(&cls);
11188 cls.lpfnWndProc = StopQuitMsgCheckProcA;
11189 cls.lpszClassName = "StopQuitClass";
11190 register_class(&cls);
11192 cls.lpfnWndProc = DefWindowProcA;
11193 cls.lpszClassName = "SimpleWindowClass";
11194 register_class(&cls);
11196 cls.lpfnWndProc = PaintLoopProcA;
11197 cls.lpszClassName = "PaintLoopWindowClass";
11198 register_class(&cls);
11200 cls.style = CS_NOCLOSE;
11201 cls.lpszClassName = "NoCloseWindowClass";
11202 register_class(&cls);
11204 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
11205 cls.style = 0;
11206 cls.hInstance = GetModuleHandleA(0);
11207 cls.hbrBackground = 0;
11208 cls.lpfnWndProc = TestDlgProcA;
11209 cls.lpszClassName = "TestDialogClass";
11210 register_class(&cls);
11212 cls.lpfnWndProc = DefWindowProcA;
11213 cls.style = CS_PARENTDC;
11214 cls.lpszClassName = "SimpleWindowClassWithParentDC";
11215 register_class(&cls);
11217 clsW.style = 0;
11218 clsW.lpfnWndProc = MsgCheckProcW;
11219 clsW.cbClsExtra = 0;
11220 clsW.cbWndExtra = 0;
11221 clsW.hInstance = GetModuleHandleW(0);
11222 clsW.hIcon = 0;
11223 clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
11224 clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
11225 clsW.lpszMenuName = NULL;
11226 clsW.lpszClassName = testWindowClassW;
11227 RegisterClassW(&clsW); /* ignore error, this fails on Win9x */
11230 static BOOL is_our_logged_class(HWND hwnd)
11232 char buf[256];
11234 if (GetClassNameA(hwnd, buf, sizeof(buf)))
11236 if (!lstrcmpiA(buf, "TestWindowClass") ||
11237 !lstrcmpiA(buf, "ShowWindowClass") ||
11238 !lstrcmpiA(buf, "TestParentClass") ||
11239 !lstrcmpiA(buf, "TestPopupClass") ||
11240 !lstrcmpiA(buf, "SimpleWindowClass") ||
11241 !lstrcmpiA(buf, "TestDialogClass") ||
11242 !lstrcmpiA(buf, "MDI_frame_class") ||
11243 !lstrcmpiA(buf, "MDI_client_class") ||
11244 !lstrcmpiA(buf, "MDI_child_class") ||
11245 !lstrcmpiA(buf, "my_button_class") ||
11246 !lstrcmpiA(buf, "my_edit_class") ||
11247 !lstrcmpiA(buf, "static") ||
11248 !lstrcmpiA(buf, "ListBox") ||
11249 !lstrcmpiA(buf, "ComboBox") ||
11250 !lstrcmpiA(buf, "MyDialogClass") ||
11251 !lstrcmpiA(buf, "#32770") ||
11252 !lstrcmpiA(buf, "#32768"))
11253 return TRUE;
11255 return FALSE;
11258 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
11260 HWND hwnd;
11262 ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
11264 if (nCode == HCBT_CLICKSKIPPED)
11266 /* ignore this event, XP sends it a lot when switching focus between windows */
11267 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
11270 if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
11272 struct recvd_message msg;
11274 msg.hwnd = 0;
11275 msg.message = nCode;
11276 msg.flags = hook|wparam|lparam;
11277 msg.wParam = wParam;
11278 msg.lParam = lParam;
11279 msg.descr = "CBT";
11280 add_message(&msg);
11282 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
11285 if (nCode == HCBT_DESTROYWND)
11287 if (test_DestroyWindow_flag)
11289 DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
11290 if (style & WS_CHILD)
11291 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
11292 else if (style & WS_POPUP)
11293 lParam = WND_POPUP_ID;
11294 else
11295 lParam = WND_PARENT_ID;
11299 /* Log also SetFocus(0) calls */
11300 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
11302 if (is_our_logged_class(hwnd))
11304 struct recvd_message msg;
11306 msg.hwnd = hwnd;
11307 msg.message = nCode;
11308 msg.flags = hook|wparam|lparam;
11309 msg.wParam = wParam;
11310 msg.lParam = lParam;
11311 msg.descr = "CBT";
11312 add_message(&msg);
11314 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
11317 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
11318 DWORD event,
11319 HWND hwnd,
11320 LONG object_id,
11321 LONG child_id,
11322 DWORD thread_id,
11323 DWORD event_time)
11325 ok(thread_id == winevent_hook_thread_id, "we didn't ask for events from other threads\n");
11327 /* ignore mouse cursor events */
11328 if (object_id == OBJID_CURSOR) return;
11330 if (!hwnd || is_our_logged_class(hwnd))
11332 struct recvd_message msg;
11334 msg.hwnd = hwnd;
11335 msg.message = event;
11336 msg.flags = winevent_hook|wparam|lparam;
11337 msg.wParam = object_id;
11338 msg.lParam = child_id;
11339 msg.descr = "WEH";
11340 add_message(&msg);
11344 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
11345 static const WCHAR wszAnsi[] = {'U',0};
11347 static const GUID iface_guid = {0x66666666};
11349 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
11351 const DEV_BROADCAST_DEVICEINTERFACE_A *ifaceA = (const void *)lParam;
11353 switch (uMsg)
11355 case CB_FINDSTRINGEXACT:
11356 if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
11357 return 1;
11358 if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
11359 return 0;
11360 return -1;
11362 case WM_DEVICECHANGE:
11363 if (wParam == DBT_DEVICEARRIVAL && IsEqualGUID(&ifaceA->dbcc_classguid, &iface_guid))
11365 DWORD expect_size = offsetof(DEV_BROADCAST_DEVICEINTERFACE_A, dbcc_name[strlen(ifaceA->dbcc_name)]);
11367 ok(ifaceA->dbcc_size == expect_size, "Expected %lu, got %lu.\n", expect_size, ifaceA->dbcc_size);
11368 ok(ifaceA->dbcc_devicetype == DBT_DEVTYP_DEVICEINTERFACE,
11369 "Got notification type %#lx.\n", ifaceA->dbcc_devicetype);
11370 ok(!ifaceA->dbcc_reserved, "Got reserved %#lx.\n", ifaceA->dbcc_reserved);
11371 ok(!strcmp(ifaceA->dbcc_name, "test name"), "Got name %s.\n", debugstr_a(ifaceA->dbcc_name));
11372 return 2;
11375 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
11378 static const struct message WmGetTextLengthAfromW[] = {
11379 { WM_GETTEXTLENGTH, sent },
11380 { WM_GETTEXT, sent|optional },
11381 { 0 }
11384 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
11386 /* dummy window proc for WM_GETTEXTLENGTH test */
11387 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
11389 switch(msg)
11391 case WM_GETTEXTLENGTH:
11392 return lstrlenW(dummy_window_text) + 37; /* some random length */
11393 case WM_GETTEXT:
11394 lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
11395 return lstrlenW( (LPWSTR)lp );
11396 default:
11397 return DefWindowProcW( hwnd, msg, wp, lp );
11401 static void test_message_conversion(void)
11403 static const WCHAR wszMsgConversionClass[] =
11404 {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
11405 char buffer[200];
11406 DEV_BROADCAST_DEVICEINTERFACE_A *dev_interface = (void *)buffer;
11407 WNDCLASSW cls;
11408 LRESULT lRes;
11409 HWND hwnd;
11410 WNDPROC wndproc, newproc;
11411 BOOL ret;
11413 cls.style = 0;
11414 cls.lpfnWndProc = MsgConversionProcW;
11415 cls.cbClsExtra = 0;
11416 cls.cbWndExtra = 0;
11417 cls.hInstance = GetModuleHandleW(NULL);
11418 cls.hIcon = NULL;
11419 cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
11420 cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
11421 cls.lpszMenuName = NULL;
11422 cls.lpszClassName = wszMsgConversionClass;
11423 /* this call will fail on Win9x, but that doesn't matter as this test is
11424 * meaningless on those platforms */
11425 if(!RegisterClassW(&cls)) return;
11427 hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
11428 100, 100, 200, 200, 0, 0, 0, NULL);
11429 ok(hwnd != NULL, "Window creation failed\n");
11431 /* {W, A} -> A */
11433 wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
11434 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
11435 ok(lRes == 0, "String should have been converted\n");
11436 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
11437 ok(lRes == 1, "String shouldn't have been converted\n");
11439 /* {W, A} -> W */
11441 wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
11442 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
11443 ok(lRes == 1, "String shouldn't have been converted\n");
11444 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
11445 ok(lRes == 1, "String shouldn't have been converted\n");
11447 /* Synchronous messages */
11449 lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
11450 ok(lRes == 0, "String should have been converted\n");
11451 lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
11452 ok(lRes == 1, "String shouldn't have been converted\n");
11454 /* Asynchronous messages */
11456 SetLastError(0);
11457 lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
11458 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
11459 "PostMessage on sync only message returned %Id, last error %ld\n", lRes, GetLastError());
11460 SetLastError(0);
11461 lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
11462 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
11463 "PostMessage on sync only message returned %Id, last error %ld\n", lRes, GetLastError());
11464 SetLastError(0);
11465 lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
11466 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
11467 "PosThreadtMessage on sync only message returned %Id, last error %ld\n", lRes, GetLastError());
11468 SetLastError(0);
11469 lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
11470 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
11471 "PosThreadtMessage on sync only message returned %Id, last error %ld\n", lRes, GetLastError());
11472 SetLastError(0);
11473 lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
11474 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
11475 "SendNotifyMessage on sync only message returned %Id, last error %ld\n", lRes, GetLastError());
11476 SetLastError(0);
11477 lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
11478 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
11479 "SendNotifyMessage on sync only message returned %Id, last error %ld\n", lRes, GetLastError());
11480 SetLastError(0);
11481 lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
11482 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
11483 "SendMessageCallback on sync only message returned %Id, last error %ld\n", lRes, GetLastError());
11484 SetLastError(0);
11485 lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
11486 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
11487 "SendMessageCallback on sync only message returned %Id, last error %ld\n", lRes, GetLastError());
11489 /* Test WM_DEVICECHANGE. */
11491 dev_interface->dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
11492 dev_interface->dbcc_reserved = 0;
11493 dev_interface->dbcc_classguid = iface_guid;
11494 strcpy(dev_interface->dbcc_name, "test name");
11495 dev_interface->dbcc_size = offsetof(DEV_BROADCAST_DEVICEINTERFACE_A,
11496 dbcc_name[strlen(dev_interface->dbcc_name)]);
11497 lRes = SendMessageA(hwnd, WM_DEVICECHANGE, DBT_DEVICEARRIVAL, (LPARAM)dev_interface);
11498 ok(lRes == 2, "Got %Id, error %lu.\n", lRes, GetLastError());
11500 DestroyWindow(hwnd);
11502 /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
11504 hwnd = CreateWindowW (testWindowClassW, wszUnicode,
11505 WS_OVERLAPPEDWINDOW,
11506 100, 100, 200, 200, 0, 0, 0, NULL);
11507 ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError());
11508 flush_sequence();
11509 lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
11510 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
11511 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
11512 "got bad length %Id\n", lRes );
11514 flush_sequence();
11515 lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
11516 hwnd, WM_GETTEXTLENGTH, 0, 0);
11517 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
11518 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
11519 "got bad length %Id\n", lRes );
11521 wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
11522 newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
11523 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
11524 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
11525 NULL, 0, NULL, NULL ) ||
11526 broken(lRes == lstrlenW(dummy_window_text) + 37),
11527 "got bad length %Id\n", lRes );
11529 SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc ); /* restore old wnd proc */
11530 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
11531 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
11532 NULL, 0, NULL, NULL ) ||
11533 broken(lRes == lstrlenW(dummy_window_text) + 37),
11534 "got bad length %Id\n", lRes );
11536 ret = DestroyWindow(hwnd);
11537 ok( ret, "DestroyWindow() error %ld\n", GetLastError());
11540 struct timer_info
11542 HWND hWnd;
11543 HANDLE handles[2];
11544 DWORD id;
11547 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
11551 #define TIMER_ID 0x19
11552 #define TIMER_COUNT 500 /* 499 samples */
11553 #define TIMER_DURATION_EXPECTED 10000 /* 10 ms */
11554 #define TIMER_DURATION_ALT 15600 /* 15.6 ms */
11555 #define TIMER_DURATION_TOLERANCE 1000 /* 1 ms */
11557 static int count = 0;
11558 static ULONGLONG timer_ticks[TIMER_COUNT];
11559 static int timer_duration = 0;
11561 static int compare_ulonglong(const void *a, const void *b)
11563 ULONGLONG la, lb;
11564 la = *(ULONGLONG*)a;
11565 lb = *(ULONGLONG*)b;
11566 return (la > lb) - (la < lb);
11569 static void timer_fired(void)
11571 if (count < TIMER_COUNT)
11573 LARGE_INTEGER performance_counter;
11574 BOOL ret;
11576 ret = QueryPerformanceCounter(&performance_counter);
11577 ok(ret, "QueryPerformanceCounter failed\n");
11579 timer_ticks[count] = performance_counter.QuadPart;
11582 count++;
11584 if (count == TIMER_COUNT)
11586 LARGE_INTEGER performance_frequency;
11587 BOOL ret;
11589 /* calculate durations */
11590 for (int i=0; i < TIMER_COUNT-1; i++)
11591 timer_ticks[i] = timer_ticks[i+1] - timer_ticks[i];
11593 qsort(timer_ticks, TIMER_COUNT - 1, sizeof(timer_ticks[0]), compare_ulonglong);
11595 ret = QueryPerformanceFrequency(&performance_frequency);
11596 ok(ret, "QueryPerformanceFrequency failed\n");
11598 /* median duration, converted to microseconds */
11599 timer_duration = (int)(timer_ticks[(TIMER_COUNT - 1) / 2] * 1000000 / performance_frequency.QuadPart);
11603 static void CALLBACK callback_count(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
11605 timer_fired();
11608 static DWORD exception;
11609 static void CALLBACK callback_exception(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
11611 timer_fired();
11612 RaiseException(exception, 0, 0, NULL);
11615 static DWORD WINAPI timer_thread_proc(LPVOID x)
11617 struct timer_info *info = x;
11618 DWORD r;
11620 r = KillTimer(info->hWnd, 0x19);
11621 ok(r,"KillTimer failed in thread\n");
11622 r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
11623 ok(r,"SetTimer failed in thread\n");
11624 ok(r==TIMER_ID,"SetTimer id different\n");
11625 r = SetEvent(info->handles[0]);
11626 ok(r,"SetEvent failed in thread\n");
11627 return 0;
11630 static void test_timers(void)
11632 struct timer_info info;
11633 DWORD id;
11634 MSG msg;
11636 info.hWnd = CreateWindowA("TestWindowClass", NULL,
11637 WS_OVERLAPPEDWINDOW ,
11638 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
11639 NULL, NULL, 0);
11641 info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
11642 ok(info.id, "SetTimer failed\n");
11643 ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
11644 info.handles[0] = CreateEventW(NULL,0,0,NULL);
11645 info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
11647 WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
11649 WaitForSingleObject(info.handles[1], INFINITE);
11651 CloseHandle(info.handles[0]);
11652 CloseHandle(info.handles[1]);
11654 ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
11656 /* Check the minimum allowed timeout for a timer. MSDN indicates that it should be 10.0 ms,
11657 * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to
11658 * 15.6 ms.
11660 count = 0;
11661 id = SetTimer(info.hWnd, TIMER_ID, 0, callback_count);
11662 ok(id != 0, "did not get id from SetTimer.\n");
11663 ok(id==TIMER_ID, "SetTimer timer ID different\n");
11664 while (count < TIMER_COUNT && GetMessageA(&msg, info.hWnd, 0, 0))
11665 DispatchMessageA(&msg);
11666 ok(abs(timer_duration-TIMER_DURATION_EXPECTED) < TIMER_DURATION_TOLERANCE /* xp, win7 */
11667 || broken(abs(timer_duration - TIMER_DURATION_ALT) < TIMER_DURATION_TOLERANCE) /* most common */,
11668 "did not get expected median timeout (%d != ~%d).\n",
11669 timer_duration, TIMER_DURATION_EXPECTED);
11670 ok(KillTimer(info.hWnd, id), "KillTimer failed\n");
11671 /* Perform the same check on SetSystemTimer (only available on w2k3 and older) */
11672 if (pSetSystemTimer)
11674 count = 0;
11675 id = pSetSystemTimer(info.hWnd, TIMER_ID, 0, callback_count);
11676 ok(id != 0, "did not get id from SetSystemTimer.\n");
11677 ok(id==TIMER_ID, "SetTimer timer ID different\n");
11678 while (count < TIMER_COUNT && GetMessageA(&msg, info.hWnd, 0, 0))
11680 if (msg.message == WM_SYSTIMER)
11681 timer_fired();
11682 ok(msg.message != WM_TIMER, "unexpected WM_TIMER\n");
11683 DispatchMessageA(&msg);
11685 ok(abs(timer_duration-TIMER_DURATION_EXPECTED) < TIMER_DURATION_TOLERANCE
11686 || broken(abs(timer_duration - TIMER_DURATION_ALT) < TIMER_DURATION_TOLERANCE) /* most common */,
11687 "did not get expected median timeout (%d != ~%d).\n",
11688 timer_duration, TIMER_DURATION_EXPECTED);
11689 ok(pKillSystemTimer(info.hWnd, id), "KillSystemTimer failed\n");
11692 ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
11695 static void test_timers_no_wnd(void)
11697 static UINT_PTR ids[0xffff];
11698 UINT_PTR id, id2;
11699 DWORD start;
11700 MSG msg;
11701 int i;
11703 count = 0;
11704 id = SetTimer(NULL, 0, 100, callback_count);
11705 ok(id != 0, "did not get id from SetTimer.\n");
11706 id2 = SetTimer(NULL, id, 200, callback_count);
11707 ok(id2 == id, "did not get same id from SetTimer when replacing (%Ii expected %Ii).\n", id2, id);
11708 Sleep(150);
11709 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
11710 ok(count == 0, "did not get zero count as expected (%i).\n", count);
11711 Sleep(150);
11712 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
11713 ok(count == 1, "did not get one count as expected (%i).\n", count);
11714 KillTimer(NULL, id);
11715 Sleep(250);
11716 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
11717 ok(count == 1, "killing replaced timer did not work (%i).\n", count);
11719 /* Check the minimum allowed timeout for a timer. MSDN indicates that it should be 10.0 ms,
11720 * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to
11721 * 15.6 ms.
11723 count = 0;
11724 id = SetTimer(NULL, 0, 0, callback_count);
11725 ok(id != 0, "did not get id from SetTimer.\n");
11726 while (count < TIMER_COUNT && GetMessageA(&msg, NULL, 0, 0))
11727 DispatchMessageA(&msg);
11728 ok(abs(timer_duration-TIMER_DURATION_EXPECTED) < TIMER_DURATION_TOLERANCE /* xp */
11729 || broken(abs(timer_duration - TIMER_DURATION_ALT) < TIMER_DURATION_TOLERANCE) /* most common */,
11730 "did not get expected median timeout (%d != ~%d).\n",
11731 timer_duration, TIMER_DURATION_EXPECTED);
11732 KillTimer(NULL, id);
11733 /* Note: SetSystemTimer doesn't support a NULL window, see test_timers */
11735 if (pSetCoalescableTimer)
11737 count = 0;
11738 id = pSetCoalescableTimer(NULL, 0, 0, callback_count, 0);
11739 ok(id != 0, "SetCoalescableTimer failed with %lu.\n", GetLastError());
11740 start = GetTickCount();
11741 while (GetTickCount()-start < 100 && GetMessageA(&msg, NULL, 0, 0))
11742 DispatchMessageA(&msg);
11743 ok(count > 1, "expected count > 1, got %d.\n", count);
11744 KillTimer(NULL, id);
11746 else
11747 win_skip("SetCoalescableTimer not available.\n");
11749 /* Check what happens when we're running out of timers */
11750 for (i = 0; i < ARRAY_SIZE(ids); i++)
11752 SetLastError(0xdeadbeef);
11753 ids[i] = SetTimer(NULL, 0, USER_TIMER_MAXIMUM, tfunc);
11754 if (!ids[i]) break;
11756 ok(i != ARRAY_SIZE(ids), "all timers were created successfully\n");
11757 ok(GetLastError()==ERROR_NO_MORE_USER_HANDLES || broken(GetLastError()==0xdeadbeef),
11758 "GetLastError() = %ld\n", GetLastError());
11759 while (i > 0) KillTimer(NULL, ids[--i]);
11762 static void test_timers_exception(DWORD code)
11764 UINT_PTR id;
11765 MSG msg;
11767 exception = code;
11768 id = SetTimer(NULL, 0, 1000, callback_exception);
11769 ok(id != 0, "did not get id from SetTimer.\n");
11771 memset(&msg, 0, sizeof(msg));
11772 msg.message = WM_TIMER;
11773 msg.wParam = id;
11774 msg.lParam = (LPARAM)callback_exception;
11776 count = 0;
11777 DispatchMessageA(&msg);
11778 ok(count == 1, "did not get one count as expected (%i).\n", count);
11780 KillTimer(NULL, id);
11783 static void test_timers_exceptions(void)
11785 test_timers_exception(EXCEPTION_ACCESS_VIOLATION);
11786 test_timers_exception(EXCEPTION_DATATYPE_MISALIGNMENT);
11787 test_timers_exception(EXCEPTION_BREAKPOINT);
11788 test_timers_exception(EXCEPTION_SINGLE_STEP);
11789 test_timers_exception(EXCEPTION_ARRAY_BOUNDS_EXCEEDED);
11790 test_timers_exception(EXCEPTION_FLT_DENORMAL_OPERAND);
11791 test_timers_exception(EXCEPTION_FLT_DIVIDE_BY_ZERO);
11792 test_timers_exception(EXCEPTION_FLT_INEXACT_RESULT);
11793 test_timers_exception(EXCEPTION_ILLEGAL_INSTRUCTION);
11794 test_timers_exception(0xE000BEEF); /* customer exception */
11797 /* Various win events with arbitrary parameters */
11798 static const struct message WmWinEventsSeq[] = {
11799 { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
11800 { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
11801 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
11802 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
11803 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
11804 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
11805 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
11806 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
11807 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
11808 /* our win event hook ignores OBJID_CURSOR events */
11809 /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
11810 { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
11811 { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
11812 { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
11813 { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
11814 { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
11815 { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
11816 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
11817 { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
11818 { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
11819 { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
11820 { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
11821 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
11822 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
11823 { 0 }
11825 static const struct message WmWinEventCaretSeq[] = {
11826 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
11827 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
11828 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
11829 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
11830 { 0 }
11832 static const struct message WmWinEventCaretSeq_2[] = {
11833 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
11834 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
11835 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
11836 { 0 }
11838 static const struct message WmWinEventAlertSeq[] = {
11839 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
11840 { 0 }
11842 static const struct message WmWinEventAlertSeq_2[] = {
11843 /* create window in the thread proc */
11844 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
11845 /* our test event */
11846 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
11847 { 0 }
11849 static const struct message WmGlobalHookSeq_1[] = {
11850 /* create window in the thread proc */
11851 { HCBT_CREATEWND, hook|lparam, 0, 2 },
11852 /* our test events */
11853 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
11854 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
11855 { 0 }
11857 static const struct message WmGlobalHookSeq_2[] = {
11858 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
11859 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
11860 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
11861 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
11862 { 0 }
11865 static const struct message WmMouseLLHookSeq[] = {
11866 { WM_MOUSEMOVE, hook },
11867 { WM_LBUTTONUP, hook },
11868 { WM_MOUSEMOVE, hook },
11869 { 0 }
11872 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
11873 DWORD event,
11874 HWND hwnd,
11875 LONG object_id,
11876 LONG child_id,
11877 DWORD thread_id,
11878 DWORD event_time)
11880 char buf[256];
11882 if (GetClassNameA(hwnd, buf, sizeof(buf)))
11884 if (!lstrcmpiA(buf, "TestWindowClass") ||
11885 !lstrcmpiA(buf, "static"))
11887 struct recvd_message msg;
11889 msg.hwnd = hwnd;
11890 msg.message = event;
11891 msg.flags = winevent_hook|wparam|lparam;
11892 msg.wParam = object_id;
11893 msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
11894 msg.descr = "WEH_2";
11895 add_message(&msg);
11900 static HHOOK hCBT_global_hook;
11901 static DWORD cbt_global_hook_thread_id;
11903 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
11905 HWND hwnd;
11906 char buf[256];
11908 if (nCode == HCBT_SYSCOMMAND)
11910 struct recvd_message msg;
11912 msg.hwnd = 0;
11913 msg.message = nCode;
11914 msg.flags = hook|wparam|lparam;
11915 msg.wParam = wParam;
11916 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
11917 msg.descr = "CBT_2";
11918 add_message(&msg);
11920 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
11922 /* WH_MOUSE_LL hook */
11923 if (nCode == HC_ACTION)
11925 MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
11927 /* we can't test for real mouse events */
11928 if (mhll->flags & LLMHF_INJECTED)
11930 struct recvd_message msg;
11932 memset (&msg, 0, sizeof (msg));
11933 msg.message = wParam;
11934 msg.flags = hook;
11935 msg.descr = "CBT_2";
11936 add_message(&msg);
11938 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
11941 /* Log also SetFocus(0) calls */
11942 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
11944 if (GetClassNameA(hwnd, buf, sizeof(buf)))
11946 if (!lstrcmpiA(buf, "TestWindowClass") ||
11947 !lstrcmpiA(buf, "static"))
11949 struct recvd_message msg;
11951 msg.hwnd = hwnd;
11952 msg.message = nCode;
11953 msg.flags = hook|wparam|lparam;
11954 msg.wParam = wParam;
11955 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
11956 msg.descr = "CBT_2";
11957 add_message(&msg);
11960 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
11963 static DWORD WINAPI win_event_global_thread_proc(void *param)
11965 HWND hwnd;
11966 MSG msg;
11967 HANDLE hevent = *(HANDLE *)param;
11969 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
11970 ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError());
11971 if (winetest_debug > 1) trace("created thread window %p\n", hwnd);
11973 *(HWND *)param = hwnd;
11975 flush_sequence();
11976 /* this event should be received only by our new hook proc,
11977 * an old one does not expect an event from another thread.
11979 pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
11980 SetEvent(hevent);
11982 while (GetMessageA(&msg, 0, 0, 0))
11984 TranslateMessage(&msg);
11985 DispatchMessageA(&msg);
11987 return 0;
11990 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
11992 HWND hwnd;
11993 MSG msg;
11994 HANDLE hevent = *(HANDLE *)param;
11996 flush_sequence();
11997 /* these events should be received only by our new hook proc,
11998 * an old one does not expect an event from another thread.
12001 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
12002 ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError());
12003 if (winetest_debug > 1) trace("created thread window %p\n", hwnd);
12005 *(HWND *)param = hwnd;
12007 /* Windows doesn't like when a thread plays games with the focus,
12008 that leads to all kinds of misbehaviours and failures to activate
12009 a window. So, better keep next lines commented out.
12010 SetFocus(0);
12011 SetFocus(hwnd);*/
12013 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
12014 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
12016 SetEvent(hevent);
12018 while (GetMessageA(&msg, 0, 0, 0))
12020 TranslateMessage(&msg);
12021 DispatchMessageA(&msg);
12023 return 0;
12026 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
12028 HWND hwnd;
12029 MSG msg;
12030 HANDLE hevent = *(HANDLE *)param;
12032 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
12033 ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError());
12034 if (winetest_debug > 1) trace("created thread window %p\n", hwnd);
12036 *(HWND *)param = hwnd;
12038 flush_sequence();
12040 /* Windows doesn't like when a thread plays games with the focus,
12041 * that leads to all kinds of misbehaviours and failures to activate
12042 * a window. So, better don't generate a mouse click message below.
12044 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
12045 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
12046 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
12048 SetEvent(hevent);
12049 while (GetMessageA(&msg, 0, 0, 0))
12051 TranslateMessage(&msg);
12052 DispatchMessageA(&msg);
12054 return 0;
12057 static void test_winevents(void)
12059 BOOL ret;
12060 MSG msg;
12061 HWND hwnd, hwnd2;
12062 UINT i;
12063 HANDLE hthread, hevent;
12064 DWORD tid;
12065 HWINEVENTHOOK hhook;
12066 const struct message *events = WmWinEventsSeq;
12068 hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
12069 WS_OVERLAPPEDWINDOW,
12070 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
12071 NULL, NULL, 0);
12072 ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError());
12074 /****** start of global hook test *************/
12075 hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
12076 if (!hCBT_global_hook)
12078 ok(DestroyWindow(hwnd), "failed to destroy window\n");
12079 skip( "cannot set global hook\n" );
12080 return;
12083 hevent = CreateEventA(NULL, 0, 0, NULL);
12084 ok(!!hevent, "Failed to create event, error %lu.\n", GetLastError());
12085 hwnd2 = hevent;
12087 hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
12088 ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError());
12090 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
12092 ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
12094 flush_sequence();
12095 /* this one should be received only by old hook proc */
12096 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
12097 /* this one should be received only by old hook proc */
12098 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
12100 ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
12102 ret = UnhookWindowsHookEx(hCBT_global_hook);
12103 ok( ret, "UnhookWindowsHookEx error %ld\n", GetLastError());
12105 PostThreadMessageA(tid, WM_QUIT, 0, 0);
12106 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
12107 CloseHandle(hthread);
12108 CloseHandle(hevent);
12109 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
12110 /****** end of global hook test *************/
12112 if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
12114 ok(DestroyWindow(hwnd), "failed to destroy window\n");
12115 return;
12118 flush_sequence();
12120 if (0)
12122 /* this test doesn't pass under Win9x */
12123 /* win2k ignores events with hwnd == 0 */
12124 SetLastError(0xdeadbeef);
12125 pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
12126 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
12127 GetLastError() == 0xdeadbeef, /* Win9x */
12128 "unexpected error %ld\n", GetLastError());
12129 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
12132 for (i = 0; i < ARRAY_SIZE(WmWinEventsSeq); i++)
12133 pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
12135 ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
12137 /****** start of event filtering test *************/
12138 hhook = pSetWinEventHook(
12139 EVENT_OBJECT_SHOW, /* 0x8002 */
12140 EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
12141 GetModuleHandleA(0), win_event_global_hook_proc,
12142 GetCurrentProcessId(), 0,
12143 WINEVENT_INCONTEXT);
12144 ok(hhook != 0, "SetWinEventHook error %ld\n", GetLastError());
12146 hevent = CreateEventA(NULL, 0, 0, NULL);
12147 ok(!!hevent, "Failed to create event, error %lu.\n", GetLastError());
12148 hwnd2 = hevent;
12150 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
12151 ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError());
12153 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
12155 ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
12157 flush_sequence();
12158 /* this one should be received only by old hook proc */
12159 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
12160 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
12161 /* this one should be received only by old hook proc */
12162 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
12164 ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
12166 ret = pUnhookWinEvent(hhook);
12167 ok( ret, "UnhookWinEvent error %ld\n", GetLastError());
12169 PostThreadMessageA(tid, WM_QUIT, 0, 0);
12170 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
12171 CloseHandle(hthread);
12172 CloseHandle(hevent);
12173 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
12174 /****** end of event filtering test *************/
12176 /****** start of out of context event test *************/
12177 hhook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0,
12178 win_event_global_hook_proc, GetCurrentProcessId(), 0,
12179 WINEVENT_OUTOFCONTEXT);
12180 ok(hhook != 0, "SetWinEventHook error %ld\n", GetLastError());
12182 hevent = CreateEventA(NULL, 0, 0, NULL);
12183 ok(!!hevent, "Failed to create event, error %lu.\n", GetLastError());
12184 hwnd2 = hevent;
12186 flush_sequence();
12188 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
12189 ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError());
12191 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
12193 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
12194 /* process pending winevent messages */
12195 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
12196 ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
12198 flush_sequence();
12199 /* this one should be received only by old hook proc */
12200 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
12201 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
12202 /* this one should be received only by old hook proc */
12203 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
12205 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
12206 /* process pending winevent messages */
12207 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
12208 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
12210 ret = pUnhookWinEvent(hhook);
12211 ok( ret, "UnhookWinEvent error %ld\n", GetLastError());
12213 PostThreadMessageA(tid, WM_QUIT, 0, 0);
12214 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
12215 CloseHandle(hthread);
12216 CloseHandle(hevent);
12217 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
12218 /****** end of out of context event test *************/
12220 /****** start of MOUSE_LL hook test *************/
12221 hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
12222 /* WH_MOUSE_LL is not supported on Win9x platforms */
12223 if (!hCBT_global_hook)
12225 win_skip("Skipping WH_MOUSE_LL test on this platform\n");
12226 goto skip_mouse_ll_hook_test;
12229 hevent = CreateEventA(NULL, 0, 0, NULL);
12230 ok(!!hevent, "Failed to create event, error %lu.\n", GetLastError());
12231 hwnd2 = hevent;
12233 hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
12234 ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError());
12236 while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
12237 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
12239 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
12240 flush_sequence();
12242 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
12243 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
12244 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
12246 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
12248 ret = UnhookWindowsHookEx(hCBT_global_hook);
12249 ok( ret, "UnhookWindowsHookEx error %ld\n", GetLastError());
12251 PostThreadMessageA(tid, WM_QUIT, 0, 0);
12252 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
12253 CloseHandle(hthread);
12254 CloseHandle(hevent);
12255 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
12256 /****** end of MOUSE_LL hook test *************/
12257 skip_mouse_ll_hook_test:
12259 ok(DestroyWindow(hwnd), "failed to destroy window\n");
12262 static char *get_test_dll_path(void)
12264 static const char *dll_name = "testdll.dll";
12265 static char path[MAX_PATH];
12266 DWORD written;
12267 HANDLE file;
12268 HRSRC res;
12269 void *ptr;
12271 GetTempPathA(ARRAY_SIZE(path), path);
12272 strcat(path, dll_name);
12274 file = CreateFileA(path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
12275 ok(file != INVALID_HANDLE_VALUE, "Failed to create file %s: %lu.\n", debugstr_a(path), GetLastError());
12277 res = FindResourceA(NULL, dll_name, "TESTDLL");
12278 ok(!!res, "Failed to load resource: %lu\n", GetLastError());
12279 ptr = LockResource(LoadResource(GetModuleHandleA(NULL), res));
12280 WriteFile(file, ptr, SizeofResource(GetModuleHandleA(NULL), res), &written, NULL);
12281 ok(written == SizeofResource(GetModuleHandleA(NULL), res), "Failed to write resource\n");
12282 CloseHandle(file);
12284 return path;
12287 static void test_set_hook(void)
12289 LRESULT (CALLBACK *p_dummy_hook_proc)(int code, WPARAM wp, LPARAM lp);
12290 HMODULE test_dll_module;
12291 char *test_dll_path;
12292 DWORD error;
12293 BOOL ret;
12294 HHOOK hhook;
12295 HWINEVENTHOOK hwinevent_hook;
12296 int i;
12298 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
12299 ok(hhook != 0, "local hook does not require hModule set to 0\n");
12300 UnhookWindowsHookEx(hhook);
12302 SetLastError(0xdeadbeef);
12303 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
12304 ok(!hhook, "global hook requires hModule != 0\n");
12305 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %ld\n", GetLastError());
12307 SetLastError(0xdeadbeef);
12308 hhook = SetWindowsHookExA(WH_JOURNALRECORD, cbt_hook_proc, 0, 0);
12309 ok(!hhook, "global hook requires hModule != 0\n");
12310 ok(GetLastError() == ERROR_ACCESS_DENIED, "unexpected error %ld\n", GetLastError());
12312 SetLastError(0xdeadbeef);
12313 hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
12314 ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
12315 ok(GetLastError() == ERROR_INVALID_FILTER_PROC, "unexpected error %ld\n", GetLastError());
12317 SetLastError(0xdeadbeef);
12318 ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
12319 ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE, "unexpected error %ld\n", GetLastError());
12321 test_dll_path = get_test_dll_path();
12322 test_dll_module = LoadLibraryA(test_dll_path);
12323 p_dummy_hook_proc = (void *)GetProcAddress(test_dll_module, "dummy_hook_proc");
12324 for (i = WH_MIN; i <= WH_MAX; i++)
12326 winetest_push_context("ID %d", i);
12328 /* Test that setting hooks should succeed for hook procs in a library. But for WH_JOURNALRECORD
12329 * and WH_JOURNALPLAYBACK, ERROR_ACCESS_DENIED is returned, even with administrator rights */
12330 SetLastError(0xdeadbeef);
12331 hhook = SetWindowsHookExA(i, p_dummy_hook_proc, test_dll_module, 0);
12332 error = GetLastError();
12333 if (i == WH_JOURNALRECORD || i == WH_JOURNALPLAYBACK)
12335 ok(!hhook, "SetWinEventHook succeeded.\n");
12336 ok(error == ERROR_ACCESS_DENIED, "Got unexpected error %ld.\n", GetLastError());
12338 else
12340 ok(!!hhook, "SetWinEventHook failed.\n");
12341 ok(error == NO_ERROR, "Got unexpected error %ld.\n", GetLastError());
12343 if (hhook)
12344 UnhookWindowsHookEx(hhook);
12346 /* Test settings global hooks with a thread ID */
12347 SetLastError(0xdeadbeef);
12348 hhook = SetWindowsHookExA(i, p_dummy_hook_proc, test_dll_module, GetCurrentThreadId());
12349 error = GetLastError();
12350 if (i == WH_JOURNALRECORD || i == WH_JOURNALPLAYBACK || i == WH_SYSMSGFILTER
12351 || i == WH_KEYBOARD_LL || i == WH_MOUSE_LL)
12353 ok(!hhook, "SetWinEventHook succeeded.\n");
12354 ok(error == ERROR_GLOBAL_ONLY_HOOK, "Got unexpected error %ld.\n", GetLastError());
12356 else
12358 ok(!!hhook, "SetWinEventHook failed.\n");
12359 ok(error == NO_ERROR, "Got unexpected error %ld.\n", GetLastError());
12361 if (hhook)
12362 UnhookWindowsHookEx(hhook);
12364 winetest_pop_context();
12366 FreeLibrary(test_dll_module);
12367 ret = DeleteFileA(test_dll_path);
12368 ok(ret, "Failed to remove the test dll, error %ld.\n", GetLastError());
12370 if (!pSetWinEventHook || !pUnhookWinEvent) return;
12372 /* even process local incontext hooks require hmodule */
12373 SetLastError(0xdeadbeef);
12374 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
12375 GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
12376 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
12377 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %ld\n", GetLastError());
12379 /* even thread local incontext hooks require hmodule */
12380 SetLastError(0xdeadbeef);
12381 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
12382 GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
12383 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
12384 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %ld\n", GetLastError());
12386 SetLastError(0xdeadbeef);
12387 hwinevent_hook = pSetWinEventHook(1, 0, 0, win_event_proc,
12388 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
12389 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
12390 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %ld\n", GetLastError());
12392 SetLastError(0xdeadbeef);
12393 hwinevent_hook = pSetWinEventHook(-1, 1, 0, win_event_proc,
12394 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
12395 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
12396 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %ld\n", GetLastError());
12398 SetLastError(0xdeadbeef);
12399 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
12400 0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
12401 ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
12402 todo_wine
12403 ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %ld\n", GetLastError());
12405 SetLastError(0xdeadbeef);
12406 hwinevent_hook = pSetWinEventHook(0, 0, 0, win_event_proc,
12407 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
12408 ok(hwinevent_hook != 0, "SetWinEventHook error %ld\n", GetLastError());
12409 ok(GetLastError() == 0xdeadbeef, "unexpected error %ld\n", GetLastError());
12410 ret = pUnhookWinEvent(hwinevent_hook);
12411 ok( ret, "UnhookWinEvent error %ld\n", GetLastError());
12413 todo_wine {
12414 /* This call succeeds under win2k SP4, but fails under Wine.
12415 Does win2k test/use passed process id? */
12416 SetLastError(0xdeadbeef);
12417 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
12418 0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
12419 ok(hwinevent_hook != 0, "SetWinEventHook error %ld\n", GetLastError());
12420 ok(GetLastError() == 0xdeadbeef, "unexpected error %ld\n", GetLastError());
12421 ret = pUnhookWinEvent(hwinevent_hook);
12422 ok( ret, "UnhookWinEvent error %ld\n", GetLastError());
12425 SetLastError(0xdeadbeef);
12426 ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
12427 ok(GetLastError() == ERROR_INVALID_HANDLE, "unexpected error %ld\n", GetLastError());
12430 static HWND hook_hwnd;
12431 static HHOOK recursive_hook;
12432 static int hook_depth, max_hook_depth;
12434 static LRESULT WINAPI rec_get_message_hook(int code, WPARAM w, LPARAM l)
12436 LRESULT res;
12437 MSG msg;
12438 BOOL b;
12440 hook_depth++;
12441 if(hook_depth > max_hook_depth)
12442 max_hook_depth = hook_depth;
12444 b = PeekMessageW(&msg, hook_hwnd, 0, 0, PM_NOREMOVE);
12445 ok(b, "PeekMessage failed\n");
12447 res = CallNextHookEx(recursive_hook, code, w, l);
12449 hook_depth--;
12450 return res;
12453 static void test_recursive_hook(void)
12455 MSG msg;
12456 BOOL b;
12458 hook_hwnd = CreateWindowA("Static", NULL, WS_POPUP, 0, 0, 200, 60, NULL, NULL, NULL, NULL);
12459 ok(hook_hwnd != NULL, "CreateWindow failed\n");
12461 recursive_hook = SetWindowsHookExW(WH_GETMESSAGE, rec_get_message_hook, NULL, GetCurrentThreadId());
12462 ok(recursive_hook != NULL, "SetWindowsHookEx failed\n");
12464 PostMessageW(hook_hwnd, WM_USER, 0, 0);
12465 PostMessageW(hook_hwnd, WM_USER+1, 0, 0);
12467 hook_depth = 0;
12468 GetMessageW(&msg, hook_hwnd, 0, 0);
12469 ok(15 <= max_hook_depth && max_hook_depth < 45, "max_hook_depth = %d\n", max_hook_depth);
12470 if (winetest_debug > 1) trace("max_hook_depth = %d\n", max_hook_depth);
12472 b = UnhookWindowsHookEx(recursive_hook);
12473 ok(b, "UnhokWindowsHookEx failed\n");
12475 DestroyWindow(hook_hwnd);
12478 static const struct message ScrollWindowPaint1[] = {
12479 { WM_PAINT, sent },
12480 { WM_ERASEBKGND, sent|beginpaint },
12481 { WM_GETTEXTLENGTH, sent|optional },
12482 { WM_PAINT, sent|optional },
12483 { WM_NCPAINT, sent|beginpaint|optional },
12484 { WM_GETTEXT, sent|beginpaint|optional },
12485 { WM_GETTEXT, sent|beginpaint|optional },
12486 { WM_GETTEXT, sent|beginpaint|optional },
12487 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
12488 { WM_ERASEBKGND, sent|beginpaint|optional },
12489 { 0 }
12492 static const struct message ScrollWindowPaint2[] = {
12493 { WM_PAINT, sent },
12494 { 0 }
12497 static void test_scrollwindowex(void)
12499 HWND hwnd, hchild;
12500 RECT rect={0,0,130,130};
12502 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
12503 WS_VISIBLE|WS_OVERLAPPEDWINDOW,
12504 100, 100, 200, 200, 0, 0, 0, NULL);
12505 ok (hwnd != 0, "Failed to create overlapped window\n");
12506 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
12507 WS_VISIBLE|WS_CAPTION|WS_CHILD,
12508 10, 10, 150, 150, hwnd, 0, 0, NULL);
12509 ok (hchild != 0, "Failed to create child\n");
12510 UpdateWindow(hwnd);
12511 flush_events();
12512 flush_sequence();
12514 /* scroll without the child window */
12515 if (winetest_debug > 1) trace("start scroll\n");
12516 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
12517 SW_ERASE|SW_INVALIDATE);
12518 ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
12519 if (winetest_debug > 1) trace("end scroll\n");
12520 flush_sequence();
12521 flush_events();
12522 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
12523 flush_events();
12524 flush_sequence();
12526 /* Now without the SW_ERASE flag */
12527 if (winetest_debug > 1) trace("start scroll\n");
12528 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
12529 ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
12530 if (winetest_debug > 1) trace("end scroll\n");
12531 flush_sequence();
12532 flush_events();
12533 ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", FALSE);
12534 flush_events();
12535 flush_sequence();
12537 /* now scroll the child window as well */
12538 if (winetest_debug > 1) trace("start scroll\n");
12539 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
12540 SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
12541 /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
12542 /* windows sometimes a WM_MOVE */
12543 ok_sequence(WmEmptySeq, "ScrollWindowEx", TRUE);
12544 if (winetest_debug > 1) trace("end scroll\n");
12545 flush_sequence();
12546 flush_events();
12547 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
12548 flush_events();
12549 flush_sequence();
12551 /* now scroll with ScrollWindow() */
12552 if (winetest_debug > 1) trace("start scroll with ScrollWindow\n");
12553 ScrollWindow( hwnd, 5, 5, NULL, NULL);
12554 if (winetest_debug > 1) trace("end scroll\n");
12555 flush_sequence();
12556 flush_events();
12557 ok_sequence(ScrollWindowPaint1, "ScrollWindow", FALSE);
12559 ok(DestroyWindow(hchild), "failed to destroy window\n");
12560 ok(DestroyWindow(hwnd), "failed to destroy window\n");
12561 flush_sequence();
12564 static const struct message destroy_window_with_children[] = {
12565 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* popup */
12566 { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
12567 { 0x0090, sent|optional },
12568 { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
12569 { 0x0090, sent|optional },
12570 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* popup */
12571 { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
12572 { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
12573 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
12574 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, /* parent */
12575 { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
12576 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
12577 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
12578 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
12579 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
12580 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
12581 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
12582 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
12583 { 0 }
12586 static void test_DestroyWindow(void)
12588 BOOL ret;
12589 HWND parent, child1, child2, child3, child4, test;
12590 UINT_PTR child_id = WND_CHILD_ID + 1;
12592 parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
12593 100, 100, 200, 200, 0, 0, 0, NULL);
12594 ok(!!parent, "Failed to create window, error %lu.\n", GetLastError());
12595 child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
12596 0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
12597 ok(!!child1, "Failed to create window, error %lu.\n", GetLastError());
12598 child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
12599 0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
12600 ok(!!child2, "Failed to create window, error %lu.\n", GetLastError());
12601 child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
12602 0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
12603 ok(!!child3, "Failed to create window, error %lu.\n", GetLastError());
12604 child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
12605 0, 0, 50, 50, parent, 0, 0, NULL);
12606 ok(!!child4, "Failed to create window, error %lu.\n", GetLastError());
12608 /* test owner/parent of child2 */
12609 test = GetParent(child2);
12610 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
12611 ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
12612 test = GetAncestor(child2, GA_PARENT);
12613 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
12614 test = GetWindow(child2, GW_OWNER);
12615 ok(!test, "wrong owner %p\n", test);
12617 test = SetParent(child2, parent);
12618 ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
12620 /* test owner/parent of the parent */
12621 test = GetParent(parent);
12622 ok(!test, "wrong parent %p\n", test);
12623 ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
12624 test = GetAncestor(parent, GA_PARENT);
12625 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
12626 test = GetWindow(parent, GW_OWNER);
12627 ok(!test, "wrong owner %p\n", test);
12629 /* test owner/parent of child1 */
12630 test = GetParent(child1);
12631 ok(test == parent, "wrong parent %p\n", test);
12632 ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
12633 test = GetAncestor(child1, GA_PARENT);
12634 ok(test == parent, "wrong parent %p\n", test);
12635 test = GetWindow(child1, GW_OWNER);
12636 ok(!test, "wrong owner %p\n", test);
12638 /* test owner/parent of child2 */
12639 test = GetParent(child2);
12640 ok(test == parent, "wrong parent %p\n", test);
12641 ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
12642 test = GetAncestor(child2, GA_PARENT);
12643 ok(test == parent, "wrong parent %p\n", test);
12644 test = GetWindow(child2, GW_OWNER);
12645 ok(!test, "wrong owner %p\n", test);
12647 /* test owner/parent of child3 */
12648 test = GetParent(child3);
12649 ok(test == child1, "wrong parent %p\n", test);
12650 ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
12651 test = GetAncestor(child3, GA_PARENT);
12652 ok(test == child1, "wrong parent %p\n", test);
12653 test = GetWindow(child3, GW_OWNER);
12654 ok(!test, "wrong owner %p\n", test);
12656 /* test owner/parent of child4 */
12657 test = GetParent(child4);
12658 ok(test == parent, "wrong parent %p\n", test);
12659 ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
12660 test = GetAncestor(child4, GA_PARENT);
12661 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
12662 test = GetWindow(child4, GW_OWNER);
12663 ok(test == parent, "wrong owner %p\n", test);
12665 flush_sequence();
12667 if (winetest_debug > 1) trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
12668 parent, child1, child2, child3, child4);
12670 SetCapture(child4);
12671 test = GetCapture();
12672 ok(test == child4, "wrong capture window %p\n", test);
12674 test_DestroyWindow_flag = TRUE;
12675 ret = DestroyWindow(parent);
12676 ok( ret, "DestroyWindow() error %ld\n", GetLastError());
12677 test_DestroyWindow_flag = FALSE;
12678 ok_sequence(destroy_window_with_children, "destroy window with children", FALSE);
12680 ok(!IsWindow(parent), "parent still exists\n");
12681 ok(!IsWindow(child1), "child1 still exists\n");
12682 ok(!IsWindow(child2), "child2 still exists\n");
12683 ok(!IsWindow(child3), "child3 still exists\n");
12684 ok(!IsWindow(child4), "child4 still exists\n");
12686 test = GetCapture();
12687 ok(!test, "wrong capture window %p\n", test);
12691 static const struct message WmDispatchPaint[] = {
12692 { WM_NCPAINT, sent },
12693 { WM_GETTEXT, sent|defwinproc|optional },
12694 { WM_GETTEXT, sent|defwinproc|optional },
12695 { WM_ERASEBKGND, sent },
12696 { 0 }
12699 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
12701 if (message == WM_PAINT) return 0;
12702 return MsgCheckProcA( hwnd, message, wParam, lParam );
12705 static void test_DispatchMessage(void)
12707 RECT rect;
12708 MSG msg;
12709 int count;
12710 HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
12711 100, 100, 200, 200, 0, 0, 0, NULL);
12712 ShowWindow( hwnd, SW_SHOW );
12713 UpdateWindow( hwnd );
12714 flush_events();
12715 flush_sequence();
12716 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
12718 SetRect( &rect, -5, -5, 5, 5 );
12719 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
12720 count = 0;
12721 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
12723 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
12724 else
12726 flush_sequence();
12727 DispatchMessageA( &msg );
12728 /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
12729 if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
12730 else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
12731 if (++count > 10) break;
12734 ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
12736 if (winetest_debug > 1) trace("now without DispatchMessage\n");
12737 flush_sequence();
12738 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
12739 count = 0;
12740 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
12742 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
12743 else
12745 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
12746 flush_sequence();
12747 /* this will send WM_NCCPAINT just like DispatchMessage does */
12748 GetUpdateRgn( hwnd, hrgn, TRUE );
12749 ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
12750 DeleteObject( hrgn );
12751 GetClientRect( hwnd, &rect );
12752 ValidateRect( hwnd, &rect ); /* this will stop WM_PAINTs */
12753 ok( !count, "Got multiple WM_PAINTs\n" );
12754 if (++count > 10) break;
12758 flush_sequence();
12759 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
12760 count = 0;
12761 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
12763 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
12764 else
12766 HDC hdc;
12768 flush_sequence();
12769 hdc = BeginPaint( hwnd, NULL );
12770 ok( !hdc, "got valid hdc %p from BeginPaint\n", hdc );
12771 ok( !EndPaint( hwnd, NULL ), "EndPaint succeeded\n" );
12772 ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
12773 ok( !count, "Got multiple WM_PAINTs\n" );
12774 if (++count > 10) break;
12777 DestroyWindow(hwnd);
12781 static const struct message WmUser[] = {
12782 { WM_USER, sent },
12783 { 0 }
12786 struct sendmsg_info
12788 HWND hwnd;
12789 DWORD timeout;
12790 DWORD ret;
12791 HANDLE ready;
12794 static DWORD CALLBACK send_msg_thread( LPVOID arg )
12796 struct sendmsg_info *info = arg;
12797 SetLastError( 0xdeadbeef );
12798 SetEvent( info->ready );
12799 info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
12800 if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT ||
12801 broken(GetLastError() == 0), /* win9x */
12802 "unexpected error %ld\n", GetLastError());
12803 return 0;
12806 static void wait_for_thread( HANDLE thread )
12808 while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
12810 MSG msg;
12811 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA(&msg);
12815 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
12817 if (message == WM_USER) Sleep(200);
12818 return MsgCheckProcA( hwnd, message, wParam, lParam );
12821 static void test_SendMessageTimeout(void)
12823 HANDLE thread;
12824 struct sendmsg_info info;
12825 DWORD tid;
12826 BOOL is_win9x;
12828 info.ready = CreateEventA( NULL, 0, 0, NULL );
12829 info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
12830 100, 100, 200, 200, 0, 0, 0, NULL);
12831 flush_events();
12832 flush_sequence();
12834 info.timeout = 1000;
12835 info.ret = 0xdeadbeef;
12836 ResetEvent( info.ready );
12837 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
12838 WaitForSingleObject( info.ready, INFINITE );
12839 wait_for_thread( thread );
12840 CloseHandle( thread );
12841 ok( info.ret == 1, "SendMessageTimeout failed\n" );
12842 ok_sequence( WmUser, "WmUser", FALSE );
12844 info.timeout = 1;
12845 info.ret = 0xdeadbeef;
12846 ResetEvent( info.ready );
12847 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
12848 WaitForSingleObject( info.ready, INFINITE );
12849 Sleep(100); /* SendMessageTimeout should time out here */
12850 wait_for_thread( thread );
12851 CloseHandle( thread );
12852 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
12853 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
12855 /* 0 means infinite timeout (but not on win9x) */
12856 info.timeout = 0;
12857 info.ret = 0xdeadbeef;
12858 ResetEvent( info.ready );
12859 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
12860 WaitForSingleObject( info.ready, INFINITE );
12861 Sleep(100);
12862 wait_for_thread( thread );
12863 CloseHandle( thread );
12864 is_win9x = !info.ret;
12865 if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
12866 else ok_sequence( WmUser, "WmUser", FALSE );
12868 /* timeout is treated as signed despite the prototype (but not on win9x) */
12869 info.timeout = 0x7fffffff;
12870 info.ret = 0xdeadbeef;
12871 ResetEvent( info.ready );
12872 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
12873 WaitForSingleObject( info.ready, INFINITE );
12874 Sleep(100);
12875 wait_for_thread( thread );
12876 CloseHandle( thread );
12877 ok( info.ret == 1, "SendMessageTimeout failed\n" );
12878 ok_sequence( WmUser, "WmUser", FALSE );
12880 info.timeout = 0x80000000;
12881 info.ret = 0xdeadbeef;
12882 ResetEvent( info.ready );
12883 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
12884 WaitForSingleObject( info.ready, INFINITE );
12885 Sleep(100);
12886 wait_for_thread( thread );
12887 CloseHandle( thread );
12888 if (is_win9x)
12890 ok( info.ret == 1, "SendMessageTimeout failed\n" );
12891 ok_sequence( WmUser, "WmUser", FALSE );
12893 else
12895 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
12896 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
12899 /* now check for timeout during message processing */
12900 SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
12901 info.timeout = 100;
12902 info.ret = 0xdeadbeef;
12903 ResetEvent( info.ready );
12904 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
12905 WaitForSingleObject( info.ready, INFINITE );
12906 wait_for_thread( thread );
12907 CloseHandle( thread );
12908 /* we should time out but still get the message */
12909 ok( info.ret == 0, "SendMessageTimeout failed\n" );
12910 ok_sequence( WmUser, "WmUser", FALSE );
12912 DestroyWindow( info.hwnd );
12913 CloseHandle( info.ready );
12917 /****************** edit message test *************************/
12918 #define ID_EDIT 0x1234
12919 static const struct message sl_edit_setfocus[] =
12921 { HCBT_SETFOCUS, hook },
12922 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
12923 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
12924 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
12925 { WM_SETFOCUS, sent|wparam, 0 },
12926 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
12927 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
12928 { WM_CTLCOLOREDIT, sent|parent },
12929 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
12930 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
12931 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
12932 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
12933 { 0 }
12935 static const struct message sl_edit_invisible[] =
12937 { HCBT_SETFOCUS, hook },
12938 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
12939 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
12940 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Sent for IME. */
12941 { WM_KILLFOCUS, sent|parent },
12942 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
12943 { WM_SETFOCUS, sent },
12944 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
12945 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
12946 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
12947 { 0 }
12949 static const struct message ml_edit_setfocus[] =
12951 { HCBT_SETFOCUS, hook },
12952 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
12953 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
12954 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
12955 { WM_SETFOCUS, sent|wparam, 0 },
12956 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
12957 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
12958 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
12959 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
12960 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CARET, 0 },
12961 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
12962 { 0 }
12964 static const struct message sl_edit_killfocus[] =
12966 { HCBT_SETFOCUS, hook },
12967 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
12968 { WM_KILLFOCUS, sent|wparam, 0 },
12969 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
12970 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
12971 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
12972 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
12973 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
12974 { 0 }
12976 static const struct message sl_edit_lbutton_dblclk[] =
12978 { WM_LBUTTONDBLCLK, sent },
12979 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
12980 { 0 }
12982 static const struct message sl_edit_lbutton_down[] =
12984 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
12985 { HCBT_SETFOCUS, hook },
12986 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
12987 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
12988 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
12989 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
12990 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
12991 { WM_CTLCOLOREDIT, sent|parent },
12992 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
12993 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
12994 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CARET, 0 },
12995 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
12996 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
12997 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
12998 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
12999 { WM_CTLCOLOREDIT, sent|parent|optional },
13000 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
13001 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CARET, 0 },
13002 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
13003 { 0 }
13005 static const struct message ml_edit_lbutton_down[] =
13007 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
13008 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13009 { HCBT_SETFOCUS, hook },
13010 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
13011 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13012 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
13013 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
13014 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
13015 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
13016 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
13017 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
13018 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
13019 { 0 }
13021 static const struct message sl_edit_lbutton_up[] =
13023 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
13024 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
13025 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13026 { WM_CAPTURECHANGED, sent|defwinproc },
13027 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
13028 { 0 }
13030 static const struct message ml_edit_lbutton_up[] =
13032 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
13033 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
13034 { WM_CAPTURECHANGED, sent|defwinproc },
13035 { 0 }
13038 static WNDPROC old_edit_proc;
13040 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13042 static LONG defwndproc_counter = 0;
13043 LRESULT ret;
13044 struct recvd_message msg;
13046 if (ignore_message( message )) return 0;
13048 msg.hwnd = hwnd;
13049 msg.message = message;
13050 msg.flags = sent|wparam|lparam;
13051 if (defwndproc_counter) msg.flags |= defwinproc;
13052 msg.wParam = wParam;
13053 msg.lParam = lParam;
13054 msg.descr = "edit";
13055 add_message(&msg);
13057 defwndproc_counter++;
13058 ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
13059 defwndproc_counter--;
13061 return ret;
13064 static const struct message edit_wm_ime_composition_seq[] =
13066 {WM_IME_STARTCOMPOSITION, sent},
13067 {WM_IME_COMPOSITION, sent | wparam, 'W'},
13068 {WM_IME_CHAR, sent | wparam | defwinproc, 'W'},
13069 {WM_IME_CHAR, sent | wparam | defwinproc, 'i'},
13070 {WM_IME_CHAR, sent | wparam | defwinproc, 'n'},
13071 {WM_IME_CHAR, sent | wparam | defwinproc, 'e'},
13072 {WM_IME_ENDCOMPOSITION, sent},
13073 {WM_CHAR, sent | wparam, 'W'},
13074 {WM_CHAR, sent | wparam, 'i'},
13075 {WM_CHAR, sent | wparam, 'n'},
13076 {WM_CHAR, sent | wparam, 'e'},
13080 static const struct message edit_wm_ime_composition_korean_seq[] =
13082 {WM_IME_ENDCOMPOSITION, sent},
13083 {WM_IME_COMPOSITION, sent | wparam, 'W'},
13084 {WM_IME_CHAR, sent | wparam | defwinproc, 'W'},
13085 {WM_IME_CHAR, sent | wparam | defwinproc, 'i'},
13086 {WM_IME_CHAR, sent | wparam | defwinproc, 'n'},
13087 {WM_IME_CHAR, sent | wparam | defwinproc, 'e'},
13088 {WM_CHAR, sent | wparam, 'W'},
13089 {WM_CHAR, sent | wparam, 'i'},
13090 {WM_CHAR, sent | wparam, 'n'},
13091 {WM_CHAR, sent | wparam, 'e'},
13095 static const struct message edit_wm_ime_char_seq[] =
13097 {WM_IME_CHAR, sent | wparam, '0'},
13098 {WM_CHAR, sent | wparam, '0'},
13102 static const struct message edit_eimes_getcompstratonce_seq[] =
13104 {WM_IME_STARTCOMPOSITION, sent},
13105 {WM_IME_COMPOSITION, sent | wparam, 'W'},
13106 {WM_IME_ENDCOMPOSITION, sent},
13110 static const struct message edit_eimes_getcompstratonce_korean_seq[] =
13112 {WM_IME_ENDCOMPOSITION, sent},
13113 {WM_IME_COMPOSITION, sent | wparam, 'W'},
13117 static LRESULT CALLBACK edit_ime_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13119 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
13120 static LONG defwndproc_counter = 0;
13121 struct recvd_message msg = {0};
13122 LRESULT ret;
13124 msg.message = message;
13125 msg.flags = sent | wparam;
13126 if (defwndproc_counter)
13127 msg.flags |= defwinproc;
13128 msg.wParam = wParam;
13130 if (message < 0xc000 &&
13131 message != WM_GETTEXTLENGTH &&
13132 message != WM_GETTEXT &&
13133 message != WM_GETFONT &&
13134 message != WM_GETICON &&
13135 message != WM_IME_SETCONTEXT &&
13136 message != WM_IME_NOTIFY &&
13137 message != WM_CTLCOLOREDIT &&
13138 message != WM_PAINT &&
13139 message != WM_ERASEBKGND &&
13140 message != WM_NCHITTEST &&
13141 message != WM_SETCURSOR &&
13142 message != WM_MOUSEMOVE &&
13143 message != WM_MOUSEACTIVATE &&
13144 message != WM_KEYUP &&
13145 (message < EM_GETSEL || message > EM_GETIMESTATUS))
13147 add_message(&msg);
13150 defwndproc_counter++;
13151 if (IsWindowUnicode(hwnd))
13152 ret = CallWindowProcW(oldproc, hwnd, message, wParam, lParam);
13153 else
13154 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
13155 defwndproc_counter--;
13157 return ret;
13160 static DWORD WINAPI test_edit_ime_messages(void *unused_arg)
13162 static const HKL korean_hkl = (HKL)0x04120412;
13163 WNDPROC old_proc;
13164 LRESULT lr;
13165 HIMC himc;
13166 HWND hwnd;
13167 BOOL ret;
13168 HKL hkl;
13169 MSG msg;
13171 hkl = GetKeyboardLayout(0);
13173 hwnd = CreateWindowA(WC_EDITA, "Test", WS_POPUP | WS_VISIBLE, 10, 10, 300, 300, NULL, NULL,
13174 NULL, NULL);
13175 ok(hwnd != NULL, "CreateWindowA failed.\n");
13177 /* Test EM_{GET|SET}IMESTATUS */
13178 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
13179 ok(lr == 0, "Got unexpected lr %#Ix.\n", lr);
13181 /* Note that EM_SETIMESTATUS always return 1, which is contrary to what MSDN says about
13182 * returning the previous LPARAM value */
13183 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_GETCOMPSTRATONCE);
13184 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
13185 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
13186 ok(lr == EIMES_GETCOMPSTRATONCE, "Got unexpected lr %#Ix.\n", lr);
13188 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_CANCELCOMPSTRINFOCUS);
13189 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
13190 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
13191 ok(lr == EIMES_CANCELCOMPSTRINFOCUS, "Got unexpected lr %#Ix.\n", lr);
13193 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_COMPLETECOMPSTRKILLFOCUS);
13194 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
13195 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
13196 ok(lr == EIMES_COMPLETECOMPSTRKILLFOCUS, "Got unexpected lr %#Ix.\n", lr);
13198 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_GETCOMPSTRATONCE
13199 | EIMES_CANCELCOMPSTRINFOCUS | EIMES_COMPLETECOMPSTRKILLFOCUS);
13200 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
13201 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
13202 ok(lr == (EIMES_GETCOMPSTRATONCE | EIMES_CANCELCOMPSTRINFOCUS | EIMES_COMPLETECOMPSTRKILLFOCUS),
13203 "Got unexpected lr %#Ix.\n", lr);
13205 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
13206 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
13207 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
13208 ok(lr == 0, "Got unexpected lr %#Ix.\n", lr);
13210 /* Invalid EM_{GET|SET}IMESTATUS status types and flags */
13211 lr = SendMessageA(hwnd, EM_GETIMESTATUS, 0, 0);
13212 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
13214 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING + 1, 0);
13215 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
13217 lr = SendMessageA(hwnd, EM_SETIMESTATUS, 0, EIMES_GETCOMPSTRATONCE);
13218 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
13219 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
13220 ok(lr == 0, "Got unexpected lr %#Ix.\n", lr);
13222 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING + 1, EIMES_GETCOMPSTRATONCE);
13223 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
13224 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
13225 ok(lr == 0, "Got unexpected lr %#Ix.\n", lr);
13227 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0xFFFFFFFF);
13228 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
13229 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
13230 ok(lr == 0xFFFF, "Got unexpected lr %#Ix.\n", lr);
13232 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
13233 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
13234 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
13235 ok(lr == 0, "Got unexpected lr %#Ix.\n", lr);
13237 /* Test IME messages when EIMES_GETCOMPSTRATONCE is not set */
13238 old_proc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)edit_ime_subclass_proc);
13239 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)old_proc);
13241 himc = ImmGetContext(hwnd);
13242 ret = ImmSetCompositionStringA(himc, SCS_SETSTR, "Wine", 4, NULL, 0);
13243 ok(ret, "ImmSetCompositionStringA failed.\n");
13244 flush_sequence();
13245 ret = ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
13246 ok(ret, "ImmNotifyIME failed.\n");
13247 /* Note that the following message loop is necessary to get the WM_CHAR messages because they
13248 * are posted. Same for the later message loops in this function. */
13249 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
13250 if (hkl == korean_hkl)
13251 ok_sequence(edit_wm_ime_composition_korean_seq,
13252 "korean WM_IME_COMPOSITION", TRUE);
13253 else
13254 ok_sequence(edit_wm_ime_composition_seq, "WM_IME_COMPOSITION", TRUE);
13256 /* Test that WM_IME_CHAR is passed to DefWindowProc() to get WM_CHAR */
13257 flush_sequence();
13258 SendMessageA(hwnd, WM_IME_CHAR, '0', 1);
13259 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
13260 ok_sequence(edit_wm_ime_char_seq, "WM_IME_CHAR", FALSE);
13262 /* Test IME messages when EIMES_GETCOMPSTRATONCE is set */
13263 lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_GETCOMPSTRATONCE);
13264 ok(lr == 1, "Got unexpected lr %#Ix.\n", lr);
13265 lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0);
13266 ok(lr == EIMES_GETCOMPSTRATONCE, "Got unexpected lr %#Ix.\n", lr);
13268 ret = ImmSetCompositionStringA(himc, SCS_SETSTR, "Wine", 4, NULL, 0);
13269 ok(ret, "ImmSetCompositionStringA failed.\n");
13270 flush_sequence();
13271 ret = ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
13272 ok(ret, "ImmNotifyIME failed.\n");
13273 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
13274 if (hkl == korean_hkl)
13275 ok_sequence(edit_eimes_getcompstratonce_korean_seq,
13276 "korean WM_IME_COMPOSITION with EIMES_GETCOMPSTRATONCE", TRUE);
13277 else
13278 ok_sequence(edit_eimes_getcompstratonce_seq,
13279 "WM_IME_COMPOSITION with EIMES_GETCOMPSTRATONCE", TRUE);
13281 /* Test that WM_IME_CHAR is passed to DefWindowProc() to get WM_CHAR with EIMES_GETCOMPSTRATONCE */
13282 flush_sequence();
13283 SendMessageA(hwnd, WM_IME_CHAR, '0', 1);
13284 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
13285 ok_sequence(edit_wm_ime_char_seq, "WM_IME_CHAR", FALSE);
13287 ImmReleaseContext(hwnd, himc);
13288 DestroyWindow(hwnd);
13289 return 0;
13292 static void subclass_edit(void)
13294 WNDCLASSA cls;
13295 BOOL ret;
13297 ret = GetClassInfoA(0, "edit", &cls);
13298 ok(ret, "Failed to get class info, error %lu.\n", GetLastError());
13300 old_edit_proc = cls.lpfnWndProc;
13302 cls.hInstance = GetModuleHandleA(NULL);
13303 cls.lpfnWndProc = edit_hook_proc;
13304 cls.lpszClassName = "my_edit_class";
13305 UnregisterClassA(cls.lpszClassName, cls.hInstance);
13306 register_class(&cls);
13309 static void test_edit_messages(void)
13311 HWND hwnd, parent;
13312 DWORD dlg_code;
13313 HANDLE thread;
13315 subclass_edit();
13316 log_all_parent_messages++;
13318 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13319 100, 100, 200, 200, 0, 0, 0, NULL);
13320 ok (parent != 0, "Failed to create parent window\n");
13322 /* test single line edit */
13323 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
13324 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
13325 ok(hwnd != 0, "Failed to create edit window\n");
13327 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
13328 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08lx\n", dlg_code);
13330 flush_sequence();
13331 SetFocus(hwnd);
13332 ok_sequence(sl_edit_invisible, "SetFocus(hwnd) on an invisible edit", FALSE);
13334 ShowWindow(hwnd, SW_SHOW);
13335 UpdateWindow(hwnd);
13336 SetFocus(0);
13337 flush_sequence();
13339 SetFocus(hwnd);
13340 ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
13342 SetFocus(0);
13343 ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
13345 SetFocus(0);
13346 ReleaseCapture();
13347 flush_sequence();
13349 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
13350 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
13352 SetFocus(0);
13353 ReleaseCapture();
13354 flush_sequence();
13356 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
13357 ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
13359 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
13360 ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
13362 DestroyWindow(hwnd);
13364 /* test multiline edit */
13365 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
13366 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
13367 ok(hwnd != 0, "Failed to create edit window\n");
13369 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
13370 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
13371 "wrong dlg_code %08lx\n", dlg_code);
13373 ShowWindow(hwnd, SW_SHOW);
13374 UpdateWindow(hwnd);
13375 SetFocus(0);
13376 flush_sequence();
13378 SetFocus(hwnd);
13379 ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
13381 SetFocus(0);
13382 ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
13384 SetFocus(0);
13385 ReleaseCapture();
13386 flush_sequence();
13388 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
13389 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
13391 SetFocus(0);
13392 ReleaseCapture();
13393 flush_sequence();
13395 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
13396 ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
13398 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
13399 ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
13401 DestroyWindow(hwnd);
13402 DestroyWindow(parent);
13404 log_all_parent_messages--;
13406 /* Test IME messages in another thread because IME is disabled in the current thread */
13407 thread = CreateThread(NULL, 0, test_edit_ime_messages, NULL, 0, NULL);
13408 WaitForSingleObject(thread, INFINITE);
13409 CloseHandle(thread);
13412 /**************************** End of Edit test ******************************/
13414 static const struct message WmKeyDownSkippedSeq[] =
13416 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
13417 { 0 }
13419 static const struct message WmKeyDownWasDownSkippedSeq[] =
13421 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x40000001 }, /* XP */
13422 { 0 }
13424 static const struct message WmKeyUpSkippedSeq[] =
13426 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
13427 { 0 }
13429 static const struct message WmUserKeyUpSkippedSeq[] =
13431 { WM_USER, sent },
13432 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
13433 { 0 }
13436 #define EV_STOP 0
13437 #define EV_SENDMSG 1
13438 #define EV_ACK 2
13440 struct peekmsg_info
13442 HWND hwnd;
13443 HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
13446 static DWORD CALLBACK send_msg_thread_2(void *param)
13448 DWORD ret;
13449 struct peekmsg_info *info = param;
13451 if (winetest_debug > 1) trace("thread: looping\n");
13452 SetEvent(info->hevent[EV_ACK]);
13454 while (1)
13456 ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
13458 switch (ret)
13460 case WAIT_OBJECT_0 + EV_STOP:
13461 if (winetest_debug > 1) trace("thread: exiting\n");
13462 return 0;
13464 case WAIT_OBJECT_0 + EV_SENDMSG:
13465 if (winetest_debug > 1) trace("thread: sending message\n");
13466 ret = SendNotifyMessageA(info->hwnd, WM_USER, 0, 0);
13467 ok(ret, "SendNotifyMessageA failed error %lu\n", GetLastError());
13468 SetEvent(info->hevent[EV_ACK]);
13469 break;
13471 default:
13472 ok(0, "Unexpected return %#lx.\n", ret);
13473 break;
13476 return 0;
13479 static void test_PeekMessage(void)
13481 MSG msg;
13482 HANDLE hthread;
13483 DWORD tid, qstatus;
13484 UINT qs_all_input = QS_ALLINPUT;
13485 UINT qs_input = QS_INPUT;
13486 BOOL ret, broken_flags = FALSE;
13487 struct peekmsg_info info;
13489 info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
13490 100, 100, 200, 200, 0, 0, 0, NULL);
13491 ok(!!info.hwnd, "Failed to create window, error %lu.\n", GetLastError());
13492 ShowWindow(info.hwnd, SW_SHOW);
13493 UpdateWindow(info.hwnd);
13494 SetFocus(info.hwnd);
13496 info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
13497 info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
13498 info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
13500 hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
13501 WaitForSingleObject(info.hevent[EV_ACK], 10000);
13503 flush_events();
13504 flush_sequence();
13506 SetLastError(0xdeadbeef);
13507 qstatus = GetQueueStatus(qs_all_input);
13508 if (GetLastError() == ERROR_INVALID_FLAGS)
13510 trace("QS_RAWINPUT not supported on this platform\n");
13511 qs_all_input &= ~QS_RAWINPUT;
13512 qs_input &= ~QS_RAWINPUT;
13514 SetLastError(0xdeadbeef);
13515 qstatus = GetQueueStatus(qs_all_input);
13516 if (GetLastError() == ERROR_INVALID_FLAGS)
13517 broken_flags = TRUE;
13518 ok(GetLastError() == 0xdeadbeef || broken(GetLastError() == ERROR_INVALID_FLAGS) /* win7 */,
13519 "wrong error %ld\n", GetLastError());
13521 if (qstatus & QS_POSTMESSAGE)
13523 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) /* nothing */ ;
13524 qstatus = GetQueueStatus(qs_all_input);
13526 ok(qstatus == 0, "wrong qstatus %08lx\n", qstatus);
13528 if (winetest_debug > 1) trace("signalling to send message\n");
13529 SetEvent(info.hevent[EV_SENDMSG]);
13530 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
13532 /* pass invalid QS_xxxx flags */
13533 SetLastError(0xdeadbeef);
13534 qstatus = GetQueueStatus(0xffffffff);
13535 ok(qstatus == 0 || broken(qstatus) /* win9x */, "GetQueueStatus should fail: %08lx\n", qstatus);
13536 if (!qstatus)
13538 ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %ld\n", GetLastError());
13539 SetLastError(0xdeadbeef);
13540 qstatus = GetQueueStatus(qs_all_input);
13541 ok(GetLastError() == 0xdeadbeef || broken(broken_flags && GetLastError() == ERROR_INVALID_FLAGS),
13542 "wrong error %ld\n", GetLastError());
13544 qstatus &= ~MAKELONG( 0x4000, 0x4000 ); /* sometimes set on Win95 */
13545 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE) ||
13546 broken(broken_flags && qstatus == 0),
13547 "wrong qstatus %08lx\n", qstatus);
13549 msg.message = 0;
13550 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
13551 ok(!ret,
13552 "PeekMessageA should have returned FALSE instead of msg %04x\n",
13553 msg.message);
13554 ok_sequence(WmUser, "WmUser", FALSE);
13556 qstatus = GetQueueStatus(qs_all_input);
13557 ok(qstatus == 0, "wrong qstatus %08lx\n", qstatus);
13559 keybd_event('N', 0, 0, 0);
13560 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
13561 qstatus = GetQueueStatus(qs_all_input);
13562 if (!(qstatus & MAKELONG(QS_KEY, QS_KEY)))
13564 skip( "queuing key events not supported\n" );
13565 goto done;
13567 ok(qstatus == MAKELONG(QS_KEY, QS_KEY) ||
13568 /* keybd_event seems to trigger a sent message on NT4 */
13569 qstatus == MAKELONG(QS_KEY|QS_SENDMESSAGE, QS_KEY|QS_SENDMESSAGE),
13570 "wrong qstatus %08lx\n", qstatus);
13572 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
13573 qstatus = GetQueueStatus(qs_all_input);
13574 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY) ||
13575 qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
13576 "wrong qstatus %08lx\n", qstatus);
13578 InvalidateRect(info.hwnd, NULL, FALSE);
13579 qstatus = GetQueueStatus(qs_all_input);
13580 ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY) ||
13581 qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
13582 "wrong qstatus %08lx\n", qstatus);
13584 if (winetest_debug > 1) trace("signalling to send message\n");
13585 SetEvent(info.hevent[EV_SENDMSG]);
13586 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
13588 qstatus = GetQueueStatus(qs_all_input);
13589 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
13590 "wrong qstatus %08lx\n", qstatus);
13592 msg.message = 0;
13593 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
13594 if (ret && msg.message == WM_CHAR)
13596 win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
13597 goto done;
13599 ok(!ret,
13600 "PeekMessageA should have returned FALSE instead of msg %04x\n",
13601 msg.message);
13602 if (!sequence_cnt) /* nt4 doesn't fetch anything with PM_QS_* flags */
13604 win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
13605 goto done;
13607 ok_sequence(WmUser, "WmUser", FALSE);
13609 qstatus = GetQueueStatus(qs_all_input);
13610 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
13611 "wrong qstatus %08lx\n", qstatus);
13613 if (winetest_debug > 1) trace("signalling to send message\n");
13614 SetEvent(info.hevent[EV_SENDMSG]);
13615 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
13617 qstatus = GetQueueStatus(qs_all_input);
13618 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
13619 "wrong qstatus %08lx\n", qstatus);
13621 msg.message = 0;
13622 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE );
13623 ok(!ret,
13624 "PeekMessageA should have returned FALSE instead of msg %04x\n",
13625 msg.message);
13626 ok_sequence(WmUser, "WmUser", FALSE);
13628 qstatus = GetQueueStatus(qs_all_input);
13629 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
13630 "wrong qstatus %08lx\n", qstatus);
13632 msg.message = 0;
13633 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
13634 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
13635 "got %d and %04x wParam %08Ix instead of TRUE and WM_CHAR wParam 'z'\n",
13636 ret, msg.message, msg.wParam);
13637 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
13639 qstatus = GetQueueStatus(qs_all_input);
13640 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
13641 "wrong qstatus %08lx\n", qstatus);
13643 msg.message = 0;
13644 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
13645 ok(!ret,
13646 "PeekMessageA should have returned FALSE instead of msg %04x\n",
13647 msg.message);
13648 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
13650 qstatus = GetQueueStatus(qs_all_input);
13651 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
13652 "wrong qstatus %08lx\n", qstatus);
13654 msg.message = 0;
13655 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
13656 ok(ret && msg.message == WM_PAINT,
13657 "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
13658 DispatchMessageA(&msg);
13659 ok_sequence(WmPaint, "WmPaint", FALSE);
13661 qstatus = GetQueueStatus(qs_all_input);
13662 ok(qstatus == MAKELONG(0, QS_KEY),
13663 "wrong qstatus %08lx\n", qstatus);
13665 msg.message = 0;
13666 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
13667 ok(!ret,
13668 "PeekMessageA should have returned FALSE instead of msg %04x\n",
13669 msg.message);
13670 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
13672 qstatus = GetQueueStatus(qs_all_input);
13673 ok(qstatus == MAKELONG(0, QS_KEY),
13674 "wrong qstatus %08lx\n", qstatus);
13676 if (winetest_debug > 1) trace("signalling to send message\n");
13677 SetEvent(info.hevent[EV_SENDMSG]);
13678 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
13680 qstatus = GetQueueStatus(qs_all_input);
13681 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
13682 "wrong qstatus %08lx\n", qstatus);
13684 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
13686 qstatus = GetQueueStatus(qs_all_input);
13687 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
13688 "wrong qstatus %08lx\n", qstatus);
13690 msg.message = 0;
13691 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
13692 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
13693 "got %d and %04x wParam %08Ix instead of TRUE and WM_CHAR wParam 'z'\n",
13694 ret, msg.message, msg.wParam);
13695 ok_sequence(WmUser, "WmUser", FALSE);
13697 qstatus = GetQueueStatus(qs_all_input);
13698 ok(qstatus == MAKELONG(0, QS_KEY),
13699 "wrong qstatus %08lx\n", qstatus);
13701 msg.message = 0;
13702 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
13703 ok(!ret,
13704 "PeekMessageA should have returned FALSE instead of msg %04x\n",
13705 msg.message);
13706 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
13708 qstatus = GetQueueStatus(qs_all_input);
13709 ok(qstatus == MAKELONG(0, QS_KEY),
13710 "wrong qstatus %08lx\n", qstatus);
13712 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
13714 qstatus = GetQueueStatus(qs_all_input);
13715 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
13716 "wrong qstatus %08lx\n", qstatus);
13718 if (winetest_debug > 1) trace("signalling to send message\n");
13719 SetEvent(info.hevent[EV_SENDMSG]);
13720 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
13722 qstatus = GetQueueStatus(qs_all_input);
13723 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
13724 "wrong qstatus %08lx\n", qstatus);
13726 msg.message = 0;
13727 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
13728 ok(!ret,
13729 "PeekMessageA should have returned FALSE instead of msg %04x\n",
13730 msg.message);
13731 ok_sequence(WmUser, "WmUser", FALSE);
13733 qstatus = GetQueueStatus(qs_all_input);
13734 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
13735 "wrong qstatus %08lx\n", qstatus);
13737 msg.message = 0;
13738 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
13739 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
13740 else /* workaround for a missing QS_RAWINPUT support */
13741 ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
13742 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
13743 "got %d and %04x wParam %08Ix instead of TRUE and WM_KEYDOWN wParam 'N'\n",
13744 ret, msg.message, msg.wParam);
13745 ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
13747 qstatus = GetQueueStatus(qs_all_input);
13748 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
13749 "wrong qstatus %08lx\n", qstatus);
13751 msg.message = 0;
13752 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
13753 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
13754 else /* workaround for a missing QS_RAWINPUT support */
13755 ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
13756 ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
13757 "got %d and %04x wParam %08Ix instead of TRUE and WM_KEYUP wParam 'N'\n",
13758 ret, msg.message, msg.wParam);
13759 ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
13761 qstatus = GetQueueStatus(qs_all_input);
13762 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
13763 "wrong qstatus %08lx\n", qstatus);
13765 msg.message = 0;
13766 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
13767 ok(!ret,
13768 "PeekMessageA should have returned FALSE instead of msg %04x\n",
13769 msg.message);
13770 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
13772 qstatus = GetQueueStatus(qs_all_input);
13773 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
13774 "wrong qstatus %08lx\n", qstatus);
13776 msg.message = 0;
13777 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
13778 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
13779 "got %d and %04x wParam %08Ix instead of TRUE and WM_CHAR wParam 'z'\n",
13780 ret, msg.message, msg.wParam);
13781 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
13783 qstatus = GetQueueStatus(qs_all_input);
13784 ok(qstatus == 0,
13785 "wrong qstatus %08lx\n", qstatus);
13787 msg.message = 0;
13788 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
13789 ok(!ret,
13790 "PeekMessageA should have returned FALSE instead of msg %04x\n",
13791 msg.message);
13792 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
13794 qstatus = GetQueueStatus(qs_all_input);
13795 ok(qstatus == 0,
13796 "wrong qstatus %08lx\n", qstatus);
13798 /* test whether presence of the quit flag in the queue affects
13799 * the queue state
13801 PostQuitMessage(0x1234abcd);
13803 qstatus = GetQueueStatus(qs_all_input);
13804 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
13805 "wrong qstatus %08lx\n", qstatus);
13807 PostMessageA(info.hwnd, WM_USER, 0, 0);
13809 qstatus = GetQueueStatus(qs_all_input);
13810 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
13811 "wrong qstatus %08lx\n", qstatus);
13813 msg.message = 0;
13814 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
13815 ok(ret && msg.message == WM_USER,
13816 "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
13817 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
13819 qstatus = GetQueueStatus(qs_all_input);
13820 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
13821 "wrong qstatus %08lx\n", qstatus);
13823 msg.message = 0;
13824 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
13825 ok(ret && msg.message == WM_QUIT,
13826 "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
13827 ok(msg.wParam == 0x1234abcd, "got wParam %08Ix instead of 0x1234abcd\n", msg.wParam);
13828 ok(msg.lParam == 0, "got lParam %08Ix instead of 0\n", msg.lParam);
13829 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
13831 qstatus = GetQueueStatus(qs_all_input);
13832 todo_wine {
13833 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
13834 "wrong qstatus %08lx\n", qstatus);
13837 msg.message = 0;
13838 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
13839 ok(!ret,
13840 "PeekMessageA should have returned FALSE instead of msg %04x\n",
13841 msg.message);
13842 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
13844 qstatus = GetQueueStatus(qs_all_input);
13845 ok(qstatus == 0,
13846 "wrong qstatus %08lx\n", qstatus);
13848 /* some GetMessage tests */
13850 keybd_event('N', 0, 0, 0);
13851 qstatus = GetQueueStatus(qs_all_input);
13852 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08lx\n", qstatus);
13854 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
13855 qstatus = GetQueueStatus(qs_all_input);
13856 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08lx\n", qstatus);
13858 if (qstatus)
13860 ret = GetMessageA( &msg, 0, 0, 0 );
13861 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
13862 "got %d and %04x wParam %08Ix instead of TRUE and WM_CHAR wParam 'z'\n",
13863 ret, msg.message, msg.wParam);
13864 qstatus = GetQueueStatus(qs_all_input);
13865 ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08lx\n", qstatus);
13868 if (qstatus)
13870 ret = GetMessageA( &msg, 0, 0, 0 );
13871 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
13872 "got %d and %04x wParam %08Ix instead of TRUE and WM_KEYDOWN wParam 'N'\n",
13873 ret, msg.message, msg.wParam);
13874 ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
13875 qstatus = GetQueueStatus(qs_all_input);
13876 ok(qstatus == 0, "wrong qstatus %08lx\n", qstatus);
13879 keybd_event('N', 0, 0, 0);
13880 qstatus = GetQueueStatus(qs_all_input);
13881 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08lx\n", qstatus);
13883 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
13884 qstatus = GetQueueStatus(qs_all_input);
13885 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08lx\n", qstatus);
13887 if (qstatus & (QS_KEY << 16))
13889 ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
13890 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
13891 "got %d and %04x wParam %08Ix instead of TRUE and WM_KEYDOWN wParam 'N'\n",
13892 ret, msg.message, msg.wParam);
13893 ok_sequence(WmKeyDownWasDownSkippedSeq, "WmKeyDownWasDownSkippedSeq", FALSE);
13894 qstatus = GetQueueStatus(qs_all_input);
13895 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08lx\n", qstatus);
13898 if (qstatus)
13900 ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
13901 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
13902 "got %d and %04x wParam %08Ix instead of TRUE and WM_CHAR wParam 'z'\n",
13903 ret, msg.message, msg.wParam);
13904 qstatus = GetQueueStatus(qs_all_input);
13905 ok(qstatus == 0, "wrong qstatus %08lx\n", qstatus);
13908 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
13909 qstatus = GetQueueStatus(qs_all_input);
13910 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08lx\n", qstatus);
13912 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
13913 qstatus = GetQueueStatus(qs_all_input);
13914 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08lx\n", qstatus);
13916 if (winetest_debug > 1) trace("signalling to send message\n");
13917 SetEvent(info.hevent[EV_SENDMSG]);
13918 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
13919 qstatus = GetQueueStatus(qs_all_input);
13920 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
13921 "wrong qstatus %08lx\n", qstatus);
13923 if (qstatus & (QS_KEY << 16))
13925 ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
13926 ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
13927 "got %d and %04x wParam %08Ix instead of TRUE and WM_KEYDOWN wParam 'N'\n",
13928 ret, msg.message, msg.wParam);
13929 ok_sequence(WmUserKeyUpSkippedSeq, "WmUserKeyUpSkippedSeq", FALSE);
13930 qstatus = GetQueueStatus(qs_all_input);
13931 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08lx\n", qstatus);
13934 if (qstatus)
13936 ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
13937 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
13938 "got %d and %04x wParam %08Ix instead of TRUE and WM_CHAR wParam 'z'\n",
13939 ret, msg.message, msg.wParam);
13940 qstatus = GetQueueStatus(qs_all_input);
13941 ok(qstatus == 0, "wrong qstatus %08lx\n", qstatus);
13944 PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
13945 ret = PeekMessageA(&msg, (HWND)-1, 0, 0, PM_NOREMOVE);
13946 ok(ret == TRUE, "wrong ret %d\n", ret);
13947 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
13948 ret = GetMessageA(&msg, (HWND)-1, 0, 0);
13949 ok(ret == TRUE, "wrong ret %d\n", ret);
13950 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
13952 PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
13953 ret = PeekMessageA(&msg, (HWND)1, 0, 0, PM_NOREMOVE);
13954 ok(ret == TRUE, "wrong ret %d\n", ret);
13955 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
13956 ret = GetMessageA(&msg, (HWND)1, 0, 0);
13957 ok(ret == TRUE, "wrong ret %d\n", ret);
13958 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
13960 PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
13961 ret = PeekMessageA(&msg, (HWND)0xffff, 0, 0, PM_NOREMOVE);
13962 ok(ret == TRUE, "wrong ret %d\n", ret);
13963 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
13964 ret = GetMessageA(&msg, (HWND)0xffff, 0, 0);
13965 ok(ret == TRUE, "wrong ret %d\n", ret);
13966 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
13968 done:
13969 if (winetest_debug > 1) trace("signalling to exit\n");
13970 SetEvent(info.hevent[EV_STOP]);
13972 WaitForSingleObject(hthread, INFINITE);
13974 CloseHandle(hthread);
13975 CloseHandle(info.hevent[0]);
13976 CloseHandle(info.hevent[1]);
13977 CloseHandle(info.hevent[2]);
13979 DestroyWindow(info.hwnd);
13982 static void wait_move_event(HWND hwnd, int x, int y)
13984 MSG msg;
13985 DWORD timeout = GetTickCount() + 500;
13986 BOOL ret;
13987 int delay;
13989 while ((delay = timeout - GetTickCount()) > 0)
13991 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
13992 if (ret && msg.pt.x > x && msg.pt.y > y) break;
13993 if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, delay, QS_ALLINPUT );
13994 else Sleep( delay );
13998 #define STEP 5
13999 static void test_PeekMessage2(void)
14001 HWND hwnd;
14002 BOOL ret;
14003 MSG msg;
14004 UINT message;
14005 DWORD time1, time2, time3;
14006 int x1, y1, x2, y2, x3, y3;
14007 POINT pos;
14009 time1 = time2 = time3 = 0;
14010 x1 = y1 = x2 = y2 = x3 = y3 = 0;
14012 /* Initialise window and make sure it is ready for events */
14013 hwnd = CreateWindowA("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
14014 10, 10, 800, 800, NULL, NULL, NULL, NULL);
14015 ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError());
14016 if (winetest_debug > 1) trace("Window for test_PeekMessage2 %p\n", hwnd);
14017 ShowWindow(hwnd, SW_SHOW);
14018 UpdateWindow(hwnd);
14019 SetFocus(hwnd);
14020 GetCursorPos(&pos);
14021 SetCursorPos(100, 100);
14022 mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
14023 flush_events();
14025 /* Do initial mousemove, wait until we can see it
14026 and then do our test peek with PM_NOREMOVE. */
14027 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
14028 wait_move_event(hwnd, 100-STEP, 100-STEP);
14030 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
14031 if (!ret)
14033 skip( "queuing mouse events not supported\n" );
14034 goto done;
14036 else
14038 if (winetest_debug > 1) trace("1st move event: %04x %lx %ld %ld\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
14039 message = msg.message;
14040 time1 = msg.time;
14041 x1 = msg.pt.x;
14042 y1 = msg.pt.y;
14043 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
14046 /* Allow time to advance a bit, and then simulate the user moving their
14047 * mouse around. After that we peek again with PM_NOREMOVE.
14048 * Although the previous mousemove message was never removed, the
14049 * mousemove we now peek should reflect the recent mouse movements
14050 * because the input queue will merge the move events. */
14051 Sleep(100);
14052 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
14053 wait_move_event(hwnd, x1, y1);
14055 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
14056 ok(ret, "no message available\n");
14057 if (ret) {
14058 if (winetest_debug > 1) trace("2nd move event: %04x %lx %ld %ld\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
14059 message = msg.message;
14060 time2 = msg.time;
14061 x2 = msg.pt.x;
14062 y2 = msg.pt.y;
14063 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
14064 ok(time2 > time1, "message time not advanced: %lx %lx\n", time1, time2);
14065 ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
14068 /* Have another go, to drive the point home */
14069 Sleep(100);
14070 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
14071 wait_move_event(hwnd, x2, y2);
14073 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
14074 ok(ret, "no message available\n");
14075 if (ret) {
14076 if (winetest_debug > 1) trace("3rd move event: %04x %lx %ld %ld\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
14077 message = msg.message;
14078 time3 = msg.time;
14079 x3 = msg.pt.x;
14080 y3 = msg.pt.y;
14081 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
14082 ok(time3 > time2, "message time not advanced: %lx %lx\n", time2, time3);
14083 ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
14086 done:
14087 DestroyWindow(hwnd);
14088 SetCursorPos(pos.x, pos.y);
14089 flush_events();
14092 static void test_PeekMessage3(void)
14094 HWND parent_hwnd, hwnd;
14095 BOOL ret;
14096 MSG msg;
14098 parent_hwnd = CreateWindowA("SimpleWindowClass", "PeekMessage3", WS_OVERLAPPEDWINDOW,
14099 10, 10, 800, 800, NULL, NULL, NULL, NULL);
14100 ok(parent_hwnd != NULL, "expected parent_hwnd != NULL\n");
14102 hwnd = CreateWindowA("TestWindowClass", "PeekMessage3", WS_CHILD, 0, 0, 1, 1,
14103 parent_hwnd, NULL, NULL, NULL);
14104 ok(hwnd != NULL, "expected hwnd != NULL\n");
14106 flush_events();
14108 /* GetMessage() and PeekMessage(..., PM_REMOVE) should prefer messages which
14109 * were already seen. */
14111 SetTimer(hwnd, 1, 100, NULL);
14112 while (!PeekMessageA(&msg, hwnd, 0, 0, PM_NOREMOVE));
14113 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14114 PostMessageA(hwnd, WM_USER, 0, 0);
14115 ret = PeekMessageA(&msg, hwnd, 0, 0, PM_NOREMOVE);
14116 todo_wine
14117 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14118 ret = GetMessageA(&msg, hwnd, 0, 0);
14119 todo_wine
14120 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14121 ret = GetMessageA(&msg, hwnd, 0, 0);
14122 todo_wine
14123 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
14124 ret = PeekMessageA(&msg, hwnd, 0, 0, 0);
14125 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
14127 SetTimer(hwnd, 1, 100, NULL);
14128 while (!PeekMessageA(&msg, hwnd, 0, 0, PM_NOREMOVE));
14129 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14130 PostMessageA(hwnd, WM_USER, 0, 0);
14131 ret = PeekMessageA(&msg, hwnd, 0, 0, PM_REMOVE);
14132 todo_wine
14133 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14134 ret = PeekMessageA(&msg, hwnd, 0, 0, PM_REMOVE);
14135 todo_wine
14136 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
14137 ret = PeekMessageA(&msg, hwnd, 0, 0, 0);
14138 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
14140 /* It doesn't matter if a message range is specified or not. */
14142 SetTimer(hwnd, 1, 100, NULL);
14143 while (!PeekMessageA(&msg, hwnd, WM_TIMER, WM_TIMER, PM_NOREMOVE));
14144 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14145 PostMessageA(hwnd, WM_USER, 0, 0);
14146 ret = GetMessageA(&msg, hwnd, 0, 0);
14147 todo_wine
14148 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14149 ret = GetMessageA(&msg, hwnd, 0, 0);
14150 todo_wine
14151 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
14152 ret = PeekMessageA(&msg, hwnd, 0, 0, 0);
14153 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
14155 /* But not if the post messages were added before the PeekMessage() call. */
14157 PostMessageA(hwnd, WM_USER, 0, 0);
14158 SetTimer(hwnd, 1, 100, NULL);
14159 while (!PeekMessageA(&msg, hwnd, WM_TIMER, WM_TIMER, PM_NOREMOVE));
14160 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14161 ret = GetMessageA(&msg, hwnd, 0, 0);
14162 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
14163 ret = GetMessageA(&msg, hwnd, 0, 0);
14164 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14165 ret = PeekMessageA(&msg, hwnd, 0, 0, 0);
14166 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
14168 /* More complicated test with multiple messages. */
14170 PostMessageA(hwnd, WM_USER, 0, 0);
14171 SetTimer(hwnd, 1, 100, NULL);
14172 while (!PeekMessageA(&msg, hwnd, WM_TIMER, WM_TIMER, PM_NOREMOVE));
14173 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14174 PostMessageA(hwnd, WM_USER + 1, 0, 0);
14175 ret = GetMessageA(&msg, hwnd, 0, 0);
14176 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
14177 ret = GetMessageA(&msg, hwnd, 0, 0);
14178 todo_wine
14179 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14180 ret = GetMessageA(&msg, hwnd, 0, 0);
14181 todo_wine
14182 ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message);
14183 ret = PeekMessageA(&msg, hwnd, 0, 0, 0);
14184 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
14186 /* Also works for posted messages, but the situation is a bit different,
14187 * because both messages are in the same queue. */
14189 PostMessageA(hwnd, WM_TIMER, 0, 0);
14190 while (!PeekMessageA(&msg, hwnd, WM_TIMER, WM_TIMER, PM_NOREMOVE));
14191 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14192 PostMessageA(hwnd, WM_USER, 0, 0);
14193 ret = GetMessageA(&msg, hwnd, 0, 0);
14194 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14195 ret = GetMessageA(&msg, hwnd, 0, 0);
14196 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
14197 ret = PeekMessageA(&msg, hwnd, 0, 0, 0);
14198 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
14200 PostMessageA(hwnd, WM_USER, 0, 0);
14201 PostMessageA(hwnd, WM_TIMER, 0, 0);
14202 while (!PeekMessageA(&msg, hwnd, WM_TIMER, WM_TIMER, PM_NOREMOVE));
14203 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14204 ret = GetMessageA(&msg, hwnd, 0, 0);
14205 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
14206 ret = GetMessageA(&msg, hwnd, 0, 0);
14207 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
14208 ret = PeekMessageA(&msg, hwnd, 0, 0, 0);
14209 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
14211 DestroyWindow(parent_hwnd);
14212 flush_events();
14215 static INT_PTR CALLBACK wm_quit_dlg_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
14217 struct recvd_message msg;
14219 if (ignore_message( message )) return 0;
14221 msg.hwnd = hwnd;
14222 msg.message = message;
14223 msg.flags = sent|wparam|lparam;
14224 msg.wParam = wp;
14225 msg.lParam = lp;
14226 msg.descr = "dialog";
14227 add_message(&msg);
14229 switch (message)
14231 case WM_INITDIALOG:
14232 PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
14233 PostMessageA(hwnd, WM_USER, 0xdead, 0xbeef);
14234 return 0;
14236 case WM_GETDLGCODE:
14237 return 0;
14239 case WM_USER:
14240 EndDialog(hwnd, 0);
14241 break;
14244 return 1;
14247 static const struct message WmQuitDialogSeq[] = {
14248 { HCBT_CREATEWND, hook },
14249 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
14250 { WM_SETFONT, sent },
14251 { WM_INITDIALOG, sent },
14252 { WM_CHANGEUISTATE, sent|optional },
14253 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14254 { HCBT_DESTROYWND, hook },
14255 { 0x0090, sent|optional }, /* Vista */
14256 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14257 { WM_DESTROY, sent },
14258 { WM_NCDESTROY, sent },
14259 { 0 }
14262 static const struct message WmStopQuitSeq[] = {
14263 { WM_DWMNCRENDERINGCHANGED, posted|optional },
14264 { WM_CLOSE, posted },
14265 { WM_QUIT, posted|wparam|lparam, 0x1234, 0 },
14266 { 0 }
14269 static void test_quit_message(void)
14271 MSG msg;
14272 BOOL ret;
14274 /* test using PostQuitMessage */
14275 flush_events();
14276 PostQuitMessage(0xbeef);
14278 msg.message = 0;
14279 ret = PeekMessageA(&msg, 0, 0, 0, PM_QS_SENDMESSAGE);
14280 ok(!ret, "got %x message\n", msg.message);
14282 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
14283 ok(ret, "PeekMessage failed with error %ld\n", GetLastError());
14284 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
14285 ok(msg.wParam == 0xbeef, "wParam was 0x%Ix instead of 0xbeef\n", msg.wParam);
14287 ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
14288 ok(ret, "PostMessage failed with error %ld\n", GetLastError());
14290 ret = GetMessageA(&msg, NULL, 0, 0);
14291 ok(ret > 0, "GetMessage failed with error %ld\n", GetLastError());
14292 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
14294 /* note: WM_QUIT message received after WM_USER message */
14295 ret = GetMessageA(&msg, NULL, 0, 0);
14296 ok(!ret, "GetMessage return %d with error %ld instead of FALSE\n", ret, GetLastError());
14297 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
14298 ok(msg.wParam == 0xbeef, "wParam was 0x%Ix instead of 0xbeef\n", msg.wParam);
14300 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
14301 ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
14303 /* now test with PostThreadMessage - different behaviour! */
14304 PostThreadMessageA(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
14306 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
14307 ok(ret, "PeekMessage failed with error %ld\n", GetLastError());
14308 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
14309 ok(msg.wParam == 0xdead, "wParam was 0x%Ix instead of 0xdead\n", msg.wParam);
14311 ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
14312 ok(ret, "PostMessage failed with error %ld\n", GetLastError());
14314 /* note: we receive the WM_QUIT message first this time */
14315 ret = GetMessageA(&msg, NULL, 0, 0);
14316 ok(!ret, "GetMessage return %d with error %ld instead of FALSE\n", ret, GetLastError());
14317 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
14318 ok(msg.wParam == 0xdead, "wParam was 0x%Ix instead of 0xdead\n", msg.wParam);
14320 ret = GetMessageA(&msg, NULL, 0, 0);
14321 ok(ret > 0, "GetMessage failed with error %ld\n", GetLastError());
14322 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
14324 flush_events();
14325 flush_sequence();
14326 ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, wm_quit_dlg_proc, 0);
14327 ok(ret == 1, "expected 1, got %d\n", ret);
14328 ok_sequence(WmQuitDialogSeq, "WmQuitDialogSeq", FALSE);
14329 memset(&msg, 0xab, sizeof(msg));
14330 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
14331 ok(ret, "PeekMessage failed\n");
14332 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
14333 ok(msg.wParam == 0x1234, "wParam was 0x%Ix instead of 0x1234\n", msg.wParam);
14334 ok(msg.lParam == 0, "lParam was 0x%Ix instead of 0\n", msg.lParam);
14336 /* Check what happens to a WM_QUIT message posted to a window that gets
14337 * destroyed.
14339 CreateWindowExA(0, "StopQuitClass", "Stop Quit Test", WS_OVERLAPPEDWINDOW,
14340 0, 0, 100, 100, NULL, NULL, NULL, NULL);
14341 flush_sequence();
14342 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
14344 struct recvd_message rmsg;
14345 rmsg.hwnd = msg.hwnd;
14346 rmsg.message = msg.message;
14347 rmsg.flags = posted|wparam|lparam;
14348 rmsg.wParam = msg.wParam;
14349 rmsg.lParam = msg.lParam;
14350 rmsg.descr = "stop/quit";
14351 if (msg.message == WM_QUIT)
14352 /* The hwnd can only be checked here */
14353 ok(!msg.hwnd, "The WM_QUIT hwnd was %p instead of NULL\n", msg.hwnd);
14354 add_message(&rmsg);
14355 DispatchMessageA(&msg);
14357 ok_sequence(WmStopQuitSeq, "WmStopQuitSeq", FALSE);
14360 static const struct message WmNotifySeq[] = {
14361 { WM_NOTIFY, sent|wparam|lparam, 0x1234, 0xdeadbeef },
14362 { 0 }
14365 static void test_notify_message(void)
14367 HWND hwnd;
14368 BOOL ret;
14369 MSG msg;
14371 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
14372 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0, NULL, NULL, 0);
14373 ok(hwnd != 0, "Failed to create window\n");
14374 flush_events();
14375 flush_sequence();
14377 ret = SendNotifyMessageA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
14378 ok(ret == TRUE, "SendNotifyMessageA failed with error %lu\n", GetLastError());
14379 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
14381 ret = SendNotifyMessageW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
14382 ok(ret == TRUE, "SendNotifyMessageW failed with error %lu\n", GetLastError());
14383 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
14385 ret = SendMessageCallbackA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef, NULL, 0);
14386 ok(ret == TRUE, "SendMessageCallbackA failed with error %lu\n", GetLastError());
14387 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
14389 ret = SendMessageCallbackW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef, NULL, 0);
14390 ok(ret == TRUE, "SendMessageCallbackW failed with error %lu\n", GetLastError());
14391 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
14393 ret = PostMessageA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
14394 ok(ret == TRUE, "PostMessageA failed with error %lu\n", GetLastError());
14395 flush_events();
14396 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
14398 ret = PostMessageW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
14399 ok(ret == TRUE, "PostMessageW failed with error %lu\n", GetLastError());
14400 flush_events();
14401 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
14403 ret = PostThreadMessageA(GetCurrentThreadId(), WM_NOTIFY, 0x1234, 0xdeadbeef);
14404 ok(ret == TRUE, "PostThreadMessageA failed with error %lu\n", GetLastError());
14405 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
14407 msg.hwnd = hwnd;
14408 DispatchMessageA(&msg);
14410 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
14412 ret = PostThreadMessageW(GetCurrentThreadId(), WM_NOTIFY, 0x1234, 0xdeadbeef);
14413 ok(ret == TRUE, "PostThreadMessageW failed with error %lu\n", GetLastError());
14414 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
14416 msg.hwnd = hwnd;
14417 DispatchMessageA(&msg);
14419 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
14421 DestroyWindow(hwnd);
14424 static const struct message WmMouseHoverSeq[] = {
14425 { WM_GETMINMAXINFO, sent|optional }, /* sometimes seen on w1064v1809 */
14426 { WM_MOUSEACTIVATE, sent|optional }, /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
14427 { WM_MOUSEACTIVATE, sent|optional },
14428 { WM_TIMER, sent|optional }, /* XP sends it */
14429 { WM_SYSTIMER, sent },
14430 { WM_MOUSEHOVER, sent|wparam, 0 },
14431 { 0 }
14434 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
14436 MSG msg;
14437 DWORD start_ticks, end_ticks;
14439 start_ticks = GetTickCount();
14440 /* add some deviation (50%) to cover not expected delays */
14441 start_ticks += timeout / 2;
14445 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
14447 /* Timer proc messages are not dispatched to the window proc,
14448 * and therefore not logged.
14450 if ((msg.message == WM_TIMER || msg.message == WM_SYSTIMER) && msg.hwnd)
14452 struct recvd_message s_msg;
14454 s_msg.hwnd = msg.hwnd;
14455 s_msg.message = msg.message;
14456 s_msg.flags = sent|wparam|lparam;
14457 s_msg.wParam = msg.wParam;
14458 s_msg.lParam = msg.lParam;
14459 s_msg.descr = "msg_loop";
14460 add_message(&s_msg);
14462 DispatchMessageA(&msg);
14465 end_ticks = GetTickCount();
14467 /* inject WM_MOUSEMOVE to see how it changes tracking */
14468 if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
14470 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
14471 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
14473 inject_mouse_move = FALSE;
14475 } while (start_ticks + timeout >= end_ticks);
14478 static void test_TrackMouseEvent(void)
14480 TRACKMOUSEEVENT tme;
14481 BOOL ret;
14482 HWND hwnd, hchild;
14483 RECT rc_parent, rc_child;
14484 UINT default_hover_time, hover_width = 0, hover_height = 0;
14486 #define track_hover(track_hwnd, track_hover_time) \
14487 tme.cbSize = sizeof(tme); \
14488 tme.dwFlags = TME_HOVER; \
14489 tme.hwndTrack = track_hwnd; \
14490 tme.dwHoverTime = track_hover_time; \
14491 SetLastError(0xdeadbeef); \
14492 ret = pTrackMouseEvent(&tme); \
14493 ok(ret, "TrackMouseEvent(TME_HOVER) error %ld\n", GetLastError())
14495 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
14496 tme.cbSize = sizeof(tme); \
14497 tme.dwFlags = TME_QUERY; \
14498 tme.hwndTrack = (HWND)0xdeadbeef; \
14499 tme.dwHoverTime = 0xdeadbeef; \
14500 SetLastError(0xdeadbeef); \
14501 ret = pTrackMouseEvent(&tme); \
14502 ok(ret, "TrackMouseEvent(TME_QUERY) error %ld\n", GetLastError());\
14503 ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %lu\n", tme.cbSize); \
14504 ok(tme.dwFlags == (expected_track_flags), \
14505 "wrong tme.dwFlags %08lx, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
14506 ok(tme.hwndTrack == (expected_track_hwnd), \
14507 "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
14508 ok(tme.dwHoverTime == (expected_hover_time), \
14509 "wrong tme.dwHoverTime %lu, expected %u\n", tme.dwHoverTime, (expected_hover_time))
14511 #define track_hover_cancel(track_hwnd) \
14512 tme.cbSize = sizeof(tme); \
14513 tme.dwFlags = TME_HOVER | TME_CANCEL; \
14514 tme.hwndTrack = track_hwnd; \
14515 tme.dwHoverTime = 0xdeadbeef; \
14516 SetLastError(0xdeadbeef); \
14517 ret = pTrackMouseEvent(&tme); \
14518 ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %ld\n", GetLastError())
14520 default_hover_time = 0xdeadbeef;
14521 SetLastError(0xdeadbeef);
14522 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
14523 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
14524 "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %lu\n", GetLastError());
14525 if (!ret) default_hover_time = 400;
14526 if (winetest_debug > 1) trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
14528 SetLastError(0xdeadbeef);
14529 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
14530 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
14531 "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %lu\n", GetLastError());
14532 if (!ret) hover_width = 4;
14533 SetLastError(0xdeadbeef);
14534 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
14535 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
14536 "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %lu\n", GetLastError());
14537 if (!ret) hover_height = 4;
14538 if (winetest_debug > 1) trace("hover rect is %u x %d\n", hover_width, hover_height);
14540 hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
14541 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14542 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
14543 NULL, NULL, 0);
14544 ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError());
14546 hchild = CreateWindowExA(0, "TestWindowClass", NULL,
14547 WS_CHILD | WS_BORDER | WS_VISIBLE,
14548 50, 50, 200, 200, hwnd,
14549 NULL, NULL, 0);
14550 ok(!!hchild, "Failed to create window, error %lu.\n", GetLastError());
14552 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
14553 flush_events();
14554 flush_sequence();
14556 tme.cbSize = 0;
14557 tme.dwFlags = TME_QUERY;
14558 tme.hwndTrack = (HWND)0xdeadbeef;
14559 tme.dwHoverTime = 0xdeadbeef;
14560 SetLastError(0xdeadbeef);
14561 ret = pTrackMouseEvent(&tme);
14562 ok(!ret, "TrackMouseEvent should fail\n");
14563 ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
14564 "not expected error %lu\n", GetLastError());
14566 tme.cbSize = sizeof(tme);
14567 tme.dwFlags = TME_HOVER;
14568 tme.hwndTrack = (HWND)0xdeadbeef;
14569 tme.dwHoverTime = 0xdeadbeef;
14570 SetLastError(0xdeadbeef);
14571 ret = pTrackMouseEvent(&tme);
14572 ok(!ret, "TrackMouseEvent should fail\n");
14573 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
14574 "not expected error %lu\n", GetLastError());
14576 tme.cbSize = sizeof(tme);
14577 tme.dwFlags = TME_HOVER | TME_CANCEL;
14578 tme.hwndTrack = (HWND)0xdeadbeef;
14579 tme.dwHoverTime = 0xdeadbeef;
14580 SetLastError(0xdeadbeef);
14581 ret = pTrackMouseEvent(&tme);
14582 ok(!ret, "TrackMouseEvent should fail\n");
14583 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
14584 "not expected error %lu\n", GetLastError());
14586 GetWindowRect(hwnd, &rc_parent);
14587 GetWindowRect(hchild, &rc_child);
14588 SetCursorPos(rc_child.left - 10, rc_child.top - 10);
14590 /* Process messages so that the system updates its internal current
14591 * window and hittest, otherwise TrackMouseEvent calls don't have any
14592 * effect.
14594 flush_events();
14595 flush_sequence();
14597 track_query(0, NULL, 0);
14598 track_hover(hchild, 0);
14599 track_query(0, NULL, 0);
14601 flush_events();
14602 flush_sequence();
14604 track_hover(hwnd, 0);
14605 tme.cbSize = sizeof(tme);
14606 tme.dwFlags = TME_QUERY;
14607 tme.hwndTrack = (HWND)0xdeadbeef;
14608 tme.dwHoverTime = 0xdeadbeef;
14609 SetLastError(0xdeadbeef);
14610 ret = pTrackMouseEvent(&tme);
14611 ok(ret, "TrackMouseEvent(TME_QUERY) error %ld\n", GetLastError());
14612 ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %lu\n", tme.cbSize);
14613 if (!tme.dwFlags)
14615 skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" );
14616 DestroyWindow( hwnd );
14617 return;
14619 ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08lx, expected TME_HOVER\n", tme.dwFlags);
14620 ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd);
14621 ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %lu, expected %u\n",
14622 tme.dwHoverTime, default_hover_time);
14624 pump_msg_loop_timeout(default_hover_time, FALSE);
14625 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
14627 track_query(0, NULL, 0);
14629 track_hover(hwnd, HOVER_DEFAULT);
14630 track_query(TME_HOVER, hwnd, default_hover_time);
14632 Sleep(default_hover_time / 2);
14633 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
14634 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
14636 track_query(TME_HOVER, hwnd, default_hover_time);
14638 pump_msg_loop_timeout(default_hover_time, FALSE);
14639 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
14641 track_query(0, NULL, 0);
14643 track_hover(hwnd, HOVER_DEFAULT);
14644 track_query(TME_HOVER, hwnd, default_hover_time);
14646 pump_msg_loop_timeout(default_hover_time, TRUE);
14647 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
14649 track_query(0, NULL, 0);
14651 track_hover(hwnd, HOVER_DEFAULT);
14652 track_query(TME_HOVER, hwnd, default_hover_time);
14653 track_hover_cancel(hwnd);
14655 DestroyWindow(hwnd);
14657 #undef track_hover
14658 #undef track_query
14659 #undef track_hover_cancel
14663 static const struct message WmSetWindowRgn[] = {
14664 { WM_WINDOWPOSCHANGING, sent|wparam|lparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE
14665 |SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE, 0 },
14666 { WM_NCCALCSIZE, sent|wparam, 1 },
14667 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
14668 { WM_GETTEXT, sent|defwinproc|optional },
14669 { WM_ERASEBKGND, sent|optional },
14670 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
14671 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14672 { 0 }
14675 static const struct message WmSetWindowRgn_no_redraw[] = {
14676 { WM_WINDOWPOSCHANGING, sent|wparam|lparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE
14677 |SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW, 0 },
14678 { WM_NCCALCSIZE, sent|wparam, 1 },
14679 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
14680 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14681 { 0 }
14684 static const struct message WmSetWindowRgn_clear[] = {
14685 { WM_WINDOWPOSCHANGING, sent/*|wparam|lparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED
14686 |SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */
14687 /* Some newer Windows versions set window coordinates instead of zeros in WINDOWPOS structure */},
14688 { WM_NCCALCSIZE, sent|wparam, 1 },
14689 { WM_NCPAINT, sent|optional },
14690 { WM_GETTEXT, sent|defwinproc|optional },
14691 { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
14692 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
14693 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
14694 { WM_NCPAINT, sent|optional },
14695 { WM_GETTEXT, sent|defwinproc|optional },
14696 { WM_ERASEBKGND, sent|optional },
14697 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14698 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14699 { WM_WINDOWPOSCHANGING, sent|optional },
14700 { WM_NCCALCSIZE, sent|optional|wparam, 1 },
14701 { WM_NCPAINT, sent|optional },
14702 { WM_GETTEXT, sent|defwinproc|optional },
14703 { WM_ERASEBKGND, sent|optional },
14704 { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
14705 { WM_NCCALCSIZE, sent|optional|wparam, 1 },
14706 { WM_NCPAINT, sent|optional },
14707 { WM_GETTEXT, sent|defwinproc|optional },
14708 { WM_ERASEBKGND, sent|optional },
14709 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14710 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not always sent. */
14711 { 0 }
14714 static void test_SetWindowRgn(void)
14716 HRGN hrgn;
14717 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
14718 100, 100, 200, 200, 0, 0, 0, NULL);
14719 ok( hwnd != 0, "Failed to create overlapped window\n" );
14721 ShowWindow( hwnd, SW_SHOW );
14722 UpdateWindow( hwnd );
14723 flush_events();
14724 flush_sequence();
14726 if (winetest_debug > 1) trace("testing SetWindowRgn\n");
14727 hrgn = CreateRectRgn( 0, 0, 150, 150 );
14728 SetWindowRgn( hwnd, hrgn, TRUE );
14729 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
14731 hrgn = CreateRectRgn( 30, 30, 160, 160 );
14732 SetWindowRgn( hwnd, hrgn, FALSE );
14733 ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
14735 hrgn = CreateRectRgn( 0, 0, 180, 180 );
14736 SetWindowRgn( hwnd, hrgn, TRUE );
14737 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
14739 SetWindowRgn( hwnd, 0, TRUE );
14740 ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
14742 DestroyWindow( hwnd );
14745 /*************************** ShowWindow() test ******************************/
14746 static const struct message WmShowNormal[] = {
14747 { WM_SHOWWINDOW, sent|wparam, 1 },
14748 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
14749 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
14750 { HCBT_ACTIVATE, hook },
14751 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14752 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
14753 { HCBT_SETFOCUS, hook },
14754 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
14755 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14756 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends it, but Win8+ doesn't. */
14757 { 0 }
14759 static const struct message WmShow[] = {
14760 { WM_SHOWWINDOW, sent|wparam, 1 },
14761 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
14762 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
14763 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
14764 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
14765 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
14766 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14767 { 0 }
14769 static const struct message WmShowNoActivate_1[] = {
14770 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
14771 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
14772 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
14773 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
14774 { WM_MOVE, sent|defwinproc|optional },
14775 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
14776 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14777 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
14778 { 0 }
14780 static const struct message WmShowNoActivate_2[] = {
14781 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
14782 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
14783 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14784 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
14785 { HCBT_ACTIVATE, hook|optional },
14786 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends this. */
14787 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
14788 { WM_WINDOWPOSCHANGED, sent|optional }, /* Sometimes sent on Win8+. */
14789 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
14790 { HCBT_SETFOCUS, hook|optional },
14791 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Win7 sends this. */
14792 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
14793 { WM_MOVE, sent|defwinproc },
14794 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
14795 { HCBT_SETFOCUS, hook|optional },
14796 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
14797 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
14798 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14799 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
14800 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14801 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
14802 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14803 { 0 }
14805 static const struct message WmShowNA_1[] = {
14806 { WM_SHOWWINDOW, sent|wparam, 1 },
14807 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
14808 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
14809 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14810 { 0 }
14812 static const struct message WmShowNA_2[] = {
14813 { WM_SHOWWINDOW, sent|wparam, 1 },
14814 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
14815 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14816 { 0 }
14818 static const struct message WmRestore_1[] = {
14819 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
14820 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
14821 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14822 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
14823 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
14824 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
14825 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
14826 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
14827 { WM_MOVE, sent|defwinproc },
14828 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
14829 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14830 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
14831 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14832 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
14833 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
14834 { 0 }
14836 static const struct message WmRestore_2[] = {
14837 { WM_SHOWWINDOW, sent|wparam, 1 },
14838 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
14839 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
14840 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
14841 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
14842 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
14843 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14844 { 0 }
14846 static const struct message WmRestore_3[] = {
14847 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
14848 { WM_GETMINMAXINFO, sent },
14849 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
14850 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14851 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
14852 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14853 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
14854 { WM_WINDOWPOSCHANGED, sent|optional }, /* Win8+ sometimes sends this. */
14855 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
14856 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
14857 { WM_WINDOWPOSCHANGED, sent|optional },
14858 { WM_MOVE, sent|defwinproc },
14859 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
14860 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
14861 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14862 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
14863 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14864 { 0 }
14866 static const struct message WmRestore_4[] = {
14867 { HCBT_MINMAX, hook|lparam|optional, 0, SW_RESTORE },
14868 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
14869 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
14870 { WM_MOVE, sent|defwinproc|optional },
14871 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
14872 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14873 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
14874 { 0 }
14876 static const struct message WmRestore_5[] = {
14877 { HCBT_MINMAX, hook|lparam|optional, 0, SW_SHOWNORMAL },
14878 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
14879 { HCBT_ACTIVATE, hook|optional },
14880 { HCBT_SETFOCUS, hook|optional },
14881 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
14882 { WM_MOVE, sent|defwinproc|optional },
14883 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
14884 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
14885 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
14886 { 0 }
14888 static const struct message WmHide_1[] = {
14889 { WM_SHOWWINDOW, sent|wparam, 0 },
14890 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOACTIVATE },
14891 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
14892 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOACTIVATE },
14893 { HCBT_ACTIVATE, hook|optional },
14894 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
14895 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
14896 { 0 }
14898 static const struct message WmHide_2[] = {
14899 { WM_SHOWWINDOW, sent|wparam, 0 },
14900 { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
14901 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
14902 { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
14903 { HCBT_ACTIVATE, hook|optional },
14904 { 0 }
14906 static const struct message WmHide_3[] = {
14907 { WM_SHOWWINDOW, sent|wparam, 0 },
14908 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
14909 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
14910 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14911 { HCBT_SETFOCUS, hook|optional },
14912 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
14913 { 0 }
14915 static const struct message WmShowMinimized_1[] = {
14916 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
14917 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
14918 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14919 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
14920 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
14921 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
14922 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
14923 { WM_MOVE, sent|defwinproc },
14924 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
14925 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14926 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
14927 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14928 { 0 }
14930 static const struct message WmMinimize_1[] = {
14931 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
14932 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
14933 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
14934 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
14935 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14936 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
14937 { WM_MOVE, sent|defwinproc },
14938 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
14939 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14940 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
14941 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14942 { 0 }
14944 static const struct message WmMinimize_2[] = {
14945 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
14946 { HCBT_SETFOCUS, hook|optional },
14947 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
14948 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14949 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
14950 { WM_MOVE, sent|defwinproc },
14951 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
14952 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14953 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
14954 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14955 { 0 }
14957 static const struct message WmMinimize_3[] = {
14958 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
14959 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
14960 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14961 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
14962 { HCBT_ACTIVATE, hook|optional },
14963 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sometimes sent on Win8/10. */
14964 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
14965 { WM_WINDOWPOSCHANGED, sent|optional },
14966 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sometimes sent on Win7. */
14967 { WM_WINDOWPOSCHANGED, sent|optional },
14968 { WM_MOVE, sent|defwinproc },
14969 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
14970 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14971 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
14972 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
14973 { 0 }
14975 static const struct message WmShowMinNoActivate[] = {
14976 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
14977 { WM_WINDOWPOSCHANGING, sent },
14978 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
14979 { WM_WINDOWPOSCHANGED, sent },
14980 { WM_MOVE, sent|defwinproc|optional },
14981 { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
14982 { 0 }
14984 static const struct message WmMinMax_1[] = {
14985 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
14986 { 0 }
14988 static const struct message WmMinMax_2[] = {
14989 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
14990 { WM_GETMINMAXINFO, sent|optional },
14991 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED },
14992 { HCBT_ACTIVATE, hook|optional },
14993 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
14994 { HCBT_SETFOCUS, hook|optional },
14995 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14996 { WM_MOVE, sent|defwinproc|optional },
14997 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MAXIMIZED },
14998 { HCBT_SETFOCUS, hook|optional },
14999 { 0 }
15001 static const struct message WmMinMax_3[] = {
15002 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
15003 { HCBT_SETFOCUS, hook|optional },
15004 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
15005 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
15006 { WM_MOVE, sent|defwinproc|optional },
15007 { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
15008 { 0 }
15010 static const struct message WmMinMax_4[] = {
15011 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
15012 { 0 }
15014 static const struct message WmShowMaximized_1[] = {
15015 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
15016 { WM_GETMINMAXINFO, sent },
15017 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
15018 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15019 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
15020 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
15021 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
15022 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
15023 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
15024 { WM_MOVE, sent|defwinproc },
15025 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
15026 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15027 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
15028 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15029 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
15030 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
15031 { 0 }
15033 static const struct message WmShowMaximized_2[] = {
15034 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
15035 { WM_GETMINMAXINFO, sent },
15036 { WM_WINDOWPOSCHANGING, sent|optional },
15037 { HCBT_ACTIVATE, hook|optional },
15038 { WM_WINDOWPOSCHANGED, sent|optional },
15039 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
15040 { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
15041 { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
15042 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends this. */
15043 { WM_WINDOWPOSCHANGING, sent|optional },
15044 { HCBT_SETFOCUS, hook|optional },
15045 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
15046 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
15047 { WM_MOVE, sent|defwinproc },
15048 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
15049 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15050 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
15051 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15052 { HCBT_SETFOCUS, hook|optional },
15053 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
15054 { 0 }
15056 static const struct message WmShowMaximized_3[] = {
15057 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
15058 { WM_GETMINMAXINFO, sent|optional },
15059 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
15060 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
15061 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
15062 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
15063 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
15064 { WM_MOVE, sent|defwinproc|optional },
15065 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
15066 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15067 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
15068 { 0 }
15071 static void test_ShowWindow(void)
15073 /* ShowWindow commands in random order */
15074 static const struct
15076 INT cmd; /* ShowWindow command */
15077 LPARAM ret; /* ShowWindow return value */
15078 DWORD style; /* window style after the command */
15079 const struct message *msg; /* message sequence the command produces */
15080 INT wp_cmd, wp_flags; /* window placement after the command */
15081 POINT wp_min, wp_max; /* window placement after the command */
15082 BOOL todo_msg; /* message sequence doesn't match what Wine does */
15083 } sw[] =
15085 /* 1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal,
15086 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
15087 /* 2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq,
15088 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
15089 /* 3 */ { SW_HIDE, TRUE, 0, WmHide_1,
15090 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
15091 /* 4 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
15092 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
15093 /* 5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1,
15094 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15095 /* 6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1,
15096 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15097 /* 7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1,
15098 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15099 /* 8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
15100 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15101 /* 9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1,
15102 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15103 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
15104 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15105 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1,
15106 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15107 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq,
15108 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15109 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1,
15110 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15111 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
15112 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15113 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2,
15114 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15115 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
15116 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15117 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow,
15118 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15119 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
15120 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15121 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
15122 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15123 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
15124 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15125 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
15126 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15127 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate,
15128 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, TRUE },
15129 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4,
15130 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15131 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
15132 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15133 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
15134 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15135 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1,
15136 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15137 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2,
15138 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15139 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
15140 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15141 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
15142 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15143 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1,
15144 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15145 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
15146 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15147 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3,
15148 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15149 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
15150 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15151 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, /* what does this mean?! */
15152 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15153 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq,
15154 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15155 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
15156 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15157 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2,
15158 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15159 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
15160 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15161 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
15162 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15163 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2,
15164 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15165 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
15166 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15167 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2,
15168 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15169 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
15170 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15171 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
15172 SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15173 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
15174 SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15175 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3,
15176 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15177 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4,
15178 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15179 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3,
15180 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15181 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq,
15182 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15183 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
15184 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15185 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
15186 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15187 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1,
15188 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15189 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
15190 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
15191 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3,
15192 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15193 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
15194 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
15195 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2,
15196 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
15197 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
15198 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE }
15200 HWND hwnd;
15201 DWORD style;
15202 LPARAM ret;
15203 INT i;
15204 WINDOWPLACEMENT wp;
15205 RECT win_rc, work_rc = {0, 0, 0, 0};
15206 HMONITOR hmon;
15207 MONITORINFO mi;
15208 POINT pt = {0, 0};
15210 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
15211 hwnd = CreateWindowExA(0, "ShowWindowClass", NULL, WS_BASE,
15212 120, 120, 90, 90,
15213 0, 0, 0, NULL);
15214 ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError());
15216 style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
15217 ok(style == 0, "expected style 0, got %08lx\n", style);
15219 flush_events();
15220 flush_sequence();
15222 SetLastError(0xdeadbeef);
15223 hmon = MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
15224 ok(hmon != 0, "MonitorFromPoint error %lu\n", GetLastError());
15226 mi.cbSize = sizeof(mi);
15227 SetLastError(0xdeadbeef);
15228 ret = GetMonitorInfoA(hmon, &mi);
15229 ok(ret, "GetMonitorInfo error %lu\n", GetLastError());
15230 if (winetest_debug > 1) trace("monitor %s, work %s\n", wine_dbgstr_rect(&mi.rcMonitor),
15231 wine_dbgstr_rect(&mi.rcWork));
15232 work_rc = mi.rcWork;
15234 GetWindowRect(hwnd, &win_rc);
15235 OffsetRect(&win_rc, -work_rc.left, -work_rc.top);
15237 wp.length = sizeof(wp);
15238 SetLastError(0xdeadbeaf);
15239 ret = GetWindowPlacement(hwnd, &wp);
15240 ok(ret, "GetWindowPlacement error %lu\n", GetLastError());
15241 ok(wp.flags == 0, "expected 0, got %#x\n", wp.flags);
15242 ok(wp.showCmd == SW_SHOWNORMAL, "expected SW_SHOWNORMAL, got %d\n", wp.showCmd);
15243 ok(wp.ptMinPosition.x == -1 && wp.ptMinPosition.y == -1,
15244 "expected -1,-1 got %ld,%ld\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
15245 ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
15246 "expected -1,-1 got %ld,%ld\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
15247 todo_wine_if (work_rc.left || work_rc.top) /* FIXME: remove once Wine is fixed */
15248 ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n", wine_dbgstr_rect(&win_rc),
15249 wine_dbgstr_rect(&wp.rcNormalPosition));
15251 for (i = 0; i < ARRAY_SIZE(sw); i++)
15253 static const char * const sw_cmd_name[13] =
15255 "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
15256 "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
15257 "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
15258 "SW_NORMALNA" /* 0xCC */
15260 char comment[64];
15261 INT idx; /* index into the above array of names */
15263 idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
15265 style = GetWindowLongA(hwnd, GWL_STYLE);
15266 if (winetest_debug > 1) trace("%d: sending %s, current window style %08lx\n", i+1, sw_cmd_name[idx], style);
15267 ret = ShowWindow(hwnd, sw[i].cmd);
15268 ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %Iu, got %Iu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
15269 style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
15270 ok(style == sw[i].style, "%d: expected style %08lx, got %08lx\n", i+1, sw[i].style, style);
15272 sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
15273 ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
15275 wp.length = sizeof(wp);
15276 SetLastError(0xdeadbeaf);
15277 ret = GetWindowPlacement(hwnd, &wp);
15278 ok(ret, "GetWindowPlacement error %lu\n", GetLastError());
15279 ok(wp.flags == sw[i].wp_flags, "expected %#x, got %#x\n", sw[i].wp_flags, wp.flags);
15280 ok(wp.showCmd == sw[i].wp_cmd, "expected %d, got %d\n", sw[i].wp_cmd, wp.showCmd);
15282 /* NT moves the minimized window to -32000,-32000, win9x to 3000,3000 */
15283 if ((wp.ptMinPosition.x + work_rc.left == -32000 && wp.ptMinPosition.y + work_rc.top == -32000) ||
15284 (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000))
15286 ok((wp.ptMinPosition.x + work_rc.left == sw[i].wp_min.x && wp.ptMinPosition.y + work_rc.top == sw[i].wp_min.y) ||
15287 (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000),
15288 "expected %ld,%ld got %ld,%ld\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
15290 else
15292 ok(wp.ptMinPosition.x == sw[i].wp_min.x && wp.ptMinPosition.y == sw[i].wp_min.y,
15293 "expected %ld,%ld got %ld,%ld\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
15296 todo_wine_if(wp.ptMaxPosition.x != sw[i].wp_max.x || wp.ptMaxPosition.y != sw[i].wp_max.y)
15297 ok(wp.ptMaxPosition.x == sw[i].wp_max.x && wp.ptMaxPosition.y == sw[i].wp_max.y,
15298 "expected %ld,%ld got %ld,%ld\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y);
15300 if (0) /* FIXME: Wine behaves completely different here */
15301 ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n",
15302 wine_dbgstr_rect(&win_rc), wine_dbgstr_rect(&wp.rcNormalPosition));
15304 DestroyWindow(hwnd);
15305 flush_events();
15308 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
15310 struct recvd_message msg;
15312 if (ignore_message( message )) return 0;
15314 msg.hwnd = hwnd;
15315 msg.message = message;
15316 msg.flags = sent|wparam|lparam;
15317 msg.wParam = wParam;
15318 msg.lParam = lParam;
15319 msg.descr = "dialog";
15320 add_message(&msg);
15322 /* calling DefDlgProc leads to a recursion under XP */
15324 switch (message)
15326 case WM_INITDIALOG:
15327 return lParam;
15329 case WM_GETDLGCODE:
15330 return 0;
15332 return 1;
15335 static WNDPROC orig_edit_proc;
15336 static LRESULT WINAPI dlg_creation_edit_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
15338 struct recvd_message msg;
15340 if (ignore_message( message )) return 0;
15342 msg.hwnd = hwnd;
15343 msg.message = message;
15344 msg.flags = sent|wparam|lparam;
15345 msg.wParam = wp;
15346 msg.lParam = lp;
15347 msg.descr = "edit";
15348 add_message(&msg);
15350 return CallWindowProcW(orig_edit_proc, hwnd, message, wp, lp);
15353 static INT_PTR WINAPI test_dlg_proc2(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
15355 struct recvd_message msg;
15357 if (ignore_message( message )) return 0;
15359 msg.hwnd = hwnd;
15360 msg.message = message;
15361 msg.flags = sent|wparam|lparam|parent;
15362 msg.wParam = wParam;
15363 msg.lParam = lParam;
15364 msg.descr = "dialog";
15365 add_message(&msg);
15367 if (message == WM_INITDIALOG)
15369 orig_edit_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwnd, 200),
15370 GWLP_WNDPROC, (LONG_PTR)dlg_creation_edit_proc);
15373 return 1;
15376 static INT_PTR WINAPI test_dlg_proc3(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
15378 ok( 0, "should not be called since DefDlgProc is not used\n" );
15379 return 0;
15382 static LRESULT WINAPI test_dlg_proc4(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
15384 struct recvd_message msg;
15386 if (!ignore_message( message ))
15388 msg.hwnd = hwnd;
15389 msg.message = message;
15390 msg.flags = sent|wparam|lparam|parent;
15391 msg.wParam = wParam;
15392 msg.lParam = lParam;
15393 msg.descr = "dialog";
15394 add_message(&msg);
15396 if (message == WM_INITDIALOG)
15398 orig_edit_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwnd, 200),
15399 GWLP_WNDPROC, (LONG_PTR)dlg_creation_edit_proc);
15400 return 1;
15402 return DefWindowProcW( hwnd, message, wParam, lParam );
15405 static const struct message WmDefDlgSetFocus_1[] = {
15406 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
15407 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
15408 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
15409 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
15410 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
15411 { HCBT_SETFOCUS, hook },
15412 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
15413 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
15414 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
15415 { WM_SETFOCUS, sent|wparam, 0 },
15416 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
15417 { WM_CTLCOLOREDIT, sent },
15418 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
15419 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
15420 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
15421 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
15422 { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
15423 { 0 }
15425 static const struct message WmDefDlgSetFocus_2[] = {
15426 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
15427 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
15428 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
15429 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
15430 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
15431 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
15432 { WM_CTLCOLOREDIT, sent|optional }, /* XP */
15433 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CARET, 0 },
15434 { 0 }
15436 /* Creation of a dialog */
15437 static const struct message WmCreateDialogParamSeq_0[] = {
15438 { HCBT_CREATEWND, hook },
15439 { WM_NCCREATE, sent },
15440 { WM_NCCALCSIZE, sent|wparam, 0 },
15441 { WM_CREATE, sent },
15442 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
15443 { WM_SIZE, sent|wparam, SIZE_RESTORED },
15444 { WM_MOVE, sent },
15445 { WM_SETFONT, sent },
15446 { WM_INITDIALOG, sent },
15447 { WM_CHANGEUISTATE, sent|optional },
15448 { 0 }
15450 /* Creation of a dialog */
15451 static const struct message WmCreateDialogParamSeq_1[] = {
15452 { HCBT_CREATEWND, hook },
15453 { WM_NCCREATE, sent },
15454 { WM_NCCALCSIZE, sent|wparam, 0 },
15455 { WM_CREATE, sent },
15456 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
15457 { WM_SIZE, sent|wparam, SIZE_RESTORED },
15458 { WM_MOVE, sent },
15459 { WM_SETFONT, sent },
15460 { WM_INITDIALOG, sent },
15461 { WM_GETDLGCODE, sent|wparam|lparam|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
15462 { HCBT_SETFOCUS, hook },
15463 { HCBT_ACTIVATE, hook },
15464 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15465 { WM_QUERYNEWPALETTE, sent|optional },
15466 { WM_PALETTEISCHANGING, sent|optional },
15467 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
15468 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOREDRAW },
15469 { WM_GETTEXT, sent|optional }, /* win7 */
15470 { WM_NCCALCSIZE, sent|optional }, /* win7 */
15471 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win7 */
15472 { WM_ACTIVATEAPP, sent|wparam, 1 },
15473 { WM_NCACTIVATE, sent },
15474 { WM_ACTIVATE, sent|wparam, 1 },
15475 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
15476 { WM_SETFOCUS, sent },
15477 { WM_CHANGEUISTATE, sent|optional },
15478 { 0 }
15480 /* Creation of a dialog */
15481 static const struct message WmCreateDialogParamSeq_2[] = {
15482 { HCBT_CREATEWND, hook },
15483 { WM_NCCREATE, sent },
15484 { WM_NCCALCSIZE, sent|wparam, 0 },
15485 { WM_CREATE, sent },
15486 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
15487 { WM_SIZE, sent|wparam, SIZE_RESTORED },
15488 { WM_MOVE, sent },
15489 { WM_CHANGEUISTATE, sent|optional },
15490 { 0 }
15493 static const struct message WmCreateDialogParamSeq_3[] = {
15494 { HCBT_CREATEWND, hook },
15495 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15496 { WM_SETFONT, sent|parent },
15497 { WM_INITDIALOG, sent|parent },
15498 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
15499 { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
15500 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
15501 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
15502 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
15503 { HCBT_ACTIVATE, hook },
15504 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15505 { WM_QUERYNEWPALETTE, sent|parent|optional }, /* TODO: this message should not be sent */
15506 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
15507 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
15508 { WM_WINDOWPOSCHANGED, sent|parent|wparam|optional, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15509 { WM_WINDOWPOSCHANGED, sent|parent|wparam|optional, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15510 { WM_NCCALCSIZE, sent|parent|optional, 0 },
15511 { WM_MOVE, sent|parent|optional },
15512 { WM_SIZE, sent|parent|optional },
15513 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
15514 { WM_ACTIVATEAPP, sent|parent|wparam, 1 },
15515 { WM_NCACTIVATE, sent|parent },
15516 { WM_ACTIVATE, sent|parent|wparam, 1 },
15517 { WM_SETFOCUS, sent },
15518 { WM_COMMAND, sent|parent|wparam, MAKELONG(200, EN_SETFOCUS) },
15519 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
15520 { WM_USER, sent|parent },
15521 { WM_CHANGEUISTATE, sent|parent|optional },
15522 { 0 }
15525 static const struct message WmCreateDialogParamSeq_4[] = {
15526 { HCBT_CREATEWND, hook },
15527 { WM_NCCREATE, sent|parent },
15528 { WM_NCCALCSIZE, sent|parent|wparam, 0 },
15529 { WM_CREATE, sent|parent },
15530 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15531 { WM_SIZE, sent|parent|wparam, SIZE_RESTORED },
15532 { WM_MOVE, sent|parent },
15533 { WM_SETFONT, sent|parent },
15534 { WM_INITDIALOG, sent|parent },
15535 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
15536 { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
15537 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
15538 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
15539 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
15540 { HCBT_ACTIVATE, hook },
15541 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15542 { WM_QUERYNEWPALETTE, sent|parent|optional }, /* TODO: this message should not be sent */
15543 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
15544 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
15545 { WM_WINDOWPOSCHANGED, sent|parent|wparam|optional, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15546 { WM_NCCALCSIZE, sent|parent|optional, 0 },
15547 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
15548 { WM_ACTIVATEAPP, sent|parent|wparam, 1 },
15549 { WM_NCACTIVATE, sent|parent },
15550 { WM_ACTIVATE, sent|parent|wparam, 1 },
15551 { HCBT_SETFOCUS, hook },
15552 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
15553 { WM_SETFOCUS, sent|parent },
15554 { WM_KILLFOCUS, sent|parent },
15555 { WM_SETFOCUS, sent },
15556 { WM_COMMAND, sent|parent|wparam, MAKELONG(200, EN_SETFOCUS) },
15557 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
15558 { WM_USER, sent|parent },
15559 { WM_CHANGEUISTATE, sent|parent|optional },
15560 { WM_UPDATEUISTATE, sent|parent|optional },
15561 { WM_UPDATEUISTATE, sent|optional },
15562 { 0 }
15565 static void test_dialog_messages(void)
15567 WNDCLASSA cls;
15568 HWND hdlg, hedit1, hedit2, hfocus, parent, child, child2;
15569 LRESULT ret;
15571 #define set_selection(hctl, start, end) \
15572 ret = SendMessageA(hctl, EM_SETSEL, start, end); \
15573 ok(ret == 1, "EM_SETSEL returned %Id\n", ret);
15575 #define check_selection(hctl, start, end) \
15576 ret = SendMessageA(hctl, EM_GETSEL, 0, 0); \
15577 ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
15579 subclass_edit();
15581 hdlg = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
15582 WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
15583 0, 0, 100, 100, 0, 0, 0, NULL);
15584 ok(hdlg != 0, "Failed to create custom dialog window\n");
15586 hedit1 = CreateWindowExA(0, "my_edit_class", NULL,
15587 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
15588 0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
15589 ok(hedit1 != 0, "Failed to create edit control\n");
15590 hedit2 = CreateWindowExA(0, "my_edit_class", NULL,
15591 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
15592 0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
15593 ok(hedit2 != 0, "Failed to create edit control\n");
15595 SendMessageA(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
15596 SendMessageA(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
15598 hfocus = GetFocus();
15599 ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
15601 SetFocus(hedit2);
15602 hfocus = GetFocus();
15603 ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
15605 check_selection(hedit1, 0, 0);
15606 check_selection(hedit2, 0, 0);
15608 set_selection(hedit2, 0, -1);
15609 check_selection(hedit2, 0, 3);
15611 SetFocus(0);
15612 hfocus = GetFocus();
15613 ok(hfocus == 0, "wrong focus %p\n", hfocus);
15615 flush_sequence();
15616 ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
15617 ok(ret == 0, "WM_SETFOCUS returned %Id\n", ret);
15618 ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
15620 hfocus = GetFocus();
15621 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
15623 check_selection(hedit1, 0, 5);
15624 check_selection(hedit2, 0, 3);
15626 flush_sequence();
15627 ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
15628 ok(ret == 0, "WM_SETFOCUS returned %Id\n", ret);
15629 ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
15631 hfocus = GetFocus();
15632 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
15634 check_selection(hedit1, 0, 5);
15635 check_selection(hedit2, 0, 3);
15637 EndDialog(hdlg, 0);
15638 DestroyWindow(hedit1);
15639 DestroyWindow(hedit2);
15640 DestroyWindow(hdlg);
15641 flush_sequence();
15643 #undef set_selection
15644 #undef check_selection
15646 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
15647 cls.lpszClassName = "MyDialogClass";
15648 cls.hInstance = GetModuleHandleA(NULL);
15649 /* need a cast since a dlgproc is used as a wndproc */
15650 cls.lpfnWndProc = (WNDPROC)test_dlg_proc;
15651 register_class(&cls);
15653 SetFocus(0);
15654 flush_sequence();
15655 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
15656 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
15657 ok_sequence(WmCreateDialogParamSeq_0, "CreateDialogParam_0", FALSE);
15658 hfocus = GetFocus();
15659 ok(hfocus == 0, "wrong focus %p\n", hfocus);
15660 EndDialog(hdlg, 0);
15661 DestroyWindow(hdlg);
15662 flush_sequence();
15664 SetFocus(0);
15665 flush_sequence();
15666 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 1);
15667 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
15668 ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
15669 hfocus = GetFocus();
15670 ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
15671 EndDialog(hdlg, 0);
15672 DestroyWindow(hdlg);
15673 flush_sequence();
15675 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
15676 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
15677 ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
15678 EndDialog(hdlg, 0);
15679 DestroyWindow(hdlg);
15680 flush_sequence();
15682 hdlg = CreateDialogParamA(0, "FOCUS_TEST_DIALOG_3", 0, test_dlg_proc2, 0);
15683 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
15684 ok_sequence(WmCreateDialogParamSeq_3, "CreateDialogParam_3", TRUE);
15685 EndDialog(hdlg, 0);
15686 DestroyWindow(hdlg);
15687 flush_sequence();
15689 UnregisterClassA( cls.lpszClassName, cls.hInstance );
15690 cls.lpfnWndProc = test_dlg_proc4;
15691 register_class(&cls);
15692 hdlg = CreateDialogParamA(0, "FOCUS_TEST_DIALOG_4", 0, test_dlg_proc3, 0);
15693 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
15694 ok_sequence(WmCreateDialogParamSeq_4, "CreateDialogParam_4", TRUE);
15695 EndDialog(hdlg, 0);
15696 DestroyWindow(hdlg);
15697 flush_sequence();
15699 UnregisterClassA(cls.lpszClassName, cls.hInstance);
15701 parent = CreateWindowExA(0, "TestParentClass", "Test parent",
15702 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
15703 100, 100, 200, 200, 0, 0, 0, NULL);
15704 ok (parent != 0, "Failed to create parent window\n");
15706 /* This child has no parent set. We will later call SetParent on it,
15707 * so that it will have a parent set, but no WS_CHILD style. */
15708 child = CreateWindowExA(0, "TestWindowClass", "Test child",
15709 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
15710 100, 100, 200, 200, 0, 0, 0, NULL);
15711 ok (child != 0, "Failed to create child window\n");
15713 /* This is a regular child window. When used as an owner, the other
15714 * child window will be used. */
15715 child2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2",
15716 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CHILD,
15717 100, 100, 200, 200, child, 0, 0, NULL);
15718 ok (child2 != 0, "Failed to create child window\n");
15720 SetParent(child, parent);
15721 SetFocus(child);
15723 flush_sequence();
15724 DialogBoxA( 0, "TEST_DIALOG", child2, TestModalDlgProc2 );
15725 ok_sequence(WmModalDialogSeq_2, "ModalDialog2", TRUE);
15727 DestroyWindow(child2);
15728 DestroyWindow(child);
15729 DestroyWindow(parent);
15730 flush_sequence();
15733 static void test_enddialog_seq(HWND dialog, HWND owner)
15735 const struct message seq[] = {
15736 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15737 { WM_ENABLE, sent },
15738 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
15739 { HCBT_ACTIVATE, hook|wparam, (WPARAM)owner },
15740 { WM_NCACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
15741 { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
15742 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15743 /* FIXME: Following two are optional because Wine sends WM_QUERYNEWPALETTE instead of WM_WINDOWPOSCHANGING */
15744 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
15745 { WM_QUERYNEWPALETTE, sent|optional },
15746 { WM_NCACTIVATE, sent|wparam|lparam, WA_ACTIVE, (LPARAM)dialog },
15747 { WM_GETTEXT, sent|optional|defwinproc },
15748 { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, (LPARAM)dialog },
15749 { HCBT_SETFOCUS, hook|wparam, (WPARAM)owner },
15750 { WM_KILLFOCUS, sent|wparam, (WPARAM)owner },
15751 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
15752 { WM_SETFOCUS, sent|defwinproc|wparam, (WPARAM)dialog },
15753 { 0 }
15756 flush_sequence();
15757 EndDialog(dialog, 0);
15758 ok_sequence(seq, "EndDialog", FALSE);
15761 static void test_enddialog_seq2(HWND dialog, HWND owner)
15763 const struct message seq[] = {
15764 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15765 { WM_ENABLE, parent|sent },
15766 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
15767 { HCBT_ACTIVATE, hook|wparam, (WPARAM)owner },
15768 { WM_NCACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
15769 { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
15770 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15771 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
15772 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
15773 { HCBT_SETFOCUS, hook|wparam, (WPARAM)owner },
15774 { WM_KILLFOCUS, sent|wparam, (WPARAM)owner },
15775 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
15776 { WM_SETFOCUS, sent|parent|defwinproc|wparam, (WPARAM)dialog },
15777 { 0 }
15780 flush_sequence();
15781 EndDialog(dialog, 0);
15782 ok_sequence(seq, "EndDialog2", FALSE);
15785 static void test_EndDialog(void)
15787 HWND hparent, hother, hactive, hdlg, hchild;
15788 WNDCLASSA cls;
15790 hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
15791 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
15792 100, 100, 200, 200, 0, 0, 0, NULL);
15793 ok (hparent != 0, "Failed to create parent window\n");
15795 hother = CreateWindowExA(0, "TestParentClass", "Test parent 2",
15796 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
15797 200, 100, 200, 200, 0, 0, 0, NULL);
15798 ok (hother != 0, "Failed to create parent window\n");
15800 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
15801 cls.lpszClassName = "MyDialogClass";
15802 cls.hInstance = GetModuleHandleA(NULL);
15803 cls.lpfnWndProc = (WNDPROC)test_dlg_proc;
15804 register_class(&cls);
15806 flush_sequence();
15807 SetForegroundWindow(hother);
15808 hactive = GetForegroundWindow();
15809 ok(hother == hactive, "Wrong window has focus (%p != %p)\n", hother, hactive);
15811 /* create a dialog where the parent is disabled, this parent should be
15812 * enabled and receive focus when dialog exits */
15813 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hparent, test_dlg_proc, 0);
15814 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
15815 SetForegroundWindow(hdlg);
15816 hactive = GetForegroundWindow();
15817 ok(hdlg == hactive, "Wrong window has focus (%p != %p)\n", hdlg, hactive);
15818 EndDialog(hdlg, 0);
15819 ok(IsWindowEnabled(hparent), "parent is not enabled\n");
15820 hactive = GetForegroundWindow();
15821 ok(hparent == hactive, "Wrong window has focus (parent != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
15822 DestroyWindow(hdlg);
15823 flush_sequence();
15825 /* create a dialog where the parent is disabled and set active window to other window before calling EndDialog */
15826 EnableWindow(hparent, FALSE);
15827 hdlg = CreateWindowExA(0, "TestDialogClass", NULL,
15828 WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
15829 0, 0, 100, 100, hparent, 0, 0, NULL);
15830 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
15831 flush_sequence();
15832 SetForegroundWindow(hother);
15833 flush_sequence();
15834 hactive = GetForegroundWindow();
15835 ok(hactive == hother, "Wrong foreground (%p != %p)\n", hactive, hother);
15836 hactive = GetActiveWindow();
15837 ok(hactive == hother, "Wrong active window (%p != %p)\n", hactive, hother);
15838 EndDialog(hdlg, 0);
15839 ok(IsWindowEnabled(hparent), "parent is not enabled\n");
15840 hactive = GetForegroundWindow();
15841 ok(hother == hactive, "Wrong window has focus (other != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
15842 DestroyWindow(hdlg);
15843 flush_sequence();
15845 DestroyWindow( hparent );
15847 hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
15848 WS_POPUP | WS_VISIBLE | WS_DISABLED,
15849 100, 100, 200, 200, 0, 0, 0, NULL);
15850 ok (hparent != 0, "Failed to create parent window\n");
15852 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
15853 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
15854 0, 0, 0, 0, 0, 0, 0, NULL);
15855 ok (hchild != 0, "Failed to create child window\n");
15857 SetParent(hchild, hparent);
15859 flush_sequence();
15860 SetForegroundWindow(hother);
15861 hactive = GetForegroundWindow();
15862 ok(hother == hactive, "Wrong foreground window (%p != %p)\n", hother, hactive);
15864 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hchild, test_dlg_proc, 0);
15865 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
15867 SetForegroundWindow(hdlg);
15868 test_enddialog_seq(hdlg, hchild);
15870 hactive = GetForegroundWindow();
15871 ok(hactive == hchild, "Wrong foreground window (active: %p, parent: %p, dlg: %p, other: %p child: %p)\n", hactive, hparent, hdlg, hother, hchild);
15873 DestroyWindow(hdlg);
15875 /* Now set WS_CHILD style flag so that it's a real child and its parent will be dialog's owner. */
15876 SetWindowLongW(hchild, GWL_STYLE, GetWindowLongW(hchild, GWL_STYLE) | WS_CHILD);
15878 SetForegroundWindow(hother);
15879 hactive = GetForegroundWindow();
15880 ok(hother == hactive, "Wrong foreground window (%p != %p)\n", hother, hactive);
15882 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hchild, test_dlg_proc, 0);
15883 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
15885 SetForegroundWindow(hdlg);
15886 test_enddialog_seq2(hdlg, hparent);
15888 hactive = GetForegroundWindow();
15889 ok(hactive == hparent, "Wrong foreground window (active: %p, parent: %p, dlg: %p, other: %p child: %p)\n", hactive, hparent, hdlg, hother, hchild);
15890 DestroyWindow(hdlg);
15891 DestroyWindow(hchild);
15892 DestroyWindow(hparent);
15893 DestroyWindow(hother);
15894 flush_sequence();
15896 UnregisterClassA(cls.lpszClassName, cls.hInstance);
15899 static void test_nullCallback(void)
15901 HWND hwnd;
15903 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
15904 100, 100, 200, 200, 0, 0, 0, NULL);
15905 ok (hwnd != 0, "Failed to create overlapped window\n");
15907 SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
15908 flush_events();
15909 DestroyWindow(hwnd);
15912 /* SetActiveWindow( 0 ) hwnd visible */
15913 static const struct message SetActiveWindowSeq0[] =
15915 { HCBT_ACTIVATE, hook|optional },
15916 { WM_NCACTIVATE, sent|wparam, 0 },
15917 { WM_GETTEXT, sent|defwinproc|optional },
15918 { WM_ACTIVATE, sent|wparam, 0 },
15919 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15920 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
15921 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
15922 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
15923 { WM_KILLFOCUS, sent|optional },
15924 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
15925 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
15926 { WM_NCACTIVATE, sent|wparam|optional, 1 },
15927 { WM_GETTEXT, sent|defwinproc|optional },
15928 { WM_ACTIVATE, sent|wparam|optional, 1 },
15929 { HCBT_SETFOCUS, hook|optional },
15930 { WM_KILLFOCUS, sent|defwinproc|optional },
15931 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
15932 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
15933 { WM_IME_SETCONTEXT, sent|optional },
15934 { WM_IME_SETCONTEXT, sent|optional },
15935 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
15936 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
15937 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
15938 { WM_SETFOCUS, sent|defwinproc|optional },
15939 { WM_GETTEXT, sent|optional },
15940 { 0 }
15942 /* SetActiveWindow( hwnd ) hwnd visible */
15943 static const struct message SetActiveWindowSeq1[] =
15945 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
15946 { 0 }
15948 /* SetActiveWindow( popup ) hwnd visible, popup visible */
15949 static const struct message SetActiveWindowSeq2[] =
15951 { HCBT_ACTIVATE, hook },
15952 { WM_NCACTIVATE, sent|wparam, 0 },
15953 { WM_GETTEXT, sent|defwinproc|optional },
15954 { WM_ACTIVATE, sent|wparam, 0 },
15955 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15956 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
15957 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
15958 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
15959 { WM_NCPAINT, sent|optional },
15960 { WM_GETTEXT, sent|defwinproc|optional },
15961 { WM_ERASEBKGND, sent|optional },
15962 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15963 { WM_NCACTIVATE, sent|wparam, 1 },
15964 { WM_GETTEXT, sent|defwinproc|optional },
15965 { WM_ACTIVATE, sent|wparam, 1 },
15966 { HCBT_SETFOCUS, hook },
15967 { WM_KILLFOCUS, sent|defwinproc },
15968 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
15969 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
15970 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
15971 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
15972 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
15973 { WM_SETFOCUS, sent|defwinproc },
15974 { WM_GETTEXT, sent|optional },
15975 { 0 }
15978 /* SetActiveWindow( hwnd ) hwnd not visible */
15979 static const struct message SetActiveWindowSeq3[] =
15981 { HCBT_ACTIVATE, hook },
15982 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
15983 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
15984 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
15985 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
15986 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15987 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15988 { WM_ACTIVATEAPP, sent|wparam, 1 },
15989 { WM_ACTIVATEAPP, sent|wparam, 1 },
15990 { WM_NCACTIVATE, sent|wparam, 1 },
15991 { WM_ACTIVATE, sent|wparam, 1 },
15992 { HCBT_SETFOCUS, hook },
15993 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
15994 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
15995 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
15996 { WM_SETFOCUS, sent|defwinproc },
15997 { 0 }
15999 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
16000 static const struct message SetActiveWindowSeq4[] =
16002 { HCBT_ACTIVATE, hook },
16003 { WM_NCACTIVATE, sent|wparam, 0 },
16004 { WM_GETTEXT, sent|defwinproc|optional },
16005 { WM_ACTIVATE, sent|wparam, 0 },
16006 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
16007 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
16008 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
16009 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
16010 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
16011 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
16012 { WM_NCACTIVATE, sent|wparam, 1 },
16013 { WM_GETTEXT, sent|defwinproc|optional },
16014 { WM_ACTIVATE, sent|wparam, 1 },
16015 { HCBT_SETFOCUS, hook },
16016 { WM_KILLFOCUS, sent|defwinproc },
16017 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
16018 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
16019 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
16020 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
16021 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
16022 { WM_SETFOCUS, sent|defwinproc },
16023 { 0 }
16027 static void test_SetActiveWindow(void)
16029 HWND hwnd, popup, ret;
16031 hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
16032 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
16033 100, 100, 200, 200, 0, 0, 0, NULL);
16035 popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
16036 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
16037 100, 100, 200, 200, hwnd, 0, 0, NULL);
16039 ok(hwnd != 0, "Failed to create overlapped window\n");
16040 ok(popup != 0, "Failed to create popup window\n");
16041 SetForegroundWindow( popup );
16042 flush_sequence();
16044 if (winetest_debug > 1) trace("SetActiveWindow(0)\n");
16045 ret = SetActiveWindow(0);
16046 ok( ret == popup || broken(ret == 0) /* w1064v1809 */, "Failed to SetActiveWindow(0), ret:%p\n", ret);
16047 if (ret == popup) ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", FALSE);
16048 flush_sequence();
16050 if (winetest_debug > 1) trace("SetActiveWindow(hwnd), hwnd visible\n");
16051 ret = SetActiveWindow(hwnd);
16052 if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
16053 flush_sequence();
16055 if (winetest_debug > 1) trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
16056 ret = SetActiveWindow(popup);
16057 ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
16058 ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
16059 flush_sequence();
16061 ShowWindow(hwnd, SW_HIDE);
16062 ShowWindow(popup, SW_HIDE);
16063 flush_sequence();
16065 if (winetest_debug > 1) trace("SetActiveWindow(hwnd), hwnd not visible\n");
16066 ret = SetActiveWindow(hwnd);
16067 ok( ret == NULL, "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret );
16068 ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
16069 flush_sequence();
16071 if (winetest_debug > 1) trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
16072 ret = SetActiveWindow(popup);
16073 ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
16074 ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
16075 flush_sequence();
16077 if (winetest_debug > 1) trace("done\n");
16079 DestroyWindow(hwnd);
16082 static const struct message SetForegroundWindowSeq[] =
16084 { WM_NCACTIVATE, sent|wparam, 0 },
16085 { WM_GETTEXT, sent|defwinproc|optional },
16086 { WM_ACTIVATE, sent|wparam, 0 },
16087 { WM_ACTIVATEAPP, sent|wparam, 0 },
16088 { WM_KILLFOCUS, sent },
16089 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
16090 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
16091 { 0 }
16094 static void test_SetForegroundWindow(void)
16096 HWND hwnd;
16098 hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
16099 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
16100 100, 100, 200, 200, 0, 0, 0, NULL);
16101 ok (hwnd != 0, "Failed to create overlapped window\n");
16102 SetForegroundWindow( hwnd );
16103 flush_sequence();
16105 if (winetest_debug > 1) trace("SetForegroundWindow( 0 )\n");
16106 SetForegroundWindow( 0 );
16107 ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
16108 if (winetest_debug > 1) trace("SetForegroundWindow( GetDesktopWindow() )\n");
16109 SetForegroundWindow( GetDesktopWindow() );
16110 ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
16111 "foreground top level window", FALSE);
16112 if (winetest_debug > 1) trace("done\n");
16114 DestroyWindow(hwnd);
16117 static DWORD get_input_codepage( void )
16119 DWORD cp;
16120 int ret;
16121 HKL hkl = GetKeyboardLayout( 0 );
16123 ret = GetLocaleInfoW( LOWORD(hkl), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
16124 (WCHAR *)&cp, sizeof(cp) / sizeof(WCHAR) );
16125 if (!ret) cp = CP_ACP;
16126 return cp;
16129 static void test_dbcs_wm_char(void)
16131 BYTE dbch[2];
16132 WCHAR wch, bad_wch;
16133 HWND hwnd, hwnd2;
16134 MSG msg;
16135 DWORD time;
16136 POINT pt;
16137 DWORD_PTR res;
16138 CPINFOEXA cpinfo;
16139 UINT i, j, k;
16140 struct message wmCharSeq[2];
16141 BOOL ret;
16142 DWORD cp = get_input_codepage();
16144 if (!pGetCPInfoExA)
16146 win_skip("GetCPInfoExA is not available\n");
16147 return;
16150 pGetCPInfoExA( cp, 0, &cpinfo );
16151 if (cpinfo.MaxCharSize != 2)
16153 skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
16154 return;
16157 dbch[0] = dbch[1] = 0;
16158 wch = 0;
16159 bad_wch = cpinfo.UnicodeDefaultChar;
16160 for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
16161 for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
16162 for (k = 128; k <= 255; k++)
16164 char str[2];
16165 WCHAR wstr[2];
16166 str[0] = j;
16167 str[1] = k;
16168 if (MultiByteToWideChar( cp, 0, str, 2, wstr, 2 ) == 1 &&
16169 WideCharToMultiByte( cp, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
16170 (BYTE)str[0] == j && (BYTE)str[1] == k &&
16171 HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
16173 dbch[0] = j;
16174 dbch[1] = k;
16175 wch = wstr[0];
16176 break;
16180 if (!wch)
16182 skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
16183 return;
16185 if (winetest_debug > 1) trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
16186 dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
16188 hwnd = CreateWindowExW(0, testWindowClassW, NULL,
16189 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
16190 hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
16191 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
16192 ok (hwnd != 0, "Failed to create overlapped window\n");
16193 ok (hwnd2 != 0, "Failed to create overlapped window\n");
16194 flush_events();
16195 flush_sequence();
16197 memset( wmCharSeq, 0, sizeof(wmCharSeq) );
16198 wmCharSeq[0].message = WM_CHAR;
16199 wmCharSeq[0].flags = sent|wparam;
16200 wmCharSeq[0].wParam = wch;
16202 /* posted message */
16203 PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
16204 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16205 ok( !ret, "got message %x\n", msg.message );
16206 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
16207 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16208 ok( ret, "no message\n" );
16209 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16210 ok( msg.wParam == wch, "bad wparam %Ix/%x\n", msg.wParam, wch );
16211 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16212 ok( !ret, "got message %x\n", msg.message );
16214 /* posted thread message */
16215 PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
16216 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16217 ok( !ret, "got message %x\n", msg.message );
16218 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
16219 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16220 ok( ret, "no message\n" );
16221 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16222 ok( msg.wParam == wch, "bad wparam %Ix/%x\n", msg.wParam, wch );
16223 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16224 ok( !ret, "got message %x\n", msg.message );
16226 /* sent message */
16227 flush_sequence();
16228 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
16229 ok_sequence( WmEmptySeq, "no messages", FALSE );
16230 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
16231 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16232 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16233 ok( !ret, "got message %x\n", msg.message );
16235 /* sent message with timeout */
16236 flush_sequence();
16237 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
16238 ok_sequence( WmEmptySeq, "no messages", FALSE );
16239 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
16240 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16241 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16242 ok( !ret, "got message %x\n", msg.message );
16244 /* sent message with timeout and callback */
16245 flush_sequence();
16246 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
16247 ok_sequence( WmEmptySeq, "no messages", FALSE );
16248 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
16249 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16250 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16251 ok( !ret, "got message %x\n", msg.message );
16253 /* sent message with callback */
16254 flush_sequence();
16255 SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
16256 ok_sequence( WmEmptySeq, "no messages", FALSE );
16257 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
16258 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16259 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16260 ok( !ret, "got message %x\n", msg.message );
16262 /* direct window proc call */
16263 flush_sequence();
16264 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
16265 ok_sequence( WmEmptySeq, "no messages", FALSE );
16266 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
16267 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16269 /* dispatch message */
16270 msg.hwnd = hwnd;
16271 msg.message = WM_CHAR;
16272 msg.wParam = dbch[0];
16273 msg.lParam = 0;
16274 DispatchMessageA( &msg );
16275 ok_sequence( WmEmptySeq, "no messages", FALSE );
16276 msg.wParam = dbch[1];
16277 DispatchMessageA( &msg );
16278 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16280 /* window handle is irrelevant */
16281 flush_sequence();
16282 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
16283 ok_sequence( WmEmptySeq, "no messages", FALSE );
16284 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
16285 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16286 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16287 ok( !ret, "got message %x\n", msg.message );
16289 /* interleaved post and send */
16290 flush_sequence();
16291 PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
16292 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
16293 ok_sequence( WmEmptySeq, "no messages", FALSE );
16294 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16295 ok( !ret, "got message %x\n", msg.message );
16296 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
16297 ok_sequence( WmEmptySeq, "no messages", FALSE );
16298 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16299 ok( ret, "no message\n" );
16300 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16301 ok( msg.wParam == wch, "bad wparam %Ix/%x\n", msg.wParam, wch );
16302 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16303 ok( !ret, "got message %x\n", msg.message );
16304 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
16305 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16306 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16307 ok( !ret, "got message %x\n", msg.message );
16309 /* interleaved sent message and winproc */
16310 flush_sequence();
16311 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
16312 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
16313 ok_sequence( WmEmptySeq, "no messages", FALSE );
16314 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
16315 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16316 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
16317 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16319 /* interleaved winproc and dispatch */
16320 msg.hwnd = hwnd;
16321 msg.message = WM_CHAR;
16322 msg.wParam = dbch[0];
16323 msg.lParam = 0;
16324 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
16325 DispatchMessageA( &msg );
16326 ok_sequence( WmEmptySeq, "no messages", FALSE );
16327 msg.wParam = dbch[1];
16328 DispatchMessageA( &msg );
16329 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16330 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
16331 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16333 /* interleaved sends */
16334 flush_sequence();
16335 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
16336 SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
16337 ok_sequence( WmEmptySeq, "no messages", FALSE );
16338 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
16339 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16340 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
16341 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16343 /* dbcs WM_CHAR */
16344 flush_sequence();
16345 SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
16346 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
16347 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16348 ok( !ret, "got message %x\n", msg.message );
16350 /* other char messages are not magic */
16351 PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
16352 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16353 ok( ret, "no message\n" );
16354 ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
16355 ok( msg.wParam == bad_wch, "bad wparam %Ix/%x\n", msg.wParam, bad_wch );
16356 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16357 ok( !ret, "got message %x\n", msg.message );
16358 PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
16359 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16360 ok( ret, "no message\n" );
16361 ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
16362 ok( msg.wParam == bad_wch, "bad wparam %Ix/%x\n", msg.wParam, bad_wch );
16363 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
16364 ok( !ret, "got message %x\n", msg.message );
16366 /* test retrieving messages */
16368 PostMessageW( hwnd, WM_CHAR, wch, 0 );
16369 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
16370 ok( ret, "no message\n" );
16371 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
16372 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16373 ok( msg.wParam == dbch[0], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
16374 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
16375 ok( ret, "no message\n" );
16376 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
16377 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16378 ok( msg.wParam == dbch[1], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
16379 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
16380 ok( !ret, "got message %x\n", msg.message );
16382 /* message filters */
16383 PostMessageW( hwnd, WM_CHAR, wch, 0 );
16384 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
16385 ok( ret, "no message\n" );
16386 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
16387 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16388 ok( msg.wParam == dbch[0], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
16389 /* message id is filtered, hwnd is not */
16390 ret = PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE );
16391 ok( !ret, "no message\n" );
16392 ret = PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE );
16393 ok( ret, "no message\n" );
16394 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
16395 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16396 ok( msg.wParam == dbch[1], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
16397 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
16398 ok( !ret, "got message %x\n", msg.message );
16400 /* mixing GetMessage and PostMessage */
16401 PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
16402 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
16403 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
16404 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16405 ok( msg.wParam == dbch[0], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
16406 ok( msg.lParam == 0xbeef, "bad lparam %Ix\n", msg.lParam );
16407 time = msg.time;
16408 pt = msg.pt;
16409 ok( time - GetTickCount() <= 100, "bad time %lx\n", msg.time );
16410 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
16411 ok( ret, "no message\n" );
16412 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
16413 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16414 ok( msg.wParam == dbch[1], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
16415 ok( msg.lParam == 0xbeef, "bad lparam %Ix\n", msg.lParam );
16416 ok( msg.time == time, "bad time %lx/%lx\n", msg.time, time );
16417 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 );
16418 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
16419 ok( !ret, "got message %x\n", msg.message );
16421 /* without PM_REMOVE */
16422 PostMessageW( hwnd, WM_CHAR, wch, 0 );
16423 ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
16424 ok( ret, "no message\n" );
16425 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
16426 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16427 ok( msg.wParam == dbch[0], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
16428 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
16429 ok( ret, "no message\n" );
16430 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
16431 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16432 ok( msg.wParam == dbch[0], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
16433 ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
16434 ok( ret, "no message\n" );
16435 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
16436 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16437 ok( msg.wParam == dbch[1], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
16438 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
16439 ok( ret, "no message\n" );
16440 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
16441 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16442 ok( msg.wParam == dbch[1], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] );
16443 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
16444 ok( !ret, "got message %x\n", msg.message );
16446 DestroyWindow(hwnd);
16447 DestroyWindow(hwnd2);
16450 static void test_unicode_wm_char(void)
16452 HWND hwnd;
16453 MSG msg;
16454 struct message seq[2];
16455 HKL hkl_orig, hkl_greek;
16456 DWORD cp;
16457 LCID thread_locale;
16459 hkl_orig = GetKeyboardLayout( 0 );
16460 GetLocaleInfoW( LOWORD( hkl_orig ), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, (WCHAR*)&cp, sizeof(cp) / sizeof(WCHAR) );
16461 if (cp != 1252)
16463 skip( "Default codepage %ld\n", cp );
16464 return;
16467 hkl_greek = LoadKeyboardLayoutA( "00000408", 0 );
16468 if (!hkl_greek || hkl_greek == hkl_orig /* win2k */)
16470 skip( "Unable to load Greek keyboard layout\n" );
16471 return;
16474 hwnd = CreateWindowExW( 0, testWindowClassW, NULL, WS_OVERLAPPEDWINDOW,
16475 100, 100, 200, 200, 0, 0, 0, NULL );
16476 flush_sequence();
16478 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
16480 while (GetMessageW( &msg, hwnd, 0, 0 ))
16482 if (!ignore_message( msg.message )) break;
16485 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
16486 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16487 ok( msg.wParam == 0x3b1, "bad wparam %Ix\n", msg.wParam );
16488 ok( msg.lParam == 0, "bad lparam %Ix\n", msg.lParam );
16490 DispatchMessageW( &msg );
16492 memset( seq, 0, sizeof(seq) );
16493 seq[0].message = WM_CHAR;
16494 seq[0].flags = sent|wparam;
16495 seq[0].wParam = 0x3b1;
16497 ok_sequence( seq, "unicode WM_CHAR", FALSE );
16499 flush_sequence();
16501 /* greek alpha -> 'a' in cp1252 */
16502 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
16504 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
16505 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
16506 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16507 ok( msg.wParam == 0x61, "bad wparam %Ix\n", msg.wParam );
16508 ok( msg.lParam == 0, "bad lparam %Ix\n", msg.lParam );
16510 DispatchMessageA( &msg );
16512 seq[0].wParam = 0x61;
16513 ok_sequence( seq, "unicode WM_CHAR", FALSE );
16515 thread_locale = GetThreadLocale();
16516 ActivateKeyboardLayout( hkl_greek, 0 );
16517 ok( GetThreadLocale() == thread_locale, "locale changed from %08lx to %08lx\n",
16518 thread_locale, GetThreadLocale() );
16520 flush_sequence();
16522 /* greek alpha -> 0xe1 in cp1253 */
16523 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
16525 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
16526 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
16527 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
16528 ok( msg.wParam == 0xe1, "bad wparam %Ix\n", msg.wParam );
16529 ok( msg.lParam == 0, "bad lparam %Ix\n", msg.lParam );
16531 DispatchMessageA( &msg );
16533 seq[0].wParam = 0x3b1;
16534 ok_sequence( seq, "unicode WM_CHAR", FALSE );
16536 DestroyWindow( hwnd );
16537 ActivateKeyboardLayout( hkl_orig, 0 );
16538 UnloadKeyboardLayout( hkl_greek );
16541 #define ID_LISTBOX 0x000f
16543 static const struct message wm_lb_setcursel_0[] =
16545 { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
16546 { WM_CTLCOLORLISTBOX, sent|parent },
16547 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
16548 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 1 },
16549 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 1 },
16550 { 0 }
16552 static const struct message wm_lb_setcursel_1[] =
16554 { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
16555 { WM_CTLCOLORLISTBOX, sent|parent },
16556 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
16557 { WM_CTLCOLORLISTBOX, sent|parent },
16558 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
16559 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 2 },
16560 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 2 },
16561 { 0 }
16563 static const struct message wm_lb_setcursel_2[] =
16565 { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
16566 { WM_CTLCOLORLISTBOX, sent|parent },
16567 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
16568 { WM_CTLCOLORLISTBOX, sent|parent },
16569 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
16570 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 3 },
16571 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 3 },
16572 { 0 }
16574 static const struct message wm_lb_click_0[] =
16576 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
16577 { HCBT_SETFOCUS, hook },
16578 { WM_KILLFOCUS, sent|parent },
16579 { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
16580 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
16581 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
16582 { WM_SETFOCUS, sent|defwinproc },
16584 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
16585 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
16586 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 3 },
16587 { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
16588 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
16590 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
16591 { WM_CTLCOLORLISTBOX, sent|parent },
16592 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
16593 { WM_CTLCOLORLISTBOX, sent|parent },
16594 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
16595 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
16597 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 1 },
16598 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 1 },
16600 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
16601 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
16602 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
16603 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
16604 { 0 }
16606 static const struct message wm_lb_deletestring[] =
16608 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
16609 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 1 },
16610 { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
16611 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
16612 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
16613 { 0 }
16615 static const struct message wm_lb_deletestring_reset[] =
16617 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
16618 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 1 },
16619 { LB_RESETCONTENT, sent|wparam|lparam|defwinproc|optional, 0, 0 },
16620 { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
16621 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
16622 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
16623 { 0 }
16625 static const struct message wm_lb_addstring[] =
16627 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
16628 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 1 },
16629 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
16630 /* Child ID changes each test, don't test lparam. */
16631 { EVENT_OBJECT_CREATE, winevent_hook|wparam|winevent_hook_todo, OBJID_CLIENT, 0 },
16632 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
16633 { EVENT_OBJECT_CREATE, winevent_hook|wparam|winevent_hook_todo, OBJID_CLIENT, 0 },
16634 { 0 }
16636 static const struct message wm_lb_addstring_ownerdraw[] =
16638 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
16639 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf0f2, 0xf30604ed },
16640 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 1 },
16641 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
16642 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf1f2, 0xf30604ee },
16643 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 2 },
16644 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
16645 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf2f2, 0xf30604ef },
16646 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 3 },
16647 { 0 }
16649 static const struct message wm_lb_addstring_sort_ownerdraw[] =
16651 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
16652 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf0f2, 0xf30604ed },
16653 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 1 },
16654 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
16655 { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ed, 0xf30604ee },
16656 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf1f2, 0xf30604ee },
16657 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 2 },
16658 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
16659 { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ed, 0xf30604ef },
16660 { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ee, 0xf30604ef },
16661 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf2f2, 0xf30604ef },
16662 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 3 },
16663 { 0 }
16665 static const struct message wm_lb_dblclick_0[] =
16667 { WM_LBUTTONDBLCLK, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
16668 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
16669 { 0 }
16672 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
16674 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
16676 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
16678 static LONG defwndproc_counter = 0;
16679 LRESULT ret;
16680 struct recvd_message msg;
16682 /* do not log painting messages */
16683 if (message != WM_PAINT &&
16684 message != WM_NCPAINT &&
16685 message != WM_SYNCPAINT &&
16686 message != WM_ERASEBKGND &&
16687 message != WM_NCHITTEST &&
16688 message != WM_GETTEXT &&
16689 !ignore_message( message ))
16691 msg.hwnd = hwnd;
16692 msg.message = message;
16693 msg.flags = sent|wparam|lparam;
16694 if (defwndproc_counter) msg.flags |= defwinproc;
16695 msg.wParam = wp;
16696 if (message == LB_ADDSTRING)
16697 msg.lParam = lp ? hash_Ly((const char *)lp) : 0;
16698 else
16699 msg.lParam = lp;
16700 msg.descr = "listbox";
16701 add_message(&msg);
16704 defwndproc_counter++;
16705 ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
16706 defwndproc_counter--;
16708 return ret;
16711 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
16712 int caret_index, int top_index, int line)
16714 LRESULT ret;
16716 /* calling an orig proc helps to avoid unnecessary message logging */
16717 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
16718 ok_(__FILE__, line)(ret == count, "expected count %d, got %Id\n", count, ret);
16719 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
16720 ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %Id\n", cur_sel, ret);
16721 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
16722 ok_(__FILE__, line)(ret == caret_index ||
16723 broken(cur_sel == -1 && caret_index == 0 && ret == -1), /* nt4 */
16724 "expected caret index %d, got %Id\n", caret_index, ret);
16725 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
16726 ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %Id\n", top_index, ret);
16729 static void test_listbox_messages(void)
16731 HWND parent, listbox;
16732 LRESULT ret;
16734 parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
16735 100, 100, 200, 200, 0, 0, 0, NULL);
16736 /* with LBS_HASSTRINGS */
16737 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
16738 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
16739 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
16740 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
16742 check_lb_state(listbox, 0, LB_ERR, 0, 0);
16744 flush_sequence();
16746 log_all_parent_messages++;
16748 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
16749 ok(ret == 0, "expected 0, got %Id\n", ret);
16750 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
16751 ok(ret == 1, "expected 1, got %Id\n", ret);
16752 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
16753 ok(ret == 2, "expected 2, got %Id\n", ret);
16755 ok_sequence(wm_lb_addstring_ownerdraw, "LB_ADDSTRING", FALSE);
16756 check_lb_state(listbox, 3, LB_ERR, 0, 0);
16758 flush_sequence();
16760 if (winetest_debug > 1) trace("selecting item 0\n");
16761 ret = SendMessageA(listbox, LB_SETCURSEL, 0, 0);
16762 ok(ret == 0, "expected 0, got %Id\n", ret);
16763 ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
16764 check_lb_state(listbox, 3, 0, 0, 0);
16765 flush_sequence();
16767 if (winetest_debug > 1) trace("selecting item 1\n");
16768 ret = SendMessageA(listbox, LB_SETCURSEL, 1, 0);
16769 ok(ret == 1, "expected 1, got %Id\n", ret);
16770 ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
16771 check_lb_state(listbox, 3, 1, 1, 0);
16773 if (winetest_debug > 1) trace("selecting item 2\n");
16774 ret = SendMessageA(listbox, LB_SETCURSEL, 2, 0);
16775 ok(ret == 2, "expected 2, got %Id\n", ret);
16776 ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
16777 check_lb_state(listbox, 3, 2, 2, 0);
16779 if (winetest_debug > 1) trace("clicking on item 0\n");
16780 ret = SendMessageA(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
16781 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
16782 ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0);
16783 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
16784 ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
16785 check_lb_state(listbox, 3, 0, 0, 0);
16786 flush_sequence();
16788 if (winetest_debug > 1) trace("deleting item 0\n");
16789 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
16790 ok(ret == 2, "expected 2, got %Id\n", ret);
16791 ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
16792 check_lb_state(listbox, 2, -1, 0, 0);
16793 flush_sequence();
16795 if (winetest_debug > 1) trace("deleting item 0\n");
16796 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
16797 ok(ret == 1, "expected 1, got %Id\n", ret);
16798 ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
16799 check_lb_state(listbox, 1, -1, 0, 0);
16800 flush_sequence();
16802 if (winetest_debug > 1) trace("deleting item 0\n");
16803 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
16804 ok(ret == 0, "expected 0, got %Id\n", ret);
16805 ok_sequence(wm_lb_deletestring_reset, "LB_DELETESTRING 0", FALSE );
16806 check_lb_state(listbox, 0, -1, 0, 0);
16807 flush_sequence();
16809 if (winetest_debug > 1) trace("deleting item 0\n");
16810 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
16811 ok(ret == LB_ERR, "expected LB_ERR, got %Id\n", ret);
16812 check_lb_state(listbox, 0, -1, 0, 0);
16813 flush_sequence();
16815 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
16816 ok(ret == LB_ERR, "expected LB_ERR, got %Id\n", ret);
16817 check_lb_state(listbox, 0, LB_ERR, 0, 0);
16818 flush_sequence();
16820 ret = SendMessageA(listbox, LB_RESETCONTENT, 0, 0);
16821 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
16822 check_lb_state(listbox, 0, LB_ERR, 0, 0);
16823 flush_sequence();
16825 if (winetest_debug > 1) trace("clicking on item 0\n");
16826 ret = SendMessageA(listbox, WM_LBUTTONDBLCLK, 0, MAKELPARAM(1, 1));
16827 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
16828 ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0);
16829 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
16830 ok_sequence(wm_lb_dblclick_0, "WM_LBUTTONDBLCLK 0", FALSE );
16831 check_lb_state(listbox, 0, LB_ERR, 0, 0);
16832 flush_sequence();
16834 log_all_parent_messages--;
16836 DestroyWindow(listbox);
16838 /* with LBS_SORT and without LBS_HASSTRINGS */
16839 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
16840 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_SORT | WS_VISIBLE,
16841 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
16842 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
16844 check_lb_state(listbox, 0, LB_ERR, 0, 0);
16846 flush_sequence();
16848 log_all_parent_messages++;
16850 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
16851 ok(ret == 0, "expected 0, got %Id\n", ret);
16852 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
16853 ok(ret == 1, "expected 1, got %Id\n", ret);
16854 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
16855 ok(ret == 2, "expected 2, got %Id\n", ret);
16857 ok_sequence(wm_lb_addstring_sort_ownerdraw, "LB_ADDSTRING", FALSE);
16858 check_lb_state(listbox, 3, LB_ERR, 0, 0);
16860 ret = SendMessageA(listbox, LB_RESETCONTENT, 0, 0);
16861 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
16862 check_lb_state(listbox, 0, LB_ERR, 0, 0);
16863 SetFocus(listbox); /* avoid focus messages */
16864 flush_sequence();
16866 if (winetest_debug > 1) trace("clicking on item 0\n");
16867 ret = SendMessageA(listbox, WM_LBUTTONDBLCLK, 0, MAKELPARAM(1, 1));
16868 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
16869 ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0);
16870 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
16871 ok_sequence(wm_lb_dblclick_0, "WM_LBUTTONDBLCLK 0", FALSE );
16872 check_lb_state(listbox, 0, LB_ERR, 0, 0);
16873 flush_sequence();
16875 log_all_parent_messages--;
16877 DestroyWindow(listbox);
16879 /* with LBS_HASSTRINGS */
16880 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
16881 WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | WS_VISIBLE,
16882 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
16883 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
16885 check_lb_state(listbox, 0, LB_ERR, 0, 0);
16887 flush_sequence();
16889 log_all_parent_messages++;
16891 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
16892 ok(ret == 0, "expected 0, got %Id\n", ret);
16893 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
16894 ok(ret == 1, "expected 1, got %Id\n", ret);
16895 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
16896 ok(ret == 2, "expected 2, got %Id\n", ret);
16898 ok_sequence(wm_lb_addstring, "LB_ADDSTRING", FALSE);
16899 check_lb_state(listbox, 3, LB_ERR, 0, 0);
16901 ret = SendMessageA(listbox, LB_RESETCONTENT, 0, 0);
16902 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
16903 check_lb_state(listbox, 0, LB_ERR, 0, 0);
16904 SetFocus(listbox); /* avoid focus messages */
16905 flush_sequence();
16907 if (winetest_debug > 1) trace("clicking on item 0\n");
16908 ret = SendMessageA(listbox, WM_LBUTTONDBLCLK, 0, MAKELPARAM(1, 1));
16909 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
16910 ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0);
16911 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
16912 ok_sequence(wm_lb_dblclick_0, "WM_LBUTTONDBLCLK 0", FALSE );
16913 check_lb_state(listbox, 0, LB_ERR, 0, 0);
16914 flush_sequence();
16916 log_all_parent_messages--;
16918 DestroyWindow(listbox);
16920 /* with LBS_HASSTRINGS and LBS_SORT */
16921 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
16922 WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | LBS_SORT | WS_VISIBLE,
16923 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
16924 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
16926 check_lb_state(listbox, 0, LB_ERR, 0, 0);
16928 flush_sequence();
16930 log_all_parent_messages++;
16932 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
16933 ok(ret == 0, "expected 0, got %Id\n", ret);
16934 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
16935 ok(ret == 0, "expected 0, got %Id\n", ret);
16936 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
16937 ok(ret == 1, "expected 1, got %Id\n", ret);
16939 ok_sequence(wm_lb_addstring, "LB_ADDSTRING", FALSE);
16940 check_lb_state(listbox, 3, LB_ERR, 0, 0);
16942 ret = SendMessageA(listbox, LB_RESETCONTENT, 0, 0);
16943 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
16944 check_lb_state(listbox, 0, LB_ERR, 0, 0);
16945 SetFocus(listbox); /* avoid focus messages */
16946 flush_sequence();
16948 if (winetest_debug > 1) trace("clicking on item 0\n");
16949 ret = SendMessageA(listbox, WM_LBUTTONDBLCLK, 0, MAKELPARAM(1, 1));
16950 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
16951 ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0);
16952 ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret);
16953 ok_sequence(wm_lb_dblclick_0, "WM_LBUTTONDBLCLK 0", FALSE );
16954 check_lb_state(listbox, 0, LB_ERR, 0, 0);
16955 flush_sequence();
16957 log_all_parent_messages--;
16959 DestroyWindow(listbox);
16960 DestroyWindow(parent);
16963 /*************************** Menu test ******************************/
16964 static const struct message wm_popup_menu_1[] =
16966 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
16967 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
16968 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
16969 { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
16970 { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
16971 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
16972 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
16973 { WM_INITMENU, sent|lparam, 0, 0 },
16974 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
16975 { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
16976 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
16977 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
16978 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
16979 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
16980 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
16981 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
16982 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
16983 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 1 },
16984 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
16985 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
16986 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001, 0, 0x40000000 },
16987 { EVENT_OBJECT_INVOKED, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_MENU, 0 },
16988 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
16989 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
16990 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
16991 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
16992 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
16993 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
16994 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
16995 { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
16996 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
16997 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
16998 { 0 }
17000 static const struct message wm_popup_menu_2[] =
17002 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
17003 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
17004 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
17005 { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
17006 { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
17007 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
17008 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
17009 { WM_INITMENU, sent|lparam, 0, 0 },
17010 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
17011 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
17012 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
17013 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
17014 { HCBT_CREATEWND, hook },
17015 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
17016 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
17017 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
17018 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
17019 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
17020 { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
17021 |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
17022 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 1 },
17023 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
17024 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
17025 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
17026 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
17027 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
17028 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
17029 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
17030 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
17031 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
17032 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
17033 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
17034 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 1 },
17035 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
17036 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
17037 { EVENT_OBJECT_INVOKED, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_MENU, 0 },
17038 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
17039 { HCBT_DESTROYWND, hook },
17040 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
17041 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
17042 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
17043 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
17044 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
17045 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
17046 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
17047 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
17048 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
17049 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
17050 { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
17051 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
17052 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
17053 { 0 }
17055 static const struct message wm_popup_menu_3[] =
17057 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
17058 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
17059 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
17060 { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
17061 { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
17062 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
17063 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
17064 { WM_INITMENU, sent|lparam, 0, 0 },
17065 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
17066 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
17067 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
17068 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
17069 { HCBT_CREATEWND, hook },
17070 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
17071 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
17072 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
17073 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
17074 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
17075 { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
17076 |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
17077 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 1 },
17078 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
17079 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
17080 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
17081 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
17082 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
17083 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
17084 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
17085 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
17086 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
17087 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
17088 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
17089 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 1 },
17090 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
17091 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
17092 { EVENT_OBJECT_INVOKED, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_MENU, 100 },
17093 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
17094 { HCBT_DESTROYWND, hook },
17095 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
17096 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
17097 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
17098 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 },
17099 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
17100 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
17101 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
17102 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
17103 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
17104 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
17105 { WM_COMMAND, sent|wparam|lparam, 100, 0 },
17106 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
17107 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
17108 { 0 }
17111 static const struct message wm_single_menu_item[] =
17113 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
17114 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
17115 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0x20000001 },
17116 { WM_SYSKEYDOWN, sent|wparam|lparam, 'Q', 0x20000001 },
17117 { WM_SYSCHAR, sent|wparam|lparam, 'q', 0x20000001 },
17118 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'q' },
17119 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
17120 { WM_INITMENU, sent|lparam, 0, 0 },
17121 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(300,MF_HILITE) },
17122 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
17123 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
17124 { WM_MENUCOMMAND, sent },
17125 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0xe0000001 },
17126 { WM_SYSKEYUP, sent|wparam|lparam, 'Q', 0xe0000001 },
17127 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 },
17128 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
17130 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 1 },
17131 { WM_KEYDOWN, sent|wparam|lparam, VK_ESCAPE, 1 },
17132 { WM_CHAR, sent|wparam|lparam, VK_ESCAPE, 0x00000001 },
17133 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 },
17134 { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
17135 { 0 }
17138 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
17140 if (message == WM_ENTERIDLE ||
17141 message == WM_INITMENU ||
17142 message == WM_INITMENUPOPUP ||
17143 message == WM_MENUSELECT ||
17144 message == WM_PARENTNOTIFY ||
17145 message == WM_ENTERMENULOOP ||
17146 message == WM_EXITMENULOOP ||
17147 message == WM_UNINITMENUPOPUP ||
17148 message == WM_KEYDOWN ||
17149 message == WM_KEYUP ||
17150 message == WM_CHAR ||
17151 message == WM_SYSKEYDOWN ||
17152 message == WM_SYSKEYUP ||
17153 message == WM_SYSCHAR ||
17154 message == WM_COMMAND ||
17155 message == WM_MENUCOMMAND)
17157 struct recvd_message msg;
17159 msg.hwnd = hwnd;
17160 msg.message = message;
17161 msg.flags = sent|wparam|lparam;
17162 msg.wParam = wp;
17163 msg.lParam = lp;
17164 msg.descr = "parent_menu_proc";
17165 add_message(&msg);
17168 return DefWindowProcA(hwnd, message, wp, lp);
17171 static void set_menu_style(HMENU hmenu, DWORD style)
17173 MENUINFO mi;
17174 BOOL ret;
17176 mi.cbSize = sizeof(mi);
17177 mi.fMask = MIM_STYLE;
17178 mi.dwStyle = style;
17179 SetLastError(0xdeadbeef);
17180 ret = SetMenuInfo(hmenu, &mi);
17181 ok(ret, "SetMenuInfo error %lu\n", GetLastError());
17184 static DWORD get_menu_style(HMENU hmenu)
17186 MENUINFO mi;
17187 BOOL ret;
17189 mi.cbSize = sizeof(mi);
17190 mi.fMask = MIM_STYLE;
17191 mi.dwStyle = 0;
17192 SetLastError(0xdeadbeef);
17193 ret = GetMenuInfo(hmenu, &mi);
17194 ok(ret, "GetMenuInfo error %lu\n", GetLastError());
17196 return mi.dwStyle;
17199 static void test_menu_messages(void)
17201 MSG msg;
17202 WNDCLASSA cls;
17203 HMENU hmenu, hmenu_popup;
17204 HWND hwnd;
17205 DWORD style;
17206 BOOL us_kbd = (GetKeyboardLayout(0) == (HKL)(ULONG_PTR)0x04090409);
17208 cls.style = 0;
17209 cls.lpfnWndProc = parent_menu_proc;
17210 cls.cbClsExtra = 0;
17211 cls.cbWndExtra = 0;
17212 cls.hInstance = GetModuleHandleA(0);
17213 cls.hIcon = 0;
17214 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
17215 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
17216 cls.lpszMenuName = NULL;
17217 cls.lpszClassName = "TestMenuClass";
17218 UnregisterClassA(cls.lpszClassName, cls.hInstance);
17219 register_class(&cls);
17221 SetLastError(0xdeadbeef);
17222 hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
17223 100, 100, 200, 200, 0, 0, 0, NULL);
17224 ok(hwnd != 0, "LoadMenuA error %lu\n", GetLastError());
17226 SetLastError(0xdeadbeef);
17227 hmenu = LoadMenuA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
17228 ok(hmenu != 0, "LoadMenuA error %lu\n", GetLastError());
17230 SetMenu(hwnd, hmenu);
17231 SetForegroundWindow( hwnd );
17232 flush_events();
17234 set_menu_style(hmenu, MNS_NOTIFYBYPOS);
17235 style = get_menu_style(hmenu);
17236 ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %lu\n", style);
17238 hmenu_popup = GetSubMenu(hmenu, 0);
17239 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
17240 style = get_menu_style(hmenu_popup);
17241 ok(style == 0, "expected 0, got %lu\n", style);
17243 hmenu_popup = GetSubMenu(hmenu_popup, 0);
17244 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
17245 style = get_menu_style(hmenu_popup);
17246 ok(style == 0, "expected 0, got %lu\n", style);
17248 if (!us_kbd)
17250 skip("skipping ascii VK events on non-us keyboard\n");
17251 goto done;
17254 /* Alt+E, Enter */
17255 if (winetest_debug > 1) trace("testing a popup menu command\n");
17256 flush_sequence();
17257 keybd_event(VK_MENU, 0, 0, 0);
17258 keybd_event('E', 0, 0, 0);
17259 keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
17260 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
17261 keybd_event(VK_RETURN, 0, 0, 0);
17262 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
17263 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
17265 TranslateMessage(&msg);
17266 DispatchMessageA(&msg);
17268 if (!sequence_cnt) /* we didn't get any message */
17270 skip( "queuing key events not supported\n" );
17271 goto done;
17273 /* win98 queues only a WM_KEYUP and doesn't start menu tracking */
17274 if (sequence[0].message == WM_KEYUP && sequence[0].wParam == VK_MENU)
17276 win_skip( "menu tracking through VK_MENU not supported\n" );
17277 goto done;
17279 ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
17281 /* Alt+F, Right, Enter */
17282 if (winetest_debug > 1) trace("testing submenu of a popup menu command\n");
17283 flush_sequence();
17284 keybd_event(VK_MENU, 0, 0, 0);
17285 keybd_event('F', 0, 0, 0);
17286 keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
17287 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
17288 keybd_event(VK_RIGHT, 0, 0, 0);
17289 keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
17290 keybd_event(VK_RETURN, 0, 0, 0);
17291 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
17292 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
17294 TranslateMessage(&msg);
17295 DispatchMessageA(&msg);
17297 ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
17299 if (winetest_debug > 1) trace("testing single menu item command\n");
17300 flush_sequence();
17301 keybd_event(VK_MENU, 0, 0, 0);
17302 keybd_event('Q', 0, 0, 0);
17303 keybd_event('Q', 0, KEYEVENTF_KEYUP, 0);
17304 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
17305 keybd_event(VK_ESCAPE, 0, 0, 0);
17306 keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
17307 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
17309 TranslateMessage(&msg);
17310 DispatchMessageA(&msg);
17312 ok_sequence(wm_single_menu_item, "single menu item command", FALSE);
17314 set_menu_style(hmenu, 0);
17315 style = get_menu_style(hmenu);
17316 ok(style == 0, "expected 0, got %lu\n", style);
17318 hmenu_popup = GetSubMenu(hmenu, 0);
17319 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
17320 set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
17321 style = get_menu_style(hmenu_popup);
17322 ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %lu\n", style);
17324 hmenu_popup = GetSubMenu(hmenu_popup, 0);
17325 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
17326 style = get_menu_style(hmenu_popup);
17327 ok(style == 0, "expected 0, got %lu\n", style);
17329 /* Alt+F, Right, Enter */
17330 if (winetest_debug > 1) trace("testing submenu of a popup menu command\n");
17331 flush_sequence();
17332 keybd_event(VK_MENU, 0, 0, 0);
17333 keybd_event('F', 0, 0, 0);
17334 keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
17335 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
17336 keybd_event(VK_RIGHT, 0, 0, 0);
17337 keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
17338 keybd_event(VK_RETURN, 0, 0, 0);
17339 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
17340 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
17342 TranslateMessage(&msg);
17343 DispatchMessageA(&msg);
17345 ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
17347 done:
17348 DestroyWindow(hwnd);
17349 DestroyMenu(hmenu);
17353 static void test_paintingloop(void)
17355 HWND hwnd;
17357 paint_loop_done = FALSE;
17358 hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
17359 "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
17360 100, 100, 100, 100, 0, 0, 0, NULL );
17361 ok(hwnd != 0, "PaintLoop window error %lu\n", GetLastError());
17362 ShowWindow(hwnd,SW_NORMAL);
17363 SetFocus(hwnd);
17365 while (!paint_loop_done)
17367 MSG msg;
17368 if (PeekMessageA(&msg, 0, 0, 0, 1))
17370 TranslateMessage(&msg);
17371 DispatchMessageA(&msg);
17374 DestroyWindow(hwnd);
17377 static const struct message NCRBUTTONDOWNSeq[] =
17379 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
17380 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
17381 { WM_CAPTURECHANGED, sent },
17382 { WM_CONTEXTMENU, sent, /*hwnd*/0, -1 },
17383 { 0 }
17386 static const struct message NCXBUTTONUPSeq1[] =
17388 { WM_APPCOMMAND, sent|lparam, /*hwnd*/0, MAKELPARAM(0, FAPPCOMMAND_MOUSE | APPCOMMAND_BROWSER_BACKWARD) },
17389 { 0 }
17392 static const struct message NCXBUTTONUPSeq2[] =
17394 { WM_APPCOMMAND, sent|lparam, /*hwnd*/0, MAKELPARAM(0, FAPPCOMMAND_MOUSE | APPCOMMAND_BROWSER_FORWARD) },
17395 { 0 }
17398 /* DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0) to minimized visible window */
17399 static const struct message WmRestoreMinimizedOverlappedSeq[] =
17401 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_RESTORE, 0 },
17402 { HCBT_MINMAX, hook },
17403 { WM_QUERYOPEN, sent },
17404 { WM_GETTEXT, sent|optional },
17405 { WM_NCACTIVATE, sent|optional },
17406 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
17407 { WM_WINDOWPOSCHANGED, sent|optional },
17408 { WM_WINDOWPOSCHANGING, sent|optional },
17409 { WM_GETMINMAXINFO, sent|defwinproc },
17410 { WM_NCCALCSIZE, sent|optional },
17411 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
17412 { WM_NCPAINT, sent|optional },
17413 { WM_GETTEXT, sent|defwinproc|optional },
17414 { WM_ERASEBKGND, sent|optional },
17415 { WM_WINDOWPOSCHANGED, sent|optional },
17416 { HCBT_ACTIVATE, hook },
17417 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
17418 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
17419 { WM_ACTIVATEAPP, sent|wparam, TRUE },
17420 { WM_NCACTIVATE, sent|wparam, TRUE },
17421 { WM_GETTEXT, sent|defwinproc|optional },
17422 { WM_ACTIVATE, sent|wparam, TRUE },
17423 { HCBT_SETFOCUS, hook },
17424 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
17425 { WM_SETFOCUS, sent|defwinproc },
17426 { WM_NCPAINT, sent },
17427 { WM_GETTEXT, sent|defwinproc|optional },
17428 { WM_ERASEBKGND, sent },
17429 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_FRAMECHANGED|SWP_STATECHANGED },
17430 { WM_MOVE, sent|defwinproc },
17431 { WM_SIZE, sent|defwinproc },
17432 { WM_NCCALCSIZE, sent|optional },
17433 { WM_NCPAINT, sent|optional },
17434 { WM_ERASEBKGND, sent|optional },
17435 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
17436 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
17437 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
17438 { WM_ACTIVATE, sent|wparam, TRUE },
17439 { WM_SYNCPAINT, sent|optional },
17440 { WM_PAINT, sent },
17441 { 0 }
17444 /* DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0) to an active minimized window */
17445 static const struct message WmRestoreActiveMinimizedOverlappedSeq[] =
17447 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_RESTORE, 0 },
17448 { HCBT_MINMAX, hook },
17449 { WM_QUERYOPEN, sent },
17450 { WM_GETTEXT, sent|optional },
17451 { WM_NCACTIVATE, sent },
17452 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
17453 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
17454 { WM_NCCALCSIZE, sent|optional },
17455 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sent on Win7. */
17456 { WM_MOVE, sent|optional },
17457 { WM_SIZE, sent|optional },
17458 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sent on Win7. */
17459 { WM_GETTEXT, sent|optional },
17460 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
17461 { WM_GETMINMAXINFO, sent|defwinproc },
17462 { WM_NCCALCSIZE, sent },
17463 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sent on Win8+. */
17464 { WM_NCPAINT, sent },
17465 { WM_GETTEXT, sent|defwinproc|optional },
17466 { WM_ERASEBKGND, sent },
17467 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
17468 { WM_MOVE, sent|defwinproc },
17469 { WM_SIZE, sent|defwinproc },
17470 { WM_NCCALCSIZE, sent|optional },
17471 { WM_NCPAINT, sent|optional },
17472 { WM_ERASEBKGND, sent|optional },
17473 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
17474 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */
17475 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
17476 { HCBT_SETFOCUS, hook },
17477 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
17478 { WM_SETFOCUS, sent },
17479 /* Note this WM_ACTIVATE messages even if the window is already active */
17480 { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, 0 },
17481 { WM_SYNCPAINT, sent|optional },
17482 { WM_PAINT, sent },
17483 { WM_GETMINMAXINFO, sent|optional },
17484 { 0 }
17487 static struct message WmContextMenuSeq[] = {
17488 { WM_CONTEXTMENU, sent|wparam, 0 }, /* wparams set in the code */
17489 { WM_CONTEXTMENU, sent|wparam|defwinproc, 0 },
17490 { WM_CONTEXTMENU, sent|wparam|defwinproc, 0 },
17491 { 0 }
17494 struct rbuttonup_thread_data
17496 HWND hwnd;
17497 HANDLE wndproc_finished;
17500 static DWORD CALLBACK post_rbuttonup_msg( void *arg )
17502 struct rbuttonup_thread_data *data = arg;
17503 DWORD ret;
17505 ret = WaitForSingleObject( data->wndproc_finished, 500 );
17506 todo_wine ok( ret == WAIT_OBJECT_0, "WaitForSingleObject returned %lx\n", ret );
17507 if( ret == WAIT_OBJECT_0 ) return 0;
17509 PostMessageA( data->hwnd, WM_RBUTTONUP, 0, 0 );
17510 return 0;
17513 static void test_defwinproc(void)
17515 HWND hwnd, child[3];
17516 MSG msg;
17517 BOOL gotwmquit = FALSE;
17518 POINT pos;
17519 RECT rect;
17520 INT x, y;
17521 LRESULT res;
17522 struct rbuttonup_thread_data data;
17523 char buffA[64];
17524 HANDLE thread;
17526 hwnd = CreateWindowExA(0, "TestWindowClass", "test_defwndproc",
17527 WS_VISIBLE | WS_CAPTION | WS_OVERLAPPEDWINDOW, 0,0,500,100,0,0,0, NULL);
17528 ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError());
17529 flush_events();
17531 buffA[0] = 0;
17532 GetWindowTextA(hwnd, buffA, ARRAY_SIZE(buffA));
17533 ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
17535 /* Zero high word of the lParam */
17536 res = DefWindowProcA(hwnd, WM_SETTEXT, 0, 0x1234);
17537 ok(res == 0, "WM_SETTEXT was expected to fail, %Id\n", res);
17539 GetWindowTextA(hwnd, buffA, ARRAY_SIZE(buffA));
17540 ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
17542 res = DefWindowProcW(hwnd, WM_SETTEXT, 0, 0x1234);
17543 ok(res == 0, "WM_SETTEXT was expected to fail, %Id\n", res);
17545 GetWindowTextA(hwnd, buffA, ARRAY_SIZE(buffA));
17546 ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
17548 ShowWindow(hwnd, SW_MINIMIZE);
17549 flush_events();
17550 flush_sequence();
17552 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
17553 flush_events();
17554 ok_sequence(WmRestoreMinimizedOverlappedSeq, "DefWindowProcA(SC_RESTORE):overlapped", TRUE);
17556 ShowWindow(hwnd, SW_MINIMIZE);
17557 SetActiveWindow(hwnd);
17558 ok(GetActiveWindow() == hwnd, "Unexpected active window\n");
17559 flush_events();
17560 flush_sequence();
17561 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
17562 flush_events();
17563 ok_sequence(WmRestoreActiveMinimizedOverlappedSeq, "DefWindowProcA(SC_RESTORE):active minimized overlapped", TRUE);
17565 child[0] = CreateWindowExA(0, "TestWindowClass", "1st child",
17566 WS_VISIBLE | WS_CHILD, 0,0,500,100, hwnd, 0, 0, NULL);
17567 child[1] = CreateWindowExA(0, "TestWindowClass", "2nd child",
17568 WS_VISIBLE | WS_CHILD, 0,0,500,100, child[0], 0, 0, NULL);
17569 child[2] = CreateWindowExA(0, "TestWindowClass", "3rd child",
17570 WS_VISIBLE | WS_CHILD, 0,0,500,100, child[1], 0, 0, NULL);
17571 flush_events();
17572 flush_sequence();
17573 test_context_menu = TRUE;
17574 DefWindowProcA(child[2], WM_CONTEXTMENU, 0xcafe, 0);
17575 test_context_menu = FALSE;
17576 WmContextMenuSeq[0].wParam = (WPARAM)child[2];
17577 WmContextMenuSeq[1].wParam = (WPARAM)child[1];
17578 WmContextMenuSeq[2].wParam = (WPARAM)child[0];
17579 ok_sequence(WmContextMenuSeq, "DefWindowProcA(WM_CONTEXTMENU)", FALSE);
17580 DestroyWindow(child[0]);
17582 GetCursorPos(&pos);
17583 GetWindowRect(hwnd, &rect);
17584 x = (rect.left+rect.right) / 2;
17585 y = rect.top + GetSystemMetrics(SM_CYFRAME) + 1;
17586 SetCursorPos(x, y);
17587 flush_events();
17588 res = DefWindowProcA( hwnd, WM_NCHITTEST, 0, MAKELPARAM(x, y));
17589 ok(res == HTCAPTION, "WM_NCHITTEST returned %Id\n", res);
17591 mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 );
17592 mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 );
17593 flush_events();
17595 flush_sequence();
17596 mouse_event( MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0 );
17597 /* workaround for missing support for clicking on window frame */
17598 data.hwnd = hwnd;
17599 data.wndproc_finished = CreateEventA( NULL, FALSE, FALSE, NULL );
17600 thread = CreateThread( NULL, 0, post_rbuttonup_msg, (void*)&data, 0, NULL );
17602 DefWindowProcA( hwnd, WM_NCRBUTTONDOWN, HTCAPTION, MAKELPARAM(x, y));
17603 ok_sequence(NCRBUTTONDOWNSeq, "WM_NCRBUTTONDOWN on caption", FALSE);
17605 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, 0, MAKELPARAM(x, y));
17606 ok(!res, "WM_NCXBUTTONUP returned %Id\n", res);
17607 ok_sequence(WmEmptySeq, "WM_NCXBUTTONUP without button", FALSE);
17609 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, XBUTTON1), MAKELPARAM(x, y));
17610 ok(!res, "WM_NCXBUTTONUP returned %Id\n", res);
17611 ok_sequence(NCXBUTTONUPSeq1, "WM_NCXBUTTONUP with XBUTTON1", FALSE);
17613 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, XBUTTON2), MAKELPARAM(x, y));
17614 ok(!res, "WM_NCXBUTTONUP returned %Id\n", res);
17615 ok_sequence(NCXBUTTONUPSeq2, "WM_NCXBUTTONUP with XBUTTON2", FALSE);
17617 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, 3), MAKELPARAM(x, y));
17618 ok(!res, "WM_NCXBUTTONUP returned %Id\n", res);
17619 ok_sequence(WmEmptySeq, "WM_NCXBUTTONUP with invalid button", FALSE);
17621 /* Test WM_MOUSEACTIVATE */
17622 #define TEST_MOUSEACTIVATE(A,B,C) \
17623 res = DefWindowProcA(hwnd, WM_MOUSEACTIVATE, (WPARAM)hwnd, (LPARAM)MAKELRESULT(A,0)); \
17624 ok(res == B, "WM_MOUSEACTIVATE for %s returned %Id\n", #A, res); \
17625 res = DefWindowProcA(hwnd, WM_MOUSEACTIVATE, (WPARAM)hwnd, (LPARAM)MAKELRESULT(A,WM_LBUTTONDOWN)); \
17626 ok(res == C, "WM_MOUSEACTIVATE for %s returned %Id\n", #A, res);
17628 TEST_MOUSEACTIVATE(HTERROR, MA_ACTIVATE, MA_ACTIVATE);
17629 TEST_MOUSEACTIVATE(HTTRANSPARENT, MA_ACTIVATE, MA_ACTIVATE);
17630 TEST_MOUSEACTIVATE(HTNOWHERE, MA_ACTIVATE, MA_ACTIVATE);
17631 TEST_MOUSEACTIVATE(HTCLIENT, MA_ACTIVATE, MA_ACTIVATE);
17632 TEST_MOUSEACTIVATE(HTCAPTION, MA_ACTIVATE, MA_NOACTIVATE);
17633 TEST_MOUSEACTIVATE(HTSYSMENU, MA_ACTIVATE, MA_ACTIVATE);
17634 TEST_MOUSEACTIVATE(HTSIZE, MA_ACTIVATE, MA_ACTIVATE);
17635 TEST_MOUSEACTIVATE(HTMENU, MA_ACTIVATE, MA_ACTIVATE);
17636 TEST_MOUSEACTIVATE(HTHSCROLL, MA_ACTIVATE, MA_ACTIVATE);
17637 TEST_MOUSEACTIVATE(HTVSCROLL, MA_ACTIVATE, MA_ACTIVATE);
17638 TEST_MOUSEACTIVATE(HTMINBUTTON, MA_ACTIVATE, MA_ACTIVATE);
17639 TEST_MOUSEACTIVATE(HTMAXBUTTON, MA_ACTIVATE, MA_ACTIVATE);
17640 TEST_MOUSEACTIVATE(HTLEFT, MA_ACTIVATE, MA_ACTIVATE);
17641 TEST_MOUSEACTIVATE(HTRIGHT, MA_ACTIVATE, MA_ACTIVATE);
17642 TEST_MOUSEACTIVATE(HTTOP, MA_ACTIVATE, MA_ACTIVATE);
17643 TEST_MOUSEACTIVATE(HTTOPLEFT, MA_ACTIVATE, MA_ACTIVATE);
17644 TEST_MOUSEACTIVATE(HTTOPRIGHT, MA_ACTIVATE, MA_ACTIVATE);
17645 TEST_MOUSEACTIVATE(HTBOTTOM, MA_ACTIVATE, MA_ACTIVATE);
17646 TEST_MOUSEACTIVATE(HTBOTTOMLEFT, MA_ACTIVATE, MA_ACTIVATE);
17647 TEST_MOUSEACTIVATE(HTBOTTOMRIGHT, MA_ACTIVATE, MA_ACTIVATE);
17648 TEST_MOUSEACTIVATE(HTBORDER, MA_ACTIVATE, MA_ACTIVATE);
17649 TEST_MOUSEACTIVATE(HTOBJECT, MA_ACTIVATE, MA_ACTIVATE);
17650 TEST_MOUSEACTIVATE(HTCLOSE, MA_ACTIVATE, MA_ACTIVATE);
17651 TEST_MOUSEACTIVATE(HTHELP, MA_ACTIVATE, MA_ACTIVATE);
17653 SetEvent( data.wndproc_finished );
17654 WaitForSingleObject( thread, 1000 );
17655 CloseHandle( data.wndproc_finished );
17656 CloseHandle( thread );
17658 SetCursorPos(pos.x, pos.y);
17660 DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0);
17661 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) {
17662 if( msg.message == WM_QUIT) gotwmquit = TRUE;
17663 DispatchMessageA( &msg );
17665 ok(!gotwmquit, "Unexpected WM_QUIT message!\n");
17666 DestroyWindow( hwnd);
17669 static void test_desktop_winproc(void)
17671 HINSTANCE instance = GetModuleHandleA(NULL);
17672 RECT rect, default_rect;
17673 WNDPROC desktop_proc;
17674 char buffer[256];
17675 WNDCLASSA cls;
17676 LRESULT res;
17677 HWND hwnd;
17678 BOOL ret;
17680 ret = GetClassInfoA(instance, (const CHAR *)MAKEINTATOM(32769), &cls);
17681 ok(ret, "Failed to get desktop class.\n");
17682 desktop_proc = cls.lpfnWndProc;
17684 memset(&cls, 0, sizeof(cls));
17685 cls.lpfnWndProc = desktop_proc;
17686 cls.hInstance = instance;
17687 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
17688 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
17689 cls.lpszClassName = "TestDesktopClass";
17690 register_class(&cls);
17692 hwnd = CreateWindowExA(0, cls.lpszClassName, "test_desktop_wndproc",
17693 WS_VISIBLE | WS_CAPTION | WS_OVERLAPPEDWINDOW, 0, 0, 500, 100, 0, 0, 0, NULL);
17694 if (!hwnd) /* win2003 */
17696 skip("Failed to create window with desktop window procedure.\n");
17697 goto out_unregister;
17700 memset(&cls, 0, sizeof(cls));
17701 ret = GetClassInfoA(instance, "TestDesktopClass", &cls);
17702 ok(ret, "Failed to get class info.\n");
17703 ok(cls.lpfnWndProc == desktop_proc, "Got %p, expected %p.\n", cls.lpfnWndProc, desktop_proc);
17705 GetWindowTextA(hwnd, buffer, ARRAY_SIZE(buffer));
17706 todo_wine ok(!strcmp(buffer, "test_desktop_wndproc"), "Got unexpected window text: %s.\n", buffer);
17708 res = CallWindowProcA(desktop_proc, hwnd, WM_SETTEXT, 0, (LPARAM)"test");
17709 ok(res == TRUE, "Failed to set text, %Id.\n", res);
17710 GetWindowTextA(hwnd, buffer, ARRAY_SIZE(buffer));
17711 ok(!strcmp(buffer, "test"), "Got unexpected window text: %s.\n", buffer);
17713 SetRect(&default_rect, 0, 0, 100, 100);
17714 res = DefWindowProcW(hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&default_rect);
17715 ok(!res, "Got unexpected result %Id.\n", res);
17717 SetRect(&rect, 0, 0, 100, 100);
17718 res = CallWindowProcA(desktop_proc, hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rect);
17719 ok(!res, "Got unexpected result %Id.\n", res);
17720 todo_wine ok(EqualRect(&rect, &default_rect), "rect Got %s, expected %s.\n",
17721 wine_dbgstr_rect(&rect), wine_dbgstr_rect(&default_rect));
17723 DestroyWindow(hwnd);
17725 out_unregister:
17726 UnregisterClassA("TestDesktopClass", instance);
17729 #define open_clipboard(hwnd) open_clipboard_(__LINE__, hwnd)
17730 static BOOL open_clipboard_(int line, HWND hwnd)
17732 DWORD start = GetTickCount();
17733 while (1)
17735 BOOL ret = OpenClipboard(hwnd);
17736 if (ret || GetLastError() != ERROR_ACCESS_DENIED)
17737 return ret;
17738 if (GetTickCount() - start > 100)
17740 char classname[256];
17741 DWORD le = GetLastError();
17742 HWND clipwnd = GetOpenClipboardWindow();
17743 /* Provide a hint as to the source of interference:
17744 * - The class name would typically be CLIPBRDWNDCLASS if the
17745 * clipboard was opened by a Windows application using the
17746 * ole32 API.
17747 * - And it would be __wine_clipboard_manager if it was opened in
17748 * response to a native application.
17750 GetClassNameA(clipwnd, classname, ARRAY_SIZE(classname));
17751 trace_(__FILE__, line)("%p (%s) opened the clipboard\n", clipwnd, classname);
17752 SetLastError(le);
17753 return ret;
17755 Sleep(15);
17759 #define clear_clipboard(hwnd) clear_clipboard_(__LINE__, (hwnd))
17760 static void clear_clipboard_(int line, HWND hWnd)
17762 BOOL succ;
17763 succ = open_clipboard_(line, hWnd);
17764 ok_(__FILE__, line)(succ, "OpenClipboard failed, err=%lu\n", GetLastError());
17765 succ = EmptyClipboard();
17766 ok_(__FILE__, line)(succ, "EmptyClipboard failed, err=%lu\n", GetLastError());
17767 succ = CloseClipboard();
17768 ok_(__FILE__, line)(succ, "CloseClipboard failed, err=%lu\n", GetLastError());
17771 #define expect_HWND(expected, got) expect_HWND_(__LINE__, (expected), (got))
17772 static void expect_HWND_(int line, HWND expected, HWND got)
17774 ok_(__FILE__, line)(got==expected, "Expected %p, got %p\n", expected, got);
17777 static WNDPROC pOldViewerProc;
17779 static LRESULT CALLBACK recursive_viewer_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
17781 static BOOL recursion_guard;
17783 if (message == WM_DRAWCLIPBOARD && !recursion_guard)
17785 recursion_guard = TRUE;
17786 clear_clipboard(hWnd);
17787 recursion_guard = FALSE;
17789 return CallWindowProcA(pOldViewerProc, hWnd, message, wParam, lParam);
17792 static void test_clipboard_viewers(void)
17794 static struct message wm_change_cb_chain[] =
17796 { WM_CHANGECBCHAIN, sent|wparam|lparam, 0, 0 },
17797 { 0 }
17799 static const struct message wm_clipboard_destroyed[] =
17801 { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
17802 { 0 }
17804 static struct message wm_clipboard_changed[] =
17806 { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
17807 { 0 }
17809 static struct message wm_clipboard_changed_and_owned[] =
17811 { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
17812 { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
17813 { 0 }
17816 HINSTANCE hInst = GetModuleHandleA(NULL);
17817 HWND hWnd1, hWnd2, hWnd3;
17818 HWND hOrigViewer;
17819 HWND hRet;
17821 hWnd1 = CreateWindowExA(0, "TestWindowClass", "Clipboard viewer test wnd 1",
17822 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
17823 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
17824 GetDesktopWindow(), NULL, hInst, NULL);
17825 ok(!!hWnd1, "Failed to create window, error %lu.\n", GetLastError());
17826 hWnd2 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 2",
17827 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
17828 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
17829 GetDesktopWindow(), NULL, hInst, NULL);
17830 ok(!!hWnd2, "Failed to create window, error %lu.\n", GetLastError());
17831 hWnd3 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 3",
17832 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
17833 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
17834 GetDesktopWindow(), NULL, hInst, NULL);
17835 ok(!!hWnd3, "Failed to create window, error %lu.\n", GetLastError());
17836 if (winetest_debug > 1) trace("clipbd viewers: hWnd1=%p, hWnd2=%p, hWnd3=%p\n", hWnd1, hWnd2, hWnd3);
17838 CountClipboardFormats(); /* Ensure that we do not have an X11 update to the clipboard */
17839 flush_sequence();
17841 /* Test getting the clipboard viewer and setting the viewer to NULL. */
17842 hOrigViewer = GetClipboardViewer();
17843 hRet = SetClipboardViewer(NULL);
17844 ok_sequence(WmEmptySeq, "set viewer to NULL", FALSE);
17845 expect_HWND(hOrigViewer, hRet);
17846 expect_HWND(NULL, GetClipboardViewer());
17848 /* Test registering hWnd1 as a viewer. */
17849 hRet = SetClipboardViewer(hWnd1);
17850 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
17851 ok_sequence(wm_clipboard_changed, "set viewer NULL->1", FALSE);
17852 expect_HWND(NULL, hRet);
17853 expect_HWND(hWnd1, GetClipboardViewer());
17855 /* Test that changing the clipboard actually refreshes the registered viewer. */
17856 clear_clipboard(hWnd1);
17857 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
17858 ok_sequence(wm_clipboard_changed, "clear clipbd (viewer=owner=1)", FALSE);
17860 /* Again, but with different owner. */
17861 clear_clipboard(hWnd2);
17862 wm_clipboard_changed_and_owned[1].wParam = (WPARAM) GetClipboardOwner();
17863 ok_sequence(wm_clipboard_changed_and_owned, "clear clipbd (viewer=1, owner=2)", FALSE);
17865 /* Test re-registering same window. */
17866 hRet = SetClipboardViewer(hWnd1);
17867 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
17868 ok_sequence(wm_clipboard_changed, "set viewer 1->1", FALSE);
17869 expect_HWND(hWnd1, hRet);
17870 expect_HWND(hWnd1, GetClipboardViewer());
17872 /* Test ChangeClipboardChain. */
17873 ChangeClipboardChain(hWnd2, hWnd3);
17874 wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
17875 wm_change_cb_chain[0].lParam = (LPARAM) hWnd3;
17876 ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=3)", FALSE);
17877 expect_HWND(hWnd1, GetClipboardViewer());
17879 ChangeClipboardChain(hWnd2, NULL);
17880 wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
17881 wm_change_cb_chain[0].lParam = 0;
17882 ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=NULL)", FALSE);
17883 expect_HWND(hWnd1, GetClipboardViewer());
17885 ChangeClipboardChain(NULL, hWnd2);
17886 ok_sequence(WmEmptySeq, "change chain (viewer=1, remove=NULL, next=2)", FALSE);
17887 expect_HWND(hWnd1, GetClipboardViewer());
17889 /* Actually change clipboard viewer with ChangeClipboardChain. */
17890 ChangeClipboardChain(hWnd1, hWnd2);
17891 ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=2)", FALSE);
17892 expect_HWND(hWnd2, GetClipboardViewer());
17894 /* Test that no refresh messages are sent when viewer has unregistered. */
17895 clear_clipboard(hWnd2);
17896 ok_sequence(WmEmptySeq, "clear clipd (viewer=2, owner=1)", FALSE);
17898 /* Register hWnd1 again. */
17899 ChangeClipboardChain(hWnd2, hWnd1);
17900 ok_sequence(WmEmptySeq, "change chain (viewer=remove=2, next=1)", FALSE);
17901 expect_HWND(hWnd1, GetClipboardViewer());
17903 /* Subclass hWnd1 so that when it receives a WM_DRAWCLIPBOARD message, it
17904 * changes the clipboard. When this happens, the system shouldn't send
17905 * another WM_DRAWCLIPBOARD (as this could cause an infinite loop).
17907 pOldViewerProc = (WNDPROC) SetWindowLongPtrA(hWnd1, GWLP_WNDPROC, (LONG_PTR) recursive_viewer_proc);
17908 clear_clipboard(hWnd2);
17909 /* The clipboard owner is changed in recursive_viewer_proc: */
17910 wm_clipboard_changed[0].wParam = (WPARAM) hWnd2;
17911 ok_sequence(wm_clipboard_changed, "recursive clear clipbd (viewer=1, owner=2)", TRUE);
17913 /* Test unregistering. */
17914 ChangeClipboardChain(hWnd1, NULL);
17915 ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=NULL)", FALSE);
17916 expect_HWND(NULL, GetClipboardViewer());
17918 clear_clipboard(hWnd1);
17919 ok_sequence(wm_clipboard_destroyed, "clear clipbd (no viewer, owner=1)", FALSE);
17921 DestroyWindow(hWnd1);
17922 DestroyWindow(hWnd2);
17923 DestroyWindow(hWnd3);
17924 SetClipboardViewer(hOrigViewer);
17927 static void test_PostMessage(void)
17929 static const struct
17931 HWND hwnd;
17932 BOOL ret;
17933 } data[] =
17935 { HWND_TOP /* 0 */, TRUE },
17936 { HWND_BROADCAST, TRUE },
17937 { HWND_BOTTOM, TRUE },
17938 { HWND_TOPMOST, TRUE },
17939 { HWND_NOTOPMOST, FALSE },
17940 { HWND_MESSAGE, FALSE },
17941 { (HWND)0xdeadbeef, FALSE }
17943 int i;
17944 HWND hwnd;
17945 BOOL ret;
17946 MSG msg;
17947 static const WCHAR staticW[] = {'s','t','a','t','i','c',0};
17949 SetLastError(0xdeadbeef);
17950 hwnd = CreateWindowExW(0, staticW, NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
17951 if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
17953 win_skip("Skipping some PostMessage tests on Win9x/WinMe\n");
17954 return;
17956 ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError());
17958 flush_events();
17960 PostMessageA(hwnd, WM_USER+1, 0x1234, 0x5678);
17961 PostMessageA(0, WM_USER+2, 0x5678, 0x1234);
17963 for (i = 0; i < ARRAY_SIZE(data); i++)
17965 memset(&msg, 0xab, sizeof(msg));
17966 ret = PeekMessageA(&msg, data[i].hwnd, 0, 0, PM_NOREMOVE);
17967 ok(ret == data[i].ret, "%d: hwnd %p expected %d, got %d\n", i, data[i].hwnd, data[i].ret, ret);
17968 if (data[i].ret)
17970 if (data[i].hwnd)
17971 ok(ret && msg.hwnd == 0 && msg.message == WM_USER+2 &&
17972 msg.wParam == 0x5678 && msg.lParam == 0x1234,
17973 "%d: got ret %d hwnd %p msg %04x wParam %08Ix lParam %08Ix instead of TRUE/0/WM_USER+2/0x5678/0x1234\n",
17974 i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam);
17975 else
17976 ok(ret && msg.hwnd == hwnd && msg.message == WM_USER+1 &&
17977 msg.wParam == 0x1234 && msg.lParam == 0x5678,
17978 "%d: got ret %d hwnd %p msg %04x wParam %08Ix lParam %08Ix instead of TRUE/%p/WM_USER+1/0x1234/0x5678\n",
17979 i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam, msg.hwnd);
17983 DestroyWindow(hwnd);
17984 flush_events();
17987 static WPARAM g_broadcast_wparam;
17988 static UINT g_broadcast_msg;
17989 static LRESULT WINAPI broadcast_test_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
17991 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
17993 if (message == g_broadcast_msg)
17994 g_broadcast_wparam = wParam;
17996 return CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
17998 static WNDPROC *g_oldproc_sub;
17999 static WPARAM *g_broadcast_sub_wparam;
18000 static LRESULT WINAPI broadcast_test_sub_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
18002 int sub_index = GetWindowLongPtrA(hwnd, GWLP_USERDATA);
18004 if (message == g_broadcast_msg)
18005 g_broadcast_sub_wparam[sub_index] = wParam;
18007 return CallWindowProcA(g_oldproc_sub[sub_index], hwnd, message, wParam, lParam);
18010 static void test_broadcast(void)
18012 static const UINT messages[] =
18014 WM_USER-1,
18015 WM_USER,
18016 WM_USER+1,
18017 0xc000-1,
18018 0xc000, /* lowest possible atom returned by RegisterWindowMessage */
18019 0xffff,
18021 static const struct
18023 LONG style;
18024 BOOL receive;
18025 } bcast_expect[] =
18027 {WS_OVERLAPPED, TRUE},
18028 {WS_OVERLAPPED|WS_DLGFRAME, TRUE},
18029 {WS_OVERLAPPED|WS_BORDER, TRUE},
18030 {WS_OVERLAPPED|WS_CAPTION, TRUE},
18031 {WS_CHILD, FALSE},
18032 {WS_CHILD|WS_DLGFRAME, FALSE},
18033 {WS_CHILD|WS_BORDER, FALSE},
18034 {WS_CHILD|WS_CAPTION, FALSE},
18035 {WS_CHILD|WS_POPUP, TRUE},
18036 {WS_POPUP, TRUE},
18037 {WS_POPUP|WS_DLGFRAME, TRUE},
18038 {WS_POPUP|WS_BORDER, TRUE},
18039 {WS_POPUP|WS_CAPTION, TRUE},
18041 WNDPROC oldproc;
18042 unsigned int i, j;
18043 HWND hwnd;
18044 HWND *hwnd_sub;
18046 hwnd_sub = malloc(ARRAY_SIZE(bcast_expect) * sizeof(*hwnd_sub));
18047 g_oldproc_sub = malloc(ARRAY_SIZE(bcast_expect) * sizeof(*g_oldproc_sub));
18048 g_broadcast_sub_wparam = malloc(ARRAY_SIZE(bcast_expect) * sizeof(*g_broadcast_sub_wparam));
18050 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, NULL);
18051 ok(hwnd != NULL, "got %p\n", hwnd);
18053 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)broadcast_test_proc);
18054 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
18056 for (i = 0; i < ARRAY_SIZE(messages); i++)
18058 BOOL ret;
18059 BOOL msg_expected = (messages[i] < WM_USER || messages[i] >= 0xc000);
18060 MSG msg;
18062 flush_events();
18063 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
18066 /* post, broadcast */
18067 ret = PostMessageA(HWND_BROADCAST, messages[i], 0, 0);
18068 ok(ret, "%d: got %d, error %ld\n", i, ret, GetLastError());
18070 memset(&msg, 0xab, sizeof(msg));
18071 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
18072 ok(ret == msg_expected, "%d: message %04x, got %d, error %ld\n", i, messages[i], ret, GetLastError());
18073 if (msg_expected)
18074 ok(msg.hwnd == hwnd, "%d: got %p\n", i, msg.hwnd);
18076 /* post, topmost */
18077 ret = PostMessageA(HWND_TOPMOST, messages[i], 0, 0);
18078 ok(ret, "%d: got %d, error %ld\n", i, ret, GetLastError());
18080 memset(&msg, 0xab, sizeof(msg));
18081 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
18082 ok(ret == msg_expected, "%d: message %04x, got %d, error %ld\n", i, messages[i], ret, GetLastError());
18083 if (msg_expected)
18084 ok(msg.hwnd == hwnd, "%d: got %p\n", i, msg.hwnd);
18087 for (j = 0; j < ARRAY_SIZE(bcast_expect); j++)
18089 hwnd_sub[j] = CreateWindowA("static", NULL, bcast_expect[j].style, 0, 0, 0, 0, hwnd, 0, 0, NULL);
18090 ok(hwnd_sub[j] != NULL, "got %p\n", hwnd_sub[j]);
18091 /* CreateWindow adds extra style flags, so call SetWindowLong to clear some of those. */
18092 SetWindowLongA(hwnd_sub[j], GWL_STYLE, bcast_expect[j].style);
18094 g_oldproc_sub[j] = (WNDPROC)SetWindowLongPtrA(hwnd_sub[j], GWLP_WNDPROC, (LONG_PTR)broadcast_test_sub_proc);
18095 SetWindowLongPtrA(hwnd_sub[j], GWLP_USERDATA, (LONG_PTR)j);
18098 for (i = 0; i < ARRAY_SIZE(messages); i++)
18100 BOOL ret;
18101 BOOL msg_expected = (messages[i] < WM_USER || messages[i] >= 0xc000);
18103 /* send, broadcast */
18104 g_broadcast_wparam = 0xdead;
18105 for (j = 0; j < ARRAY_SIZE(bcast_expect); j++)
18106 g_broadcast_sub_wparam[j] = 0xdead;
18107 g_broadcast_msg = messages[i];
18108 ret = SendMessageTimeoutA(HWND_BROADCAST, messages[i], 0xbaadbeef, 0, SMTO_NORMAL, 2000, NULL);
18109 if (!ret && GetLastError() == ERROR_TIMEOUT)
18110 win_skip("broadcasting test %d, timeout\n", i);
18111 else
18113 WPARAM wparam_expected = msg_expected ? 0xbaadbeef : 0xdead;
18114 ok(g_broadcast_wparam == wparam_expected, "%d: message %04x, got %#Ix, error %ld\n",
18115 i, messages[i], g_broadcast_wparam, GetLastError());
18116 for (j = 0; j < ARRAY_SIZE(bcast_expect); j++)
18118 wparam_expected = (msg_expected && bcast_expect[j].receive) ? 0xbaadbeef : 0xdead;
18119 ok(g_broadcast_sub_wparam[j] == wparam_expected,
18120 "%d,%d: message %04x, got %#Ix, error %ld\n", i, j, messages[i],
18121 g_broadcast_sub_wparam[j], GetLastError());
18125 /* send, topmost */
18126 g_broadcast_wparam = 0xdead;
18127 for (j = 0; j < ARRAY_SIZE(bcast_expect); j++)
18128 g_broadcast_sub_wparam[j] = 0xdead;
18129 ret = SendMessageTimeoutA(HWND_TOPMOST, messages[i], 0xbaadbeef, 0, SMTO_NORMAL, 2000, NULL);
18130 if (!ret && GetLastError() == ERROR_TIMEOUT)
18131 win_skip("broadcasting test %d, timeout\n", i);
18132 else
18134 WPARAM wparam_expected = msg_expected ? 0xbaadbeef : 0xdead;
18135 ok(g_broadcast_wparam == wparam_expected, "%d: message %04x, got %#Ix, error %ld\n",
18136 i, messages[i], g_broadcast_wparam, GetLastError());
18137 for (j = 0; j < ARRAY_SIZE(bcast_expect); j++)
18139 wparam_expected = (msg_expected && bcast_expect[j].receive) ? 0xbaadbeef : 0xdead;
18140 ok(g_broadcast_sub_wparam[j] == wparam_expected,
18141 "%d,%d: message %04x, got %#Ix, error %ld\n", i, j, messages[i],
18142 g_broadcast_sub_wparam[j], GetLastError());
18147 for (j = 0; j < ARRAY_SIZE(bcast_expect); j++)
18148 DestroyWindow(hwnd_sub[j]);
18150 free(g_broadcast_sub_wparam);
18151 free(g_oldproc_sub);
18152 free(hwnd_sub);
18154 DestroyWindow(hwnd);
18157 static const struct
18159 DWORD exp, broken;
18160 BOOL todo;
18161 } wait_idle_expect[] =
18163 /* 0 */ { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
18164 { WAIT_TIMEOUT, 0, FALSE },
18165 { WAIT_TIMEOUT, 0, FALSE },
18166 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
18167 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
18168 /* 5 */ { WAIT_TIMEOUT, 0, FALSE },
18169 { WAIT_TIMEOUT, 0, FALSE },
18170 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
18171 { 0, 0, FALSE },
18172 { 0, 0, FALSE },
18173 /* 10 */ { 0, 0, FALSE },
18174 { 0, 0, FALSE },
18175 { 0, WAIT_TIMEOUT, FALSE },
18176 { 0, 0, FALSE },
18177 { 0, 0, FALSE },
18178 /* 15 */ { 0, 0, FALSE },
18179 { WAIT_TIMEOUT, 0, FALSE },
18180 { WAIT_TIMEOUT, 0, FALSE },
18181 { WAIT_TIMEOUT, 0, FALSE },
18182 { WAIT_TIMEOUT, 0, FALSE },
18183 /* 20 */ { WAIT_TIMEOUT, 0, FALSE },
18186 static DWORD CALLBACK do_wait_idle_child_thread( void *arg )
18188 MSG msg;
18190 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
18191 Sleep( 200 );
18192 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
18193 return 0;
18196 static void do_wait_idle_child( int arg )
18198 WNDCLASSA cls;
18199 MSG msg;
18200 HWND hwnd = 0;
18201 HANDLE thread;
18202 DWORD id;
18203 HANDLE start_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_start" );
18204 HANDLE end_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_end" );
18206 memset( &cls, 0, sizeof(cls) );
18207 cls.lpfnWndProc = DefWindowProcA;
18208 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
18209 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
18210 cls.lpszClassName = "TestClass";
18211 register_class(&cls);
18213 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ); /* create the msg queue */
18215 ok( start_event != 0, "failed to create start event, error %lu\n", GetLastError() );
18216 ok( end_event != 0, "failed to create end event, error %lu\n", GetLastError() );
18218 switch (arg)
18220 case 0:
18221 SetEvent( start_event );
18222 break;
18223 case 1:
18224 SetEvent( start_event );
18225 Sleep( 200 );
18226 PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
18227 break;
18228 case 2:
18229 SetEvent( start_event );
18230 Sleep( 200 );
18231 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
18232 PostThreadMessageA( GetCurrentThreadId(), WM_COMMAND, 0x1234, 0xabcd );
18233 PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
18234 break;
18235 case 3:
18236 SetEvent( start_event );
18237 Sleep( 200 );
18238 SendMessageA( HWND_BROADCAST, WM_WININICHANGE, 0, 0 );
18239 break;
18240 case 4:
18241 SetEvent( start_event );
18242 Sleep( 200 );
18243 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
18244 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
18245 break;
18246 case 5:
18247 SetEvent( start_event );
18248 Sleep( 200 );
18249 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
18250 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
18251 break;
18252 case 6:
18253 SetEvent( start_event );
18254 Sleep( 200 );
18255 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
18256 while (PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ))
18258 GetMessageA( &msg, 0, 0, 0 );
18259 DispatchMessageA( &msg );
18261 break;
18262 case 7:
18263 SetEvent( start_event );
18264 Sleep( 200 );
18265 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
18266 SetTimer( hwnd, 3, 1, NULL );
18267 Sleep( 200 );
18268 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
18269 break;
18270 case 8:
18271 SetEvent( start_event );
18272 Sleep( 200 );
18273 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
18274 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
18275 break;
18276 case 9:
18277 SetEvent( start_event );
18278 Sleep( 200 );
18279 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
18280 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
18281 for (;;) GetMessageA( &msg, 0, 0, 0 );
18282 break;
18283 case 10:
18284 SetEvent( start_event );
18285 Sleep( 200 );
18286 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
18287 SetTimer( hwnd, 3, 1, NULL );
18288 Sleep( 200 );
18289 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
18290 break;
18291 case 11:
18292 SetEvent( start_event );
18293 Sleep( 200 );
18294 return; /* exiting the process makes WaitForInputIdle return success too */
18295 case 12:
18296 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
18297 Sleep( 200 );
18298 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
18299 SetEvent( start_event );
18300 break;
18301 case 13:
18302 SetEvent( start_event );
18303 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
18304 Sleep( 200 );
18305 thread = CreateThread( NULL, 0, do_wait_idle_child_thread, NULL, 0, &id );
18306 WaitForSingleObject( thread, 10000 );
18307 CloseHandle( thread );
18308 break;
18309 case 14:
18310 SetEvent( start_event );
18311 Sleep( 200 );
18312 PeekMessageA( &msg, HWND_TOPMOST, 0, 0, PM_NOREMOVE );
18313 break;
18314 case 15:
18315 SetEvent( start_event );
18316 Sleep( 200 );
18317 PeekMessageA( &msg, HWND_BROADCAST, 0, 0, PM_NOREMOVE );
18318 break;
18319 case 16:
18320 SetEvent( start_event );
18321 Sleep( 200 );
18322 PeekMessageA( &msg, HWND_BOTTOM, 0, 0, PM_NOREMOVE );
18323 break;
18324 case 17:
18325 SetEvent( start_event );
18326 Sleep( 200 );
18327 PeekMessageA( &msg, (HWND)0xdeadbeef, 0, 0, PM_NOREMOVE );
18328 break;
18329 case 18:
18330 SetEvent( start_event );
18331 Sleep( 200 );
18332 PeekMessageA( &msg, HWND_NOTOPMOST, 0, 0, PM_NOREMOVE );
18333 break;
18334 case 19:
18335 SetEvent( start_event );
18336 Sleep( 200 );
18337 PeekMessageA( &msg, HWND_MESSAGE, 0, 0, PM_NOREMOVE );
18338 break;
18339 case 20:
18340 SetEvent( start_event );
18341 Sleep( 200 );
18342 PeekMessageA( &msg, GetDesktopWindow(), 0, 0, PM_NOREMOVE );
18343 break;
18345 WaitForSingleObject( end_event, 2000 );
18346 CloseHandle( start_event );
18347 CloseHandle( end_event );
18348 if (hwnd) DestroyWindow( hwnd );
18351 static LRESULT CALLBACK wait_idle_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
18353 if (msg == WM_WININICHANGE) Sleep( 200 ); /* make sure the child waits */
18354 return DefWindowProcA( hwnd, msg, wp, lp );
18357 static DWORD CALLBACK wait_idle_thread( void *arg )
18359 WNDCLASSA cls;
18360 MSG msg;
18361 HWND hwnd;
18363 memset( &cls, 0, sizeof(cls) );
18364 cls.lpfnWndProc = wait_idle_proc;
18365 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
18366 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
18367 cls.lpszClassName = "TestClass";
18368 register_class(&cls);
18370 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL);
18371 while (GetMessageA( &msg, 0, 0, 0 )) DispatchMessageA( &msg );
18372 DestroyWindow(hwnd);
18373 return 0;
18376 static void test_WaitForInputIdle( char *argv0 )
18378 char path[MAX_PATH];
18379 PROCESS_INFORMATION pi;
18380 STARTUPINFOA startup;
18381 BOOL ret;
18382 HANDLE start_event, end_event, thread;
18383 unsigned int i;
18384 DWORD id;
18385 const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)GetModuleHandleA(0);
18386 const IMAGE_NT_HEADERS *nt = (const IMAGE_NT_HEADERS *)((const char *)dos + dos->e_lfanew);
18387 BOOL console_app = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI);
18389 if (console_app) /* build the test with -mwindows for better coverage */
18390 trace( "not built as a GUI app, WaitForInputIdle may not be fully tested\n" );
18392 start_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_start");
18393 end_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_end");
18394 ok(start_event != 0, "failed to create start event, error %lu\n", GetLastError());
18395 ok(end_event != 0, "failed to create end event, error %lu\n", GetLastError());
18397 memset( &startup, 0, sizeof(startup) );
18398 startup.cb = sizeof(startup);
18399 startup.dwFlags = STARTF_USESHOWWINDOW;
18400 startup.wShowWindow = SW_SHOWNORMAL;
18402 thread = CreateThread( NULL, 0, wait_idle_thread, NULL, 0, &id );
18404 for (i = 0; i < ARRAY_SIZE(wait_idle_expect); i++)
18406 ResetEvent( start_event );
18407 ResetEvent( end_event );
18408 sprintf( path, "%s msg %u", argv0, i );
18409 ret = CreateProcessA( NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &pi );
18410 ok( ret, "CreateProcess '%s' failed err %lu.\n", path, GetLastError() );
18411 if (ret)
18413 ret = WaitForSingleObject( start_event, 5000 );
18414 ok( ret == WAIT_OBJECT_0, "%u: WaitForSingleObject failed\n", i );
18415 if (ret == WAIT_OBJECT_0)
18417 ret = WaitForInputIdle( pi.hProcess, 1000 );
18418 if (ret == WAIT_FAILED)
18419 ok( console_app ||
18420 ret == wait_idle_expect[i].exp ||
18421 broken(ret == wait_idle_expect[i].broken),
18422 "%u: WaitForInputIdle error %08x expected %08lx\n",
18423 i, ret, wait_idle_expect[i].exp );
18424 else todo_wine_if (wait_idle_expect[i].todo)
18425 ok( ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken),
18426 "%u: WaitForInputIdle error %08x expected %08lx\n",
18427 i, ret, wait_idle_expect[i].exp );
18428 SetEvent( end_event );
18429 WaitForSingleObject( pi.hProcess, 1000 ); /* give it a chance to exit on its own */
18431 TerminateProcess( pi.hProcess, 0 ); /* just in case */
18432 wait_child_process( pi.hProcess );
18433 ret = WaitForInputIdle( pi.hProcess, 100 );
18434 ok( ret == WAIT_FAILED, "%u: WaitForInputIdle after exit error %08x\n", i, ret );
18435 CloseHandle( pi.hProcess );
18436 CloseHandle( pi.hThread );
18439 CloseHandle( end_event );
18440 CloseHandle( start_event );
18441 PostThreadMessageA( id, WM_QUIT, 0, 0 );
18442 WaitForSingleObject( thread, 10000 );
18443 CloseHandle( thread );
18446 static const struct message WmSetParentSeq_1[] = {
18447 { WM_SHOWWINDOW, sent|wparam, 0 },
18448 { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
18449 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
18450 { WM_CHILDACTIVATE, sent },
18451 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE },
18452 { WM_MOVE, sent|defwinproc|wparam, 0 },
18453 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
18454 { WM_SHOWWINDOW, sent|wparam, 1 },
18455 { 0 }
18458 static const struct message WmSetParentSeq_2[] = {
18459 { WM_SHOWWINDOW, sent|wparam, 0 },
18460 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
18461 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
18462 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
18463 { HCBT_SETFOCUS, hook|optional },
18464 { WM_NCACTIVATE, sent|wparam|optional, 0 },
18465 { WM_ACTIVATE, sent|wparam|optional, 0 },
18466 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
18467 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
18468 { WM_KILLFOCUS, sent|wparam, 0 },
18469 { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
18470 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
18471 { HCBT_ACTIVATE, hook|optional },
18472 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|optional, 0, 0 },
18473 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
18474 { WM_NCACTIVATE, sent|wparam|optional, 1 },
18475 { WM_ACTIVATE, sent|wparam|optional, 1 },
18476 { HCBT_SETFOCUS, hook|optional },
18477 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
18478 { WM_SETFOCUS, sent|optional|defwinproc },
18479 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOCLIENTSIZE },
18480 { WM_MOVE, sent|defwinproc|wparam, 0 },
18481 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
18482 { WM_SHOWWINDOW, sent|wparam, 1 },
18483 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
18484 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
18485 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
18486 { 0 }
18490 static void test_SetParent(void)
18492 HWND parent1, parent2, child, popup;
18493 RECT rc, rc_old;
18495 parent1 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
18496 100, 100, 200, 200, 0, 0, 0, NULL);
18497 ok(parent1 != 0, "Failed to create parent1 window\n");
18499 parent2 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
18500 400, 100, 200, 200, 0, 0, 0, NULL);
18501 ok(parent2 != 0, "Failed to create parent2 window\n");
18503 /* WS_CHILD window */
18504 child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD | WS_VISIBLE,
18505 10, 10, 150, 150, parent1, 0, 0, NULL);
18506 ok(child != 0, "Failed to create child window\n");
18508 GetWindowRect(parent1, &rc);
18509 if (winetest_debug > 1) trace("parent1 %s\n", wine_dbgstr_rect(&rc));
18510 GetWindowRect(child, &rc_old);
18511 MapWindowPoints(0, parent1, (POINT *)&rc_old, 2);
18512 if (winetest_debug > 1) trace("child %s\n", wine_dbgstr_rect(&rc_old));
18514 flush_sequence();
18516 SetParent(child, parent2);
18517 flush_events();
18518 ok_sequence(WmSetParentSeq_1, "SetParent() visible WS_CHILD", FALSE);
18520 ok(GetWindowLongA(child, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
18521 ok(!IsWindowVisible(child), "IsWindowVisible() should return FALSE\n");
18523 GetWindowRect(parent2, &rc);
18524 if (winetest_debug > 1) trace("parent2 %s\n", wine_dbgstr_rect(&rc));
18525 GetWindowRect(child, &rc);
18526 MapWindowPoints(0, parent2, (POINT *)&rc, 2);
18527 if (winetest_debug > 1) trace("child %s\n", wine_dbgstr_rect(&rc));
18529 ok(EqualRect(&rc_old, &rc), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc_old),
18530 wine_dbgstr_rect(&rc));
18532 /* WS_POPUP window */
18533 popup = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP | WS_VISIBLE,
18534 20, 20, 100, 100, 0, 0, 0, NULL);
18535 ok(popup != 0, "Failed to create popup window\n");
18537 GetWindowRect(popup, &rc_old);
18538 if (winetest_debug > 1) trace("popup %s\n", wine_dbgstr_rect(&rc_old));
18540 flush_sequence();
18542 SetParent(popup, child);
18543 flush_events();
18544 ok_sequence(WmSetParentSeq_2, "SetParent() visible WS_POPUP", TRUE);
18546 ok(GetWindowLongA(popup, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
18547 ok(!IsWindowVisible(popup), "IsWindowVisible() should return FALSE\n");
18549 GetWindowRect(child, &rc);
18550 if (winetest_debug > 1) trace("parent2 %s\n", wine_dbgstr_rect(&rc));
18551 GetWindowRect(popup, &rc);
18552 MapWindowPoints(0, child, (POINT *)&rc, 2);
18553 if (winetest_debug > 1) trace("popup %s\n", wine_dbgstr_rect(&rc));
18555 ok(EqualRect(&rc_old, &rc), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc_old),
18556 wine_dbgstr_rect(&rc));
18558 DestroyWindow(popup);
18559 DestroyWindow(child);
18560 DestroyWindow(parent1);
18561 DestroyWindow(parent2);
18563 flush_sequence();
18566 static const struct message WmKeyReleaseOnly[] = {
18567 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x80000001 },
18568 { WM_KEYUP, sent|wparam|lparam, 0x41, 0x80000001 },
18569 { 0 }
18571 static const struct message WmKeyPressNormal[] = {
18572 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x1 },
18573 { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x1 },
18574 { 0 }
18576 static const struct message WmKeyPressRepeat[] = {
18577 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x40000001 },
18578 { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x40000001 },
18579 { 0 }
18581 static const struct message WmKeyReleaseNormal[] = {
18582 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0xc0000001 },
18583 { WM_KEYUP, sent|wparam|lparam, 0x41, 0xc0000001 },
18584 { 0 }
18587 static void test_keyflags(void)
18589 HWND test_window;
18590 SHORT key_state;
18591 BYTE keyboard_state[256];
18592 MSG msg;
18594 test_window = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
18595 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
18596 0, 0, 0, NULL);
18598 flush_events();
18599 flush_sequence();
18601 /* keyup without a keydown */
18602 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
18603 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
18604 DispatchMessageA(&msg);
18605 ok_sequence(WmKeyReleaseOnly, "key release only", TRUE);
18607 key_state = GetAsyncKeyState(0x41);
18608 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
18610 key_state = GetKeyState(0x41);
18611 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
18613 /* keydown */
18614 keybd_event(0x41, 0, 0, 0);
18615 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
18616 DispatchMessageA(&msg);
18617 ok_sequence(WmKeyPressNormal, "key press only", FALSE);
18619 key_state = GetAsyncKeyState(0x41);
18620 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
18622 key_state = GetKeyState(0x41);
18623 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
18625 /* keydown repeat */
18626 keybd_event(0x41, 0, 0, 0);
18627 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
18628 DispatchMessageA(&msg);
18629 ok_sequence(WmKeyPressRepeat, "key press repeat", FALSE);
18631 key_state = GetAsyncKeyState(0x41);
18632 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
18634 key_state = GetKeyState(0x41);
18635 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
18637 /* keyup */
18638 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
18639 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
18640 DispatchMessageA(&msg);
18641 ok_sequence(WmKeyReleaseNormal, "key release repeat", FALSE);
18643 key_state = GetAsyncKeyState(0x41);
18644 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
18646 key_state = GetKeyState(0x41);
18647 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
18649 /* set the key state in this thread */
18650 GetKeyboardState(keyboard_state);
18651 keyboard_state[0x41] = 0x80;
18652 SetKeyboardState(keyboard_state);
18654 key_state = GetAsyncKeyState(0x41);
18655 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
18657 /* keydown */
18658 keybd_event(0x41, 0, 0, 0);
18659 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
18660 DispatchMessageA(&msg);
18661 ok_sequence(WmKeyPressRepeat, "key press after setkeyboardstate", TRUE);
18663 key_state = GetAsyncKeyState(0x41);
18664 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
18666 key_state = GetKeyState(0x41);
18667 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
18669 /* clear the key state in this thread */
18670 GetKeyboardState(keyboard_state);
18671 keyboard_state[0x41] = 0;
18672 SetKeyboardState(keyboard_state);
18674 key_state = GetAsyncKeyState(0x41);
18675 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
18677 /* keyup */
18678 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
18679 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
18680 DispatchMessageA(&msg);
18681 ok_sequence(WmKeyReleaseOnly, "key release after setkeyboardstate", TRUE);
18683 key_state = GetAsyncKeyState(0x41);
18684 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
18686 key_state = GetKeyState(0x41);
18687 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
18689 DestroyWindow(test_window);
18690 flush_sequence();
18693 static const struct message WmHotkeyPressLWIN[] = {
18694 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
18695 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
18696 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
18697 { 0 }
18699 static const struct message WmHotkeyPress[] = {
18700 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
18701 { WM_HOTKEY, sent|wparam, 5 },
18702 { 0 }
18704 static const struct message WmHotkeyRelease[] = {
18705 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
18706 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 0x80000001 },
18707 { WM_KEYUP, sent|lparam, 0, 0x80000001 },
18708 { 0 }
18710 static const struct message WmHotkeyReleaseLWIN[] = {
18711 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
18712 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
18713 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
18714 { 0 }
18716 static const struct message WmHotkeyCombined[] = {
18717 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
18718 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
18719 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
18720 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
18721 { WM_APP, sent, 0, 0 },
18722 { WM_HOTKEY, sent|wparam, 5 },
18723 { WM_APP+1, sent, 0, 0 },
18724 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
18725 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
18726 { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
18727 { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
18728 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
18729 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
18730 { 0 }
18732 static const struct message WmHotkeyPrevious[] = {
18733 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
18734 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
18735 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
18736 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
18737 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
18738 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
18739 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 1 },
18740 { WM_KEYDOWN, sent|lparam, 0, 1 },
18741 { HCBT_KEYSKIPPED, hook|optional|lparam, 0, 0xc0000001 },
18742 { WM_KEYUP, sent|lparam, 0, 0xc0000001 },
18743 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
18744 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
18745 { 0 }
18747 static const struct message WmHotkeyNew[] = {
18748 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
18749 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
18750 { WM_HOTKEY, sent|wparam, 5 },
18751 { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
18752 { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
18753 { 0 }
18755 static const struct message WmHotkeyPressALT[] = {
18756 { WM_SYSKEYDOWN, kbd_hook|wparam|lparam, VK_LMENU, LLKHF_INJECTED|LLKHF_ALTDOWN },
18757 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
18758 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
18759 { 0 }
18761 static const struct message WmHotkeyPressWithALT[] = {
18762 { WM_SYSKEYDOWN, kbd_hook, 0, LLKHF_INJECTED|LLKHF_ALTDOWN }, /* lparam not checked */
18763 { WM_HOTKEY, sent|wparam, 6 },
18764 { 0 }
18766 static const struct message WmHotkeyReleaseWithALT[] = {
18767 { WM_SYSKEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP|LLKHF_ALTDOWN },
18768 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 0xa0000001 },
18769 { WM_SYSKEYUP, sent|lparam, 0, 0xa0000001 },
18770 { 0 }
18772 static const struct message WmHotkeyReleaseALT[] = {
18773 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LMENU, LLKHF_INJECTED|LLKHF_UP },
18774 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 },
18775 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
18776 { 0 }
18779 static int hotkey_letter;
18781 static LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
18783 struct recvd_message msg;
18785 if (nCode == HC_ACTION)
18787 KBDLLHOOKSTRUCT *kdbhookstruct = (KBDLLHOOKSTRUCT*)lParam;
18789 msg.hwnd = 0;
18790 msg.message = wParam;
18791 msg.flags = kbd_hook|wparam|lparam;
18792 msg.wParam = kdbhookstruct->vkCode;
18793 msg.lParam = kdbhookstruct->flags;
18794 msg.descr = "KeyboardHookProc";
18795 add_message(&msg);
18797 if (wParam == WM_KEYUP || wParam == WM_KEYDOWN ||
18798 wParam == WM_SYSKEYUP || wParam == WM_SYSKEYDOWN)
18800 ok(kdbhookstruct->vkCode == VK_LWIN ||
18801 kdbhookstruct->vkCode == VK_LMENU ||
18802 kdbhookstruct->vkCode == hotkey_letter,
18803 "unexpected keycode %lx\n", kdbhookstruct->vkCode);
18807 return CallNextHookEx(hKBD_hook, nCode, wParam, lParam);
18810 static void test_hotkey(void)
18812 HWND test_window, taskbar_window;
18813 BOOL ret;
18814 MSG msg;
18815 DWORD queue_status;
18816 SHORT key_state;
18818 SetLastError(0xdeadbeef);
18819 ret = UnregisterHotKey(NULL, 0);
18820 if (ret == TRUE)
18822 skip("hotkeys not supported\n");
18823 return;
18826 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
18827 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
18828 "unexpected error %ld\n", GetLastError());
18830 test_window = CreateWindowExA(0, "HotkeyWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
18831 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
18832 0, 0, 0, NULL);
18834 SetForegroundWindow(test_window);
18835 flush_events();
18836 flush_sequence();
18838 SetLastError(0xdeadbeef);
18839 ret = UnregisterHotKey(test_window, 0);
18840 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
18841 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
18842 "unexpected error %ld\n", GetLastError());
18844 /* Search for a Windows Key + letter combination that hasn't been registered */
18845 for (hotkey_letter = 'A'; hotkey_letter <= 'Z'; hotkey_letter ++)
18847 SetLastError(0xdeadbeef);
18848 ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
18850 if (ret == TRUE)
18852 break;
18854 else
18856 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
18857 "unexpected error %ld\n", GetLastError());
18861 if (hotkey_letter > 'Z')
18863 ok(0, "Couldn't find any free Windows Key + letter combination\n");
18864 goto end;
18867 hKBD_hook = SetWindowsHookExA(WH_KEYBOARD_LL, KeyboardHookProc, GetModuleHandleA(NULL), 0);
18868 if (!hKBD_hook) win_skip("WH_KEYBOARD_LL is not supported\n");
18870 /* Same key combination, different id */
18871 SetLastError(0xdeadbeef);
18872 ret = RegisterHotKey(test_window, 4, MOD_WIN, hotkey_letter);
18873 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
18874 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
18875 "unexpected error %ld\n", GetLastError());
18877 /* Same key combination, different window */
18878 SetLastError(0xdeadbeef);
18879 ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
18880 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
18881 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
18882 "unexpected error %ld\n", GetLastError());
18884 /* Register the same hotkey twice */
18885 SetLastError(0xdeadbeef);
18886 ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
18887 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
18888 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
18889 "unexpected error %ld\n", GetLastError());
18891 /* Window on another thread */
18892 taskbar_window = FindWindowA("Shell_TrayWnd", NULL);
18893 if (!taskbar_window)
18895 skip("no taskbar?\n");
18897 else
18899 SetLastError(0xdeadbeef);
18900 ret = RegisterHotKey(taskbar_window, 5, 0, hotkey_letter);
18901 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
18902 ok(GetLastError() == ERROR_WINDOW_OF_OTHER_THREAD || broken(GetLastError() == 0xdeadbeef),
18903 "unexpected error %ld\n", GetLastError());
18906 /* Inject the appropriate key sequence */
18907 keybd_event(VK_LWIN, 0, 0, 0);
18908 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
18909 DispatchMessageA(&msg);
18910 ok_sequence(WmHotkeyPressLWIN, "window hotkey press LWIN", FALSE);
18912 keybd_event(hotkey_letter, 0, 0, 0);
18913 queue_status = GetQueueStatus(QS_HOTKEY);
18914 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %lx\n", queue_status);
18915 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
18917 if (msg.message == WM_HOTKEY)
18919 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
18920 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %Ix\n", msg.lParam);
18922 DispatchMessageA(&msg);
18924 ok_sequence(WmHotkeyPress, "window hotkey press", FALSE);
18926 queue_status = GetQueueStatus(QS_HOTKEY);
18927 ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %lx\n", queue_status);
18929 key_state = GetAsyncKeyState(hotkey_letter);
18930 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
18932 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
18933 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
18934 DispatchMessageA(&msg);
18935 ok_sequence(WmHotkeyRelease, "window hotkey release", TRUE);
18937 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
18938 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
18939 DispatchMessageA(&msg);
18940 ok_sequence(WmHotkeyReleaseLWIN, "window hotkey release LWIN", FALSE);
18942 /* normal posted WM_HOTKEY messages set QS_HOTKEY */
18943 PostMessageA(test_window, WM_HOTKEY, 0, 0);
18944 queue_status = GetQueueStatus(QS_HOTKEY);
18945 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %lx\n", queue_status);
18946 queue_status = GetQueueStatus(QS_POSTMESSAGE);
18947 ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %lx\n", queue_status);
18948 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
18949 DispatchMessageA(&msg);
18950 flush_sequence();
18952 /* Send and process all messages at once */
18953 PostMessageA(test_window, WM_APP, 0, 0);
18954 keybd_event(VK_LWIN, 0, 0, 0);
18955 keybd_event(hotkey_letter, 0, 0, 0);
18956 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
18957 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
18959 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
18961 if (msg.message == WM_HOTKEY)
18963 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
18964 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %Ix\n", msg.lParam);
18966 DispatchMessageA(&msg);
18968 ok_sequence(WmHotkeyCombined, "window hotkey combined", FALSE);
18970 /* Register same hwnd/id with different key combination */
18971 ret = RegisterHotKey(test_window, 5, 0, hotkey_letter);
18972 ok(ret == TRUE, "expected TRUE, got %i, err=%ld\n", ret, GetLastError());
18974 /* Previous key combination does not work */
18975 keybd_event(VK_LWIN, 0, 0, 0);
18976 keybd_event(hotkey_letter, 0, 0, 0);
18977 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
18978 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
18980 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
18981 DispatchMessageA(&msg);
18982 ok_sequence(WmHotkeyPrevious, "window hotkey previous", FALSE);
18984 /* New key combination works */
18985 keybd_event(hotkey_letter, 0, 0, 0);
18986 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
18988 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
18990 if (msg.message == WM_HOTKEY)
18992 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
18993 ok(msg.lParam == MAKELPARAM(0, hotkey_letter), "unexpected WM_HOTKEY lparam %Ix\n", msg.lParam);
18995 DispatchMessageA(&msg);
18997 ok_sequence(WmHotkeyNew, "window hotkey new", FALSE);
18999 /* Unregister hotkey properly */
19000 ret = UnregisterHotKey(test_window, 5);
19001 ok(ret == TRUE, "expected TRUE, got %i, err=%ld\n", ret, GetLastError());
19003 /* Unregister hotkey again */
19004 SetLastError(0xdeadbeef);
19005 ret = UnregisterHotKey(test_window, 5);
19006 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
19007 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
19008 "unexpected error %ld\n", GetLastError());
19010 /* Register thread hotkey */
19011 ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
19012 ok(ret == TRUE, "expected TRUE, got %i, err=%ld\n", ret, GetLastError());
19014 /* Inject the appropriate key sequence */
19015 keybd_event(VK_LWIN, 0, 0, 0);
19016 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
19018 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
19019 DispatchMessageA(&msg);
19021 ok_sequence(WmHotkeyPressLWIN, "thread hotkey press LWIN", FALSE);
19023 keybd_event(hotkey_letter, 0, 0, 0);
19024 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
19026 if (msg.message == WM_HOTKEY)
19028 struct recvd_message message;
19029 ok(msg.hwnd == NULL, "unexpected hwnd %p\n", msg.hwnd);
19030 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %Ix\n", msg.lParam);
19031 message.message = msg.message;
19032 message.flags = sent|wparam|lparam;
19033 message.wParam = msg.wParam;
19034 message.lParam = msg.lParam;
19035 message.descr = "test_hotkey thread message";
19036 add_message(&message);
19038 else
19039 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
19040 DispatchMessageA(&msg);
19042 ok_sequence(WmHotkeyPress, "thread hotkey press", FALSE);
19044 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
19045 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
19047 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
19048 DispatchMessageA(&msg);
19050 ok_sequence(WmHotkeyRelease, "thread hotkey release", TRUE);
19052 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
19053 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
19055 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
19056 DispatchMessageA(&msg);
19058 ok_sequence(WmHotkeyReleaseLWIN, "thread hotkey release LWIN", FALSE);
19060 /* Search for an ALT + letter combination that hasn't been registered */
19061 for (hotkey_letter = 'A'; hotkey_letter <= 'Z'; hotkey_letter ++)
19063 SetLastError(0xdeadbeef);
19064 ret = RegisterHotKey(test_window, 6, MOD_ALT, hotkey_letter);
19066 if (ret == TRUE)
19068 break;
19070 else
19072 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
19073 "unexpected error %ld\n", GetLastError());
19077 if (hotkey_letter > 'Z')
19079 ok(0, "Couldn't find any free ALT + letter combination\n");
19080 goto end;
19083 keybd_event(VK_LMENU, 0, 0, 0);
19084 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
19085 DispatchMessageA(&msg);
19086 ok_sequence(WmHotkeyPressALT, "window hotkey press ALT", TRUE);
19088 keybd_event(hotkey_letter, 0, 0, 0);
19089 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
19091 if (msg.message == WM_HOTKEY)
19093 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
19094 ok(msg.lParam == MAKELPARAM(MOD_ALT, hotkey_letter), "unexpected WM_HOTKEY lparam %Ix\n", msg.lParam);
19096 DispatchMessageA(&msg);
19098 ok_sequence(WmHotkeyPressWithALT, "window hotkey press with ALT", FALSE);
19100 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
19101 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
19102 DispatchMessageA(&msg);
19103 ok_sequence(WmHotkeyReleaseWithALT, "window hotkey release with ALT", TRUE);
19105 keybd_event(VK_LMENU, 0, KEYEVENTF_KEYUP, 0);
19106 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
19107 DispatchMessageA(&msg);
19108 ok_sequence(WmHotkeyReleaseALT, "window hotkey release ALT", FALSE);
19110 /* Unregister thread hotkey */
19111 ret = UnregisterHotKey(NULL, 5);
19112 ok(ret == TRUE, "expected TRUE, got %i, err=%ld\n", ret, GetLastError());
19114 if (hKBD_hook) UnhookWindowsHookEx(hKBD_hook);
19115 hKBD_hook = NULL;
19117 end:
19118 UnregisterHotKey(NULL, 5);
19119 UnregisterHotKey(test_window, 5);
19120 UnregisterHotKey(test_window, 6);
19121 DestroyWindow(test_window);
19122 flush_sequence();
19126 static const struct message WmSetFocus_1[] = {
19127 { HCBT_SETFOCUS, hook }, /* child */
19128 { HCBT_ACTIVATE, hook }, /* parent */
19129 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
19130 { WM_QUERYNEWPALETTE, sent|wparam|lparam|parent|optional, 0, 0 },
19131 { WM_WINDOWPOSCHANGING, sent|parent, 0, SWP_NOSIZE|SWP_NOMOVE },
19132 { WM_ACTIVATEAPP, sent|wparam|parent, 1 },
19133 { WM_NCACTIVATE, sent|parent },
19134 { WM_GETTEXT, sent|defwinproc|parent|optional },
19135 { WM_GETTEXT, sent|defwinproc|parent|optional },
19136 { WM_ACTIVATE, sent|wparam|parent, 1 },
19137 { HCBT_SETFOCUS, hook }, /* parent */
19138 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
19139 { WM_SETFOCUS, sent|defwinproc|parent },
19140 { WM_KILLFOCUS, sent|parent },
19141 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
19142 { WM_SETFOCUS, sent },
19143 { 0 }
19145 static const struct message WmSetFocus_2[] = {
19146 { HCBT_SETFOCUS, hook }, /* parent */
19147 { WM_KILLFOCUS, sent },
19148 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
19149 { WM_SETFOCUS, sent|parent },
19150 { 0 }
19152 static const struct message WmSetFocus_3[] = {
19153 { HCBT_SETFOCUS, hook }, /* child */
19154 { 0 }
19157 static void test_SetFocus(void)
19159 HWND parent, old_parent, child, old_focus, old_active;
19160 MSG msg;
19161 struct wnd_event wnd_event;
19162 HANDLE hthread;
19163 DWORD ret, tid;
19165 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
19166 ok(wnd_event.start_event != 0, "CreateEvent error %ld\n", GetLastError());
19167 hthread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
19168 ok(hthread != 0, "CreateThread error %ld\n", GetLastError());
19169 ret = WaitForSingleObject(wnd_event.start_event, INFINITE);
19170 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
19171 CloseHandle(wnd_event.start_event);
19173 parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
19174 0, 0, 0, 0, 0, 0, 0, NULL);
19175 ok(parent != 0, "failed to create parent window\n");
19176 child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
19177 0, 0, 0, 0, parent, 0, 0, NULL);
19178 ok(child != 0, "failed to create child window\n");
19180 if (winetest_debug > 1) trace("parent %p, child %p, thread window %p\n", parent, child, wnd_event.hwnd);
19182 SetFocus(0);
19183 SetActiveWindow(0);
19185 flush_events();
19186 flush_sequence();
19188 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
19189 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
19191 log_all_parent_messages++;
19193 old_focus = SetFocus(child);
19194 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
19195 ok_sequence(WmSetFocus_1, "SetFocus on a child window", TRUE);
19196 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
19197 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
19198 ok(GetFocus() == child, "expected focus %p, got %p\n", child, GetFocus());
19200 old_focus = SetFocus(parent);
19201 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
19202 ok_sequence(WmSetFocus_2, "SetFocus on a parent window", FALSE);
19203 ok(old_focus == child, "expected old focus %p, got %p\n", child, old_focus);
19204 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
19205 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
19207 SetLastError(0xdeadbeef);
19208 old_focus = SetFocus((HWND)0xdeadbeef);
19209 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
19210 "expected ERROR_INVALID_WINDOW_HANDLE, got %ld\n", GetLastError());
19211 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
19212 ok_sequence(WmEmptySeq, "SetFocus on an invalid window", FALSE);
19213 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
19214 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
19215 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
19217 SetLastError(0xdeadbeef);
19218 old_focus = SetFocus(GetDesktopWindow());
19219 ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
19220 broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
19221 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
19222 ok_sequence(WmEmptySeq, "SetFocus on a desktop window", TRUE);
19223 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
19224 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
19225 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
19227 SetLastError(0xdeadbeef);
19228 old_focus = SetFocus(wnd_event.hwnd);
19229 ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
19230 broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
19231 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
19232 ok_sequence(WmEmptySeq, "SetFocus on another thread window", TRUE);
19233 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
19234 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
19235 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
19237 SetLastError(0xdeadbeef);
19238 old_active = SetActiveWindow((HWND)0xdeadbeef);
19239 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
19240 "expected ERROR_INVALID_WINDOW_HANDLE, got %ld\n", GetLastError());
19241 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
19242 ok_sequence(WmEmptySeq, "SetActiveWindow on an invalid window", FALSE);
19243 ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
19244 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
19245 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
19247 SetLastError(0xdeadbeef);
19248 old_active = SetActiveWindow(GetDesktopWindow());
19249 todo_wine
19250 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
19251 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
19252 ok_sequence(WmEmptySeq, "SetActiveWindow on a desktop window", TRUE);
19253 ok(old_active == 0, "expected old focus 0, got %p\n", old_focus);
19254 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
19255 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
19257 SetLastError(0xdeadbeef);
19258 old_active = SetActiveWindow(wnd_event.hwnd);
19259 todo_wine
19260 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
19261 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
19262 ok_sequence(WmEmptySeq, "SetActiveWindow on another thread window", TRUE);
19263 ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
19264 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
19265 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
19267 SetLastError(0xdeadbeef);
19268 ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE);
19269 ok(ret, "AttachThreadInput error %ld\n", GetLastError());
19271 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
19272 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
19274 flush_events();
19275 flush_sequence();
19277 old_focus = SetFocus(wnd_event.hwnd);
19278 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
19279 ok(old_focus == wnd_event.hwnd, "expected old focus %p, got %p\n", wnd_event.hwnd, old_focus);
19280 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
19281 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
19283 old_focus = SetFocus(parent);
19284 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
19285 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
19286 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
19287 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
19289 flush_events();
19290 flush_sequence();
19292 old_active = SetActiveWindow(wnd_event.hwnd);
19293 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
19294 ok(old_active == parent, "expected old focus %p, got %p\n", parent, old_active);
19295 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
19296 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
19298 SetLastError(0xdeadbeef);
19299 ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE);
19300 ok(ret, "AttachThreadInput error %ld\n", GetLastError());
19302 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
19303 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
19305 old_parent = SetParent(child, GetDesktopWindow());
19306 ok(old_parent == parent, "expected old parent %p, got %p\n", parent, old_parent);
19308 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
19309 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
19311 old_focus = SetFocus(parent);
19312 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
19313 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
19314 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
19315 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
19317 flush_events();
19318 flush_sequence();
19320 SetLastError(0xdeadbeef);
19321 old_focus = SetFocus(child);
19322 todo_wine
19323 ok(GetLastError() == ERROR_INVALID_PARAMETER /* Vista+ */ ||
19324 broken(GetLastError() == 0) /* XP */ ||
19325 broken(GetLastError() == 0xdeadbeef), "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
19326 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
19327 ok_sequence(WmSetFocus_3, "SetFocus on a child window", TRUE);
19328 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
19329 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
19330 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
19332 SetLastError(0xdeadbeef);
19333 old_active = SetActiveWindow(child);
19334 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
19335 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
19336 ok_sequence(WmEmptySeq, "SetActiveWindow on a child window", FALSE);
19337 ok(old_active == parent, "expected old active %p, got %p\n", parent, old_active);
19338 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
19339 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
19341 log_all_parent_messages--;
19343 DestroyWindow(child);
19344 DestroyWindow(parent);
19346 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
19347 ok(ret, "PostMessage(WM_QUIT) error %ld\n", GetLastError());
19348 ret = WaitForSingleObject(hthread, INFINITE);
19349 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
19350 CloseHandle(hthread);
19353 static const struct message WmSetLayeredStyle[] = {
19354 { WM_STYLECHANGING, sent },
19355 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
19356 { WM_STYLECHANGED, sent },
19357 { WM_GETTEXT, sent|defwinproc|optional },
19358 { 0 }
19361 static const struct message WmSetLayeredStyle2[] = {
19362 { WM_STYLECHANGING, sent },
19363 { WM_STYLECHANGED, sent },
19364 { WM_WINDOWPOSCHANGING, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
19365 { WM_NCCALCSIZE, sent|optional|wparam|defwinproc, 1 },
19366 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
19367 { WM_WINDOWPOSCHANGED, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
19368 { WM_MOVE, sent|optional|defwinproc|wparam, 0 },
19369 { WM_SIZE, sent|optional|defwinproc|wparam, SIZE_RESTORED },
19370 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 },
19371 { 0 }
19374 static const struct message WmLayeredWinEmptySeq[] = {
19375 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
19376 { 0 }
19379 struct layered_window_info
19381 HWND hwnd;
19382 HDC hdc;
19383 SIZE size;
19384 HANDLE event;
19385 BOOL ret;
19388 static DWORD CALLBACK update_layered_proc( void *param )
19390 struct layered_window_info *info = param;
19391 POINT src = { 0, 0 };
19393 info->ret = pUpdateLayeredWindow( info->hwnd, 0, NULL, &info->size,
19394 info->hdc, &src, 0, NULL, ULW_OPAQUE );
19395 ok( info->ret, "failed\n");
19396 SetEvent( info->event );
19397 return 0;
19400 static void test_layered_window(void)
19402 HWND hwnd;
19403 HDC hdc;
19404 HBITMAP bmp;
19405 BOOL ret;
19406 SIZE size;
19407 POINT pos, src;
19408 RECT rect, client;
19409 HANDLE thread;
19410 DWORD tid;
19411 struct layered_window_info info;
19413 if (!pUpdateLayeredWindow)
19415 win_skip( "UpdateLayeredWindow not supported\n" );
19416 return;
19419 hdc = CreateCompatibleDC( 0 );
19420 bmp = CreateCompatibleBitmap( hdc, 300, 300 );
19421 SelectObject( hdc, bmp );
19423 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_CAPTION | WS_THICKFRAME | WS_SYSMENU,
19424 100, 100, 300, 300, 0, 0, 0, NULL);
19425 ok( hwnd != 0, "failed to create window\n" );
19426 ShowWindow( hwnd, SW_SHOWNORMAL );
19427 UpdateWindow( hwnd );
19428 flush_events();
19429 flush_sequence();
19431 GetWindowRect( hwnd, &rect );
19432 GetClientRect( hwnd, &client );
19433 ok( client.right < rect.right - rect.left, "wrong client area\n" );
19434 ok( client.bottom < rect.bottom - rect.top, "wrong client area\n" );
19436 src.x = src.y = 0;
19437 pos.x = pos.y = 300;
19438 size.cx = size.cy = 250;
19439 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
19440 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
19441 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() );
19442 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
19443 ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
19445 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
19446 ok( ret, "UpdateLayeredWindow failed err %lu\n", GetLastError() );
19447 ok_sequence( WmLayeredWinEmptySeq, "UpdateLayeredWindow", FALSE );
19448 GetWindowRect( hwnd, &rect );
19449 ok( rect.left == 300 && rect.top == 300 && rect.right == 550 && rect.bottom == 550,
19450 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
19451 GetClientRect( hwnd, &rect );
19452 ok( rect.right == client.right - 50 && rect.bottom == client.bottom - 50,
19453 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
19455 size.cx = 150;
19456 pos.y = 200;
19457 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
19458 ok( ret, "UpdateLayeredWindow failed err %lu\n", GetLastError() );
19459 ok_sequence( WmLayeredWinEmptySeq, "UpdateLayeredWindow", FALSE );
19460 GetWindowRect( hwnd, &rect );
19461 ok( rect.left == 300 && rect.top == 200 && rect.right == 450 && rect.bottom == 450,
19462 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
19463 GetClientRect( hwnd, &rect );
19464 ok( rect.right == client.right - 150 && rect.bottom == client.bottom - 50,
19465 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
19467 SetWindowLongA( hwnd, GWL_STYLE,
19468 GetWindowLongA(hwnd, GWL_STYLE) & ~(WS_CAPTION | WS_THICKFRAME | WS_SYSMENU) );
19469 ok_sequence( WmSetLayeredStyle2, "WmSetLayeredStyle2", FALSE );
19471 size.cx = 200;
19472 pos.x = 200;
19473 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
19474 ok( ret, "UpdateLayeredWindow failed err %lu\n", GetLastError() );
19475 ok_sequence( WmLayeredWinEmptySeq, "UpdateLayeredWindow", FALSE );
19476 GetWindowRect( hwnd, &rect );
19477 ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
19478 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
19479 GetClientRect( hwnd, &rect );
19480 ok( (rect.right == 200 && rect.bottom == 250) ||
19481 broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
19482 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
19484 size.cx = 0;
19485 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
19486 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
19487 ok( GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == ERROR_MR_MID_NOT_FOUND) ||
19488 broken(GetLastError() == ERROR_GEN_FAILURE) /* win7 */, "wrong error %lu\n", GetLastError() );
19489 size.cx = 1;
19490 size.cy = -1;
19491 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
19492 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
19493 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() );
19495 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED );
19496 ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
19497 GetWindowRect( hwnd, &rect );
19498 ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
19499 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
19500 GetClientRect( hwnd, &rect );
19501 ok( (rect.right == 200 && rect.bottom == 250) ||
19502 broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
19503 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
19505 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
19506 info.hwnd = hwnd;
19507 info.hdc = hdc;
19508 info.size.cx = 250;
19509 info.size.cy = 300;
19510 info.event = CreateEventA( NULL, TRUE, FALSE, NULL );
19511 info.ret = FALSE;
19512 thread = CreateThread( NULL, 0, update_layered_proc, &info, 0, &tid );
19513 ok( WaitForSingleObject( info.event, 1000 ) == 0, "wait failed\n" );
19514 ok( info.ret, "UpdateLayeredWindow failed in other thread\n" );
19515 WaitForSingleObject( thread, 1000 );
19516 CloseHandle( thread );
19517 GetWindowRect( hwnd, &rect );
19518 ok( rect.left == 200 && rect.top == 200 && rect.right == 450 && rect.bottom == 500,
19519 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
19520 GetClientRect( hwnd, &rect );
19521 ok( (rect.right == 250 && rect.bottom == 300) ||
19522 broken(rect.right == client.right - 50 && rect.bottom == client.bottom),
19523 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
19525 DestroyWindow( hwnd );
19526 DeleteDC( hdc );
19527 DeleteObject( bmp );
19530 static HMENU hpopupmenu;
19532 static LRESULT WINAPI minimize_popup_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
19534 LRESULT ret;
19536 if (ignore_message( message )) return 0;
19537 ret = MsgCheckProc( FALSE, hwnd, message, wParam, lParam );
19539 switch (message) {
19540 case WM_ENTERIDLE:
19541 ShowWindow(hwnd, SW_MINIMIZE);
19542 break;
19543 case WM_TIMER:
19544 EndMenu();
19545 break;
19548 return ret;
19551 static LRESULT WINAPI cancel_popup_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
19553 if (ignore_message( message )) return 0;
19555 switch (message) {
19556 case WM_ENTERIDLE:
19557 todo_wine ok(GetCapture() == hwnd, "expected %p, got %p\n", hwnd, GetCapture());
19558 EndMenu();
19559 break;
19560 case WM_INITMENU:
19561 case WM_INITMENUPOPUP:
19562 case WM_UNINITMENUPOPUP:
19563 ok((HMENU)wParam == hpopupmenu, "expected %p, got %Ix\n", hpopupmenu, wParam);
19564 break;
19565 case WM_CAPTURECHANGED:
19566 todo_wine ok(!lParam || (HWND)lParam == hwnd, "lost capture to %Ix\n", lParam);
19567 break;
19570 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
19573 static LRESULT WINAPI cancel_init_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
19575 if (ignore_message( message )) return 0;
19577 switch (message) {
19578 case WM_ENTERMENULOOP:
19579 ok(EndMenu() == TRUE, "EndMenu() failed\n");
19580 break;
19583 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
19586 static void test_TrackPopupMenu(void)
19588 MSG msg;
19589 HWND hwnd;
19590 BOOL ret;
19592 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
19593 0, 0, 1, 1, 0,
19594 NULL, NULL, 0);
19595 ok(hwnd != NULL, "CreateWindowEx failed with error %ld\n", GetLastError());
19597 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
19599 hpopupmenu = CreatePopupMenu();
19600 ok(hpopupmenu != NULL, "CreateMenu failed with error %ld\n", GetLastError());
19602 AppendMenuA(hpopupmenu, MF_STRING, 100, "item 1");
19603 AppendMenuA(hpopupmenu, MF_STRING, 100, "item 2");
19605 flush_events();
19606 flush_sequence();
19607 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
19608 ok_sequence(WmTrackPopupMenu, "TrackPopupMenu", TRUE);
19609 ok(ret == 1, "TrackPopupMenu failed with error %li\n", GetLastError());
19611 /* Test popup closing with an ESC-press */
19612 flush_events();
19613 PostMessageW(hwnd, WM_KEYDOWN, VK_ESCAPE, 0);
19614 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
19615 ok(ret == 1, "TrackPopupMenu failed with error %li\n", GetLastError());
19616 PostQuitMessage(0);
19617 flush_sequence();
19618 while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
19620 TranslateMessage(&msg);
19621 DispatchMessageA(&msg);
19623 ok_sequence(WmTrackPopupMenuEsc, "TrackPopupMenuEsc", FALSE); /* Shouldn't get any message */
19625 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_init_proc);
19627 flush_events();
19628 flush_sequence();
19629 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
19630 ok_sequence(WmTrackPopupMenuAbort, "WmTrackPopupMenuAbort", TRUE);
19631 ok(ret == TRUE, "TrackPopupMenu failed\n");
19633 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)minimize_popup_proc);
19635 /* set cursor over the window, otherwise the WM_CANCELMODE message may not always be sent */
19636 SetCursorPos( 0, 0 );
19637 ShowWindow( hwnd, SW_SHOW );
19639 flush_events();
19640 flush_sequence();
19641 SetTimer( hwnd, TIMER_ID, 500, NULL );
19642 ret = TrackPopupMenu( hpopupmenu, 0, 100,100, 0, hwnd, NULL );
19643 ok_sequence( WmTrackPopupMenuMinimizeWindow, "TrackPopupMenuMinimizeWindow", TRUE );
19644 ok( ret == 1, "TrackPopupMenu failed with error %li\n", GetLastError() );
19645 KillTimer( hwnd, TIMER_ID );
19646 ShowWindow( hwnd, SW_RESTORE );
19648 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
19650 SetCapture(hwnd);
19652 flush_events();
19653 flush_sequence();
19654 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
19655 ok_sequence(WmTrackPopupMenuCapture, "TrackPopupMenuCapture", TRUE);
19656 ok(ret == 1, "TrackPopupMenuCapture failed with error %li\n", GetLastError());
19658 DestroyMenu(hpopupmenu);
19659 DestroyWindow(hwnd);
19662 static void test_TrackPopupMenuEmpty(void)
19664 HWND hwnd;
19665 BOOL ret;
19667 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
19668 0, 0, 1, 1, 0,
19669 NULL, NULL, 0);
19670 ok(hwnd != NULL, "CreateWindowEx failed with error %ld\n", GetLastError());
19672 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
19674 hpopupmenu = CreatePopupMenu();
19675 ok(hpopupmenu != NULL, "CreateMenu failed with error %ld\n", GetLastError());
19677 flush_events();
19678 flush_sequence();
19679 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
19680 ok_sequence(WmTrackPopupMenuEmpty, "TrackPopupMenuEmpty", TRUE);
19681 ok(ret == 0, "TrackPopupMenu succeeded\n");
19683 DestroyMenu(hpopupmenu);
19684 DestroyWindow(hwnd);
19687 static const struct message send_message_1[] = {
19688 { WM_USER+2, sent|wparam|lparam, 0, 0 },
19689 { WM_USER, sent|wparam|lparam, 0, 0 },
19690 { 0 }
19692 static const struct message send_message_2[] = {
19693 { WM_USER+4, sent|wparam|lparam, 0, 0 },
19694 { 0 }
19696 static const struct message send_message_3[] = {
19697 { WM_USER+3, sent|wparam|lparam, 0, 0 },
19698 { WM_USER+1, sent|wparam|lparam, 0, 0 },
19699 { 0 }
19701 static const struct message send_message_5[] = {
19702 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE, 0, SWP_NOZORDER }, /* win7+ dual monitor */
19703 { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* win7+ dual monitor */
19704 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE, 0, SWP_NOZORDER }, /* win7+ dual monitor */
19705 { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* win7+ dual monitor */
19706 { 0 }
19709 static DWORD WINAPI SendMessage_thread_1(void *param)
19711 struct wnd_event *wnd_event = param;
19712 DWORD ret;
19714 if (winetest_debug > 1) trace("thread: starting\n");
19715 WaitForSingleObject(wnd_event->start_event, INFINITE);
19717 if (winetest_debug > 1) trace("thread: call PostMessage\n");
19718 PostMessageA(wnd_event->hwnd, WM_USER, 0, 0);
19720 if (winetest_debug > 1) trace("thread: call PostMessage\n");
19721 PostMessageA(wnd_event->hwnd, WM_USER+1, 0, 0);
19723 if (winetest_debug > 1) trace("thread: call SendMessage\n");
19724 SendMessageA(wnd_event->hwnd, WM_USER+2, 0, 0);
19725 SetEvent(wnd_event->stop_event);
19726 ret = WaitForSingleObject(wnd_event->getmessage_complete, 100);
19727 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed, ret:%lx\n", ret);
19729 if (winetest_debug > 1) trace("thread: call SendMessage\n");
19730 SendMessageA(wnd_event->hwnd, WM_USER+3, 0, 0);
19732 return 0;
19735 static DWORD WINAPI SendMessage_thread_2(void *param)
19737 struct wnd_event *wnd_event = param;
19738 DWORD ret;
19740 if (winetest_debug > 1) trace("thread: starting\n");
19741 WaitForSingleObject(wnd_event->start_event, INFINITE);
19743 if (winetest_debug > 1) trace("thread: call PostMessage\n");
19744 PostMessageA(wnd_event->hwnd, WM_USER, 0, 0);
19746 if (winetest_debug > 1) trace("thread: call PostMessage\n");
19747 PostMessageA(wnd_event->hwnd, WM_USER+1, 0, 0);
19749 /* this leads to sending an internal message under Wine */
19750 if (winetest_debug > 1) trace("thread: call SetParent\n");
19751 SetParent(wnd_event->hwnd, wnd_event->hwnd);
19753 if (winetest_debug > 1) trace("thread: call SendMessage\n");
19754 SendMessageA(wnd_event->hwnd, WM_USER+2, 0, 0);
19755 SetEvent(wnd_event->stop_event);
19756 ret = WaitForSingleObject(wnd_event->getmessage_complete, 100);
19757 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed, ret:%lx\n", ret);
19759 if (winetest_debug > 1) trace("thread: call SendMessage\n");
19760 SendMessageA(wnd_event->hwnd, WM_USER+3, 0, 0);
19762 return 0;
19765 static void test_SendMessage_other_thread(int thread_n)
19767 DWORD qs_all_input = QS_ALLINPUT & ~QS_RAWINPUT;
19768 HANDLE hthread;
19769 struct wnd_event wnd_event;
19770 DWORD tid, ret;
19771 MSG msg;
19773 winetest_push_context("thread_%i", thread_n);
19775 wnd_event.start_event = CreateEventA(NULL, 0, 0, NULL);
19776 wnd_event.stop_event = CreateEventA(NULL, 0, 0, NULL);
19777 wnd_event.getmessage_complete = CreateEventA(NULL, 0, 0, NULL);
19779 wnd_event.hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
19780 100, 100, 200, 200, 0, 0, 0, NULL);
19781 ok(wnd_event.hwnd != 0, "CreateWindowEx failed\n");
19783 hthread = CreateThread(NULL, 0, thread_n == 1 ? SendMessage_thread_1 : SendMessage_thread_2, &wnd_event, 0, &tid);
19784 ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError());
19785 CloseHandle(hthread);
19787 flush_events();
19788 flush_sequence();
19790 ret = GetQueueStatus(QS_SENDMESSAGE);
19791 ok(ret == 0, "wrong status %08lx\n", ret);
19793 SetEvent(wnd_event.start_event);
19795 /* wait for other thread's SendMessage */
19796 for (;;)
19798 ret = GetQueueStatus(QS_SENDMESSAGE);
19799 if (ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE)) break;
19800 Sleep(50);
19803 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
19804 ok(ret == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08lx\n", ret);
19806 if (winetest_debug > 1) trace("main: call GetMessage\n");
19807 GetMessageA(&msg, 0, 0, 0);
19808 ok(msg.message == WM_USER, "expected WM_USER, got %04x\n", msg.message);
19809 DispatchMessageA(&msg);
19810 ok_sequence(send_message_1, "SendMessage from other thread 1", thread_n == 2);
19812 SetEvent(wnd_event.getmessage_complete);
19814 ret = WaitForSingleObject(wnd_event.stop_event, 100);
19815 todo_wine_if (thread_n == 2)
19816 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed, ret:%lx\n", ret);
19818 /* intentionally yield */
19819 MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input);
19821 if (winetest_debug > 1) trace("main: call SendMessage\n");
19822 SendMessageA(wnd_event.hwnd, WM_USER+4, 0, 0);
19823 ok_sequence(send_message_2, "SendMessage from other thread 2", FALSE);
19825 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
19826 ok(ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08lx\n", ret);
19828 if (winetest_debug > 1) trace("main: call PeekMessage\n");
19829 ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should not fail\n");
19830 ok(msg.message == WM_USER+1, "expected WM_USER+1, got %04x\n", msg.message);
19831 DispatchMessageA(&msg);
19832 ok_sequence(send_message_3, "SendMessage from other thread 3", thread_n == 2);
19834 /* intentionally yield */
19835 MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input);
19837 if (winetest_debug > 1) trace("main: call PeekMessage\n");
19838 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
19839 ok(ignore_message(msg.message), "got unexpected message %04x from PeekMessageA\n", msg.message);
19841 ok_sequence(send_message_5, "SendMessage from other thread 5", thread_n == 2);
19843 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
19844 ok(ret == 0, "wrong status %08lx\n", ret);
19846 if (winetest_debug > 1) trace("main: call DestroyWindow\n");
19847 DestroyWindow(msg.hwnd);
19849 flush_events();
19850 flush_sequence();
19852 winetest_pop_context();
19854 CloseHandle(wnd_event.start_event);
19855 CloseHandle(wnd_event.stop_event);
19856 CloseHandle(wnd_event.getmessage_complete);
19859 static LRESULT CALLBACK insendmessage_wnd_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
19861 DWORD flags = InSendMessageEx( NULL );
19862 BOOL ret;
19864 switch (msg)
19866 case WM_USER:
19867 ok( flags == ISMEX_SEND, "wrong flags %lx\n", flags );
19868 ok( InSendMessage(), "InSendMessage returned false\n" );
19869 ret = ReplyMessage( msg );
19870 ok( ret, "ReplyMessage failed err %lu\n", GetLastError() );
19871 flags = InSendMessageEx( NULL );
19872 ok( flags == (ISMEX_SEND | ISMEX_REPLIED) || broken( flags == (ISMEX_NOTIFY | ISMEX_REPLIED) ),
19873 "wrong flags %lx\n", flags );
19874 ok( InSendMessage(), "InSendMessage returned false\n" );
19875 break;
19876 case WM_USER + 1:
19877 ok( flags == ISMEX_NOTIFY, "wrong flags %lx\n", flags );
19878 ok( InSendMessage(), "InSendMessage returned false\n" );
19879 ret = ReplyMessage( msg );
19880 ok( ret, "ReplyMessage failed err %lu\n", GetLastError() );
19881 flags = InSendMessageEx( NULL );
19882 ok( flags == ISMEX_NOTIFY, "wrong flags %lx\n", flags );
19883 ok( InSendMessage(), "InSendMessage returned false\n" );
19884 break;
19885 case WM_USER + 2:
19886 ok( flags == ISMEX_CALLBACK, "wrong flags %lx\n", flags );
19887 ok( InSendMessage(), "InSendMessage returned false\n" );
19888 ret = ReplyMessage( msg );
19889 ok( ret, "ReplyMessage failed err %lu\n", GetLastError() );
19890 flags = InSendMessageEx( NULL );
19891 ok( flags == (ISMEX_CALLBACK | ISMEX_REPLIED) || flags == ISMEX_SEND, "wrong flags %lx\n", flags );
19892 ok( InSendMessage(), "InSendMessage returned false\n" );
19893 break;
19894 case WM_USER + 3:
19895 ok( flags == ISMEX_NOSEND, "wrong flags %lx\n", flags );
19896 ok( !InSendMessage(), "InSendMessage returned true\n" );
19897 ret = ReplyMessage( msg );
19898 ok( !ret, "ReplyMessage succeeded\n" );
19899 break;
19902 return DefWindowProcA( hwnd, msg, wp, lp );
19905 static void CALLBACK msg_callback( HWND hwnd, UINT msg, ULONG_PTR arg, LRESULT result )
19907 ok( msg == WM_USER + 2, "wrong msg %x\n", msg );
19908 ok( result == WM_USER + 2, "wrong result %Ix\n", result );
19911 static DWORD WINAPI send_message_thread( void *arg )
19913 HWND win = arg;
19915 SendMessageA( win, WM_USER, 0, 0 );
19916 SendNotifyMessageA( win, WM_USER + 1, 0, 0 );
19917 SendMessageCallbackA( win, WM_USER + 2, 0, 0, msg_callback, 0 );
19918 PostMessageA( win, WM_USER + 3, 0, 0 );
19919 PostMessageA( win, WM_QUIT, 0, 0 );
19920 return 0;
19923 static void test_InSendMessage(void)
19925 WNDCLASSA cls;
19926 HWND win;
19927 MSG msg;
19928 HANDLE thread;
19929 DWORD tid;
19931 memset(&cls, 0, sizeof(cls));
19932 cls.lpfnWndProc = insendmessage_wnd_proc;
19933 cls.hInstance = GetModuleHandleA(NULL);
19934 cls.lpszClassName = "InSendMessage_test";
19935 register_class(&cls);
19937 win = CreateWindowA( "InSendMessage_test", NULL, 0, 0, 0, 0, 0, NULL, 0, NULL, 0 );
19938 ok( win != NULL, "CreateWindow failed: %ld\n", GetLastError() );
19940 thread = CreateThread( NULL, 0, send_message_thread, win, 0, &tid );
19941 ok( thread != NULL, "CreateThread failed: %ld\n", GetLastError() );
19943 while (GetMessageA(&msg, NULL, 0, 0)) DispatchMessageA( &msg );
19945 ok( WaitForSingleObject( thread, 30000 ) == WAIT_OBJECT_0, "WaitForSingleObject failed\n" );
19946 CloseHandle( thread );
19948 DestroyWindow( win );
19949 UnregisterClassA( "InSendMessage_test", GetModuleHandleA(NULL) );
19952 static const struct message DoubleSetCaptureSeq[] =
19954 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
19955 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
19956 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
19957 { WM_CAPTURECHANGED, sent },
19958 { 0 }
19961 static void test_DoubleSetCapture(void)
19963 HWND hwnd;
19965 hwnd = CreateWindowExA(0, "TestWindowClass", "Test DoubleSetCapture",
19966 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
19967 100, 100, 200, 200, 0, 0, 0, NULL);
19968 ok (hwnd != 0, "Failed to create overlapped window\n");
19970 ShowWindow( hwnd, SW_SHOW );
19971 UpdateWindow( hwnd );
19972 flush_events();
19973 flush_sequence();
19975 SetCapture( hwnd );
19976 SetCapture( hwnd );
19977 ok_sequence(DoubleSetCaptureSeq, "SetCapture( hwnd ) twice", FALSE);
19979 DestroyWindow(hwnd);
19982 static const struct message WmRestoreMinimizedSeq[] =
19984 { HCBT_ACTIVATE, hook },
19985 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
19986 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
19987 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
19988 { WM_ACTIVATEAPP, sent|wparam, 1 },
19989 { WM_NCACTIVATE, sent|wparam, 0x200001 },
19990 { WM_GETTEXT, sent|defwinproc|optional },
19991 { WM_ACTIVATE, sent|wparam, 0x200001 }, /* Note that activate messages are after WM_WINDOWPOSCHANGED and before WM_SYSCOMMAND */
19992 { HCBT_KEYSKIPPED, hook|optional },
19993 { WM_SYSKEYUP, sent|optional },
19994 { WM_SYSCOMMAND, sent|wparam, SC_RESTORE },
19995 { HCBT_SYSCOMMAND, hook|wparam, SC_RESTORE },
19996 { HCBT_SYSCOMMAND, hook|wparam|optional, SC_RESTORE },
19997 { HCBT_MINMAX, hook },
19998 { HCBT_MINMAX, hook|optional },
19999 { WM_QUERYOPEN, sent|defwinproc },
20000 { WM_QUERYOPEN, sent|optional },
20001 { WM_GETTEXT, sent|defwinproc|optional },
20002 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
20003 { WM_GETMINMAXINFO, sent|defwinproc },
20004 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
20005 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
20006 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
20007 { WM_GETTEXT, sent|defwinproc|optional },
20008 { WM_ERASEBKGND, sent|defwinproc },
20009 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
20010 { WM_MOVE, sent|defwinproc },
20011 { WM_SIZE, sent|defwinproc },
20012 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
20013 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 },
20014 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
20015 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
20016 { WM_ERASEBKGND, sent|defwinproc|optional },
20017 { HCBT_SETFOCUS, hook },
20018 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
20019 { WM_SETFOCUS, sent|defwinproc },
20020 { WM_ACTIVATE, sent|wparam|defwinproc, 1 },
20021 { WM_PAINT, sent| optional },
20022 { WM_SETFOCUS, sent|defwinproc|optional },
20023 { HCBT_KEYSKIPPED, hook|optional },
20024 { WM_KEYUP, sent|optional },
20025 { HCBT_KEYSKIPPED, hook|optional },
20026 { WM_SYSKEYUP, sent|optional },
20027 { HCBT_KEYSKIPPED, hook|optional },
20028 { WM_KEYUP, sent|optional },
20029 { HCBT_KEYSKIPPED, hook|optional },
20030 { WM_SYSKEYUP, sent|optional },
20031 { HCBT_KEYSKIPPED, hook|optional },
20032 { WM_KEYUP, sent|optional },
20033 { WM_PAINT, sent| optional },
20034 { 0 }
20037 static void test_restore_messages(void)
20039 INPUT ip = {0};
20040 HWND hwnd;
20041 INT i;
20043 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100,
20044 100, 200, 200, 0, 0, 0, NULL);
20045 ok (hwnd != 0, "Failed to create overlapped window\n");
20046 SetForegroundWindow(hwnd);
20047 ShowWindow(hwnd, SW_MINIMIZE);
20048 flush_events();
20049 flush_sequence();
20051 for (i = 0; i < 5; i++)
20053 /* Send Alt+Tab to restore test window from minimized state */
20054 ip.type = INPUT_KEYBOARD;
20055 ip.ki.wVk = VK_MENU;
20056 SendInput(1, &ip, sizeof(INPUT));
20057 ip.ki.wVk = VK_TAB;
20058 SendInput(1, &ip, sizeof(INPUT));
20059 ip.ki.wVk = VK_MENU;
20060 ip.ki.dwFlags = KEYEVENTF_KEYUP;
20061 SendInput(1, &ip, sizeof(INPUT));
20062 ip.ki.wVk = VK_TAB;
20063 ip.ki.dwFlags = KEYEVENTF_KEYUP;
20064 SendInput(1, &ip, sizeof(INPUT));
20065 flush_events();
20066 if (!IsIconic(hwnd))
20067 break;
20070 if (IsIconic(hwnd))
20072 skip("Alt+Tab failed to bring up test window.\n");
20073 goto done;
20075 ok_sequence(WmRestoreMinimizedSeq, "Restore minimized window", TRUE);
20077 done:
20078 DestroyWindow(hwnd);
20081 static void test_invalid_window(void)
20083 MSG msg;
20084 BOOL ret;
20086 SetLastError(0xdeadbeef);
20087 ret = GetMessageA(&msg, (HWND)0xdeadbeef, 0, 0);
20088 ok(ret == -1, "wrong ret %d\n", ret);
20089 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %lu\n", GetLastError());
20091 SetLastError(0xdeadbeef);
20092 ret = PeekMessageA(&msg, (HWND)0xdeadbeef, 0, 0, PM_REMOVE);
20093 ok(!ret, "wrong ret %d\n", ret);
20094 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %lu\n", GetLastError());
20097 static void test_button_style(void)
20099 DWORD type, expected_type;
20100 HWND button;
20101 LRESULT ret;
20102 DWORD i, j;
20104 for (i = BS_PUSHBUTTON; i <= BS_DEFCOMMANDLINK; ++i)
20106 button = CreateWindowA(WC_BUTTONA, "test", i, 0, 0, 50, 50, NULL, 0, 0, NULL);
20107 ok(button != NULL, "Expected button not null.\n");
20109 type = GetWindowLongW(button, GWL_STYLE) & BS_TYPEMASK;
20110 expected_type = (i == BS_USERBUTTON ? BS_PUSHBUTTON : i);
20111 ok(type == expected_type, "Expected type %#lx, got %#lx.\n", expected_type, type);
20113 for (j = BS_PUSHBUTTON; j <= BS_DEFCOMMANDLINK; ++j)
20115 ret = SendMessageA(button, BM_SETSTYLE, j, FALSE);
20116 ok(ret == 0, "Expected %#x, got %#Ix.\n", 0, ret);
20118 type = GetWindowLongW(button, GWL_STYLE) & BS_TYPEMASK;
20119 expected_type = j;
20121 ok(type == expected_type, "Original type %#lx, expected new type %#lx, got %#lx.\n", i,
20122 expected_type, type);
20124 DestroyWindow(button);
20128 static LRESULT WINAPI test_create_name_procW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
20130 switch (msg)
20132 case WM_NCCREATE:
20133 case WM_CREATE:
20135 CREATESTRUCTW *cs = (CREATESTRUCTW *)lparam;
20136 memcpy( cs->lpCreateParams, cs->lpszName, 3 * sizeof(WCHAR) );
20137 break;
20139 case WM_SETTEXT:
20140 if (winetest_debug > 1) trace("%s\n", debugstr_w((const WCHAR *)lparam));
20141 break;
20144 return DefWindowProcW( hwnd, msg, wparam, lparam );
20147 static void test_create_name(void)
20149 WNDCLASSW clsW = { 0 };
20150 WCHAR name_buf[3];
20151 HWND hwnd;
20153 clsW.lpfnWndProc = test_create_name_procW;
20154 clsW.lpszClassName = L"TestCreateNameClassW";
20155 RegisterClassW( &clsW );
20157 hwnd = CreateWindowExW( 0, L"TestCreateNameClassW", L"\xffff\x6162",
20158 WS_POPUP, 0,0,0,0,0,0,0, name_buf );
20159 ok( hwnd != NULL, "CreateWindowEx failed: %lu\n", GetLastError() );
20160 ok(!memcmp(name_buf, L"\xffff\x6162", 2 * sizeof(WCHAR)),
20161 "name param = %s\n", debugstr_wn(name_buf, 2));
20162 DestroyWindow( hwnd );
20164 hwnd = CreateWindowExA( 0, "TestCreateNameClassW", "\xff\0\x61\x60",
20165 WS_POPUP, 0,0,0,0,0,0,0, name_buf );
20166 ok( hwnd != NULL, "CreateWindowEx failed: %lu\n", GetLastError() );
20167 ok(!memcmp(name_buf, L"\xffff\x6100", 2 * sizeof(WCHAR)),
20168 "name param = %s\n", debugstr_wn(name_buf, 2));
20169 DestroyWindow( hwnd );
20171 UnregisterClassW( L"TestCreateNameClassW", NULL );
20174 static LRESULT WINAPI changed_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
20176 if (msg == WM_USER) return 3;
20177 return DefWindowProcW( hwnd, msg, wparam, lparam );
20180 static LRESULT WINAPI call_window_proc_hook( INT code, WPARAM wparam, LPARAM lparam )
20182 CWPSTRUCT *cwp = (CWPSTRUCT *)lparam;
20184 ok( cwp->message == WM_USER, "message = %u\n", cwp->message );
20185 SetWindowLongPtrW( cwp->hwnd, GWLP_WNDPROC, (LONG_PTR)changed_window_proc );
20186 return CallNextHookEx( NULL, code, wparam, lparam );
20189 static void test_hook_changing_window_proc(void)
20191 HWND hwnd;
20192 HHOOK hook;
20193 LRESULT res;
20195 hwnd = CreateWindowExW( 0, L"static", NULL, WS_POPUP, 0,0,0,0,GetDesktopWindow(),0,0, NULL );
20196 hook = SetWindowsHookExW( WH_CALLWNDPROC, call_window_proc_hook, NULL, GetCurrentThreadId() );
20197 ok( hook != NULL, "SetWindowsHookExW failed: %lu\n", GetLastError() );
20199 res = SendMessageW( hwnd, WM_USER, 1, 2 );
20200 ok( res == 3, "SendMessageW(WM_USER) returned %Iu\n", res );
20202 UnhookWindowsHookEx( hook );
20203 DestroyWindow( hwnd );
20206 START_TEST(msg)
20208 char **test_argv;
20209 BOOL ret;
20210 BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
20211 int argc;
20213 argc = winetest_get_mainargs( &test_argv );
20214 if (argc >= 3)
20216 unsigned int arg;
20217 /* Child process. */
20218 sscanf (test_argv[2], "%d", (unsigned int *) &arg);
20219 do_wait_idle_child( arg );
20220 return;
20223 InitializeCriticalSection( &sequence_cs );
20224 init_procs();
20225 ImmDisableIME(0);
20227 register_classes();
20229 if (pSetWinEventHook)
20231 hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
20232 GetModuleHandleA(0), win_event_proc,
20233 0, GetCurrentThreadId(),
20234 WINEVENT_INCONTEXT);
20235 if (pIsWinEventHookInstalled && hEvent_hook)
20237 UINT event;
20238 for (event = EVENT_MIN; event <= EVENT_MAX; event++)
20239 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
20242 if (!hEvent_hook) win_skip( "no win event hook support\n" );
20244 cbt_hook_thread_id = winevent_hook_thread_id = GetCurrentThreadId();
20245 hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
20246 if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
20248 test_winevents();
20249 test_SendMessage_other_thread(1);
20250 test_SendMessage_other_thread(2);
20251 test_InSendMessage();
20252 test_SetFocus();
20253 test_SetParent();
20254 test_PostMessage();
20255 test_broadcast();
20256 test_ShowWindow();
20257 test_PeekMessage();
20258 test_PeekMessage2();
20259 test_PeekMessage3();
20260 test_WaitForInputIdle( test_argv[0] );
20261 test_scrollwindowex();
20262 test_messages();
20263 test_setwindowpos();
20264 test_showwindow();
20265 invisible_parent_tests();
20266 test_mdi_messages();
20267 test_button_messages();
20268 test_button_bm_get_set_image();
20269 test_button_style();
20270 test_autoradio_BM_CLICK();
20271 test_autoradio_kbd_move();
20272 test_static_messages();
20273 test_listbox_messages();
20274 test_combobox_messages();
20275 test_wmime_keydown_message();
20276 test_paint_messages();
20277 run_in_temp_desktop(test_swp_paint_regions);
20278 run_in_temp_desktop(test_swp_paint_region_on_show);
20279 run_in_temp_desktop(test_swp_paint_region_on_extend_zerosize);
20280 run_in_temp_desktop(test_hvredraw);
20281 test_interthread_messages();
20282 test_message_conversion();
20283 test_accelerators();
20284 test_timers();
20285 test_timers_no_wnd();
20286 test_timers_exceptions();
20287 if (hCBT_hook)
20289 test_set_hook();
20290 test_recursive_hook();
20292 test_DestroyWindow();
20293 test_DispatchMessage();
20294 test_SendMessageTimeout();
20295 test_edit_messages();
20296 test_quit_message();
20297 test_notify_message();
20298 test_SetActiveWindow();
20299 test_restore_messages();
20300 test_invalid_window();
20301 test_menu_messages();
20302 test_paintingloop();
20304 if (!pTrackMouseEvent)
20305 win_skip("TrackMouseEvent is not available\n");
20306 else
20307 test_TrackMouseEvent();
20309 test_SetWindowRgn();
20310 test_sys_menu();
20311 test_dialog_messages();
20312 test_EndDialog();
20313 test_nullCallback();
20314 test_dbcs_wm_char();
20315 test_unicode_wm_char();
20316 test_defwinproc();
20317 test_desktop_winproc();
20318 test_clipboard_viewers();
20319 test_keyflags();
20320 test_hotkey();
20321 test_layered_window();
20322 test_TrackPopupMenu();
20323 test_TrackPopupMenuEmpty();
20324 test_DoubleSetCapture();
20325 test_create_name();
20326 test_hook_changing_window_proc();
20327 /* keep it the last test, under Windows it tends to break the tests
20328 * which rely on active/foreground windows being correct.
20330 test_SetForegroundWindow();
20332 UnhookWindowsHookEx(hCBT_hook);
20333 if (pUnhookWinEvent && hEvent_hook)
20335 ret = pUnhookWinEvent(hEvent_hook);
20336 ok( ret, "UnhookWinEvent error %ld\n", GetLastError());
20337 SetLastError(0xdeadbeef);
20338 ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
20339 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
20340 GetLastError() == 0xdeadbeef, /* Win9x */
20341 "unexpected error %ld\n", GetLastError());
20343 DeleteCriticalSection( &sequence_cs );