mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / user32 / tests / msg.c
blob7eaa2c67945d9e8c8974fed74354b56199f185da
1 /*
2 * Unit tests for window message handling
4 * Copyright 1999 Ove Kaaven
5 * Copyright 2003 Dimitrie O. Paun
6 * Copyright 2004,2005,2016 Dmitry Timoshkov
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <assert.h>
24 #include <limits.h>
25 #include <stdarg.h>
26 #include <stdio.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "winuser.h"
32 #include "winnls.h"
33 #include "dbt.h"
34 #include "commctrl.h"
36 #include "wine/test.h"
38 #define MDI_FIRST_CHILD_ID 2004
40 /* undocumented SWP flags - from SDK 3.1 */
41 #define SWP_NOCLIENTSIZE 0x0800
42 #define SWP_NOCLIENTMOVE 0x1000
43 #define SWP_STATECHANGED 0x8000
45 #define SW_NORMALNA 0xCC /* undoc. flag in MinMaximize */
47 #ifndef WM_KEYF1
48 #define WM_KEYF1 0x004d
49 #endif
51 #ifndef WM_SYSTIMER
52 #define WM_SYSTIMER 0x0118
53 #endif
55 #define WND_PARENT_ID 1
56 #define WND_POPUP_ID 2
57 #define WND_CHILD_ID 3
59 #ifndef WM_LBTRACKPOINT
60 #define WM_LBTRACKPOINT 0x0131
61 #endif
63 #ifdef __i386__
64 #define ARCH "x86"
65 #elif defined __x86_64__
66 #define ARCH "amd64"
67 #elif defined __arm__
68 #define ARCH "arm"
69 #elif defined __aarch64__
70 #define ARCH "arm64"
71 #else
72 #define ARCH "none"
73 #endif
75 /* encoded DRAWITEMSTRUCT into an LPARAM */
76 typedef struct
78 union
80 struct
82 UINT type : 4; /* ODT_* flags */
83 UINT ctl_id : 4; /* Control ID */
84 UINT item_id : 4; /* Menu item ID */
85 UINT action : 4; /* ODA_* flags */
86 UINT state : 16; /* ODS_* flags */
87 } item;
88 LPARAM lp;
89 } u;
90 } DRAW_ITEM_STRUCT;
92 /* encoded MEASUREITEMSTRUCT into a WPARAM */
93 typedef struct
95 union
97 struct
99 UINT CtlType : 4;
100 UINT CtlID : 4;
101 UINT itemID : 4;
102 UINT wParam : 20;
103 } item;
104 WPARAM wp;
105 } u;
106 } MEASURE_ITEM_STRUCT;
108 static BOOL test_DestroyWindow_flag;
109 static HWINEVENTHOOK hEvent_hook;
110 static HHOOK hKBD_hook;
111 static HHOOK hCBT_hook;
112 static DWORD cbt_hook_thread_id;
114 static const WCHAR testWindowClassW[] =
115 { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 };
117 static LRESULT WINAPI ParentMsgCheckProcA(HWND, UINT, WPARAM, LPARAM);
120 FIXME: add tests for these
121 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
122 WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
123 WS_THICKFRAME: thick border
124 WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
125 WS_BORDER (default for overlapped windows): single black border
126 none (default for child (and popup?) windows): no border
129 typedef enum {
130 sent=0x1,
131 posted=0x2,
132 parent=0x4,
133 wparam=0x8,
134 lparam=0x10,
135 defwinproc=0x20,
136 beginpaint=0x40,
137 optional=0x80,
138 hook=0x100,
139 winevent_hook=0x200,
140 kbd_hook=0x400
141 } msg_flags_t;
143 struct message {
144 UINT message; /* the WM_* code */
145 msg_flags_t flags; /* message props */
146 WPARAM wParam; /* expected value of wParam */
147 LPARAM lParam; /* expected value of lParam */
148 WPARAM wp_mask; /* mask for wParam checks */
149 LPARAM lp_mask; /* mask for lParam checks */
152 struct recvd_message {
153 UINT message; /* the WM_* code */
154 msg_flags_t flags; /* message props */
155 HWND hwnd; /* window that received the message */
156 WPARAM wParam; /* expected value of wParam */
157 LPARAM lParam; /* expected value of lParam */
158 int line; /* source line where logged */
159 const char *descr; /* description for trace output */
160 char output[512]; /* trace output */
163 /* Empty message sequence */
164 static const struct message WmEmptySeq[] =
166 { 0 }
168 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
169 static const struct message WmCreateOverlappedSeq[] = {
170 { HCBT_CREATEWND, hook },
171 { WM_GETMINMAXINFO, sent },
172 { WM_NCCREATE, sent },
173 { WM_NCCALCSIZE, sent|wparam, 0 },
174 { 0x0093, sent|defwinproc|optional },
175 { 0x0094, sent|defwinproc|optional },
176 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
177 { WM_CREATE, sent },
178 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
179 { 0 }
181 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
182 * for a not visible overlapped window.
184 static const struct message WmSWP_ShowOverlappedSeq[] = {
185 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
186 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
187 { WM_NCPAINT, sent|wparam|optional, 1 },
188 { WM_GETTEXT, sent|defwinproc|optional },
189 { WM_ERASEBKGND, sent|optional },
190 { HCBT_ACTIVATE, hook },
191 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
192 { WM_NOTIFYFORMAT, sent|optional },
193 { WM_QUERYUISTATE, sent|optional },
194 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
195 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
196 { WM_ACTIVATEAPP, sent|wparam, 1 },
197 { WM_NCACTIVATE, sent },
198 { WM_GETTEXT, sent|defwinproc|optional },
199 { WM_ACTIVATE, sent|wparam, 1 },
200 { HCBT_SETFOCUS, hook },
201 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
202 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
203 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
204 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
205 { WM_GETTEXT, sent|optional },
206 { WM_NCPAINT, sent|wparam|optional, 1 },
207 { WM_GETTEXT, sent|defwinproc|optional },
208 { WM_ERASEBKGND, sent|optional },
209 /* Win9x adds SWP_NOZORDER below */
210 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
211 { WM_GETTEXT, sent|optional },
212 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
213 { WM_NCPAINT, sent|wparam|optional, 1 },
214 { WM_ERASEBKGND, sent|optional },
215 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
216 { WM_SYNCPAINT, sent|optional },
217 { WM_GETTITLEBARINFOEX, sent|optional },
218 { WM_PAINT, sent|optional },
219 { WM_NCPAINT, sent|beginpaint|optional },
220 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
221 { WM_ERASEBKGND, sent|beginpaint|optional },
222 { 0 }
224 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
225 * for a visible overlapped window.
227 static const struct message WmSWP_HideOverlappedSeq[] = {
228 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
229 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
230 { HCBT_ACTIVATE, hook|optional },
231 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
232 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
233 { WM_NCACTIVATE, sent|optional },
234 { WM_ACTIVATE, sent|optional },
235 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
236 { 0 }
239 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
240 * for a visible overlapped window.
242 static const struct message WmSWP_ResizeSeq[] = {
243 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
244 { WM_GETMINMAXINFO, sent|defwinproc },
245 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
246 { WM_NCPAINT, sent|optional },
247 { WM_GETTEXT, sent|defwinproc|optional },
248 { WM_ERASEBKGND, sent|optional },
249 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
250 { WM_SIZE, sent|defwinproc|optional },
251 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
252 { WM_NCPAINT, sent|optional },
253 { WM_GETTEXT, sent|defwinproc|optional },
254 { WM_ERASEBKGND, sent|optional },
255 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
256 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
257 { 0 }
260 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
261 * for a visible popup window.
263 static const struct message WmSWP_ResizePopupSeq[] = {
264 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
265 { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */
266 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
267 { WM_NCPAINT, sent|optional },
268 { WM_GETTEXT, sent|defwinproc|optional },
269 { WM_ERASEBKGND, sent|optional },
270 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
271 { WM_SIZE, sent|defwinproc|wparam|optional, SIZE_RESTORED },
272 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
273 { WM_NCPAINT, sent|optional },
274 { WM_GETTEXT, sent|defwinproc|optional },
275 { WM_ERASEBKGND, sent|optional },
276 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
277 { 0 }
280 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
281 * for a visible overlapped window.
283 static const struct message WmSWP_MoveSeq[] = {
284 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
285 { WM_NCPAINT, sent|optional },
286 { WM_GETTEXT, sent|defwinproc|optional },
287 { WM_ERASEBKGND, sent|optional },
288 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
289 { WM_MOVE, sent|defwinproc|wparam, 0 },
290 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
291 { 0 }
293 /* Resize with SetWindowPos(SWP_NOZORDER)
294 * for a visible overlapped window
295 * SWP_NOZORDER is stripped by the logging code
297 static const struct message WmSWP_ResizeNoZOrder[] = {
298 { WM_WINDOWPOSCHANGING, sent|wparam, /*SWP_NOZORDER|*/SWP_NOACTIVATE },
299 { WM_GETMINMAXINFO, sent|defwinproc },
300 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
301 { WM_NCPAINT, sent|optional },
302 { WM_GETTEXT, sent|defwinproc|optional },
303 { WM_ERASEBKGND, sent|optional },
304 { WM_WINDOWPOSCHANGED, sent|wparam|optional, /*SWP_NOZORDER|*/SWP_NOACTIVATE, 0,
305 SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
306 { WM_MOVE, sent|defwinproc|optional },
307 { WM_SIZE, sent|defwinproc|optional },
308 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
309 { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
310 { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */
311 { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */
312 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
313 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
314 { 0 }
317 /* Switch visible mdi children */
318 static const struct message WmSwitchChild[] = {
319 /* Switch MDI child */
320 { WM_MDIACTIVATE, sent },/* in the MDI client */
321 { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 1st MDI child */
322 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
323 { WM_CHILDACTIVATE, sent },/* in the 1st MDI child */
324 /* Deactivate 2nd MDI child */
325 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
326 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
327 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
328 /* Preparing for maximize and maximize the 1st MDI child */
329 { WM_GETMINMAXINFO, sent|defwinproc }, /* in the 1st MDI child */
330 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED }, /* in the 1st MDI child */
331 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
332 { WM_CHILDACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
333 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 1st MDI child */
334 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, /* in the 1st MDI child */
335 /* Lock redraw 2nd MDI child */
336 { WM_SETREDRAW, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
337 { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
338 /* Restore 2nd MDI child */
339 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },/* in the 2nd MDI child */
340 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
341 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
342 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 2nd MDI child */
343 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, /* in the 2nd MDI child */
344 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
345 /* Redraw 2nd MDI child */
346 { WM_SETREDRAW, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
347 /* Redraw MDI frame */
348 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },/* in MDI frame */
349 { WM_NCCALCSIZE, sent|wparam, 1 },/* in MDI frame */
350 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in MDI frame */
351 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in MDI frame */
352 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
353 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
354 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
355 { HCBT_SETFOCUS, hook },
356 { WM_KILLFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
357 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },/* in the 1st MDI child */
358 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
359 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
360 { WM_SETFOCUS, sent },/* in the MDI client */
361 { HCBT_SETFOCUS, hook },
362 { WM_KILLFOCUS, sent },/* in the MDI client */
363 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
364 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, /* in the 1st MDI child */
365 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
366 { WM_SETFOCUS, sent|defwinproc }, /* in the 1st MDI child */
367 { WM_MDIACTIVATE, sent|defwinproc },/* in the 1st MDI child */
368 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* in the 1st MDI child */
369 { 0 }
372 /* Switch visible not maximized mdi children */
373 static const struct message WmSwitchNotMaximizedChild[] = {
374 /* Switch not maximized MDI child */
375 { WM_MDIACTIVATE, sent },/* in the MDI client */
376 { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 2nd MDI child */
377 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
378 { WM_CHILDACTIVATE, sent },/* in the 2nd MDI child */
379 /* Deactivate 1st MDI child */
380 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
381 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
382 /* Activate 2nd MDI child */
383 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE}, /* in the 2nd MDI child */
384 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 2nd MDI child */
385 { HCBT_SETFOCUS, hook }, /* in the 1st MDI child */
386 { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
387 { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
388 { WM_IME_SETCONTEXT, sent|optional }, /* in the MDI client */
389 { WM_SETFOCUS, sent, 0 }, /* in the MDI client */
390 { HCBT_SETFOCUS, hook },
391 { WM_KILLFOCUS, sent }, /* in the MDI client */
392 { WM_IME_SETCONTEXT, sent|optional }, /* in the MDI client */
393 { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
394 { WM_SETFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
395 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
396 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in the 2nd MDI child */
397 { 0 }
401 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
402 SWP_NOZORDER|SWP_FRAMECHANGED)
403 * for a visible overlapped window with WS_CLIPCHILDREN style set.
405 static const struct message WmSWP_FrameChanged_clip[] = {
406 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
407 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
408 { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
409 { WM_GETTEXT, sent|parent|defwinproc|optional },
410 { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
411 { WM_NCPAINT, sent }, /* wparam != 1 */
412 { WM_ERASEBKGND, sent },
413 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
414 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
415 { WM_PAINT, sent },
416 { 0 }
418 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
419 SWP_NOZORDER|SWP_FRAMECHANGED)
420 * for a visible overlapped window.
422 static const struct message WmSWP_FrameChangedDeferErase[] = {
423 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
424 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
425 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
426 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
427 { WM_PAINT, sent|parent|optional },
428 { WM_NCPAINT, sent|beginpaint|parent|optional }, /* wparam != 1 */
429 { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
430 { WM_PAINT, sent },
431 { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
432 { WM_ERASEBKGND, sent|beginpaint|optional },
433 { 0 }
436 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
437 SWP_NOZORDER|SWP_FRAMECHANGED)
438 * for a visible overlapped window without WS_CLIPCHILDREN style set.
440 static const struct message WmSWP_FrameChanged_noclip[] = {
441 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
442 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
443 { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
444 { WM_GETTEXT, sent|parent|defwinproc|optional },
445 { WM_ERASEBKGND, sent|parent|optional },
446 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
447 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
448 { WM_PAINT, sent },
449 { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
450 { WM_ERASEBKGND, sent|beginpaint|optional },
451 { 0 }
454 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
455 static const struct message WmShowOverlappedSeq[] = {
456 { WM_SHOWWINDOW, sent|wparam, 1 },
457 { WM_NCPAINT, sent|wparam|optional, 1 },
458 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
459 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
460 { WM_NCPAINT, sent|wparam|optional, 1 },
461 { WM_GETTEXT, sent|defwinproc|optional },
462 { WM_ERASEBKGND, sent|optional },
463 { HCBT_ACTIVATE, hook|optional },
464 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
465 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
466 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
467 { WM_NCPAINT, sent|wparam|optional, 1 },
468 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
469 { WM_NCACTIVATE, sent|wparam|optional, 1 },
470 { WM_GETTEXT, sent|defwinproc|optional },
471 { WM_ACTIVATE, sent|wparam|optional, 1 },
472 { HCBT_SETFOCUS, hook|optional },
473 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
474 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
475 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
476 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
477 { WM_GETTEXT, sent|optional },
478 { WM_NCPAINT, sent|wparam|optional, 1 },
479 { WM_GETTEXT, sent|defwinproc|optional },
480 { WM_ERASEBKGND, sent|optional },
481 /* Win9x adds SWP_NOZORDER below */
482 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
483 { WM_NCCALCSIZE, sent|optional },
484 { WM_GETTEXT, sent|optional },
485 { WM_NCPAINT, sent|optional },
486 { WM_ERASEBKGND, sent|optional },
487 { WM_SYNCPAINT, sent|optional },
488 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
489 * messages. Does that mean that CreateWindow doesn't set initial
490 * window dimensions for overlapped windows?
492 { WM_SIZE, sent },
493 { WM_MOVE, sent },
494 #endif
495 { WM_PAINT, sent|optional },
496 { WM_NCPAINT, sent|beginpaint|optional },
497 { 0 }
499 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
500 static const struct message WmShowMaxOverlappedSeq[] = {
501 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
502 { WM_GETMINMAXINFO, sent },
503 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
504 { WM_GETMINMAXINFO, sent|defwinproc },
505 { WM_NCCALCSIZE, sent|wparam, TRUE },
506 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
507 { HCBT_ACTIVATE, hook|optional },
508 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
509 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
510 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
511 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
512 { WM_NCACTIVATE, sent|wparam|optional, 1 },
513 { WM_GETTEXT, sent|defwinproc|optional },
514 { WM_ACTIVATE, sent|wparam|optional, 1 },
515 { HCBT_SETFOCUS, hook|optional },
516 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
517 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
518 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
519 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
520 { WM_GETTEXT, sent|optional },
521 { WM_NCPAINT, sent|wparam|optional, 1 },
522 { WM_GETTEXT, sent|defwinproc|optional },
523 { WM_ERASEBKGND, sent|optional },
524 /* Win9x adds SWP_NOZORDER below */
525 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
526 { WM_MOVE, sent|defwinproc },
527 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
528 { WM_GETTEXT, sent|optional },
529 { WM_NCCALCSIZE, sent|optional },
530 { WM_NCPAINT, sent|optional },
531 { WM_ERASEBKGND, sent|optional },
532 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
533 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
534 { WM_SYNCPAINT, sent|optional },
535 { WM_GETTITLEBARINFOEX, sent|optional },
536 { WM_PAINT, sent|optional },
537 { WM_NCPAINT, sent|beginpaint|optional },
538 { WM_ERASEBKGND, sent|beginpaint|optional },
539 { 0 }
541 /* ShowWindow(SW_RESTORE) for a not visible maximized overlapped window */
542 static const struct message WmShowRestoreMaxOverlappedSeq[] = {
543 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
544 { WM_GETTEXT, sent|optional },
545 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
546 { WM_GETMINMAXINFO, sent|defwinproc },
547 { WM_NCCALCSIZE, sent|wparam, TRUE },
548 { WM_NCPAINT, sent|optional },
549 { WM_GETTEXT, sent|defwinproc|optional },
550 { WM_ERASEBKGND, sent|optional },
551 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
552 { WM_MOVE, sent|defwinproc|optional },
553 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
554 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
555 { WM_NCPAINT, sent|optional },
556 { WM_ERASEBKGND, sent|optional },
557 { WM_PAINT, sent|optional },
558 { WM_GETTITLEBARINFOEX, sent|optional },
559 { WM_NCPAINT, sent|beginpaint|optional },
560 { WM_ERASEBKGND, sent|beginpaint|optional },
561 { WM_SYNCPAINT, sent|optional },
562 { 0 }
564 /* ShowWindow(SW_RESTORE) for a not visible minimized overlapped window */
565 static const struct message WmShowRestoreMinOverlappedSeq[] = {
566 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
567 { WM_QUERYOPEN, sent|optional },
568 { WM_GETTEXT, sent|optional },
569 { WM_NCACTIVATE, sent|wparam|optional, 1 },
570 { WM_WINDOWPOSCHANGING, sent|optional }, /* SWP_NOSIZE|SWP_NOMOVE */
571 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
572 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
573 { WM_MOVE, sent|optional },
574 { WM_SIZE, sent|wparam|optional, SIZE_RESTORED },
575 { WM_GETTEXT, sent|optional },
576 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED|SWP_NOCOPYBITS },
577 { WM_GETMINMAXINFO, sent|defwinproc|optional },
578 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
579 { HCBT_ACTIVATE, hook|optional },
580 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
581 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
582 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
583 { WM_NCACTIVATE, sent|wparam|optional, 1 },
584 { WM_GETTEXT, sent|defwinproc|optional },
585 { WM_ACTIVATE, sent|wparam|optional, 1 },
586 { HCBT_SETFOCUS, hook|optional },
587 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
588 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
589 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
590 { WM_GETTEXT, sent|optional },
591 { WM_NCPAINT, sent|wparam|optional, 1 },
592 { WM_GETTEXT, sent|defwinproc|optional },
593 { WM_ERASEBKGND, sent },
594 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_STATECHANGED|SWP_FRAMECHANGED|SWP_NOCOPYBITS },
595 { WM_MOVE, sent|defwinproc },
596 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
597 { HCBT_SETFOCUS, hook|optional },
598 { WM_SETFOCUS, sent|wparam|optional, 0 },
599 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
600 { WM_NCPAINT, sent|wparam|optional, 1 },
601 { WM_ERASEBKGND, sent|optional },
602 { HCBT_SETFOCUS, hook|optional },
603 { WM_SETFOCUS, sent|wparam|optional, 0 },
604 { WM_ACTIVATE, sent|wparam, 1 },
605 { WM_GETTEXT, sent|optional },
606 { WM_PAINT, sent|optional },
607 { WM_GETTITLEBARINFOEX, sent|optional },
608 { WM_NCPAINT, sent|beginpaint|optional },
609 { WM_ERASEBKGND, sent|beginpaint|optional },
610 { 0 }
612 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
613 static const struct message WmShowMinOverlappedSeq[] = {
614 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
615 { HCBT_SETFOCUS, hook|optional },
616 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
617 { WM_KILLFOCUS, sent|optional },
618 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
619 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
620 { WM_GETTEXT, sent|optional },
621 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
622 { WM_GETMINMAXINFO, sent|defwinproc },
623 { WM_NCCALCSIZE, sent|wparam, TRUE },
624 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
625 { WM_NCPAINT, sent|optional },
626 { WM_GETTEXT, sent|defwinproc|optional },
627 { WM_WINDOWPOSCHANGED, sent },
628 { WM_MOVE, sent|defwinproc },
629 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
630 { WM_NCCALCSIZE, sent|optional },
631 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
632 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
633 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
634 { WM_NCACTIVATE, sent|wparam|optional, 0 },
635 { WM_GETTEXT, sent|defwinproc|optional },
636 { WM_ACTIVATE, sent|optional },
637 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
639 /* Vista sometimes restores the window right away... */
640 { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
641 { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
642 { HCBT_MINMAX, hook|optional|lparam, 0, SW_RESTORE },
643 { WM_QUERYOPEN, sent|optional },
644 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
645 { WM_GETMINMAXINFO, sent|optional|defwinproc },
646 { WM_NCCALCSIZE, sent|optional|wparam, TRUE },
647 { HCBT_ACTIVATE, hook|optional },
648 { WM_ACTIVATEAPP, sent|optional|wparam, 1 },
649 { WM_NCACTIVATE, sent|optional },
650 { WM_GETTEXT, sent|optional },
651 { WM_ACTIVATE, sent|optional|wparam, 1 },
652 { HCBT_SETFOCUS, hook|optional },
653 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
654 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
655 { WM_SETFOCUS, sent|optional },
656 { WM_NCPAINT, sent|optional },
657 { WM_GETTEXT, sent|defwinproc|optional },
658 { WM_ERASEBKGND, sent|optional },
659 { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
660 { WM_MOVE, sent|defwinproc|optional },
661 { WM_SIZE, sent|defwinproc|optional|wparam, SIZE_RESTORED },
662 { WM_ACTIVATE, sent|optional|wparam, 1 },
663 { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
664 { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
666 { WM_PAINT, sent|optional },
667 { WM_NCPAINT, sent|beginpaint|optional },
668 { WM_ERASEBKGND, sent|beginpaint|optional },
669 { 0 }
671 /* ShowWindow(SW_HIDE) for a visible overlapped window */
672 static const struct message WmHideOverlappedSeq[] = {
673 { WM_SHOWWINDOW, sent|wparam, 0 },
674 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
675 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
676 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
677 { WM_SIZE, sent|optional }, /* XP doesn't send it */
678 { WM_MOVE, sent|optional }, /* XP doesn't send it */
679 { WM_NCACTIVATE, sent|wparam|optional, 0 },
680 { WM_ACTIVATE, sent|wparam|optional, 0 },
681 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
682 { HCBT_SETFOCUS, hook|optional },
683 { WM_KILLFOCUS, sent|wparam|optional, 0 },
684 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
685 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
686 { 0 }
688 /* DestroyWindow for a visible overlapped window */
689 static const struct message WmDestroyOverlappedSeq[] = {
690 { HCBT_DESTROYWND, hook },
691 { 0x0090, sent|optional },
692 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
693 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
694 { 0x0090, sent|optional },
695 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
696 { WM_NCACTIVATE, sent|optional|wparam, 0 },
697 { WM_ACTIVATE, sent|optional },
698 { WM_ACTIVATEAPP, sent|optional|wparam, 0 },
699 { WM_KILLFOCUS, sent|optional|wparam, 0 },
700 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
701 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
702 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
703 { WM_DESTROY, sent },
704 { WM_NCDESTROY, sent },
705 { 0 }
707 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
708 static const struct message WmCreateMaxPopupSeq[] = {
709 { HCBT_CREATEWND, hook },
710 { WM_NCCREATE, sent },
711 { WM_NCCALCSIZE, sent|wparam, 0 },
712 { WM_CREATE, sent },
713 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
714 { WM_SIZE, sent|wparam, SIZE_RESTORED },
715 { WM_MOVE, sent },
716 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
717 { WM_GETMINMAXINFO, sent },
718 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
719 { WM_NCCALCSIZE, sent|wparam, TRUE },
720 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
721 { WM_MOVE, sent|defwinproc },
722 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
723 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
724 { WM_SHOWWINDOW, sent|wparam, 1 },
725 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
726 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
727 { HCBT_ACTIVATE, hook },
728 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
729 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
730 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
731 { WM_NCPAINT, sent|wparam|optional, 1 },
732 { WM_ERASEBKGND, sent|optional },
733 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_NOMOVE|SWP_NOSIZE },
734 { WM_ACTIVATEAPP, sent|wparam, 1 },
735 { WM_NCACTIVATE, sent },
736 { WM_ACTIVATE, sent|wparam, 1 },
737 { HCBT_SETFOCUS, hook },
738 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
739 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
740 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
741 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
742 { WM_GETTEXT, sent|optional },
743 { WM_SYNCPAINT, sent|wparam|optional, 4 },
744 { WM_NCPAINT, sent|wparam|optional, 1 },
745 { WM_ERASEBKGND, sent|optional },
746 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
747 { WM_ERASEBKGND, sent|defwinproc|optional },
748 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
749 { 0 }
751 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
752 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
753 { HCBT_CREATEWND, hook },
754 { WM_NCCREATE, sent },
755 { WM_NCCALCSIZE, sent|wparam, 0 },
756 { WM_CREATE, sent },
757 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
758 { WM_SIZE, sent|wparam, SIZE_RESTORED },
759 { WM_MOVE, sent },
760 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
761 { WM_GETMINMAXINFO, sent },
762 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
763 { WM_NCCALCSIZE, sent|wparam, TRUE },
764 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
765 { WM_MOVE, sent|defwinproc },
766 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
767 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
768 { 0 }
770 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
771 static const struct message WmShowMaxPopupResizedSeq[] = {
772 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
773 { WM_GETMINMAXINFO, sent },
774 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED, 0, SWP_STATECHANGED /* w1064v1809 */ },
775 { WM_NCCALCSIZE, sent|wparam, TRUE },
776 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
777 { HCBT_ACTIVATE, hook },
778 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
779 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
780 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
781 { WM_NCPAINT, sent|wparam|optional, 1 },
782 { WM_ERASEBKGND, sent|optional },
783 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
784 { WM_ACTIVATEAPP, sent|wparam, 1 },
785 { WM_NCACTIVATE, sent },
786 { WM_ACTIVATE, sent|wparam, 1 },
787 { HCBT_SETFOCUS, hook },
788 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
789 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
790 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
791 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
792 { WM_GETTEXT, sent|optional },
793 { WM_NCPAINT, sent|wparam|optional, 1 },
794 { WM_ERASEBKGND, sent|optional },
795 { WM_WINDOWPOSCHANGED, sent },
796 /* WinNT4.0 sends WM_MOVE */
797 { WM_MOVE, sent|defwinproc|optional },
798 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
799 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
800 { 0 }
802 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
803 static const struct message WmShowMaxPopupSeq[] = {
804 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
805 { WM_GETMINMAXINFO, sent },
806 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED, 0, SWP_STATECHANGED /* w1064v1809 */ },
807 { WM_NCCALCSIZE, sent|wparam, TRUE },
808 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
809 { HCBT_ACTIVATE, hook },
810 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
811 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
812 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
813 { WM_NCPAINT, sent|wparam|optional, 1 },
814 { WM_ERASEBKGND, sent|optional },
815 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOMOVE|SWP_NOSIZE },
816 { WM_ACTIVATEAPP, sent|wparam, 1 },
817 { WM_NCACTIVATE, sent },
818 { WM_ACTIVATE, sent|wparam, 1 },
819 { HCBT_SETFOCUS, hook },
820 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
821 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
822 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
823 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
824 { WM_GETTEXT, sent|optional },
825 { WM_SYNCPAINT, sent|wparam|optional, 4 },
826 { WM_NCPAINT, sent|wparam|optional, 1 },
827 { WM_ERASEBKGND, sent|optional },
828 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
829 { WM_ERASEBKGND, sent|defwinproc|optional },
830 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE, 0, SWP_STATECHANGED /* w1064v1809 */ },
831 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
832 { WM_SIZE, sent|defwinproc|optional },
833 { 0 }
835 /* CreateWindow(WS_VISIBLE) for popup window */
836 static const struct message WmCreatePopupSeq[] = {
837 { HCBT_CREATEWND, hook },
838 { WM_NCCREATE, sent },
839 { WM_NCCALCSIZE, sent|wparam, 0 },
840 { WM_CREATE, sent },
841 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
842 { WM_SIZE, sent|wparam, SIZE_RESTORED },
843 { WM_MOVE, sent },
844 { WM_SHOWWINDOW, sent|wparam, 1 },
845 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
846 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
847 { HCBT_ACTIVATE, hook },
848 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
849 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
850 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
851 { WM_NCPAINT, sent|wparam|optional, 1 },
852 { WM_ERASEBKGND, sent|optional },
853 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
854 { WM_ACTIVATEAPP, sent|wparam, 1 },
855 { WM_NCACTIVATE, sent },
856 { WM_ACTIVATE, sent|wparam, 1 },
857 { HCBT_SETFOCUS, hook },
858 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
859 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
860 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
861 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
862 { WM_GETTEXT, sent|optional },
863 { WM_SYNCPAINT, sent|wparam|optional, 4 },
864 { WM_NCPAINT, sent|wparam|optional, 1 },
865 { WM_ERASEBKGND, sent|optional },
866 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
867 { 0 }
869 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
870 static const struct message WmShowVisMaxPopupSeq[] = {
871 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
872 { WM_GETMINMAXINFO, sent },
873 { WM_GETTEXT, sent|optional },
874 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
875 { WM_GETTEXT, sent|optional },
876 { WM_NCCALCSIZE, sent|wparam, TRUE },
877 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
878 { WM_NCPAINT, sent|wparam|optional, 1 },
879 { WM_ERASEBKGND, sent|optional },
880 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
881 { WM_MOVE, sent|defwinproc },
882 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
883 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
884 { 0 }
886 /* ShowWindow(hwnd, SW_RESTORE) to a minimized window */
887 static const struct message WmShowRestoreMinimizedOverlappedSeq[] =
889 { HCBT_MINMAX, hook },
890 { WM_QUERYOPEN, sent },
891 { WM_GETTEXT, sent|optional },
892 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
893 { WM_GETMINMAXINFO, sent|defwinproc },
894 { WM_NCCALCSIZE, sent },
895 { HCBT_ACTIVATE, hook },
896 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
897 { WM_NCACTIVATE, sent },
898 { WM_GETTEXT, sent|defwinproc|optional },
899 { WM_ACTIVATE, sent|wparam, WA_ACTIVE },
900 { HCBT_SETFOCUS, hook },
901 { WM_SETFOCUS, sent|defwinproc },
902 { WM_NCPAINT, sent },
903 { WM_GETTEXT, sent|defwinproc|optional },
904 { WM_GETTEXT, sent|defwinproc|optional },
905 { WM_ERASEBKGND, sent },
906 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
907 { WM_MOVE, sent|defwinproc },
908 { WM_SIZE, sent|defwinproc },
909 { WM_NCCALCSIZE, sent|optional },
910 { WM_NCPAINT, sent|optional },
911 { WM_ERASEBKGND, sent|optional },
912 /* Note this WM_ACTIVATE message even if the window is already active and focused */
913 { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, 0 },
914 { WM_SYNCPAINT, sent|optional },
915 { WM_PAINT, sent },
916 { WM_GETMINMAXINFO, sent|optional },
917 { 0 }
919 /* ShowWindow(hwnd, SW_SHOWNOACTIVATE) to a minimized window */
920 static const struct message WmShowNoActivateMinimizedOverlappedSeq[] =
922 { HCBT_MINMAX, hook },
923 { WM_QUERYOPEN, sent },
924 { WM_GETTEXT, sent|optional },
925 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
926 { WM_GETMINMAXINFO, sent|defwinproc },
927 { WM_NCCALCSIZE, sent },
928 { WM_NCPAINT, sent },
929 { WM_GETTEXT, sent|defwinproc|optional },
930 { WM_ERASEBKGND, sent },
931 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
932 { WM_MOVE, sent|defwinproc },
933 { WM_SIZE, sent|defwinproc },
934 /* Following optional messages are on XP/2003 */
935 { WM_NCCALCSIZE, sent|optional },
936 { WM_NCPAINT, sent|optional },
937 { WM_ERASEBKGND, sent|optional },
938 { HCBT_SETFOCUS, hook|optional },
939 { WM_SETFOCUS, sent|optional },
940 { HCBT_ACTIVATE, hook|optional },
941 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
942 { WM_NCACTIVATE, sent|optional },
943 { WM_GETTEXT, sent|defwinproc|optional },
944 { WM_ACTIVATE, sent|wparam|optional, WA_ACTIVE },
945 { HCBT_SETFOCUS, hook|optional },
946 { WM_SETFOCUS, sent|defwinproc|optional },
947 { WM_KILLFOCUS, sent|optional },
948 { WM_SETFOCUS, sent|optional },
949 /* Note this WM_ACTIVATE message on XP even if the window is already active and focused */
950 { WM_ACTIVATE, sent|wparam|lparam|optional, WA_ACTIVE, 0 },
951 { WM_SYNCPAINT, sent|optional },
952 { WM_PAINT, sent },
953 { WM_GETMINMAXINFO, sent|optional },
954 { 0 }
956 /* ShowWindow(hwnd, SW_RESTORE) to an active minimized window */
957 static const struct message WmShowRestoreActiveMinimizedOverlappedSeq[] =
959 { HCBT_MINMAX, hook },
960 { WM_QUERYOPEN, sent },
961 { WM_GETTEXT, sent|optional },
962 { WM_NCACTIVATE, sent },
963 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
964 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
965 { WM_NCCALCSIZE, sent|optional },
966 { WM_MOVE, sent|optional },
967 { WM_SIZE, sent|optional },
968 { WM_GETTEXT, sent|optional },
969 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
970 { WM_GETMINMAXINFO, sent|defwinproc },
971 { WM_NCCALCSIZE, sent },
972 { WM_NCPAINT, sent },
973 { WM_GETTEXT, sent|defwinproc|optional },
974 { WM_ERASEBKGND, sent },
975 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
976 { WM_MOVE, sent|defwinproc },
977 { WM_SIZE, sent|defwinproc },
978 { WM_NCCALCSIZE, sent|optional },
979 { WM_NCPAINT, sent|optional },
980 { WM_ERASEBKGND, sent|optional },
981 { HCBT_SETFOCUS, hook },
982 { WM_SETFOCUS, sent },
983 /* Note this WM_ACTIVATE message even if the window is already active */
984 { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, 0 },
985 { WM_SYNCPAINT, sent|optional },
986 { WM_PAINT, sent },
987 { WM_GETMINMAXINFO, sent|optional },
988 { 0 }
990 /* ShowWindow(hwnd, SW_SHOWNOACTIVATE) to an active minimized window */
991 static const struct message WmShowNoActivateActiveMinimizedOverlappedSeq[] =
993 { HCBT_MINMAX, hook },
994 { WM_QUERYOPEN, sent },
995 { WM_GETTEXT, sent|optional },
996 { WM_NCACTIVATE, sent },
997 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
998 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
999 { WM_NCCALCSIZE, sent|optional },
1000 { WM_MOVE, sent|optional },
1001 { WM_SIZE, sent|optional },
1002 { WM_GETTEXT, sent|optional },
1003 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1004 { WM_GETMINMAXINFO, sent|defwinproc },
1005 { WM_NCCALCSIZE, sent },
1006 { WM_NCPAINT, sent },
1007 { WM_GETTEXT, sent|defwinproc|optional },
1008 { WM_ERASEBKGND, sent },
1009 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1010 { WM_MOVE, sent|defwinproc },
1011 { WM_SIZE, sent|defwinproc },
1012 { WM_NCCALCSIZE, sent|optional },
1013 { WM_NCPAINT, sent|optional },
1014 { WM_ERASEBKGND, sent|optional },
1015 /* Following optional messages are present on XP */
1016 { HCBT_SETFOCUS, hook|optional },
1017 { WM_SETFOCUS, sent|optional },
1018 /* Note this WM_ACTIVATE message even if the window is already active and with flag SW_SHOWNOACTIVATE */
1019 { WM_ACTIVATE, sent|wparam|lparam|optional, WA_ACTIVE, 0 },
1020 { WM_SYNCPAINT, sent|optional },
1021 { WM_PAINT, sent },
1022 { WM_GETMINMAXINFO, sent|optional },
1023 { 0 }
1025 /* CreateWindow (for a child popup window, not initially visible) */
1026 static const struct message WmCreateChildPopupSeq[] = {
1027 { HCBT_CREATEWND, hook },
1028 { WM_NCCREATE, sent },
1029 { WM_NCCALCSIZE, sent|wparam, 0 },
1030 { WM_CREATE, sent },
1031 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1032 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1033 { WM_MOVE, sent },
1034 { 0 }
1036 /* CreateWindow (for a popup window, not initially visible,
1037 * which sets WS_VISIBLE in WM_CREATE handler)
1039 static const struct message WmCreateInvisiblePopupSeq[] = {
1040 { HCBT_CREATEWND, hook },
1041 { WM_NCCREATE, sent },
1042 { WM_NCCALCSIZE, sent|wparam, 0 },
1043 { WM_CREATE, sent },
1044 { WM_STYLECHANGING, sent },
1045 { WM_STYLECHANGED, sent },
1046 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1047 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1048 { WM_MOVE, sent },
1049 { 0 }
1051 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
1052 * for a popup window with WS_VISIBLE style set
1054 static const struct message WmShowVisiblePopupSeq_2[] = {
1055 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1056 { 0 }
1058 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1059 * for a popup window with WS_VISIBLE style set
1061 static const struct message WmShowVisiblePopupSeq_3[] = {
1062 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1063 { HCBT_ACTIVATE, hook },
1064 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1065 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1066 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1067 { WM_NCACTIVATE, sent },
1068 { WM_ACTIVATE, sent|wparam, 1 },
1069 { HCBT_SETFOCUS, hook },
1070 { WM_KILLFOCUS, sent|parent },
1071 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1072 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1073 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1074 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1075 { WM_SETFOCUS, sent|defwinproc },
1076 { WM_GETTEXT, sent|optional },
1077 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_SHOWWINDOW },
1078 { 0 }
1080 /* CreateWindow (for a popup window with WS_VISIBLE style set and extreme location)
1082 static const struct message WmShowPopupExtremeLocationSeq[] = {
1083 { HCBT_CREATEWND, hook },
1084 { WM_NCCREATE, sent },
1085 { WM_NCCALCSIZE, sent|wparam, 0 },
1086 { WM_CREATE, sent },
1087 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1088 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1089 { WM_MOVE, sent },
1090 { WM_SHOWWINDOW, sent|wparam, 1 },
1091 { WM_WINDOWPOSCHANGING, sent },
1092 { HCBT_ACTIVATE, hook },
1093 { WM_WINDOWPOSCHANGING, sent|optional },
1094 { WM_QUERYNEWPALETTE, sent|optional },
1096 /* occasionally received on test machines */
1097 { WM_NCPAINT, sent|optional },
1098 { WM_ERASEBKGND, sent|optional },
1099 { WM_WINDOWPOSCHANGED, sent|optional },
1101 { WM_ACTIVATEAPP, sent },
1102 { WM_NCACTIVATE, sent },
1103 { WM_ACTIVATE, sent },
1104 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1105 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1106 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1107 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1108 { HCBT_SETFOCUS, hook },
1109 { WM_SETFOCUS, sent|defwinproc },
1110 { WM_NCPAINT, sent|wparam, 1 },
1111 { WM_ERASEBKGND, sent },
1112 { WM_WINDOWPOSCHANGED, sent },
1113 /* occasionally received on test machines */
1114 { WM_NCPAINT, sent|optional },
1115 { WM_ERASEBKGND, sent|optional },
1116 { 0 }
1118 /* CreateWindow (for a popup window with WS_VISIBLE style set)
1120 static const struct message WmShowPopupFirstDrawSeq_1[] = {
1121 { HCBT_CREATEWND, hook },
1122 { WM_NCCREATE, sent },
1123 { WM_NCCALCSIZE, sent|wparam, 0 },
1124 { WM_CREATE, sent },
1125 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1126 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1127 { WM_MOVE, sent },
1128 { WM_SHOWWINDOW, sent|wparam, 1 },
1129 { WM_WINDOWPOSCHANGING, sent },
1130 { HCBT_ACTIVATE, hook },
1131 { WM_WINDOWPOSCHANGING, sent|optional },
1132 { WM_QUERYNEWPALETTE, sent|optional },
1133 { WM_ACTIVATEAPP, sent },
1134 { WM_NCACTIVATE, sent },
1135 { WM_ACTIVATE, sent },
1136 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1137 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1138 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1139 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1140 { HCBT_SETFOCUS, hook },
1141 { WM_SETFOCUS, sent|defwinproc },
1142 { WM_NCPAINT, sent|wparam, 1 },
1143 { WM_ERASEBKGND, sent },
1144 { WM_WINDOWPOSCHANGED, sent },
1145 { WM_PAINT, sent },
1146 /* occasionally received on test machines */
1147 { WM_NCPAINT, sent|beginpaint|optional },
1148 { WM_ERASEBKGND, sent|beginpaint|optional },
1149 { 0 }
1151 /* CreateWindow (for a popup window that is shown with ShowWindow(SW_SHOWMAXIMIZED))
1153 static const struct message WmShowPopupFirstDrawSeq_2[] = {
1154 { HCBT_CREATEWND, hook },
1155 { WM_NCCREATE, sent },
1156 { WM_NCCALCSIZE, sent|wparam, 0 },
1157 { WM_CREATE, sent },
1158 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1159 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1160 { WM_MOVE, sent },
1161 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1162 { WM_GETMINMAXINFO, sent },
1163 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_STATECHANGED|SWP_SHOWWINDOW|SWP_FRAMECHANGED },
1164 { WM_NCCALCSIZE, sent|wparam, TRUE },
1165 { HCBT_ACTIVATE, hook },
1166 { WM_WINDOWPOSCHANGING, sent|optional },
1167 { WM_NCPAINT, sent|optional|wparam, 1 },
1168 { WM_ERASEBKGND, sent|optional },
1169 { WM_WINDOWPOSCHANGED, sent|optional },
1170 { WM_QUERYNEWPALETTE, sent|optional },
1171 { WM_ACTIVATEAPP, sent },
1172 { WM_NCACTIVATE, sent },
1173 { WM_ACTIVATE, sent },
1174 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1175 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1176 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1177 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1178 { HCBT_SETFOCUS, hook },
1179 { WM_SETFOCUS, sent|defwinproc },
1180 { WM_NCPAINT, sent|wparam, 1 },
1181 { WM_ERASEBKGND, sent },
1182 { WM_WINDOWPOSCHANGED, sent|optional },
1183 { WM_MOVE, sent|defwinproc },
1184 { WM_SIZE, sent|defwinproc, 0 },
1185 { WM_PAINT, sent},
1186 /* occasionally received on test machines */
1187 { WM_NCPAINT, sent|beginpaint|optional },
1188 { WM_ERASEBKGND, sent|beginpaint|optional },
1189 { 0 }
1191 static const struct message WmFirstDrawSetWindowPosSeq1[] = {
1192 { HCBT_CREATEWND, hook },
1193 { WM_NCCREATE, sent },
1194 { WM_NCCALCSIZE, sent|wparam, 0 },
1195 { WM_CREATE, sent },
1196 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1197 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1198 { WM_MOVE, sent },
1199 { WM_WINDOWPOSCHANGING, sent },
1200 { HCBT_ACTIVATE, hook },
1201 { WM_WINDOWPOSCHANGING, sent|optional },
1202 { WM_QUERYNEWPALETTE, sent|optional },
1203 { WM_ACTIVATEAPP, sent },
1204 { WM_NCACTIVATE, sent },
1205 { WM_ACTIVATE, sent },
1206 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1207 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1208 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1209 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1210 { HCBT_SETFOCUS, hook },
1211 { WM_SETFOCUS, sent|defwinproc },
1212 { WM_NCPAINT, sent|wparam, 1 },
1213 { WM_ERASEBKGND, sent },
1214 { WM_WINDOWPOSCHANGED, sent },
1215 { WM_MOVE, sent|defwinproc },
1216 { 0 }
1218 static const struct message WmFirstDrawSetWindowPosSeq2[] = {
1219 { HCBT_CREATEWND, hook },
1220 { WM_NCCREATE, sent },
1221 { WM_NCCALCSIZE, sent|wparam, 0 },
1222 { WM_CREATE, sent },
1223 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1224 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1225 { WM_MOVE, sent },
1226 { WM_WINDOWPOSCHANGING, sent },
1227 { HCBT_ACTIVATE, hook },
1228 { WM_QUERYNEWPALETTE, sent|optional },
1229 { WM_WINDOWPOSCHANGING, sent|optional },
1230 { WM_ACTIVATEAPP, sent },
1231 { WM_NCACTIVATE, sent },
1232 { WM_ACTIVATE, sent },
1233 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1234 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1235 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1236 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1237 { HCBT_SETFOCUS, hook },
1238 { WM_SETFOCUS, sent|defwinproc },
1239 { WM_WINDOWPOSCHANGED, sent },
1240 { WM_MOVE, sent|defwinproc },
1241 { 0 }
1243 static const struct message WmFirstDrawSetWindowPosSeq3[] = {
1244 { HCBT_CREATEWND, hook },
1245 { WM_NCCREATE, sent },
1246 { WM_NCCALCSIZE, sent|wparam, 0 },
1247 { WM_CREATE, sent },
1248 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1249 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1250 { WM_MOVE, sent },
1251 { HCBT_ACTIVATE, hook|optional },
1252 /* Probably shouldn't happen, but not part of this test */
1253 { WM_QUERYNEWPALETTE, sent|optional },
1254 { WM_ACTIVATEAPP, sent|optional },
1255 { WM_NCACTIVATE, sent|optional },
1256 { WM_ACTIVATE, sent|optional },
1257 { HCBT_SETFOCUS, hook|optional },
1258 { WM_SETFOCUS, sent|defwinproc|optional },
1259 { 0 }
1261 static const struct message WmFirstDrawSetWindowPosSeq4[] = {
1262 { HCBT_CREATEWND, hook },
1263 { WM_NCCREATE, sent },
1264 { WM_NCCALCSIZE, sent|wparam, 0 },
1265 { WM_CREATE, sent },
1266 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1267 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1268 { WM_MOVE, sent },
1269 { WM_WINDOWPOSCHANGING, sent },
1270 { HCBT_ACTIVATE, hook },
1271 { WM_WINDOWPOSCHANGING, sent|optional },
1272 { WM_QUERYNEWPALETTE, sent|optional },
1273 { WM_ACTIVATEAPP, sent },
1274 { WM_NCACTIVATE, sent },
1275 { WM_ACTIVATE, sent },
1276 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1277 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1278 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1279 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1280 { HCBT_SETFOCUS, hook },
1281 { WM_SETFOCUS, sent|defwinproc },
1282 { WM_NCPAINT, sent|wparam, 1 },
1283 { WM_ERASEBKGND, sent },
1284 { WM_WINDOWPOSCHANGED, sent },
1285 { 0 }
1287 static const struct message WmFirstDrawSetWindowPosSeq5[] = {
1288 { HCBT_CREATEWND, hook },
1289 { WM_NCCREATE, sent },
1290 { WM_NCCALCSIZE, sent|wparam, 0 },
1291 { WM_CREATE, sent },
1292 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1293 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1294 { WM_MOVE, sent },
1295 { WM_WINDOWPOSCHANGING, sent },
1296 { HCBT_ACTIVATE, hook },
1297 { WM_WINDOWPOSCHANGING, sent|optional },
1298 { WM_QUERYNEWPALETTE, sent|optional },
1299 { WM_ACTIVATEAPP, sent },
1300 { WM_NCACTIVATE, sent },
1301 { WM_ACTIVATE, sent },
1302 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1303 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1304 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1305 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1306 { HCBT_SETFOCUS, hook },
1307 { WM_SETFOCUS, sent|defwinproc },
1308 { WM_WINDOWPOSCHANGED, sent },
1309 { 0 }
1311 static const struct message WmFirstDrawChildSeq1[] = {
1312 { 0 }
1314 static const struct message WmFirstDrawChildSeq2[] = {
1315 { WM_NCPAINT, sent|wparam, 1 },
1316 { WM_ERASEBKGND, sent },
1317 /* occasionally received on test machines */
1318 { WM_NCPAINT, sent|optional },
1319 { WM_ERASEBKGND, sent|optional },
1320 { 0 }
1322 /* CreateWindow (for child window, not initially visible) */
1323 static const struct message WmCreateChildSeq[] = {
1324 { HCBT_CREATEWND, hook },
1325 { WM_NCCREATE, sent },
1326 /* child is inserted into parent's child list after WM_NCCREATE returns */
1327 { WM_NCCALCSIZE, sent|wparam, 0 },
1328 { WM_CREATE, sent },
1329 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1330 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1331 { WM_MOVE, sent },
1332 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1333 { 0 }
1335 /* CreateWindow (for maximized child window, not initially visible) */
1336 static const struct message WmCreateMaximizedChildSeq[] = {
1337 { HCBT_CREATEWND, hook },
1338 { WM_NCCREATE, sent },
1339 { WM_NCCALCSIZE, sent|wparam, 0 },
1340 { WM_CREATE, sent },
1341 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1342 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1343 { WM_MOVE, sent },
1344 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1345 { WM_GETMINMAXINFO, sent },
1346 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
1347 { WM_NCCALCSIZE, sent|wparam, 1 },
1348 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1349 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1350 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1351 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1352 { 0 }
1354 /* CreateWindow (for a child window, initially visible) */
1355 static const struct message WmCreateVisibleChildSeq[] = {
1356 { HCBT_CREATEWND, hook },
1357 { WM_NCCREATE, sent },
1358 /* child is inserted into parent's child list after WM_NCCREATE returns */
1359 { WM_NCCALCSIZE, sent|wparam, 0 },
1360 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 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_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1366 { WM_SHOWWINDOW, sent|wparam, 1 },
1367 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1368 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1369 { WM_ERASEBKGND, sent|parent|optional },
1370 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1371 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
1372 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1373 { 0 }
1375 /* ShowWindow(SW_SHOW) for a not visible child window */
1376 static const struct message WmShowChildSeq[] = {
1377 { WM_SHOWWINDOW, sent|wparam, 1 },
1378 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1379 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1380 { WM_ERASEBKGND, sent|parent|optional },
1381 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1382 { 0 }
1384 /* ShowWindow(SW_HIDE) for a visible child window */
1385 static const struct message WmHideChildSeq[] = {
1386 { WM_SHOWWINDOW, sent|wparam, 0 },
1387 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1388 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1389 { WM_ERASEBKGND, sent|parent|optional },
1390 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1391 { 0 }
1393 /* ShowWindow(SW_HIDE) for a visible child window checking all parent events*/
1394 static const struct message WmHideChildSeq2[] = {
1395 { WM_SHOWWINDOW, sent|wparam, 0 },
1396 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1397 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1398 { WM_ERASEBKGND, sent|parent|optional },
1399 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1400 { 0 }
1402 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1403 * for a not visible child window
1405 static const struct message WmShowChildSeq_2[] = {
1406 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1407 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1408 { WM_CHILDACTIVATE, sent },
1409 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1410 { 0 }
1412 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
1413 * for a not visible child window
1415 static const struct message WmShowChildSeq_3[] = {
1416 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1417 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1418 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1419 { 0 }
1421 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1422 * for a visible child window with a caption
1424 static const struct message WmShowChildSeq_4[] = {
1425 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1426 { WM_CHILDACTIVATE, sent },
1427 { 0 }
1429 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
1430 static const struct message WmShowChildInvisibleParentSeq_1[] = {
1431 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1432 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1433 { WM_NCCALCSIZE, sent|wparam, 1 },
1434 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1435 { WM_CHILDACTIVATE, sent|optional },
1436 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1437 { WM_MOVE, sent|defwinproc },
1438 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1439 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1440 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1441 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1442 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1443 { WM_GETTEXT, sent|optional },
1444 { 0 }
1446 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
1447 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
1448 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1449 { 0 }
1451 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1452 static const struct message WmShowChildInvisibleParentSeq_2[] = {
1453 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1454 { WM_GETMINMAXINFO, sent },
1455 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
1456 { WM_NCCALCSIZE, sent|wparam, 1 },
1457 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1458 { WM_CHILDACTIVATE, sent },
1459 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1460 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1461 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1462 { 0 }
1464 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1465 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
1466 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1467 { 0 }
1469 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1470 static const struct message WmShowChildInvisibleParentSeq_3[] = {
1471 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1472 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1473 { WM_NCCALCSIZE, sent|wparam, 1 },
1474 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1475 { WM_CHILDACTIVATE, sent },
1476 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1477 { WM_MOVE, sent|defwinproc },
1478 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1479 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1480 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1481 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1482 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1483 { WM_GETTEXT, sent|optional },
1484 { 0 }
1486 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1487 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
1488 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1489 { 0 }
1491 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1492 static const struct message WmShowChildInvisibleParentSeq_4[] = {
1493 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1494 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
1495 { WM_NCCALCSIZE, sent|wparam, 1 },
1496 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1497 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1498 { WM_MOVE, sent|defwinproc },
1499 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1500 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1501 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1502 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1503 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1504 { WM_GETTEXT, sent|optional },
1505 { 0 }
1507 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1508 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
1509 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1510 { 0 }
1512 /* ShowWindow(SW_SHOW) for child with invisible parent */
1513 static const struct message WmShowChildInvisibleParentSeq_5[] = {
1514 { WM_SHOWWINDOW, sent|wparam, 1 },
1515 { 0 }
1517 /* ShowWindow(SW_HIDE) for child with invisible parent */
1518 static const struct message WmHideChildInvisibleParentSeq[] = {
1519 { WM_SHOWWINDOW, sent|wparam, 0 },
1520 { 0 }
1522 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
1523 static const struct message WmShowChildInvisibleParentSeq_6[] = {
1524 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1525 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1526 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1527 { 0 }
1529 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
1530 static const struct message WmHideChildInvisibleParentSeq_2[] = {
1531 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1532 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1533 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1534 { 0 }
1536 /* DestroyWindow for a visible child window */
1537 static const struct message WmDestroyChildSeq[] = {
1538 { HCBT_DESTROYWND, hook },
1539 { 0x0090, sent|optional },
1540 { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1541 { WM_SHOWWINDOW, sent|wparam, 0 },
1542 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1543 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1544 { WM_ERASEBKGND, sent|parent|optional },
1545 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1546 { HCBT_SETFOCUS, hook }, /* set focus to a parent */
1547 { WM_KILLFOCUS, sent },
1548 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1549 { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
1550 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1551 { WM_SETFOCUS, sent|parent },
1552 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1553 { WM_DESTROY, sent },
1554 { WM_DESTROY, sent|optional }, /* some other (IME?) window */
1555 { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
1556 { WM_NCDESTROY, sent },
1557 { 0 }
1559 /* visible child window destroyed by thread exit */
1560 static const struct message WmExitThreadSeq[] = {
1561 { WM_NCDESTROY, sent }, /* actually in grandchild */
1562 { WM_PAINT, sent|parent },
1563 { WM_ERASEBKGND, sent|parent|beginpaint },
1564 { 0 }
1566 /* DestroyWindow for a visible child window with invisible parent */
1567 static const struct message WmDestroyInvisibleChildSeq[] = {
1568 { HCBT_DESTROYWND, hook },
1569 { 0x0090, sent|optional },
1570 { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1571 { WM_SHOWWINDOW, sent|wparam, 0 },
1572 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1573 { WM_DESTROY, sent },
1574 { WM_NCDESTROY, sent },
1575 { 0 }
1577 /* Resizing child window with MoveWindow (32) */
1578 static const struct message WmResizingChildWithMoveWindowSeq[] = {
1579 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
1580 { WM_NCCALCSIZE, sent|wparam, 1 },
1581 { WM_ERASEBKGND, sent|parent|optional },
1582 { WM_ERASEBKGND, sent|optional },
1583 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
1584 { WM_MOVE, sent|defwinproc },
1585 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1586 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1587 { 0 }
1589 /* Creation of a custom dialog (32) */
1590 static const struct message WmCreateCustomDialogSeq[] = {
1591 { HCBT_CREATEWND, hook },
1592 { WM_GETMINMAXINFO, sent },
1593 { WM_NCCREATE, sent },
1594 { WM_NCCALCSIZE, sent|wparam, 0 },
1595 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1596 { WM_CREATE, sent },
1597 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1598 { WM_NOTIFYFORMAT, sent|optional },
1599 { WM_QUERYUISTATE, sent|optional },
1600 { WM_WINDOWPOSCHANGING, sent|optional },
1601 { WM_GETMINMAXINFO, sent|optional },
1602 { WM_NCCALCSIZE, sent|optional },
1603 { WM_WINDOWPOSCHANGED, sent|optional },
1604 { WM_SHOWWINDOW, sent|wparam, 1 },
1605 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1606 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1607 { HCBT_ACTIVATE, hook },
1608 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1611 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1613 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1615 { WM_NCACTIVATE, sent },
1616 { WM_GETTEXT, sent|optional|defwinproc },
1617 { WM_GETTEXT, sent|optional|defwinproc },
1618 { WM_GETTEXT, sent|optional|defwinproc },
1619 { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1620 { WM_ACTIVATE, sent|wparam, 1 },
1621 { WM_GETTEXT, sent|optional },
1622 { WM_KILLFOCUS, sent|parent },
1623 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1624 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1625 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1626 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1627 { WM_SETFOCUS, sent },
1628 { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1629 { WM_NCPAINT, sent|wparam, 1 },
1630 { WM_GETTEXT, sent|optional|defwinproc },
1631 { WM_GETTEXT, sent|optional|defwinproc },
1632 { WM_ERASEBKGND, sent },
1633 { WM_CTLCOLORDLG, sent|optional|defwinproc },
1634 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1635 { WM_GETTEXT, sent|optional },
1636 { WM_GETTEXT, sent|optional },
1637 { WM_NCCALCSIZE, sent|optional },
1638 { WM_NCPAINT, sent|optional },
1639 { WM_GETTEXT, sent|optional|defwinproc },
1640 { WM_GETTEXT, sent|optional|defwinproc },
1641 { WM_ERASEBKGND, sent|optional },
1642 { WM_CTLCOLORDLG, sent|optional|defwinproc },
1643 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1644 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1645 { WM_MOVE, sent },
1646 { 0 }
1648 /* Calling EndDialog for a custom dialog (32) */
1649 static const struct message WmEndCustomDialogSeq[] = {
1650 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1651 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1652 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1653 { WM_GETTEXT, sent|optional },
1654 { HCBT_ACTIVATE, hook },
1655 { WM_NCACTIVATE, sent|wparam, 0 },
1656 { WM_GETTEXT, sent|optional|defwinproc },
1657 { WM_GETTEXT, sent|optional|defwinproc },
1658 { WM_ACTIVATE, sent|wparam, 0 },
1659 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1660 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1661 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1662 { WM_GETTEXT, sent|optional|defwinproc },
1663 { WM_GETTEXT, sent|optional|defwinproc },
1664 { HCBT_SETFOCUS, hook },
1665 { WM_KILLFOCUS, sent },
1666 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1667 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1668 { WM_IME_NOTIFY, sent|wparam|optional, 1 },
1669 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1670 { WM_SETFOCUS, sent|parent|defwinproc },
1671 { 0 }
1673 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
1674 static const struct message WmShowCustomDialogSeq[] = {
1675 { WM_SHOWWINDOW, sent|wparam, 1 },
1676 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1677 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1678 { HCBT_ACTIVATE, hook },
1679 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1681 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1683 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1684 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1685 { WM_NCACTIVATE, sent },
1686 { WM_ACTIVATE, sent|wparam, 1 },
1687 { WM_GETTEXT, sent|optional },
1689 { WM_KILLFOCUS, sent|parent },
1690 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1691 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1692 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1693 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1694 { WM_SETFOCUS, sent },
1695 { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1696 { WM_NCPAINT, sent|wparam, 1 },
1697 { WM_ERASEBKGND, sent },
1698 { WM_CTLCOLORDLG, sent|defwinproc },
1699 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1700 { 0 }
1702 /* Creation and destruction of a modal dialog (32) */
1703 static const struct message WmModalDialogSeq[] = {
1704 { WM_CANCELMODE, sent|parent },
1705 { HCBT_SETFOCUS, hook },
1706 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1707 { WM_KILLFOCUS, sent|parent },
1708 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1709 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1710 { WM_ENABLE, sent|parent|wparam, 0 },
1711 { HCBT_CREATEWND, hook },
1712 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1713 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1714 { WM_SETFONT, sent },
1715 { WM_INITDIALOG, sent },
1716 { WM_CHANGEUISTATE, sent|optional },
1717 { WM_UPDATEUISTATE, sent|optional },
1718 { WM_SHOWWINDOW, sent },
1719 { HCBT_ACTIVATE, hook },
1720 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1721 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1722 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1723 { WM_NCACTIVATE, sent },
1724 { WM_GETTEXT, sent|optional },
1725 { WM_ACTIVATE, sent|wparam, 1 },
1726 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1727 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1728 { WM_NCPAINT, sent|optional },
1729 { WM_GETTEXT, sent|optional },
1730 { WM_ERASEBKGND, sent|optional },
1731 { WM_CTLCOLORDLG, sent|optional },
1732 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1733 { WM_GETTEXT, sent|optional },
1734 { WM_NCCALCSIZE, sent|optional },
1735 { WM_NCPAINT, sent|optional },
1736 { WM_GETTEXT, sent|optional },
1737 { WM_ERASEBKGND, sent|optional },
1738 { WM_CTLCOLORDLG, sent|optional },
1739 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1740 { WM_PAINT, sent|optional },
1741 { WM_CTLCOLORBTN, sent|optional },
1742 { WM_GETTITLEBARINFOEX, sent|optional },
1743 { WM_ENTERIDLE, sent|parent|optional },
1744 { WM_ENTERIDLE, sent|parent|optional },
1745 { WM_ENTERIDLE, sent|parent|optional },
1746 { WM_ENTERIDLE, sent|parent|optional },
1747 { WM_ENTERIDLE, sent|parent|optional },
1748 { WM_ENTERIDLE, sent|parent|optional },
1749 { WM_ENTERIDLE, sent|parent|optional },
1750 { WM_ENTERIDLE, sent|parent|optional },
1751 { WM_ENTERIDLE, sent|parent|optional },
1752 { WM_ENTERIDLE, sent|parent|optional },
1753 { WM_ENTERIDLE, sent|parent|optional },
1754 { WM_ENTERIDLE, sent|parent|optional },
1755 { WM_ENTERIDLE, sent|parent|optional },
1756 { WM_ENTERIDLE, sent|parent|optional },
1757 { WM_ENTERIDLE, sent|parent|optional },
1758 { WM_ENTERIDLE, sent|parent|optional },
1759 { WM_ENTERIDLE, sent|parent|optional },
1760 { WM_ENTERIDLE, sent|parent|optional },
1761 { WM_ENTERIDLE, sent|parent|optional },
1762 { WM_ENTERIDLE, sent|parent|optional },
1763 { WM_TIMER, sent },
1764 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1765 { WM_ENABLE, sent|parent|wparam, 1 },
1766 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1767 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1768 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1769 { WM_GETTEXT, sent|optional },
1770 { HCBT_ACTIVATE, hook },
1771 { WM_NCACTIVATE, sent|wparam, 0 },
1772 { WM_GETTEXT, sent|optional },
1773 { WM_ACTIVATE, sent|wparam, 0 },
1774 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1775 { WM_WINDOWPOSCHANGING, sent|optional },
1776 { WM_WINDOWPOSCHANGED, sent|optional },
1777 { HCBT_SETFOCUS, hook },
1778 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1779 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1780 { WM_SETFOCUS, sent|parent|defwinproc },
1781 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
1782 { HCBT_DESTROYWND, hook },
1783 { 0x0090, sent|optional },
1784 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1785 { WM_DESTROY, sent },
1786 { WM_NCDESTROY, sent },
1787 { 0 }
1789 static const struct message WmModalDialogSeq_2[] = {
1790 { WM_CANCELMODE, sent },
1791 { HCBT_SETFOCUS, hook },
1792 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1793 { WM_KILLFOCUS, sent },
1794 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1795 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1796 { WM_ENABLE, sent|wparam, 0 },
1797 { HCBT_CREATEWND, hook },
1798 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1799 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1800 { WM_SETFONT, sent },
1801 { WM_INITDIALOG, sent },
1802 { WM_CHANGEUISTATE, sent|optional },
1803 { WM_UPDATEUISTATE, sent|optional },
1804 { WM_ENABLE, sent|wparam, 1 },
1805 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1806 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1807 { WM_CHANGEUISTATE, sent|optional },
1808 { WM_UPDATEUISTATE, sent|optional },
1809 { HCBT_DESTROYWND, hook },
1810 { 0x0090, sent|optional },
1811 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1812 { WM_DESTROY, sent },
1813 { WM_NCDESTROY, sent },
1814 { 0 }
1816 /* SetMenu for NonVisible windows with size change*/
1817 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1818 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1819 { WM_NCCALCSIZE, sent|wparam, 1 },
1820 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1821 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1822 { WM_MOVE, sent|defwinproc },
1823 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1824 { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1825 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1826 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1827 { WM_GETTEXT, sent|optional },
1828 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1829 { 0 }
1831 /* SetMenu for NonVisible windows with no size change */
1832 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1833 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1834 { WM_NCCALCSIZE, sent|wparam, 1 },
1835 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1836 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1837 { 0 }
1839 /* SetMenu for Visible windows with size change */
1840 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1841 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1842 { WM_NCCALCSIZE, sent|wparam, 1 },
1843 { 0x0093, sent|defwinproc|optional },
1844 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1845 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1846 { 0x0093, sent|defwinproc|optional },
1847 { 0x0093, sent|defwinproc|optional },
1848 { 0x0091, sent|defwinproc|optional },
1849 { 0x0092, sent|defwinproc|optional },
1850 { WM_GETTEXT, sent|defwinproc|optional },
1851 { WM_ERASEBKGND, sent|optional },
1852 { WM_ACTIVATE, sent|optional },
1853 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1854 { WM_MOVE, sent|defwinproc },
1855 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1856 { 0x0093, sent|optional },
1857 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1858 { 0x0093, sent|defwinproc|optional },
1859 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1860 { 0x0093, sent|defwinproc|optional },
1861 { 0x0093, sent|defwinproc|optional },
1862 { 0x0091, sent|defwinproc|optional },
1863 { 0x0092, sent|defwinproc|optional },
1864 { WM_ERASEBKGND, sent|optional },
1865 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1866 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1867 { 0 }
1869 /* SetMenu for Visible windows with no size change */
1870 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1871 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1872 { WM_NCCALCSIZE, sent|wparam, 1 },
1873 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1874 { WM_GETTEXT, sent|defwinproc|optional },
1875 { WM_ERASEBKGND, sent|optional },
1876 { WM_ACTIVATE, sent|optional },
1877 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1878 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1879 { 0 }
1881 /* DrawMenuBar for a visible window */
1882 static const struct message WmDrawMenuBarSeq[] =
1884 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1885 { WM_NCCALCSIZE, sent|wparam, 1 },
1886 { 0x0093, sent|defwinproc|optional },
1887 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1888 { 0x0093, sent|defwinproc|optional },
1889 { 0x0093, sent|defwinproc|optional },
1890 { 0x0091, sent|defwinproc|optional },
1891 { 0x0092, sent|defwinproc|optional },
1892 { WM_GETTEXT, sent|defwinproc|optional },
1893 { WM_ERASEBKGND, sent|optional },
1894 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1895 { 0x0093, sent|optional },
1896 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1897 { 0 }
1900 static const struct message WmSetRedrawFalseSeq[] =
1902 { WM_SETREDRAW, sent|wparam, 0 },
1903 { 0 }
1906 static const struct message WmSetRedrawTrueSeq[] =
1908 { WM_SETREDRAW, sent|wparam, 1 },
1909 { 0 }
1912 static const struct message WmEnableWindowSeq_1[] =
1914 { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1915 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1916 { HCBT_SETFOCUS, hook|optional },
1917 { WM_KILLFOCUS, sent|optional },
1918 { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1919 { 0 }
1922 static const struct message WmEnableWindowSeq_2[] =
1924 { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1925 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1926 { 0 }
1929 static const struct message WmEnableWindowSeq_3[] =
1931 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1932 { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
1933 { 0 }
1936 static const struct message WmEnableWindowSeq_4[] =
1938 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1939 { 0 }
1942 static const struct message WmGetScrollRangeSeq[] =
1944 { SBM_GETRANGE, sent },
1945 { 0 }
1947 static const struct message WmGetScrollInfoSeq[] =
1949 { SBM_GETSCROLLINFO, sent },
1950 { 0 }
1952 static const struct message WmSetScrollRangeSeq[] =
1954 /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
1955 sends SBM_SETSCROLLINFO.
1957 { SBM_SETSCROLLINFO, sent },
1958 { 0 }
1960 /* SetScrollRange for a window without a non-client area */
1961 static const struct message WmSetScrollRangeHSeq_empty[] =
1963 { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
1964 { 0 }
1966 static const struct message WmSetScrollRangeVSeq_empty[] =
1968 { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
1969 { 0 }
1971 static const struct message WmSetScrollRangeHVSeq[] =
1973 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1974 { WM_NCCALCSIZE, sent|wparam, 1 },
1975 { WM_GETTEXT, sent|defwinproc|optional },
1976 { WM_ERASEBKGND, sent|optional },
1977 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1978 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1979 { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1980 { 0 }
1982 /* SetScrollRange for a window with a non-client area */
1983 static const struct message WmSetScrollRangeHV_NC_Seq[] =
1985 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1986 { WM_NCCALCSIZE, sent|wparam, 1 },
1987 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1988 { WM_NCPAINT, sent|optional },
1989 { WM_STYLECHANGING, sent|defwinproc|optional },
1990 { WM_STYLECHANGED, sent|defwinproc|optional },
1991 { WM_STYLECHANGING, sent|defwinproc|optional },
1992 { WM_STYLECHANGED, sent|defwinproc|optional },
1993 { WM_STYLECHANGING, sent|defwinproc|optional },
1994 { WM_STYLECHANGED, sent|defwinproc|optional },
1995 { WM_STYLECHANGING, sent|defwinproc|optional },
1996 { WM_STYLECHANGED, sent|defwinproc|optional },
1997 { WM_GETTEXT, sent|defwinproc|optional },
1998 { WM_GETTEXT, sent|defwinproc|optional },
1999 { WM_ERASEBKGND, sent|optional },
2000 { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
2001 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOCLIENTSIZE },
2002 { WM_SIZE, sent|defwinproc|optional },
2003 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2004 { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
2005 { WM_GETTEXT, sent|optional },
2006 { WM_GETTEXT, sent|optional },
2007 { WM_GETTEXT, sent|optional },
2008 { WM_GETTEXT, sent|optional },
2009 { 0 }
2011 /* test if we receive the right sequence of messages */
2012 /* after calling ShowWindow( SW_SHOWNA) */
2013 static const struct message WmSHOWNAChildInvisParInvis[] = {
2014 { WM_SHOWWINDOW, sent|wparam, 1 },
2015 { 0 }
2017 static const struct message WmSHOWNAChildVisParInvis[] = {
2018 { WM_SHOWWINDOW, sent|wparam, 1 },
2019 { 0 }
2021 static const struct message WmSHOWNAChildVisParVis[] = {
2022 { WM_SHOWWINDOW, sent|wparam, 1 },
2023 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
2024 { 0 }
2026 static const struct message WmSHOWNAChildInvisParVis[] = {
2027 { WM_SHOWWINDOW, sent|wparam, 1 },
2028 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2029 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2030 { WM_ERASEBKGND, sent|optional },
2031 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
2032 { 0 }
2034 static const struct message WmSHOWNATopVisible[] = {
2035 { WM_SHOWWINDOW, sent|wparam, 1 },
2036 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
2037 { WM_NCPAINT, sent|wparam|optional, 1 },
2038 { WM_GETTEXT, sent|defwinproc|optional },
2039 { WM_ERASEBKGND, sent|optional },
2040 { WM_WINDOWPOSCHANGED, sent|optional },
2041 { 0 }
2043 static const struct message WmSHOWNATopInvisible[] = {
2044 { WM_NOTIFYFORMAT, sent|optional },
2045 { WM_QUERYUISTATE, sent|optional },
2046 { WM_WINDOWPOSCHANGING, sent|optional },
2047 { WM_GETMINMAXINFO, sent|optional },
2048 { WM_NCCALCSIZE, sent|optional },
2049 { WM_WINDOWPOSCHANGED, sent|optional },
2050 { WM_SHOWWINDOW, sent|wparam, 1 },
2051 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2052 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2053 { WM_NCPAINT, sent|wparam|optional, 1 },
2054 { WM_GETTEXT, sent|defwinproc|optional },
2055 { WM_ERASEBKGND, sent|optional },
2056 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2057 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2058 { WM_NCPAINT, sent|wparam|optional, 1 },
2059 { WM_ERASEBKGND, sent|optional },
2060 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2061 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2062 { WM_MOVE, sent },
2063 { 0 }
2066 static const struct message WmTrackPopupMenuMinimizeWindow[] = {
2067 { HCBT_CREATEWND, hook },
2068 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
2069 { WM_INITMENU, sent|lparam, 0, 0 },
2070 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
2071 { 0x0093, sent|optional },
2072 { 0x0094, sent|optional },
2073 { 0x0094, sent|optional },
2074 { WM_ENTERIDLE, sent|wparam, 2 },
2075 { HCBT_MINMAX, hook },
2076 { HCBT_SETFOCUS, hook },
2077 { WM_KILLFOCUS, sent|wparam, 0 },
2078 { WM_GETTEXT, sent|optional },
2079 { WM_WINDOWPOSCHANGING, sent },
2080 { WM_GETMINMAXINFO, sent|defwinproc },
2081 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2082 { WM_WINDOWPOSCHANGED, sent },
2083 { WM_MOVE, sent|defwinproc },
2084 { WM_SIZE, sent|defwinproc },
2085 { WM_GETTEXT, sent|optional },
2086 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2087 { WM_CANCELMODE, sent },
2088 { WM_CAPTURECHANGED, sent|defwinproc },
2089 { HCBT_DESTROYWND, hook },
2090 { WM_UNINITMENUPOPUP, sent|defwinproc|lparam, 0, 0 },
2091 { WM_MENUSELECT, sent|defwinproc|wparam|lparam, 0xffff0000, 0 },
2092 { WM_EXITMENULOOP, sent|defwinproc|wparam|lparam, 1, 0 },
2093 { WM_NCACTIVATE, sent },
2094 { WM_GETTEXT, sent|defwinproc|optional },
2095 { WM_GETTEXT, sent|defwinproc|optional },
2096 { WM_ACTIVATE, sent },
2097 { WM_ACTIVATEAPP, sent|wparam, 0 },
2098 { 0 }
2101 static const struct message WmTrackPopupMenu[] = {
2102 { HCBT_CREATEWND, hook },
2103 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
2104 { WM_INITMENU, sent|lparam, 0, 0 },
2105 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
2106 { 0x0093, sent|optional },
2107 { 0x0094, sent|optional },
2108 { 0x0094, sent|optional },
2109 { WM_ENTERIDLE, sent|wparam, 2 },
2110 { WM_CAPTURECHANGED, sent },
2111 { HCBT_DESTROYWND, hook },
2112 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
2113 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
2114 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
2115 { 0 }
2118 static const struct message WmTrackPopupMenuEsc[] = {
2119 { 0 }
2122 static const struct message WmTrackPopupMenuCapture[] = {
2123 { HCBT_CREATEWND, hook },
2124 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
2125 { WM_CAPTURECHANGED, sent },
2126 { WM_INITMENU, sent|lparam, 0, 0 },
2127 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
2128 { 0x0093, sent|optional },
2129 { 0x0094, sent|optional },
2130 { 0x0094, sent|optional },
2131 { WM_ENTERIDLE, sent|wparam, 2 },
2132 { WM_CAPTURECHANGED, sent },
2133 { HCBT_DESTROYWND, hook },
2134 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
2135 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
2136 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
2137 { 0 }
2140 static const struct message WmTrackPopupMenuEmpty[] = {
2141 { HCBT_CREATEWND, hook },
2142 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
2143 { WM_INITMENU, sent|lparam, 0, 0 },
2144 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
2145 { 0x0093, sent|optional },
2146 { 0x0094, sent|optional },
2147 { 0x0094, sent|optional },
2148 { WM_CAPTURECHANGED, sent },
2149 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
2150 { HCBT_DESTROYWND, hook },
2151 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
2152 { 0 }
2155 static const struct message WmTrackPopupMenuAbort[] = {
2156 { HCBT_CREATEWND, hook },
2157 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
2158 { WM_INITMENU, sent|lparam, 0, 0 },
2159 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
2160 { 0x0093, sent|optional },
2161 { 0x0094, sent|optional },
2162 { 0x0094, sent|optional },
2163 { WM_CAPTURECHANGED, sent },
2164 { HCBT_DESTROYWND, hook },
2165 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
2166 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
2167 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
2168 { 0 }
2171 static BOOL after_end_dialog, test_def_id, paint_loop_done;
2172 static int sequence_cnt, sequence_size;
2173 static struct recvd_message* sequence;
2174 static int log_all_parent_messages;
2175 static CRITICAL_SECTION sequence_cs;
2177 /* user32 functions */
2178 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
2179 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
2180 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
2181 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
2182 static BOOL (WINAPI *pUpdateLayeredWindow)(HWND,HDC,POINT*,SIZE*,HDC,POINT*,COLORREF,BLENDFUNCTION*,DWORD);
2183 static UINT_PTR (WINAPI *pSetSystemTimer)(HWND, UINT_PTR, UINT, TIMERPROC);
2184 static UINT_PTR (WINAPI *pKillSystemTimer)(HWND, UINT_PTR);
2185 static UINT_PTR (WINAPI *pSetCoalescableTimer)(HWND, UINT_PTR, UINT, TIMERPROC, ULONG);
2186 /* kernel32 functions */
2187 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
2189 static void init_procs(void)
2191 HMODULE user32 = GetModuleHandleA("user32.dll");
2192 HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
2194 #define GET_PROC(dll, func) \
2195 p ## func = (void*)GetProcAddress(dll, #func); \
2196 if(!p ## func) { \
2197 trace("GetProcAddress(%s) failed\n", #func); \
2200 GET_PROC(user32, NotifyWinEvent)
2201 GET_PROC(user32, SetWinEventHook)
2202 GET_PROC(user32, TrackMouseEvent)
2203 GET_PROC(user32, UnhookWinEvent)
2204 GET_PROC(user32, UpdateLayeredWindow)
2205 GET_PROC(user32, SetSystemTimer)
2206 GET_PROC(user32, KillSystemTimer)
2207 GET_PROC(user32, SetCoalescableTimer)
2209 GET_PROC(kernel32, GetCPInfoExA)
2211 #undef GET_PROC
2214 static const char *get_winpos_flags(UINT flags)
2216 static char buffer[300];
2218 buffer[0] = 0;
2219 #define DUMP(flag) do { if (flags & flag) { strcat( buffer, "|" #flag ); flags &= ~flag; } } while(0)
2220 DUMP( SWP_SHOWWINDOW );
2221 DUMP( SWP_HIDEWINDOW );
2222 DUMP( SWP_NOACTIVATE );
2223 DUMP( SWP_FRAMECHANGED );
2224 DUMP( SWP_NOCOPYBITS );
2225 DUMP( SWP_NOOWNERZORDER );
2226 DUMP( SWP_NOSENDCHANGING );
2227 DUMP( SWP_DEFERERASE );
2228 DUMP( SWP_ASYNCWINDOWPOS );
2229 DUMP( SWP_NOZORDER );
2230 DUMP( SWP_NOREDRAW );
2231 DUMP( SWP_NOSIZE );
2232 DUMP( SWP_NOMOVE );
2233 DUMP( SWP_NOCLIENTSIZE );
2234 DUMP( SWP_NOCLIENTMOVE );
2235 if (flags) sprintf(buffer + strlen(buffer),"|0x%04x", flags);
2236 return buffer + 1;
2237 #undef DUMP
2240 static BOOL ignore_message( UINT message )
2242 /* these are always ignored */
2243 return (message >= 0xc000 ||
2244 message == WM_GETICON ||
2245 message == WM_GETOBJECT ||
2246 message == WM_TIMECHANGE ||
2247 message == WM_DISPLAYCHANGE ||
2248 message == WM_DEVICECHANGE ||
2249 message == WM_DWMNCRENDERINGCHANGED ||
2250 message == WM_WININICHANGE);
2253 static unsigned hash_Ly_W(const WCHAR *str)
2255 unsigned hash = 0;
2257 for (; *str; str++)
2258 hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u;
2260 return hash;
2263 static unsigned hash_Ly(const char *str)
2265 unsigned hash = 0;
2267 for (; *str; str++)
2268 hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u;
2270 return hash;
2273 #define add_message(msg) add_message_(__LINE__,msg);
2274 static void add_message_(int line, const struct recvd_message *msg)
2276 struct recvd_message *seq;
2278 EnterCriticalSection( &sequence_cs );
2279 if (!sequence)
2281 sequence_size = 10;
2282 sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof(*sequence) );
2284 if (sequence_cnt == sequence_size)
2286 sequence_size *= 2;
2287 sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof(*sequence) );
2289 assert(sequence);
2291 seq = &sequence[sequence_cnt++];
2292 seq->hwnd = msg->hwnd;
2293 seq->message = msg->message;
2294 seq->flags = msg->flags;
2295 seq->wParam = msg->wParam;
2296 seq->lParam = msg->lParam;
2297 seq->line = line;
2298 seq->descr = msg->descr;
2299 seq->output[0] = 0;
2300 LeaveCriticalSection( &sequence_cs );
2302 if (msg->descr)
2304 if (msg->flags & hook)
2306 static const char * const CBT_code_name[10] =
2308 "HCBT_MOVESIZE",
2309 "HCBT_MINMAX",
2310 "HCBT_QS",
2311 "HCBT_CREATEWND",
2312 "HCBT_DESTROYWND",
2313 "HCBT_ACTIVATE",
2314 "HCBT_CLICKSKIPPED",
2315 "HCBT_KEYSKIPPED",
2316 "HCBT_SYSCOMMAND",
2317 "HCBT_SETFOCUS"
2319 const char *code_name = (msg->message <= HCBT_SETFOCUS) ? CBT_code_name[msg->message] : "Unknown";
2321 sprintf( seq->output, "%s: hook %d (%s) wp %08lx lp %08lx",
2322 msg->descr, msg->message, code_name, msg->wParam, msg->lParam );
2324 else if (msg->flags & winevent_hook)
2326 sprintf( seq->output, "%s: winevent %p %08x %08lx %08lx",
2327 msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
2329 else
2331 switch (msg->message)
2333 case WM_WINDOWPOSCHANGING:
2334 case WM_WINDOWPOSCHANGED:
2336 WINDOWPOS *winpos = (WINDOWPOS *)msg->lParam;
2338 sprintf( seq->output, "%s: %p WM_WINDOWPOS%s wp %08lx lp %08lx after %p x %d y %d cx %d cy %d flags %s",
2339 msg->descr, msg->hwnd,
2340 (msg->message == WM_WINDOWPOSCHANGING) ? "CHANGING" : "CHANGED",
2341 msg->wParam, msg->lParam, winpos->hwndInsertAfter,
2342 winpos->x, winpos->y, winpos->cx, winpos->cy,
2343 get_winpos_flags(winpos->flags) );
2345 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2346 * in the high word for internal purposes
2348 seq->wParam = winpos->flags & 0xffff;
2349 /* We are not interested in the flags that don't match under XP and Win9x */
2350 seq->wParam &= ~SWP_NOZORDER;
2351 seq->lParam = (!!winpos->cx) | ((!!winpos->cy) << 1)
2352 | ((!!winpos->x) << 2) | ((!!winpos->y) << 3);
2353 break;
2356 case WM_NCCALCSIZE:
2357 if (msg->wParam)
2359 NCCALCSIZE_PARAMS *p = (NCCALCSIZE_PARAMS *)msg->lParam;
2360 WINDOWPOS *winpos = p->lppos;
2362 sprintf(seq->output, "%s: %p WM_NCCALCSIZE: winpos->cx %u, winpos->cy %u",
2363 msg->descr, msg->hwnd, winpos->cx, winpos->cy);
2364 seq->lParam = (!!winpos->cx) | ((!!winpos->cy) << 1)
2365 | ((!!winpos->x) << 2) | ((!!winpos->y) << 3);
2367 else
2369 seq->lParam = 0;
2371 break;
2372 case WM_DRAWITEM:
2374 DRAW_ITEM_STRUCT di;
2375 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)msg->lParam;
2377 sprintf( seq->output, "%s: %p WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x",
2378 msg->descr, msg->hwnd, dis->CtlType, dis->CtlID,
2379 dis->itemID, dis->itemAction, dis->itemState);
2381 di.u.lp = 0;
2382 di.u.item.type = dis->CtlType;
2383 di.u.item.ctl_id = dis->CtlID;
2384 if (dis->CtlType == ODT_LISTBOX ||
2385 dis->CtlType == ODT_COMBOBOX ||
2386 dis->CtlType == ODT_MENU)
2387 di.u.item.item_id = dis->itemID;
2388 di.u.item.action = dis->itemAction;
2389 di.u.item.state = dis->itemState;
2391 seq->lParam = di.u.lp;
2392 break;
2395 case WM_MEASUREITEM:
2397 MEASURE_ITEM_STRUCT mi;
2398 MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)msg->lParam;
2399 BOOL is_unicode_data = TRUE;
2401 sprintf( seq->output, "%s: %p WM_MEASUREITEM: CtlType %#x, CtlID %#x, itemID %#x, itemData %#lx",
2402 msg->descr, msg->hwnd, mis->CtlType, mis->CtlID,
2403 mis->itemID, mis->itemData);
2405 if (mis->CtlType == ODT_LISTBOX)
2407 HWND ctrl = GetDlgItem(msg->hwnd, mis->CtlID);
2408 is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
2411 mi.u.wp = 0;
2412 mi.u.item.CtlType = mis->CtlType;
2413 mi.u.item.CtlID = mis->CtlID;
2414 mi.u.item.itemID = mis->itemID;
2415 mi.u.item.wParam = msg->wParam;
2416 seq->wParam = mi.u.wp;
2417 if (is_unicode_data)
2418 seq->lParam = mis->itemData ? hash_Ly_W((const WCHAR *)mis->itemData) : 0;
2419 else
2420 seq->lParam = mis->itemData ? hash_Ly((const char *)mis->itemData) : 0;
2421 break;
2424 case WM_COMPAREITEM:
2426 COMPAREITEMSTRUCT *cis = (COMPAREITEMSTRUCT *)msg->lParam;
2427 HWND ctrl = GetDlgItem(msg->hwnd, cis->CtlID);
2428 BOOL is_unicode_data = TRUE;
2430 ok(msg->wParam == cis->CtlID, "expected %#x, got %#lx\n", cis->CtlID, msg->wParam);
2431 ok(cis->hwndItem == ctrl, "expected %p, got %p\n", ctrl, cis->hwndItem);
2432 ok((int)cis->itemID1 >= 0, "expected >= 0, got %d\n", cis->itemID1);
2433 ok((int)cis->itemID2 == -1, "expected -1, got %d\n", cis->itemID2);
2435 sprintf( seq->output, "%s: %p WM_COMPAREITEM: CtlType %#x, CtlID %#x, itemID1 %#x, itemData1 %#lx, itemID2 %#x, itemData2 %#lx",
2436 msg->descr, msg->hwnd, cis->CtlType, cis->CtlID,
2437 cis->itemID1, cis->itemData1, cis->itemID2, cis->itemData2);
2439 if (cis->CtlType == ODT_LISTBOX)
2440 is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
2442 if (is_unicode_data)
2444 seq->wParam = cis->itemData1 ? hash_Ly_W((const WCHAR *)cis->itemData1) : 0;
2445 seq->lParam = cis->itemData2 ? hash_Ly_W((const WCHAR *)cis->itemData2) : 0;
2447 else
2449 seq->wParam = cis->itemData1 ? hash_Ly((const char *)cis->itemData1) : 0;
2450 seq->lParam = cis->itemData2 ? hash_Ly((const char *)cis->itemData2) : 0;
2452 break;
2455 default:
2456 if (msg->message >= 0xc000) return; /* ignore registered messages */
2457 sprintf( seq->output, "%s: %p %04x wp %08lx lp %08lx",
2458 msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
2460 if (msg->flags & (sent|posted|parent|defwinproc|beginpaint))
2461 sprintf( seq->output + strlen(seq->output), " (flags %x)", msg->flags );
2466 /* try to make sure pending X events have been processed before continuing */
2467 static void flush_events(void)
2469 MSG msg;
2470 int diff = 200;
2471 int min_timeout = 100;
2472 DWORD time = GetTickCount() + diff;
2474 while (diff > 0)
2476 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
2477 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
2478 diff = time - GetTickCount();
2482 static void flush_sequence(void)
2484 EnterCriticalSection( &sequence_cs );
2485 HeapFree(GetProcessHeap(), 0, sequence);
2486 sequence = 0;
2487 sequence_cnt = sequence_size = 0;
2488 LeaveCriticalSection( &sequence_cs );
2491 static void dump_sequence(const struct message *expected, const char *context, const char *file, int line)
2493 const struct recvd_message *actual = sequence;
2494 unsigned int count = 0;
2496 trace_(file, line)("Failed sequence %s:\n", context );
2497 while (expected->message && actual->message)
2499 if (actual->output[0])
2501 if (expected->flags & hook)
2503 trace_(file, line)( " %u: expected: hook %04x - actual: %s\n",
2504 count, expected->message, actual->output );
2506 else if (expected->flags & winevent_hook)
2508 trace_(file, line)( " %u: expected: winevent %04x - actual: %s\n",
2509 count, expected->message, actual->output );
2511 else if (expected->flags & kbd_hook)
2513 trace_(file, line)( " %u: expected: kbd %04x - actual: %s\n",
2514 count, expected->message, actual->output );
2516 else
2518 trace_(file, line)( " %u: expected: msg %04x - actual: %s\n",
2519 count, expected->message, actual->output );
2523 if (expected->message == actual->message)
2525 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) &&
2526 (expected->flags & optional))
2528 /* don't match messages if their defwinproc status differs */
2529 expected++;
2531 else
2533 expected++;
2534 actual++;
2537 /* silently drop winevent messages if there is no support for them */
2538 else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
2539 expected++;
2540 else
2542 expected++;
2543 actual++;
2545 count++;
2548 /* optional trailing messages */
2549 while (expected->message && ((expected->flags & optional) ||
2550 ((expected->flags & winevent_hook) && !hEvent_hook)))
2552 trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2553 expected++;
2554 count++;
2557 if (expected->message)
2559 trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2560 return;
2563 while (actual->message && actual->output[0])
2565 trace_(file, line)( " %u: expected: nothing - actual: %s\n", count, actual->output );
2566 actual++;
2567 count++;
2571 #define ok_sequence( exp, contx, todo) \
2572 ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
2575 static void ok_sequence_(const struct message *expected_list, const char *context, BOOL todo,
2576 const char *file, int line)
2578 static const struct recvd_message end_of_sequence;
2579 const struct message *expected = expected_list;
2580 const struct recvd_message *actual;
2581 int failcount = 0, dump = 0;
2582 unsigned int count = 0;
2584 add_message(&end_of_sequence);
2586 actual = sequence;
2588 while (expected->message && actual->message)
2590 if (expected->message == actual->message &&
2591 !((expected->flags ^ actual->flags) & (hook|winevent_hook|kbd_hook)))
2593 if (expected->flags & wparam)
2595 if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && todo)
2597 todo_wine {
2598 failcount ++;
2599 if (strcmp(winetest_platform, "wine")) dump++;
2600 ok_( file, line) (FALSE,
2601 "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2602 context, count, expected->message, expected->wParam, actual->wParam);
2605 else
2607 ok_( file, line)( ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) == 0,
2608 "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2609 context, count, expected->message, expected->wParam, actual->wParam);
2610 if ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) dump++;
2614 if (expected->flags & lparam)
2616 if (((expected->lParam ^ actual->lParam) & ~expected->lp_mask) && todo)
2618 todo_wine {
2619 failcount ++;
2620 if (strcmp(winetest_platform, "wine")) dump++;
2621 ok_( file, line) (FALSE,
2622 "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2623 context, count, expected->message, expected->lParam, actual->lParam);
2626 else
2628 ok_( file, line)(((expected->lParam ^ actual->lParam) & ~expected->lp_mask) == 0,
2629 "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2630 context, count, expected->message, expected->lParam, actual->lParam);
2631 if ((expected->lParam ^ actual->lParam) & ~expected->lp_mask) dump++;
2634 if ((expected->flags & optional) &&
2635 ((expected->flags ^ actual->flags) & (defwinproc|parent)))
2637 /* don't match optional messages if their defwinproc or parent status differs */
2638 expected++;
2639 count++;
2640 continue;
2642 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
2644 todo_wine {
2645 failcount ++;
2646 if (strcmp(winetest_platform, "wine")) dump++;
2647 ok_( file, line) (FALSE,
2648 "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2649 context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2652 else
2654 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
2655 "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2656 context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2657 if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++;
2660 ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
2661 "%s: %u: the msg 0x%04x should %shave been sent by BeginPaint\n",
2662 context, count, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
2663 if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++;
2665 ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
2666 "%s: %u: the msg 0x%04x should have been %s\n",
2667 context, count, expected->message, (expected->flags & posted) ? "posted" : "sent");
2668 if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++;
2670 ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
2671 "%s: %u: the msg 0x%04x was expected in %s\n",
2672 context, count, expected->message, (expected->flags & parent) ? "parent" : "child");
2673 if ((expected->flags & parent) != (actual->flags & parent)) dump++;
2675 ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
2676 "%s: %u: the msg 0x%04x should have been sent by a hook\n",
2677 context, count, expected->message);
2678 if ((expected->flags & hook) != (actual->flags & hook)) dump++;
2680 ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
2681 "%s: %u: the msg 0x%04x should have been sent by a winevent hook\n",
2682 context, count, expected->message);
2683 if ((expected->flags & winevent_hook) != (actual->flags & winevent_hook)) dump++;
2685 ok_( file, line) ((expected->flags & kbd_hook) == (actual->flags & kbd_hook),
2686 "%s: %u: the msg 0x%04x should have been sent by a keyboard hook\n",
2687 context, count, expected->message);
2688 if ((expected->flags & kbd_hook) != (actual->flags & kbd_hook)) dump++;
2690 expected++;
2691 actual++;
2693 /* silently drop hook messages if there is no support for them */
2694 else if ((expected->flags & optional) ||
2695 ((expected->flags & hook) && !hCBT_hook) ||
2696 ((expected->flags & winevent_hook) && !hEvent_hook) ||
2697 ((expected->flags & kbd_hook) && !hKBD_hook))
2698 expected++;
2699 else if (todo)
2701 failcount++;
2702 todo_wine {
2703 if (strcmp(winetest_platform, "wine")) dump++;
2704 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2705 context, count, expected->message, actual->message);
2707 goto done;
2709 else
2711 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2712 context, count, expected->message, actual->message);
2713 dump++;
2714 expected++;
2715 actual++;
2717 count++;
2720 /* skip all optional trailing messages */
2721 while (expected->message && ((expected->flags & optional) ||
2722 ((expected->flags & hook) && !hCBT_hook) ||
2723 ((expected->flags & winevent_hook) && !hEvent_hook)))
2724 expected++;
2726 if (todo)
2728 todo_wine {
2729 if (expected->message || actual->message) {
2730 failcount++;
2731 if (strcmp(winetest_platform, "wine")) dump++;
2732 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2733 context, count, expected->message, actual->message);
2737 else
2739 if (expected->message || actual->message)
2741 dump++;
2742 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2743 context, count, expected->message, actual->message);
2746 if( todo && !failcount) /* succeeded yet marked todo */
2747 todo_wine {
2748 if (!strcmp(winetest_platform, "wine")) dump++;
2749 ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
2752 done:
2753 if (dump) dump_sequence(expected_list, context, file, line);
2754 flush_sequence();
2757 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
2759 /******************************** MDI test **********************************/
2761 /* CreateWindow for MDI frame window, initially visible */
2762 static const struct message WmCreateMDIframeSeq[] = {
2763 { HCBT_CREATEWND, hook },
2764 { WM_GETMINMAXINFO, sent },
2765 { WM_NCCREATE, sent },
2766 { WM_NCCALCSIZE, sent|wparam, 0 },
2767 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2768 { WM_CREATE, sent },
2769 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2770 { WM_NOTIFYFORMAT, sent|optional },
2771 { WM_QUERYUISTATE, sent|optional },
2772 { WM_WINDOWPOSCHANGING, sent|optional },
2773 { WM_GETMINMAXINFO, sent|optional },
2774 { WM_NCCALCSIZE, sent|optional },
2775 { WM_WINDOWPOSCHANGED, sent|optional },
2776 { WM_SHOWWINDOW, sent|wparam, 1 },
2777 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2778 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2779 { HCBT_ACTIVATE, hook },
2780 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
2781 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
2782 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
2783 { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
2784 { WM_NCACTIVATE, sent },
2785 { WM_GETTEXT, sent|defwinproc|optional },
2786 { WM_ACTIVATE, sent|wparam, 1 },
2787 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
2788 { HCBT_SETFOCUS, hook },
2789 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2790 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2791 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2792 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
2793 /* Win9x adds SWP_NOZORDER below */
2794 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2795 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2796 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2797 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2798 { WM_MOVE, sent },
2799 { 0 }
2801 /* DestroyWindow for MDI frame window, initially visible */
2802 static const struct message WmDestroyMDIframeSeq[] = {
2803 { HCBT_DESTROYWND, hook },
2804 { 0x0090, sent|optional },
2805 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2806 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2807 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2808 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2809 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
2810 { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2811 { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
2812 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
2813 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2814 { WM_DESTROY, sent },
2815 { WM_NCDESTROY, sent },
2816 { 0 }
2818 /* CreateWindow for MDI client window, initially visible */
2819 static const struct message WmCreateMDIclientSeq[] = {
2820 { HCBT_CREATEWND, hook },
2821 { WM_NCCREATE, sent },
2822 { WM_NCCALCSIZE, sent|wparam, 0 },
2823 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2824 { WM_CREATE, sent },
2825 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2826 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2827 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2828 { WM_MOVE, sent },
2829 { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
2830 { WM_SHOWWINDOW, sent|wparam, 1 },
2831 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2832 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2833 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2834 { 0 }
2836 /* ShowWindow(SW_SHOW) for MDI client window */
2837 static const struct message WmShowMDIclientSeq[] = {
2838 { WM_SHOWWINDOW, sent|wparam, 1 },
2839 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2840 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2841 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2842 { 0 }
2844 /* ShowWindow(SW_HIDE) for MDI client window */
2845 static const struct message WmHideMDIclientSeq[] = {
2846 { WM_SHOWWINDOW, sent|wparam, 0 },
2847 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2848 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
2849 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
2850 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2851 { 0 }
2853 /* DestroyWindow for MDI client window, initially visible */
2854 static const struct message WmDestroyMDIclientSeq[] = {
2855 { HCBT_DESTROYWND, hook },
2856 { 0x0090, sent|optional },
2857 { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
2858 { WM_SHOWWINDOW, sent|wparam, 0 },
2859 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2860 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2861 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2862 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2863 { WM_DESTROY, sent },
2864 { WM_NCDESTROY, sent },
2865 { 0 }
2867 /* CreateWindow for MDI child window, initially visible */
2868 static const struct message WmCreateMDIchildVisibleSeq[] = {
2869 { HCBT_CREATEWND, hook },
2870 { WM_NCCREATE, sent },
2871 { WM_NCCALCSIZE, sent|wparam, 0 },
2872 { WM_CREATE, sent },
2873 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2874 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2875 { WM_MOVE, sent },
2876 /* Win2k sends wparam set to
2877 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2878 * while Win9x doesn't bother to set child window id according to
2879 * CLIENTCREATESTRUCT.idFirstChild
2881 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2882 { WM_SHOWWINDOW, sent|wparam, 1 },
2883 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2884 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2885 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2886 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2887 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2888 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2889 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2891 /* Win9x: message sequence terminates here. */
2893 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2894 { HCBT_SETFOCUS, hook }, /* in MDI client */
2895 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2896 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2897 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2898 { WM_SETFOCUS, sent }, /* in MDI client */
2899 { HCBT_SETFOCUS, hook },
2900 { WM_KILLFOCUS, sent }, /* in MDI client */
2901 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2902 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2903 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2904 { WM_SETFOCUS, sent|defwinproc },
2905 { WM_MDIACTIVATE, sent|defwinproc },
2906 { 0 }
2908 /* WM_CHILDACTIVATE sent to disabled window */
2909 static const struct message WmChildActivateDisabledWindowSeq[] = {
2910 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2911 { 0 }
2913 /* WM_CHILDACTIVATE sent to enabled window */
2914 static const struct message WmChildActivateWindowSeq[] = {
2915 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2916 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 },
2917 { WM_MDIACTIVATE, sent|defwinproc },
2918 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2919 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2920 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2921 { HCBT_SETFOCUS, hook },
2922 { WM_KILLFOCUS, sent|defwinproc },
2923 { WM_SETFOCUS, sent },
2924 { HCBT_SETFOCUS, hook },
2925 { WM_KILLFOCUS, sent },
2926 { WM_SETFOCUS, sent|defwinproc },
2927 { WM_MDIACTIVATE, sent|defwinproc },
2928 { 0 }
2930 /* CreateWindow for MDI child window with invisible parent */
2931 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
2932 { HCBT_CREATEWND, hook },
2933 { WM_GETMINMAXINFO, sent },
2934 { WM_NCCREATE, sent },
2935 { WM_NCCALCSIZE, sent|wparam, 0 },
2936 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2937 { WM_CREATE, sent },
2938 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2939 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2940 { WM_MOVE, sent },
2941 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2942 { WM_SHOWWINDOW, sent|wparam, 1 },
2943 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2944 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2945 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2946 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2948 /* Win9x: message sequence terminates here. */
2950 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2951 { HCBT_SETFOCUS, hook }, /* in MDI client */
2952 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2953 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2954 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2955 { WM_SETFOCUS, sent }, /* in MDI client */
2956 { HCBT_SETFOCUS, hook },
2957 { WM_KILLFOCUS, sent }, /* in MDI client */
2958 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2959 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2960 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2961 { WM_SETFOCUS, sent|defwinproc },
2962 { WM_MDIACTIVATE, sent|defwinproc },
2963 { 0 }
2965 /* DestroyWindow for MDI child window, initially visible */
2966 static const struct message WmDestroyMDIchildVisibleSeq[] = {
2967 { HCBT_DESTROYWND, hook },
2968 /* Win2k sends wparam set to
2969 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2970 * while Win9x doesn't bother to set child window id according to
2971 * CLIENTCREATESTRUCT.idFirstChild
2973 { 0x0090, sent|optional },
2974 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2975 { WM_SHOWWINDOW, sent|wparam, 0 },
2976 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2977 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2978 { WM_ERASEBKGND, sent|parent|optional },
2979 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2981 /* { WM_DESTROY, sent }
2982 * Win9x: message sequence terminates here.
2985 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2986 { WM_KILLFOCUS, sent },
2987 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2988 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2989 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2990 { WM_SETFOCUS, sent }, /* in MDI client */
2992 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2993 { WM_KILLFOCUS, sent }, /* in MDI client */
2994 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2995 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2996 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2997 { WM_SETFOCUS, sent }, /* in MDI client */
2999 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3001 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
3002 { WM_KILLFOCUS, sent },
3003 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3004 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3005 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3006 { WM_SETFOCUS, sent }, /* in MDI client */
3008 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
3009 { WM_KILLFOCUS, sent }, /* in MDI client */
3010 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3011 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3012 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3013 { WM_SETFOCUS, sent }, /* in MDI client */
3015 { WM_DESTROY, sent },
3017 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
3018 { WM_KILLFOCUS, sent },
3019 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3020 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3021 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3022 { WM_SETFOCUS, sent }, /* in MDI client */
3024 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
3025 { WM_KILLFOCUS, sent }, /* in MDI client */
3026 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3027 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3028 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3029 { WM_SETFOCUS, sent }, /* in MDI client */
3031 { WM_NCDESTROY, sent },
3032 { 0 }
3034 /* CreateWindow for MDI child window, initially invisible */
3035 static const struct message WmCreateMDIchildInvisibleSeq[] = {
3036 { HCBT_CREATEWND, hook },
3037 { WM_NCCREATE, sent },
3038 { WM_NCCALCSIZE, sent|wparam, 0 },
3039 { WM_CREATE, sent },
3040 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3041 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3042 { WM_MOVE, sent },
3043 /* Win2k sends wparam set to
3044 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3045 * while Win9x doesn't bother to set child window id according to
3046 * CLIENTCREATESTRUCT.idFirstChild
3048 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3049 { 0 }
3051 /* DestroyWindow for MDI child window, initially invisible */
3052 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
3053 { HCBT_DESTROYWND, hook },
3054 /* Win2k sends wparam set to
3055 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3056 * while Win9x doesn't bother to set child window id according to
3057 * CLIENTCREATESTRUCT.idFirstChild
3059 { 0x0090, sent|optional },
3060 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3061 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3062 { WM_DESTROY, sent },
3063 { WM_NCDESTROY, sent },
3064 /* FIXME: Wine destroys an icon/title window while Windows doesn't */
3065 { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
3066 { 0 }
3068 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
3069 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
3070 { HCBT_CREATEWND, hook },
3071 { WM_NCCREATE, sent },
3072 { WM_NCCALCSIZE, sent|wparam, 0 },
3073 { WM_CREATE, sent },
3074 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3075 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3076 { WM_MOVE, sent },
3077 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3078 { WM_GETMINMAXINFO, sent },
3079 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3080 { WM_NCCALCSIZE, sent|wparam, 1 },
3081 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3082 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3083 /* in MDI frame */
3084 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3085 { WM_NCCALCSIZE, sent|wparam, 1 },
3086 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3087 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3088 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3089 /* Win2k sends wparam set to
3090 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3091 * while Win9x doesn't bother to set child window id according to
3092 * CLIENTCREATESTRUCT.idFirstChild
3094 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3095 { WM_SHOWWINDOW, sent|wparam, 1 },
3096 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3097 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3098 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3099 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
3100 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3101 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3102 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_FRAMECHANGED },
3104 /* Win9x: message sequence terminates here. */
3106 { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
3107 { HCBT_SETFOCUS, hook|optional }, /* in MDI client */
3108 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3109 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
3110 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3111 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3112 { HCBT_SETFOCUS, hook|optional },
3113 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3114 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3115 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3116 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3117 { WM_SETFOCUS, sent|defwinproc|optional },
3118 { WM_MDIACTIVATE, sent|defwinproc|optional },
3119 /* in MDI frame */
3120 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3121 { WM_NCCALCSIZE, sent|wparam, 1 },
3122 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3123 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3124 { 0 }
3126 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
3127 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
3128 /* restore the 1st MDI child */
3129 { WM_SETREDRAW, sent|wparam, 0 },
3130 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
3131 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3132 { WM_NCCALCSIZE, sent|wparam, 1 },
3133 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3134 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3135 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3136 /* in MDI frame */
3137 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3138 { WM_NCCALCSIZE, sent|wparam, 1 },
3139 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3140 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3141 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3142 { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
3143 /* create the 2nd MDI child */
3144 { HCBT_CREATEWND, hook },
3145 { WM_NCCREATE, sent },
3146 { WM_NCCALCSIZE, sent|wparam, 0 },
3147 { WM_CREATE, sent },
3148 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3149 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3150 { WM_MOVE, sent },
3151 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3152 { WM_GETMINMAXINFO, sent },
3153 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3154 { WM_NCCALCSIZE, sent|wparam, 1 },
3155 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3156 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3157 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3158 /* in MDI frame */
3159 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3160 { WM_NCCALCSIZE, sent|wparam, 1 },
3161 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3162 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3163 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3164 /* Win2k sends wparam set to
3165 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3166 * while Win9x doesn't bother to set child window id according to
3167 * CLIENTCREATESTRUCT.idFirstChild
3169 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3170 { WM_SHOWWINDOW, sent|wparam, 1 },
3171 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3172 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3173 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3174 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
3175 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3176 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3178 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
3179 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
3181 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3183 /* Win9x: message sequence terminates here. */
3185 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3186 { HCBT_SETFOCUS, hook },
3187 { WM_KILLFOCUS, sent|defwinproc|optional }, /* in the 1st MDI child */
3188 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
3189 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3190 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3191 { WM_SETFOCUS, sent }, /* in MDI client */
3192 { HCBT_SETFOCUS, hook },
3193 { WM_KILLFOCUS, sent }, /* in MDI client */
3194 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3195 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3196 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3197 { WM_SETFOCUS, sent|defwinproc },
3199 { WM_MDIACTIVATE, sent|defwinproc },
3200 /* in MDI frame */
3201 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3202 { WM_NCCALCSIZE, sent|wparam, 1 },
3203 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3204 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3205 { 0 }
3207 /* WM_MDICREATE MDI child window, initially visible and maximized */
3208 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
3209 { WM_MDICREATE, sent },
3210 { HCBT_CREATEWND, hook },
3211 { WM_NCCREATE, sent },
3212 { WM_NCCALCSIZE, sent|wparam, 0 },
3213 { WM_CREATE, sent },
3214 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3215 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3216 { WM_MOVE, sent },
3217 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3218 { WM_GETMINMAXINFO, sent },
3219 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3220 { WM_NCCALCSIZE, sent|wparam, 1 },
3221 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3222 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3224 /* in MDI frame */
3225 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3226 { WM_NCCALCSIZE, sent|wparam, 1 },
3227 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3228 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3229 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3231 /* Win2k sends wparam set to
3232 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3233 * while Win9x doesn't bother to set child window id according to
3234 * CLIENTCREATESTRUCT.idFirstChild
3236 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3237 { WM_SHOWWINDOW, sent|wparam, 1 },
3238 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3240 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3242 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3243 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
3244 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3246 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3247 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3249 /* Win9x: message sequence terminates here. */
3251 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3252 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3253 { HCBT_SETFOCUS, hook }, /* in MDI client */
3254 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3255 { WM_IME_NOTIFY, sent|wparam|optional, 2 },
3256 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
3257 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3258 { HCBT_SETFOCUS, hook|optional },
3259 { WM_KILLFOCUS, sent }, /* in MDI client */
3260 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3261 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3262 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3263 { WM_SETFOCUS, sent|defwinproc },
3265 { WM_MDIACTIVATE, sent|defwinproc },
3267 /* in MDI child */
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, 0, 0 },
3273 /* in MDI frame */
3274 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3275 { WM_NCCALCSIZE, sent|wparam, 1 },
3276 { 0x0093, sent|defwinproc|optional },
3277 { 0x0093, sent|defwinproc|optional },
3278 { 0x0093, sent|defwinproc|optional },
3279 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3280 { WM_MOVE, sent|defwinproc },
3281 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3283 /* in MDI client */
3284 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3285 { WM_NCCALCSIZE, sent|wparam, 1 },
3286 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3287 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3289 /* in MDI child */
3290 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3291 { WM_NCCALCSIZE, sent|wparam, 1 },
3292 { 0x0093, sent|optional },
3293 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3294 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3296 { 0x0093, sent|optional },
3297 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3298 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3299 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
3300 { 0x0093, sent|defwinproc|optional },
3301 { 0x0093, sent|defwinproc|optional },
3302 { 0x0093, sent|defwinproc|optional },
3303 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3304 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3306 { 0 }
3308 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
3309 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
3310 { HCBT_CREATEWND, hook },
3311 { WM_GETMINMAXINFO, sent },
3312 { WM_NCCREATE, sent },
3313 { WM_NCCALCSIZE, sent|wparam, 0 },
3314 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
3315 { WM_CREATE, sent },
3316 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3317 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3318 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOZORDER }, /* MDI frame */
3319 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI frame */
3320 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOZORDER }, /* MDI frame */
3321 { WM_MOVE, sent },
3322 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3323 { WM_GETMINMAXINFO, sent },
3324 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3325 { WM_GETMINMAXINFO, sent|defwinproc },
3326 { WM_NCCALCSIZE, sent|wparam, 1 },
3327 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_STATECHANGED },
3328 { WM_MOVE, sent|defwinproc },
3329 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3330 /* in MDI frame */
3331 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3332 { WM_NCCALCSIZE, sent|wparam, 1 },
3333 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3334 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3335 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
3336 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3337 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3338 /* Win2k sends wparam set to
3339 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3340 * while Win9x doesn't bother to set child window id according to
3341 * CLIENTCREATESTRUCT.idFirstChild
3343 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3344 { 0 }
3346 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
3347 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
3348 { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
3349 { HCBT_SYSCOMMAND, hook },
3350 { WM_CLOSE, sent|defwinproc },
3351 { WM_MDIDESTROY, sent }, /* in MDI client */
3353 /* bring the 1st MDI child to top */
3354 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
3355 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
3357 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3359 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
3360 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
3361 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
3363 /* maximize the 1st MDI child */
3364 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3365 { WM_GETMINMAXINFO, sent|defwinproc },
3366 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED },
3367 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
3368 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
3369 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3370 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3372 /* restore the 2nd MDI child */
3373 { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
3374 { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
3375 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
3376 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
3378 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3380 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3381 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3383 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3385 { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
3386 /* in MDI frame */
3387 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3388 { WM_NCCALCSIZE, sent|wparam, 1 },
3389 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3390 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3391 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3393 /* bring the 1st MDI child to top */
3394 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3395 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3396 { HCBT_SETFOCUS, hook },
3397 { WM_KILLFOCUS, sent|defwinproc },
3398 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
3399 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3400 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3401 { WM_SETFOCUS, sent }, /* in MDI client */
3402 { HCBT_SETFOCUS, hook },
3403 { WM_KILLFOCUS, sent }, /* in MDI client */
3404 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3405 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3406 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3407 { WM_SETFOCUS, sent|defwinproc },
3408 { WM_MDIACTIVATE, sent|defwinproc },
3409 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3411 /* apparently ShowWindow(SW_SHOW) on an MDI client */
3412 { WM_SHOWWINDOW, sent|wparam, 1 },
3413 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3414 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3415 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3416 { WM_MDIREFRESHMENU, sent },
3418 { HCBT_DESTROYWND, hook },
3419 /* Win2k sends wparam set to
3420 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3421 * while Win9x doesn't bother to set child window id according to
3422 * CLIENTCREATESTRUCT.idFirstChild
3424 { 0x0090, sent|defwinproc|optional },
3425 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3426 { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
3427 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3428 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3429 { WM_ERASEBKGND, sent|parent|optional },
3430 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3432 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3433 { WM_DESTROY, sent|defwinproc },
3434 { WM_NCDESTROY, sent|defwinproc },
3435 { 0 }
3437 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
3438 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
3439 { WM_MDIDESTROY, sent }, /* in MDI client */
3440 { WM_SHOWWINDOW, sent|wparam, 0 },
3441 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3442 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3443 { WM_ERASEBKGND, sent|parent|optional },
3444 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3446 { HCBT_SETFOCUS, hook },
3447 { WM_KILLFOCUS, sent },
3448 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3449 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3450 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3451 { WM_SETFOCUS, sent }, /* in MDI client */
3452 { HCBT_SETFOCUS, hook },
3453 { WM_KILLFOCUS, sent }, /* in MDI client */
3454 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3455 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3456 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3457 { WM_SETFOCUS, sent },
3459 /* in MDI child */
3460 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3461 { WM_NCCALCSIZE, sent|wparam, 1 },
3462 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3463 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3465 /* in MDI frame */
3466 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3467 { WM_NCCALCSIZE, sent|wparam, 1 },
3468 { 0x0093, sent|defwinproc|optional },
3469 { 0x0093, sent|defwinproc|optional },
3470 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3471 { WM_MOVE, sent|defwinproc },
3472 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3474 /* in MDI client */
3475 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3476 { WM_NCCALCSIZE, sent|wparam, 1 },
3477 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3478 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3480 /* in MDI child */
3481 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3482 { WM_NCCALCSIZE, sent|wparam, 1 },
3483 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3484 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3486 /* in MDI child */
3487 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3488 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3489 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3490 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3492 /* in MDI frame */
3493 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3494 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3495 { 0x0093, sent|defwinproc|optional },
3496 { 0x0093, sent|defwinproc|optional },
3497 { 0x0093, sent|defwinproc|optional },
3498 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3499 { WM_MOVE, sent|defwinproc },
3500 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3502 /* in MDI client */
3503 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3504 { WM_NCCALCSIZE, sent|wparam, 1 },
3505 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3506 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3508 /* in MDI child */
3509 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3510 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3511 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3512 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3513 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3514 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3516 { 0x0093, sent|defwinproc|optional },
3517 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
3518 { 0x0093, sent|defwinproc|optional },
3519 { 0x0093, sent|defwinproc|optional },
3520 { 0x0093, sent|defwinproc|optional },
3521 { 0x0093, sent|optional },
3523 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3524 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3525 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3526 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3527 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3529 /* in MDI frame */
3530 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3531 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3532 { 0x0093, sent|defwinproc|optional },
3533 { 0x0093, sent|defwinproc|optional },
3534 { 0x0093, sent|defwinproc|optional },
3535 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3536 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3537 { 0x0093, sent|optional },
3539 { WM_NCACTIVATE, sent|wparam, 0 },
3540 { WM_MDIACTIVATE, sent },
3542 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
3543 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
3544 { WM_NCCALCSIZE, sent|wparam, 1 },
3546 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3548 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3549 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3550 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3552 /* in MDI child */
3553 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3554 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3555 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3556 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3558 /* in MDI frame */
3559 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3560 { WM_NCCALCSIZE, sent|wparam, 1 },
3561 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3562 { WM_MOVE, sent|defwinproc },
3563 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3565 /* in MDI client */
3566 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3567 { WM_NCCALCSIZE, sent|wparam, 1 },
3568 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3569 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3570 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3571 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
3572 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3573 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3574 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3576 { HCBT_SETFOCUS, hook },
3577 { WM_KILLFOCUS, sent },
3578 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3579 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3580 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3581 { WM_SETFOCUS, sent }, /* in MDI client */
3583 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
3585 { HCBT_DESTROYWND, hook },
3586 /* Win2k sends wparam set to
3587 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3588 * while Win9x doesn't bother to set child window id according to
3589 * CLIENTCREATESTRUCT.idFirstChild
3591 { 0x0090, sent|optional },
3592 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3594 { WM_SHOWWINDOW, sent|wparam, 0 },
3595 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3596 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3597 { WM_ERASEBKGND, sent|parent|optional },
3598 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3600 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3601 { WM_DESTROY, sent },
3602 { WM_NCDESTROY, sent },
3603 { 0 }
3605 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
3606 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
3607 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3608 { WM_GETMINMAXINFO, sent },
3609 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3610 { WM_NCCALCSIZE, sent|wparam, 1 },
3611 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3612 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3614 { WM_WINDOWPOSCHANGING, sent|wparam|optional|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3615 { WM_NCACTIVATE, sent|wparam|optional|defwinproc, 1 },
3616 { HCBT_SETFOCUS, hook|optional },
3617 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3618 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3619 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3620 { HCBT_SETFOCUS, hook|optional },
3621 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3622 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3623 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3624 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3625 { WM_SETFOCUS, sent|optional|defwinproc },
3626 { WM_MDIACTIVATE, sent|optional|defwinproc },
3627 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3628 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3629 /* in MDI frame */
3630 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3631 { WM_NCCALCSIZE, sent|wparam, 1 },
3632 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3633 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3634 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3635 { 0 }
3637 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
3638 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
3639 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3640 { WM_GETMINMAXINFO, sent },
3641 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED, 0, SWP_STATECHANGED /* w1064v1809 */ },
3642 { WM_GETMINMAXINFO, sent|defwinproc },
3643 { WM_NCCALCSIZE, sent|wparam, 1 },
3644 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3645 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3647 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3648 { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
3649 { HCBT_SETFOCUS, hook|optional },
3650 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3651 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3652 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3653 { HCBT_SETFOCUS, hook|optional },
3654 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3655 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3656 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3657 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3658 { WM_SETFOCUS, sent|defwinproc|optional },
3659 { WM_MDIACTIVATE, sent|defwinproc|optional },
3660 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_STATECHANGED /* w1064v1809 */ },
3661 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3662 { WM_SIZE, sent|defwinproc|optional },
3663 { 0 }
3665 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
3666 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
3667 { WM_MDIMAXIMIZE, sent }, /* in MDI client */
3668 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3669 { WM_GETMINMAXINFO, sent },
3670 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3671 { WM_GETMINMAXINFO, sent|defwinproc },
3672 { WM_NCCALCSIZE, sent|wparam, 1 },
3673 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
3674 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3675 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
3676 { WM_MOVE, sent|defwinproc },
3677 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3679 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3680 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3681 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3682 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3683 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3684 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3685 /* in MDI frame */
3686 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3687 { WM_NCCALCSIZE, sent|wparam, 1 },
3688 { 0x0093, sent|defwinproc|optional },
3689 { 0x0094, sent|defwinproc|optional },
3690 { 0x0094, sent|defwinproc|optional },
3691 { 0x0094, sent|defwinproc|optional },
3692 { 0x0094, sent|defwinproc|optional },
3693 { 0x0093, sent|defwinproc|optional },
3694 { 0x0093, sent|defwinproc|optional },
3695 { 0x0091, sent|defwinproc|optional },
3696 { 0x0092, sent|defwinproc|optional },
3697 { 0x0092, sent|defwinproc|optional },
3698 { 0x0092, sent|defwinproc|optional },
3699 { 0x0092, sent|defwinproc|optional },
3700 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3701 { WM_MOVE, sent|defwinproc },
3702 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3703 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
3704 /* in MDI client */
3705 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3706 { WM_NCCALCSIZE, sent|wparam, 1 },
3707 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3708 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3709 /* in MDI child */
3710 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3711 { WM_GETMINMAXINFO, sent|defwinproc },
3712 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3713 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3714 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3715 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
3716 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3717 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3718 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3719 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3720 /* in MDI frame */
3721 { 0x0093, sent|optional },
3722 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3723 { 0x0093, sent|defwinproc|optional },
3724 { 0x0093, sent|defwinproc|optional },
3725 { 0x0093, sent|defwinproc|optional },
3726 { 0x0091, sent|defwinproc|optional },
3727 { 0x0092, sent|defwinproc|optional },
3728 { 0x0092, sent|defwinproc|optional },
3729 { 0x0092, sent|defwinproc|optional },
3730 { 0x0092, sent|defwinproc|optional },
3731 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3732 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3733 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3734 { 0 }
3736 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
3737 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
3738 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3739 { WM_GETMINMAXINFO, sent },
3740 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3741 { WM_NCCALCSIZE, sent|wparam, 1 },
3742 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3743 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3744 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
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|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3749 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3750 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3751 { 0 }
3753 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
3754 static const struct message WmRestoreMDIchildVisibleSeq[] = {
3755 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3756 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3757 { WM_NCCALCSIZE, sent|wparam, 1 },
3758 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3759 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3760 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3761 /* in MDI frame */
3762 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3763 { WM_NCCALCSIZE, sent|wparam, 1 },
3764 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3765 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3766 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3767 { 0 }
3769 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
3770 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
3771 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3772 { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
3773 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3774 { WM_NCCALCSIZE, sent|wparam, 1 },
3775 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3776 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3777 { WM_MOVE, sent|defwinproc },
3778 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3779 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3780 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3781 { HCBT_SETFOCUS, hook },
3782 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3783 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
3784 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3785 { WM_SETFOCUS, sent },
3786 { 0 }
3788 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
3789 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
3790 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
3791 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3792 { WM_NCCALCSIZE, sent|wparam, 1 },
3793 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3794 { WM_MOVE, sent|defwinproc },
3795 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
3796 { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
3797 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3798 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3799 /* FIXME: Wine creates an icon/title window while Windows doesn't */
3800 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
3801 { 0 }
3803 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
3804 static const struct message WmRestoreMDIchildInvisibleSeq[] = {
3805 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3806 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3807 { WM_NCCALCSIZE, sent|wparam, 1 },
3808 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3809 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3810 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3811 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3812 /* in MDI frame */
3813 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3814 { WM_NCCALCSIZE, sent|wparam, 1 },
3815 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3816 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3817 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3818 { 0 }
3821 static HWND mdi_client;
3822 static WNDPROC old_mdi_client_proc;
3824 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3826 struct recvd_message msg;
3828 /* do not log painting messages */
3829 if (message != WM_PAINT &&
3830 message != WM_NCPAINT &&
3831 message != WM_SYNCPAINT &&
3832 message != WM_ERASEBKGND &&
3833 message != WM_NCHITTEST &&
3834 message != WM_GETTEXT &&
3835 message != WM_MDIGETACTIVE &&
3836 !ignore_message( message ))
3838 msg.hwnd = hwnd;
3839 msg.message = message;
3840 msg.flags = sent|wparam|lparam;
3841 msg.wParam = wParam;
3842 msg.lParam = lParam;
3843 msg.descr = "mdi client";
3844 add_message(&msg);
3847 return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
3850 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3852 static LONG defwndproc_counter = 0;
3853 LRESULT ret;
3854 struct recvd_message msg;
3856 /* do not log painting messages */
3857 if (message != WM_PAINT &&
3858 message != WM_NCPAINT &&
3859 message != WM_SYNCPAINT &&
3860 message != WM_ERASEBKGND &&
3861 message != WM_NCHITTEST &&
3862 message != WM_GETTEXT &&
3863 !ignore_message( message ))
3865 switch (message)
3867 case WM_MDIACTIVATE:
3869 HWND active, client = GetParent(hwnd);
3871 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
3873 if (hwnd == (HWND)lParam) /* if we are being activated */
3874 ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
3875 else
3876 ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
3877 break;
3881 msg.hwnd = hwnd;
3882 msg.message = message;
3883 msg.flags = sent|wparam|lparam;
3884 if (defwndproc_counter) msg.flags |= defwinproc;
3885 msg.wParam = wParam;
3886 msg.lParam = lParam;
3887 msg.descr = "mdi child";
3888 add_message(&msg);
3891 defwndproc_counter++;
3892 ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
3893 defwndproc_counter--;
3895 return ret;
3898 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3900 static LONG defwndproc_counter = 0;
3901 LRESULT ret;
3902 struct recvd_message msg;
3904 /* do not log painting messages */
3905 if (message != WM_PAINT &&
3906 message != WM_NCPAINT &&
3907 message != WM_SYNCPAINT &&
3908 message != WM_ERASEBKGND &&
3909 message != WM_NCHITTEST &&
3910 message != WM_GETTEXT &&
3911 !ignore_message( message ))
3913 msg.hwnd = hwnd;
3914 msg.message = message;
3915 msg.flags = sent|wparam|lparam;
3916 if (defwndproc_counter) msg.flags |= defwinproc;
3917 msg.wParam = wParam;
3918 msg.lParam = lParam;
3919 msg.descr = "mdi frame";
3920 add_message(&msg);
3923 defwndproc_counter++;
3924 ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
3925 defwndproc_counter--;
3927 return ret;
3930 static BOOL mdi_RegisterWindowClasses(void)
3932 WNDCLASSA cls;
3934 cls.style = 0;
3935 cls.lpfnWndProc = mdi_frame_wnd_proc;
3936 cls.cbClsExtra = 0;
3937 cls.cbWndExtra = 0;
3938 cls.hInstance = GetModuleHandleA(0);
3939 cls.hIcon = 0;
3940 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
3941 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3942 cls.lpszMenuName = NULL;
3943 cls.lpszClassName = "MDI_frame_class";
3944 if (!RegisterClassA(&cls)) return FALSE;
3946 cls.lpfnWndProc = mdi_child_wnd_proc;
3947 cls.lpszClassName = "MDI_child_class";
3948 if (!RegisterClassA(&cls)) return FALSE;
3950 if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
3951 old_mdi_client_proc = cls.lpfnWndProc;
3952 cls.hInstance = GetModuleHandleA(0);
3953 cls.lpfnWndProc = mdi_client_hook_proc;
3954 cls.lpszClassName = "MDI_client_class";
3955 if (!RegisterClassA(&cls)) assert(0);
3957 return TRUE;
3960 static void test_mdi_messages(void)
3962 MDICREATESTRUCTA mdi_cs;
3963 CLIENTCREATESTRUCT client_cs;
3964 HWND mdi_frame, mdi_child, mdi_child2, active_child;
3965 BOOL zoomed;
3966 RECT rc;
3967 HMENU hMenu = CreateMenu();
3968 LONG val;
3970 if (!mdi_RegisterWindowClasses()) assert(0);
3972 flush_sequence();
3974 trace("creating MDI frame window\n");
3975 mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
3976 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
3977 WS_MAXIMIZEBOX | WS_VISIBLE,
3978 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
3979 GetDesktopWindow(), hMenu,
3980 GetModuleHandleA(0), NULL);
3981 assert(mdi_frame);
3982 ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
3984 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3985 ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
3987 trace("creating MDI client window\n");
3988 GetClientRect(mdi_frame, &rc);
3989 client_cs.hWindowMenu = 0;
3990 client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
3991 mdi_client = CreateWindowExA(0, "MDI_client_class",
3992 NULL,
3993 WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
3994 rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
3995 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3996 assert(mdi_client);
3997 SetWindowLongA(mdi_client, 0, 0xdeadbeef);
3999 ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
4000 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4001 ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
4003 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4004 ok(!active_child, "wrong active MDI child %p\n", active_child);
4005 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4007 SetFocus(0);
4008 flush_sequence();
4010 trace("creating invisible MDI child window\n");
4011 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4012 WS_CHILD,
4013 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4014 mdi_client, 0, GetModuleHandleA(0), NULL);
4015 assert(mdi_child);
4017 flush_sequence();
4018 ShowWindow(mdi_child, SW_SHOWNORMAL);
4019 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
4021 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4022 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
4024 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4025 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4027 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4028 ok(!active_child, "wrong active MDI child %p\n", active_child);
4029 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4031 ShowWindow(mdi_child, SW_HIDE);
4032 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
4033 flush_sequence();
4035 ShowWindow(mdi_child, SW_SHOW);
4036 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
4038 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4039 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
4041 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4042 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4044 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4045 ok(!active_child, "wrong active MDI child %p\n", active_child);
4046 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4048 DestroyWindow(mdi_child);
4049 flush_sequence();
4051 trace("creating visible MDI child window\n");
4052 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4053 WS_CHILD | WS_VISIBLE,
4054 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4055 mdi_client, 0, GetModuleHandleA(0), NULL);
4056 assert(mdi_child);
4057 ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
4059 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4060 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
4062 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4063 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4065 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4066 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4067 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4068 flush_sequence();
4070 DestroyWindow(mdi_child);
4071 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4073 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4074 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4076 /* Win2k: MDI client still returns a just destroyed child as active
4077 * Win9x: MDI client returns 0
4079 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4080 ok(active_child == mdi_child || /* win2k */
4081 !active_child, /* win9x */
4082 "wrong active MDI child %p\n", active_child);
4083 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4085 flush_sequence();
4087 trace("creating invisible MDI child window\n");
4088 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4089 WS_CHILD,
4090 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4091 mdi_client, 0, GetModuleHandleA(0), NULL);
4092 assert(mdi_child2);
4093 ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
4095 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
4096 ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
4098 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4099 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4101 /* Win2k: MDI client still returns a just destroyed child as active
4102 * Win9x: MDI client returns mdi_child2
4104 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4105 ok(active_child == mdi_child || /* win2k */
4106 active_child == mdi_child2, /* win9x */
4107 "wrong active MDI child %p\n", active_child);
4108 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4109 flush_sequence();
4111 ShowWindow(mdi_child2, SW_MAXIMIZE);
4112 ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
4114 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4115 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
4117 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4118 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4119 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4120 flush_sequence();
4122 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4123 ok(GetFocus() == mdi_child2 || /* win2k */
4124 GetFocus() == 0, /* win9x */
4125 "wrong focus window %p\n", GetFocus());
4127 SetFocus(0);
4128 flush_sequence();
4130 ShowWindow(mdi_child2, SW_HIDE);
4131 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
4133 ShowWindow(mdi_child2, SW_RESTORE);
4134 ok_sequence(WmRestoreMDIchildInvisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
4135 flush_sequence();
4137 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4138 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
4140 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4141 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4142 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4143 flush_sequence();
4145 SetFocus(0);
4146 flush_sequence();
4148 ShowWindow(mdi_child2, SW_HIDE);
4149 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
4151 ShowWindow(mdi_child2, SW_SHOW);
4152 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
4154 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4155 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4157 ShowWindow(mdi_child2, SW_MAXIMIZE);
4158 ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
4160 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4161 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4163 ShowWindow(mdi_child2, SW_RESTORE);
4164 ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
4166 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4167 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4169 ShowWindow(mdi_child2, SW_MINIMIZE);
4170 ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", FALSE);
4172 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4173 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4175 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4176 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4177 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4178 flush_sequence();
4180 ShowWindow(mdi_child2, SW_RESTORE);
4181 ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", FALSE);
4183 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4184 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4186 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4187 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4188 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4189 flush_sequence();
4191 SetFocus(0);
4192 flush_sequence();
4194 ShowWindow(mdi_child2, SW_HIDE);
4195 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
4197 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4198 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4200 DestroyWindow(mdi_child2);
4201 ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
4203 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4204 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4206 trace("Testing WM_CHILDACTIVATE\n");
4208 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4209 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_DISABLED,
4210 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4211 mdi_client, 0, GetModuleHandleA(0), NULL);
4213 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4214 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX,
4215 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4216 mdi_client, 0, GetModuleHandleA(0), NULL);
4218 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4219 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4220 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4222 flush_sequence();
4223 SendMessageW(mdi_child, WM_CHILDACTIVATE, 0, 0);
4224 ok_sequence(WmChildActivateDisabledWindowSeq, "WM_CHILDACTIVATE sent to disabled window", FALSE);
4226 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4227 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4228 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4229 flush_sequence();
4231 EnableWindow(mdi_child, TRUE);
4233 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4234 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4235 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4237 flush_sequence();
4238 SendMessageW(mdi_child, WM_CHILDACTIVATE, 0, 0);
4239 ok_sequence(WmChildActivateWindowSeq, "WM_CHILDACTIVATE sent to enabled window", FALSE);
4241 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4242 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4243 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4244 flush_sequence();
4246 DestroyWindow(mdi_child);
4247 DestroyWindow(mdi_child2);
4248 flush_sequence();
4250 /* test for maximized MDI children */
4251 trace("creating maximized visible MDI child window 1\n");
4252 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4253 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4254 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4255 mdi_client, 0, GetModuleHandleA(0), NULL);
4256 assert(mdi_child);
4257 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
4258 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4260 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4261 ok(GetFocus() == mdi_child || /* win2k */
4262 GetFocus() == 0, /* win9x */
4263 "wrong focus window %p\n", GetFocus());
4265 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4266 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4267 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4268 flush_sequence();
4270 trace("creating maximized visible MDI child window 2\n");
4271 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4272 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4273 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4274 mdi_client, 0, GetModuleHandleA(0), NULL);
4275 assert(mdi_child2);
4276 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
4277 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
4278 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4280 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4281 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4283 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4284 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4285 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4286 flush_sequence();
4288 trace("destroying maximized visible MDI child window 2\n");
4289 DestroyWindow(mdi_child2);
4290 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4292 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4294 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4295 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4297 /* Win2k: MDI client still returns a just destroyed child as active
4298 * Win9x: MDI client returns 0
4300 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4301 ok(active_child == mdi_child2 || /* win2k */
4302 !active_child, /* win9x */
4303 "wrong active MDI child %p\n", active_child);
4304 flush_sequence();
4306 ShowWindow(mdi_child, SW_MAXIMIZE);
4307 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4308 flush_sequence();
4310 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4311 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4313 trace("re-creating maximized visible MDI child window 2\n");
4314 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4315 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4316 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4317 mdi_client, 0, GetModuleHandleA(0), NULL);
4318 assert(mdi_child2);
4319 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
4320 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
4321 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4323 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4324 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4326 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4327 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4328 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4329 flush_sequence();
4331 SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
4332 ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
4333 ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
4335 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4336 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4337 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4339 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4340 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4341 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4342 flush_sequence();
4344 DestroyWindow(mdi_child);
4345 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4347 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4348 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4350 /* Win2k: MDI client still returns a just destroyed child as active
4351 * Win9x: MDI client returns 0
4353 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4354 ok(active_child == mdi_child || /* win2k */
4355 !active_child, /* win9x */
4356 "wrong active MDI child %p\n", active_child);
4357 flush_sequence();
4359 trace("creating maximized invisible MDI child window\n");
4360 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4361 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
4362 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4363 mdi_client, 0, GetModuleHandleA(0), NULL);
4364 assert(mdi_child2);
4365 ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE);
4366 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
4367 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
4368 ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
4370 /* Win2k: MDI client still returns a just destroyed child as active
4371 * Win9x: MDI client returns 0
4373 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4374 ok(active_child == mdi_child || /* win2k */
4375 !active_child || active_child == mdi_child2, /* win9x */
4376 "wrong active MDI child %p\n", active_child);
4377 flush_sequence();
4379 trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
4380 ShowWindow(mdi_child2, SW_MAXIMIZE);
4381 ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
4382 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
4383 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4384 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
4386 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4387 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4388 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4389 flush_sequence();
4391 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
4392 flush_sequence();
4394 /* end of test for maximized MDI children */
4395 SetFocus(0);
4396 flush_sequence();
4397 trace("creating maximized visible MDI child window 1(Switch test)\n");
4398 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4399 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4400 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4401 mdi_client, 0, GetModuleHandleA(0), NULL);
4402 assert(mdi_child);
4403 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
4404 ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
4406 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
4407 ok(GetFocus() == mdi_child || /* win2k */
4408 GetFocus() == 0, /* win9x */
4409 "wrong focus window %p(Switch test)\n", GetFocus());
4411 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4412 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
4413 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
4414 flush_sequence();
4416 trace("creating maximized visible MDI child window 2(Switch test)\n");
4417 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4418 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4419 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4420 mdi_client, 0, GetModuleHandleA(0), NULL);
4421 assert(mdi_child2);
4422 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
4424 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
4425 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
4427 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
4428 ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
4430 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4431 ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
4432 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
4433 flush_sequence();
4435 trace("Switch child window.\n");
4436 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
4437 ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
4438 trace("end of test for switch maximized MDI children\n");
4439 flush_sequence();
4441 /* Prepare for switching test of not maximized MDI children */
4442 ShowWindow( mdi_child, SW_NORMAL );
4443 ok(!IsZoomed(mdi_child), "wrong zoomed state for %p(Switch test)\n", mdi_child);
4444 ok(!IsZoomed(mdi_child2), "wrong zoomed state for %p(Switch test)\n", mdi_child2);
4445 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
4446 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
4447 flush_sequence();
4449 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0);
4450 ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE);
4451 trace("end of test for switch not maximized MDI children\n");
4452 flush_sequence();
4454 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
4455 flush_sequence();
4457 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
4458 flush_sequence();
4460 SetFocus(0);
4461 flush_sequence();
4462 /* end of tests for switch maximized/not maximized MDI children */
4464 mdi_cs.szClass = "MDI_child_Class";
4465 mdi_cs.szTitle = "MDI child";
4466 mdi_cs.hOwner = GetModuleHandleA(0);
4467 mdi_cs.x = 0;
4468 mdi_cs.y = 0;
4469 mdi_cs.cx = CW_USEDEFAULT;
4470 mdi_cs.cy = CW_USEDEFAULT;
4471 mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
4472 mdi_cs.lParam = 0;
4473 mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
4474 ok(mdi_child != 0, "MDI child creation failed\n");
4475 ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
4477 ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
4479 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4480 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4482 ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
4483 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4484 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4486 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4487 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4488 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4489 flush_sequence();
4491 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
4492 ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
4494 ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
4495 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4496 ok(!active_child, "wrong active MDI child %p\n", active_child);
4498 SetFocus(0);
4499 flush_sequence();
4501 val = GetWindowLongA(mdi_client, 0);
4502 ok(val == 0xdeadbeef || broken(val == 0) /* >= Win Vista */, "Expected 0xdeadbeef, got 0x%x\n", val);
4503 DestroyWindow(mdi_client);
4504 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
4506 /* test maximization of MDI child with invisible parent */
4507 client_cs.hWindowMenu = 0;
4508 mdi_client = CreateWindowA("MDI_client_class",
4509 NULL,
4510 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
4511 0, 0, 660, 430,
4512 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
4513 ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
4515 ShowWindow(mdi_client, SW_HIDE);
4516 ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
4518 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4519 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
4520 0, 0, 650, 440,
4521 mdi_client, 0, GetModuleHandleA(0), NULL);
4522 ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
4524 SendMessageA(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
4525 ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
4526 zoomed = IsZoomed(mdi_child);
4527 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4529 ShowWindow(mdi_client, SW_SHOW);
4530 ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
4532 DestroyWindow(mdi_child);
4533 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
4535 /* end of test for maximization of MDI child with invisible parent */
4537 DestroyWindow(mdi_client);
4538 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
4540 DestroyWindow(mdi_frame);
4541 ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
4543 /************************* End of MDI test **********************************/
4545 static void test_WM_SETREDRAW(HWND hwnd)
4547 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
4549 flush_events();
4550 flush_sequence();
4552 SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
4553 ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
4555 ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
4556 ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
4558 flush_sequence();
4559 SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
4560 ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
4562 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4563 ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
4565 /* restore original WS_VISIBLE state */
4566 SetWindowLongA(hwnd, GWL_STYLE, style);
4568 flush_events();
4569 flush_sequence();
4572 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4574 struct recvd_message msg;
4576 if (ignore_message( message )) return 0;
4578 switch (message)
4580 /* ignore */
4581 case WM_MOUSEMOVE:
4582 case WM_NCMOUSEMOVE:
4583 case WM_NCMOUSELEAVE:
4584 case WM_SETCURSOR:
4585 return 0;
4586 case WM_NCHITTEST:
4587 return HTCLIENT;
4590 msg.hwnd = hwnd;
4591 msg.message = message;
4592 msg.flags = sent|wparam|lparam;
4593 msg.wParam = wParam;
4594 msg.lParam = lParam;
4595 msg.descr = "dialog";
4596 add_message(&msg);
4598 if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
4599 if (message == WM_TIMER) EndDialog( hwnd, 0 );
4600 return 0;
4603 static INT_PTR CALLBACK TestModalDlgProc2(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4605 struct recvd_message msg;
4607 if (ignore_message( message )) return 0;
4609 switch (message)
4611 /* ignore */
4612 case WM_MOUSEMOVE:
4613 case WM_NCMOUSEMOVE:
4614 case WM_NCMOUSELEAVE:
4615 case WM_SETCURSOR:
4616 return 0;
4617 case WM_NCHITTEST:
4618 return HTCLIENT;
4621 msg.hwnd = hwnd;
4622 msg.message = message;
4623 msg.flags = sent|wparam|lparam;
4624 msg.wParam = wParam;
4625 msg.lParam = lParam;
4626 msg.descr = "dialog";
4627 add_message(&msg);
4629 if (message == WM_INITDIALOG) EndDialog( hwnd, 0 );
4630 return 0;
4633 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4635 DWORD style, exstyle;
4636 INT xmin, xmax;
4637 BOOL ret;
4639 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4640 style = GetWindowLongA(hwnd, GWL_STYLE);
4641 /* do not be confused by WS_DLGFRAME set */
4642 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4644 if (clear) ok(style & clear, "style %08x should be set\n", clear);
4645 if (set) ok(!(style & set), "style %08x should not be set\n", set);
4647 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4648 ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
4649 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4650 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
4651 else
4652 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
4654 style = GetWindowLongA(hwnd, GWL_STYLE);
4655 if (set) ok(style & set, "style %08x should be set\n", set);
4656 if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4658 /* a subsequent call should do nothing */
4659 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4660 ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
4661 ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4663 xmin = 0xdeadbeef;
4664 xmax = 0xdeadbeef;
4665 ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
4666 ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
4667 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4668 ok(xmin == min, "unexpected min scroll value %d\n", xmin);
4669 ok(xmax == max, "unexpected max scroll value %d\n", xmax);
4672 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4674 DWORD style, exstyle;
4675 SCROLLINFO si;
4676 BOOL ret;
4678 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4679 style = GetWindowLongA(hwnd, GWL_STYLE);
4680 /* do not be confused by WS_DLGFRAME set */
4681 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4683 if (clear) ok(style & clear, "style %08x should be set\n", clear);
4684 if (set) ok(!(style & set), "style %08x should not be set\n", set);
4686 si.cbSize = sizeof(si);
4687 si.fMask = SIF_RANGE;
4688 si.nMin = min;
4689 si.nMax = max;
4690 SetScrollInfo(hwnd, ctl, &si, TRUE);
4691 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4692 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
4693 else
4694 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
4696 style = GetWindowLongA(hwnd, GWL_STYLE);
4697 if (set) ok(style & set, "style %08x should be set\n", set);
4698 if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4700 /* a subsequent call should do nothing */
4701 SetScrollInfo(hwnd, ctl, &si, TRUE);
4702 if (style & WS_HSCROLL)
4703 ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4704 else if (style & WS_VSCROLL)
4705 ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4706 else
4707 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4709 si.fMask = SIF_PAGE;
4710 si.nPage = 5;
4711 SetScrollInfo(hwnd, ctl, &si, FALSE);
4712 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4714 si.fMask = SIF_POS;
4715 si.nPos = max - 1;
4716 SetScrollInfo(hwnd, ctl, &si, FALSE);
4717 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4719 si.fMask = SIF_RANGE;
4720 si.nMin = 0xdeadbeef;
4721 si.nMax = 0xdeadbeef;
4722 ret = GetScrollInfo(hwnd, ctl, &si);
4723 ok( ret, "GetScrollInfo error %d\n", GetLastError());
4724 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4725 ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
4726 ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
4729 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
4730 static void test_scroll_messages(HWND hwnd)
4732 SCROLLINFO si;
4733 INT min, max;
4734 BOOL ret;
4736 flush_events();
4737 flush_sequence();
4739 min = 0xdeadbeef;
4740 max = 0xdeadbeef;
4741 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4742 ok( ret, "GetScrollRange error %d\n", GetLastError());
4743 if (sequence->message != WmGetScrollRangeSeq[0].message)
4744 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4745 /* values of min and max are undefined */
4746 flush_sequence();
4748 ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
4749 ok( ret, "SetScrollRange error %d\n", GetLastError());
4750 if (sequence->message != WmSetScrollRangeSeq[0].message)
4751 trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4752 flush_sequence();
4754 min = 0xdeadbeef;
4755 max = 0xdeadbeef;
4756 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4757 ok( ret, "GetScrollRange error %d\n", GetLastError());
4758 if (sequence->message != WmGetScrollRangeSeq[0].message)
4759 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4760 /* values of min and max are undefined */
4761 flush_sequence();
4763 si.cbSize = sizeof(si);
4764 si.fMask = SIF_RANGE;
4765 si.nMin = 20;
4766 si.nMax = 160;
4767 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4768 if (sequence->message != WmSetScrollRangeSeq[0].message)
4769 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4770 flush_sequence();
4772 si.fMask = SIF_PAGE;
4773 si.nPage = 10;
4774 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4775 if (sequence->message != WmSetScrollRangeSeq[0].message)
4776 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4777 flush_sequence();
4779 si.fMask = SIF_POS;
4780 si.nPos = 20;
4781 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4782 if (sequence->message != WmSetScrollRangeSeq[0].message)
4783 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4784 flush_sequence();
4786 si.fMask = SIF_RANGE;
4787 si.nMin = 0xdeadbeef;
4788 si.nMax = 0xdeadbeef;
4789 ret = GetScrollInfo(hwnd, SB_CTL, &si);
4790 ok( ret, "GetScrollInfo error %d\n", GetLastError());
4791 if (sequence->message != WmGetScrollInfoSeq[0].message)
4792 trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4793 /* values of min and max are undefined */
4794 flush_sequence();
4796 /* set WS_HSCROLL */
4797 test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4798 /* clear WS_HSCROLL */
4799 test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4801 /* set WS_HSCROLL */
4802 test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4803 /* clear WS_HSCROLL */
4804 test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4806 /* set WS_VSCROLL */
4807 test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4808 /* clear WS_VSCROLL */
4809 test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4811 /* set WS_VSCROLL */
4812 test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4813 /* clear WS_VSCROLL */
4814 test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4817 static void test_showwindow(void)
4819 HWND hwnd, hwnd2, hchild;
4820 RECT rc;
4822 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4823 100, 100, 200, 200, 0, 0, 0, NULL);
4824 ok (hwnd != 0, "Failed to create overlapped window\n");
4825 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4826 0, 0, 10, 10, hwnd, 0, 0, NULL);
4827 ok (hchild != 0, "Failed to create child\n");
4828 flush_sequence();
4830 /* ShowWindow( SW_SHOWNA) for invisible top level window */
4831 trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
4832 ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4833 ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", FALSE);
4835 /* ShowWindow( SW_SHOWNA) for now visible top level window */
4836 trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
4837 ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4838 ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
4839 /* back to invisible */
4840 ShowWindow(hchild, SW_HIDE);
4841 ShowWindow(hwnd, SW_HIDE);
4842 flush_sequence();
4843 /* ShowWindow(SW_SHOWNA) with child and parent invisible */
4844 trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
4845 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4846 ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
4847 /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */
4848 ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
4849 flush_sequence();
4850 trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
4851 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4852 ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
4853 /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
4854 ShowWindow( hwnd, SW_SHOW);
4855 flush_sequence();
4856 trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
4857 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4858 ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
4860 /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
4861 ShowWindow( hchild, SW_HIDE);
4862 flush_sequence();
4863 trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
4864 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4865 ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
4867 SetCapture(hchild);
4868 ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
4869 DestroyWindow(hchild);
4870 ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
4872 DestroyWindow(hwnd);
4873 flush_sequence();
4875 /* Popup windows */
4876 /* Test 1:
4877 * 1. Create invisible maximized popup window.
4878 * 2. Move and resize it.
4879 * 3. Show it maximized.
4881 trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4882 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4883 100, 100, 200, 200, 0, 0, 0, NULL);
4884 ok (hwnd != 0, "Failed to create popup window\n");
4885 ok(IsZoomed(hwnd), "window should be maximized\n");
4886 ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4888 GetWindowRect(hwnd, &rc);
4889 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4890 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4891 "Invalid maximized size before ShowWindow %s\n", wine_dbgstr_rect( &rc ));
4892 /* Reset window's size & position */
4893 SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
4894 ok(IsZoomed(hwnd), "window should be maximized\n");
4895 flush_sequence();
4897 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4898 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4899 ok(IsZoomed(hwnd), "window should be maximized\n");
4900 ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
4902 GetWindowRect(hwnd, &rc);
4903 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4904 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4905 "Invalid maximized size after ShowWindow %s\n", wine_dbgstr_rect( &rc ));
4906 DestroyWindow(hwnd);
4907 flush_sequence();
4909 /* Test 2:
4910 * 1. Create invisible maximized popup window.
4911 * 2. Show it maximized.
4913 trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4914 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4915 100, 100, 200, 200, 0, 0, 0, NULL);
4916 ok (hwnd != 0, "Failed to create popup window\n");
4917 ok(IsZoomed(hwnd), "window should be maximized\n");
4918 ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4920 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4921 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4922 ok(IsZoomed(hwnd), "window should be maximized\n");
4923 ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
4924 DestroyWindow(hwnd);
4925 flush_sequence();
4927 /* Test 3:
4928 * 1. Create visible maximized popup window.
4930 trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
4931 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
4932 100, 100, 200, 200, 0, 0, 0, NULL);
4933 ok (hwnd != 0, "Failed to create popup window\n");
4934 ok(IsZoomed(hwnd), "window should be maximized\n");
4935 ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4936 DestroyWindow(hwnd);
4937 flush_sequence();
4939 /* Test 4:
4940 * 1. Create visible popup window.
4941 * 2. Maximize it.
4943 trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
4944 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
4945 100, 100, 200, 200, 0, 0, 0, NULL);
4946 ok (hwnd != 0, "Failed to create popup window\n");
4947 ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
4948 ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
4950 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
4951 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4952 ok(IsZoomed(hwnd), "window should be maximized\n");
4953 ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
4954 DestroyWindow(hwnd);
4955 flush_sequence();
4957 /* Test 5:
4958 * 1. Restoring a minimized window.
4960 hwnd = CreateWindowA("TestWindowClass", "window1", WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 0, 0, 0, 0);
4961 ok(hwnd != NULL, "Failed to create window\n");
4963 hwnd2 = CreateWindowA("static", "window2", WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 0, 0, 0, 0);
4964 ok(hwnd2 != NULL, "Failed to create window\n");
4966 ShowWindow(hwnd, SW_MINIMIZE);
4967 SetActiveWindow(hwnd2);
4968 ok(GetActiveWindow() == hwnd2, "Unexpected active window\n");
4969 flush_events();
4970 flush_sequence();
4971 ShowWindow(hwnd, SW_RESTORE);
4972 flush_events();
4973 ok_sequence(WmShowRestoreMinimizedOverlappedSeq,
4974 "ShowWindow(hwnd, SW_RESTORE): minimized overlapped", TRUE);
4976 ShowWindow(hwnd, SW_MINIMIZE);
4977 SetActiveWindow(hwnd2);
4978 ok(GetActiveWindow() == hwnd2, "Unexpected active window\n");
4979 flush_events();
4980 flush_sequence();
4981 ShowWindow(hwnd, SW_SHOWNOACTIVATE);
4982 flush_events();
4983 ok_sequence(WmShowNoActivateMinimizedOverlappedSeq,
4984 "ShowWindow(hwnd, SW_SHOWNOACTIVATE): minimized overlapped", TRUE);
4986 DestroyWindow(hwnd2);
4987 DestroyWindow(hwnd);
4988 flush_sequence();
4990 /* Test 6:
4991 * 1. Restoring a minimized but active window.
4993 hwnd = CreateWindowA("TestWindowClass", "parent", WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 0, 0, 0, 0);
4994 ok(hwnd != NULL, "Failed to create window\n");
4996 ShowWindow(hwnd, SW_MINIMIZE);
4997 SetActiveWindow(hwnd);
4998 ok(GetActiveWindow() == hwnd, "Unexpected active window\n");
4999 flush_events();
5000 flush_sequence();
5001 ShowWindow(hwnd, SW_RESTORE);
5002 flush_events();
5003 ok_sequence(WmShowRestoreActiveMinimizedOverlappedSeq,
5004 "ShowWindow(hwnd, SW_RESTORE): active minimized overlapped", TRUE);
5006 ShowWindow(hwnd, SW_MINIMIZE);
5007 SetActiveWindow(hwnd);
5008 ok(GetActiveWindow() == hwnd, "Unexpected active window\n");
5009 flush_events();
5010 flush_sequence();
5011 ShowWindow(hwnd, SW_SHOWNOACTIVATE);
5012 flush_events();
5013 ok_sequence(WmShowNoActivateActiveMinimizedOverlappedSeq,
5014 "ShowWindow(hwnd, SW_SHOWNOACTIVATE): active minimized overlapped", TRUE);
5016 DestroyWindow(hwnd);
5017 flush_sequence();
5020 static void test_sys_menu(void)
5022 HWND hwnd;
5023 HMENU hmenu;
5024 UINT state;
5026 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
5027 100, 100, 200, 200, 0, 0, 0, NULL);
5028 ok (hwnd != 0, "Failed to create overlapped window\n");
5030 flush_sequence();
5032 /* test existing window without CS_NOCLOSE style */
5033 hmenu = GetSystemMenu(hwnd, FALSE);
5034 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
5036 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
5037 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
5038 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
5040 EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
5041 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
5043 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
5044 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
5045 ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
5047 EnableMenuItem(hmenu, SC_CLOSE, 0);
5048 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
5050 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
5051 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
5052 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
5054 /* test whether removing WS_SYSMENU destroys a system menu */
5055 SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
5056 SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
5057 flush_sequence();
5058 hmenu = GetSystemMenu(hwnd, FALSE);
5059 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
5061 DestroyWindow(hwnd);
5063 /* test new window with CS_NOCLOSE style */
5064 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
5065 100, 100, 200, 200, 0, 0, 0, NULL);
5066 ok (hwnd != 0, "Failed to create overlapped window\n");
5068 hmenu = GetSystemMenu(hwnd, FALSE);
5069 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
5071 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
5072 ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
5074 DestroyWindow(hwnd);
5076 /* test new window without WS_SYSMENU style */
5077 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
5078 100, 100, 200, 200, 0, 0, 0, NULL);
5079 ok(hwnd != 0, "Failed to create overlapped window\n");
5081 hmenu = GetSystemMenu(hwnd, FALSE);
5082 ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
5084 DestroyWindow(hwnd);
5087 /* For shown WS_OVERLAPPEDWINDOW */
5088 static const struct message WmSetIcon_1[] = {
5089 { WM_SETICON, sent },
5090 { 0x00AE, sent|defwinproc|optional }, /* XP */
5091 { WM_GETTEXT, sent|defwinproc|optional },
5092 { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
5093 { 0 }
5096 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
5097 static const struct message WmSetIcon_2[] = {
5098 { WM_SETICON, sent },
5099 { 0 }
5102 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
5103 static const struct message WmInitEndSession[] = {
5104 { 0x003B, sent },
5105 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
5106 { 0 }
5109 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
5110 static const struct message WmInitEndSession_2[] = {
5111 { 0x003B, sent },
5112 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
5113 { 0 }
5116 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
5117 static const struct message WmInitEndSession_3[] = {
5118 { 0x003B, sent },
5119 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
5120 { 0 }
5123 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
5124 static const struct message WmInitEndSession_4[] = {
5125 { 0x003B, sent },
5126 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
5127 { 0 }
5130 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
5131 static const struct message WmInitEndSession_5[] = {
5132 { 0x003B, sent },
5133 { WM_ENDSESSION, sent|defwinproc/*|wparam*/|lparam, 1, ENDSESSION_LOGOFF },
5134 { 0 }
5137 static const struct message WmOptionalPaint[] = {
5138 { WM_PAINT, sent|optional },
5139 { WM_NCPAINT, sent|beginpaint|optional },
5140 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5141 { WM_ERASEBKGND, sent|beginpaint|optional },
5142 { 0 }
5145 static const struct message WmZOrder[] = {
5146 { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 },
5147 { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 },
5148 { HCBT_ACTIVATE, hook },
5149 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
5150 { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 },
5151 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 },
5152 { WM_GETTEXT, sent|optional },
5153 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
5154 { WM_ACTIVATEAPP, sent|wparam, 1, 0 },
5155 { WM_NCACTIVATE, sent|lparam, 1, 0 },
5156 { WM_GETTEXT, sent|defwinproc|optional },
5157 { WM_GETTEXT, sent|defwinproc|optional },
5158 { WM_ACTIVATE, sent|wparam|lparam, 1, 0 },
5159 { HCBT_SETFOCUS, hook },
5160 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5161 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5162 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
5163 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
5164 { WM_GETTEXT, sent|optional },
5165 { WM_NCCALCSIZE, sent|optional },
5166 { 0 }
5169 static void CALLBACK apc_test_proc(ULONG_PTR param)
5171 /* nothing */
5174 static void test_MsgWaitForMultipleObjects(HWND hwnd)
5176 DWORD ret;
5177 MSG msg;
5179 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5180 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
5182 PostMessageA(hwnd, WM_USER, 0, 0);
5184 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5185 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
5187 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5188 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5190 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5191 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
5193 PostMessageA(hwnd, WM_USER, 0, 0);
5195 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5196 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
5198 ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
5199 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5201 /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
5202 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5203 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
5205 PostMessageA(hwnd, WM_USER, 0, 0);
5207 /* new incoming message causes it to become signaled again */
5208 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5209 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
5211 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5212 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5213 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5214 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5216 /* MWMO_INPUTAVAILABLE should succeed even if the message was already seen */
5217 PostMessageA( hwnd, WM_USER, 0, 0 );
5218 ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
5219 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5221 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_INPUTAVAILABLE );
5222 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5224 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5225 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5227 /* without MWMO_ALERTABLE the result is never WAIT_IO_COMPLETION */
5228 ret = QueueUserAPC( apc_test_proc, GetCurrentThread(), 0 );
5229 ok(ret, "QueueUserAPC failed %u\n", GetLastError());
5231 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, 0 );
5232 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5234 /* but even with MWMO_ALERTABLE window events are preferred */
5235 PostMessageA( hwnd, WM_USER, 0, 0 );
5237 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_ALERTABLE );
5238 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5240 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5241 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5243 /* the APC call is still queued */
5244 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_ALERTABLE );
5245 ok(ret == WAIT_IO_COMPLETION, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5248 static void test_WM_DEVICECHANGE(HWND hwnd)
5250 DWORD ret;
5251 MSG msg;
5252 int i;
5253 static const WPARAM wparams[] = {0,
5254 DBT_DEVNODES_CHANGED,
5255 DBT_QUERYCHANGECONFIG,
5256 DBT_CONFIGCHANGED,
5257 DBT_CONFIGCHANGECANCELED,
5258 DBT_NO_DISK_SPACE,
5259 DBT_LOW_DISK_SPACE,
5260 DBT_CONFIGMGPRIVATE, /* 0x7fff */
5261 DBT_DEVICEARRIVAL, /* 0x8000 */
5262 DBT_DEVICEQUERYREMOVE,
5263 DBT_DEVICEQUERYREMOVEFAILED,
5264 DBT_DEVICEREMOVEPENDING,
5265 DBT_DEVICEREMOVECOMPLETE,
5266 DBT_DEVICETYPESPECIFIC,
5267 DBT_CUSTOMEVENT};
5269 for (i = 0; i < ARRAY_SIZE(wparams); i++)
5271 SetLastError(0xdeadbeef);
5272 ret = PostMessageA(hwnd, WM_DEVICECHANGE, wparams[i], 0);
5273 if (wparams[i] & 0x8000)
5275 ok(ret == FALSE, "PostMessage should returned %d\n", ret);
5276 ok(GetLastError() == ERROR_MESSAGE_SYNC_ONLY, "PostMessage error %08x\n", GetLastError());
5278 else
5280 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5281 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
5282 memset(&msg, 0, sizeof(msg));
5283 ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should succeed\n");
5284 ok(msg.message == WM_DEVICECHANGE, "got %04x instead of WM_DEVICECHANGE\n", msg.message);
5289 static DWORD CALLBACK hide_window_thread( LPVOID arg )
5291 HWND hwnd = arg;
5293 /* function will not return if ShowWindow(SW_HIDE) calls SendMessage() */
5294 ok(ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow(SW_HIDE) expected FALSE\n");
5296 return 0;
5299 static DWORD CALLBACK show_window_thread( LPVOID arg )
5301 HWND hwnd = arg;
5303 /* function will not return if ShowWindow(SW_SHOW) calls SendMessage() */
5304 ok( ShowWindow( hwnd, SW_SHOW ), "ShowWindow(SW_SHOW) expected TRUE\n" ); /* actually it's 24... */
5306 return 0;
5309 /* Helper function to easier test SetWindowPos messages */
5310 #define test_msg_setpos( expected_list, flags, todo ) \
5311 test_msg_setpos_( (expected_list), (flags), (todo), __FILE__, __LINE__)
5312 static void test_msg_setpos_(const struct message *expected_list, UINT flags, BOOL todo, const char *file, int line)
5314 HWND hwnd;
5316 flush_events();
5317 flush_sequence();
5318 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5319 10, 10, 100, 100, NULL, 0, 0, NULL );
5320 ok (hwnd != 0, "Failed to create popup window\n");
5321 SetWindowPos(hwnd, NULL, 0, 0, 100, 100, flags);
5322 ok_sequence_(expected_list, "SetWindowPos:show_popup_first_show_window", todo, file, line);
5323 DestroyWindow(hwnd);
5326 /* test if we receive the right sequence of messages */
5327 static void test_messages(void)
5329 DWORD tid;
5330 HANDLE hthread;
5331 HWND hwnd, hparent, hchild;
5332 HWND hchild2, hbutton;
5333 HMENU hmenu;
5334 MSG msg;
5335 LRESULT res;
5336 POINT pos;
5337 BOOL ret;
5339 flush_sequence();
5341 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5342 100, 100, 200, 200, 0, 0, 0, NULL);
5343 ok (hwnd != 0, "Failed to create overlapped window\n");
5344 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
5346 /* test ShowWindow(SW_HIDE) on a newly created invisible window */
5347 ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
5348 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
5350 /* test WM_SETREDRAW on a not visible top level window */
5351 test_WM_SETREDRAW(hwnd);
5353 SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5354 flush_events();
5355 ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
5356 ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
5358 ok(GetActiveWindow() == hwnd, "window should be active\n");
5359 ok(GetFocus() == hwnd, "window should have input focus\n");
5360 ShowWindow(hwnd, SW_HIDE);
5361 flush_events();
5362 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5364 /* test ShowWindow(SW_HIDE) on a hidden window - single threaded */
5365 ok(ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow(SW_HIDE) expected FALSE\n");
5366 flush_events();
5367 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5369 /* test ShowWindow(SW_HIDE) on a hidden window - multi-threaded */
5370 hthread = CreateThread( NULL, 0, hide_window_thread, hwnd, 0, &tid );
5371 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
5372 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5373 CloseHandle(hthread);
5374 flush_events();
5375 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5377 ShowWindow(hwnd, SW_SHOW);
5378 flush_events();
5379 ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
5381 /* test ShowWindow(SW_SHOW) on a visible window - multi-threaded */
5382 hthread = CreateThread( NULL, 0, show_window_thread, hwnd, 0, &tid );
5383 ok( hthread != NULL, "CreateThread failed, error %d\n", GetLastError() );
5384 ok( WaitForSingleObject( hthread, INFINITE ) == WAIT_OBJECT_0, "WaitForSingleObject failed\n" );
5385 CloseHandle( hthread );
5386 flush_events();
5387 ok_sequence( WmEmptySeq, "ShowWindow(SW_SHOW):overlapped", FALSE );
5389 ShowWindow(hwnd, SW_HIDE);
5390 flush_events();
5391 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5393 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5394 flush_events();
5395 ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
5396 flush_sequence();
5398 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZE)
5400 ShowWindow(hwnd, SW_RESTORE);
5401 flush_events();
5402 ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
5403 flush_sequence();
5406 ShowWindow(hwnd, SW_MINIMIZE);
5407 flush_events();
5408 ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
5409 flush_sequence();
5411 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)
5413 ShowWindow(hwnd, SW_RESTORE);
5414 flush_events();
5415 ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", FALSE);
5416 flush_sequence();
5419 ShowWindow(hwnd, SW_SHOW);
5420 flush_events();
5421 ok_sequence(WmOptionalPaint, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
5423 SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5424 ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
5425 ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
5426 ok(GetActiveWindow() == hwnd, "window should still be active\n");
5428 /* test WM_SETREDRAW on a visible top level window */
5429 ShowWindow(hwnd, SW_SHOW);
5430 flush_events();
5431 test_WM_SETREDRAW(hwnd);
5433 trace("testing scroll APIs on a visible top level window %p\n", hwnd);
5434 test_scroll_messages(hwnd);
5436 /* test resizing and moving */
5437 SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
5438 ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
5439 flush_events();
5440 flush_sequence();
5441 SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
5442 ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
5443 flush_events();
5444 flush_sequence();
5445 SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER|SWP_NOACTIVATE );
5446 ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
5447 flush_events();
5448 flush_sequence();
5450 /* popups don't get WM_GETMINMAXINFO */
5451 SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
5452 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
5453 flush_sequence();
5454 SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
5455 ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
5457 DestroyWindow(hwnd);
5458 ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
5460 /* Test if windows are correctly drawn when first shown */
5462 /* Visible, redraw */
5463 flush_events();
5464 flush_sequence();
5465 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5466 10, 10, 100, 100, NULL, 0, 0, NULL );
5467 ok (hwnd != 0, "Failed to create popup window\n");
5468 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
5469 ok_sequence(WmShowPopupFirstDrawSeq_1, "RedrawWindow:show_popup_first_draw_visible", FALSE);
5470 DestroyWindow(hwnd);
5472 /* Invisible, show, message */
5473 flush_events();
5474 flush_sequence();
5475 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5476 10, 10, 100, 100, NULL, 0, 0, NULL );
5477 ok (hwnd != 0, "Failed to create popup window\n");
5478 ShowWindow(hwnd, SW_SHOW);
5479 SendMessageW(hwnd, WM_PAINT, 0, 0);
5480 ok_sequence(WmShowPopupFirstDrawSeq_1, "RedrawWindow:show_popup_first_draw_show", FALSE);
5481 DestroyWindow(hwnd);
5483 /* Invisible, show maximized, redraw */
5484 flush_events();
5485 flush_sequence();
5486 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5487 10, 10, 100, 100, NULL, 0, 0, NULL );
5488 ok (hwnd != 0, "Failed to create popup window\n");
5489 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5490 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
5491 ok_sequence(WmShowPopupFirstDrawSeq_2, "RedrawWindow:show_popup_first_draw_show_maximized", FALSE);
5492 DestroyWindow(hwnd);
5494 /* Test SetWindowPos */
5495 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW, FALSE);
5496 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, 0, FALSE);
5497 test_msg_setpos(WmFirstDrawSetWindowPosSeq3,
5498 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER, FALSE);
5500 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOSIZE, FALSE);
5501 test_msg_setpos(WmFirstDrawSetWindowPosSeq4, SWP_SHOWWINDOW | SWP_NOMOVE, FALSE);
5502 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCLIENTSIZE, FALSE);
5503 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCLIENTMOVE, FALSE);
5504 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOZORDER, FALSE);
5506 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE, FALSE);
5507 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOCLIENTMOVE, FALSE);
5508 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOCLIENTSIZE, FALSE);
5509 test_msg_setpos(WmFirstDrawSetWindowPosSeq5, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOMOVE, FALSE);
5510 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOSIZE, FALSE);
5511 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOZORDER, FALSE);
5513 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS, FALSE);
5514 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOCLIENTMOVE, FALSE);
5515 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOCLIENTSIZE, FALSE);
5516 test_msg_setpos(WmFirstDrawSetWindowPosSeq4, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOMOVE, FALSE);
5517 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOSIZE, FALSE);
5518 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOZORDER, FALSE);
5520 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW, FALSE);
5521 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCLIENTMOVE, FALSE);
5522 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCLIENTSIZE, FALSE);
5523 test_msg_setpos(WmFirstDrawSetWindowPosSeq5, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOMOVE, FALSE);
5524 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOSIZE, FALSE);
5525 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOZORDER, FALSE);
5527 /* Test SetWindowPos with child windows */
5528 flush_events();
5529 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5530 100, 100, 200, 200, 0, 0, 0, NULL);
5531 ok (hparent != 0, "Failed to create parent window\n");
5533 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5534 0, 0, 10, 10, hparent, 0, 0, NULL);
5535 ok (hchild != 0, "Failed to create child window\n");
5536 flush_sequence();
5537 SetWindowPos(hparent, NULL, 0, 0, 100, 100, SWP_SHOWWINDOW);
5538 ok_sequence(WmFirstDrawChildSeq1, /* Expect no messages for the child */
5539 "SetWindowPos:show_popup_first_show_window_child1", FALSE);
5540 DestroyWindow(hchild);
5541 DestroyWindow(hparent);
5543 flush_events();
5544 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN,
5545 100, 100, 200, 200, 0, 0, 0, NULL);
5546 ok (hparent != 0, "Failed to create parent window\n");
5548 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5549 0, 0, 10, 10, hparent, 0, 0, NULL);
5550 ok (hchild != 0, "Failed to create child window\n");
5551 flush_sequence();
5552 SetWindowPos(hparent, NULL, 0, 0, 100, 100, SWP_SHOWWINDOW);
5553 ok_sequence(WmFirstDrawChildSeq2, /* Expect child to be redrawn */
5554 "SetWindowPos:show_popup_first_show_window_child2", FALSE);
5555 DestroyWindow(hchild);
5556 DestroyWindow(hparent);
5558 /* Test message sequence for extreme position and size */
5560 flush_sequence();
5561 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5562 -10, -10, 10000, 10000, NULL, 0, 0, NULL );
5563 ok (hwnd != 0, "Failed to create popup window\n");
5564 ok_sequence(WmShowPopupExtremeLocationSeq, "RedrawWindow:show_popup_extreme_location", FALSE);
5565 DestroyWindow(hwnd);
5568 /* Test child windows */
5570 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5571 100, 100, 200, 200, 0, 0, 0, NULL);
5572 ok (hparent != 0, "Failed to create parent window\n");
5573 flush_sequence();
5575 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
5576 0, 0, 10, 10, hparent, 0, 0, NULL);
5577 ok (hchild != 0, "Failed to create child window\n");
5578 ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
5579 DestroyWindow(hchild);
5580 flush_sequence();
5582 /* visible child window with a caption */
5583 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
5584 WS_CHILD | WS_VISIBLE | WS_CAPTION,
5585 0, 0, 10, 10, hparent, 0, 0, NULL);
5586 ok (hchild != 0, "Failed to create child window\n");
5587 ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
5589 trace("testing scroll APIs on a visible child window %p\n", hchild);
5590 test_scroll_messages(hchild);
5592 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5593 ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
5595 DestroyWindow(hchild);
5596 flush_sequence();
5598 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5599 0, 0, 10, 10, hparent, 0, 0, NULL);
5600 ok (hchild != 0, "Failed to create child window\n");
5601 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
5603 hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
5604 100, 100, 50, 50, hparent, 0, 0, NULL);
5605 ok (hchild2 != 0, "Failed to create child2 window\n");
5606 flush_sequence();
5608 hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
5609 0, 100, 50, 50, hchild, 0, 0, NULL);
5610 ok (hbutton != 0, "Failed to create button window\n");
5612 /* test WM_SETREDRAW on a not visible child window */
5613 test_WM_SETREDRAW(hchild);
5615 ShowWindow(hchild, SW_SHOW);
5616 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5618 /* check parent messages too */
5619 log_all_parent_messages++;
5620 ShowWindow(hchild, SW_HIDE);
5621 ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
5622 log_all_parent_messages--;
5624 ShowWindow(hchild, SW_SHOW);
5625 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5627 ShowWindow(hchild, SW_HIDE);
5628 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
5630 ShowWindow(hchild, SW_SHOW);
5631 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5633 /* test WM_SETREDRAW on a visible child window */
5634 test_WM_SETREDRAW(hchild);
5636 log_all_parent_messages++;
5637 MoveWindow(hchild, 10, 10, 20, 20, TRUE);
5638 ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
5639 log_all_parent_messages--;
5641 ShowWindow(hchild, SW_HIDE);
5642 flush_sequence();
5643 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5644 ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
5646 ShowWindow(hchild, SW_HIDE);
5647 flush_sequence();
5648 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
5649 ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
5651 /* DestroyWindow sequence below expects that a child has focus */
5652 SetFocus(hchild);
5653 flush_sequence();
5655 DestroyWindow(hchild);
5656 ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
5657 DestroyWindow(hchild2);
5658 DestroyWindow(hbutton);
5660 flush_sequence();
5661 hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
5662 0, 0, 100, 100, hparent, 0, 0, NULL);
5663 ok (hchild != 0, "Failed to create child popup window\n");
5664 ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
5665 DestroyWindow(hchild);
5667 /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
5668 flush_sequence();
5669 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
5670 0, 0, 100, 100, hparent, 0, 0, NULL);
5671 ok (hchild != 0, "Failed to create popup window\n");
5672 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
5673 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5674 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
5675 flush_sequence();
5676 ShowWindow(hchild, SW_SHOW);
5677 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
5678 flush_sequence();
5679 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5680 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
5681 flush_sequence();
5682 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5683 ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
5684 DestroyWindow(hchild);
5686 /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
5687 * changes nothing in message sequences.
5689 flush_sequence();
5690 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5691 0, 0, 100, 100, hparent, 0, 0, NULL);
5692 ok (hchild != 0, "Failed to create popup window\n");
5693 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
5694 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5695 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
5696 flush_sequence();
5697 ShowWindow(hchild, SW_SHOW);
5698 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
5699 flush_sequence();
5700 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5701 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
5702 DestroyWindow(hchild);
5704 flush_sequence();
5705 hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
5706 0, 0, 100, 100, hparent, 0, 0, NULL);
5707 ok(hwnd != 0, "Failed to create custom dialog window\n");
5708 ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
5710 if(0) {
5711 trace("testing scroll APIs on a visible dialog %p\n", hwnd);
5712 test_scroll_messages(hwnd);
5715 flush_sequence();
5717 test_def_id = TRUE;
5718 SendMessageA(hwnd, WM_NULL, 0, 0);
5720 flush_sequence();
5721 after_end_dialog = TRUE;
5722 EndDialog( hwnd, 0 );
5723 ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
5725 DestroyWindow(hwnd);
5726 after_end_dialog = FALSE;
5727 test_def_id = FALSE;
5729 ok(GetCursorPos(&pos), "GetCursorPos failed\n");
5730 ok(SetCursorPos(109, 109), "SetCursorPos failed\n");
5732 hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP|WS_CHILD,
5733 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
5734 ok(hwnd != 0, "Failed to create custom dialog window\n");
5735 flush_sequence();
5736 trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
5737 ShowWindow(hwnd, SW_SHOW);
5738 ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
5740 flush_events();
5741 flush_sequence();
5742 ret = DrawMenuBar(hwnd);
5743 ok(ret, "DrawMenuBar failed: %d\n", GetLastError());
5744 flush_events();
5745 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
5746 ok(SetCursorPos(pos.x, pos.y), "SetCursorPos failed\n");
5748 DestroyWindow(hwnd);
5750 hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_CHILD|WS_VISIBLE,
5751 0, 0, 100, 100, hparent, 0, GetModuleHandleA(0), NULL);
5752 ok(hwnd != 0, "Failed to create custom dialog window\n");
5753 flush_events();
5754 flush_sequence();
5755 ret = DrawMenuBar(hwnd);
5756 ok(ret, "DrawMenuBar failed: %d\n", GetLastError());
5757 flush_events();
5758 ok_sequence(WmEmptySeq, "DrawMenuBar for a child window", FALSE);
5760 DestroyWindow(hwnd);
5762 flush_sequence();
5763 DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
5764 ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
5766 DestroyWindow(hparent);
5767 flush_sequence();
5769 /* Message sequence for SetMenu */
5770 ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a destroyed window\n");
5771 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "last error is %d\n", GetLastError());
5772 ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
5774 hmenu = CreateMenu();
5775 ok (hmenu != 0, "Failed to create menu\n");
5776 ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
5777 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5778 100, 100, 200, 200, 0, hmenu, 0, NULL);
5779 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
5780 ok (SetMenu(hwnd, 0), "SetMenu\n");
5781 ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
5782 ok (SetMenu(hwnd, 0), "SetMenu\n");
5783 ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
5784 ShowWindow(hwnd, SW_SHOW);
5785 UpdateWindow( hwnd );
5786 flush_events();
5787 flush_sequence();
5788 ok (SetMenu(hwnd, 0), "SetMenu\n");
5789 ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
5790 ok (SetMenu(hwnd, hmenu), "SetMenu\n");
5791 ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
5793 UpdateWindow( hwnd );
5794 flush_events();
5795 flush_sequence();
5796 ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
5797 flush_events();
5798 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
5800 DestroyWindow(hwnd);
5801 flush_sequence();
5803 /* Message sequence for EnableWindow */
5804 hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5805 100, 100, 200, 200, 0, 0, 0, NULL);
5806 ok (hparent != 0, "Failed to create parent window\n");
5807 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5808 0, 0, 10, 10, hparent, 0, 0, NULL);
5809 ok (hchild != 0, "Failed to create child window\n");
5811 SetFocus(hchild);
5812 flush_events();
5813 flush_sequence();
5815 EnableWindow(hparent, FALSE);
5816 ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
5818 EnableWindow(hparent, FALSE);
5819 ok_sequence(WmEnableWindowSeq_2, "EnableWindow(FALSE)", FALSE);
5821 EnableWindow(hparent, TRUE);
5822 ok_sequence(WmEnableWindowSeq_3, "EnableWindow(TRUE)", FALSE);
5824 EnableWindow(hparent, TRUE);
5825 ok_sequence(WmEnableWindowSeq_4, "EnableWindow(TRUE)", FALSE);
5827 flush_events();
5828 flush_sequence();
5830 test_MsgWaitForMultipleObjects(hparent);
5831 test_WM_DEVICECHANGE(hparent);
5833 /* the following test causes an exception in user.exe under win9x */
5834 if (!PostMessageW( hparent, WM_USER, 0, 0 ))
5836 DestroyWindow(hparent);
5837 flush_sequence();
5838 return;
5840 PostMessageW( hparent, WM_USER+1, 0, 0 );
5841 /* PeekMessage(NULL) fails, but still removes the message */
5842 SetLastError(0xdeadbeef);
5843 ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
5844 ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
5845 GetLastError() == 0xdeadbeef, /* NT4 */
5846 "last error is %d\n", GetLastError() );
5847 ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
5848 ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
5850 DestroyWindow(hchild);
5851 DestroyWindow(hparent);
5852 flush_sequence();
5854 /* Message sequences for WM_SETICON */
5855 trace("testing WM_SETICON\n");
5856 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
5857 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5858 NULL, NULL, 0);
5859 ShowWindow(hwnd, SW_SHOW);
5860 UpdateWindow(hwnd);
5861 flush_events();
5862 flush_sequence();
5863 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5864 ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
5866 ShowWindow(hwnd, SW_HIDE);
5867 flush_events();
5868 flush_sequence();
5869 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5870 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
5871 DestroyWindow(hwnd);
5872 flush_sequence();
5874 hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
5875 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5876 NULL, NULL, 0);
5877 ShowWindow(hwnd, SW_SHOW);
5878 UpdateWindow(hwnd);
5879 flush_events();
5880 flush_sequence();
5881 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5882 ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
5884 ShowWindow(hwnd, SW_HIDE);
5885 flush_events();
5886 flush_sequence();
5887 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5888 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
5890 flush_sequence();
5891 res = SendMessageA(hwnd, 0x3B, 0x8000000b, 0);
5892 if (!res)
5894 todo_wine win_skip( "Message 0x3b not supported\n" );
5895 goto done;
5897 ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
5898 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res);
5899 res = SendMessageA(hwnd, 0x3B, 0x0000000b, 0);
5900 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
5901 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res);
5902 res = SendMessageA(hwnd, 0x3B, 0x0000000f, 0);
5903 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
5904 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res);
5906 flush_sequence();
5907 res = SendMessageA(hwnd, 0x3B, 0x80000008, 0);
5908 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
5909 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res);
5910 res = SendMessageA(hwnd, 0x3B, 0x00000008, 0);
5911 ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
5912 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res);
5914 res = SendMessageA(hwnd, 0x3B, 0x80000004, 0);
5915 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
5916 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res);
5918 res = SendMessageA(hwnd, 0x3B, 0x80000001, 0);
5919 ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
5920 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res);
5922 done:
5923 DestroyWindow(hwnd);
5924 flush_sequence();
5927 static const struct message WmFrameChanged[] = {
5928 { WM_WINDOWPOSCHANGING, sent|wparam|lparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE, 0 },
5929 { WM_NCCALCSIZE, sent|wparam|lparam, 1, 0xf },
5930 { WM_WINDOWPOSCHANGED, sent|wparam|lparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW
5931 |SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0xf },
5932 { WM_GETTEXT, sent|optional },
5933 { 0 }
5936 static const struct message WmFrameChanged_move[] = {
5937 { WM_WINDOWPOSCHANGING, sent|wparam|lparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE, 0 },
5938 { WM_NCCALCSIZE, sent|wparam|lparam, 1, 0x3 },
5939 { WM_WINDOWPOSCHANGED, sent|wparam|lparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW
5940 |SWP_NOSIZE|SWP_NOCLIENTSIZE, 0x3 },
5941 { WM_MOVE, sent|defwinproc, 0 },
5942 { WM_GETTEXT, sent|optional },
5943 { 0 }
5946 static void test_setwindowpos(void)
5948 HWND hwnd;
5949 RECT rc;
5950 LRESULT res;
5951 const INT X = 50;
5952 const INT Y = 50;
5953 const INT winX = 100;
5954 const INT winY = 100;
5955 const INT sysX = GetSystemMetrics(SM_CXMINTRACK);
5957 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
5958 X, Y, winX, winY, 0,
5959 NULL, NULL, 0);
5961 GetWindowRect(hwnd, &rc);
5962 expect(sysX + X, rc.right);
5963 expect(winY + Y, rc.bottom);
5965 flush_events();
5966 flush_sequence();
5967 res = SetWindowPos(hwnd, HWND_TOPMOST, 50, 50, winX, winY, 0);
5968 ok_sequence(WmZOrder, "Z-Order", TRUE);
5969 ok(res == TRUE, "SetWindowPos expected TRUE, got %ld\n", res);
5971 GetWindowRect(hwnd, &rc);
5972 expect(sysX + X, rc.right);
5973 expect(winY + Y, rc.bottom);
5975 res = SetWindowPos( hwnd, 0, 0, 0, 0, 0,
5976 SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
5977 ok_sequence(WmFrameChanged, "FrameChanged", FALSE);
5978 ok(res == TRUE, "SetWindowPos expected TRUE, got %ld.\n", res);
5980 GetWindowRect(hwnd, &rc);
5981 expect(sysX + X, rc.right);
5982 expect(winY + Y, rc.bottom);
5984 res = SetWindowPos( hwnd, 0, 0, 0, 0, 0,
5985 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
5986 ok_sequence(WmFrameChanged_move, "FrameChanged", FALSE);
5987 ok(res == TRUE, "SetWindowPos expected TRUE, got %ld.\n", res);
5989 GetWindowRect(hwnd, &rc);
5990 expect(sysX, rc.right);
5991 expect(winY, rc.bottom);
5993 DestroyWindow(hwnd);
5996 static void invisible_parent_tests(void)
5998 HWND hparent, hchild;
6000 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
6001 100, 100, 200, 200, 0, 0, 0, NULL);
6002 ok (hparent != 0, "Failed to create parent window\n");
6003 flush_sequence();
6005 /* test showing child with hidden parent */
6007 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6008 0, 0, 10, 10, hparent, 0, 0, NULL);
6009 ok (hchild != 0, "Failed to create child window\n");
6010 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
6012 ShowWindow( hchild, SW_MINIMIZE );
6013 ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
6014 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6015 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6017 /* repeat */
6018 flush_events();
6019 flush_sequence();
6020 ShowWindow( hchild, SW_MINIMIZE );
6021 ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
6023 DestroyWindow(hchild);
6024 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6025 0, 0, 10, 10, hparent, 0, 0, NULL);
6026 flush_sequence();
6028 ShowWindow( hchild, SW_MAXIMIZE );
6029 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
6030 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6031 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6033 /* repeat */
6034 flush_events();
6035 flush_sequence();
6036 ShowWindow( hchild, SW_MAXIMIZE );
6037 ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
6039 DestroyWindow(hchild);
6040 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6041 0, 0, 10, 10, hparent, 0, 0, NULL);
6042 flush_sequence();
6044 ShowWindow( hchild, SW_RESTORE );
6045 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
6046 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6047 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6049 DestroyWindow(hchild);
6050 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6051 0, 0, 10, 10, hparent, 0, 0, NULL);
6052 flush_sequence();
6054 ShowWindow( hchild, SW_SHOWMINIMIZED );
6055 ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
6056 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6057 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6059 /* repeat */
6060 flush_events();
6061 flush_sequence();
6062 ShowWindow( hchild, SW_SHOWMINIMIZED );
6063 ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
6065 DestroyWindow(hchild);
6066 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6067 0, 0, 10, 10, hparent, 0, 0, NULL);
6068 flush_sequence();
6070 /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
6071 ShowWindow( hchild, SW_SHOWMAXIMIZED );
6072 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
6073 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6074 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6076 DestroyWindow(hchild);
6077 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6078 0, 0, 10, 10, hparent, 0, 0, NULL);
6079 flush_sequence();
6081 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
6082 ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
6083 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6084 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6086 /* repeat */
6087 flush_events();
6088 flush_sequence();
6089 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
6090 ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
6092 DestroyWindow(hchild);
6093 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6094 0, 0, 10, 10, hparent, 0, 0, NULL);
6095 flush_sequence();
6097 /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
6098 ShowWindow( hchild, SW_FORCEMINIMIZE );
6099 ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
6100 todo_wine {
6101 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
6103 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6105 DestroyWindow(hchild);
6106 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6107 0, 0, 10, 10, hparent, 0, 0, NULL);
6108 flush_sequence();
6110 ShowWindow( hchild, SW_SHOWNA );
6111 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
6112 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6113 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6115 /* repeat */
6116 flush_events();
6117 flush_sequence();
6118 ShowWindow( hchild, SW_SHOWNA );
6119 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
6121 DestroyWindow(hchild);
6122 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
6123 0, 0, 10, 10, hparent, 0, 0, NULL);
6124 flush_sequence();
6126 ShowWindow( hchild, SW_SHOW );
6127 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
6128 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6129 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6131 /* repeat */
6132 flush_events();
6133 flush_sequence();
6134 ShowWindow( hchild, SW_SHOW );
6135 ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
6137 ShowWindow( hchild, SW_HIDE );
6138 ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
6139 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
6140 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6142 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
6143 ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
6144 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
6145 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6147 SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
6148 ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
6149 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
6150 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
6152 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
6153 flush_sequence();
6154 DestroyWindow(hchild);
6155 ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
6157 DestroyWindow(hparent);
6158 flush_sequence();
6161 /****************** button message test *************************/
6162 #define ID_BUTTON 0x000e
6164 static const struct message WmSetFocusButtonSeq[] =
6166 { HCBT_SETFOCUS, hook },
6167 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
6168 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
6169 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6170 { WM_SETFOCUS, sent|wparam, 0 },
6171 { WM_CTLCOLORBTN, sent|parent },
6172 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
6173 { WM_APP, sent|wparam|lparam, 0, 0 },
6174 { 0 }
6176 static const struct message WmKillFocusButtonSeq[] =
6178 { HCBT_SETFOCUS, hook },
6179 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6180 { WM_KILLFOCUS, sent|wparam, 0 },
6181 { WM_CTLCOLORBTN, sent|parent },
6182 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
6183 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
6184 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
6185 { WM_APP, sent|wparam|lparam, 0, 0 },
6186 { WM_PAINT, sent },
6187 { WM_CTLCOLORBTN, sent|parent },
6188 { 0 }
6190 static const struct message WmSetFocusStaticSeq[] =
6192 { HCBT_SETFOCUS, hook },
6193 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
6194 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
6195 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6196 { WM_SETFOCUS, sent|wparam, 0 },
6197 { WM_CTLCOLORSTATIC, sent|parent },
6198 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
6199 { WM_COMMAND, sent|wparam|parent|optional, MAKEWPARAM(ID_BUTTON, BN_CLICKED) }, /* radio button */
6200 { WM_APP, sent|wparam|lparam, 0, 0 },
6201 { 0 }
6203 static const struct message WmKillFocusStaticSeq[] =
6205 { HCBT_SETFOCUS, hook },
6206 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6207 { WM_KILLFOCUS, sent|wparam, 0 },
6208 { WM_CTLCOLORSTATIC, sent|parent },
6209 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
6210 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
6211 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
6212 { WM_APP, sent|wparam|lparam, 0, 0 },
6213 { WM_PAINT, sent },
6214 { WM_CTLCOLORSTATIC, sent|parent },
6215 { 0 }
6217 static const struct message WmSetFocusOwnerdrawSeq[] =
6219 { HCBT_SETFOCUS, hook },
6220 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
6221 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
6222 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6223 { WM_SETFOCUS, sent|wparam, 0 },
6224 { WM_CTLCOLORBTN, sent|parent },
6225 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x001040e4 },
6226 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
6227 { WM_APP, sent|wparam|lparam, 0, 0 },
6228 { 0 }
6230 static const struct message WmKillFocusOwnerdrawSeq[] =
6232 { HCBT_SETFOCUS, hook },
6233 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6234 { WM_KILLFOCUS, sent|wparam, 0 },
6235 { WM_CTLCOLORBTN, sent|parent },
6236 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000040e4 },
6237 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
6238 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
6239 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
6240 { WM_APP, sent|wparam|lparam, 0, 0 },
6241 { WM_PAINT, sent },
6242 { WM_CTLCOLORBTN, sent|parent },
6243 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
6244 { 0 }
6246 static const struct message WmLButtonDownSeq[] =
6248 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
6249 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6250 { HCBT_SETFOCUS, hook },
6251 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
6252 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
6253 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6254 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
6255 { WM_CTLCOLORBTN, sent|defwinproc },
6256 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
6257 { WM_CTLCOLORBTN, sent|defwinproc },
6258 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6259 { 0 }
6261 static const struct message WmLButtonDownStaticSeq[] =
6263 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
6264 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6265 { HCBT_SETFOCUS, hook },
6266 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
6267 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
6268 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6269 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
6270 { WM_CTLCOLORSTATIC, sent|defwinproc },
6271 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
6272 { WM_CTLCOLORSTATIC, sent|defwinproc },
6273 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6274 { 0 }
6276 static const struct message WmLButtonUpSeq[] =
6278 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6279 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6280 { WM_CTLCOLORBTN, sent|defwinproc },
6281 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6282 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6283 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6284 { 0 }
6286 static const struct message WmLButtonUpStaticSeq[] =
6288 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6289 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6290 { WM_CTLCOLORSTATIC, sent|defwinproc },
6291 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6292 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6293 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6294 { 0 }
6296 static const struct message WmLButtonUpAutoSeq[] =
6298 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6299 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6300 { WM_CTLCOLORSTATIC, sent|defwinproc },
6301 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6302 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6303 { BM_SETCHECK, sent|defwinproc },
6304 { WM_CTLCOLORSTATIC, sent|defwinproc, 0, 0 },
6305 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6306 { 0 }
6308 static const struct message WmLButtonUpBrokenSeq[] =
6310 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6311 { 0 }
6313 static const struct message WmSetFontButtonSeq[] =
6315 { WM_SETFONT, sent },
6316 { WM_PAINT, sent },
6317 { WM_ERASEBKGND, sent|defwinproc|optional },
6318 { WM_CTLCOLORBTN, sent|defwinproc },
6319 { WM_CTLCOLORBTN, sent|defwinproc|optional }, /* FIXME: Wine sends it twice for BS_OWNERDRAW */
6320 { 0 }
6322 static const struct message WmSetFontStaticSeq[] =
6324 { WM_SETFONT, sent },
6325 { WM_PAINT, sent },
6326 { WM_ERASEBKGND, sent|defwinproc|optional },
6327 { WM_CTLCOLORSTATIC, sent|defwinproc },
6328 { 0 }
6330 static const struct message WmSetTextButtonSeq[] =
6332 { WM_SETTEXT, sent },
6333 { WM_CTLCOLORBTN, sent|parent },
6334 { WM_CTLCOLORBTN, sent|parent },
6335 { WM_COMMAND, sent|parent|optional },
6336 { WM_DRAWITEM, sent|parent|optional },
6337 { 0 }
6339 static const struct message WmSetTextStaticSeq[] =
6341 { WM_SETTEXT, sent },
6342 { WM_CTLCOLORSTATIC, sent|parent },
6343 { WM_CTLCOLORSTATIC, sent|parent },
6344 { 0 }
6346 static const struct message WmSetTextGroupSeq[] =
6348 { WM_SETTEXT, sent },
6349 { WM_CTLCOLORSTATIC, sent|parent },
6350 { WM_CTLCOLORSTATIC, sent|parent|optional }, /* FIXME: Missing in Wine */
6351 { WM_CTLCOLORSTATIC, sent|parent|optional }, /* FIXME: Missing in Wine */
6352 { 0 }
6354 static const struct message WmSetTextInvisibleSeq[] =
6356 { WM_SETTEXT, sent },
6357 { 0 }
6359 static const struct message WmSetStyleButtonSeq[] =
6361 { BM_SETSTYLE, sent },
6362 { WM_APP, sent|wparam|lparam, 0, 0 },
6363 { WM_PAINT, sent },
6364 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6365 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6366 { WM_CTLCOLORBTN, sent|parent },
6367 { 0 }
6369 static const struct message WmSetStyleStaticSeq[] =
6371 { BM_SETSTYLE, sent },
6372 { WM_APP, sent|wparam|lparam, 0, 0 },
6373 { WM_PAINT, sent },
6374 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6375 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6376 { WM_CTLCOLORSTATIC, sent|parent },
6377 { 0 }
6379 static const struct message WmSetStyleUserSeq[] =
6381 { BM_SETSTYLE, sent },
6382 { WM_APP, sent|wparam|lparam, 0, 0 },
6383 { WM_PAINT, sent },
6384 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6385 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6386 { WM_CTLCOLORBTN, sent|parent },
6387 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_PAINT) },
6388 { 0 }
6390 static const struct message WmSetStyleOwnerdrawSeq[] =
6392 { BM_SETSTYLE, sent },
6393 { WM_APP, sent|wparam|lparam, 0, 0 },
6394 { WM_PAINT, sent },
6395 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
6396 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6397 { WM_CTLCOLORBTN, sent|parent },
6398 { WM_CTLCOLORBTN, sent|parent|optional }, /* Win9x doesn't send it */
6399 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
6400 { 0 }
6402 static const struct message WmSetStateButtonSeq[] =
6404 { BM_SETSTATE, sent },
6405 { WM_CTLCOLORBTN, sent|parent },
6406 { WM_APP, sent|wparam|lparam, 0, 0 },
6407 { 0 }
6409 static const struct message WmSetStateStaticSeq[] =
6411 { BM_SETSTATE, sent },
6412 { WM_CTLCOLORSTATIC, sent|parent },
6413 { WM_APP, sent|wparam|lparam, 0, 0 },
6414 { 0 }
6416 static const struct message WmSetStateUserSeq[] =
6418 { BM_SETSTATE, sent },
6419 { WM_CTLCOLORBTN, sent|parent },
6420 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_HILITE) },
6421 { WM_APP, sent|wparam|lparam, 0, 0 },
6422 { 0 }
6424 static const struct message WmSetStateOwnerdrawSeq[] =
6426 { BM_SETSTATE, sent },
6427 { WM_CTLCOLORBTN, sent|parent },
6428 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000120e4 },
6429 { WM_APP, sent|wparam|lparam, 0, 0 },
6430 { 0 }
6432 static const struct message WmClearStateButtonSeq[] =
6434 { BM_SETSTATE, sent },
6435 { WM_CTLCOLORBTN, sent|parent },
6436 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_UNHILITE) },
6437 { WM_APP, sent|wparam|lparam, 0, 0 },
6438 { 0 }
6440 static const struct message WmDisableButtonSeq[] =
6442 { WM_LBUTTONDOWN, sent },
6443 { BM_SETSTATE, sent|defwinproc },
6444 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6445 { WM_CTLCOLORBTN, sent|optional },
6446 { WM_LBUTTONUP, sent },
6447 { BM_SETSTATE, sent|defwinproc },
6448 { WM_CTLCOLORBTN, sent|defwinproc|optional },
6449 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6450 { BM_SETCHECK, sent|defwinproc|optional },
6451 { WM_CTLCOLORBTN, sent|optional },
6452 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6453 { WM_CAPTURECHANGED, sent|defwinproc },
6454 { WM_COMMAND, sent },
6455 { 0 }
6457 static const struct message WmClearStateOwnerdrawSeq[] =
6459 { BM_SETSTATE, sent },
6460 { WM_CTLCOLORBTN, sent|parent },
6461 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000020e4 },
6462 { WM_APP, sent|wparam|lparam, 0, 0 },
6463 { 0 }
6465 static const struct message WmSetCheckIgnoredSeq[] =
6467 { BM_SETCHECK, sent },
6468 { WM_APP, sent|wparam|lparam, 0, 0 },
6469 { 0 }
6471 static const struct message WmSetCheckStaticSeq[] =
6473 { BM_SETCHECK, sent },
6474 { WM_CTLCOLORSTATIC, sent|parent },
6475 { WM_APP, sent|wparam|lparam, 0, 0 },
6476 { 0 }
6479 static WNDPROC old_button_proc;
6481 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6483 static LONG defwndproc_counter = 0;
6484 LRESULT ret;
6485 struct recvd_message msg;
6487 if (ignore_message( message )) return 0;
6489 switch (message)
6491 case WM_SYNCPAINT:
6492 break;
6493 case BM_SETSTATE:
6494 if (GetCapture())
6495 ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
6497 lParam = (ULONG_PTR)GetMenu(hwnd);
6498 goto log_it;
6500 case WM_GETDLGCODE:
6501 if (lParam)
6503 MSG *msg = (MSG *)lParam;
6504 lParam = MAKELPARAM(msg->message, msg->wParam);
6506 wParam = (ULONG_PTR)GetMenu(hwnd);
6507 goto log_it;
6509 case BM_SETCHECK:
6510 case BM_GETCHECK:
6511 lParam = (ULONG_PTR)GetMenu(hwnd);
6512 /* fall through */
6513 log_it:
6514 default:
6515 msg.hwnd = hwnd;
6516 msg.message = message;
6517 msg.flags = sent|wparam|lparam;
6518 if (defwndproc_counter) msg.flags |= defwinproc;
6519 msg.wParam = wParam;
6520 msg.lParam = lParam;
6521 msg.descr = "button";
6522 add_message(&msg);
6525 defwndproc_counter++;
6526 ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
6527 defwndproc_counter--;
6529 return ret;
6532 static void subclass_button(void)
6534 WNDCLASSA cls;
6536 if (!GetClassInfoA(0, "button", &cls)) assert(0);
6538 old_button_proc = cls.lpfnWndProc;
6540 cls.hInstance = GetModuleHandleA(NULL);
6541 cls.lpfnWndProc = button_hook_proc;
6542 cls.lpszClassName = "my_button_class";
6543 UnregisterClassA(cls.lpszClassName, cls.hInstance);
6544 if (!RegisterClassA(&cls)) assert(0);
6547 static void test_button_messages(void)
6549 static const struct
6551 DWORD style;
6552 DWORD dlg_code;
6553 const struct message *setfocus;
6554 const struct message *killfocus;
6555 const struct message *setstyle;
6556 const struct message *setstate;
6557 const struct message *clearstate;
6558 const struct message *setcheck;
6559 const struct message *lbuttondown;
6560 const struct message *lbuttonup;
6561 const struct message *setfont;
6562 const struct message *settext;
6563 } button[] = {
6564 { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
6565 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
6566 WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq,
6567 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6568 WmSetTextButtonSeq },
6569 { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
6570 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
6571 WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq,
6572 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6573 WmSetTextButtonSeq },
6574 { BS_CHECKBOX, DLGC_BUTTON,
6575 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6576 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6577 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6578 WmSetTextStaticSeq },
6579 { BS_AUTOCHECKBOX, DLGC_BUTTON,
6580 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6581 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6582 WmLButtonDownStaticSeq, WmLButtonUpAutoSeq, WmSetFontStaticSeq,
6583 WmSetTextStaticSeq },
6584 { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
6585 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6586 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6587 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6588 WmSetTextStaticSeq },
6589 { BS_3STATE, DLGC_BUTTON,
6590 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6591 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6592 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6593 WmSetTextStaticSeq },
6594 { BS_AUTO3STATE, DLGC_BUTTON,
6595 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6596 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6597 WmLButtonDownStaticSeq, WmLButtonUpAutoSeq, WmSetFontStaticSeq,
6598 WmSetTextStaticSeq },
6599 { BS_GROUPBOX, DLGC_STATIC,
6600 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6601 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckIgnoredSeq,
6602 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6603 WmSetTextGroupSeq },
6604 { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
6605 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleUserSeq,
6606 WmSetStateUserSeq, WmClearStateButtonSeq, WmSetCheckIgnoredSeq,
6607 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6608 WmSetTextButtonSeq },
6609 { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
6610 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6611 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6612 NULL /* avoid infinite loop */, WmLButtonUpBrokenSeq, WmSetFontStaticSeq,
6613 WmSetTextStaticSeq },
6614 { BS_OWNERDRAW, DLGC_BUTTON,
6615 WmSetFocusOwnerdrawSeq, WmKillFocusOwnerdrawSeq, WmSetStyleOwnerdrawSeq,
6616 WmSetStateOwnerdrawSeq, WmClearStateOwnerdrawSeq, WmSetCheckIgnoredSeq,
6617 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6618 WmSetTextButtonSeq },
6620 LOGFONTA logfont = { 0 };
6621 HFONT zfont, hfont2;
6622 unsigned int i;
6623 HWND hwnd, parent;
6624 DWORD dlg_code;
6626 /* selection with VK_SPACE should capture button window */
6627 hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
6628 0, 0, 50, 14, 0, 0, 0, NULL);
6629 ok(hwnd != 0, "Failed to create button window\n");
6630 ReleaseCapture();
6631 SetFocus(hwnd);
6632 SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
6633 ok(GetCapture() == hwnd, "Should be captured on VK_SPACE WM_KEYDOWN\n");
6634 SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
6635 DestroyWindow(hwnd);
6637 subclass_button();
6639 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6640 100, 100, 200, 200, 0, 0, 0, NULL);
6641 ok(parent != 0, "Failed to create parent window\n");
6643 memset(&logfont, 0, sizeof(logfont));
6644 logfont.lfHeight = -12;
6645 logfont.lfWeight = FW_NORMAL;
6646 strcpy(logfont.lfFaceName, "Tahoma");
6648 hfont2 = CreateFontIndirectA(&logfont);
6649 ok(hfont2 != NULL, "Failed to create Tahoma font\n");
6651 for (i = 0; i < ARRAY_SIZE(button); i++)
6653 MSG msg;
6654 DWORD style, state;
6655 HFONT prevfont;
6656 char desc[64];
6657 HDC hdc;
6659 trace("button style %08x\n", button[i].style);
6661 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_CHILD | BS_NOTIFY,
6662 0, 0, 50, 14, parent, (HMENU)ID_BUTTON, 0, NULL);
6663 ok(hwnd != 0, "Failed to create button window\n");
6665 style = GetWindowLongA(hwnd, GWL_STYLE);
6666 style &= ~(WS_CHILD | BS_NOTIFY);
6667 /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
6668 if (button[i].style == BS_USERBUTTON)
6669 ok(style == BS_PUSHBUTTON, "expected style BS_PUSHBUTTON got %x\n", style);
6670 else
6671 ok(style == button[i].style, "expected style %x got %x\n", button[i].style, style);
6673 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
6674 ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
6676 ShowWindow(hwnd, SW_SHOW);
6677 UpdateWindow(hwnd);
6678 SetFocus(0);
6679 flush_events();
6680 SetFocus(0);
6681 flush_sequence();
6683 log_all_parent_messages++;
6685 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
6686 SetFocus(hwnd);
6687 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6688 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6689 ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
6691 SetFocus(0);
6692 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6693 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6694 ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
6696 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
6698 SendMessageA(hwnd, BM_SETSTYLE, button[i].style | BS_BOTTOM, TRUE);
6699 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6700 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6701 ok_sequence(button[i].setstyle, "BM_SETSTYLE on a button", FALSE);
6703 style = GetWindowLongA(hwnd, GWL_STYLE);
6704 style &= ~(WS_VISIBLE | WS_CHILD | BS_NOTIFY);
6705 /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */
6706 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6708 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6709 ok(state == 0, "expected state 0, got %04x\n", state);
6711 flush_sequence();
6713 SendMessageA(hwnd, BM_SETSTATE, TRUE, 0);
6714 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6715 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6716 ok_sequence(button[i].setstate, "BM_SETSTATE/TRUE on a button", FALSE);
6718 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6719 ok(state == 0x0004, "expected state 0x0004, got %04x\n", state);
6721 style = GetWindowLongA(hwnd, GWL_STYLE);
6722 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6723 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6725 flush_sequence();
6727 SendMessageA(hwnd, BM_SETSTATE, FALSE, 0);
6728 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6729 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6730 ok_sequence(button[i].clearstate, "BM_SETSTATE/FALSE on a button", FALSE);
6732 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6733 ok(state == 0, "expected state 0, got %04x\n", state);
6735 style = GetWindowLongA(hwnd, GWL_STYLE);
6736 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6737 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6739 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6740 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
6742 flush_sequence();
6744 SendMessageA(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
6745 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6746 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6747 ok_sequence(WmSetCheckIgnoredSeq, "BM_SETCHECK on a button", FALSE);
6749 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6750 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
6752 style = GetWindowLongA(hwnd, GWL_STYLE);
6753 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6754 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6756 flush_sequence();
6758 SendMessageA(hwnd, BM_SETCHECK, BST_CHECKED, 0);
6759 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6760 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6761 ok_sequence(button[i].setcheck, "BM_SETCHECK on a button", FALSE);
6763 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 1");
6764 sprintf(desc, "button[%i]: WM_SETTEXT on a visible button", i);
6765 ok_sequence(button[i].settext, desc, FALSE);
6767 ShowWindow(hwnd, SW_HIDE);
6768 flush_events();
6769 flush_sequence();
6771 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 2");
6772 sprintf(desc, "button[%i]: WM_SETTEXT on an invisible button", i);
6773 ok_sequence(WmSetTextInvisibleSeq, desc, FALSE);
6775 ShowWindow(hwnd, SW_SHOW);
6776 ShowWindow(parent, SW_HIDE);
6777 flush_events();
6778 flush_sequence();
6780 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 3");
6781 sprintf(desc, "button[%i]: WM_SETTEXT on an invisible button", i);
6782 ok_sequence(WmSetTextInvisibleSeq, desc, FALSE);
6784 ShowWindow(parent, SW_SHOW);
6785 flush_events();
6787 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6788 if (button[i].style == BS_PUSHBUTTON ||
6789 button[i].style == BS_DEFPUSHBUTTON ||
6790 button[i].style == BS_GROUPBOX ||
6791 button[i].style == BS_USERBUTTON ||
6792 button[i].style == BS_OWNERDRAW)
6793 ok(state == BST_UNCHECKED, "expected check 0, got %04x\n", state);
6794 else
6795 ok(state == BST_CHECKED, "expected check 1, got %04x\n", state);
6797 style = GetWindowLongA(hwnd, GWL_STYLE);
6798 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6799 if (button[i].style == BS_RADIOBUTTON ||
6800 button[i].style == BS_AUTORADIOBUTTON)
6801 ok(style == (button[i].style | WS_TABSTOP), "expected style %04x | WS_TABSTOP got %04x\n", button[i].style, style);
6802 else
6803 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6805 log_all_parent_messages--;
6807 DestroyWindow(hwnd);
6809 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP | WS_VISIBLE,
6810 0, 0, 50, 14, 0, 0, 0, NULL);
6811 ok(hwnd != 0, "Failed to create button window\n");
6813 SetForegroundWindow(hwnd);
6814 flush_events();
6816 SetActiveWindow(hwnd);
6817 SetFocus(0);
6818 flush_sequence();
6820 if (button[i].lbuttondown)
6822 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
6823 sprintf(desc, "button[%i]: WM_LBUTTONDOWN on a button", i);
6824 ok_sequence(button[i].lbuttondown, desc, FALSE);
6827 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
6828 sprintf(desc, "button[%i]: WM_LBUTTONUP on a button", i);
6829 ok_sequence(button[i].lbuttonup, desc, FALSE);
6831 flush_sequence();
6832 zfont = GetStockObject(DEFAULT_GUI_FONT);
6833 SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
6834 UpdateWindow(hwnd);
6835 sprintf(desc, "button[%i]: WM_SETFONT on a button", i);
6836 ok_sequence(button[i].setfont, desc, FALSE);
6838 /* Test that original font is not selected back after painting */
6839 hdc = CreateCompatibleDC(0);
6841 prevfont = SelectObject(hdc, hfont2);
6842 ok(prevfont == GetStockObject(SYSTEM_FONT), "Unexpected default font\n");
6843 SendMessageA(hwnd, WM_PRINTCLIENT, (WPARAM)hdc, 0);
6844 ok(hfont2 != GetCurrentObject(hdc, OBJ_FONT), "button[%u]: unexpected font selected after WM_PRINTCLIENT\n", i);
6845 SelectObject(hdc, prevfont);
6847 prevfont = SelectObject(hdc, hfont2);
6848 ok(prevfont == GetStockObject(SYSTEM_FONT), "Unexpected default font\n");
6849 SendMessageA(hwnd, WM_PAINT, (WPARAM)hdc, 0);
6850 ok(hfont2 != GetCurrentObject(hdc, OBJ_FONT), "button[%u]: unexpected font selected after WM_PAINT\n", i);
6851 SelectObject(hdc, prevfont);
6853 DeleteDC(hdc);
6855 DestroyWindow(hwnd);
6858 DeleteObject(hfont2);
6859 DestroyWindow(parent);
6861 /* Test if WM_LBUTTONDOWN and WM_LBUTTONUP to a disabled button leads to a WM_COMMAND for the parent */
6863 parent = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6864 100, 100, 200, 200, 0, 0, 0, NULL);
6865 ok (hwnd != 0, "Failed to create overlapped window\n");
6867 hwnd = CreateWindowExA(0, "my_button_class", "test", BS_DEFPUSHBUTTON | WS_VISIBLE | WS_CHILD,
6868 0, 0, 50, 14, parent, 0, 0, NULL);
6870 EnableWindow(hwnd, FALSE);
6871 flush_sequence();
6872 SendMessageA(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, 0);
6873 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
6874 ok_sequence(WmDisableButtonSeq, "Mouseclick on a disabled button", FALSE);
6876 DestroyWindow(hwnd);
6877 DestroyWindow(parent);
6880 static void test_button_bm_get_set_image(void)
6882 HWND hwnd;
6883 HDC hdc;
6884 HBITMAP hbmp1x1;
6885 HBITMAP hbmp2x2;
6886 HBITMAP hmask2x2;
6887 ICONINFO icon_info2x2;
6888 HICON hicon2x2;
6889 HBITMAP hbmp;
6890 HICON hicon;
6891 ICONINFO icon_info;
6892 BITMAP bm;
6893 DWORD default_style = BS_PUSHBUTTON | WS_TABSTOP | WS_POPUP | WS_VISIBLE;
6894 LRESULT ret;
6896 hdc = GetDC(0);
6897 hbmp1x1 = CreateCompatibleBitmap(hdc, 1, 1);
6898 hbmp2x2 = CreateCompatibleBitmap(hdc, 2, 2);
6899 ZeroMemory(&bm, sizeof(bm));
6900 ok(GetObjectW(hbmp1x1, sizeof(bm), &bm), "Expect GetObjectW() success\n");
6901 ok(bm.bmWidth == 1 && bm.bmHeight == 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
6902 bm.bmWidth, bm.bmHeight);
6903 ZeroMemory(&bm, sizeof(bm));
6904 ok(GetObjectW(hbmp2x2, sizeof(bm), &bm), "Expect GetObjectW() success\n");
6905 ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
6906 bm.bmWidth, bm.bmHeight);
6908 hmask2x2 = CreateCompatibleBitmap(hdc, 2, 2);
6909 ZeroMemory(&icon_info2x2, sizeof(icon_info2x2));
6910 icon_info2x2.fIcon = TRUE;
6911 icon_info2x2.hbmMask = hmask2x2;
6912 icon_info2x2.hbmColor = hbmp2x2;
6913 hicon2x2 = CreateIconIndirect(&icon_info2x2);
6915 ZeroMemory(&icon_info, sizeof(icon_info));
6916 ok(GetIconInfo(hicon2x2, &icon_info), "Expect GetIconInfo() success\n");
6917 ZeroMemory(&bm, sizeof(bm));
6918 ok(GetObjectW(icon_info.hbmColor, sizeof(bm), &bm), "Expect GetObjectW() success\n");
6919 ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
6920 bm.bmWidth, bm.bmHeight);
6921 DeleteObject(icon_info.hbmColor);
6922 DeleteObject(icon_info.hbmMask);
6924 /* Set bitmap with BS_BITMAP */
6925 hwnd = CreateWindowA("Button", "test", default_style | BS_BITMAP, 0, 0, 100, 100, 0, 0, 0, 0);
6926 ok(hwnd != NULL, "Expect hwnd not NULL\n");
6927 SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp1x1);
6928 hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_BITMAP, 0);
6929 ok(hbmp != 0, "Expect hbmp not 0\n");
6930 ZeroMemory(&bm, sizeof(bm));
6931 ok(GetObjectW(hbmp, sizeof(bm), &bm), "Expect GetObjectW() success\n");
6932 ok(bm.bmWidth == 1 && bm.bmHeight == 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
6933 bm.bmWidth, bm.bmHeight);
6934 DestroyWindow(hwnd);
6936 /* Set bitmap without BS_BITMAP */
6937 hwnd = CreateWindowA("Button", "test", default_style, 0, 0, 100, 100, 0, 0, 0, 0);
6938 ok(hwnd != NULL, "Expect hwnd not NULL\n");
6939 ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp1x1);
6940 ok(ret == 0, "Expect ret to be 0\n");
6941 hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_BITMAP, 0);
6942 ok(hbmp == NULL, "Expect hbmp to be NULL\n");
6943 DestroyWindow(hwnd);
6945 /* Set icon with BS_ICON */
6946 hwnd = CreateWindowA("Button", "test", default_style | BS_ICON, 0, 0, 100, 100, 0, 0, 0, 0);
6947 ok(hwnd != NULL, "Expect hwnd not NULL\n");
6948 SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicon2x2);
6949 hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_ICON, 0);
6950 ok(hicon != NULL, "Expect hicon not NULL\n");
6951 ZeroMemory(&icon_info, sizeof(icon_info));
6952 ok(GetIconInfo(hicon, &icon_info), "Expect GetIconInfo() success\n");
6953 ZeroMemory(&bm, sizeof(bm));
6954 ok(GetObjectW(icon_info.hbmColor, sizeof(bm), &bm), "Expect GetObjectW() success\n");
6955 ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
6956 bm.bmWidth, bm.bmHeight);
6957 DeleteObject(icon_info.hbmColor);
6958 DeleteObject(icon_info.hbmMask);
6959 DestroyWindow(hwnd);
6961 /* Set icon without BS_ICON */
6962 hwnd = CreateWindowA("Button", "test", default_style, 0, 0, 100, 100, 0, 0, 0, 0);
6963 ok(hwnd != NULL, "Expect hwnd not NULL\n");
6964 ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicon2x2);
6965 ok(ret == 0, "Expect ret to be 0\n");
6966 hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_ICON, 0);
6967 ok(hicon == NULL, "Expect hicon to be NULL\n");
6968 DestroyWindow(hwnd);
6970 /* Set icon with BS_BITMAP */
6971 hwnd = CreateWindowA("Button", "test", default_style | BS_BITMAP, 0, 0, 100, 100, 0, 0, 0, 0);
6972 ok(hwnd != NULL, "Expect hwnd to be not NULL\n");
6973 ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicon2x2);
6974 ok(ret == 0, "Expect ret to be 0\n");
6975 hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_ICON, 0);
6976 ok(hicon == NULL, "Expect hicon to be NULL\n");
6977 DestroyWindow(hwnd);
6979 /* Set bitmap with BS_ICON */
6980 hwnd = CreateWindowA("Button", "test", default_style | BS_ICON, 0, 0, 100, 100, 0, 0, 0, 0);
6981 ok(hwnd != NULL, "Expect hwnd to be not NULL\n");
6982 ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp1x1);
6983 ok(ret == 0, "Expect ret to be 0\n");
6984 hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_BITMAP, 0);
6985 ok(hbmp == NULL, "Expect hbmp to be NULL\n");
6986 DestroyWindow(hwnd);
6988 DestroyIcon(hicon2x2);
6989 DeleteObject(hmask2x2);
6990 DeleteObject(hbmp2x2);
6991 DeleteObject(hbmp1x1);
6992 ReleaseDC(0, hdc);
6995 #define ID_RADIO1 501
6996 #define ID_RADIO2 502
6997 #define ID_RADIO3 503
6998 #define ID_TEXT 504
7000 static const struct message auto_radio_button_BM_CLICK[] =
7002 { BM_CLICK, sent|wparam|lparam, 0, 0 },
7003 { WM_LBUTTONDOWN, sent|wparam|lparam|defwinproc, 0, 0 },
7004 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7005 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO2 },
7006 { WM_CTLCOLORSTATIC, sent|parent },
7007 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7008 { WM_LBUTTONUP, sent|wparam|lparam|defwinproc, 0, 0 },
7009 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO2 },
7010 { WM_CTLCOLORSTATIC, sent|parent },
7011 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7012 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO2, 0 },
7013 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO2 },
7014 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO1, 0 },
7015 { BM_SETCHECK, sent|wparam|lparam|defwinproc, 0, ID_RADIO1 },
7016 { WM_CTLCOLORSTATIC, sent|parent },
7017 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7018 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO3, 0 },
7019 { BM_SETCHECK, sent|wparam|lparam|defwinproc, 0, ID_RADIO3 },
7020 { WM_CTLCOLORSTATIC, sent|parent },
7021 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7022 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_TEXT, 0 },
7023 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
7024 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
7025 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO2, BN_CLICKED) },
7026 { WM_NCHITTEST, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
7027 { WM_SETCURSOR, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
7028 { WM_MOUSEMOVE, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
7029 { 0 }
7032 static const struct message auto_radio_button_VK_UP_child[] =
7034 { WM_KEYDOWN, sent|wparam|lparam, VK_UP, 0 },
7035 { WM_KEYUP, sent|wparam|lparam, VK_UP, 0 },
7036 { 0 }
7039 static const struct message auto_radio_button_VK_UP_parent[] =
7041 { WM_KEYDOWN, sent|wparam|lparam|parent, VK_UP, 0 },
7042 { WM_KEYUP, sent|wparam|lparam|parent, VK_UP, 0 },
7043 { 0 }
7046 static const struct message auto_radio_button_VK_UP_dialog[] =
7048 { WM_GETDLGCODE, sent|parent, 0, 0 },
7050 /* optional trailer seen on some windows setups */
7051 { WM_CHANGEUISTATE, sent|optional },
7052 { WM_UPDATEUISTATE, sent|optional },
7053 { WM_UPDATEUISTATE, sent|optional },
7054 { WM_UPDATEUISTATE, sent|optional },
7055 { WM_UPDATEUISTATE, sent|optional },
7056 { WM_UPDATEUISTATE, sent|optional },
7057 { WM_UPDATEUISTATE, sent|optional },
7058 { WM_UPDATEUISTATE, sent|optional },
7059 { WM_UPDATEUISTATE, sent|optional },
7060 { WM_UPDATEUISTATE, sent|optional },
7061 { WM_UPDATEUISTATE, sent|optional },
7062 { WM_UPDATEUISTATE, sent|optional },
7063 { WM_UPDATEUISTATE, sent|optional },
7064 { WM_UPDATEUISTATE, sent|optional },
7065 { WM_UPDATEUISTATE, sent|optional },
7066 { WM_UPDATEUISTATE, sent|optional },
7067 { WM_UPDATEUISTATE, sent|optional },
7068 { WM_UPDATEUISTATE, sent|optional },
7069 { WM_UPDATEUISTATE, sent|optional },
7070 { WM_CTLCOLORSTATIC, sent|parent|optional },
7071 { WM_CTLCOLORSTATIC, sent|parent|optional },
7072 { WM_CTLCOLORSTATIC, sent|parent|optional },
7073 { WM_UPDATEUISTATE, sent|optional },
7074 { WM_CTLCOLORSTATIC, sent|parent|optional },
7075 { WM_CTLCOLORSTATIC, sent|parent|optional },
7076 { WM_UPDATEUISTATE, sent|optional },
7077 { WM_CTLCOLORBTN, sent|parent|optional },
7078 { WM_CTLCOLORBTN, sent|parent|optional },
7079 { WM_UPDATEUISTATE, sent|optional },
7080 { WM_CTLCOLORSTATIC, sent|parent|optional },
7081 { WM_CTLCOLORSTATIC, sent|parent|optional },
7082 { 0 }
7085 static const struct message auto_radio_button_VK_DOWN_dialog[] =
7087 { WM_GETDLGCODE, sent|parent, 0, 0 },
7088 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, MAKELPARAM(WM_KEYDOWN, VK_DOWN) },
7089 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
7090 { HCBT_SETFOCUS, hook },
7091 { WM_KILLFOCUS, sent, 0, 0 },
7092 { WM_CTLCOLORSTATIC, sent|parent },
7093 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO3, BN_KILLFOCUS) },
7094 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7095 { WM_SETFOCUS, sent, 0, 0 },
7096 { WM_CTLCOLORSTATIC, sent|parent },
7097 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_SETFOCUS) },
7098 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_CLICKED) },
7099 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
7100 { WM_GETDLGCODE, sent|parent, 0, 0 },
7101 { DM_GETDEFID, sent|parent, 0, 0 },
7102 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
7103 { BM_CLICK, sent|wparam|lparam, 1, 0 },
7104 { WM_LBUTTONDOWN, sent|wparam|lparam|defwinproc, 0, 0 },
7105 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7106 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO1 },
7107 { WM_CTLCOLORSTATIC, sent|parent },
7108 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7109 { WM_LBUTTONUP, sent|wparam|lparam|defwinproc, 0, 0 },
7110 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO1 },
7111 { WM_CTLCOLORSTATIC, sent|parent },
7112 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7113 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO1, 0 },
7114 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO1 },
7115 { WM_CTLCOLORSTATIC, sent|parent },
7116 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7117 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO3, 0 },
7118 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO3 },
7119 { WM_CTLCOLORSTATIC, sent|parent },
7120 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7121 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_TEXT, 0 },
7122 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO2, 0 },
7123 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO2 },
7124 { WM_CTLCOLORSTATIC, sent|parent },
7125 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7126 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
7127 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
7128 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_CLICKED) },
7129 { WM_NCHITTEST, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
7130 { WM_SETCURSOR, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
7131 { WM_MOUSEMOVE, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
7132 { WM_PAINT, sent },
7133 { WM_CTLCOLORSTATIC, sent|parent },
7134 { 0 }
7137 static const struct message auto_radio_button_VK_DOWN_radio3[] =
7139 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
7140 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO2 },
7141 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO3 },
7142 { WM_GETDLGCODE, sent|parent, 0, 0 },
7143 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, MAKELPARAM(WM_KEYDOWN, VK_DOWN) },
7144 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
7145 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
7146 { WM_GETDLGCODE, sent|wparam|lparam|parent, 0, 0 },
7147 { WM_USER, sent|parent, 0, 0 },
7148 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
7149 { 0 }
7152 static const struct message auto_radio_button_VK_UP_radio1[] =
7154 { WM_GETDLGCODE, sent|parent, 0, 0 },
7155 { 0 }
7158 static INT_PTR WINAPI radio_test_dlg_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
7160 ParentMsgCheckProcA(hwnd, msg, wp, lp);
7161 return 1;
7164 static void test_autoradio_BM_CLICK(void)
7166 HWND parent, radio1, radio2, radio3;
7167 RECT rc;
7168 MSG msg;
7169 DWORD ret;
7171 subclass_button();
7173 parent = CreateDialogParamA(0, "AUTORADIO_TEST_DIALOG_1", 0, radio_test_dlg_proc, 0);
7174 ok(parent != 0, "failed to create parent window\n");
7176 radio1 = GetDlgItem(parent, ID_RADIO1);
7177 radio2 = GetDlgItem(parent, ID_RADIO2);
7178 radio3 = GetDlgItem(parent, ID_RADIO3);
7180 /* this avoids focus messages in the generated sequence */
7181 SetFocus(radio2);
7183 flush_events();
7184 flush_sequence();
7186 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
7187 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
7188 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
7189 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
7190 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
7191 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
7193 SendMessageA(radio1, BM_SETCHECK, BST_CHECKED, 0);
7195 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
7196 ok(ret == BST_CHECKED, "got %08x\n", ret);
7197 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
7198 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
7199 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
7200 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
7202 SendMessageA(radio2, BM_SETCHECK, BST_CHECKED, 0);
7204 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
7205 ok(ret == BST_CHECKED, "got %08x\n", ret);
7206 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
7207 ok(ret == BST_CHECKED, "got %08x\n", ret);
7208 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
7209 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
7211 SendMessageA(radio3, BM_SETCHECK, BST_CHECKED, 0);
7213 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
7214 ok(ret == BST_CHECKED, "got %08x\n", ret);
7215 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
7216 ok(ret == BST_CHECKED, "got %08x\n", ret);
7217 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
7218 ok(ret == BST_CHECKED, "got %08x\n", ret);
7220 GetWindowRect(radio2, &rc);
7221 SetCursorPos(rc.left+1, rc.top+1);
7223 flush_events();
7224 flush_sequence();
7226 log_all_parent_messages++;
7228 SendMessageA(radio2, BM_CLICK, 0, 0);
7229 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7230 ok_sequence(auto_radio_button_BM_CLICK, "BM_CLICK on auto-radio button", FALSE);
7232 log_all_parent_messages--;
7234 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
7235 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
7236 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
7237 ok(ret == BST_CHECKED, "got %08x\n", ret);
7238 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
7239 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
7241 DestroyWindow(parent);
7244 #define test_radio(r1, s1, r2, s2, r3, s3) test_radio_dbg(r1, s1, r2, s2, r3, s3, __LINE__)
7245 static void test_radio_dbg(HWND radio1, int state1, HWND radio2, int state2, HWND radio3, int state3, int line)
7247 DWORD ret;
7249 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
7250 ok_(__FILE__,line)(ret == state1 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret);
7251 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
7252 ok_(__FILE__,line)(ret == state2 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret);
7253 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
7254 ok_(__FILE__,line)(ret == state3 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret);
7257 static void set_radio(HWND radio1, int state1, HWND radio2, int state2, HWND radio3, int state3)
7259 SendMessageA(radio1, BM_SETCHECK, state1 ? BST_CHECKED : BST_UNCHECKED, 0);
7260 SendMessageA(radio2, BM_SETCHECK, state2 ? BST_CHECKED : BST_UNCHECKED, 0);
7261 SendMessageA(radio3, BM_SETCHECK, state3 ? BST_CHECKED : BST_UNCHECKED, 0);
7264 static void test_autoradio_kbd_move(void)
7266 HWND parent, radio1, radio2, radio3, hwnd;
7267 RECT rc;
7268 MSG msg;
7269 DWORD ret;
7271 subclass_button();
7273 parent = CreateDialogParamA(0, "AUTORADIO_TEST_DIALOG_2", 0, radio_test_dlg_proc, 0);
7274 ok(parent != 0, "failed to create parent window\n");
7276 radio1 = GetDlgItem(parent, ID_RADIO1);
7277 radio2 = GetDlgItem(parent, ID_RADIO2);
7278 radio3 = GetDlgItem(parent, ID_RADIO3);
7280 flush_events();
7281 flush_sequence();
7283 test_radio(radio1, 0, radio2, 0, radio3, 0);
7284 set_radio(radio1, 1, radio2, 1, radio3, 1);
7285 test_radio(radio1, 1, radio2, 1, radio3, 1);
7287 SetFocus(radio3);
7289 flush_events();
7290 flush_sequence();
7292 log_all_parent_messages++;
7294 SendMessageA(radio3, WM_KEYDOWN, VK_UP, 0);
7295 SendMessageA(radio3, WM_KEYUP, VK_UP, 0);
7296 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7297 ok_sequence(auto_radio_button_VK_UP_child, "press/release VK_UP on auto-radio button", FALSE);
7299 test_radio(radio1, 1, radio2, 1, radio3, 1);
7301 flush_events();
7302 flush_sequence();
7304 DefDlgProcA(parent, WM_KEYDOWN, VK_UP, 0);
7305 DefDlgProcA(parent, WM_KEYUP, VK_UP, 0);
7306 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7307 ok_sequence(auto_radio_button_VK_UP_parent, "press/release VK_UP on dialog", FALSE);
7309 test_radio(radio1, 1, radio2, 1, radio3, 1);
7311 SetFocus(radio3);
7312 GetWindowRect(radio3, &rc);
7314 flush_events();
7315 flush_sequence();
7317 msg.hwnd = parent;
7318 msg.message = WM_KEYDOWN;
7319 msg.wParam = VK_UP;
7320 msg.lParam = 0;
7321 msg.pt.x = rc.left + 1;
7322 msg.pt.y = rc.top + 1;
7323 ret = IsDialogMessageA(parent, &msg);
7324 ok(ret, "IsDialogMessage should return TRUE\n");
7325 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7326 if (0) /* actual message sequence is different on every run in some Windows setups */
7327 ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #1", FALSE);
7328 /* what really matters is that nothing has changed */
7329 test_radio(radio1, 1, radio2, 1, radio3, 1);
7331 set_radio(radio1, 0, radio2, 1, radio3, 1);
7332 test_radio(radio1, 0, radio2, 1, radio3, 1);
7334 flush_events();
7335 flush_sequence();
7337 ret = IsDialogMessageA(parent, &msg);
7338 ok(ret, "IsDialogMessage should return TRUE\n");
7339 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7340 if (0) /* actual message sequence is different on every run in some Windows setups */
7341 ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #2", FALSE);
7342 /* what really matters is that nothing has changed */
7343 test_radio(radio1, 0, radio2, 1, radio3, 1);
7345 /* switch from radio3 ro radio1 */
7346 SetFocus(radio3);
7347 GetWindowRect(radio3, &rc);
7349 flush_events();
7350 flush_sequence();
7352 msg.hwnd = parent;
7353 msg.message = WM_KEYDOWN;
7354 msg.wParam = VK_DOWN;
7355 msg.lParam = 0;
7356 msg.pt.x = rc.left + 1;
7357 msg.pt.y = rc.top + 1;
7358 ret = IsDialogMessageA(parent, &msg);
7359 ok(ret, "IsDialogMessage should return TRUE\n");
7360 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7361 ok_sequence(auto_radio_button_VK_DOWN_dialog, "IsDialogMessage(VK_DOWN)", TRUE);
7363 test_radio(radio1, 1, radio2, 0, radio3, 0);
7365 hwnd = GetFocus();
7366 ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
7367 GetWindowRect(radio1, &rc);
7369 msg.hwnd = parent;
7370 msg.message = WM_KEYDOWN;
7371 msg.wParam = VK_DOWN;
7372 msg.lParam = 0;
7373 msg.pt.x = rc.left + 1;
7374 msg.pt.y = rc.top + 1;
7375 ret = IsDialogMessageA(parent, &msg);
7376 ok(ret, "IsDialogMessage should return TRUE\n");
7377 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7378 ok_sequence(auto_radio_button_VK_DOWN_radio3, "down to radio3", TRUE);
7380 test_radio(radio1, 1, radio2, 0, radio3, 0);
7382 hwnd = GetFocus();
7383 ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
7385 flush_events();
7386 flush_sequence();
7388 msg.hwnd = parent;
7389 msg.message = WM_KEYDOWN;
7390 msg.wParam = VK_UP;
7391 msg.lParam = 0;
7392 msg.pt.x = rc.left + 1;
7393 msg.pt.y = rc.top + 1;
7394 ret = IsDialogMessageA(parent, &msg);
7395 ok(ret, "IsDialogMessage should return TRUE\n");
7396 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7397 ok_sequence(auto_radio_button_VK_UP_radio1, "up to radio1", TRUE);
7399 test_radio(radio1, 1, radio2, 0, radio3, 0);
7401 hwnd = GetFocus();
7402 ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
7404 flush_events();
7405 flush_sequence();
7407 msg.hwnd = parent;
7408 msg.message = WM_KEYDOWN;
7409 msg.wParam = VK_UP;
7410 msg.lParam = 0;
7411 msg.pt.x = rc.left + 1;
7412 msg.pt.y = rc.top + 1;
7413 ret = IsDialogMessageA(parent, &msg);
7414 ok(ret, "IsDialogMessage should return TRUE\n");
7415 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7416 if (0) /* actual message sequence is different on every run in some Windows setups */
7417 ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #3", FALSE);
7418 /* what really matters is that nothing has changed */
7419 test_radio(radio1, 1, radio2, 0, radio3, 0);
7421 log_all_parent_messages--;
7423 DestroyWindow(parent);
7426 /****************** static message test *************************/
7427 static const struct message WmSetFontStaticSeq2[] =
7429 { WM_SETFONT, sent },
7430 { WM_PAINT, sent|defwinproc|optional },
7431 { WM_ERASEBKGND, sent|defwinproc|optional },
7432 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
7433 { 0 }
7436 static WNDPROC old_static_proc;
7438 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7440 static LONG defwndproc_counter = 0;
7441 LRESULT ret;
7442 struct recvd_message msg;
7444 if (ignore_message( message )) return 0;
7446 msg.hwnd = hwnd;
7447 msg.message = message;
7448 msg.flags = sent|wparam|lparam;
7449 if (defwndproc_counter) msg.flags |= defwinproc;
7450 msg.wParam = wParam;
7451 msg.lParam = lParam;
7452 msg.descr = "static";
7453 add_message(&msg);
7455 defwndproc_counter++;
7456 ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
7457 defwndproc_counter--;
7459 return ret;
7462 static void subclass_static(void)
7464 WNDCLASSA cls;
7466 if (!GetClassInfoA(0, "static", &cls)) assert(0);
7468 old_static_proc = cls.lpfnWndProc;
7470 cls.hInstance = GetModuleHandleA(NULL);
7471 cls.lpfnWndProc = static_hook_proc;
7472 cls.lpszClassName = "my_static_class";
7473 UnregisterClassA(cls.lpszClassName, cls.hInstance);
7474 if (!RegisterClassA(&cls)) assert(0);
7477 static void test_static_messages(void)
7479 /* FIXME: make as comprehensive as the button message test */
7480 static const struct
7482 DWORD style;
7483 DWORD dlg_code;
7484 const struct message *setfont;
7485 } static_ctrl[] = {
7486 { SS_LEFT, DLGC_STATIC,
7487 WmSetFontStaticSeq2 }
7489 unsigned int i;
7490 HWND hwnd;
7491 DWORD dlg_code;
7493 subclass_static();
7495 for (i = 0; i < ARRAY_SIZE(static_ctrl); i++)
7497 hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
7498 0, 0, 50, 14, 0, 0, 0, NULL);
7499 ok(hwnd != 0, "Failed to create static window\n");
7501 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
7502 ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
7504 ShowWindow(hwnd, SW_SHOW);
7505 UpdateWindow(hwnd);
7506 SetFocus(0);
7507 flush_sequence();
7509 trace("static style %08x\n", static_ctrl[i].style);
7510 SendMessageA(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
7511 ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
7513 DestroyWindow(hwnd);
7517 /****************** ComboBox message test *************************/
7518 #define ID_COMBOBOX 0x000f
7520 static const struct message SetCurSelComboSeq[] =
7522 { CB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7523 { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7524 { LB_SETTOPINDEX, sent|wparam|lparam, 0, 0 },
7525 { LB_GETCURSEL, sent|wparam|lparam, 0, 0 },
7526 { LB_GETTEXTLEN, sent|wparam|lparam, 0, 0 },
7527 { LB_GETTEXTLEN, sent|wparam|lparam|optional, 0, 0 }, /* TODO: it's sent on all Windows versions */
7528 { LB_GETTEXT, sent|wparam, 0 },
7529 { WM_CTLCOLOREDIT, sent|parent },
7530 { LB_GETITEMDATA, sent|wparam|lparam, 0, 0 },
7531 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_COMBOBOX, 0x100010f3 },
7532 { 0 }
7535 static const struct message SetCurSelComboSeq2[] =
7537 { CB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7538 { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7539 { LB_SETTOPINDEX, sent|wparam|lparam, 0, 0 },
7540 { LB_GETCURSEL, sent|wparam|lparam, 0, 0 },
7541 { LB_GETTEXTLEN, sent|wparam|lparam, 0, 0 },
7542 { LB_GETTEXTLEN, sent|wparam|lparam|optional, 0, 0 }, /* TODO: it's sent on all Windows versions */
7543 { LB_GETTEXT, sent|wparam, 0 },
7544 { 0 }
7547 static const struct message SetCurSelComboSeq_edit[] =
7549 { CB_SETCURSEL, sent|wparam|lparam, 0, 0 },
7550 { WM_SETTEXT, sent|wparam, 0 },
7551 { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
7552 { 0 }
7555 static const struct message WmKeyDownComboSeq[] =
7557 { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
7558 { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
7559 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
7560 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
7561 { WM_CTLCOLOREDIT, sent|parent },
7562 { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
7563 { 0 }
7566 static const struct message WmSetPosComboSeq[] =
7568 { WM_WINDOWPOSCHANGING, sent },
7569 { WM_NCCALCSIZE, sent|wparam, TRUE },
7570 { WM_CHILDACTIVATE, sent },
7571 { WM_WINDOWPOSCHANGED, sent },
7572 { WM_MOVE, sent|defwinproc },
7573 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
7574 { WM_WINDOWPOSCHANGING, sent|defwinproc },
7575 { WM_NCCALCSIZE, sent|defwinproc|wparam, TRUE },
7576 { WM_WINDOWPOSCHANGED, sent|defwinproc },
7577 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
7578 { 0 }
7581 static const struct message WMSetFocusComboBoxSeq[] =
7583 { WM_SETFOCUS, sent },
7584 { WM_KILLFOCUS, sent|parent },
7585 { WM_SETFOCUS, sent },
7586 { WM_COMMAND, sent|defwinproc|wparam, MAKEWPARAM(1001, EN_SETFOCUS) },
7587 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, INT_MAX },
7588 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7589 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7590 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SETFOCUS) },
7591 { 0 }
7594 static const struct message SetFocusButtonSeq[] =
7596 { WM_KILLFOCUS, sent },
7597 { CB_GETCOMBOBOXINFO, sent|optional },/* Windows 2000 */
7598 { 0x0167, sent|optional },/* Undocumented message. Sent on all versions except Windows 2000 */
7599 { WM_LBUTTONUP, sent|defwinproc },
7600 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDCANCEL) },
7601 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, 0 },
7602 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7603 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7604 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_KILLFOCUS) },
7605 { WM_CTLCOLORBTN, sent|parent },
7606 { 0 }
7609 static const struct message SetFocusComboBoxSeq[] =
7611 { WM_CTLCOLORBTN, sent|parent },
7612 { WM_SETFOCUS, sent },
7613 { WM_KILLFOCUS, sent|defwinproc },
7614 { WM_SETFOCUS, sent },
7615 { WM_COMMAND, sent|defwinproc|wparam, MAKEWPARAM(1001, EN_SETFOCUS) },
7616 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, INT_MAX },
7617 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7618 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7619 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SETFOCUS) },
7620 { 0 }
7623 static const struct message SetFocusButtonSeq2[] =
7625 { WM_KILLFOCUS, sent },
7626 { CB_GETCOMBOBOXINFO, sent|optional },/* Windows 2000 */
7627 { 0x0167, sent|optional },/* Undocumented message. Sent on all versions except Windows 2000 */
7628 { WM_LBUTTONUP, sent|defwinproc },
7629 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDCANCEL) },
7630 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, 0 },
7631 { WM_CTLCOLOREDIT, sent|defwinproc },
7632 { WM_CTLCOLOREDIT, sent|parent },
7633 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_KILLFOCUS) },
7634 { WM_CTLCOLORBTN, sent|parent },
7635 { 0 }
7638 static WNDPROC old_combobox_proc, edit_window_proc, lbox_window_proc;
7640 static LRESULT CALLBACK combobox_edit_subclass_proc(HWND hwnd, UINT message,
7641 WPARAM wParam, LPARAM lParam)
7643 static LONG defwndproc_counter = 0;
7644 LRESULT ret;
7645 struct recvd_message msg;
7647 /* do not log painting messages */
7648 if (message != WM_PAINT &&
7649 message != WM_NCPAINT &&
7650 message != WM_SYNCPAINT &&
7651 message != WM_ERASEBKGND &&
7652 message != WM_NCHITTEST &&
7653 message != WM_GETTEXT &&
7654 !ignore_message( message ))
7656 msg.hwnd = hwnd;
7657 msg.message = message;
7658 msg.flags = sent|wparam|lparam;
7659 if (defwndproc_counter) msg.flags |= defwinproc;
7660 msg.wParam = wParam;
7661 msg.lParam = lParam;
7662 msg.descr = "combo edit";
7663 add_message(&msg);
7666 defwndproc_counter++;
7667 ret = CallWindowProcA(edit_window_proc, hwnd, message, wParam, lParam);
7668 defwndproc_counter--;
7670 return ret;
7673 static LRESULT CALLBACK combobox_lbox_subclass_proc(HWND hwnd, UINT message,
7674 WPARAM wParam, LPARAM lParam)
7676 static LONG defwndproc_counter = 0;
7677 LRESULT ret;
7678 struct recvd_message msg;
7680 /* do not log painting messages */
7681 if (message != WM_PAINT &&
7682 message != WM_NCPAINT &&
7683 message != WM_SYNCPAINT &&
7684 message != WM_ERASEBKGND &&
7685 message != WM_NCHITTEST &&
7686 !ignore_message( message ))
7688 msg.hwnd = hwnd;
7689 msg.message = message;
7690 msg.flags = sent|wparam|lparam;
7691 if (defwndproc_counter) msg.flags |= defwinproc;
7692 msg.wParam = wParam;
7693 msg.lParam = lParam;
7694 msg.descr = "combo lbox";
7695 add_message(&msg);
7698 defwndproc_counter++;
7699 ret = CallWindowProcA(lbox_window_proc, hwnd, message, wParam, lParam);
7700 defwndproc_counter--;
7702 return ret;
7705 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7707 static LONG defwndproc_counter = 0;
7708 LRESULT ret;
7709 struct recvd_message msg;
7711 /* do not log painting messages */
7712 if (message != WM_PAINT &&
7713 message != WM_NCPAINT &&
7714 message != WM_SYNCPAINT &&
7715 message != WM_ERASEBKGND &&
7716 message != WM_NCHITTEST &&
7717 message != WM_GETTEXT &&
7718 !ignore_message( message ))
7720 msg.hwnd = hwnd;
7721 msg.message = message;
7722 msg.flags = sent|wparam|lparam;
7723 if (defwndproc_counter) msg.flags |= defwinproc;
7724 msg.wParam = wParam;
7725 msg.lParam = lParam;
7726 msg.descr = "combo";
7727 add_message(&msg);
7730 defwndproc_counter++;
7731 ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
7732 defwndproc_counter--;
7734 return ret;
7737 static void subclass_combobox(void)
7739 WNDCLASSA cls;
7741 if (!GetClassInfoA(0, "ComboBox", &cls)) assert(0);
7743 old_combobox_proc = cls.lpfnWndProc;
7745 cls.hInstance = GetModuleHandleA(NULL);
7746 cls.lpfnWndProc = combobox_hook_proc;
7747 cls.lpszClassName = "my_combobox_class";
7748 UnregisterClassA(cls.lpszClassName, cls.hInstance);
7749 if (!RegisterClassA(&cls)) assert(0);
7752 static void test_combobox_messages(void)
7754 HWND parent, combo, button, edit, lbox;
7755 LRESULT ret;
7756 COMBOBOXINFO cbInfo;
7757 BOOL res;
7759 subclass_combobox();
7761 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7762 100, 100, 200, 200, 0, 0, 0, NULL);
7763 ok(parent != 0, "Failed to create parent window\n");
7764 flush_sequence();
7766 combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
7767 0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
7768 ok(combo != 0, "Failed to create combobox window\n");
7770 UpdateWindow(combo);
7772 ret = SendMessageA(combo, WM_GETDLGCODE, 0, 0);
7773 ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08lx\n", ret);
7775 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
7776 ok(ret == 0, "expected 0, got %ld\n", ret);
7777 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
7778 ok(ret == 1, "expected 1, got %ld\n", ret);
7779 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
7780 ok(ret == 2, "expected 2, got %ld\n", ret);
7782 SendMessageA(combo, CB_SETCURSEL, 0, 0);
7783 SetFocus(combo);
7784 flush_sequence();
7786 log_all_parent_messages++;
7787 SendMessageA(combo, WM_KEYDOWN, VK_DOWN, 0);
7788 SendMessageA(combo, WM_KEYUP, VK_DOWN, 0);
7789 log_all_parent_messages--;
7790 ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
7792 flush_sequence();
7793 SetWindowPos(combo, 0, 10, 10, 120, 130, SWP_NOZORDER);
7794 ok_sequence(WmSetPosComboSeq, "repositioning messages on a ComboBox", FALSE);
7796 DestroyWindow(combo);
7797 DestroyWindow(parent);
7799 /* Start again. Test combobox text selection when getting and losing focus */
7800 parent = CreateWindowExA(0, "TestParentClass", "Parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7801 10, 10, 300, 300, NULL, NULL, NULL, NULL);
7802 ok(parent != 0, "Failed to create parent window\n");
7804 combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWN,
7805 5, 5, 100, 100, parent, (HMENU)ID_COMBOBOX, NULL, NULL);
7806 ok(combo != 0, "Failed to create combobox window\n");
7808 cbInfo.cbSize = sizeof(COMBOBOXINFO);
7809 SetLastError(0xdeadbeef);
7810 res = GetComboBoxInfo(combo, &cbInfo);
7811 ok(res, "Failed to get COMBOBOXINFO structure; LastError: %u\n", GetLastError());
7812 edit = cbInfo.hwndItem;
7814 edit_window_proc = (WNDPROC)SetWindowLongPtrA(edit, GWLP_WNDPROC,
7815 (ULONG_PTR)combobox_edit_subclass_proc);
7817 button = CreateWindowExA(0, "Button", "OK", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
7818 5, 50, 100, 20, parent, NULL,
7819 (HINSTANCE)GetWindowLongPtrA(parent, GWLP_HINSTANCE), NULL);
7820 ok(button != 0, "Failed to create button window\n");
7822 flush_sequence();
7823 log_all_parent_messages++;
7824 SendMessageA(combo, WM_SETFOCUS, 0, (LPARAM)edit);
7825 log_all_parent_messages--;
7826 ok_sequence(WMSetFocusComboBoxSeq, "WM_SETFOCUS on a ComboBox", TRUE);
7828 flush_sequence();
7829 log_all_parent_messages++;
7830 SetFocus(button);
7831 log_all_parent_messages--;
7832 ok_sequence(SetFocusButtonSeq, "SetFocus on a Button", TRUE);
7834 SendMessageA(combo, WM_SETTEXT, 0, (LPARAM)"Wine Test");
7836 flush_sequence();
7837 log_all_parent_messages++;
7838 SetFocus(combo);
7839 log_all_parent_messages--;
7840 ok_sequence(SetFocusComboBoxSeq, "SetFocus on a ComboBox", TRUE);
7842 flush_sequence();
7843 log_all_parent_messages++;
7844 SetFocus(button);
7845 log_all_parent_messages--;
7846 ok_sequence(SetFocusButtonSeq2, "SetFocus on a Button (2)", TRUE);
7848 SetFocus(combo);
7849 SendMessageA(combo, WM_SETREDRAW, FALSE, 0);
7850 flush_sequence();
7851 log_all_parent_messages++;
7852 SendMessageA(combo, CB_SETCURSEL, 0, 0);
7853 log_all_parent_messages--;
7854 ok_sequence(SetCurSelComboSeq_edit, "CB_SETCURSEL on a ComboBox with edit control", FALSE);
7856 DestroyWindow(button);
7857 DestroyWindow(combo);
7859 combo = CreateWindowExA(0, "my_combobox_class", "test",
7860 WS_CHILD | WS_VISIBLE | CBS_OWNERDRAWFIXED | CBS_DROPDOWNLIST,
7861 5, 5, 100, 100, parent, (HMENU)ID_COMBOBOX, NULL, NULL);
7862 ok(combo != 0, "Failed to create combobox window\n");
7864 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
7865 ok(ret == 0, "expected 0, got %ld\n", ret);
7867 cbInfo.cbSize = sizeof(COMBOBOXINFO);
7868 SetLastError(0xdeadbeef);
7869 res = GetComboBoxInfo(combo, &cbInfo);
7870 ok(res, "Failed to get COMBOBOXINFO structure; LastError: %u\n", GetLastError());
7871 lbox = cbInfo.hwndList;
7872 lbox_window_proc = (WNDPROC)SetWindowLongPtrA(lbox, GWLP_WNDPROC,
7873 (ULONG_PTR)combobox_lbox_subclass_proc);
7874 flush_sequence();
7876 log_all_parent_messages++;
7877 SendMessageA(combo, CB_SETCURSEL, 0, 0);
7878 log_all_parent_messages--;
7879 ok_sequence(SetCurSelComboSeq, "CB_SETCURSEL on a ComboBox", FALSE);
7881 ShowWindow(combo, SW_HIDE);
7882 flush_sequence();
7883 log_all_parent_messages++;
7884 SendMessageA(combo, CB_SETCURSEL, 0, 0);
7885 log_all_parent_messages--;
7886 ok_sequence(SetCurSelComboSeq2, "CB_SETCURSEL on a ComboBox", FALSE);
7888 DestroyWindow(combo);
7889 DestroyWindow(parent);
7892 /****************** WM_IME_KEYDOWN message test *******************/
7894 static const struct message WmImeKeydownMsgSeq_0[] =
7896 { WM_IME_KEYDOWN, wparam, VK_RETURN },
7897 { WM_CHAR, wparam, 'A' },
7898 { 0 }
7901 static const struct message WmImeKeydownMsgSeq_1[] =
7903 { WM_KEYDOWN, optional|wparam, VK_RETURN },
7904 { WM_CHAR, optional|wparam, VK_RETURN },
7905 { 0 }
7908 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7910 struct recvd_message msg;
7912 msg.hwnd = hwnd;
7913 msg.message = message;
7914 msg.flags = wparam|lparam;
7915 msg.wParam = wParam;
7916 msg.lParam = lParam;
7917 msg.descr = "wmime_keydown";
7918 add_message(&msg);
7920 return DefWindowProcA(hwnd, message, wParam, lParam);
7923 static void register_wmime_keydown_class(void)
7925 WNDCLASSA cls;
7927 ZeroMemory(&cls, sizeof(WNDCLASSA));
7928 cls.lpfnWndProc = wmime_keydown_procA;
7929 cls.hInstance = GetModuleHandleA(0);
7930 cls.lpszClassName = "wmime_keydown_class";
7931 if (!RegisterClassA(&cls)) assert(0);
7934 static void test_wmime_keydown_message(void)
7936 HWND hwnd;
7937 MSG msg;
7939 trace("Message sequences by WM_IME_KEYDOWN\n");
7941 register_wmime_keydown_class();
7942 hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
7943 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
7944 NULL, NULL, 0);
7945 flush_events();
7946 flush_sequence();
7948 SendMessageA(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
7949 SendMessageA(hwnd, WM_CHAR, 'A', 1);
7950 ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
7952 while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
7954 TranslateMessage(&msg);
7955 DispatchMessageA(&msg);
7957 ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
7959 DestroyWindow(hwnd);
7962 /************* painting message test ********************/
7964 void dump_region(HRGN hrgn)
7966 DWORD i, size;
7967 RGNDATA *data = NULL;
7968 RECT *rect;
7970 if (!hrgn)
7972 printf( "null region\n" );
7973 return;
7975 if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
7976 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
7977 GetRegionData( hrgn, size, data );
7978 printf("%d rects:", data->rdh.nCount );
7979 for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
7980 printf( " %s", wine_dbgstr_rect( rect ));
7981 printf("\n");
7982 HeapFree( GetProcessHeap(), 0, data );
7985 #define check_update_rgn( hwnd, hrgn ) check_update_rgn_( __LINE__, hwnd, hrgn )
7986 static void check_update_rgn_( int line, HWND hwnd, HRGN hrgn )
7988 INT ret;
7989 RECT r1, r2;
7990 HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
7991 HRGN update = CreateRectRgn( 0, 0, 0, 0 );
7993 ret = GetUpdateRgn( hwnd, update, FALSE );
7994 ok( ret != ERROR, "GetUpdateRgn failed\n" );
7995 if (ret == NULLREGION)
7997 ok_(__FILE__,line)( !hrgn, "Update region shouldn't be empty\n" );
7999 else
8001 if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
8003 ok_(__FILE__,line)( 0, "Regions are different\n" );
8004 if (winetest_debug > 0)
8006 printf( "Update region: " );
8007 dump_region( update );
8008 printf( "Wanted region: " );
8009 dump_region( hrgn );
8013 GetRgnBox( update, &r1 );
8014 GetUpdateRect( hwnd, &r2, FALSE );
8015 ok_(__FILE__,line)( EqualRect( &r1, &r2 ), "Rectangles are different: %s / %s\n",
8016 wine_dbgstr_rect( &r1 ), wine_dbgstr_rect( &r2 ));
8018 DeleteObject( tmp );
8019 DeleteObject( update );
8022 static const struct message WmInvalidateRgn[] = {
8023 { WM_NCPAINT, sent },
8024 { WM_GETTEXT, sent|defwinproc|optional },
8025 { 0 }
8028 static const struct message WmGetUpdateRect[] = {
8029 { WM_NCPAINT, sent },
8030 { WM_GETTEXT, sent|defwinproc|optional },
8031 { WM_PAINT, sent },
8032 { 0 }
8035 static const struct message WmInvalidateFull[] = {
8036 { WM_NCPAINT, sent|wparam, 1 },
8037 { WM_GETTEXT, sent|defwinproc|optional },
8038 { 0 }
8041 static const struct message WmInvalidateErase[] = {
8042 { WM_NCPAINT, sent|wparam, 1 },
8043 { WM_GETTEXT, sent|defwinproc|optional },
8044 { WM_ERASEBKGND, sent },
8045 { 0 }
8048 static const struct message WmInvalidatePaint[] = {
8049 { WM_PAINT, sent },
8050 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
8051 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8052 { 0 }
8055 static const struct message WmInvalidateErasePaint[] = {
8056 { WM_PAINT, sent },
8057 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
8058 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8059 { WM_ERASEBKGND, sent|beginpaint|optional },
8060 { 0 }
8063 static const struct message WmInvalidateErasePaint2[] = {
8064 { WM_PAINT, sent },
8065 { WM_NCPAINT, sent|beginpaint },
8066 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8067 { WM_ERASEBKGND, sent|beginpaint|optional },
8068 { 0 }
8071 static const struct message WmErase[] = {
8072 { WM_ERASEBKGND, sent },
8073 { 0 }
8076 static const struct message WmPaint[] = {
8077 { WM_PAINT, sent },
8078 { 0 }
8081 static const struct message WmParentOnlyPaint[] = {
8082 { WM_PAINT, sent|parent },
8083 { 0 }
8086 static const struct message WmInvalidateParent[] = {
8087 { WM_NCPAINT, sent|parent },
8088 { WM_GETTEXT, sent|defwinproc|parent|optional },
8089 { WM_ERASEBKGND, sent|parent },
8090 { 0 }
8093 static const struct message WmInvalidateParentChild[] = {
8094 { WM_NCPAINT, sent|parent },
8095 { WM_GETTEXT, sent|defwinproc|parent|optional },
8096 { WM_ERASEBKGND, sent|parent },
8097 { WM_NCPAINT, sent },
8098 { WM_GETTEXT, sent|defwinproc|optional },
8099 { WM_ERASEBKGND, sent },
8100 { 0 }
8103 static const struct message WmInvalidateParentChild2[] = {
8104 { WM_ERASEBKGND, sent|parent },
8105 { WM_NCPAINT, sent },
8106 { WM_GETTEXT, sent|defwinproc|optional },
8107 { WM_ERASEBKGND, sent },
8108 { 0 }
8111 static const struct message WmParentPaint[] = {
8112 { WM_PAINT, sent|parent },
8113 { WM_PAINT, sent },
8114 { 0 }
8117 static const struct message WmParentPaintNc[] = {
8118 { WM_PAINT, sent|parent },
8119 { WM_PAINT, sent },
8120 { WM_NCPAINT, sent|beginpaint },
8121 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8122 { WM_ERASEBKGND, sent|beginpaint|optional },
8123 { WM_GETMINMAXINFO, sent|optional },
8124 { 0 }
8127 static const struct message WmChildPaintNc[] = {
8128 { WM_PAINT, sent },
8129 { WM_NCPAINT, sent|beginpaint },
8130 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8131 { WM_ERASEBKGND, sent|beginpaint|optional },
8132 { 0 }
8135 static const struct message WmParentErasePaint[] = {
8136 { WM_PAINT, sent|parent },
8137 { WM_NCPAINT, sent|parent|beginpaint },
8138 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
8139 { WM_ERASEBKGND, sent|parent|beginpaint|optional },
8140 { WM_PAINT, sent },
8141 { WM_NCPAINT, sent|beginpaint },
8142 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8143 { WM_ERASEBKGND, sent|beginpaint|optional },
8144 { 0 }
8147 static const struct message WmParentOnlyNcPaint[] = {
8148 { WM_PAINT, sent|parent },
8149 { WM_NCPAINT, sent|parent|beginpaint },
8150 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
8151 { 0 }
8154 static const struct message WmSetParentStyle[] = {
8155 { WM_STYLECHANGING, sent|parent },
8156 { WM_STYLECHANGED, sent|parent },
8157 { 0 }
8160 static void test_paint_messages(void)
8162 BOOL ret;
8163 RECT rect, rect2;
8164 POINT pt;
8165 MSG msg;
8166 HWND hparent, hchild;
8167 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
8168 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
8169 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
8170 100, 100, 200, 200, 0, 0, 0, NULL);
8171 ok (hwnd != 0, "Failed to create overlapped window\n");
8173 ShowWindow( hwnd, SW_SHOW );
8174 UpdateWindow( hwnd );
8175 flush_events();
8176 flush_sequence();
8178 check_update_rgn( hwnd, 0 );
8179 SetRectRgn( hrgn, 10, 10, 20, 20 );
8180 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
8181 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8182 check_update_rgn( hwnd, hrgn );
8183 SetRectRgn( hrgn2, 20, 20, 30, 30 );
8184 ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
8185 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8186 CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
8187 check_update_rgn( hwnd, hrgn );
8188 /* validate everything */
8189 ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8190 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8191 check_update_rgn( hwnd, 0 );
8193 /* test empty region */
8194 SetRectRgn( hrgn, 10, 10, 10, 15 );
8195 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
8196 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8197 check_update_rgn( hwnd, 0 );
8198 /* test empty rect */
8199 SetRect( &rect, 10, 10, 10, 15 );
8200 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
8201 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
8202 check_update_rgn( hwnd, 0 );
8204 /* flush pending messages */
8205 flush_events();
8206 flush_sequence();
8208 GetClientRect( hwnd, &rect );
8209 SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
8210 /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
8211 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
8213 SetRectEmpty( &rect );
8214 ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) failed\n");
8215 check_update_rgn( hwnd, hrgn );
8216 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8217 flush_events();
8218 ok_sequence( WmPaint, "Paint", FALSE );
8219 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8220 check_update_rgn( hwnd, 0 );
8222 SetRectEmpty( &rect );
8223 ok(RedrawWindow(0, &rect, 0, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
8224 "RedrawWindow failed\n");
8225 check_update_rgn( hwnd, 0 );
8227 SetRectEmpty( &rect );
8228 ok(RedrawWindow(0, &rect, 0, RDW_ALLCHILDREN | RDW_VALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
8229 "RedrawWindow failed\n");
8230 check_update_rgn( hwnd, 0 );
8232 GetWindowRect( hwnd, &rect );
8233 ok(RedrawWindow(0, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
8234 "RedrawWindow failed\n");
8235 check_update_rgn( hwnd, 0 );
8237 flush_events();
8238 ok(RedrawWindow(0, &rect, 0, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
8239 "RedrawWindow failed\n");
8240 check_update_rgn( hwnd, hrgn );
8241 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8242 flush_events();
8243 ok_sequence( WmPaint, "Paint", FALSE );
8244 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8245 check_update_rgn( hwnd, 0 );
8247 ok(RedrawWindow(GetDesktopWindow(), &rect, 0,
8248 RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
8249 "RedrawWindow failed\n");
8250 ret = GetUpdateRgn( hwnd, hrgn2, FALSE );
8251 ok( ret == NULLREGION || broken(ret == SIMPLEREGION), /* <= win7 */
8252 "region should be null (%d)\n", ret );
8253 if (ret == SIMPLEREGION) ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8254 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8255 flush_events();
8257 ok(RedrawWindow(GetDesktopWindow(), NULL, 0,
8258 RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
8259 "RedrawWindow failed\n");
8260 ret = GetUpdateRgn( hwnd, hrgn2, FALSE );
8261 ok( ret == NULLREGION || broken(ret == SIMPLEREGION), /* <= win7 */
8262 "region should be null (%d)\n", ret );
8263 if (ret == SIMPLEREGION) ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8264 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8265 flush_events();
8267 SetRectRgn( hrgn2, rect.left, rect.top, rect.right, rect.bottom );
8268 ok(RedrawWindow(0, NULL, hrgn2, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ),
8269 "RedrawWindow failed\n");
8270 check_update_rgn( hwnd, hrgn );
8271 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8272 flush_events();
8273 ok_sequence( WmPaint, "Paint", FALSE );
8274 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8275 check_update_rgn( hwnd, 0 );
8277 ok(RedrawWindow(0, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW ),
8278 "RedrawWindow failed\n");
8279 check_update_rgn( hwnd, 0 );
8281 ok(RedrawWindow(0, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW ),
8282 "RedrawWindow failed\n");
8283 check_update_rgn( hwnd, hrgn );
8284 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8285 flush_events();
8286 ok_sequence( WmPaint, "Paint", FALSE );
8287 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8288 check_update_rgn( hwnd, 0 );
8290 /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
8291 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
8293 SetRectEmpty( &rect );
8294 if (ValidateRect(0, &rect) && /* not supported on Win9x */
8295 GetUpdateRect(hwnd, NULL, FALSE)) /* or >= Win 8 */
8297 check_update_rgn( hwnd, hrgn );
8298 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8299 flush_events();
8300 ok_sequence( WmPaint, "Paint", FALSE );
8301 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
8302 check_update_rgn( hwnd, 0 );
8305 SetLastError(0xdeadbeef);
8306 ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
8307 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
8308 "wrong error code %d\n", GetLastError());
8309 check_update_rgn( hwnd, 0 );
8310 flush_events();
8311 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8313 SetLastError(0xdeadbeef);
8314 ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
8315 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
8316 broken( GetLastError() == 0xdeadbeef ) /* win9x */,
8317 "wrong error code %d\n", GetLastError());
8318 check_update_rgn( hwnd, 0 );
8319 flush_events();
8320 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8322 SetLastError(0xdeadbeef);
8323 ok(!UpdateWindow(NULL), "UpdateWindow(NULL) should fail\n");
8324 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
8325 broken( GetLastError() == 0xdeadbeef ) /* win9x */,
8326 "wrong error code %d\n", GetLastError());
8327 check_update_rgn( hwnd, 0 );
8328 flush_events();
8329 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8331 /* now with frame */
8332 SetRectRgn( hrgn, -5, -5, 20, 20 );
8334 /* flush pending messages */
8335 flush_events();
8336 flush_sequence();
8337 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8338 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
8340 SetRectRgn( hrgn, 0, 0, 20, 20 ); /* GetUpdateRgn clips to client area */
8341 check_update_rgn( hwnd, hrgn );
8343 flush_sequence();
8344 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
8345 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
8347 flush_sequence();
8348 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
8349 ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
8351 GetClientRect( hwnd, &rect );
8352 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8353 check_update_rgn( hwnd, hrgn );
8355 flush_sequence();
8356 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
8357 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
8359 flush_sequence();
8360 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
8361 ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
8362 check_update_rgn( hwnd, 0 );
8364 flush_sequence();
8365 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
8366 ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
8367 check_update_rgn( hwnd, 0 );
8369 flush_sequence();
8370 SetRectRgn( hrgn, 0, 0, 100, 100 );
8371 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
8372 SetRectRgn( hrgn, 0, 0, 50, 100 );
8373 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
8374 SetRectRgn( hrgn, 50, 0, 100, 100 );
8375 check_update_rgn( hwnd, hrgn );
8376 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
8377 ok_sequence( WmEmptySeq, "EmptySeq", FALSE ); /* must not generate messages, everything is valid */
8378 check_update_rgn( hwnd, 0 );
8380 flush_sequence();
8381 SetRectRgn( hrgn, 0, 0, 100, 100 );
8382 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
8383 SetRectRgn( hrgn, 0, 0, 100, 50 );
8384 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
8385 ok_sequence( WmErase, "Erase", FALSE );
8386 SetRectRgn( hrgn, 0, 50, 100, 100 );
8387 check_update_rgn( hwnd, hrgn );
8389 flush_sequence();
8390 SetRectRgn( hrgn, 0, 0, 100, 100 );
8391 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
8392 SetRectRgn( hrgn, 0, 0, 50, 50 );
8393 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
8394 ok_sequence( WmPaint, "Paint", FALSE );
8396 flush_sequence();
8397 SetRectRgn( hrgn, -4, -4, -2, -2 );
8398 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8399 SetRectRgn( hrgn, -200, -200, -198, -198 );
8400 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
8401 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
8403 flush_sequence();
8404 SetRectRgn( hrgn, -4, -4, -2, -2 );
8405 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8406 SetRectRgn( hrgn, -4, -4, -3, -3 );
8407 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
8408 SetRectRgn( hrgn, 0, 0, 1, 1 );
8409 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
8410 ok_sequence( WmPaint, "Paint", FALSE );
8412 flush_sequence();
8413 SetRectRgn( hrgn, -4, -4, -1, -1 );
8414 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8415 RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
8416 /* make sure no WM_PAINT was generated */
8417 flush_events();
8418 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
8420 flush_sequence();
8421 SetRectRgn( hrgn, -4, -4, -1, -1 );
8422 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
8423 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
8425 if (msg.hwnd == hwnd && msg.message == WM_PAINT)
8427 /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
8428 INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
8429 ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
8430 ret = GetUpdateRect( hwnd, &rect, FALSE );
8431 ok( ret, "Invalid GetUpdateRect result %d\n", ret );
8432 /* this will send WM_NCPAINT and validate the non client area */
8433 ret = GetUpdateRect( hwnd, &rect, TRUE );
8434 ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
8436 DispatchMessageA( &msg );
8438 ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
8440 DestroyWindow( hwnd );
8442 /* now test with a child window */
8444 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
8445 100, 100, 200, 200, 0, 0, 0, NULL);
8446 ok (hparent != 0, "Failed to create parent window\n");
8448 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
8449 10, 10, 100, 100, hparent, 0, 0, NULL);
8450 ok (hchild != 0, "Failed to create child window\n");
8452 ShowWindow( hparent, SW_SHOW );
8453 UpdateWindow( hparent );
8454 UpdateWindow( hchild );
8455 flush_events();
8456 flush_sequence();
8457 log_all_parent_messages++;
8459 SetRect( &rect, 0, 0, 50, 50 );
8460 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8461 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
8462 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
8464 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8465 pt.x = pt.y = 0;
8466 MapWindowPoints( hchild, hparent, &pt, 1 );
8467 SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
8468 check_update_rgn( hchild, hrgn );
8469 SetRectRgn( hrgn, 0, 0, 50, 50 );
8470 check_update_rgn( hparent, hrgn );
8471 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8472 ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
8473 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
8474 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
8476 flush_events();
8477 ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
8479 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
8480 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8481 ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
8482 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
8483 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
8485 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
8486 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
8487 ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
8489 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
8490 flush_sequence();
8491 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
8492 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8493 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
8495 /* flush all paint messages */
8496 flush_events();
8497 flush_sequence();
8499 /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
8500 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
8501 SetRectRgn( hrgn, 0, 0, 50, 50 );
8502 check_update_rgn( hparent, hrgn );
8503 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
8504 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8505 SetRectRgn( hrgn, 0, 0, 50, 50 );
8506 check_update_rgn( hparent, hrgn );
8508 /* flush all paint messages */
8509 flush_events();
8510 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
8511 flush_sequence();
8513 /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
8514 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8515 SetRectRgn( hrgn, 0, 0, 50, 50 );
8516 check_update_rgn( hparent, hrgn );
8517 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
8518 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8519 SetRectRgn( hrgn2, 10, 10, 50, 50 );
8520 CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
8521 check_update_rgn( hparent, hrgn );
8522 /* flush all paint messages */
8523 flush_events();
8524 flush_sequence();
8526 /* same as above but parent gets completely validated */
8527 SetRect( &rect, 20, 20, 30, 30 );
8528 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8529 SetRectRgn( hrgn, 20, 20, 30, 30 );
8530 check_update_rgn( hparent, hrgn );
8531 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
8532 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8533 check_update_rgn( hparent, 0 ); /* no update region */
8534 flush_events();
8535 ok_sequence( WmEmptySeq, "WmEmpty", FALSE ); /* and no paint messages */
8537 /* make sure RDW_VALIDATE on child doesn't have the same effect */
8538 flush_sequence();
8539 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8540 SetRectRgn( hrgn, 20, 20, 30, 30 );
8541 check_update_rgn( hparent, hrgn );
8542 RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
8543 SetRectRgn( hrgn, 20, 20, 30, 30 );
8544 check_update_rgn( hparent, hrgn );
8546 /* same as above but normal WM_PAINT doesn't validate parent */
8547 flush_sequence();
8548 SetRect( &rect, 20, 20, 30, 30 );
8549 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8550 SetRectRgn( hrgn, 20, 20, 30, 30 );
8551 check_update_rgn( hparent, hrgn );
8552 /* no WM_PAINT in child while parent still pending */
8553 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8554 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8555 while (PeekMessageA( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8556 ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
8558 flush_sequence();
8559 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8560 /* no WM_PAINT in child while parent still pending */
8561 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8562 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8563 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
8564 /* now that parent is valid child should get WM_PAINT */
8565 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8566 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8567 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8568 ok_sequence( WmEmptySeq, "No other message", FALSE );
8570 /* same thing with WS_CLIPCHILDREN in parent */
8571 flush_sequence();
8572 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
8573 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
8574 /* changing style invalidates non client area, but we need to invalidate something else to see it */
8575 RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
8576 ok_sequence( WmEmptySeq, "No message", FALSE );
8577 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
8578 ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
8580 flush_sequence();
8581 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
8582 SetRectRgn( hrgn, 20, 20, 30, 30 );
8583 check_update_rgn( hparent, hrgn );
8584 /* no WM_PAINT in child while parent still pending */
8585 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8586 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8587 /* WM_PAINT in parent first */
8588 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8589 ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
8591 /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
8592 flush_sequence();
8593 SetRect( &rect, 0, 0, 30, 30 );
8594 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
8595 SetRectRgn( hrgn, 0, 0, 30, 30 );
8596 check_update_rgn( hparent, hrgn );
8597 flush_events();
8598 ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
8600 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
8601 flush_sequence();
8602 SetRect( &rect, -10, 0, 30, 30 );
8603 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
8604 SetRect( &rect, 0, 0, 20, 20 );
8605 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
8606 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
8607 ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
8609 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
8610 flush_sequence();
8611 SetRect( &rect, -10, 0, 30, 30 );
8612 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
8613 SetRect( &rect, 0, 0, 100, 100 );
8614 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
8615 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
8616 ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
8617 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8618 ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
8620 /* WS_CLIPCHILDREN doesn't exclude children from update region */
8621 flush_sequence();
8622 RedrawWindow( hparent, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
8623 GetClientRect( hparent, &rect );
8624 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8625 check_update_rgn( hparent, hrgn );
8626 flush_events();
8628 RedrawWindow( hparent, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
8629 GetClientRect( hparent, &rect );
8630 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8631 check_update_rgn( hparent, hrgn );
8632 flush_events();
8634 /* test RDW_INTERNALPAINT behavior */
8636 flush_sequence();
8637 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
8638 flush_events();
8639 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
8641 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
8642 flush_events();
8643 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
8645 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
8646 flush_events();
8647 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
8649 assert( GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
8650 UpdateWindow( hparent );
8651 flush_events();
8652 flush_sequence();
8653 trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
8654 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8655 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
8656 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8657 flush_events();
8658 ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
8660 UpdateWindow( hparent );
8661 flush_events();
8662 flush_sequence();
8663 trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
8664 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8665 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
8666 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8667 flush_events();
8668 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
8670 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
8671 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
8672 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
8673 flush_events();
8674 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
8676 assert( !(GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
8677 UpdateWindow( hparent );
8678 flush_events();
8679 flush_sequence();
8680 trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
8681 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8682 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
8683 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8684 flush_events();
8685 ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
8687 UpdateWindow( hparent );
8688 flush_events();
8689 flush_sequence();
8690 trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
8691 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8692 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
8693 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8694 flush_events();
8695 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
8697 ok(GetWindowLongA( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
8698 ok(GetWindowLongA( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
8700 UpdateWindow( hparent );
8701 flush_events();
8702 flush_sequence();
8703 trace("testing SetWindowPos(-10000, -10000) on child\n");
8704 SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
8705 check_update_rgn( hchild, 0 );
8706 flush_events();
8708 #if 0 /* this one doesn't pass under Wine yet */
8709 UpdateWindow( hparent );
8710 flush_events();
8711 flush_sequence();
8712 trace("testing ShowWindow(SW_MINIMIZE) on child\n");
8713 ShowWindow( hchild, SW_MINIMIZE );
8714 check_update_rgn( hchild, 0 );
8715 flush_events();
8716 #endif
8718 UpdateWindow( hparent );
8719 flush_events();
8720 flush_sequence();
8721 trace("testing SetWindowPos(-10000, -10000) on parent\n");
8722 SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
8723 check_update_rgn( hparent, 0 );
8724 flush_events();
8726 log_all_parent_messages--;
8727 DestroyWindow( hparent );
8728 ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
8730 /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
8732 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
8733 100, 100, 200, 200, 0, 0, 0, NULL);
8734 ok (hparent != 0, "Failed to create parent window\n");
8736 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
8737 10, 10, 100, 100, hparent, 0, 0, NULL);
8738 ok (hchild != 0, "Failed to create child window\n");
8740 ShowWindow( hparent, SW_SHOW );
8741 UpdateWindow( hparent );
8742 UpdateWindow( hchild );
8743 flush_events();
8744 flush_sequence();
8746 /* moving child outside of parent boundaries changes update region */
8747 SetRect( &rect, 0, 0, 40, 40 );
8748 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
8749 SetRectRgn( hrgn, 0, 0, 40, 40 );
8750 check_update_rgn( hchild, hrgn );
8751 MoveWindow( hchild, -10, 10, 100, 100, FALSE );
8752 SetRectRgn( hrgn, 10, 0, 40, 40 );
8753 check_update_rgn( hchild, hrgn );
8754 MoveWindow( hchild, -10, -10, 100, 100, FALSE );
8755 SetRectRgn( hrgn, 10, 10, 40, 40 );
8756 check_update_rgn( hchild, hrgn );
8758 /* moving parent off-screen does too */
8759 SetRect( &rect, 0, 0, 100, 100 );
8760 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
8761 SetRectRgn( hrgn, 0, 0, 100, 100 );
8762 check_update_rgn( hparent, hrgn );
8763 SetRectRgn( hrgn, 10, 10, 40, 40 );
8764 check_update_rgn( hchild, hrgn );
8765 MoveWindow( hparent, -20, -20, 200, 200, FALSE );
8766 GetUpdateRect( hparent, &rect2, FALSE );
8767 if (!EqualRect( &rect2, &rect )) /* Win 8 and later don't crop update to screen */
8769 rect.left += 20;
8770 rect.top += 20;
8772 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8773 check_update_rgn( hparent, hrgn );
8774 SetRectRgn( hrgn, rect.left + 10, rect.top + 10, 40, 40 );
8775 check_update_rgn( hchild, hrgn );
8777 /* invalidated region is cropped by the parent rects */
8778 SetRect( &rect, 0, 0, 50, 50 );
8779 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
8780 SetRectRgn( hrgn, rect2.left + 10, rect2.top + 10, 50, 50 );
8781 check_update_rgn( hchild, hrgn );
8783 DestroyWindow( hparent );
8784 ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
8785 flush_sequence();
8787 DeleteObject( hrgn );
8788 DeleteObject( hrgn2 );
8791 struct wnd_event
8793 HWND hwnd;
8794 HANDLE grand_child;
8795 HANDLE start_event;
8796 HANDLE stop_event;
8799 static DWORD WINAPI thread_proc(void *param)
8801 MSG msg;
8802 struct wnd_event *wnd_event = param;
8804 wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
8805 100, 100, 200, 200, 0, 0, 0, NULL);
8806 ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
8808 SetEvent(wnd_event->start_event);
8810 while (GetMessageA(&msg, 0, 0, 0))
8812 TranslateMessage(&msg);
8813 DispatchMessageA(&msg);
8816 ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
8818 return 0;
8821 static DWORD CALLBACK create_grand_child_thread( void *param )
8823 struct wnd_event *wnd_event = param;
8824 HWND hchild;
8825 MSG msg;
8827 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
8828 WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
8829 ok (hchild != 0, "Failed to create child window\n");
8830 flush_events();
8831 flush_sequence();
8832 SetEvent( wnd_event->start_event );
8834 for (;;)
8836 MsgWaitForMultipleObjects(0, NULL, FALSE, 1000, QS_ALLINPUT);
8837 if (!IsWindow( hchild )) break; /* will be destroyed when parent thread exits */
8838 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8840 return 0;
8843 static DWORD CALLBACK create_child_thread( void *param )
8845 struct wnd_event *wnd_event = param;
8846 struct wnd_event child_event;
8847 DWORD ret, tid;
8848 MSG msg;
8850 child_event.hwnd = CreateWindowExA(0, "TestWindowClass", "Test child",
8851 WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
8852 ok (child_event.hwnd != 0, "Failed to create child window\n");
8853 SetFocus( child_event.hwnd );
8854 flush_events();
8855 flush_sequence();
8856 child_event.start_event = wnd_event->start_event;
8857 wnd_event->grand_child = CreateThread(NULL, 0, create_grand_child_thread, &child_event, 0, &tid);
8858 for (;;)
8860 DWORD ret = MsgWaitForMultipleObjects(1, &child_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
8861 if (ret != 1) break;
8862 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8864 ret = WaitForSingleObject( wnd_event->stop_event, 5000 );
8865 ok( !ret, "WaitForSingleObject failed %x\n", ret );
8866 return 0;
8869 static const char manifest_dep[] =
8870 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
8871 "<assemblyIdentity version=\"1.2.3.4\" name=\"testdep1\" type=\"win32\" processorArchitecture=\"" ARCH "\"/>"
8872 " <file name=\"testdep.dll\" />"
8873 "</assembly>";
8875 static const char manifest_main[] =
8876 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
8877 "<assemblyIdentity version=\"1.2.3.4\" name=\"Wine.Test\" type=\"win32\" />"
8878 "<dependency>"
8879 " <dependentAssembly>"
8880 " <assemblyIdentity type=\"win32\" name=\"testdep1\" version=\"1.2.3.4\" processorArchitecture=\"" ARCH "\" />"
8881 " </dependentAssembly>"
8882 "</dependency>"
8883 "</assembly>";
8885 static void create_manifest_file(const char *filename, const char *manifest)
8887 WCHAR path[MAX_PATH];
8888 HANDLE file;
8889 DWORD size;
8891 MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH );
8892 file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8893 ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
8894 WriteFile(file, manifest, strlen(manifest), &size, NULL);
8895 CloseHandle(file);
8898 static HANDLE test_create(const char *file)
8900 WCHAR path[MAX_PATH];
8901 ACTCTXW actctx;
8902 HANDLE handle;
8904 MultiByteToWideChar(CP_ACP, 0, file, -1, path, MAX_PATH);
8905 memset(&actctx, 0, sizeof(ACTCTXW));
8906 actctx.cbSize = sizeof(ACTCTXW);
8907 actctx.lpSource = path;
8909 handle = CreateActCtxW(&actctx);
8910 ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %u\n", GetLastError());
8912 ok(actctx.cbSize == sizeof(actctx), "cbSize=%d\n", actctx.cbSize);
8913 ok(actctx.dwFlags == 0, "dwFlags=%d\n", actctx.dwFlags);
8914 ok(actctx.lpSource == path, "lpSource=%p\n", actctx.lpSource);
8915 ok(actctx.wProcessorArchitecture == 0, "wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture);
8916 ok(actctx.wLangId == 0, "wLangId=%d\n", actctx.wLangId);
8917 ok(actctx.lpAssemblyDirectory == NULL, "lpAssemblyDirectory=%p\n", actctx.lpAssemblyDirectory);
8918 ok(actctx.lpResourceName == NULL, "lpResourceName=%p\n", actctx.lpResourceName);
8919 ok(actctx.lpApplicationName == NULL, "lpApplicationName=%p\n", actctx.lpApplicationName);
8920 ok(actctx.hModule == NULL, "hModule=%p\n", actctx.hModule);
8922 return handle;
8925 static void test_interthread_messages(void)
8927 HANDLE hThread, context, handle, event;
8928 ULONG_PTR cookie;
8929 DWORD tid;
8930 WNDPROC proc;
8931 MSG msg;
8932 char buf[256];
8933 int len, expected_len;
8934 struct wnd_event wnd_event;
8935 BOOL ret;
8937 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
8938 if (!wnd_event.start_event)
8940 win_skip("skipping interthread message test under win9x\n");
8941 return;
8944 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
8945 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
8947 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8949 CloseHandle(wnd_event.start_event);
8951 SetLastError(0xdeadbeef);
8952 ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeeded\n");
8953 ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
8954 "wrong error code %d\n", GetLastError());
8956 proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
8957 ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
8959 expected_len = lstrlenA("window caption text");
8960 memset(buf, 0, sizeof(buf));
8961 SetLastError(0xdeadbeef);
8962 len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
8963 ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
8964 ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
8966 msg.hwnd = wnd_event.hwnd;
8967 msg.message = WM_GETTEXT;
8968 msg.wParam = sizeof(buf);
8969 msg.lParam = (LPARAM)buf;
8970 memset(buf, 0, sizeof(buf));
8971 SetLastError(0xdeadbeef);
8972 len = DispatchMessageA(&msg);
8973 ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */
8974 "DispatchMessageA(WM_GETTEXT) succeeded on another thread window: ret %d, error %d\n", len, GetLastError());
8976 /* the following test causes an exception in user.exe under win9x */
8977 msg.hwnd = wnd_event.hwnd;
8978 msg.message = WM_TIMER;
8979 msg.wParam = 0;
8980 msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
8981 SetLastError(0xdeadbeef);
8982 len = DispatchMessageA(&msg);
8983 ok(!len && GetLastError() == 0xdeadbeef,
8984 "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
8986 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
8987 ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
8989 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8990 CloseHandle(hThread);
8992 ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
8994 wnd_event.hwnd = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8995 100, 100, 200, 200, 0, 0, 0, NULL);
8996 ok (wnd_event.hwnd != 0, "Failed to create parent window\n");
8997 flush_events();
8998 flush_sequence();
8999 log_all_parent_messages++;
9000 wnd_event.start_event = CreateEventA( NULL, TRUE, FALSE, NULL );
9001 wnd_event.stop_event = CreateEventA( NULL, TRUE, FALSE, NULL );
9002 hThread = CreateThread( NULL, 0, create_child_thread, &wnd_event, 0, &tid );
9003 for (;;)
9005 ret = MsgWaitForMultipleObjects(1, &wnd_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
9006 if (ret != 1) break;
9007 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
9009 ok( !ret, "MsgWaitForMultipleObjects failed %x\n", ret );
9010 /* now wait for the thread without processing messages; this shouldn't deadlock */
9011 SetEvent( wnd_event.stop_event );
9012 ret = WaitForSingleObject( hThread, 5000 );
9013 ok( !ret, "WaitForSingleObject failed %x\n", ret );
9014 CloseHandle( hThread );
9016 ret = WaitForSingleObject( wnd_event.grand_child, 5000 );
9017 ok( !ret, "WaitForSingleObject failed %x\n", ret );
9018 CloseHandle( wnd_event.grand_child );
9020 CloseHandle( wnd_event.start_event );
9021 CloseHandle( wnd_event.stop_event );
9022 flush_events();
9023 ok_sequence(WmExitThreadSeq, "destroy child on thread exit", FALSE);
9024 log_all_parent_messages--;
9025 DestroyWindow( wnd_event.hwnd );
9027 /* Activation context tests */
9028 create_manifest_file("testdep1.manifest", manifest_dep);
9029 create_manifest_file("main.manifest", manifest_main);
9031 context = test_create("main.manifest");
9032 DeleteFileA("testdep1.manifest");
9033 DeleteFileA("main.manifest");
9035 handle = (void*)0xdeadbeef;
9036 ret = GetCurrentActCtx(&handle);
9037 ok(ret, "GetCurrentActCtx failed: %u\n", GetLastError());
9038 ok(handle == 0, "active context %p\n", handle);
9040 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
9041 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
9042 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
9043 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
9044 CloseHandle(wnd_event.start_event);
9046 /* context is activated after thread creation, so it doesn't inherit it by default */
9047 ret = ActivateActCtx(context, &cookie);
9048 ok(ret, "activation failed: %u\n", GetLastError());
9050 handle = 0;
9051 ret = GetCurrentActCtx(&handle);
9052 ok(ret, "GetCurrentActCtx failed: %u\n", GetLastError());
9053 ok(handle != 0, "active context %p\n", handle);
9054 ReleaseActCtx(handle);
9056 /* destination window will test for active context */
9057 ret = SendMessageA(wnd_event.hwnd, WM_USER+10, 0, 0);
9058 ok(ret, "thread window returned %d\n", ret);
9060 event = CreateEventW(NULL, 0, 0, NULL);
9061 ret = PostMessageA(wnd_event.hwnd, WM_USER+10, 0, (LPARAM)event);
9062 ok(ret, "thread window returned %d\n", ret);
9063 ok(WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
9064 CloseHandle(event);
9066 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
9067 ok(ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
9069 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
9070 CloseHandle(hThread);
9072 ret = DeactivateActCtx(0, cookie);
9073 ok(ret, "DeactivateActCtx failed: %u\n", GetLastError());
9074 ReleaseActCtx(context);
9078 static const struct message WmVkN[] = {
9079 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
9080 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
9081 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
9082 { WM_CHAR, wparam|lparam, 'n', 1 },
9083 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
9084 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9085 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
9086 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
9087 { 0 }
9089 static const struct message WmShiftVkN[] = {
9090 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
9091 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
9092 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
9093 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
9094 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
9095 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
9096 { WM_CHAR, wparam|lparam, 'N', 1 },
9097 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
9098 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9099 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
9100 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
9101 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
9102 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
9103 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
9104 { 0 }
9106 static const struct message WmCtrlVkN[] = {
9107 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
9108 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
9109 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
9110 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
9111 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
9112 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
9113 { WM_CHAR, wparam|lparam, 0x000e, 1 },
9114 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
9115 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9116 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
9117 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
9118 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
9119 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
9120 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
9121 { 0 }
9123 static const struct message WmCtrlVkN_2[] = {
9124 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
9125 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
9126 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
9127 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
9128 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
9129 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
9130 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9131 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
9132 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
9133 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
9134 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
9135 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
9136 { 0 }
9138 static const struct message WmAltVkN[] = {
9139 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
9140 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
9141 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
9142 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
9143 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
9144 { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
9145 { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
9146 { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
9147 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
9148 { HCBT_SYSCOMMAND, hook },
9149 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
9150 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9151 { 0x00AE, sent|defwinproc|optional }, /* XP */
9152 { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
9153 { WM_INITMENU, sent|defwinproc },
9154 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
9155 { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
9156 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
9157 { WM_CAPTURECHANGED, sent|defwinproc },
9158 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
9159 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
9160 { WM_EXITMENULOOP, sent|defwinproc },
9161 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
9162 { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
9163 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
9164 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
9165 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
9166 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
9167 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
9168 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
9169 { 0 }
9171 static const struct message WmAltVkN_2[] = {
9172 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
9173 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
9174 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
9175 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
9176 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
9177 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
9178 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
9179 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
9180 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
9181 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
9182 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
9183 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
9184 { 0 }
9186 static const struct message WmCtrlAltVkN[] = {
9187 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
9188 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
9189 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
9190 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
9191 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
9192 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
9193 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
9194 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
9195 { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
9196 { WM_CHAR, optional },
9197 { WM_CHAR, sent|optional },
9198 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
9199 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
9200 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
9201 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
9202 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
9203 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
9204 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
9205 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
9206 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
9207 { 0 }
9209 static const struct message WmCtrlShiftVkN[] = {
9210 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
9211 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
9212 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
9213 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
9214 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
9215 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
9216 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
9217 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
9218 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
9219 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9220 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
9221 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
9222 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
9223 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
9224 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
9225 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
9226 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
9227 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
9228 { 0 }
9230 static const struct message WmCtrlAltShiftVkN[] = {
9231 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
9232 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
9233 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
9234 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
9235 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
9236 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
9237 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
9238 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
9239 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
9240 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
9241 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
9242 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
9243 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
9244 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
9245 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
9246 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
9247 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
9248 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
9249 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
9250 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
9251 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
9252 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
9253 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
9254 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
9255 { 0 }
9257 static const struct message WmAltPressRelease[] = {
9258 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
9259 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
9260 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
9261 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
9262 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
9263 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
9264 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
9265 { HCBT_SYSCOMMAND, hook },
9266 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
9267 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9268 { WM_INITMENU, sent|defwinproc },
9269 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
9270 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
9271 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
9273 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
9275 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
9276 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
9277 { WM_CAPTURECHANGED, sent|defwinproc },
9278 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
9279 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
9280 { WM_EXITMENULOOP, sent|defwinproc },
9281 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
9282 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
9283 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
9284 { 0 }
9286 static const struct message WmShiftMouseButton[] = {
9287 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
9288 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
9289 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
9290 { WM_MOUSEMOVE, wparam|optional, 0, 0 },
9291 { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
9292 { WM_LBUTTONDOWN, wparam, MK_LBUTTON|MK_SHIFT, 0 },
9293 { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON|MK_SHIFT, 0 },
9294 { WM_LBUTTONUP, wparam|optional, MK_SHIFT, 0 }, /* < w1064v1809 */
9295 { WM_LBUTTONUP, sent|wparam|optional, MK_SHIFT, 0 }, /* < w1064v1809 */
9296 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
9297 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
9298 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
9299 { WM_LBUTTONUP, optional, 0, 0 }, /* >= w1064v1809 */
9300 { WM_LBUTTONUP, sent|optional, 0, 0 }, /* >= w1064v1809 */
9301 { 0 }
9303 static const struct message WmF1Seq[] = {
9304 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
9305 { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
9306 { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
9307 { WM_KEYF1, wparam|lparam, 0, 0 },
9308 { WM_KEYF1, sent|wparam|lparam, 0, 0 },
9309 { WM_HELP, sent|defwinproc },
9310 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
9311 { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
9312 { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
9313 { 0 }
9315 static const struct message WmVkAppsSeq[] = {
9316 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
9317 { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
9318 { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
9319 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
9320 { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
9321 { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
9322 { WM_CONTEXTMENU, lparam, /*hwnd*/0, -1 },
9323 { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, -1 },
9324 { 0 }
9326 static const struct message WmVkF10Seq[] = {
9327 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
9328 { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
9329 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
9330 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
9331 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
9332 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
9333 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
9334 { HCBT_SYSCOMMAND, hook },
9335 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
9336 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9337 { WM_INITMENU, sent|defwinproc },
9338 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
9339 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
9340 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
9342 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0x10000001 }, /* XP */
9344 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
9345 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
9346 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
9347 { WM_CAPTURECHANGED, sent|defwinproc },
9348 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
9349 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
9350 { WM_EXITMENULOOP, sent|defwinproc },
9351 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
9352 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
9353 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
9354 { 0 }
9356 static const struct message WmShiftF10Seq[] = {
9357 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
9358 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
9359 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x00000001 },
9360 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
9361 { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
9362 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
9363 { WM_CONTEXTMENU, sent|defwinproc|lparam, /*hwnd*/0, -1 },
9364 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
9365 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
9366 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
9367 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
9368 { HCBT_SYSCOMMAND, hook },
9369 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
9370 { WM_INITMENU, sent|defwinproc },
9371 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
9372 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xd0000001 }, /* XP */
9373 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0x10000001 }, /* XP */
9374 { WM_CAPTURECHANGED, sent|defwinproc|wparam|lparam, 0, 0 },
9375 { WM_MENUSELECT, sent|defwinproc|wparam|lparam, 0xffff0000, 0 },
9376 { WM_EXITMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
9377 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 }, /* XP */
9378 { WM_KEYUP, wparam|lparam, VK_ESCAPE, 0xc0000001 },
9379 { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
9380 { 0 }
9383 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
9385 MSG msg;
9387 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
9389 struct recvd_message log_msg;
9391 /* ignore some unwanted messages */
9392 if (msg.message == WM_MOUSEMOVE ||
9393 msg.message == WM_TIMER ||
9394 ignore_message( msg.message ))
9395 continue;
9397 log_msg.hwnd = msg.hwnd;
9398 log_msg.message = msg.message;
9399 log_msg.flags = wparam|lparam;
9400 log_msg.wParam = msg.wParam;
9401 log_msg.lParam = msg.lParam;
9402 log_msg.descr = "accel";
9403 add_message(&log_msg);
9405 if (!hAccel || !TranslateAcceleratorA(hwnd, hAccel, &msg))
9407 TranslateMessage(&msg);
9408 DispatchMessageA(&msg);
9413 static void test_accelerators(void)
9415 RECT rc;
9416 POINT pt;
9417 SHORT state;
9418 HACCEL hAccel;
9419 HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9420 100, 100, 200, 200, 0, 0, 0, NULL);
9421 BOOL us_kbd = (GetKeyboardLayout(0) == (HKL)(ULONG_PTR)0x04090409);
9422 BOOL ret;
9424 assert(hwnd != 0);
9425 UpdateWindow(hwnd);
9426 flush_events();
9427 flush_sequence();
9429 SetFocus(hwnd);
9430 ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
9432 state = GetKeyState(VK_SHIFT);
9433 ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
9434 state = GetKeyState(VK_CAPITAL);
9435 ok(state == 0, "wrong CapsLock state %04x\n", state);
9437 hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
9438 assert(hAccel != 0);
9440 flush_events();
9441 pump_msg_loop(hwnd, 0);
9442 flush_sequence();
9444 if (!us_kbd)
9446 skip("skipping ascii VK events on non-us keyboard\n");
9447 goto done;
9450 trace("testing VK_N press/release\n");
9451 flush_sequence();
9452 keybd_event('N', 0, 0, 0);
9453 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9454 pump_msg_loop(hwnd, hAccel);
9455 if (!sequence_cnt) /* we didn't get any message */
9457 skip( "queuing key events not supported\n" );
9458 goto done;
9460 ok_sequence(WmVkN, "VK_N press/release", FALSE);
9462 trace("testing Shift+VK_N press/release\n");
9463 flush_sequence();
9464 keybd_event(VK_SHIFT, 0, 0, 0);
9465 keybd_event('N', 0, 0, 0);
9466 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9467 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9468 pump_msg_loop(hwnd, hAccel);
9469 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
9471 trace("testing Ctrl+VK_N press/release\n");
9472 flush_sequence();
9473 keybd_event(VK_CONTROL, 0, 0, 0);
9474 keybd_event('N', 0, 0, 0);
9475 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9476 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9477 pump_msg_loop(hwnd, hAccel);
9478 ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
9480 trace("testing Alt+VK_N press/release\n");
9481 flush_sequence();
9482 keybd_event(VK_MENU, 0, 0, 0);
9483 keybd_event('N', 0, 0, 0);
9484 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9485 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9486 pump_msg_loop(hwnd, hAccel);
9487 ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
9489 trace("testing Ctrl+Alt+VK_N press/release 1\n");
9490 flush_sequence();
9491 keybd_event(VK_CONTROL, 0, 0, 0);
9492 keybd_event(VK_MENU, 0, 0, 0);
9493 keybd_event('N', 0, 0, 0);
9494 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9495 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9496 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9497 pump_msg_loop(hwnd, hAccel);
9498 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
9500 ret = DestroyAcceleratorTable(hAccel);
9501 ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
9503 hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(2));
9504 assert(hAccel != 0);
9506 trace("testing VK_N press/release\n");
9507 flush_sequence();
9508 keybd_event('N', 0, 0, 0);
9509 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9510 pump_msg_loop(hwnd, hAccel);
9511 ok_sequence(WmVkN, "VK_N press/release", FALSE);
9513 trace("testing Shift+VK_N press/release\n");
9514 flush_sequence();
9515 keybd_event(VK_SHIFT, 0, 0, 0);
9516 keybd_event('N', 0, 0, 0);
9517 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9518 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9519 pump_msg_loop(hwnd, hAccel);
9520 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
9522 trace("testing Ctrl+VK_N press/release 2\n");
9523 flush_sequence();
9524 keybd_event(VK_CONTROL, 0, 0, 0);
9525 keybd_event('N', 0, 0, 0);
9526 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9527 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9528 pump_msg_loop(hwnd, hAccel);
9529 ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
9531 trace("testing Alt+VK_N press/release 2\n");
9532 flush_sequence();
9533 keybd_event(VK_MENU, 0, 0, 0);
9534 keybd_event('N', 0, 0, 0);
9535 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9536 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9537 pump_msg_loop(hwnd, hAccel);
9538 ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
9540 trace("testing Ctrl+Alt+VK_N press/release 2\n");
9541 flush_sequence();
9542 keybd_event(VK_CONTROL, 0, 0, 0);
9543 keybd_event(VK_MENU, 0, 0, 0);
9544 keybd_event('N', 0, 0, 0);
9545 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9546 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9547 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9548 pump_msg_loop(hwnd, hAccel);
9549 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
9551 trace("testing Ctrl+Shift+VK_N press/release\n");
9552 flush_sequence();
9553 keybd_event(VK_CONTROL, 0, 0, 0);
9554 keybd_event(VK_SHIFT, 0, 0, 0);
9555 keybd_event('N', 0, 0, 0);
9556 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9557 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9558 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9559 pump_msg_loop(hwnd, hAccel);
9560 ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
9562 trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
9563 flush_sequence();
9564 keybd_event(VK_CONTROL, 0, 0, 0);
9565 keybd_event(VK_MENU, 0, 0, 0);
9566 keybd_event(VK_SHIFT, 0, 0, 0);
9567 keybd_event('N', 0, 0, 0);
9568 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9569 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9570 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9571 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9572 pump_msg_loop(hwnd, hAccel);
9573 ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
9575 ret = DestroyAcceleratorTable(hAccel);
9576 ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
9577 hAccel = 0;
9579 trace("testing Alt press/release\n");
9580 flush_sequence();
9581 keybd_event(VK_MENU, 0, 0, 0);
9582 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9583 keybd_event(VK_MENU, 0, 0, 0);
9584 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9585 pump_msg_loop(hwnd, 0);
9586 /* this test doesn't pass in Wine for managed windows */
9587 ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
9589 trace("testing VK_F1 press/release\n");
9590 keybd_event(VK_F1, 0, 0, 0);
9591 keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
9592 pump_msg_loop(hwnd, 0);
9593 ok_sequence(WmF1Seq, "F1 press/release", FALSE);
9595 trace("testing VK_APPS press/release\n");
9596 keybd_event(VK_APPS, 0, 0, 0);
9597 keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
9598 pump_msg_loop(hwnd, 0);
9599 ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
9601 trace("testing VK_F10 press/release\n");
9602 keybd_event(VK_F10, 0, 0, 0);
9603 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
9604 keybd_event(VK_F10, 0, 0, 0);
9605 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
9606 pump_msg_loop(hwnd, 0);
9607 ok_sequence(WmVkF10Seq, "VK_F10 press/release", TRUE);
9609 trace("testing SHIFT+F10 press/release\n");
9610 keybd_event(VK_SHIFT, 0, 0, 0);
9611 keybd_event(VK_F10, 0, 0, 0);
9612 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
9613 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9614 keybd_event(VK_ESCAPE, 0, 0, 0);
9615 keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
9616 pump_msg_loop(hwnd, 0);
9617 ok_sequence(WmShiftF10Seq, "SHIFT+F10 press/release", TRUE);
9619 trace("testing Shift+MouseButton press/release\n");
9620 /* first, move mouse pointer inside of the window client area */
9621 GetClientRect(hwnd, &rc);
9622 MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
9623 rc.left += (rc.right - rc.left)/2;
9624 rc.top += (rc.bottom - rc.top)/2;
9625 SetCursorPos(rc.left, rc.top);
9626 SetActiveWindow(hwnd);
9628 flush_events();
9629 flush_sequence();
9630 GetCursorPos(&pt);
9631 if (pt.x == rc.left && pt.y == rc.top)
9633 int i;
9634 keybd_event(VK_SHIFT, 0, 0, 0);
9635 mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
9636 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
9637 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9638 pump_msg_loop(hwnd, 0);
9639 for (i = 0; i < sequence_cnt; i++) if (sequence[i].message == WM_LBUTTONDOWN) break;
9640 if (i < sequence_cnt)
9641 ok_sequence(WmShiftMouseButton, "Shift+MouseButton press/release", FALSE);
9642 else
9643 skip( "Shift+MouseButton event didn't get to the window\n" );
9646 done:
9647 if (hAccel) DestroyAcceleratorTable(hAccel);
9648 DestroyWindow(hwnd);
9651 /************* window procedures ********************/
9653 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message,
9654 WPARAM wParam, LPARAM lParam)
9656 static LONG defwndproc_counter = 0;
9657 static LONG beginpaint_counter = 0;
9658 LRESULT ret;
9659 struct recvd_message msg;
9661 if (ignore_message( message )) return 0;
9663 switch (message)
9665 case WM_ENABLE:
9667 LONG style = GetWindowLongA(hwnd, GWL_STYLE);
9668 ok((BOOL)wParam == !(style & WS_DISABLED),
9669 "wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
9670 break;
9673 case WM_CAPTURECHANGED:
9674 if (test_DestroyWindow_flag)
9676 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
9677 if (style & WS_CHILD)
9678 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
9679 else if (style & WS_POPUP)
9680 lParam = WND_POPUP_ID;
9681 else
9682 lParam = WND_PARENT_ID;
9684 break;
9686 case WM_NCDESTROY:
9688 HWND capture;
9690 ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
9691 capture = GetCapture();
9692 if (capture)
9694 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
9695 trace("current capture %p, releasing...\n", capture);
9696 ReleaseCapture();
9699 /* fall through */
9700 case WM_DESTROY:
9701 ok(GetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
9702 if (test_DestroyWindow_flag)
9704 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
9705 if (style & WS_CHILD)
9706 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
9707 else if (style & WS_POPUP)
9708 lParam = WND_POPUP_ID;
9709 else
9710 lParam = WND_PARENT_ID;
9712 break;
9714 /* test_accelerators() depends on this */
9715 case WM_NCHITTEST:
9716 return HTCLIENT;
9718 case WM_USER+10:
9720 ACTIVATION_CONTEXT_BASIC_INFORMATION basicinfo;
9721 HANDLE handle, event = (HANDLE)lParam;
9722 BOOL ret;
9724 handle = (void*)0xdeadbeef;
9725 ret = GetCurrentActCtx(&handle);
9726 ok(ret, "failed to get current context, %u\n", GetLastError());
9727 ok(handle == 0, "got active context %p\n", handle);
9729 memset(&basicinfo, 0xff, sizeof(basicinfo));
9730 ret = QueryActCtxW(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX, handle, 0, ActivationContextBasicInformation,
9731 &basicinfo, sizeof(basicinfo), NULL);
9732 ok(ret, "got %d, error %d\n", ret, GetLastError());
9733 ok(basicinfo.hActCtx == NULL, "got %p\n", basicinfo.hActCtx);
9734 ok(basicinfo.dwFlags == 0, "got %x\n", basicinfo.dwFlags);
9736 if (event) SetEvent(event);
9737 return 1;
9740 /* ignore */
9741 case WM_MOUSEMOVE:
9742 case WM_MOUSEACTIVATE:
9743 case WM_NCMOUSEMOVE:
9744 case WM_SETCURSOR:
9745 case WM_IME_SELECT:
9746 return 0;
9749 msg.hwnd = hwnd;
9750 msg.message = message;
9751 msg.flags = sent|wparam|lparam;
9752 if (defwndproc_counter) msg.flags |= defwinproc;
9753 if (beginpaint_counter) msg.flags |= beginpaint;
9754 msg.wParam = wParam;
9755 msg.lParam = lParam;
9756 msg.descr = "MsgCheckProc";
9757 add_message(&msg);
9759 if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
9761 HWND parent = GetParent(hwnd);
9762 RECT rc;
9763 MINMAXINFO *minmax = (MINMAXINFO *)lParam;
9765 GetClientRect(parent, &rc);
9766 trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
9767 trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n",
9768 minmax->ptReserved.x, minmax->ptReserved.y,
9769 minmax->ptMaxSize.x, minmax->ptMaxSize.y,
9770 minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
9771 minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
9772 minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
9774 ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
9775 minmax->ptMaxSize.x, rc.right);
9776 ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
9777 minmax->ptMaxSize.y, rc.bottom);
9780 if (message == WM_PAINT)
9782 PAINTSTRUCT ps;
9783 beginpaint_counter++;
9784 BeginPaint( hwnd, &ps );
9785 beginpaint_counter--;
9786 EndPaint( hwnd, &ps );
9787 return 0;
9790 if (message == WM_CONTEXTMENU)
9792 /* don't create context menu */
9793 return 0;
9796 defwndproc_counter++;
9797 ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam)
9798 : DefWindowProcA(hwnd, message, wParam, lParam);
9799 defwndproc_counter--;
9801 return ret;
9804 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9806 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
9809 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9811 return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
9814 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9816 static LONG defwndproc_counter = 0;
9817 LRESULT ret;
9818 struct recvd_message msg;
9820 if (ignore_message( message )) return 0;
9822 switch (message)
9824 case WM_QUERYENDSESSION:
9825 case WM_ENDSESSION:
9826 lParam &= ~0x01; /* Vista adds a 0x01 flag */
9827 break;
9830 msg.hwnd = hwnd;
9831 msg.message = message;
9832 msg.flags = sent|wparam|lparam;
9833 if (defwndproc_counter) msg.flags |= defwinproc;
9834 msg.wParam = wParam;
9835 msg.lParam = lParam;
9836 msg.descr = "popup";
9837 add_message(&msg);
9839 if (message == WM_CREATE)
9841 DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
9842 SetWindowLongA(hwnd, GWL_STYLE, style);
9845 defwndproc_counter++;
9846 ret = DefWindowProcA(hwnd, message, wParam, lParam);
9847 defwndproc_counter--;
9849 return ret;
9852 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9854 static LONG defwndproc_counter = 0;
9855 static LONG beginpaint_counter = 0;
9856 LRESULT ret;
9857 struct recvd_message msg;
9859 if (ignore_message( message )) return 0;
9861 if (log_all_parent_messages ||
9862 message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
9863 message == WM_SETFOCUS || message == WM_KILLFOCUS ||
9864 message == WM_ENABLE || message == WM_ENTERIDLE ||
9865 message == WM_DRAWITEM || message == WM_MEASUREITEM || message == WM_COMPAREITEM ||
9866 message == WM_COMMAND || message == WM_IME_SETCONTEXT)
9868 switch (message)
9870 /* ignore */
9871 case WM_NCHITTEST:
9872 return HTCLIENT;
9873 case WM_SETCURSOR:
9874 case WM_MOUSEMOVE:
9875 case WM_NCMOUSEMOVE:
9876 return 0;
9878 case WM_ERASEBKGND:
9880 RECT rc;
9881 INT ret = GetClipBox((HDC)wParam, &rc);
9883 trace("WM_ERASEBKGND: GetClipBox()=%d, %s\n", ret, wine_dbgstr_rect(&rc));
9884 break;
9888 msg.hwnd = hwnd;
9889 msg.message = message;
9890 msg.flags = sent|parent|wparam|lparam;
9891 if (defwndproc_counter) msg.flags |= defwinproc;
9892 if (beginpaint_counter) msg.flags |= beginpaint;
9893 msg.wParam = wParam;
9894 msg.lParam = lParam;
9895 msg.descr = "parent";
9896 add_message(&msg);
9899 if (message == WM_PAINT)
9901 PAINTSTRUCT ps;
9902 beginpaint_counter++;
9903 BeginPaint( hwnd, &ps );
9904 beginpaint_counter--;
9905 EndPaint( hwnd, &ps );
9906 return 0;
9909 defwndproc_counter++;
9910 ret = DefWindowProcA(hwnd, message, wParam, lParam);
9911 defwndproc_counter--;
9913 return message == WM_COMPAREITEM ? -1 : ret;
9916 static INT_PTR CALLBACK StopQuitMsgCheckProcA(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
9918 if (message == WM_CREATE)
9919 PostMessageA(hwnd, WM_CLOSE, 0, 0);
9920 else if (message == WM_CLOSE)
9922 /* Only the first WM_QUIT will survive the window destruction */
9923 PostMessageA(hwnd, WM_USER, 0x1234, 0x5678);
9924 PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
9925 PostMessageA(hwnd, WM_QUIT, 0x4321, 0x8765);
9928 return DefWindowProcA(hwnd, message, wp, lp);
9931 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9933 static LONG defwndproc_counter = 0;
9934 LRESULT ret;
9935 struct recvd_message msg;
9937 if (ignore_message( message )) return 0;
9939 if (test_def_id)
9941 DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
9942 ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
9943 if (after_end_dialog)
9944 ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
9945 else
9946 ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
9949 msg.hwnd = hwnd;
9950 msg.message = message;
9951 msg.flags = sent|wparam|lparam;
9952 if (defwndproc_counter) msg.flags |= defwinproc;
9953 msg.wParam = wParam;
9954 msg.lParam = lParam;
9955 msg.descr = "dialog";
9956 add_message(&msg);
9958 defwndproc_counter++;
9959 ret = DefDlgProcA(hwnd, message, wParam, lParam);
9960 defwndproc_counter--;
9962 return ret;
9965 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9967 static LONG defwndproc_counter = 0;
9968 LRESULT ret;
9969 struct recvd_message msg;
9971 /* log only specific messages we are interested in */
9972 switch (message)
9974 #if 0 /* probably log these as well */
9975 case WM_ACTIVATE:
9976 case WM_SETFOCUS:
9977 case WM_KILLFOCUS:
9978 #endif
9979 case WM_SHOWWINDOW:
9980 case WM_SIZE:
9981 case WM_MOVE:
9982 case WM_GETMINMAXINFO:
9983 case WM_WINDOWPOSCHANGING:
9984 case WM_WINDOWPOSCHANGED:
9985 break;
9987 default: /* ignore */
9988 /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
9989 return DefWindowProcA(hwnd, message, wParam, lParam);
9992 msg.hwnd = hwnd;
9993 msg.message = message;
9994 msg.flags = sent|wparam|lparam;
9995 if (defwndproc_counter) msg.flags |= defwinproc;
9996 msg.wParam = wParam;
9997 msg.lParam = lParam;
9998 msg.descr = "show";
9999 add_message(&msg);
10001 defwndproc_counter++;
10002 ret = DefWindowProcA(hwnd, message, wParam, lParam);
10003 defwndproc_counter--;
10005 return ret;
10008 static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
10010 switch (msg)
10012 case WM_CREATE: return 0;
10013 case WM_PAINT:
10015 MSG msg2;
10016 static int i = 0;
10018 if (i < 256)
10020 i++;
10021 if (PeekMessageA(&msg2, 0, 0, 0, 1))
10023 TranslateMessage(&msg2);
10024 DispatchMessageA(&msg2);
10026 i--;
10028 else ok(broken(1), "infinite loop\n");
10029 if ( i == 0)
10030 paint_loop_done = TRUE;
10031 return DefWindowProcA(hWnd,msg,wParam,lParam);
10034 return DefWindowProcA(hWnd,msg,wParam,lParam);
10037 static LRESULT WINAPI HotkeyMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10039 static LONG defwndproc_counter = 0;
10040 LRESULT ret;
10041 struct recvd_message msg;
10042 DWORD queue_status;
10044 if (ignore_message( message )) return 0;
10046 if ((message >= WM_KEYFIRST && message <= WM_KEYLAST) ||
10047 message == WM_HOTKEY || message >= WM_APP)
10049 msg.hwnd = hwnd;
10050 msg.message = message;
10051 msg.flags = sent|wparam|lparam;
10052 if (defwndproc_counter) msg.flags |= defwinproc;
10053 msg.wParam = wParam;
10054 msg.lParam = lParam;
10055 msg.descr = "HotkeyMsgCheckProcA";
10056 add_message(&msg);
10059 defwndproc_counter++;
10060 ret = DefWindowProcA(hwnd, message, wParam, lParam);
10061 defwndproc_counter--;
10063 if (message == WM_APP)
10065 queue_status = GetQueueStatus(QS_HOTKEY);
10066 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
10067 queue_status = GetQueueStatus(QS_POSTMESSAGE);
10068 ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
10069 PostMessageA(hwnd, WM_APP+1, 0, 0);
10071 else if (message == WM_APP+1)
10073 queue_status = GetQueueStatus(QS_HOTKEY);
10074 ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
10077 return ret;
10080 static BOOL RegisterWindowClasses(void)
10082 WNDCLASSA cls;
10083 WNDCLASSW clsW;
10085 cls.style = 0;
10086 cls.lpfnWndProc = MsgCheckProcA;
10087 cls.cbClsExtra = 0;
10088 cls.cbWndExtra = 0;
10089 cls.hInstance = GetModuleHandleA(0);
10090 cls.hIcon = 0;
10091 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
10092 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
10093 cls.lpszMenuName = NULL;
10094 cls.lpszClassName = "TestWindowClass";
10095 if(!RegisterClassA(&cls)) return FALSE;
10097 cls.lpfnWndProc = HotkeyMsgCheckProcA;
10098 cls.lpszClassName = "HotkeyWindowClass";
10099 if(!RegisterClassA(&cls)) return FALSE;
10101 cls.lpfnWndProc = ShowWindowProcA;
10102 cls.lpszClassName = "ShowWindowClass";
10103 if(!RegisterClassA(&cls)) return FALSE;
10105 cls.lpfnWndProc = PopupMsgCheckProcA;
10106 cls.lpszClassName = "TestPopupClass";
10107 if(!RegisterClassA(&cls)) return FALSE;
10109 cls.lpfnWndProc = ParentMsgCheckProcA;
10110 cls.lpszClassName = "TestParentClass";
10111 if(!RegisterClassA(&cls)) return FALSE;
10113 cls.lpfnWndProc = StopQuitMsgCheckProcA;
10114 cls.lpszClassName = "StopQuitClass";
10115 if(!RegisterClassA(&cls)) return FALSE;
10117 cls.lpfnWndProc = DefWindowProcA;
10118 cls.lpszClassName = "SimpleWindowClass";
10119 if(!RegisterClassA(&cls)) return FALSE;
10121 cls.lpfnWndProc = PaintLoopProcA;
10122 cls.lpszClassName = "PaintLoopWindowClass";
10123 if(!RegisterClassA(&cls)) return FALSE;
10125 cls.style = CS_NOCLOSE;
10126 cls.lpszClassName = "NoCloseWindowClass";
10127 if(!RegisterClassA(&cls)) return FALSE;
10129 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
10130 cls.style = 0;
10131 cls.hInstance = GetModuleHandleA(0);
10132 cls.hbrBackground = 0;
10133 cls.lpfnWndProc = TestDlgProcA;
10134 cls.lpszClassName = "TestDialogClass";
10135 if(!RegisterClassA(&cls)) return FALSE;
10137 clsW.style = 0;
10138 clsW.lpfnWndProc = MsgCheckProcW;
10139 clsW.cbClsExtra = 0;
10140 clsW.cbWndExtra = 0;
10141 clsW.hInstance = GetModuleHandleW(0);
10142 clsW.hIcon = 0;
10143 clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
10144 clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
10145 clsW.lpszMenuName = NULL;
10146 clsW.lpszClassName = testWindowClassW;
10147 RegisterClassW(&clsW); /* ignore error, this fails on Win9x */
10149 return TRUE;
10152 static BOOL is_our_logged_class(HWND hwnd)
10154 char buf[256];
10156 if (GetClassNameA(hwnd, buf, sizeof(buf)))
10158 if (!lstrcmpiA(buf, "TestWindowClass") ||
10159 !lstrcmpiA(buf, "ShowWindowClass") ||
10160 !lstrcmpiA(buf, "TestParentClass") ||
10161 !lstrcmpiA(buf, "TestPopupClass") ||
10162 !lstrcmpiA(buf, "SimpleWindowClass") ||
10163 !lstrcmpiA(buf, "TestDialogClass") ||
10164 !lstrcmpiA(buf, "MDI_frame_class") ||
10165 !lstrcmpiA(buf, "MDI_client_class") ||
10166 !lstrcmpiA(buf, "MDI_child_class") ||
10167 !lstrcmpiA(buf, "my_button_class") ||
10168 !lstrcmpiA(buf, "my_edit_class") ||
10169 !lstrcmpiA(buf, "static") ||
10170 !lstrcmpiA(buf, "ListBox") ||
10171 !lstrcmpiA(buf, "ComboBox") ||
10172 !lstrcmpiA(buf, "MyDialogClass") ||
10173 !lstrcmpiA(buf, "#32770") ||
10174 !lstrcmpiA(buf, "#32768"))
10175 return TRUE;
10177 return FALSE;
10180 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
10182 HWND hwnd;
10184 ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
10186 if (nCode == HCBT_CLICKSKIPPED)
10188 /* ignore this event, XP sends it a lot when switching focus between windows */
10189 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
10192 if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
10194 struct recvd_message msg;
10196 msg.hwnd = 0;
10197 msg.message = nCode;
10198 msg.flags = hook|wparam|lparam;
10199 msg.wParam = wParam;
10200 msg.lParam = lParam;
10201 msg.descr = "CBT";
10202 add_message(&msg);
10204 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
10207 if (nCode == HCBT_DESTROYWND)
10209 if (test_DestroyWindow_flag)
10211 DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
10212 if (style & WS_CHILD)
10213 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
10214 else if (style & WS_POPUP)
10215 lParam = WND_POPUP_ID;
10216 else
10217 lParam = WND_PARENT_ID;
10221 /* Log also SetFocus(0) calls */
10222 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
10224 if (is_our_logged_class(hwnd))
10226 struct recvd_message msg;
10228 msg.hwnd = hwnd;
10229 msg.message = nCode;
10230 msg.flags = hook|wparam|lparam;
10231 msg.wParam = wParam;
10232 msg.lParam = lParam;
10233 msg.descr = "CBT";
10234 add_message(&msg);
10236 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
10239 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
10240 DWORD event,
10241 HWND hwnd,
10242 LONG object_id,
10243 LONG child_id,
10244 DWORD thread_id,
10245 DWORD event_time)
10247 ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
10249 /* ignore mouse cursor events */
10250 if (object_id == OBJID_CURSOR) return;
10252 if (!hwnd || is_our_logged_class(hwnd))
10254 struct recvd_message msg;
10256 msg.hwnd = hwnd;
10257 msg.message = event;
10258 msg.flags = winevent_hook|wparam|lparam;
10259 msg.wParam = object_id;
10260 msg.lParam = child_id;
10261 msg.descr = "WEH";
10262 add_message(&msg);
10266 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
10267 static const WCHAR wszAnsi[] = {'U',0};
10269 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
10271 switch (uMsg)
10273 case CB_FINDSTRINGEXACT:
10274 trace("String: %p\n", (LPCWSTR)lParam);
10275 if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
10276 return 1;
10277 if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
10278 return 0;
10279 return -1;
10281 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
10284 static const struct message WmGetTextLengthAfromW[] = {
10285 { WM_GETTEXTLENGTH, sent },
10286 { WM_GETTEXT, sent|optional },
10287 { 0 }
10290 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
10292 /* dummy window proc for WM_GETTEXTLENGTH test */
10293 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
10295 switch(msg)
10297 case WM_GETTEXTLENGTH:
10298 return lstrlenW(dummy_window_text) + 37; /* some random length */
10299 case WM_GETTEXT:
10300 lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
10301 return lstrlenW( (LPWSTR)lp );
10302 default:
10303 return DefWindowProcW( hwnd, msg, wp, lp );
10307 static void test_message_conversion(void)
10309 static const WCHAR wszMsgConversionClass[] =
10310 {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
10311 WNDCLASSW cls;
10312 LRESULT lRes;
10313 HWND hwnd;
10314 WNDPROC wndproc, newproc;
10315 BOOL ret;
10317 cls.style = 0;
10318 cls.lpfnWndProc = MsgConversionProcW;
10319 cls.cbClsExtra = 0;
10320 cls.cbWndExtra = 0;
10321 cls.hInstance = GetModuleHandleW(NULL);
10322 cls.hIcon = NULL;
10323 cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
10324 cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
10325 cls.lpszMenuName = NULL;
10326 cls.lpszClassName = wszMsgConversionClass;
10327 /* this call will fail on Win9x, but that doesn't matter as this test is
10328 * meaningless on those platforms */
10329 if(!RegisterClassW(&cls)) return;
10331 hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
10332 100, 100, 200, 200, 0, 0, 0, NULL);
10333 ok(hwnd != NULL, "Window creation failed\n");
10335 /* {W, A} -> A */
10337 wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
10338 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10339 ok(lRes == 0, "String should have been converted\n");
10340 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10341 ok(lRes == 1, "String shouldn't have been converted\n");
10343 /* {W, A} -> W */
10345 wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
10346 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10347 ok(lRes == 1, "String shouldn't have been converted\n");
10348 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10349 ok(lRes == 1, "String shouldn't have been converted\n");
10351 /* Synchronous messages */
10353 lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10354 ok(lRes == 0, "String should have been converted\n");
10355 lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10356 ok(lRes == 1, "String shouldn't have been converted\n");
10358 /* Asynchronous messages */
10360 SetLastError(0);
10361 lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10362 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10363 "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10364 SetLastError(0);
10365 lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10366 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10367 "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10368 SetLastError(0);
10369 lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10370 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10371 "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10372 SetLastError(0);
10373 lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10374 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10375 "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10376 SetLastError(0);
10377 lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10378 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10379 "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10380 SetLastError(0);
10381 lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
10382 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10383 "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10384 SetLastError(0);
10385 lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
10386 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10387 "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10388 SetLastError(0);
10389 lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
10390 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
10391 "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
10393 /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
10395 hwnd = CreateWindowW (testWindowClassW, wszUnicode,
10396 WS_OVERLAPPEDWINDOW,
10397 100, 100, 200, 200, 0, 0, 0, NULL);
10398 assert(hwnd);
10399 flush_sequence();
10400 lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
10401 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
10402 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
10403 "got bad length %ld\n", lRes );
10405 flush_sequence();
10406 lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
10407 hwnd, WM_GETTEXTLENGTH, 0, 0);
10408 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
10409 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
10410 "got bad length %ld\n", lRes );
10412 wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
10413 newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
10414 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
10415 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
10416 NULL, 0, NULL, NULL ) ||
10417 broken(lRes == lstrlenW(dummy_window_text) + 37),
10418 "got bad length %ld\n", lRes );
10420 SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc ); /* restore old wnd proc */
10421 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
10422 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
10423 NULL, 0, NULL, NULL ) ||
10424 broken(lRes == lstrlenW(dummy_window_text) + 37),
10425 "got bad length %ld\n", lRes );
10427 ret = DestroyWindow(hwnd);
10428 ok( ret, "DestroyWindow() error %d\n", GetLastError());
10431 struct timer_info
10433 HWND hWnd;
10434 HANDLE handles[2];
10435 DWORD id;
10438 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
10442 #define TIMER_ID 0x19
10443 #define TIMER_COUNT_EXPECTED 100
10444 #define TIMER_COUNT_TOLERANCE 10
10446 static int count = 0;
10447 static void CALLBACK callback_count(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
10449 count++;
10452 static DWORD exception;
10453 static void CALLBACK callback_exception(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
10455 count++;
10456 RaiseException(exception, 0, 0, NULL);
10459 static DWORD WINAPI timer_thread_proc(LPVOID x)
10461 struct timer_info *info = x;
10462 DWORD r;
10464 r = KillTimer(info->hWnd, 0x19);
10465 ok(r,"KillTimer failed in thread\n");
10466 r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
10467 ok(r,"SetTimer failed in thread\n");
10468 ok(r==TIMER_ID,"SetTimer id different\n");
10469 r = SetEvent(info->handles[0]);
10470 ok(r,"SetEvent failed in thread\n");
10471 return 0;
10474 static void test_timers(void)
10476 struct timer_info info;
10477 DWORD start;
10478 DWORD id;
10479 MSG msg;
10481 info.hWnd = CreateWindowA("TestWindowClass", NULL,
10482 WS_OVERLAPPEDWINDOW ,
10483 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
10484 NULL, NULL, 0);
10486 info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
10487 ok(info.id, "SetTimer failed\n");
10488 ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
10489 info.handles[0] = CreateEventW(NULL,0,0,NULL);
10490 info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
10492 WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
10494 WaitForSingleObject(info.handles[1], INFINITE);
10496 CloseHandle(info.handles[0]);
10497 CloseHandle(info.handles[1]);
10499 ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
10501 /* Check the minimum allowed timeout for a timer. MSDN indicates that it should be 10.0 ms,
10502 * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to
10503 * 15.6 ms. Since there is some measurement error between test runs we are allowing for
10504 * ±9 counts (~4 ms) around the expected value.
10506 count = 0;
10507 id = SetTimer(info.hWnd, TIMER_ID, 0, callback_count);
10508 ok(id != 0, "did not get id from SetTimer.\n");
10509 ok(id==TIMER_ID, "SetTimer timer ID different\n");
10510 start = GetTickCount();
10511 while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
10512 DispatchMessageA(&msg);
10513 ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE /* xp */
10514 || broken(abs(count-64) <= TIMER_COUNT_TOLERANCE) /* most common */
10515 || broken(abs(count-43) <= TIMER_COUNT_TOLERANCE) /* w2k3, win8 */,
10516 "did not get expected count for minimum timeout (%d != ~%d).\n",
10517 count, TIMER_COUNT_EXPECTED);
10518 ok(KillTimer(info.hWnd, id), "KillTimer failed\n");
10519 /* Perform the same check on SetSystemTimer (only available on w2k3 and older) */
10520 if (pSetSystemTimer)
10522 int syscount = 0;
10524 count = 0;
10525 id = pSetSystemTimer(info.hWnd, TIMER_ID, 0, callback_count);
10526 ok(id != 0, "did not get id from SetSystemTimer.\n");
10527 ok(id==TIMER_ID, "SetTimer timer ID different\n");
10528 start = GetTickCount();
10529 while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
10531 if (msg.message == WM_SYSTIMER)
10532 syscount++;
10533 DispatchMessageA(&msg);
10535 ok(abs(syscount-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE
10536 || broken(abs(syscount-64) < TIMER_COUNT_TOLERANCE) /* most common */
10537 || broken(syscount > 4000 && syscount < 12000) /* win2k3sp0 */,
10538 "did not get expected count for minimum timeout (%d != ~%d).\n",
10539 syscount, TIMER_COUNT_EXPECTED);
10540 todo_wine ok(count == 0, "did not get expected count for callback timeout (%d != 0).\n",
10541 count);
10542 ok(pKillSystemTimer(info.hWnd, id), "KillSystemTimer failed\n");
10545 ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
10548 static void test_timers_no_wnd(void)
10550 static UINT_PTR ids[0xffff];
10551 UINT_PTR id, id2;
10552 DWORD start;
10553 MSG msg;
10554 int i;
10556 count = 0;
10557 id = SetTimer(NULL, 0, 100, callback_count);
10558 ok(id != 0, "did not get id from SetTimer.\n");
10559 id2 = SetTimer(NULL, id, 200, callback_count);
10560 ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
10561 Sleep(150);
10562 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10563 ok(count == 0, "did not get zero count as expected (%i).\n", count);
10564 Sleep(150);
10565 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10566 ok(count == 1, "did not get one count as expected (%i).\n", count);
10567 KillTimer(NULL, id);
10568 Sleep(250);
10569 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10570 ok(count == 1, "killing replaced timer did not work (%i).\n", count);
10572 /* Check the minimum allowed timeout for a timer. MSDN indicates that it should be 10.0 ms,
10573 * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to
10574 * 15.6 ms. Since there is some measurement error between test runs we are allowing for
10575 * ±9 counts (~4 ms) around the expected value.
10577 count = 0;
10578 id = SetTimer(NULL, 0, 0, callback_count);
10579 ok(id != 0, "did not get id from SetTimer.\n");
10580 start = GetTickCount();
10581 while (GetTickCount()-start < 1001 && GetMessageA(&msg, NULL, 0, 0))
10582 DispatchMessageA(&msg);
10583 ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE /* xp */
10584 || broken(abs(count-64) <= TIMER_COUNT_TOLERANCE) /* most common */
10585 || broken(abs(count-43) <= TIMER_COUNT_TOLERANCE) /* w1064v1809 */,
10586 "did not get expected count for minimum timeout (%d != ~%d).\n",
10587 count, TIMER_COUNT_EXPECTED);
10588 KillTimer(NULL, id);
10589 /* Note: SetSystemTimer doesn't support a NULL window, see test_timers */
10591 if (pSetCoalescableTimer)
10593 count = 0;
10594 id = pSetCoalescableTimer(NULL, 0, 0, callback_count, 0);
10595 ok(id != 0, "SetCoalescableTimer failed with %u.\n", GetLastError());
10596 start = GetTickCount();
10597 while (GetTickCount()-start < 100 && GetMessageA(&msg, NULL, 0, 0))
10598 DispatchMessageA(&msg);
10599 ok(count > 1, "expected count > 1, got %d.\n", count);
10600 KillTimer(NULL, id);
10602 else
10603 win_skip("SetCoalescableTimer not available.\n");
10605 /* Check what happens when we're running out of timers */
10606 for (i = 0; i < ARRAY_SIZE(ids); i++)
10608 SetLastError(0xdeadbeef);
10609 ids[i] = SetTimer(NULL, 0, USER_TIMER_MAXIMUM, tfunc);
10610 if (!ids[i]) break;
10612 ok(i != ARRAY_SIZE(ids), "all timers were created successfully\n");
10613 ok(GetLastError()==ERROR_NO_MORE_USER_HANDLES || broken(GetLastError()==0xdeadbeef),
10614 "GetLastError() = %d\n", GetLastError());
10615 while (i > 0) KillTimer(NULL, ids[--i]);
10618 static void test_timers_exception(DWORD code)
10620 UINT_PTR id;
10621 MSG msg;
10623 exception = code;
10624 id = SetTimer(NULL, 0, 1000, callback_exception);
10625 ok(id != 0, "did not get id from SetTimer.\n");
10627 memset(&msg, 0, sizeof(msg));
10628 msg.message = WM_TIMER;
10629 msg.wParam = id;
10630 msg.lParam = (LPARAM)callback_exception;
10632 count = 0;
10633 DispatchMessageA(&msg);
10634 ok(count == 1, "did not get one count as expected (%i).\n", count);
10636 KillTimer(NULL, id);
10639 static void test_timers_exceptions(void)
10641 test_timers_exception(EXCEPTION_ACCESS_VIOLATION);
10642 test_timers_exception(EXCEPTION_DATATYPE_MISALIGNMENT);
10643 test_timers_exception(EXCEPTION_BREAKPOINT);
10644 test_timers_exception(EXCEPTION_SINGLE_STEP);
10645 test_timers_exception(EXCEPTION_ARRAY_BOUNDS_EXCEEDED);
10646 test_timers_exception(EXCEPTION_FLT_DENORMAL_OPERAND);
10647 test_timers_exception(EXCEPTION_FLT_DIVIDE_BY_ZERO);
10648 test_timers_exception(EXCEPTION_FLT_INEXACT_RESULT);
10649 test_timers_exception(EXCEPTION_ILLEGAL_INSTRUCTION);
10650 test_timers_exception(0xE000BEEF); /* customer exception */
10653 /* Various win events with arbitrary parameters */
10654 static const struct message WmWinEventsSeq[] = {
10655 { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
10656 { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
10657 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
10658 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
10659 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
10660 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
10661 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
10662 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
10663 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
10664 /* our win event hook ignores OBJID_CURSOR events */
10665 /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
10666 { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
10667 { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
10668 { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
10669 { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
10670 { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
10671 { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
10672 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
10673 { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
10674 { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
10675 { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
10676 { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
10677 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
10678 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
10679 { 0 }
10681 static const struct message WmWinEventCaretSeq[] = {
10682 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
10683 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
10684 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
10685 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
10686 { 0 }
10688 static const struct message WmWinEventCaretSeq_2[] = {
10689 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
10690 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
10691 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
10692 { 0 }
10694 static const struct message WmWinEventAlertSeq[] = {
10695 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
10696 { 0 }
10698 static const struct message WmWinEventAlertSeq_2[] = {
10699 /* create window in the thread proc */
10700 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
10701 /* our test event */
10702 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
10703 { 0 }
10705 static const struct message WmGlobalHookSeq_1[] = {
10706 /* create window in the thread proc */
10707 { HCBT_CREATEWND, hook|lparam, 0, 2 },
10708 /* our test events */
10709 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
10710 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
10711 { 0 }
10713 static const struct message WmGlobalHookSeq_2[] = {
10714 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
10715 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
10716 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
10717 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
10718 { 0 }
10721 static const struct message WmMouseLLHookSeq[] = {
10722 { WM_MOUSEMOVE, hook },
10723 { WM_LBUTTONUP, hook },
10724 { WM_MOUSEMOVE, hook },
10725 { 0 }
10728 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
10729 DWORD event,
10730 HWND hwnd,
10731 LONG object_id,
10732 LONG child_id,
10733 DWORD thread_id,
10734 DWORD event_time)
10736 char buf[256];
10738 if (GetClassNameA(hwnd, buf, sizeof(buf)))
10740 if (!lstrcmpiA(buf, "TestWindowClass") ||
10741 !lstrcmpiA(buf, "static"))
10743 struct recvd_message msg;
10745 msg.hwnd = hwnd;
10746 msg.message = event;
10747 msg.flags = winevent_hook|wparam|lparam;
10748 msg.wParam = object_id;
10749 msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
10750 msg.descr = "WEH_2";
10751 add_message(&msg);
10756 static HHOOK hCBT_global_hook;
10757 static DWORD cbt_global_hook_thread_id;
10759 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
10761 HWND hwnd;
10762 char buf[256];
10764 if (nCode == HCBT_SYSCOMMAND)
10766 struct recvd_message msg;
10768 msg.hwnd = 0;
10769 msg.message = nCode;
10770 msg.flags = hook|wparam|lparam;
10771 msg.wParam = wParam;
10772 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
10773 msg.descr = "CBT_2";
10774 add_message(&msg);
10776 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
10778 /* WH_MOUSE_LL hook */
10779 if (nCode == HC_ACTION)
10781 MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
10783 /* we can't test for real mouse events */
10784 if (mhll->flags & LLMHF_INJECTED)
10786 struct recvd_message msg;
10788 memset (&msg, 0, sizeof (msg));
10789 msg.message = wParam;
10790 msg.flags = hook;
10791 msg.descr = "CBT_2";
10792 add_message(&msg);
10794 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
10797 /* Log also SetFocus(0) calls */
10798 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
10800 if (GetClassNameA(hwnd, buf, sizeof(buf)))
10802 if (!lstrcmpiA(buf, "TestWindowClass") ||
10803 !lstrcmpiA(buf, "static"))
10805 struct recvd_message msg;
10807 msg.hwnd = hwnd;
10808 msg.message = nCode;
10809 msg.flags = hook|wparam|lparam;
10810 msg.wParam = wParam;
10811 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
10812 msg.descr = "CBT_2";
10813 add_message(&msg);
10816 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
10819 static DWORD WINAPI win_event_global_thread_proc(void *param)
10821 HWND hwnd;
10822 MSG msg;
10823 HANDLE hevent = *(HANDLE *)param;
10825 assert(pNotifyWinEvent);
10827 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
10828 assert(hwnd);
10829 trace("created thread window %p\n", hwnd);
10831 *(HWND *)param = hwnd;
10833 flush_sequence();
10834 /* this event should be received only by our new hook proc,
10835 * an old one does not expect an event from another thread.
10837 pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
10838 SetEvent(hevent);
10840 while (GetMessageA(&msg, 0, 0, 0))
10842 TranslateMessage(&msg);
10843 DispatchMessageA(&msg);
10845 return 0;
10848 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
10850 HWND hwnd;
10851 MSG msg;
10852 HANDLE hevent = *(HANDLE *)param;
10854 flush_sequence();
10855 /* these events should be received only by our new hook proc,
10856 * an old one does not expect an event from another thread.
10859 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
10860 assert(hwnd);
10861 trace("created thread window %p\n", hwnd);
10863 *(HWND *)param = hwnd;
10865 /* Windows doesn't like when a thread plays games with the focus,
10866 that leads to all kinds of misbehaviours and failures to activate
10867 a window. So, better keep next lines commented out.
10868 SetFocus(0);
10869 SetFocus(hwnd);*/
10871 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
10872 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
10874 SetEvent(hevent);
10876 while (GetMessageA(&msg, 0, 0, 0))
10878 TranslateMessage(&msg);
10879 DispatchMessageA(&msg);
10881 return 0;
10884 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
10886 HWND hwnd;
10887 MSG msg;
10888 HANDLE hevent = *(HANDLE *)param;
10890 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
10891 assert(hwnd);
10892 trace("created thread window %p\n", hwnd);
10894 *(HWND *)param = hwnd;
10896 flush_sequence();
10898 /* Windows doesn't like when a thread plays games with the focus,
10899 * that leads to all kinds of misbehaviours and failures to activate
10900 * a window. So, better don't generate a mouse click message below.
10902 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10903 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
10904 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10906 SetEvent(hevent);
10907 while (GetMessageA(&msg, 0, 0, 0))
10909 TranslateMessage(&msg);
10910 DispatchMessageA(&msg);
10912 return 0;
10915 static void test_winevents(void)
10917 BOOL ret;
10918 MSG msg;
10919 HWND hwnd, hwnd2;
10920 UINT i;
10921 HANDLE hthread, hevent;
10922 DWORD tid;
10923 HWINEVENTHOOK hhook;
10924 const struct message *events = WmWinEventsSeq;
10926 hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
10927 WS_OVERLAPPEDWINDOW,
10928 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
10929 NULL, NULL, 0);
10930 assert(hwnd);
10932 /****** start of global hook test *************/
10933 hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
10934 if (!hCBT_global_hook)
10936 ok(DestroyWindow(hwnd), "failed to destroy window\n");
10937 skip( "cannot set global hook\n" );
10938 return;
10941 hevent = CreateEventA(NULL, 0, 0, NULL);
10942 assert(hevent);
10943 hwnd2 = hevent;
10945 hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
10946 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10948 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10950 ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
10952 flush_sequence();
10953 /* this one should be received only by old hook proc */
10954 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
10955 /* this one should be received only by old hook proc */
10956 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
10958 ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
10960 ret = UnhookWindowsHookEx(hCBT_global_hook);
10961 ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
10963 PostThreadMessageA(tid, WM_QUIT, 0, 0);
10964 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10965 CloseHandle(hthread);
10966 CloseHandle(hevent);
10967 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10968 /****** end of global hook test *************/
10970 if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
10972 ok(DestroyWindow(hwnd), "failed to destroy window\n");
10973 return;
10976 flush_sequence();
10978 if (0)
10980 /* this test doesn't pass under Win9x */
10981 /* win2k ignores events with hwnd == 0 */
10982 SetLastError(0xdeadbeef);
10983 pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
10984 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
10985 GetLastError() == 0xdeadbeef, /* Win9x */
10986 "unexpected error %d\n", GetLastError());
10987 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
10990 for (i = 0; i < ARRAY_SIZE(WmWinEventsSeq); i++)
10991 pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
10993 ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
10995 /****** start of event filtering test *************/
10996 hhook = pSetWinEventHook(
10997 EVENT_OBJECT_SHOW, /* 0x8002 */
10998 EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
10999 GetModuleHandleA(0), win_event_global_hook_proc,
11000 GetCurrentProcessId(), 0,
11001 WINEVENT_INCONTEXT);
11002 ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
11004 hevent = CreateEventA(NULL, 0, 0, NULL);
11005 assert(hevent);
11006 hwnd2 = hevent;
11008 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
11009 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
11011 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
11013 ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
11015 flush_sequence();
11016 /* this one should be received only by old hook proc */
11017 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
11018 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
11019 /* this one should be received only by old hook proc */
11020 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
11022 ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
11024 ret = pUnhookWinEvent(hhook);
11025 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
11027 PostThreadMessageA(tid, WM_QUIT, 0, 0);
11028 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
11029 CloseHandle(hthread);
11030 CloseHandle(hevent);
11031 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
11032 /****** end of event filtering test *************/
11034 /****** start of out of context event test *************/
11035 hhook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0,
11036 win_event_global_hook_proc, GetCurrentProcessId(), 0,
11037 WINEVENT_OUTOFCONTEXT);
11038 ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
11040 hevent = CreateEventA(NULL, 0, 0, NULL);
11041 assert(hevent);
11042 hwnd2 = hevent;
11044 flush_sequence();
11046 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
11047 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
11049 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
11051 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
11052 /* process pending winevent messages */
11053 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
11054 ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
11056 flush_sequence();
11057 /* this one should be received only by old hook proc */
11058 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
11059 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
11060 /* this one should be received only by old hook proc */
11061 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
11063 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
11064 /* process pending winevent messages */
11065 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
11066 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
11068 ret = pUnhookWinEvent(hhook);
11069 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
11071 PostThreadMessageA(tid, WM_QUIT, 0, 0);
11072 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
11073 CloseHandle(hthread);
11074 CloseHandle(hevent);
11075 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
11076 /****** end of out of context event test *************/
11078 /****** start of MOUSE_LL hook test *************/
11079 hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
11080 /* WH_MOUSE_LL is not supported on Win9x platforms */
11081 if (!hCBT_global_hook)
11083 win_skip("Skipping WH_MOUSE_LL test on this platform\n");
11084 goto skip_mouse_ll_hook_test;
11087 hevent = CreateEventA(NULL, 0, 0, NULL);
11088 assert(hevent);
11089 hwnd2 = hevent;
11091 hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
11092 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
11094 while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
11095 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
11097 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
11098 flush_sequence();
11100 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
11101 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
11102 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
11104 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
11106 ret = UnhookWindowsHookEx(hCBT_global_hook);
11107 ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
11109 PostThreadMessageA(tid, WM_QUIT, 0, 0);
11110 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
11111 CloseHandle(hthread);
11112 CloseHandle(hevent);
11113 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
11114 /****** end of MOUSE_LL hook test *************/
11115 skip_mouse_ll_hook_test:
11117 ok(DestroyWindow(hwnd), "failed to destroy window\n");
11120 static void test_set_hook(void)
11122 BOOL ret;
11123 HHOOK hhook;
11124 HWINEVENTHOOK hwinevent_hook;
11126 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
11127 ok(hhook != 0, "local hook does not require hModule set to 0\n");
11128 UnhookWindowsHookEx(hhook);
11130 if (0)
11132 /* this test doesn't pass under Win9x: BUG! */
11133 SetLastError(0xdeadbeef);
11134 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
11135 ok(!hhook, "global hook requires hModule != 0\n");
11136 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
11139 SetLastError(0xdeadbeef);
11140 hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
11141 ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
11142 ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
11143 GetLastError() == 0xdeadbeef, /* Win9x */
11144 "unexpected error %d\n", GetLastError());
11146 SetLastError(0xdeadbeef);
11147 ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
11148 ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
11149 GetLastError() == 0xdeadbeef, /* Win9x */
11150 "unexpected error %d\n", GetLastError());
11152 if (!pSetWinEventHook || !pUnhookWinEvent) return;
11154 /* even process local incontext hooks require hmodule */
11155 SetLastError(0xdeadbeef);
11156 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
11157 GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
11158 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
11159 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
11160 GetLastError() == 0xdeadbeef, /* Win9x */
11161 "unexpected error %d\n", GetLastError());
11163 /* even thread local incontext hooks require hmodule */
11164 SetLastError(0xdeadbeef);
11165 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
11166 GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
11167 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
11168 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
11169 GetLastError() == 0xdeadbeef, /* Win9x */
11170 "unexpected error %d\n", GetLastError());
11172 if (0)
11174 /* these 3 tests don't pass under Win9x */
11175 SetLastError(0xdeadbeef);
11176 hwinevent_hook = pSetWinEventHook(1, 0, 0, win_event_proc,
11177 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
11178 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
11179 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
11181 SetLastError(0xdeadbeef);
11182 hwinevent_hook = pSetWinEventHook(-1, 1, 0, win_event_proc,
11183 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
11184 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
11185 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
11187 SetLastError(0xdeadbeef);
11188 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
11189 0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
11190 ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
11191 ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
11194 SetLastError(0xdeadbeef);
11195 hwinevent_hook = pSetWinEventHook(0, 0, 0, win_event_proc,
11196 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
11197 ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
11198 ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
11199 ret = pUnhookWinEvent(hwinevent_hook);
11200 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
11202 todo_wine {
11203 /* This call succeeds under win2k SP4, but fails under Wine.
11204 Does win2k test/use passed process id? */
11205 SetLastError(0xdeadbeef);
11206 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
11207 0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
11208 ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
11209 ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
11210 ret = pUnhookWinEvent(hwinevent_hook);
11211 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
11214 SetLastError(0xdeadbeef);
11215 ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
11216 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
11217 GetLastError() == 0xdeadbeef, /* Win9x */
11218 "unexpected error %d\n", GetLastError());
11221 static HWND hook_hwnd;
11222 static HHOOK recursive_hook;
11223 static int hook_depth, max_hook_depth;
11225 static LRESULT WINAPI rec_get_message_hook(int code, WPARAM w, LPARAM l)
11227 LRESULT res;
11228 MSG msg;
11229 BOOL b;
11231 hook_depth++;
11232 if(hook_depth > max_hook_depth)
11233 max_hook_depth = hook_depth;
11235 b = PeekMessageW(&msg, hook_hwnd, 0, 0, PM_NOREMOVE);
11236 ok(b, "PeekMessage failed\n");
11238 res = CallNextHookEx(recursive_hook, code, w, l);
11240 hook_depth--;
11241 return res;
11244 static void test_recursive_hook(void)
11246 MSG msg;
11247 BOOL b;
11249 hook_hwnd = CreateWindowA("Static", NULL, WS_POPUP, 0, 0, 200, 60, NULL, NULL, NULL, NULL);
11250 ok(hook_hwnd != NULL, "CreateWindow failed\n");
11252 recursive_hook = SetWindowsHookExW(WH_GETMESSAGE, rec_get_message_hook, NULL, GetCurrentThreadId());
11253 ok(recursive_hook != NULL, "SetWindowsHookEx failed\n");
11255 PostMessageW(hook_hwnd, WM_USER, 0, 0);
11256 PostMessageW(hook_hwnd, WM_USER+1, 0, 0);
11258 hook_depth = 0;
11259 GetMessageW(&msg, hook_hwnd, 0, 0);
11260 ok(15 <= max_hook_depth && max_hook_depth < 45, "max_hook_depth = %d\n", max_hook_depth);
11261 trace("max_hook_depth = %d\n", max_hook_depth);
11263 b = UnhookWindowsHookEx(recursive_hook);
11264 ok(b, "UnhokWindowsHookEx failed\n");
11266 DestroyWindow(hook_hwnd);
11269 static const struct message ScrollWindowPaint1[] = {
11270 { WM_PAINT, sent },
11271 { WM_ERASEBKGND, sent|beginpaint },
11272 { WM_GETTEXTLENGTH, sent|optional },
11273 { WM_PAINT, sent|optional },
11274 { WM_NCPAINT, sent|beginpaint|optional },
11275 { WM_GETTEXT, sent|beginpaint|optional },
11276 { WM_GETTEXT, sent|beginpaint|optional },
11277 { WM_GETTEXT, sent|beginpaint|optional },
11278 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
11279 { WM_ERASEBKGND, sent|beginpaint|optional },
11280 { 0 }
11283 static const struct message ScrollWindowPaint2[] = {
11284 { WM_PAINT, sent },
11285 { 0 }
11288 static void test_scrollwindowex(void)
11290 HWND hwnd, hchild;
11291 RECT rect={0,0,130,130};
11293 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
11294 WS_VISIBLE|WS_OVERLAPPEDWINDOW,
11295 100, 100, 200, 200, 0, 0, 0, NULL);
11296 ok (hwnd != 0, "Failed to create overlapped window\n");
11297 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
11298 WS_VISIBLE|WS_CAPTION|WS_CHILD,
11299 10, 10, 150, 150, hwnd, 0, 0, NULL);
11300 ok (hchild != 0, "Failed to create child\n");
11301 UpdateWindow(hwnd);
11302 flush_events();
11303 flush_sequence();
11305 /* scroll without the child window */
11306 trace("start scroll\n");
11307 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
11308 SW_ERASE|SW_INVALIDATE);
11309 ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
11310 trace("end scroll\n");
11311 flush_sequence();
11312 flush_events();
11313 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
11314 flush_events();
11315 flush_sequence();
11317 /* Now without the SW_ERASE flag */
11318 trace("start scroll\n");
11319 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
11320 ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
11321 trace("end scroll\n");
11322 flush_sequence();
11323 flush_events();
11324 ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", FALSE);
11325 flush_events();
11326 flush_sequence();
11328 /* now scroll the child window as well */
11329 trace("start scroll\n");
11330 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
11331 SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
11332 /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
11333 /* windows sometimes a WM_MOVE */
11334 ok_sequence(WmEmptySeq, "ScrollWindowEx", TRUE);
11335 trace("end scroll\n");
11336 flush_sequence();
11337 flush_events();
11338 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
11339 flush_events();
11340 flush_sequence();
11342 /* now scroll with ScrollWindow() */
11343 trace("start scroll with ScrollWindow\n");
11344 ScrollWindow( hwnd, 5, 5, NULL, NULL);
11345 trace("end scroll\n");
11346 flush_sequence();
11347 flush_events();
11348 ok_sequence(ScrollWindowPaint1, "ScrollWindow", FALSE);
11350 ok(DestroyWindow(hchild), "failed to destroy window\n");
11351 ok(DestroyWindow(hwnd), "failed to destroy window\n");
11352 flush_sequence();
11355 static const struct message destroy_window_with_children[] = {
11356 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
11357 { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
11358 { 0x0090, sent|optional },
11359 { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
11360 { 0x0090, sent|optional },
11361 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
11362 { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
11363 { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
11364 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
11365 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
11366 { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
11367 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
11368 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
11369 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
11370 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
11371 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
11372 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
11373 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
11374 { 0 }
11377 static void test_DestroyWindow(void)
11379 BOOL ret;
11380 HWND parent, child1, child2, child3, child4, test;
11381 UINT_PTR child_id = WND_CHILD_ID + 1;
11383 parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11384 100, 100, 200, 200, 0, 0, 0, NULL);
11385 assert(parent != 0);
11386 child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
11387 0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
11388 assert(child1 != 0);
11389 child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
11390 0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
11391 assert(child2 != 0);
11392 child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
11393 0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
11394 assert(child3 != 0);
11395 child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
11396 0, 0, 50, 50, parent, 0, 0, NULL);
11397 assert(child4 != 0);
11399 /* test owner/parent of child2 */
11400 test = GetParent(child2);
11401 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
11402 ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
11403 test = GetAncestor(child2, GA_PARENT);
11404 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
11405 test = GetWindow(child2, GW_OWNER);
11406 ok(!test, "wrong owner %p\n", test);
11408 test = SetParent(child2, parent);
11409 ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
11411 /* test owner/parent of the parent */
11412 test = GetParent(parent);
11413 ok(!test, "wrong parent %p\n", test);
11414 ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
11415 test = GetAncestor(parent, GA_PARENT);
11416 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
11417 test = GetWindow(parent, GW_OWNER);
11418 ok(!test, "wrong owner %p\n", test);
11420 /* test owner/parent of child1 */
11421 test = GetParent(child1);
11422 ok(test == parent, "wrong parent %p\n", test);
11423 ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
11424 test = GetAncestor(child1, GA_PARENT);
11425 ok(test == parent, "wrong parent %p\n", test);
11426 test = GetWindow(child1, GW_OWNER);
11427 ok(!test, "wrong owner %p\n", test);
11429 /* test owner/parent of child2 */
11430 test = GetParent(child2);
11431 ok(test == parent, "wrong parent %p\n", test);
11432 ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
11433 test = GetAncestor(child2, GA_PARENT);
11434 ok(test == parent, "wrong parent %p\n", test);
11435 test = GetWindow(child2, GW_OWNER);
11436 ok(!test, "wrong owner %p\n", test);
11438 /* test owner/parent of child3 */
11439 test = GetParent(child3);
11440 ok(test == child1, "wrong parent %p\n", test);
11441 ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
11442 test = GetAncestor(child3, GA_PARENT);
11443 ok(test == child1, "wrong parent %p\n", test);
11444 test = GetWindow(child3, GW_OWNER);
11445 ok(!test, "wrong owner %p\n", test);
11447 /* test owner/parent of child4 */
11448 test = GetParent(child4);
11449 ok(test == parent, "wrong parent %p\n", test);
11450 ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
11451 test = GetAncestor(child4, GA_PARENT);
11452 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
11453 test = GetWindow(child4, GW_OWNER);
11454 ok(test == parent, "wrong owner %p\n", test);
11456 flush_sequence();
11458 trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
11459 parent, child1, child2, child3, child4);
11461 SetCapture(child4);
11462 test = GetCapture();
11463 ok(test == child4, "wrong capture window %p\n", test);
11465 test_DestroyWindow_flag = TRUE;
11466 ret = DestroyWindow(parent);
11467 ok( ret, "DestroyWindow() error %d\n", GetLastError());
11468 test_DestroyWindow_flag = FALSE;
11469 ok_sequence(destroy_window_with_children, "destroy window with children", FALSE);
11471 ok(!IsWindow(parent), "parent still exists\n");
11472 ok(!IsWindow(child1), "child1 still exists\n");
11473 ok(!IsWindow(child2), "child2 still exists\n");
11474 ok(!IsWindow(child3), "child3 still exists\n");
11475 ok(!IsWindow(child4), "child4 still exists\n");
11477 test = GetCapture();
11478 ok(!test, "wrong capture window %p\n", test);
11482 static const struct message WmDispatchPaint[] = {
11483 { WM_NCPAINT, sent },
11484 { WM_GETTEXT, sent|defwinproc|optional },
11485 { WM_GETTEXT, sent|defwinproc|optional },
11486 { WM_ERASEBKGND, sent },
11487 { 0 }
11490 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11492 if (message == WM_PAINT) return 0;
11493 return MsgCheckProcA( hwnd, message, wParam, lParam );
11496 static void test_DispatchMessage(void)
11498 RECT rect;
11499 MSG msg;
11500 int count;
11501 HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11502 100, 100, 200, 200, 0, 0, 0, NULL);
11503 ShowWindow( hwnd, SW_SHOW );
11504 UpdateWindow( hwnd );
11505 flush_events();
11506 flush_sequence();
11507 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
11509 SetRect( &rect, -5, -5, 5, 5 );
11510 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
11511 count = 0;
11512 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
11514 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
11515 else
11517 flush_sequence();
11518 DispatchMessageA( &msg );
11519 /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
11520 if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
11521 else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
11522 if (++count > 10) break;
11525 ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
11527 trace("now without DispatchMessage\n");
11528 flush_sequence();
11529 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
11530 count = 0;
11531 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
11533 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
11534 else
11536 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
11537 flush_sequence();
11538 /* this will send WM_NCCPAINT just like DispatchMessage does */
11539 GetUpdateRgn( hwnd, hrgn, TRUE );
11540 ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
11541 DeleteObject( hrgn );
11542 GetClientRect( hwnd, &rect );
11543 ValidateRect( hwnd, &rect ); /* this will stop WM_PAINTs */
11544 ok( !count, "Got multiple WM_PAINTs\n" );
11545 if (++count > 10) break;
11549 flush_sequence();
11550 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
11551 count = 0;
11552 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
11554 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
11555 else
11557 HDC hdc;
11559 flush_sequence();
11560 hdc = BeginPaint( hwnd, NULL );
11561 ok( !hdc, "got valid hdc %p from BeginPaint\n", hdc );
11562 ok( !EndPaint( hwnd, NULL ), "EndPaint succeeded\n" );
11563 ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
11564 ok( !count, "Got multiple WM_PAINTs\n" );
11565 if (++count > 10) break;
11568 DestroyWindow(hwnd);
11572 static const struct message WmUser[] = {
11573 { WM_USER, sent },
11574 { 0 }
11577 struct sendmsg_info
11579 HWND hwnd;
11580 DWORD timeout;
11581 DWORD ret;
11582 HANDLE ready;
11585 static DWORD CALLBACK send_msg_thread( LPVOID arg )
11587 struct sendmsg_info *info = arg;
11588 SetLastError( 0xdeadbeef );
11589 SetEvent( info->ready );
11590 info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
11591 if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT ||
11592 broken(GetLastError() == 0), /* win9x */
11593 "unexpected error %d\n", GetLastError());
11594 return 0;
11597 static void wait_for_thread( HANDLE thread )
11599 while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
11601 MSG msg;
11602 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA(&msg);
11606 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11608 if (message == WM_USER) Sleep(200);
11609 return MsgCheckProcA( hwnd, message, wParam, lParam );
11612 static void test_SendMessageTimeout(void)
11614 HANDLE thread;
11615 struct sendmsg_info info;
11616 DWORD tid;
11617 BOOL is_win9x;
11619 info.ready = CreateEventA( NULL, 0, 0, NULL );
11620 info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11621 100, 100, 200, 200, 0, 0, 0, NULL);
11622 flush_events();
11623 flush_sequence();
11625 info.timeout = 1000;
11626 info.ret = 0xdeadbeef;
11627 ResetEvent( info.ready );
11628 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11629 WaitForSingleObject( info.ready, INFINITE );
11630 wait_for_thread( thread );
11631 CloseHandle( thread );
11632 ok( info.ret == 1, "SendMessageTimeout failed\n" );
11633 ok_sequence( WmUser, "WmUser", FALSE );
11635 info.timeout = 1;
11636 info.ret = 0xdeadbeef;
11637 ResetEvent( info.ready );
11638 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11639 WaitForSingleObject( info.ready, INFINITE );
11640 Sleep(100); /* SendMessageTimeout should time out here */
11641 wait_for_thread( thread );
11642 CloseHandle( thread );
11643 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
11644 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
11646 /* 0 means infinite timeout (but not on win9x) */
11647 info.timeout = 0;
11648 info.ret = 0xdeadbeef;
11649 ResetEvent( info.ready );
11650 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11651 WaitForSingleObject( info.ready, INFINITE );
11652 Sleep(100);
11653 wait_for_thread( thread );
11654 CloseHandle( thread );
11655 is_win9x = !info.ret;
11656 if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
11657 else ok_sequence( WmUser, "WmUser", FALSE );
11659 /* timeout is treated as signed despite the prototype (but not on win9x) */
11660 info.timeout = 0x7fffffff;
11661 info.ret = 0xdeadbeef;
11662 ResetEvent( info.ready );
11663 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11664 WaitForSingleObject( info.ready, INFINITE );
11665 Sleep(100);
11666 wait_for_thread( thread );
11667 CloseHandle( thread );
11668 ok( info.ret == 1, "SendMessageTimeout failed\n" );
11669 ok_sequence( WmUser, "WmUser", FALSE );
11671 info.timeout = 0x80000000;
11672 info.ret = 0xdeadbeef;
11673 ResetEvent( info.ready );
11674 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11675 WaitForSingleObject( info.ready, INFINITE );
11676 Sleep(100);
11677 wait_for_thread( thread );
11678 CloseHandle( thread );
11679 if (is_win9x)
11681 ok( info.ret == 1, "SendMessageTimeout failed\n" );
11682 ok_sequence( WmUser, "WmUser", FALSE );
11684 else
11686 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
11687 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
11690 /* now check for timeout during message processing */
11691 SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
11692 info.timeout = 100;
11693 info.ret = 0xdeadbeef;
11694 ResetEvent( info.ready );
11695 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11696 WaitForSingleObject( info.ready, INFINITE );
11697 wait_for_thread( thread );
11698 CloseHandle( thread );
11699 /* we should time out but still get the message */
11700 ok( info.ret == 0, "SendMessageTimeout failed\n" );
11701 ok_sequence( WmUser, "WmUser", FALSE );
11703 DestroyWindow( info.hwnd );
11704 CloseHandle( info.ready );
11708 /****************** edit message test *************************/
11709 #define ID_EDIT 0x1234
11710 static const struct message sl_edit_setfocus[] =
11712 { HCBT_SETFOCUS, hook },
11713 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11714 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11715 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11716 { WM_SETFOCUS, sent|wparam, 0 },
11717 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11718 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
11719 { WM_CTLCOLOREDIT, sent|parent },
11720 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11721 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11722 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11723 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11724 { 0 }
11726 static const struct message sl_edit_invisible[] =
11728 { HCBT_SETFOCUS, hook },
11729 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11730 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11731 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11732 { WM_KILLFOCUS, sent|parent },
11733 { WM_SETFOCUS, sent },
11734 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11735 { 0 }
11737 static const struct message ml_edit_setfocus[] =
11739 { HCBT_SETFOCUS, hook },
11740 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11741 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11742 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11743 { WM_SETFOCUS, sent|wparam, 0 },
11744 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11745 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11746 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11747 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11748 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11749 { 0 }
11751 static const struct message sl_edit_killfocus[] =
11753 { HCBT_SETFOCUS, hook },
11754 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11755 { WM_KILLFOCUS, sent|wparam, 0 },
11756 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11757 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11758 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
11759 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
11760 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11761 { 0 }
11763 static const struct message sl_edit_lbutton_dblclk[] =
11765 { WM_LBUTTONDBLCLK, sent },
11766 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11767 { 0 }
11769 static const struct message sl_edit_lbutton_down[] =
11771 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
11772 { HCBT_SETFOCUS, hook },
11773 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11774 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11775 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11776 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
11777 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11778 { WM_CTLCOLOREDIT, sent|parent },
11779 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11780 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11781 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11782 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11783 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11784 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11785 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11786 { WM_CTLCOLOREDIT, sent|parent|optional },
11787 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11788 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11789 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11790 { 0 }
11792 static const struct message ml_edit_lbutton_down[] =
11794 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
11795 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11796 { HCBT_SETFOCUS, hook },
11797 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11798 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11799 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11800 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
11801 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11802 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11803 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11804 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11805 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11806 { 0 }
11808 static const struct message sl_edit_lbutton_up[] =
11810 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
11811 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11812 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
11813 { WM_CAPTURECHANGED, sent|defwinproc },
11814 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11815 { 0 }
11817 static const struct message ml_edit_lbutton_up[] =
11819 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
11820 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
11821 { WM_CAPTURECHANGED, sent|defwinproc },
11822 { 0 }
11825 static WNDPROC old_edit_proc;
11827 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11829 static LONG defwndproc_counter = 0;
11830 LRESULT ret;
11831 struct recvd_message msg;
11833 if (ignore_message( message )) return 0;
11835 msg.hwnd = hwnd;
11836 msg.message = message;
11837 msg.flags = sent|wparam|lparam;
11838 if (defwndproc_counter) msg.flags |= defwinproc;
11839 msg.wParam = wParam;
11840 msg.lParam = lParam;
11841 msg.descr = "edit";
11842 add_message(&msg);
11844 defwndproc_counter++;
11845 ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
11846 defwndproc_counter--;
11848 return ret;
11851 static void subclass_edit(void)
11853 WNDCLASSA cls;
11855 if (!GetClassInfoA(0, "edit", &cls)) assert(0);
11857 old_edit_proc = cls.lpfnWndProc;
11859 cls.hInstance = GetModuleHandleA(NULL);
11860 cls.lpfnWndProc = edit_hook_proc;
11861 cls.lpszClassName = "my_edit_class";
11862 UnregisterClassA(cls.lpszClassName, cls.hInstance);
11863 if (!RegisterClassA(&cls)) assert(0);
11866 static void test_edit_messages(void)
11868 HWND hwnd, parent;
11869 DWORD dlg_code;
11871 subclass_edit();
11872 log_all_parent_messages++;
11874 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11875 100, 100, 200, 200, 0, 0, 0, NULL);
11876 ok (parent != 0, "Failed to create parent window\n");
11878 /* test single line edit */
11879 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
11880 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
11881 ok(hwnd != 0, "Failed to create edit window\n");
11883 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
11884 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
11886 flush_sequence();
11887 SetFocus(hwnd);
11888 ok_sequence(sl_edit_invisible, "SetFocus(hwnd) on an invisible edit", FALSE);
11890 ShowWindow(hwnd, SW_SHOW);
11891 UpdateWindow(hwnd);
11892 SetFocus(0);
11893 flush_sequence();
11895 SetFocus(hwnd);
11896 ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
11898 SetFocus(0);
11899 ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
11901 SetFocus(0);
11902 ReleaseCapture();
11903 flush_sequence();
11905 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
11906 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
11908 SetFocus(0);
11909 ReleaseCapture();
11910 flush_sequence();
11912 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
11913 ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
11915 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
11916 ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
11918 DestroyWindow(hwnd);
11920 /* test multiline edit */
11921 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
11922 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
11923 ok(hwnd != 0, "Failed to create edit window\n");
11925 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
11926 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
11927 "wrong dlg_code %08x\n", dlg_code);
11929 ShowWindow(hwnd, SW_SHOW);
11930 UpdateWindow(hwnd);
11931 SetFocus(0);
11932 flush_sequence();
11934 SetFocus(hwnd);
11935 ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
11937 SetFocus(0);
11938 ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
11940 SetFocus(0);
11941 ReleaseCapture();
11942 flush_sequence();
11944 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
11945 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
11947 SetFocus(0);
11948 ReleaseCapture();
11949 flush_sequence();
11951 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
11952 ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
11954 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
11955 ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
11957 DestroyWindow(hwnd);
11958 DestroyWindow(parent);
11960 log_all_parent_messages--;
11963 /**************************** End of Edit test ******************************/
11965 static const struct message WmKeyDownSkippedSeq[] =
11967 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
11968 { 0 }
11970 static const struct message WmKeyDownWasDownSkippedSeq[] =
11972 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x40000001 }, /* XP */
11973 { 0 }
11975 static const struct message WmKeyUpSkippedSeq[] =
11977 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
11978 { 0 }
11980 static const struct message WmUserKeyUpSkippedSeq[] =
11982 { WM_USER, sent },
11983 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
11984 { 0 }
11987 #define EV_STOP 0
11988 #define EV_SENDMSG 1
11989 #define EV_ACK 2
11991 struct peekmsg_info
11993 HWND hwnd;
11994 HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
11997 static DWORD CALLBACK send_msg_thread_2(void *param)
11999 DWORD ret;
12000 struct peekmsg_info *info = param;
12002 trace("thread: looping\n");
12003 SetEvent(info->hevent[EV_ACK]);
12005 while (1)
12007 ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
12009 switch (ret)
12011 case WAIT_OBJECT_0 + EV_STOP:
12012 trace("thread: exiting\n");
12013 return 0;
12015 case WAIT_OBJECT_0 + EV_SENDMSG:
12016 trace("thread: sending message\n");
12017 ret = SendNotifyMessageA(info->hwnd, WM_USER, 0, 0);
12018 ok(ret, "SendNotifyMessageA failed error %u\n", GetLastError());
12019 SetEvent(info->hevent[EV_ACK]);
12020 break;
12022 default:
12023 trace("unexpected return: %04x\n", ret);
12024 assert(0);
12025 break;
12028 return 0;
12031 static void test_PeekMessage(void)
12033 MSG msg;
12034 HANDLE hthread;
12035 DWORD tid, qstatus;
12036 UINT qs_all_input = QS_ALLINPUT;
12037 UINT qs_input = QS_INPUT;
12038 BOOL ret;
12039 struct peekmsg_info info;
12041 info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
12042 100, 100, 200, 200, 0, 0, 0, NULL);
12043 assert(info.hwnd);
12044 ShowWindow(info.hwnd, SW_SHOW);
12045 UpdateWindow(info.hwnd);
12046 SetFocus(info.hwnd);
12048 info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
12049 info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
12050 info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
12052 hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
12053 WaitForSingleObject(info.hevent[EV_ACK], 10000);
12055 flush_events();
12056 flush_sequence();
12058 SetLastError(0xdeadbeef);
12059 qstatus = GetQueueStatus(qs_all_input);
12060 if (GetLastError() == ERROR_INVALID_FLAGS)
12062 trace("QS_RAWINPUT not supported on this platform\n");
12063 qs_all_input &= ~QS_RAWINPUT;
12064 qs_input &= ~QS_RAWINPUT;
12066 if (qstatus & QS_POSTMESSAGE)
12068 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) /* nothing */ ;
12069 qstatus = GetQueueStatus(qs_all_input);
12071 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
12073 trace("signalling to send message\n");
12074 SetEvent(info.hevent[EV_SENDMSG]);
12075 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
12077 /* pass invalid QS_xxxx flags */
12078 SetLastError(0xdeadbeef);
12079 qstatus = GetQueueStatus(0xffffffff);
12080 ok(qstatus == 0 || broken(qstatus) /* win9x */, "GetQueueStatus should fail: %08x\n", qstatus);
12081 if (!qstatus)
12083 ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
12084 qstatus = GetQueueStatus(qs_all_input);
12086 qstatus &= ~MAKELONG( 0x4000, 0x4000 ); /* sometimes set on Win95 */
12087 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
12088 "wrong qstatus %08x\n", qstatus);
12090 msg.message = 0;
12091 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
12092 ok(!ret,
12093 "PeekMessageA should have returned FALSE instead of msg %04x\n",
12094 msg.message);
12095 ok_sequence(WmUser, "WmUser", FALSE);
12097 qstatus = GetQueueStatus(qs_all_input);
12098 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
12100 keybd_event('N', 0, 0, 0);
12101 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
12102 qstatus = GetQueueStatus(qs_all_input);
12103 if (!(qstatus & MAKELONG(QS_KEY, QS_KEY)))
12105 skip( "queuing key events not supported\n" );
12106 goto done;
12108 ok(qstatus == MAKELONG(QS_KEY, QS_KEY) ||
12109 /* keybd_event seems to trigger a sent message on NT4 */
12110 qstatus == MAKELONG(QS_KEY|QS_SENDMESSAGE, QS_KEY|QS_SENDMESSAGE),
12111 "wrong qstatus %08x\n", qstatus);
12113 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
12114 qstatus = GetQueueStatus(qs_all_input);
12115 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY) ||
12116 qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
12117 "wrong qstatus %08x\n", qstatus);
12119 InvalidateRect(info.hwnd, NULL, FALSE);
12120 qstatus = GetQueueStatus(qs_all_input);
12121 ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY) ||
12122 qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
12123 "wrong qstatus %08x\n", qstatus);
12125 trace("signalling to send message\n");
12126 SetEvent(info.hevent[EV_SENDMSG]);
12127 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
12129 qstatus = GetQueueStatus(qs_all_input);
12130 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
12131 "wrong qstatus %08x\n", qstatus);
12133 msg.message = 0;
12134 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
12135 if (ret && msg.message == WM_CHAR)
12137 win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
12138 goto done;
12140 ok(!ret,
12141 "PeekMessageA should have returned FALSE instead of msg %04x\n",
12142 msg.message);
12143 if (!sequence_cnt) /* nt4 doesn't fetch anything with PM_QS_* flags */
12145 win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
12146 goto done;
12148 ok_sequence(WmUser, "WmUser", FALSE);
12150 qstatus = GetQueueStatus(qs_all_input);
12151 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
12152 "wrong qstatus %08x\n", qstatus);
12154 trace("signalling to send message\n");
12155 SetEvent(info.hevent[EV_SENDMSG]);
12156 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
12158 qstatus = GetQueueStatus(qs_all_input);
12159 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
12160 "wrong qstatus %08x\n", qstatus);
12162 msg.message = 0;
12163 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE );
12164 ok(!ret,
12165 "PeekMessageA should have returned FALSE instead of msg %04x\n",
12166 msg.message);
12167 ok_sequence(WmUser, "WmUser", FALSE);
12169 qstatus = GetQueueStatus(qs_all_input);
12170 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
12171 "wrong qstatus %08x\n", qstatus);
12173 msg.message = 0;
12174 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
12175 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12176 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
12177 ret, msg.message, msg.wParam);
12178 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12180 qstatus = GetQueueStatus(qs_all_input);
12181 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
12182 "wrong qstatus %08x\n", qstatus);
12184 msg.message = 0;
12185 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
12186 ok(!ret,
12187 "PeekMessageA should have returned FALSE instead of msg %04x\n",
12188 msg.message);
12189 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12191 qstatus = GetQueueStatus(qs_all_input);
12192 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
12193 "wrong qstatus %08x\n", qstatus);
12195 msg.message = 0;
12196 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
12197 ok(ret && msg.message == WM_PAINT,
12198 "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
12199 DispatchMessageA(&msg);
12200 ok_sequence(WmPaint, "WmPaint", FALSE);
12202 qstatus = GetQueueStatus(qs_all_input);
12203 ok(qstatus == MAKELONG(0, QS_KEY),
12204 "wrong qstatus %08x\n", qstatus);
12206 msg.message = 0;
12207 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
12208 ok(!ret,
12209 "PeekMessageA should have returned FALSE instead of msg %04x\n",
12210 msg.message);
12211 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12213 qstatus = GetQueueStatus(qs_all_input);
12214 ok(qstatus == MAKELONG(0, QS_KEY),
12215 "wrong qstatus %08x\n", qstatus);
12217 trace("signalling to send message\n");
12218 SetEvent(info.hevent[EV_SENDMSG]);
12219 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
12221 qstatus = GetQueueStatus(qs_all_input);
12222 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
12223 "wrong qstatus %08x\n", qstatus);
12225 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
12227 qstatus = GetQueueStatus(qs_all_input);
12228 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
12229 "wrong qstatus %08x\n", qstatus);
12231 msg.message = 0;
12232 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
12233 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12234 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
12235 ret, msg.message, msg.wParam);
12236 ok_sequence(WmUser, "WmUser", FALSE);
12238 qstatus = GetQueueStatus(qs_all_input);
12239 ok(qstatus == MAKELONG(0, QS_KEY),
12240 "wrong qstatus %08x\n", qstatus);
12242 msg.message = 0;
12243 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
12244 ok(!ret,
12245 "PeekMessageA should have returned FALSE instead of msg %04x\n",
12246 msg.message);
12247 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12249 qstatus = GetQueueStatus(qs_all_input);
12250 ok(qstatus == MAKELONG(0, QS_KEY),
12251 "wrong qstatus %08x\n", qstatus);
12253 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
12255 qstatus = GetQueueStatus(qs_all_input);
12256 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
12257 "wrong qstatus %08x\n", qstatus);
12259 trace("signalling to send message\n");
12260 SetEvent(info.hevent[EV_SENDMSG]);
12261 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
12263 qstatus = GetQueueStatus(qs_all_input);
12264 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
12265 "wrong qstatus %08x\n", qstatus);
12267 msg.message = 0;
12268 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
12269 ok(!ret,
12270 "PeekMessageA should have returned FALSE instead of msg %04x\n",
12271 msg.message);
12272 ok_sequence(WmUser, "WmUser", FALSE);
12274 qstatus = GetQueueStatus(qs_all_input);
12275 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
12276 "wrong qstatus %08x\n", qstatus);
12278 msg.message = 0;
12279 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
12280 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
12281 else /* workaround for a missing QS_RAWINPUT support */
12282 ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
12283 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
12284 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
12285 ret, msg.message, msg.wParam);
12286 ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
12288 qstatus = GetQueueStatus(qs_all_input);
12289 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
12290 "wrong qstatus %08x\n", qstatus);
12292 msg.message = 0;
12293 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
12294 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
12295 else /* workaround for a missing QS_RAWINPUT support */
12296 ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
12297 ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
12298 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
12299 ret, msg.message, msg.wParam);
12300 ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
12302 qstatus = GetQueueStatus(qs_all_input);
12303 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
12304 "wrong qstatus %08x\n", qstatus);
12306 msg.message = 0;
12307 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
12308 ok(!ret,
12309 "PeekMessageA should have returned FALSE instead of msg %04x\n",
12310 msg.message);
12311 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12313 qstatus = GetQueueStatus(qs_all_input);
12314 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
12315 "wrong qstatus %08x\n", qstatus);
12317 msg.message = 0;
12318 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
12319 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12320 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
12321 ret, msg.message, msg.wParam);
12322 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12324 qstatus = GetQueueStatus(qs_all_input);
12325 ok(qstatus == 0,
12326 "wrong qstatus %08x\n", qstatus);
12328 msg.message = 0;
12329 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
12330 ok(!ret,
12331 "PeekMessageA should have returned FALSE instead of msg %04x\n",
12332 msg.message);
12333 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12335 qstatus = GetQueueStatus(qs_all_input);
12336 ok(qstatus == 0,
12337 "wrong qstatus %08x\n", qstatus);
12339 /* test whether presence of the quit flag in the queue affects
12340 * the queue state
12342 PostQuitMessage(0x1234abcd);
12344 qstatus = GetQueueStatus(qs_all_input);
12345 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
12346 "wrong qstatus %08x\n", qstatus);
12348 PostMessageA(info.hwnd, WM_USER, 0, 0);
12350 qstatus = GetQueueStatus(qs_all_input);
12351 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
12352 "wrong qstatus %08x\n", qstatus);
12354 msg.message = 0;
12355 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
12356 ok(ret && msg.message == WM_USER,
12357 "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
12358 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12360 qstatus = GetQueueStatus(qs_all_input);
12361 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
12362 "wrong qstatus %08x\n", qstatus);
12364 msg.message = 0;
12365 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
12366 ok(ret && msg.message == WM_QUIT,
12367 "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
12368 ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
12369 ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
12370 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12372 qstatus = GetQueueStatus(qs_all_input);
12373 todo_wine {
12374 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
12375 "wrong qstatus %08x\n", qstatus);
12378 msg.message = 0;
12379 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
12380 ok(!ret,
12381 "PeekMessageA should have returned FALSE instead of msg %04x\n",
12382 msg.message);
12383 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
12385 qstatus = GetQueueStatus(qs_all_input);
12386 ok(qstatus == 0,
12387 "wrong qstatus %08x\n", qstatus);
12389 /* some GetMessage tests */
12391 keybd_event('N', 0, 0, 0);
12392 qstatus = GetQueueStatus(qs_all_input);
12393 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
12395 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
12396 qstatus = GetQueueStatus(qs_all_input);
12397 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
12399 if (qstatus)
12401 ret = GetMessageA( &msg, 0, 0, 0 );
12402 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12403 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
12404 ret, msg.message, msg.wParam);
12405 qstatus = GetQueueStatus(qs_all_input);
12406 ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08x\n", qstatus);
12409 if (qstatus)
12411 ret = GetMessageA( &msg, 0, 0, 0 );
12412 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
12413 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
12414 ret, msg.message, msg.wParam);
12415 ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
12416 qstatus = GetQueueStatus(qs_all_input);
12417 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
12420 keybd_event('N', 0, 0, 0);
12421 qstatus = GetQueueStatus(qs_all_input);
12422 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
12424 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
12425 qstatus = GetQueueStatus(qs_all_input);
12426 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
12428 if (qstatus & (QS_KEY << 16))
12430 ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
12431 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
12432 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
12433 ret, msg.message, msg.wParam);
12434 ok_sequence(WmKeyDownWasDownSkippedSeq, "WmKeyDownWasDownSkippedSeq", FALSE);
12435 qstatus = GetQueueStatus(qs_all_input);
12436 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
12439 if (qstatus)
12441 ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
12442 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12443 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
12444 ret, msg.message, msg.wParam);
12445 qstatus = GetQueueStatus(qs_all_input);
12446 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
12449 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
12450 qstatus = GetQueueStatus(qs_all_input);
12451 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
12453 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
12454 qstatus = GetQueueStatus(qs_all_input);
12455 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
12457 trace("signalling to send message\n");
12458 SetEvent(info.hevent[EV_SENDMSG]);
12459 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
12460 qstatus = GetQueueStatus(qs_all_input);
12461 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
12462 "wrong qstatus %08x\n", qstatus);
12464 if (qstatus & (QS_KEY << 16))
12466 ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
12467 ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
12468 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
12469 ret, msg.message, msg.wParam);
12470 ok_sequence(WmUserKeyUpSkippedSeq, "WmUserKeyUpSkippedSeq", FALSE);
12471 qstatus = GetQueueStatus(qs_all_input);
12472 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
12475 if (qstatus)
12477 ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
12478 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
12479 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
12480 ret, msg.message, msg.wParam);
12481 qstatus = GetQueueStatus(qs_all_input);
12482 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
12485 PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12486 ret = PeekMessageA(&msg, (HWND)-1, 0, 0, PM_NOREMOVE);
12487 ok(ret == TRUE, "wrong ret %d\n", ret);
12488 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12489 ret = GetMessageA(&msg, (HWND)-1, 0, 0);
12490 ok(ret == TRUE, "wrong ret %d\n", ret);
12491 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12493 PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12494 ret = PeekMessageA(&msg, (HWND)1, 0, 0, PM_NOREMOVE);
12495 ok(ret == TRUE, "wrong ret %d\n", ret);
12496 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12497 ret = GetMessageA(&msg, (HWND)1, 0, 0);
12498 ok(ret == TRUE, "wrong ret %d\n", ret);
12499 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12501 PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12502 ret = PeekMessageA(&msg, (HWND)0xffff, 0, 0, PM_NOREMOVE);
12503 ok(ret == TRUE, "wrong ret %d\n", ret);
12504 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12505 ret = GetMessageA(&msg, (HWND)0xffff, 0, 0);
12506 ok(ret == TRUE, "wrong ret %d\n", ret);
12507 ok(msg.message == WM_USER, "wrong message %u\n", msg.message);
12509 done:
12510 trace("signalling to exit\n");
12511 SetEvent(info.hevent[EV_STOP]);
12513 WaitForSingleObject(hthread, INFINITE);
12515 CloseHandle(hthread);
12516 CloseHandle(info.hevent[0]);
12517 CloseHandle(info.hevent[1]);
12518 CloseHandle(info.hevent[2]);
12520 DestroyWindow(info.hwnd);
12523 static void wait_move_event(HWND hwnd, int x, int y)
12525 MSG msg;
12526 DWORD timeout = GetTickCount() + 500, delay;
12527 BOOL ret;
12529 while ((delay = timeout - GetTickCount()) > 0)
12531 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12532 if (ret && msg.pt.x > x && msg.pt.y > y) break;
12533 if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, delay, QS_ALLINPUT );
12534 else Sleep( delay );
12538 #define STEP 5
12539 static void test_PeekMessage2(void)
12541 HWND hwnd;
12542 BOOL ret;
12543 MSG msg;
12544 UINT message;
12545 DWORD time1, time2, time3;
12546 int x1, y1, x2, y2, x3, y3;
12547 POINT pos;
12549 time1 = time2 = time3 = 0;
12550 x1 = y1 = x2 = y2 = x3 = y3 = 0;
12552 /* Initialise window and make sure it is ready for events */
12553 hwnd = CreateWindowA("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
12554 10, 10, 800, 800, NULL, NULL, NULL, NULL);
12555 assert(hwnd);
12556 trace("Window for test_PeekMessage2 %p\n", hwnd);
12557 ShowWindow(hwnd, SW_SHOW);
12558 UpdateWindow(hwnd);
12559 SetFocus(hwnd);
12560 GetCursorPos(&pos);
12561 SetCursorPos(100, 100);
12562 mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
12563 flush_events();
12565 /* Do initial mousemove, wait until we can see it
12566 and then do our test peek with PM_NOREMOVE. */
12567 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
12568 wait_move_event(hwnd, 100-STEP, 100-STEP);
12570 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12571 if (!ret)
12573 skip( "queuing mouse events not supported\n" );
12574 goto done;
12576 else
12578 trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
12579 message = msg.message;
12580 time1 = msg.time;
12581 x1 = msg.pt.x;
12582 y1 = msg.pt.y;
12583 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
12586 /* Allow time to advance a bit, and then simulate the user moving their
12587 * mouse around. After that we peek again with PM_NOREMOVE.
12588 * Although the previous mousemove message was never removed, the
12589 * mousemove we now peek should reflect the recent mouse movements
12590 * because the input queue will merge the move events. */
12591 Sleep(100);
12592 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
12593 wait_move_event(hwnd, x1, y1);
12595 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12596 ok(ret, "no message available\n");
12597 if (ret) {
12598 trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
12599 message = msg.message;
12600 time2 = msg.time;
12601 x2 = msg.pt.x;
12602 y2 = msg.pt.y;
12603 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
12604 ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
12605 ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
12608 /* Have another go, to drive the point home */
12609 Sleep(100);
12610 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
12611 wait_move_event(hwnd, x2, y2);
12613 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12614 ok(ret, "no message available\n");
12615 if (ret) {
12616 trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
12617 message = msg.message;
12618 time3 = msg.time;
12619 x3 = msg.pt.x;
12620 y3 = msg.pt.y;
12621 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
12622 ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
12623 ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
12626 done:
12627 DestroyWindow(hwnd);
12628 SetCursorPos(pos.x, pos.y);
12629 flush_events();
12632 static void test_PeekMessage3(void)
12634 HWND hwnd;
12635 BOOL ret;
12636 MSG msg;
12638 hwnd = CreateWindowA("TestWindowClass", "PeekMessage3", WS_OVERLAPPEDWINDOW,
12639 10, 10, 800, 800, NULL, NULL, NULL, NULL);
12640 ok(hwnd != NULL, "expected hwnd != NULL\n");
12641 flush_events();
12643 /* GetMessage() and PeekMessage(..., PM_REMOVE) should prefer messages which
12644 * were already seen. */
12646 SetTimer(hwnd, 1, 100, NULL);
12647 while (!PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE));
12648 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12649 PostMessageA(hwnd, WM_USER, 0, 0);
12650 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
12651 todo_wine
12652 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12653 ret = GetMessageA(&msg, NULL, 0, 0);
12654 todo_wine
12655 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12656 ret = GetMessageA(&msg, NULL, 0, 0);
12657 todo_wine
12658 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12659 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12660 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12662 SetTimer(hwnd, 1, 100, NULL);
12663 while (!PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE));
12664 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12665 PostMessageA(hwnd, WM_USER, 0, 0);
12666 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12667 todo_wine
12668 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12669 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12670 todo_wine
12671 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12672 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12673 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12675 /* It doesn't matter if a message range is specified or not. */
12677 SetTimer(hwnd, 1, 100, NULL);
12678 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12679 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12680 PostMessageA(hwnd, WM_USER, 0, 0);
12681 ret = GetMessageA(&msg, NULL, 0, 0);
12682 todo_wine
12683 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12684 ret = GetMessageA(&msg, NULL, 0, 0);
12685 todo_wine
12686 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12687 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12688 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12690 /* But not if the post messages were added before the PeekMessage() call. */
12692 PostMessageA(hwnd, WM_USER, 0, 0);
12693 SetTimer(hwnd, 1, 100, NULL);
12694 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12695 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12696 ret = GetMessageA(&msg, NULL, 0, 0);
12697 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12698 ret = GetMessageA(&msg, NULL, 0, 0);
12699 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12700 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12701 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12703 /* More complicated test with multiple messages. */
12705 PostMessageA(hwnd, WM_USER, 0, 0);
12706 SetTimer(hwnd, 1, 100, NULL);
12707 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12708 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12709 PostMessageA(hwnd, WM_USER + 1, 0, 0);
12710 ret = GetMessageA(&msg, NULL, 0, 0);
12711 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12712 ret = GetMessageA(&msg, NULL, 0, 0);
12713 todo_wine
12714 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12715 ret = GetMessageA(&msg, NULL, 0, 0);
12716 todo_wine
12717 ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message);
12718 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12719 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12721 /* Also works for posted messages, but the situation is a bit different,
12722 * because both messages are in the same queue. */
12724 PostMessageA(hwnd, WM_TIMER, 0, 0);
12725 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12726 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12727 PostMessageA(hwnd, WM_USER, 0, 0);
12728 ret = GetMessageA(&msg, NULL, 0, 0);
12729 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12730 ret = GetMessageA(&msg, NULL, 0, 0);
12731 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12732 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12733 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12735 PostMessageA(hwnd, WM_USER, 0, 0);
12736 PostMessageA(hwnd, WM_TIMER, 0, 0);
12737 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12738 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12739 ret = GetMessageA(&msg, NULL, 0, 0);
12740 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12741 ret = GetMessageA(&msg, NULL, 0, 0);
12742 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12743 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12744 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12746 DestroyWindow(hwnd);
12747 flush_events();
12750 static INT_PTR CALLBACK wm_quit_dlg_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
12752 struct recvd_message msg;
12754 if (ignore_message( message )) return 0;
12756 msg.hwnd = hwnd;
12757 msg.message = message;
12758 msg.flags = sent|wparam|lparam;
12759 msg.wParam = wp;
12760 msg.lParam = lp;
12761 msg.descr = "dialog";
12762 add_message(&msg);
12764 switch (message)
12766 case WM_INITDIALOG:
12767 PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
12768 PostMessageA(hwnd, WM_USER, 0xdead, 0xbeef);
12769 return 0;
12771 case WM_GETDLGCODE:
12772 return 0;
12774 case WM_USER:
12775 EndDialog(hwnd, 0);
12776 break;
12779 return 1;
12782 static const struct message WmQuitDialogSeq[] = {
12783 { HCBT_CREATEWND, hook },
12784 { WM_SETFONT, sent },
12785 { WM_INITDIALOG, sent },
12786 { WM_CHANGEUISTATE, sent|optional },
12787 { HCBT_DESTROYWND, hook },
12788 { 0x0090, sent|optional }, /* Vista */
12789 { WM_DESTROY, sent },
12790 { WM_NCDESTROY, sent },
12791 { 0 }
12794 static const struct message WmStopQuitSeq[] = {
12795 { WM_DWMNCRENDERINGCHANGED, posted|optional },
12796 { WM_CLOSE, posted },
12797 { WM_QUIT, posted|wparam|lparam, 0x1234, 0 },
12798 { 0 }
12801 static void test_quit_message(void)
12803 MSG msg;
12804 BOOL ret;
12806 /* test using PostQuitMessage */
12807 flush_events();
12808 PostQuitMessage(0xbeef);
12810 msg.message = 0;
12811 ret = PeekMessageA(&msg, 0, 0, 0, PM_QS_SENDMESSAGE);
12812 ok(!ret, "got %x message\n", msg.message);
12814 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
12815 ok(ret, "PeekMessage failed with error %d\n", GetLastError());
12816 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12817 ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
12819 ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12820 ok(ret, "PostMessage failed with error %d\n", GetLastError());
12822 ret = GetMessageA(&msg, NULL, 0, 0);
12823 ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
12824 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
12826 /* note: WM_QUIT message received after WM_USER message */
12827 ret = GetMessageA(&msg, NULL, 0, 0);
12828 ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
12829 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12830 ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
12832 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12833 ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
12835 /* now test with PostThreadMessage - different behaviour! */
12836 PostThreadMessageA(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
12838 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
12839 ok(ret, "PeekMessage failed with error %d\n", GetLastError());
12840 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12841 ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
12843 ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12844 ok(ret, "PostMessage failed with error %d\n", GetLastError());
12846 /* note: we receive the WM_QUIT message first this time */
12847 ret = GetMessageA(&msg, NULL, 0, 0);
12848 ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
12849 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12850 ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
12852 ret = GetMessageA(&msg, NULL, 0, 0);
12853 ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
12854 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
12856 flush_events();
12857 flush_sequence();
12858 ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, wm_quit_dlg_proc, 0);
12859 ok(ret == 1, "expected 1, got %d\n", ret);
12860 ok_sequence(WmQuitDialogSeq, "WmQuitDialogSeq", FALSE);
12861 memset(&msg, 0xab, sizeof(msg));
12862 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12863 ok(ret, "PeekMessage failed\n");
12864 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12865 ok(msg.wParam == 0x1234, "wParam was 0x%lx instead of 0x1234\n", msg.wParam);
12866 ok(msg.lParam == 0, "lParam was 0x%lx instead of 0\n", msg.lParam);
12868 /* Check what happens to a WM_QUIT message posted to a window that gets
12869 * destroyed.
12871 CreateWindowExA(0, "StopQuitClass", "Stop Quit Test", WS_OVERLAPPEDWINDOW,
12872 0, 0, 100, 100, NULL, NULL, NULL, NULL);
12873 flush_sequence();
12874 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12876 struct recvd_message rmsg;
12877 rmsg.hwnd = msg.hwnd;
12878 rmsg.message = msg.message;
12879 rmsg.flags = posted|wparam|lparam;
12880 rmsg.wParam = msg.wParam;
12881 rmsg.lParam = msg.lParam;
12882 rmsg.descr = "stop/quit";
12883 if (msg.message == WM_QUIT)
12884 /* The hwnd can only be checked here */
12885 ok(!msg.hwnd, "The WM_QUIT hwnd was %p instead of NULL\n", msg.hwnd);
12886 add_message(&rmsg);
12887 DispatchMessageA(&msg);
12889 ok_sequence(WmStopQuitSeq, "WmStopQuitSeq", FALSE);
12892 static const struct message WmNotifySeq[] = {
12893 { WM_NOTIFY, sent|wparam|lparam, 0x1234, 0xdeadbeef },
12894 { 0 }
12897 static void test_notify_message(void)
12899 HWND hwnd;
12900 BOOL ret;
12901 MSG msg;
12903 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
12904 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0, NULL, NULL, 0);
12905 ok(hwnd != 0, "Failed to create window\n");
12906 flush_events();
12907 flush_sequence();
12909 ret = SendNotifyMessageA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12910 ok(ret == TRUE, "SendNotifyMessageA failed with error %u\n", GetLastError());
12911 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12913 ret = SendNotifyMessageW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12914 ok(ret == TRUE, "SendNotifyMessageW failed with error %u\n", GetLastError());
12915 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12917 ret = SendMessageCallbackA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef, NULL, 0);
12918 ok(ret == TRUE, "SendMessageCallbackA failed with error %u\n", GetLastError());
12919 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12921 ret = SendMessageCallbackW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef, NULL, 0);
12922 ok(ret == TRUE, "SendMessageCallbackW failed with error %u\n", GetLastError());
12923 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12925 ret = PostMessageA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12926 ok(ret == TRUE, "PostMessageA failed with error %u\n", GetLastError());
12927 flush_events();
12928 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12930 ret = PostMessageW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12931 ok(ret == TRUE, "PostMessageW failed with error %u\n", GetLastError());
12932 flush_events();
12933 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12935 ret = PostThreadMessageA(GetCurrentThreadId(), WM_NOTIFY, 0x1234, 0xdeadbeef);
12936 ok(ret == TRUE, "PostThreadMessageA failed with error %u\n", GetLastError());
12937 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12939 msg.hwnd = hwnd;
12940 DispatchMessageA(&msg);
12942 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12944 ret = PostThreadMessageW(GetCurrentThreadId(), WM_NOTIFY, 0x1234, 0xdeadbeef);
12945 ok(ret == TRUE, "PostThreadMessageW failed with error %u\n", GetLastError());
12946 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12948 msg.hwnd = hwnd;
12949 DispatchMessageA(&msg);
12951 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12953 DestroyWindow(hwnd);
12956 static const struct message WmMouseHoverSeq[] = {
12957 { WM_GETMINMAXINFO, sent|optional }, /* sometimes seen on w1064v1809 */
12958 { WM_MOUSEACTIVATE, sent|optional }, /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
12959 { WM_MOUSEACTIVATE, sent|optional },
12960 { WM_TIMER, sent|optional }, /* XP sends it */
12961 { WM_SYSTIMER, sent },
12962 { WM_MOUSEHOVER, sent|wparam, 0 },
12963 { 0 }
12966 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
12968 MSG msg;
12969 DWORD start_ticks, end_ticks;
12971 start_ticks = GetTickCount();
12972 /* add some deviation (50%) to cover not expected delays */
12973 start_ticks += timeout / 2;
12977 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12979 /* Timer proc messages are not dispatched to the window proc,
12980 * and therefore not logged.
12982 if ((msg.message == WM_TIMER || msg.message == WM_SYSTIMER) && msg.hwnd)
12984 struct recvd_message s_msg;
12986 s_msg.hwnd = msg.hwnd;
12987 s_msg.message = msg.message;
12988 s_msg.flags = sent|wparam|lparam;
12989 s_msg.wParam = msg.wParam;
12990 s_msg.lParam = msg.lParam;
12991 s_msg.descr = "msg_loop";
12992 add_message(&s_msg);
12994 DispatchMessageA(&msg);
12997 end_ticks = GetTickCount();
12999 /* inject WM_MOUSEMOVE to see how it changes tracking */
13000 if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
13002 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
13003 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
13005 inject_mouse_move = FALSE;
13007 } while (start_ticks + timeout >= end_ticks);
13010 static void test_TrackMouseEvent(void)
13012 TRACKMOUSEEVENT tme;
13013 BOOL ret;
13014 HWND hwnd, hchild;
13015 RECT rc_parent, rc_child;
13016 UINT default_hover_time, hover_width = 0, hover_height = 0;
13018 #define track_hover(track_hwnd, track_hover_time) \
13019 tme.cbSize = sizeof(tme); \
13020 tme.dwFlags = TME_HOVER; \
13021 tme.hwndTrack = track_hwnd; \
13022 tme.dwHoverTime = track_hover_time; \
13023 SetLastError(0xdeadbeef); \
13024 ret = pTrackMouseEvent(&tme); \
13025 ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
13027 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
13028 tme.cbSize = sizeof(tme); \
13029 tme.dwFlags = TME_QUERY; \
13030 tme.hwndTrack = (HWND)0xdeadbeef; \
13031 tme.dwHoverTime = 0xdeadbeef; \
13032 SetLastError(0xdeadbeef); \
13033 ret = pTrackMouseEvent(&tme); \
13034 ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
13035 ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
13036 ok(tme.dwFlags == (expected_track_flags), \
13037 "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
13038 ok(tme.hwndTrack == (expected_track_hwnd), \
13039 "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
13040 ok(tme.dwHoverTime == (expected_hover_time), \
13041 "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
13043 #define track_hover_cancel(track_hwnd) \
13044 tme.cbSize = sizeof(tme); \
13045 tme.dwFlags = TME_HOVER | TME_CANCEL; \
13046 tme.hwndTrack = track_hwnd; \
13047 tme.dwHoverTime = 0xdeadbeef; \
13048 SetLastError(0xdeadbeef); \
13049 ret = pTrackMouseEvent(&tme); \
13050 ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
13052 default_hover_time = 0xdeadbeef;
13053 SetLastError(0xdeadbeef);
13054 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
13055 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
13056 "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
13057 if (!ret) default_hover_time = 400;
13058 trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
13060 SetLastError(0xdeadbeef);
13061 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
13062 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
13063 "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
13064 if (!ret) hover_width = 4;
13065 SetLastError(0xdeadbeef);
13066 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
13067 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
13068 "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
13069 if (!ret) hover_height = 4;
13070 trace("hover rect is %u x %d\n", hover_width, hover_height);
13072 hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
13073 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13074 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
13075 NULL, NULL, 0);
13076 assert(hwnd);
13078 hchild = CreateWindowExA(0, "TestWindowClass", NULL,
13079 WS_CHILD | WS_BORDER | WS_VISIBLE,
13080 50, 50, 200, 200, hwnd,
13081 NULL, NULL, 0);
13082 assert(hchild);
13084 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
13085 flush_events();
13086 flush_sequence();
13088 tme.cbSize = 0;
13089 tme.dwFlags = TME_QUERY;
13090 tme.hwndTrack = (HWND)0xdeadbeef;
13091 tme.dwHoverTime = 0xdeadbeef;
13092 SetLastError(0xdeadbeef);
13093 ret = pTrackMouseEvent(&tme);
13094 ok(!ret, "TrackMouseEvent should fail\n");
13095 ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
13096 "not expected error %u\n", GetLastError());
13098 tme.cbSize = sizeof(tme);
13099 tme.dwFlags = TME_HOVER;
13100 tme.hwndTrack = (HWND)0xdeadbeef;
13101 tme.dwHoverTime = 0xdeadbeef;
13102 SetLastError(0xdeadbeef);
13103 ret = pTrackMouseEvent(&tme);
13104 ok(!ret, "TrackMouseEvent should fail\n");
13105 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
13106 "not expected error %u\n", GetLastError());
13108 tme.cbSize = sizeof(tme);
13109 tme.dwFlags = TME_HOVER | TME_CANCEL;
13110 tme.hwndTrack = (HWND)0xdeadbeef;
13111 tme.dwHoverTime = 0xdeadbeef;
13112 SetLastError(0xdeadbeef);
13113 ret = pTrackMouseEvent(&tme);
13114 ok(!ret, "TrackMouseEvent should fail\n");
13115 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
13116 "not expected error %u\n", GetLastError());
13118 GetWindowRect(hwnd, &rc_parent);
13119 GetWindowRect(hchild, &rc_child);
13120 SetCursorPos(rc_child.left - 10, rc_child.top - 10);
13122 /* Process messages so that the system updates its internal current
13123 * window and hittest, otherwise TrackMouseEvent calls don't have any
13124 * effect.
13126 flush_events();
13127 flush_sequence();
13129 track_query(0, NULL, 0);
13130 track_hover(hchild, 0);
13131 track_query(0, NULL, 0);
13133 flush_events();
13134 flush_sequence();
13136 track_hover(hwnd, 0);
13137 tme.cbSize = sizeof(tme);
13138 tme.dwFlags = TME_QUERY;
13139 tme.hwndTrack = (HWND)0xdeadbeef;
13140 tme.dwHoverTime = 0xdeadbeef;
13141 SetLastError(0xdeadbeef);
13142 ret = pTrackMouseEvent(&tme);
13143 ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());
13144 ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize);
13145 if (!tme.dwFlags)
13147 skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" );
13148 DestroyWindow( hwnd );
13149 return;
13151 ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08x, expected TME_HOVER\n", tme.dwFlags);
13152 ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd);
13153 ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %u, expected %u\n",
13154 tme.dwHoverTime, default_hover_time);
13156 pump_msg_loop_timeout(default_hover_time, FALSE);
13157 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
13159 track_query(0, NULL, 0);
13161 track_hover(hwnd, HOVER_DEFAULT);
13162 track_query(TME_HOVER, hwnd, default_hover_time);
13164 Sleep(default_hover_time / 2);
13165 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
13166 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
13168 track_query(TME_HOVER, hwnd, default_hover_time);
13170 pump_msg_loop_timeout(default_hover_time, FALSE);
13171 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
13173 track_query(0, NULL, 0);
13175 track_hover(hwnd, HOVER_DEFAULT);
13176 track_query(TME_HOVER, hwnd, default_hover_time);
13178 pump_msg_loop_timeout(default_hover_time, TRUE);
13179 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
13181 track_query(0, NULL, 0);
13183 track_hover(hwnd, HOVER_DEFAULT);
13184 track_query(TME_HOVER, hwnd, default_hover_time);
13185 track_hover_cancel(hwnd);
13187 DestroyWindow(hwnd);
13189 #undef track_hover
13190 #undef track_query
13191 #undef track_hover_cancel
13195 static const struct message WmSetWindowRgn[] = {
13196 { WM_WINDOWPOSCHANGING, sent|wparam|lparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE
13197 |SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE, 0 },
13198 { WM_NCCALCSIZE, sent|wparam|lparam, 1, 0xf },
13199 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
13200 { WM_GETTEXT, sent|defwinproc|optional },
13201 { WM_ERASEBKGND, sent|optional },
13202 { WM_WINDOWPOSCHANGED, sent|wparam|lparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE, 0xf },
13203 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
13204 { 0 }
13207 static const struct message WmSetWindowRgn_no_redraw[] = {
13208 { WM_WINDOWPOSCHANGING, sent|wparam|lparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE
13209 |SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW, 0 },
13210 { WM_NCCALCSIZE, sent|wparam|lparam, 1, 0xf },
13211 { WM_WINDOWPOSCHANGED, sent|wparam|lparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW, 0xf },
13212 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
13213 { 0 }
13216 static const struct message WmSetWindowRgn_clear[] = {
13217 { WM_WINDOWPOSCHANGING, sent/*|wparam|lparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED
13218 |SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */, 0xf
13219 /* Some newer Windows versions set window coordinates instead of zeros in WINDOWPOS structure */},
13220 { WM_NCCALCSIZE, sent|wparam|lparam, 1, 0xf },
13221 { WM_NCPAINT, sent|optional },
13222 { WM_GETTEXT, sent|defwinproc|optional },
13223 { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
13224 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
13225 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
13226 { WM_NCPAINT, sent|optional },
13227 { WM_GETTEXT, sent|defwinproc|optional },
13228 { WM_ERASEBKGND, sent|optional },
13229 { WM_WINDOWPOSCHANGING, sent|optional },
13230 { WM_NCCALCSIZE, sent|optional|wparam, 1 },
13231 { WM_NCPAINT, sent|optional },
13232 { WM_GETTEXT, sent|defwinproc|optional },
13233 { WM_ERASEBKGND, sent|optional },
13234 { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
13235 { WM_NCCALCSIZE, sent|optional|wparam, 1 },
13236 { WM_NCPAINT, sent|optional },
13237 { WM_GETTEXT, sent|defwinproc|optional },
13238 { WM_ERASEBKGND, sent|optional },
13239 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
13240 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
13241 { 0 }
13244 static void test_SetWindowRgn(void)
13246 HRGN hrgn;
13247 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
13248 100, 100, 200, 200, 0, 0, 0, NULL);
13249 ok( hwnd != 0, "Failed to create overlapped window\n" );
13251 ShowWindow( hwnd, SW_SHOW );
13252 UpdateWindow( hwnd );
13253 flush_events();
13254 flush_sequence();
13256 trace("testing SetWindowRgn\n");
13257 hrgn = CreateRectRgn( 0, 0, 150, 150 );
13258 SetWindowRgn( hwnd, hrgn, TRUE );
13259 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
13261 hrgn = CreateRectRgn( 30, 30, 160, 160 );
13262 SetWindowRgn( hwnd, hrgn, FALSE );
13263 ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
13265 hrgn = CreateRectRgn( 0, 0, 180, 180 );
13266 SetWindowRgn( hwnd, hrgn, TRUE );
13267 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
13269 SetWindowRgn( hwnd, 0, TRUE );
13270 ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
13272 DestroyWindow( hwnd );
13275 /*************************** ShowWindow() test ******************************/
13276 static const struct message WmShowNormal[] = {
13277 { WM_SHOWWINDOW, sent|wparam, 1 },
13278 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
13279 { HCBT_ACTIVATE, hook },
13280 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
13281 { HCBT_SETFOCUS, hook },
13282 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13283 { 0 }
13285 static const struct message WmShow[] = {
13286 { WM_SHOWWINDOW, sent|wparam, 1 },
13287 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
13288 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13289 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13290 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13291 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13292 { 0 }
13294 static const struct message WmShowNoActivate_1[] = {
13295 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
13296 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13297 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13298 { WM_MOVE, sent|defwinproc|optional },
13299 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
13300 { 0 }
13302 static const struct message WmShowNoActivate_2[] = {
13303 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
13304 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13305 { HCBT_ACTIVATE, hook|optional },
13306 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13307 { HCBT_SETFOCUS, hook|optional },
13308 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13309 { WM_MOVE, sent|defwinproc },
13310 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
13311 { HCBT_SETFOCUS, hook|optional },
13312 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
13313 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
13314 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13315 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
13316 { 0 }
13318 static const struct message WmShowNA_1[] = {
13319 { WM_SHOWWINDOW, sent|wparam, 1 },
13320 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13321 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13322 { 0 }
13324 static const struct message WmShowNA_2[] = {
13325 { WM_SHOWWINDOW, sent|wparam, 1 },
13326 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13327 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13328 { 0 }
13330 static const struct message WmRestore_1[] = {
13331 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
13332 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13333 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13334 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13335 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13336 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13337 { WM_MOVE, sent|defwinproc },
13338 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
13339 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
13340 { 0 }
13342 static const struct message WmRestore_2[] = {
13343 { WM_SHOWWINDOW, sent|wparam, 1 },
13344 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
13345 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13346 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13347 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13348 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13349 { 0 }
13351 static const struct message WmRestore_3[] = {
13352 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
13353 { WM_GETMINMAXINFO, sent },
13354 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13355 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
13356 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
13357 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
13358 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13359 { WM_MOVE, sent|defwinproc },
13360 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
13361 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
13362 { 0 }
13364 static const struct message WmRestore_4[] = {
13365 { HCBT_MINMAX, hook|lparam|optional, 0, SW_RESTORE },
13366 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13367 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13368 { WM_MOVE, sent|defwinproc|optional },
13369 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
13370 { 0 }
13372 static const struct message WmRestore_5[] = {
13373 { HCBT_MINMAX, hook|lparam|optional, 0, SW_SHOWNORMAL },
13374 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13375 { HCBT_ACTIVATE, hook|optional },
13376 { HCBT_SETFOCUS, hook|optional },
13377 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13378 { WM_MOVE, sent|defwinproc|optional },
13379 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
13380 { 0 }
13382 static const struct message WmHide_1[] = {
13383 { WM_SHOWWINDOW, sent|wparam, 0 },
13384 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOACTIVATE },
13385 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOACTIVATE },
13386 { HCBT_ACTIVATE, hook|optional },
13387 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
13388 { 0 }
13390 static const struct message WmHide_2[] = {
13391 { WM_SHOWWINDOW, sent|wparam, 0 },
13392 { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
13393 { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
13394 { HCBT_ACTIVATE, hook|optional },
13395 { 0 }
13397 static const struct message WmHide_3[] = {
13398 { WM_SHOWWINDOW, sent|wparam, 0 },
13399 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
13400 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13401 { HCBT_SETFOCUS, hook|optional },
13402 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
13403 { 0 }
13405 static const struct message WmShowMinimized_1[] = {
13406 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
13407 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13408 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13409 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13410 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13411 { WM_MOVE, sent|defwinproc },
13412 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
13413 { 0 }
13415 static const struct message WmMinimize_1[] = {
13416 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
13417 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13418 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
13419 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13420 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13421 { WM_MOVE, sent|defwinproc },
13422 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
13423 { 0 }
13425 static const struct message WmMinimize_2[] = {
13426 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
13427 { HCBT_SETFOCUS, hook|optional },
13428 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13429 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13430 { WM_MOVE, sent|defwinproc },
13431 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
13432 { 0 }
13434 static const struct message WmMinimize_3[] = {
13435 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
13436 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13437 { HCBT_ACTIVATE, hook|optional },
13438 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13439 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
13440 { WM_MOVE, sent|defwinproc },
13441 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
13442 { 0 }
13444 static const struct message WmShowMinNoActivate[] = {
13445 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
13446 { WM_WINDOWPOSCHANGING, sent },
13447 { WM_WINDOWPOSCHANGED, sent },
13448 { WM_MOVE, sent|defwinproc|optional },
13449 { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
13450 { 0 }
13452 static const struct message WmMinMax_1[] = {
13453 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
13454 { 0 }
13456 static const struct message WmMinMax_2[] = {
13457 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
13458 { WM_GETMINMAXINFO, sent|optional },
13459 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED },
13460 { HCBT_ACTIVATE, hook|optional },
13461 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13462 { HCBT_SETFOCUS, hook|optional },
13463 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13464 { WM_MOVE, sent|defwinproc|optional },
13465 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MAXIMIZED },
13466 { HCBT_SETFOCUS, hook|optional },
13467 { 0 }
13469 static const struct message WmMinMax_3[] = {
13470 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
13471 { HCBT_SETFOCUS, hook|optional },
13472 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13473 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13474 { WM_MOVE, sent|defwinproc|optional },
13475 { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
13476 { 0 }
13478 static const struct message WmMinMax_4[] = {
13479 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
13480 { 0 }
13482 static const struct message WmShowMaximized_1[] = {
13483 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
13484 { WM_GETMINMAXINFO, sent },
13485 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13486 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13487 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13488 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13489 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13490 { WM_MOVE, sent|defwinproc },
13491 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
13492 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
13493 { 0 }
13495 static const struct message WmShowMaximized_2[] = {
13496 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
13497 { WM_GETMINMAXINFO, sent },
13498 { WM_WINDOWPOSCHANGING, sent|optional },
13499 { HCBT_ACTIVATE, hook|optional },
13500 { WM_WINDOWPOSCHANGED, sent|optional },
13501 { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
13502 { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
13503 { WM_WINDOWPOSCHANGING, sent|optional },
13504 { HCBT_SETFOCUS, hook|optional },
13505 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
13506 { WM_MOVE, sent|defwinproc },
13507 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
13508 { HCBT_SETFOCUS, hook|optional },
13509 { 0 }
13511 static const struct message WmShowMaximized_3[] = {
13512 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
13513 { WM_GETMINMAXINFO, sent|optional },
13514 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13515 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
13516 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
13517 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
13518 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
13519 { WM_MOVE, sent|defwinproc|optional },
13520 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
13521 { 0 }
13524 static void test_ShowWindow(void)
13526 /* ShowWindow commands in random order */
13527 static const struct
13529 INT cmd; /* ShowWindow command */
13530 LPARAM ret; /* ShowWindow return value */
13531 DWORD style; /* window style after the command */
13532 const struct message *msg; /* message sequence the command produces */
13533 INT wp_cmd, wp_flags; /* window placement after the command */
13534 POINT wp_min, wp_max; /* window placement after the command */
13535 BOOL todo_msg; /* message sequence doesn't match what Wine does */
13536 } sw[] =
13538 /* 1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal,
13539 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
13540 /* 2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq,
13541 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
13542 /* 3 */ { SW_HIDE, TRUE, 0, WmHide_1,
13543 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
13544 /* 4 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13545 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
13546 /* 5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1,
13547 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13548 /* 6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1,
13549 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13550 /* 7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1,
13551 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13552 /* 8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
13553 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13554 /* 9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1,
13555 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13556 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
13557 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13558 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1,
13559 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13560 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq,
13561 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13562 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1,
13563 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13564 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
13565 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13566 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2,
13567 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13568 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13569 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13570 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow,
13571 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13572 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
13573 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13574 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
13575 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13576 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
13577 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13578 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13579 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13580 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate,
13581 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, TRUE },
13582 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4,
13583 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13584 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13585 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13586 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
13587 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13588 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1,
13589 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13590 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2,
13591 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13592 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13593 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13594 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
13595 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13596 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1,
13597 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13598 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
13599 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13600 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3,
13601 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13602 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13603 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13604 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, /* what does this mean?! */
13605 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13606 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq,
13607 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13608 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13609 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13610 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2,
13611 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13612 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
13613 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13614 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
13615 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13616 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2,
13617 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13618 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
13619 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13620 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2,
13621 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13622 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
13623 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13624 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
13625 SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13626 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
13627 SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13628 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3,
13629 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13630 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4,
13631 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13632 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3,
13633 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13634 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq,
13635 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13636 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
13637 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13638 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
13639 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13640 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1,
13641 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13642 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13643 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13644 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3,
13645 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13646 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13647 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13648 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2,
13649 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13650 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
13651 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE }
13653 HWND hwnd;
13654 DWORD style;
13655 LPARAM ret;
13656 INT i;
13657 WINDOWPLACEMENT wp;
13658 RECT win_rc, work_rc = {0, 0, 0, 0};
13659 HMONITOR hmon;
13660 MONITORINFO mi;
13661 POINT pt = {0, 0};
13663 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
13664 hwnd = CreateWindowExA(0, "ShowWindowClass", NULL, WS_BASE,
13665 120, 120, 90, 90,
13666 0, 0, 0, NULL);
13667 assert(hwnd);
13669 style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
13670 ok(style == 0, "expected style 0, got %08x\n", style);
13672 flush_events();
13673 flush_sequence();
13675 SetLastError(0xdeadbeef);
13676 hmon = MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
13677 ok(hmon != 0, "MonitorFromPoint error %u\n", GetLastError());
13679 mi.cbSize = sizeof(mi);
13680 SetLastError(0xdeadbeef);
13681 ret = GetMonitorInfoA(hmon, &mi);
13682 ok(ret, "GetMonitorInfo error %u\n", GetLastError());
13683 trace("monitor %s, work %s\n", wine_dbgstr_rect(&mi.rcMonitor),
13684 wine_dbgstr_rect(&mi.rcWork));
13685 work_rc = mi.rcWork;
13687 GetWindowRect(hwnd, &win_rc);
13688 OffsetRect(&win_rc, -work_rc.left, -work_rc.top);
13690 wp.length = sizeof(wp);
13691 SetLastError(0xdeadbeaf);
13692 ret = GetWindowPlacement(hwnd, &wp);
13693 ok(ret, "GetWindowPlacement error %u\n", GetLastError());
13694 ok(wp.flags == 0, "expected 0, got %#x\n", wp.flags);
13695 ok(wp.showCmd == SW_SHOWNORMAL, "expected SW_SHOWNORMAL, got %d\n", wp.showCmd);
13696 ok(wp.ptMinPosition.x == -1 && wp.ptMinPosition.y == -1,
13697 "expected -1,-1 got %d,%d\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
13698 ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
13699 "expected -1,-1 got %d,%d\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
13700 todo_wine_if (work_rc.left || work_rc.top) /* FIXME: remove once Wine is fixed */
13701 ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n", wine_dbgstr_rect(&win_rc),
13702 wine_dbgstr_rect(&wp.rcNormalPosition));
13704 for (i = 0; i < ARRAY_SIZE(sw); i++)
13706 static const char * const sw_cmd_name[13] =
13708 "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
13709 "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
13710 "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
13711 "SW_NORMALNA" /* 0xCC */
13713 char comment[64];
13714 INT idx; /* index into the above array of names */
13716 idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
13718 style = GetWindowLongA(hwnd, GWL_STYLE);
13719 trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
13720 ret = ShowWindow(hwnd, sw[i].cmd);
13721 ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
13722 style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
13723 ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
13725 sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
13726 ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
13728 wp.length = sizeof(wp);
13729 SetLastError(0xdeadbeaf);
13730 ret = GetWindowPlacement(hwnd, &wp);
13731 ok(ret, "GetWindowPlacement error %u\n", GetLastError());
13732 ok(wp.flags == sw[i].wp_flags, "expected %#x, got %#x\n", sw[i].wp_flags, wp.flags);
13733 ok(wp.showCmd == sw[i].wp_cmd, "expected %d, got %d\n", sw[i].wp_cmd, wp.showCmd);
13735 /* NT moves the minimized window to -32000,-32000, win9x to 3000,3000 */
13736 if ((wp.ptMinPosition.x + work_rc.left == -32000 && wp.ptMinPosition.y + work_rc.top == -32000) ||
13737 (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000))
13739 ok((wp.ptMinPosition.x + work_rc.left == sw[i].wp_min.x && wp.ptMinPosition.y + work_rc.top == sw[i].wp_min.y) ||
13740 (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000),
13741 "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
13743 else
13745 ok(wp.ptMinPosition.x == sw[i].wp_min.x && wp.ptMinPosition.y == sw[i].wp_min.y,
13746 "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
13749 todo_wine_if(wp.ptMaxPosition.x != sw[i].wp_max.x || wp.ptMaxPosition.y != sw[i].wp_max.y)
13750 ok(wp.ptMaxPosition.x == sw[i].wp_max.x && wp.ptMaxPosition.y == sw[i].wp_max.y,
13751 "expected %d,%d got %d,%d\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y);
13753 if (0) /* FIXME: Wine behaves completely different here */
13754 ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n",
13755 wine_dbgstr_rect(&win_rc), wine_dbgstr_rect(&wp.rcNormalPosition));
13757 DestroyWindow(hwnd);
13758 flush_events();
13761 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13763 struct recvd_message msg;
13765 if (ignore_message( message )) return 0;
13767 msg.hwnd = hwnd;
13768 msg.message = message;
13769 msg.flags = sent|wparam|lparam;
13770 msg.wParam = wParam;
13771 msg.lParam = lParam;
13772 msg.descr = "dialog";
13773 add_message(&msg);
13775 /* calling DefDlgProc leads to a recursion under XP */
13777 switch (message)
13779 case WM_INITDIALOG:
13780 return lParam;
13782 case WM_GETDLGCODE:
13783 return 0;
13785 return 1;
13788 static WNDPROC orig_edit_proc;
13789 static LRESULT WINAPI dlg_creation_edit_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
13791 struct recvd_message msg;
13793 if (ignore_message( message )) return 0;
13795 msg.hwnd = hwnd;
13796 msg.message = message;
13797 msg.flags = sent|wparam|lparam;
13798 msg.wParam = wp;
13799 msg.lParam = lp;
13800 msg.descr = "edit";
13801 add_message(&msg);
13803 return CallWindowProcW(orig_edit_proc, hwnd, message, wp, lp);
13806 static INT_PTR WINAPI test_dlg_proc2(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13808 struct recvd_message msg;
13810 if (ignore_message( message )) return 0;
13812 msg.hwnd = hwnd;
13813 msg.message = message;
13814 msg.flags = sent|wparam|lparam|parent;
13815 msg.wParam = wParam;
13816 msg.lParam = lParam;
13817 msg.descr = "dialog";
13818 add_message(&msg);
13820 if (message == WM_INITDIALOG)
13822 orig_edit_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwnd, 200),
13823 GWLP_WNDPROC, (LONG_PTR)dlg_creation_edit_proc);
13826 return 1;
13829 static INT_PTR WINAPI test_dlg_proc3(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13831 ok( 0, "should not be called since DefDlgProc is not used\n" );
13832 return 0;
13835 static LRESULT WINAPI test_dlg_proc4(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13837 struct recvd_message msg;
13839 if (!ignore_message( message ))
13841 msg.hwnd = hwnd;
13842 msg.message = message;
13843 msg.flags = sent|wparam|lparam|parent;
13844 msg.wParam = wParam;
13845 msg.lParam = lParam;
13846 msg.descr = "dialog";
13847 add_message(&msg);
13849 if (message == WM_INITDIALOG)
13851 orig_edit_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwnd, 200),
13852 GWLP_WNDPROC, (LONG_PTR)dlg_creation_edit_proc);
13853 return 1;
13855 return DefWindowProcW( hwnd, message, wParam, lParam );
13858 static const struct message WmDefDlgSetFocus_1[] = {
13859 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13860 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
13861 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
13862 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
13863 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
13864 { HCBT_SETFOCUS, hook },
13865 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
13866 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13867 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
13868 { WM_SETFOCUS, sent|wparam, 0 },
13869 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
13870 { WM_CTLCOLOREDIT, sent },
13871 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
13872 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13873 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13874 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13875 { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
13876 { 0 }
13878 static const struct message WmDefDlgSetFocus_2[] = {
13879 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13880 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
13881 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
13882 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
13883 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
13884 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13885 { WM_CTLCOLOREDIT, sent|optional }, /* XP */
13886 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13887 { 0 }
13889 /* Creation of a dialog */
13890 static const struct message WmCreateDialogParamSeq_0[] = {
13891 { HCBT_CREATEWND, hook },
13892 { WM_NCCREATE, sent },
13893 { WM_NCCALCSIZE, sent|wparam, 0 },
13894 { WM_CREATE, sent },
13895 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13896 { WM_SIZE, sent|wparam, SIZE_RESTORED },
13897 { WM_MOVE, sent },
13898 { WM_SETFONT, sent },
13899 { WM_INITDIALOG, sent },
13900 { WM_CHANGEUISTATE, sent|optional },
13901 { 0 }
13903 /* Creation of a dialog */
13904 static const struct message WmCreateDialogParamSeq_1[] = {
13905 { HCBT_CREATEWND, hook },
13906 { WM_NCCREATE, sent },
13907 { WM_NCCALCSIZE, sent|wparam, 0 },
13908 { WM_CREATE, sent },
13909 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13910 { WM_SIZE, sent|wparam, SIZE_RESTORED },
13911 { WM_MOVE, sent },
13912 { WM_SETFONT, sent },
13913 { WM_INITDIALOG, sent },
13914 { WM_GETDLGCODE, sent|wparam|lparam|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
13915 { HCBT_SETFOCUS, hook },
13916 { HCBT_ACTIVATE, hook },
13917 { WM_QUERYNEWPALETTE, sent|optional },
13918 { WM_PALETTEISCHANGING, sent|optional },
13919 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13920 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOREDRAW },
13921 { WM_ACTIVATEAPP, sent|wparam, 1 },
13922 { WM_NCACTIVATE, sent },
13923 { WM_ACTIVATE, sent|wparam, 1 },
13924 { WM_SETFOCUS, sent },
13925 { WM_CHANGEUISTATE, sent|optional },
13926 { 0 }
13928 /* Creation of a dialog */
13929 static const struct message WmCreateDialogParamSeq_2[] = {
13930 { HCBT_CREATEWND, hook },
13931 { WM_NCCREATE, sent },
13932 { WM_NCCALCSIZE, sent|wparam, 0 },
13933 { WM_CREATE, sent },
13934 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13935 { WM_SIZE, sent|wparam, SIZE_RESTORED },
13936 { WM_MOVE, sent },
13937 { WM_CHANGEUISTATE, sent|optional },
13938 { 0 }
13941 static const struct message WmCreateDialogParamSeq_3[] = {
13942 { HCBT_CREATEWND, hook },
13943 { WM_SETFONT, sent|parent },
13944 { WM_INITDIALOG, sent|parent },
13945 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13946 { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
13947 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13948 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13949 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13950 { HCBT_ACTIVATE, hook },
13951 { WM_QUERYNEWPALETTE, sent|parent|optional }, /* TODO: this message should not be sent */
13952 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13953 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13954 { WM_WINDOWPOSCHANGED, sent|parent|wparam|optional, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13955 { WM_WINDOWPOSCHANGED, sent|parent|wparam|optional, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13956 { WM_ACTIVATEAPP, sent|parent|wparam, 1 },
13957 { WM_NCACTIVATE, sent|parent },
13958 { WM_ACTIVATE, sent|parent|wparam, 1 },
13959 { WM_SETFOCUS, sent },
13960 { WM_COMMAND, sent|parent|wparam, MAKELONG(200, EN_SETFOCUS) },
13961 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13962 { WM_USER, sent|parent },
13963 { WM_CHANGEUISTATE, sent|parent|optional },
13964 { 0 }
13967 static const struct message WmCreateDialogParamSeq_4[] = {
13968 { HCBT_CREATEWND, hook },
13969 { WM_NCCREATE, sent|parent },
13970 { WM_NCCALCSIZE, sent|parent|wparam, 0 },
13971 { WM_CREATE, sent|parent },
13972 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13973 { WM_SIZE, sent|parent|wparam, SIZE_RESTORED },
13974 { WM_MOVE, sent|parent },
13975 { WM_SETFONT, sent|parent },
13976 { WM_INITDIALOG, sent|parent },
13977 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13978 { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
13979 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13980 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13981 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13982 { HCBT_ACTIVATE, hook },
13983 { WM_QUERYNEWPALETTE, sent|parent|optional }, /* TODO: this message should not be sent */
13984 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13985 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13986 { WM_WINDOWPOSCHANGED, sent|parent|wparam|optional, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13987 { WM_ACTIVATEAPP, sent|parent|wparam, 1 },
13988 { WM_NCACTIVATE, sent|parent },
13989 { WM_ACTIVATE, sent|parent|wparam, 1 },
13990 { HCBT_SETFOCUS, hook },
13991 { WM_SETFOCUS, sent|parent },
13992 { WM_KILLFOCUS, sent|parent },
13993 { WM_SETFOCUS, sent },
13994 { WM_COMMAND, sent|parent|wparam, MAKELONG(200, EN_SETFOCUS) },
13995 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13996 { WM_USER, sent|parent },
13997 { WM_CHANGEUISTATE, sent|parent|optional },
13998 { WM_UPDATEUISTATE, sent|parent|optional },
13999 { WM_UPDATEUISTATE, sent|optional },
14000 { 0 }
14003 static void test_dialog_messages(void)
14005 WNDCLASSA cls;
14006 HWND hdlg, hedit1, hedit2, hfocus, parent, child, child2;
14007 LRESULT ret;
14009 #define set_selection(hctl, start, end) \
14010 ret = SendMessageA(hctl, EM_SETSEL, start, end); \
14011 ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
14013 #define check_selection(hctl, start, end) \
14014 ret = SendMessageA(hctl, EM_GETSEL, 0, 0); \
14015 ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
14017 subclass_edit();
14019 hdlg = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
14020 WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
14021 0, 0, 100, 100, 0, 0, 0, NULL);
14022 ok(hdlg != 0, "Failed to create custom dialog window\n");
14024 hedit1 = CreateWindowExA(0, "my_edit_class", NULL,
14025 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
14026 0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
14027 ok(hedit1 != 0, "Failed to create edit control\n");
14028 hedit2 = CreateWindowExA(0, "my_edit_class", NULL,
14029 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
14030 0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
14031 ok(hedit2 != 0, "Failed to create edit control\n");
14033 SendMessageA(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
14034 SendMessageA(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
14036 hfocus = GetFocus();
14037 ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
14039 SetFocus(hedit2);
14040 hfocus = GetFocus();
14041 ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
14043 check_selection(hedit1, 0, 0);
14044 check_selection(hedit2, 0, 0);
14046 set_selection(hedit2, 0, -1);
14047 check_selection(hedit2, 0, 3);
14049 SetFocus(0);
14050 hfocus = GetFocus();
14051 ok(hfocus == 0, "wrong focus %p\n", hfocus);
14053 flush_sequence();
14054 ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
14055 ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
14056 ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
14058 hfocus = GetFocus();
14059 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
14061 check_selection(hedit1, 0, 5);
14062 check_selection(hedit2, 0, 3);
14064 flush_sequence();
14065 ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
14066 ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
14067 ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
14069 hfocus = GetFocus();
14070 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
14072 check_selection(hedit1, 0, 5);
14073 check_selection(hedit2, 0, 3);
14075 EndDialog(hdlg, 0);
14076 DestroyWindow(hedit1);
14077 DestroyWindow(hedit2);
14078 DestroyWindow(hdlg);
14079 flush_sequence();
14081 #undef set_selection
14082 #undef check_selection
14084 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
14085 cls.lpszClassName = "MyDialogClass";
14086 cls.hInstance = GetModuleHandleA(NULL);
14087 /* need a cast since a dlgproc is used as a wndproc */
14088 cls.lpfnWndProc = test_dlg_proc;
14089 if (!RegisterClassA(&cls)) assert(0);
14091 SetFocus(0);
14092 flush_sequence();
14093 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
14094 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14095 ok_sequence(WmCreateDialogParamSeq_0, "CreateDialogParam_0", FALSE);
14096 hfocus = GetFocus();
14097 ok(hfocus == 0, "wrong focus %p\n", hfocus);
14098 EndDialog(hdlg, 0);
14099 DestroyWindow(hdlg);
14100 flush_sequence();
14102 SetFocus(0);
14103 flush_sequence();
14104 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 1);
14105 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14106 ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
14107 hfocus = GetFocus();
14108 ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
14109 EndDialog(hdlg, 0);
14110 DestroyWindow(hdlg);
14111 flush_sequence();
14113 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
14114 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14115 ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
14116 EndDialog(hdlg, 0);
14117 DestroyWindow(hdlg);
14118 flush_sequence();
14120 hdlg = CreateDialogParamA(0, "FOCUS_TEST_DIALOG_3", 0, test_dlg_proc2, 0);
14121 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14122 ok_sequence(WmCreateDialogParamSeq_3, "CreateDialogParam_3", TRUE);
14123 EndDialog(hdlg, 0);
14124 DestroyWindow(hdlg);
14125 flush_sequence();
14127 UnregisterClassA( cls.lpszClassName, cls.hInstance );
14128 cls.lpfnWndProc = test_dlg_proc4;
14129 ok( RegisterClassA(&cls), "failed to register class again\n" );
14130 hdlg = CreateDialogParamA(0, "FOCUS_TEST_DIALOG_4", 0, test_dlg_proc3, 0);
14131 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14132 ok_sequence(WmCreateDialogParamSeq_4, "CreateDialogParam_4", TRUE);
14133 EndDialog(hdlg, 0);
14134 DestroyWindow(hdlg);
14135 flush_sequence();
14137 UnregisterClassA(cls.lpszClassName, cls.hInstance);
14139 parent = CreateWindowExA(0, "TestParentClass", "Test parent",
14140 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14141 100, 100, 200, 200, 0, 0, 0, NULL);
14142 ok (parent != 0, "Failed to create parent window\n");
14144 /* This child has no parent set. We will later call SetParent on it,
14145 * so that it will have a parent set, but no WS_CHILD style. */
14146 child = CreateWindowExA(0, "TestWindowClass", "Test child",
14147 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14148 100, 100, 200, 200, 0, 0, 0, NULL);
14149 ok (child != 0, "Failed to create child window\n");
14151 /* This is a regular child window. When used as an owner, the other
14152 * child window will be used. */
14153 child2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2",
14154 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CHILD,
14155 100, 100, 200, 200, child, 0, 0, NULL);
14156 ok (child2 != 0, "Failed to create child window\n");
14158 SetParent(child, parent);
14159 SetFocus(child);
14161 flush_sequence();
14162 DialogBoxA( 0, "TEST_DIALOG", child2, TestModalDlgProc2 );
14163 ok_sequence(WmModalDialogSeq_2, "ModalDialog2", TRUE);
14165 DestroyWindow(child2);
14166 DestroyWindow(child);
14167 DestroyWindow(parent);
14168 flush_sequence();
14171 static void test_enddialog_seq(HWND dialog, HWND owner)
14173 const struct message seq[] = {
14174 { WM_ENABLE, sent },
14175 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
14176 { HCBT_ACTIVATE, hook|wparam, (WPARAM)owner },
14177 { WM_NCACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
14178 { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
14179 /* FIXME: Following two are optional because Wine sends WM_QUERYNEWPALETTE instead of WM_WINDOWPOSCHANGING */
14180 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
14181 { WM_QUERYNEWPALETTE, sent|optional },
14182 { WM_NCACTIVATE, sent|wparam|lparam, WA_ACTIVE, (LPARAM)dialog },
14183 { WM_GETTEXT, sent|optional|defwinproc },
14184 { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, (LPARAM)dialog },
14185 { HCBT_SETFOCUS, hook|wparam, (WPARAM)owner },
14186 { WM_KILLFOCUS, sent|wparam, (WPARAM)owner },
14187 { WM_SETFOCUS, sent|defwinproc|wparam, (WPARAM)dialog },
14188 { 0 }
14191 flush_sequence();
14192 EndDialog(dialog, 0);
14193 ok_sequence(seq, "EndDialog", FALSE);
14196 static void test_enddialog_seq2(HWND dialog, HWND owner)
14198 const struct message seq[] = {
14199 { WM_ENABLE, parent|sent },
14200 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
14201 { HCBT_ACTIVATE, hook|wparam, (WPARAM)owner },
14202 { WM_NCACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
14203 { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
14204 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
14205 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
14206 { HCBT_SETFOCUS, hook|wparam, (WPARAM)owner },
14207 { WM_KILLFOCUS, sent|wparam, (WPARAM)owner },
14208 { WM_SETFOCUS, sent|parent|defwinproc|wparam, (WPARAM)dialog },
14209 { 0 }
14212 flush_sequence();
14213 EndDialog(dialog, 0);
14214 ok_sequence(seq, "EndDialog2", FALSE);
14217 static void test_EndDialog(void)
14219 HWND hparent, hother, hactive, hdlg, hchild;
14220 WNDCLASSA cls;
14222 hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
14223 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
14224 100, 100, 200, 200, 0, 0, 0, NULL);
14225 ok (hparent != 0, "Failed to create parent window\n");
14227 hother = CreateWindowExA(0, "TestParentClass", "Test parent 2",
14228 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14229 200, 100, 200, 200, 0, 0, 0, NULL);
14230 ok (hother != 0, "Failed to create parent window\n");
14232 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
14233 cls.lpszClassName = "MyDialogClass";
14234 cls.hInstance = GetModuleHandleA(NULL);
14235 cls.lpfnWndProc = test_dlg_proc;
14236 if (!RegisterClassA(&cls)) assert(0);
14238 flush_sequence();
14239 SetForegroundWindow(hother);
14240 hactive = GetForegroundWindow();
14241 ok(hother == hactive, "Wrong window has focus (%p != %p)\n", hother, hactive);
14243 /* create a dialog where the parent is disabled, this parent should be
14244 * enabled and receive focus when dialog exits */
14245 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hparent, test_dlg_proc, 0);
14246 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14247 SetForegroundWindow(hdlg);
14248 hactive = GetForegroundWindow();
14249 ok(hdlg == hactive, "Wrong window has focus (%p != %p)\n", hdlg, hactive);
14250 EndDialog(hdlg, 0);
14251 ok(IsWindowEnabled(hparent), "parent is not enabled\n");
14252 hactive = GetForegroundWindow();
14253 ok(hparent == hactive, "Wrong window has focus (parent != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
14254 DestroyWindow(hdlg);
14255 flush_sequence();
14257 /* create a dialog where the parent is disabled and set active window to other window before calling EndDialog */
14258 EnableWindow(hparent, FALSE);
14259 hdlg = CreateWindowExA(0, "TestDialogClass", NULL,
14260 WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
14261 0, 0, 100, 100, hparent, 0, 0, NULL);
14262 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14263 flush_sequence();
14264 SetForegroundWindow(hother);
14265 flush_sequence();
14266 hactive = GetForegroundWindow();
14267 ok(hactive == hother, "Wrong foreground (%p != %p)\n", hactive, hother);
14268 hactive = GetActiveWindow();
14269 ok(hactive == hother, "Wrong active window (%p != %p)\n", hactive, hother);
14270 EndDialog(hdlg, 0);
14271 ok(IsWindowEnabled(hparent), "parent is not enabled\n");
14272 hactive = GetForegroundWindow();
14273 ok(hother == hactive, "Wrong window has focus (other != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
14274 DestroyWindow(hdlg);
14275 flush_sequence();
14277 DestroyWindow( hparent );
14279 hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
14280 WS_POPUP | WS_VISIBLE | WS_DISABLED,
14281 100, 100, 200, 200, 0, 0, 0, NULL);
14282 ok (hparent != 0, "Failed to create parent window\n");
14284 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
14285 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
14286 0, 0, 0, 0, 0, 0, 0, NULL);
14287 ok (hchild != 0, "Failed to create child window\n");
14289 SetParent(hchild, hparent);
14291 flush_sequence();
14292 SetForegroundWindow(hother);
14293 hactive = GetForegroundWindow();
14294 ok(hother == hactive, "Wrong foreground window (%p != %p)\n", hother, hactive);
14296 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hchild, test_dlg_proc, 0);
14297 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14299 SetForegroundWindow(hdlg);
14300 test_enddialog_seq(hdlg, hchild);
14302 hactive = GetForegroundWindow();
14303 ok(hactive == hchild, "Wrong foreground window (active: %p, parent: %p, dlg: %p, other: %p child: %p)\n", hactive, hparent, hdlg, hother, hchild);
14305 DestroyWindow(hdlg);
14307 /* Now set WS_CHILD style flag so that it's a real child and its parent will be dialog's owner. */
14308 SetWindowLongW(hchild, GWL_STYLE, GetWindowLongW(hchild, GWL_STYLE) | WS_CHILD);
14310 SetForegroundWindow(hother);
14311 hactive = GetForegroundWindow();
14312 ok(hother == hactive, "Wrong foreground window (%p != %p)\n", hother, hactive);
14314 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hchild, test_dlg_proc, 0);
14315 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
14317 SetForegroundWindow(hdlg);
14318 test_enddialog_seq2(hdlg, hparent);
14320 hactive = GetForegroundWindow();
14321 ok(hactive == hparent, "Wrong foreground window (active: %p, parent: %p, dlg: %p, other: %p child: %p)\n", hactive, hparent, hdlg, hother, hchild);
14322 DestroyWindow(hdlg);
14323 DestroyWindow(hchild);
14324 DestroyWindow(hparent);
14325 DestroyWindow(hother);
14326 flush_sequence();
14328 UnregisterClassA(cls.lpszClassName, cls.hInstance);
14331 static void test_nullCallback(void)
14333 HWND hwnd;
14335 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
14336 100, 100, 200, 200, 0, 0, 0, NULL);
14337 ok (hwnd != 0, "Failed to create overlapped window\n");
14339 SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
14340 flush_events();
14341 DestroyWindow(hwnd);
14344 /* SetActiveWindow( 0 ) hwnd visible */
14345 static const struct message SetActiveWindowSeq0[] =
14347 { HCBT_ACTIVATE, hook|optional },
14348 { WM_NCACTIVATE, sent|wparam, 0 },
14349 { WM_GETTEXT, sent|defwinproc|optional },
14350 { WM_ACTIVATE, sent|wparam, 0 },
14351 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
14352 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
14353 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
14354 { WM_KILLFOCUS, sent|optional },
14355 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
14356 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
14357 { WM_NCACTIVATE, sent|wparam|optional, 1 },
14358 { WM_GETTEXT, sent|defwinproc|optional },
14359 { WM_ACTIVATE, sent|wparam|optional, 1 },
14360 { HCBT_SETFOCUS, hook|optional },
14361 { WM_KILLFOCUS, sent|defwinproc|optional },
14362 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
14363 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
14364 { WM_IME_SETCONTEXT, sent|optional },
14365 { WM_IME_SETCONTEXT, sent|optional },
14366 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
14367 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
14368 { WM_SETFOCUS, sent|defwinproc|optional },
14369 { WM_GETTEXT, sent|optional },
14370 { 0 }
14372 /* SetActiveWindow( hwnd ) hwnd visible */
14373 static const struct message SetActiveWindowSeq1[] =
14375 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
14376 { 0 }
14378 /* SetActiveWindow( popup ) hwnd visible, popup visible */
14379 static const struct message SetActiveWindowSeq2[] =
14381 { HCBT_ACTIVATE, hook },
14382 { WM_NCACTIVATE, sent|wparam, 0 },
14383 { WM_GETTEXT, sent|defwinproc|optional },
14384 { WM_ACTIVATE, sent|wparam, 0 },
14385 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
14386 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
14387 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
14388 { WM_NCPAINT, sent|optional },
14389 { WM_GETTEXT, sent|defwinproc|optional },
14390 { WM_ERASEBKGND, sent|optional },
14391 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14392 { WM_NCACTIVATE, sent|wparam, 1 },
14393 { WM_GETTEXT, sent|defwinproc|optional },
14394 { WM_ACTIVATE, sent|wparam, 1 },
14395 { HCBT_SETFOCUS, hook },
14396 { WM_KILLFOCUS, sent|defwinproc },
14397 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
14398 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
14399 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
14400 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
14401 { WM_SETFOCUS, sent|defwinproc },
14402 { WM_GETTEXT, sent|optional },
14403 { 0 }
14406 /* SetActiveWindow( hwnd ) hwnd not visible */
14407 static const struct message SetActiveWindowSeq3[] =
14409 { HCBT_ACTIVATE, hook },
14410 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
14411 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
14412 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
14413 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14414 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14415 { WM_ACTIVATEAPP, sent|wparam, 1 },
14416 { WM_ACTIVATEAPP, sent|wparam, 1 },
14417 { WM_NCACTIVATE, sent|wparam, 1 },
14418 { WM_ACTIVATE, sent|wparam, 1 },
14419 { HCBT_SETFOCUS, hook },
14420 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
14421 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
14422 { WM_SETFOCUS, sent|defwinproc },
14423 { 0 }
14425 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
14426 static const struct message SetActiveWindowSeq4[] =
14428 { HCBT_ACTIVATE, hook },
14429 { WM_NCACTIVATE, sent|wparam, 0 },
14430 { WM_GETTEXT, sent|defwinproc|optional },
14431 { WM_ACTIVATE, sent|wparam, 0 },
14432 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
14433 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
14434 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
14435 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14436 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
14437 { WM_NCACTIVATE, sent|wparam, 1 },
14438 { WM_GETTEXT, sent|defwinproc|optional },
14439 { WM_ACTIVATE, sent|wparam, 1 },
14440 { HCBT_SETFOCUS, hook },
14441 { WM_KILLFOCUS, sent|defwinproc },
14442 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
14443 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
14444 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
14445 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
14446 { WM_SETFOCUS, sent|defwinproc },
14447 { 0 }
14451 static void test_SetActiveWindow(void)
14453 HWND hwnd, popup, ret;
14455 hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
14456 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14457 100, 100, 200, 200, 0, 0, 0, NULL);
14459 popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
14460 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
14461 100, 100, 200, 200, hwnd, 0, 0, NULL);
14463 ok(hwnd != 0, "Failed to create overlapped window\n");
14464 ok(popup != 0, "Failed to create popup window\n");
14465 SetForegroundWindow( popup );
14466 flush_sequence();
14468 trace("SetActiveWindow(0)\n");
14469 ret = SetActiveWindow(0);
14470 ok( ret == popup || broken(ret == 0) /* w1064v1809 */, "Failed to SetActiveWindow(0), ret:%p\n", ret);
14471 if (ret == popup) ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", FALSE);
14472 flush_sequence();
14474 trace("SetActiveWindow(hwnd), hwnd visible\n");
14475 ret = SetActiveWindow(hwnd);
14476 if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
14477 flush_sequence();
14479 trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
14480 ret = SetActiveWindow(popup);
14481 ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
14482 ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
14483 flush_sequence();
14485 ShowWindow(hwnd, SW_HIDE);
14486 ShowWindow(popup, SW_HIDE);
14487 flush_sequence();
14489 trace("SetActiveWindow(hwnd), hwnd not visible\n");
14490 ret = SetActiveWindow(hwnd);
14491 ok( ret == NULL, "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret );
14492 ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
14493 flush_sequence();
14495 trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
14496 ret = SetActiveWindow(popup);
14497 ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
14498 ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
14499 flush_sequence();
14501 trace("done\n");
14503 DestroyWindow(hwnd);
14506 static const struct message SetForegroundWindowSeq[] =
14508 { WM_NCACTIVATE, sent|wparam, 0 },
14509 { WM_GETTEXT, sent|defwinproc|optional },
14510 { WM_ACTIVATE, sent|wparam, 0 },
14511 { WM_ACTIVATEAPP, sent|wparam, 0 },
14512 { WM_KILLFOCUS, sent },
14513 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
14514 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
14515 { 0 }
14518 static void test_SetForegroundWindow(void)
14520 HWND hwnd;
14522 hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
14523 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14524 100, 100, 200, 200, 0, 0, 0, NULL);
14525 ok (hwnd != 0, "Failed to create overlapped window\n");
14526 SetForegroundWindow( hwnd );
14527 flush_sequence();
14529 trace("SetForegroundWindow( 0 )\n");
14530 SetForegroundWindow( 0 );
14531 ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
14532 trace("SetForegroundWindow( GetDesktopWindow() )\n");
14533 SetForegroundWindow( GetDesktopWindow() );
14534 ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
14535 "foreground top level window", FALSE);
14536 trace("done\n");
14538 DestroyWindow(hwnd);
14541 static DWORD get_input_codepage( void )
14543 DWORD cp;
14544 int ret;
14545 HKL hkl = GetKeyboardLayout( 0 );
14547 ret = GetLocaleInfoW( LOWORD(hkl), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
14548 (WCHAR *)&cp, sizeof(cp) / sizeof(WCHAR) );
14549 if (!ret) cp = CP_ACP;
14550 return cp;
14553 static void test_dbcs_wm_char(void)
14555 BYTE dbch[2];
14556 WCHAR wch, bad_wch;
14557 HWND hwnd, hwnd2;
14558 MSG msg;
14559 DWORD time;
14560 POINT pt;
14561 DWORD_PTR res;
14562 CPINFOEXA cpinfo;
14563 UINT i, j, k;
14564 struct message wmCharSeq[2];
14565 BOOL ret;
14566 DWORD cp = get_input_codepage();
14568 if (!pGetCPInfoExA)
14570 win_skip("GetCPInfoExA is not available\n");
14571 return;
14574 pGetCPInfoExA( cp, 0, &cpinfo );
14575 if (cpinfo.MaxCharSize != 2)
14577 skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
14578 return;
14581 dbch[0] = dbch[1] = 0;
14582 wch = 0;
14583 bad_wch = cpinfo.UnicodeDefaultChar;
14584 for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
14585 for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
14586 for (k = 128; k <= 255; k++)
14588 char str[2];
14589 WCHAR wstr[2];
14590 str[0] = j;
14591 str[1] = k;
14592 if (MultiByteToWideChar( cp, 0, str, 2, wstr, 2 ) == 1 &&
14593 WideCharToMultiByte( cp, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
14594 (BYTE)str[0] == j && (BYTE)str[1] == k &&
14595 HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
14597 dbch[0] = j;
14598 dbch[1] = k;
14599 wch = wstr[0];
14600 break;
14604 if (!wch)
14606 skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
14607 return;
14609 trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
14610 dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
14612 hwnd = CreateWindowExW(0, testWindowClassW, NULL,
14613 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
14614 hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
14615 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
14616 ok (hwnd != 0, "Failed to create overlapped window\n");
14617 ok (hwnd2 != 0, "Failed to create overlapped window\n");
14618 flush_events();
14619 flush_sequence();
14621 memset( wmCharSeq, 0, sizeof(wmCharSeq) );
14622 wmCharSeq[0].message = WM_CHAR;
14623 wmCharSeq[0].flags = sent|wparam;
14624 wmCharSeq[0].wParam = wch;
14626 /* posted message */
14627 PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14628 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14629 ok( !ret, "got message %x\n", msg.message );
14630 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14631 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14632 ok( ret, "no message\n" );
14633 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14634 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
14635 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14636 ok( !ret, "got message %x\n", msg.message );
14638 /* posted thread message */
14639 PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
14640 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14641 ok( !ret, "got message %x\n", msg.message );
14642 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14643 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14644 ok( ret, "no message\n" );
14645 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14646 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
14647 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14648 ok( !ret, "got message %x\n", msg.message );
14650 /* sent message */
14651 flush_sequence();
14652 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14653 ok_sequence( WmEmptySeq, "no messages", FALSE );
14654 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14655 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14656 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14657 ok( !ret, "got message %x\n", msg.message );
14659 /* sent message with timeout */
14660 flush_sequence();
14661 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
14662 ok_sequence( WmEmptySeq, "no messages", FALSE );
14663 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
14664 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14665 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14666 ok( !ret, "got message %x\n", msg.message );
14668 /* sent message with timeout and callback */
14669 flush_sequence();
14670 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
14671 ok_sequence( WmEmptySeq, "no messages", FALSE );
14672 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
14673 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14674 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14675 ok( !ret, "got message %x\n", msg.message );
14677 /* sent message with callback */
14678 flush_sequence();
14679 SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14680 ok_sequence( WmEmptySeq, "no messages", FALSE );
14681 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
14682 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14683 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14684 ok( !ret, "got message %x\n", msg.message );
14686 /* direct window proc call */
14687 flush_sequence();
14688 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
14689 ok_sequence( WmEmptySeq, "no messages", FALSE );
14690 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
14691 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14693 /* dispatch message */
14694 msg.hwnd = hwnd;
14695 msg.message = WM_CHAR;
14696 msg.wParam = dbch[0];
14697 msg.lParam = 0;
14698 DispatchMessageA( &msg );
14699 ok_sequence( WmEmptySeq, "no messages", FALSE );
14700 msg.wParam = dbch[1];
14701 DispatchMessageA( &msg );
14702 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14704 /* window handle is irrelevant */
14705 flush_sequence();
14706 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
14707 ok_sequence( WmEmptySeq, "no messages", FALSE );
14708 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14709 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14710 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14711 ok( !ret, "got message %x\n", msg.message );
14713 /* interleaved post and send */
14714 flush_sequence();
14715 PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
14716 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
14717 ok_sequence( WmEmptySeq, "no messages", FALSE );
14718 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14719 ok( !ret, "got message %x\n", msg.message );
14720 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14721 ok_sequence( WmEmptySeq, "no messages", FALSE );
14722 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14723 ok( ret, "no message\n" );
14724 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14725 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
14726 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14727 ok( !ret, "got message %x\n", msg.message );
14728 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14729 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14730 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14731 ok( !ret, "got message %x\n", msg.message );
14733 /* interleaved sent message and winproc */
14734 flush_sequence();
14735 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14736 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
14737 ok_sequence( WmEmptySeq, "no messages", FALSE );
14738 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14739 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14740 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
14741 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14743 /* interleaved winproc and dispatch */
14744 msg.hwnd = hwnd;
14745 msg.message = WM_CHAR;
14746 msg.wParam = dbch[0];
14747 msg.lParam = 0;
14748 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
14749 DispatchMessageA( &msg );
14750 ok_sequence( WmEmptySeq, "no messages", FALSE );
14751 msg.wParam = dbch[1];
14752 DispatchMessageA( &msg );
14753 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14754 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
14755 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14757 /* interleaved sends */
14758 flush_sequence();
14759 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14760 SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
14761 ok_sequence( WmEmptySeq, "no messages", FALSE );
14762 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
14763 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14764 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14765 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14767 /* dbcs WM_CHAR */
14768 flush_sequence();
14769 SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
14770 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14771 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14772 ok( !ret, "got message %x\n", msg.message );
14774 /* other char messages are not magic */
14775 PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
14776 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14777 ok( ret, "no message\n" );
14778 ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
14779 ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
14780 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14781 ok( !ret, "got message %x\n", msg.message );
14782 PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
14783 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14784 ok( ret, "no message\n" );
14785 ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
14786 ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
14787 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14788 ok( !ret, "got message %x\n", msg.message );
14790 /* test retrieving messages */
14792 PostMessageW( hwnd, WM_CHAR, wch, 0 );
14793 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14794 ok( ret, "no message\n" );
14795 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14796 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14797 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14798 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14799 ok( ret, "no message\n" );
14800 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14801 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14802 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14803 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14804 ok( !ret, "got message %x\n", msg.message );
14806 /* message filters */
14807 PostMessageW( hwnd, WM_CHAR, wch, 0 );
14808 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14809 ok( ret, "no message\n" );
14810 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14811 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14812 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14813 /* message id is filtered, hwnd is not */
14814 ret = PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE );
14815 ok( !ret, "no message\n" );
14816 ret = PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE );
14817 ok( ret, "no message\n" );
14818 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14819 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14820 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14821 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14822 ok( !ret, "got message %x\n", msg.message );
14824 /* mixing GetMessage and PostMessage */
14825 PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
14826 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
14827 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14828 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14829 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14830 ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
14831 time = msg.time;
14832 pt = msg.pt;
14833 ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
14834 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
14835 ok( ret, "no message\n" );
14836 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14837 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14838 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14839 ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
14840 ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
14841 ok( msg.pt.x == pt.x && msg.pt.y == pt.y, "bad point %u,%u/%u,%u\n", msg.pt.x, msg.pt.y, pt.x, pt.y );
14842 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14843 ok( !ret, "got message %x\n", msg.message );
14845 /* without PM_REMOVE */
14846 PostMessageW( hwnd, WM_CHAR, wch, 0 );
14847 ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
14848 ok( ret, "no message\n" );
14849 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14850 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14851 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14852 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
14853 ok( ret, "no message\n" );
14854 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14855 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14856 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14857 ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
14858 ok( ret, "no message\n" );
14859 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14860 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14861 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14862 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
14863 ok( ret, "no message\n" );
14864 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14865 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14866 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14867 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14868 ok( !ret, "got message %x\n", msg.message );
14870 DestroyWindow(hwnd);
14871 DestroyWindow(hwnd2);
14874 static void test_unicode_wm_char(void)
14876 HWND hwnd;
14877 MSG msg;
14878 struct message seq[2];
14879 HKL hkl_orig, hkl_greek;
14880 DWORD cp;
14881 LCID thread_locale;
14883 hkl_orig = GetKeyboardLayout( 0 );
14884 GetLocaleInfoW( LOWORD( hkl_orig ), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, (WCHAR*)&cp, sizeof(cp) / sizeof(WCHAR) );
14885 if (cp != 1252)
14887 skip( "Default codepage %d\n", cp );
14888 return;
14891 hkl_greek = LoadKeyboardLayoutA( "00000408", 0 );
14892 if (!hkl_greek || hkl_greek == hkl_orig /* win2k */)
14894 skip( "Unable to load Greek keyboard layout\n" );
14895 return;
14898 hwnd = CreateWindowExW( 0, testWindowClassW, NULL, WS_OVERLAPPEDWINDOW,
14899 100, 100, 200, 200, 0, 0, 0, NULL );
14900 flush_sequence();
14902 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
14904 while (GetMessageW( &msg, hwnd, 0, 0 ))
14906 if (!ignore_message( msg.message )) break;
14909 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14910 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14911 ok( msg.wParam == 0x3b1, "bad wparam %lx\n", msg.wParam );
14912 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
14914 DispatchMessageW( &msg );
14916 memset( seq, 0, sizeof(seq) );
14917 seq[0].message = WM_CHAR;
14918 seq[0].flags = sent|wparam;
14919 seq[0].wParam = 0x3b1;
14921 ok_sequence( seq, "unicode WM_CHAR", FALSE );
14923 flush_sequence();
14925 /* greek alpha -> 'a' in cp1252 */
14926 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
14928 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
14929 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14930 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14931 ok( msg.wParam == 0x61, "bad wparam %lx\n", msg.wParam );
14932 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
14934 DispatchMessageA( &msg );
14936 seq[0].wParam = 0x61;
14937 ok_sequence( seq, "unicode WM_CHAR", FALSE );
14939 thread_locale = GetThreadLocale();
14940 ActivateKeyboardLayout( hkl_greek, 0 );
14941 ok( GetThreadLocale() == thread_locale, "locale changed from %08x to %08x\n",
14942 thread_locale, GetThreadLocale() );
14944 flush_sequence();
14946 /* greek alpha -> 0xe1 in cp1253 */
14947 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
14949 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
14950 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14951 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14952 ok( msg.wParam == 0xe1, "bad wparam %lx\n", msg.wParam );
14953 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
14955 DispatchMessageA( &msg );
14957 seq[0].wParam = 0x3b1;
14958 ok_sequence( seq, "unicode WM_CHAR", FALSE );
14960 DestroyWindow( hwnd );
14961 ActivateKeyboardLayout( hkl_orig, 0 );
14962 UnloadKeyboardLayout( hkl_greek );
14965 #define ID_LISTBOX 0x000f
14967 static const struct message wm_lb_setcursel_0[] =
14969 { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
14970 { WM_CTLCOLORLISTBOX, sent|parent },
14971 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
14972 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14973 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14974 { 0 }
14976 static const struct message wm_lb_setcursel_1[] =
14978 { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
14979 { WM_CTLCOLORLISTBOX, sent|parent },
14980 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
14981 { WM_CTLCOLORLISTBOX, sent|parent },
14982 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
14983 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
14984 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
14985 { 0 }
14987 static const struct message wm_lb_setcursel_2[] =
14989 { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
14990 { WM_CTLCOLORLISTBOX, sent|parent },
14991 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
14992 { WM_CTLCOLORLISTBOX, sent|parent },
14993 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
14994 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
14995 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
14996 { 0 }
14998 static const struct message wm_lb_click_0[] =
15000 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
15001 { HCBT_SETFOCUS, hook },
15002 { WM_KILLFOCUS, sent|parent },
15003 { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
15004 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
15005 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
15006 { WM_SETFOCUS, sent|defwinproc },
15008 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
15009 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
15010 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
15011 { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
15012 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
15014 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
15015 { WM_CTLCOLORLISTBOX, sent|parent },
15016 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
15017 { WM_CTLCOLORLISTBOX, sent|parent },
15018 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
15019 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
15021 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
15022 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
15024 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
15025 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
15026 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
15027 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
15028 { 0 }
15030 static const struct message wm_lb_deletestring[] =
15032 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
15033 { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
15034 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
15035 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
15036 { 0 }
15038 static const struct message wm_lb_deletestring_reset[] =
15040 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
15041 { LB_RESETCONTENT, sent|wparam|lparam|defwinproc|optional, 0, 0 },
15042 { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
15043 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
15044 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
15045 { 0 }
15047 static const struct message wm_lb_addstring[] =
15049 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
15050 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
15051 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
15052 { 0 }
15054 static const struct message wm_lb_addstring_ownerdraw[] =
15056 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
15057 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf0f2, 0xf30604ed },
15058 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
15059 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf1f2, 0xf30604ee },
15060 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
15061 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf2f2, 0xf30604ef },
15062 { 0 }
15064 static const struct message wm_lb_addstring_sort_ownerdraw[] =
15066 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
15067 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf0f2, 0xf30604ed },
15068 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
15069 { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ed, 0xf30604ee },
15070 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf1f2, 0xf30604ee },
15071 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
15072 { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ed, 0xf30604ef },
15073 { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ee, 0xf30604ef },
15074 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf2f2, 0xf30604ef },
15075 { 0 }
15078 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
15080 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
15082 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
15084 static LONG defwndproc_counter = 0;
15085 LRESULT ret;
15086 struct recvd_message msg;
15088 /* do not log painting messages */
15089 if (message != WM_PAINT &&
15090 message != WM_NCPAINT &&
15091 message != WM_SYNCPAINT &&
15092 message != WM_ERASEBKGND &&
15093 message != WM_NCHITTEST &&
15094 message != WM_GETTEXT &&
15095 !ignore_message( message ))
15097 msg.hwnd = hwnd;
15098 msg.message = message;
15099 msg.flags = sent|wparam|lparam;
15100 if (defwndproc_counter) msg.flags |= defwinproc;
15101 msg.wParam = wp;
15102 if (message == LB_ADDSTRING)
15103 msg.lParam = lp ? hash_Ly((const char *)lp) : 0;
15104 else
15105 msg.lParam = lp;
15106 msg.descr = "listbox";
15107 add_message(&msg);
15110 defwndproc_counter++;
15111 ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
15112 defwndproc_counter--;
15114 return ret;
15117 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
15118 int caret_index, int top_index, int line)
15120 LRESULT ret;
15122 /* calling an orig proc helps to avoid unnecessary message logging */
15123 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
15124 ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
15125 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
15126 ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
15127 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
15128 ok_(__FILE__, line)(ret == caret_index ||
15129 broken(cur_sel == -1 && caret_index == 0 && ret == -1), /* nt4 */
15130 "expected caret index %d, got %ld\n", caret_index, ret);
15131 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
15132 ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
15135 static void test_listbox_messages(void)
15137 HWND parent, listbox;
15138 LRESULT ret;
15140 parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
15141 100, 100, 200, 200, 0, 0, 0, NULL);
15142 /* with LBS_HASSTRINGS */
15143 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
15144 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
15145 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
15146 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
15148 check_lb_state(listbox, 0, LB_ERR, 0, 0);
15150 flush_sequence();
15152 log_all_parent_messages++;
15154 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
15155 ok(ret == 0, "expected 0, got %ld\n", ret);
15156 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
15157 ok(ret == 1, "expected 1, got %ld\n", ret);
15158 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
15159 ok(ret == 2, "expected 2, got %ld\n", ret);
15161 ok_sequence(wm_lb_addstring_ownerdraw, "LB_ADDSTRING", FALSE);
15162 check_lb_state(listbox, 3, LB_ERR, 0, 0);
15164 flush_sequence();
15166 trace("selecting item 0\n");
15167 ret = SendMessageA(listbox, LB_SETCURSEL, 0, 0);
15168 ok(ret == 0, "expected 0, got %ld\n", ret);
15169 ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
15170 check_lb_state(listbox, 3, 0, 0, 0);
15171 flush_sequence();
15173 trace("selecting item 1\n");
15174 ret = SendMessageA(listbox, LB_SETCURSEL, 1, 0);
15175 ok(ret == 1, "expected 1, got %ld\n", ret);
15176 ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
15177 check_lb_state(listbox, 3, 1, 1, 0);
15179 trace("selecting item 2\n");
15180 ret = SendMessageA(listbox, LB_SETCURSEL, 2, 0);
15181 ok(ret == 2, "expected 2, got %ld\n", ret);
15182 ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
15183 check_lb_state(listbox, 3, 2, 2, 0);
15185 trace("clicking on item 0\n");
15186 ret = SendMessageA(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
15187 ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
15188 ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0);
15189 ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
15190 ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
15191 check_lb_state(listbox, 3, 0, 0, 0);
15192 flush_sequence();
15194 trace("deleting item 0\n");
15195 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
15196 ok(ret == 2, "expected 2, got %ld\n", ret);
15197 ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
15198 check_lb_state(listbox, 2, -1, 0, 0);
15199 flush_sequence();
15201 trace("deleting item 0\n");
15202 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
15203 ok(ret == 1, "expected 1, got %ld\n", ret);
15204 ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
15205 check_lb_state(listbox, 1, -1, 0, 0);
15206 flush_sequence();
15208 trace("deleting item 0\n");
15209 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
15210 ok(ret == 0, "expected 0, got %ld\n", ret);
15211 ok_sequence(wm_lb_deletestring_reset, "LB_DELETESTRING 0", FALSE );
15212 check_lb_state(listbox, 0, -1, 0, 0);
15213 flush_sequence();
15215 trace("deleting item 0\n");
15216 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
15217 ok(ret == LB_ERR, "expected LB_ERR, got %ld\n", ret);
15218 check_lb_state(listbox, 0, -1, 0, 0);
15219 flush_sequence();
15221 log_all_parent_messages--;
15223 DestroyWindow(listbox);
15225 /* with LBS_SORT and without LBS_HASSTRINGS */
15226 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
15227 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_SORT | WS_VISIBLE,
15228 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
15229 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
15231 check_lb_state(listbox, 0, LB_ERR, 0, 0);
15233 flush_sequence();
15235 log_all_parent_messages++;
15237 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
15238 ok(ret == 0, "expected 0, got %ld\n", ret);
15239 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
15240 ok(ret == 1, "expected 1, got %ld\n", ret);
15241 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
15242 ok(ret == 2, "expected 2, got %ld\n", ret);
15244 ok_sequence(wm_lb_addstring_sort_ownerdraw, "LB_ADDSTRING", FALSE);
15245 check_lb_state(listbox, 3, LB_ERR, 0, 0);
15247 log_all_parent_messages--;
15249 DestroyWindow(listbox);
15251 /* with LBS_HASSTRINGS */
15252 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
15253 WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | WS_VISIBLE,
15254 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
15255 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
15257 check_lb_state(listbox, 0, LB_ERR, 0, 0);
15259 flush_sequence();
15261 log_all_parent_messages++;
15263 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
15264 ok(ret == 0, "expected 0, got %ld\n", ret);
15265 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
15266 ok(ret == 1, "expected 1, got %ld\n", ret);
15267 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
15268 ok(ret == 2, "expected 2, got %ld\n", ret);
15270 ok_sequence(wm_lb_addstring, "LB_ADDSTRING", FALSE);
15271 check_lb_state(listbox, 3, LB_ERR, 0, 0);
15273 log_all_parent_messages--;
15275 DestroyWindow(listbox);
15277 /* with LBS_HASSTRINGS and LBS_SORT */
15278 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
15279 WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | LBS_SORT | WS_VISIBLE,
15280 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
15281 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
15283 check_lb_state(listbox, 0, LB_ERR, 0, 0);
15285 flush_sequence();
15287 log_all_parent_messages++;
15289 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
15290 ok(ret == 0, "expected 0, got %ld\n", ret);
15291 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
15292 ok(ret == 0, "expected 0, got %ld\n", ret);
15293 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
15294 ok(ret == 1, "expected 1, got %ld\n", ret);
15296 ok_sequence(wm_lb_addstring, "LB_ADDSTRING", FALSE);
15297 check_lb_state(listbox, 3, LB_ERR, 0, 0);
15299 log_all_parent_messages--;
15301 DestroyWindow(listbox);
15302 DestroyWindow(parent);
15305 /*************************** Menu test ******************************/
15306 static const struct message wm_popup_menu_1[] =
15308 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
15309 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
15310 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
15311 { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
15312 { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
15313 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
15314 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
15315 { WM_INITMENU, sent|lparam, 0, 0 },
15316 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
15317 { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
15318 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
15319 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
15320 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
15321 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
15322 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001, 0, 0x40000000 },
15323 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
15324 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
15325 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
15326 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
15327 { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
15328 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
15329 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
15330 { 0 }
15332 static const struct message wm_popup_menu_2[] =
15334 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
15335 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
15336 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
15337 { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
15338 { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
15339 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
15340 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
15341 { WM_INITMENU, sent|lparam, 0, 0 },
15342 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
15343 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
15344 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
15345 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
15346 { HCBT_CREATEWND, hook },
15347 { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
15348 |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
15349 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
15350 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
15351 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
15352 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
15353 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
15354 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
15355 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
15356 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
15357 { HCBT_DESTROYWND, hook },
15358 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
15359 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
15360 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
15361 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
15362 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
15363 { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
15364 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
15365 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
15366 { 0 }
15368 static const struct message wm_popup_menu_3[] =
15370 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
15371 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
15372 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
15373 { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
15374 { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
15375 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
15376 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
15377 { WM_INITMENU, sent|lparam, 0, 0 },
15378 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
15379 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
15380 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
15381 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
15382 { HCBT_CREATEWND, hook },
15383 { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
15384 |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
15385 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
15386 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
15387 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
15388 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
15389 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
15390 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
15391 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
15392 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
15393 { HCBT_DESTROYWND, hook },
15394 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
15395 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
15396 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
15397 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
15398 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
15399 { WM_COMMAND, sent|wparam|lparam, 100, 0 },
15400 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
15401 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
15402 { 0 }
15405 static const struct message wm_single_menu_item[] =
15407 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
15408 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
15409 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0x20000001 },
15410 { WM_SYSKEYDOWN, sent|wparam|lparam, 'Q', 0x20000001 },
15411 { WM_SYSCHAR, sent|wparam|lparam, 'q', 0x20000001 },
15412 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'q' },
15413 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
15414 { WM_INITMENU, sent|lparam, 0, 0 },
15415 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(300,MF_HILITE) },
15416 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
15417 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
15418 { WM_MENUCOMMAND, sent },
15419 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0xe0000001 },
15420 { WM_SYSKEYUP, sent|wparam|lparam, 'Q', 0xe0000001 },
15421 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 },
15422 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
15424 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 1 },
15425 { WM_KEYDOWN, sent|wparam|lparam, VK_ESCAPE, 1 },
15426 { WM_CHAR, sent|wparam|lparam, VK_ESCAPE, 0x00000001 },
15427 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 },
15428 { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
15429 { 0 }
15432 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
15434 if (message == WM_ENTERIDLE ||
15435 message == WM_INITMENU ||
15436 message == WM_INITMENUPOPUP ||
15437 message == WM_MENUSELECT ||
15438 message == WM_PARENTNOTIFY ||
15439 message == WM_ENTERMENULOOP ||
15440 message == WM_EXITMENULOOP ||
15441 message == WM_UNINITMENUPOPUP ||
15442 message == WM_KEYDOWN ||
15443 message == WM_KEYUP ||
15444 message == WM_CHAR ||
15445 message == WM_SYSKEYDOWN ||
15446 message == WM_SYSKEYUP ||
15447 message == WM_SYSCHAR ||
15448 message == WM_COMMAND ||
15449 message == WM_MENUCOMMAND)
15451 struct recvd_message msg;
15453 msg.hwnd = hwnd;
15454 msg.message = message;
15455 msg.flags = sent|wparam|lparam;
15456 msg.wParam = wp;
15457 msg.lParam = lp;
15458 msg.descr = "parent_menu_proc";
15459 add_message(&msg);
15462 return DefWindowProcA(hwnd, message, wp, lp);
15465 static void set_menu_style(HMENU hmenu, DWORD style)
15467 MENUINFO mi;
15468 BOOL ret;
15470 mi.cbSize = sizeof(mi);
15471 mi.fMask = MIM_STYLE;
15472 mi.dwStyle = style;
15473 SetLastError(0xdeadbeef);
15474 ret = SetMenuInfo(hmenu, &mi);
15475 ok(ret, "SetMenuInfo error %u\n", GetLastError());
15478 static DWORD get_menu_style(HMENU hmenu)
15480 MENUINFO mi;
15481 BOOL ret;
15483 mi.cbSize = sizeof(mi);
15484 mi.fMask = MIM_STYLE;
15485 mi.dwStyle = 0;
15486 SetLastError(0xdeadbeef);
15487 ret = GetMenuInfo(hmenu, &mi);
15488 ok(ret, "GetMenuInfo error %u\n", GetLastError());
15490 return mi.dwStyle;
15493 static void test_menu_messages(void)
15495 MSG msg;
15496 WNDCLASSA cls;
15497 HMENU hmenu, hmenu_popup;
15498 HWND hwnd;
15499 DWORD style;
15500 BOOL us_kbd = (GetKeyboardLayout(0) == (HKL)(ULONG_PTR)0x04090409);
15502 cls.style = 0;
15503 cls.lpfnWndProc = parent_menu_proc;
15504 cls.cbClsExtra = 0;
15505 cls.cbWndExtra = 0;
15506 cls.hInstance = GetModuleHandleA(0);
15507 cls.hIcon = 0;
15508 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
15509 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
15510 cls.lpszMenuName = NULL;
15511 cls.lpszClassName = "TestMenuClass";
15512 UnregisterClassA(cls.lpszClassName, cls.hInstance);
15513 if (!RegisterClassA(&cls)) assert(0);
15515 SetLastError(0xdeadbeef);
15516 hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
15517 100, 100, 200, 200, 0, 0, 0, NULL);
15518 ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError());
15520 SetLastError(0xdeadbeef);
15521 hmenu = LoadMenuA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
15522 ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError());
15524 SetMenu(hwnd, hmenu);
15525 SetForegroundWindow( hwnd );
15526 flush_events();
15528 set_menu_style(hmenu, MNS_NOTIFYBYPOS);
15529 style = get_menu_style(hmenu);
15530 ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
15532 hmenu_popup = GetSubMenu(hmenu, 0);
15533 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
15534 style = get_menu_style(hmenu_popup);
15535 ok(style == 0, "expected 0, got %u\n", style);
15537 hmenu_popup = GetSubMenu(hmenu_popup, 0);
15538 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
15539 style = get_menu_style(hmenu_popup);
15540 ok(style == 0, "expected 0, got %u\n", style);
15542 if (!us_kbd)
15544 skip("skipping ascii VK events on non-us keyboard\n");
15545 goto done;
15548 /* Alt+E, Enter */
15549 trace("testing a popup menu command\n");
15550 flush_sequence();
15551 keybd_event(VK_MENU, 0, 0, 0);
15552 keybd_event('E', 0, 0, 0);
15553 keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
15554 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
15555 keybd_event(VK_RETURN, 0, 0, 0);
15556 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
15557 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15559 TranslateMessage(&msg);
15560 DispatchMessageA(&msg);
15562 if (!sequence_cnt) /* we didn't get any message */
15564 skip( "queuing key events not supported\n" );
15565 goto done;
15567 /* win98 queues only a WM_KEYUP and doesn't start menu tracking */
15568 if (sequence[0].message == WM_KEYUP && sequence[0].wParam == VK_MENU)
15570 win_skip( "menu tracking through VK_MENU not supported\n" );
15571 goto done;
15573 ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
15575 /* Alt+F, Right, Enter */
15576 trace("testing submenu of a popup menu command\n");
15577 flush_sequence();
15578 keybd_event(VK_MENU, 0, 0, 0);
15579 keybd_event('F', 0, 0, 0);
15580 keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
15581 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
15582 keybd_event(VK_RIGHT, 0, 0, 0);
15583 keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
15584 keybd_event(VK_RETURN, 0, 0, 0);
15585 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
15586 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15588 TranslateMessage(&msg);
15589 DispatchMessageA(&msg);
15591 ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
15593 trace("testing single menu item command\n");
15594 flush_sequence();
15595 keybd_event(VK_MENU, 0, 0, 0);
15596 keybd_event('Q', 0, 0, 0);
15597 keybd_event('Q', 0, KEYEVENTF_KEYUP, 0);
15598 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
15599 keybd_event(VK_ESCAPE, 0, 0, 0);
15600 keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
15601 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15603 TranslateMessage(&msg);
15604 DispatchMessageA(&msg);
15606 ok_sequence(wm_single_menu_item, "single menu item command", FALSE);
15608 set_menu_style(hmenu, 0);
15609 style = get_menu_style(hmenu);
15610 ok(style == 0, "expected 0, got %u\n", style);
15612 hmenu_popup = GetSubMenu(hmenu, 0);
15613 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
15614 set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
15615 style = get_menu_style(hmenu_popup);
15616 ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
15618 hmenu_popup = GetSubMenu(hmenu_popup, 0);
15619 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
15620 style = get_menu_style(hmenu_popup);
15621 ok(style == 0, "expected 0, got %u\n", style);
15623 /* Alt+F, Right, Enter */
15624 trace("testing submenu of a popup menu command\n");
15625 flush_sequence();
15626 keybd_event(VK_MENU, 0, 0, 0);
15627 keybd_event('F', 0, 0, 0);
15628 keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
15629 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
15630 keybd_event(VK_RIGHT, 0, 0, 0);
15631 keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
15632 keybd_event(VK_RETURN, 0, 0, 0);
15633 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
15634 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15636 TranslateMessage(&msg);
15637 DispatchMessageA(&msg);
15639 ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
15641 done:
15642 DestroyWindow(hwnd);
15643 DestroyMenu(hmenu);
15647 static void test_paintingloop(void)
15649 HWND hwnd;
15651 paint_loop_done = FALSE;
15652 hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
15653 "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
15654 100, 100, 100, 100, 0, 0, 0, NULL );
15655 ok(hwnd != 0, "PaintLoop window error %u\n", GetLastError());
15656 ShowWindow(hwnd,SW_NORMAL);
15657 SetFocus(hwnd);
15659 while (!paint_loop_done)
15661 MSG msg;
15662 if (PeekMessageA(&msg, 0, 0, 0, 1))
15664 TranslateMessage(&msg);
15665 DispatchMessageA(&msg);
15668 DestroyWindow(hwnd);
15671 static const struct message NCRBUTTONDOWNSeq[] =
15673 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
15674 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
15675 { WM_CAPTURECHANGED, sent },
15676 { WM_CONTEXTMENU, sent, /*hwnd*/0, -1 },
15677 { 0 }
15680 static const struct message NCXBUTTONUPSeq1[] =
15682 { WM_APPCOMMAND, sent|lparam, /*hwnd*/0, MAKELPARAM(0, FAPPCOMMAND_MOUSE | APPCOMMAND_BROWSER_BACKWARD) },
15683 { 0 }
15686 static const struct message NCXBUTTONUPSeq2[] =
15688 { WM_APPCOMMAND, sent|lparam, /*hwnd*/0, MAKELPARAM(0, FAPPCOMMAND_MOUSE | APPCOMMAND_BROWSER_FORWARD) },
15689 { 0 }
15692 /* DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0) to minimized visible window */
15693 static const struct message WmRestoreMinimizedOverlappedSeq[] =
15695 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_RESTORE, 0 },
15696 { HCBT_MINMAX, hook },
15697 { WM_QUERYOPEN, sent },
15698 { WM_GETTEXT, sent|optional },
15699 { WM_NCACTIVATE, sent|optional },
15700 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
15701 { WM_WINDOWPOSCHANGED, sent|optional },
15702 { WM_WINDOWPOSCHANGING, sent|optional },
15703 { WM_GETMINMAXINFO, sent|defwinproc },
15704 { WM_NCCALCSIZE, sent|optional },
15705 { WM_NCPAINT, sent|optional },
15706 { WM_GETTEXT, sent|defwinproc|optional },
15707 { WM_ERASEBKGND, sent|optional },
15708 { WM_WINDOWPOSCHANGED, sent|optional },
15709 { HCBT_ACTIVATE, hook },
15710 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
15711 { WM_ACTIVATEAPP, sent|wparam, TRUE },
15712 { WM_NCACTIVATE, sent|wparam, TRUE },
15713 { WM_GETTEXT, sent|defwinproc|optional },
15714 { WM_ACTIVATE, sent|wparam, TRUE },
15715 { HCBT_SETFOCUS, hook },
15716 { WM_SETFOCUS, sent|defwinproc },
15717 { WM_NCPAINT, sent },
15718 { WM_GETTEXT, sent|defwinproc|optional },
15719 { WM_ERASEBKGND, sent },
15720 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_FRAMECHANGED|SWP_STATECHANGED },
15721 { WM_MOVE, sent|defwinproc },
15722 { WM_SIZE, sent|defwinproc },
15723 { WM_NCCALCSIZE, sent|optional },
15724 { WM_NCPAINT, sent|optional },
15725 { WM_ERASEBKGND, sent|optional },
15726 { WM_ACTIVATE, sent|wparam, TRUE },
15727 { WM_SYNCPAINT, sent|optional },
15728 { WM_PAINT, sent },
15729 { 0 }
15732 /* DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0) to an active minimized window */
15733 static const struct message WmRestoreActiveMinimizedOverlappedSeq[] =
15735 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_RESTORE, 0 },
15736 { HCBT_MINMAX, hook },
15737 { WM_QUERYOPEN, sent },
15738 { WM_GETTEXT, sent|optional },
15739 { WM_NCACTIVATE, sent },
15740 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
15741 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15742 { WM_NCCALCSIZE, sent|optional },
15743 { WM_MOVE, sent|optional },
15744 { WM_SIZE, sent|optional },
15745 { WM_GETTEXT, sent|optional },
15746 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
15747 { WM_GETMINMAXINFO, sent|defwinproc },
15748 { WM_NCCALCSIZE, sent },
15749 { WM_NCPAINT, sent },
15750 { WM_GETTEXT, sent|defwinproc|optional },
15751 { WM_ERASEBKGND, sent },
15752 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
15753 { WM_MOVE, sent|defwinproc },
15754 { WM_SIZE, sent|defwinproc },
15755 { WM_NCCALCSIZE, sent|optional },
15756 { WM_NCPAINT, sent|optional },
15757 { WM_ERASEBKGND, sent|optional },
15758 { HCBT_SETFOCUS, hook },
15759 { WM_SETFOCUS, sent },
15760 /* Note this WM_ACTIVATE messages even if the window is already active */
15761 { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, 0 },
15762 { WM_SYNCPAINT, sent|optional },
15763 { WM_PAINT, sent },
15764 { WM_GETMINMAXINFO, sent|optional },
15765 { 0 }
15768 struct rbuttonup_thread_data
15770 HWND hwnd;
15771 HANDLE wndproc_finished;
15774 static DWORD CALLBACK post_rbuttonup_msg( void *arg )
15776 struct rbuttonup_thread_data *data = arg;
15777 DWORD ret;
15779 ret = WaitForSingleObject( data->wndproc_finished, 500 );
15780 todo_wine ok( ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", ret );
15781 if( ret == WAIT_OBJECT_0 ) return 0;
15783 PostMessageA( data->hwnd, WM_RBUTTONUP, 0, 0 );
15784 return 0;
15787 static void test_defwinproc(void)
15789 HWND hwnd;
15790 MSG msg;
15791 BOOL gotwmquit = FALSE;
15792 POINT pos;
15793 RECT rect;
15794 INT x, y;
15795 LRESULT res;
15796 struct rbuttonup_thread_data data;
15797 char buffA[64];
15798 HANDLE thread;
15800 hwnd = CreateWindowExA(0, "TestWindowClass", "test_defwndproc",
15801 WS_VISIBLE | WS_CAPTION | WS_OVERLAPPEDWINDOW, 0,0,500,100,0,0,0, NULL);
15802 assert(hwnd);
15803 flush_events();
15805 buffA[0] = 0;
15806 GetWindowTextA(hwnd, buffA, ARRAY_SIZE(buffA));
15807 ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
15809 /* Zero high word of the lParam */
15810 res = DefWindowProcA(hwnd, WM_SETTEXT, 0, 0x1234);
15811 ok(res == 0, "WM_SETTEXT was expected to fail, %ld\n", res);
15813 GetWindowTextA(hwnd, buffA, ARRAY_SIZE(buffA));
15814 ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
15816 res = DefWindowProcW(hwnd, WM_SETTEXT, 0, 0x1234);
15817 ok(res == 0, "WM_SETTEXT was expected to fail, %ld\n", res);
15819 GetWindowTextA(hwnd, buffA, ARRAY_SIZE(buffA));
15820 ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
15822 ShowWindow(hwnd, SW_MINIMIZE);
15823 flush_events();
15824 flush_sequence();
15826 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
15827 flush_events();
15828 ok_sequence(WmRestoreMinimizedOverlappedSeq, "DefWindowProcA(SC_RESTORE):overlapped", TRUE);
15830 ShowWindow(hwnd, SW_MINIMIZE);
15831 SetActiveWindow(hwnd);
15832 ok(GetActiveWindow() == hwnd, "Unexpected active window\n");
15833 flush_events();
15834 flush_sequence();
15835 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
15836 flush_events();
15837 ok_sequence(WmRestoreActiveMinimizedOverlappedSeq, "DefWindowProcA(SC_RESTORE):active minimized overlapped", TRUE);
15839 GetCursorPos(&pos);
15840 GetWindowRect(hwnd, &rect);
15841 x = (rect.left+rect.right) / 2;
15842 y = rect.top + GetSystemMetrics(SM_CYFRAME) + 1;
15843 SetCursorPos(x, y);
15844 flush_events();
15845 res = DefWindowProcA( hwnd, WM_NCHITTEST, 0, MAKELPARAM(x, y));
15846 ok(res == HTCAPTION, "WM_NCHITTEST returned %ld\n", res);
15848 mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 );
15849 mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 );
15850 flush_events();
15852 flush_sequence();
15853 mouse_event( MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0 );
15854 /* workaround for missing support for clicking on window frame */
15855 data.hwnd = hwnd;
15856 data.wndproc_finished = CreateEventA( NULL, FALSE, FALSE, NULL );
15857 thread = CreateThread( NULL, 0, post_rbuttonup_msg, (void*)&data, 0, NULL );
15859 DefWindowProcA( hwnd, WM_NCRBUTTONDOWN, HTCAPTION, MAKELPARAM(x, y));
15860 ok_sequence(NCRBUTTONDOWNSeq, "WM_NCRBUTTONDOWN on caption", FALSE);
15862 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, 0, MAKELPARAM(x, y));
15863 ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15864 ok_sequence(WmEmptySeq, "WM_NCXBUTTONUP without button", FALSE);
15866 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, XBUTTON1), MAKELPARAM(x, y));
15867 ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15868 ok_sequence(NCXBUTTONUPSeq1, "WM_NCXBUTTONUP with XBUTTON1", FALSE);
15870 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, XBUTTON2), MAKELPARAM(x, y));
15871 ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15872 ok_sequence(NCXBUTTONUPSeq2, "WM_NCXBUTTONUP with XBUTTON2", FALSE);
15874 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, 3), MAKELPARAM(x, y));
15875 ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15876 ok_sequence(WmEmptySeq, "WM_NCXBUTTONUP with invalid button", FALSE);
15878 /* Test WM_MOUSEACTIVATE */
15879 #define TEST_MOUSEACTIVATE(A,B,C) \
15880 res = DefWindowProcA(hwnd, WM_MOUSEACTIVATE, (WPARAM)hwnd, (LPARAM)MAKELRESULT(A,0)); \
15881 ok(res == B, "WM_MOUSEACTIVATE for %s returned %ld\n", #A, res); \
15882 res = DefWindowProcA(hwnd, WM_MOUSEACTIVATE, (WPARAM)hwnd, (LPARAM)MAKELRESULT(A,WM_LBUTTONDOWN)); \
15883 ok(res == C, "WM_MOUSEACTIVATE for %s returned %ld\n", #A, res);
15885 TEST_MOUSEACTIVATE(HTERROR, MA_ACTIVATE, MA_ACTIVATE);
15886 TEST_MOUSEACTIVATE(HTTRANSPARENT, MA_ACTIVATE, MA_ACTIVATE);
15887 TEST_MOUSEACTIVATE(HTNOWHERE, MA_ACTIVATE, MA_ACTIVATE);
15888 TEST_MOUSEACTIVATE(HTCLIENT, MA_ACTIVATE, MA_ACTIVATE);
15889 TEST_MOUSEACTIVATE(HTCAPTION, MA_ACTIVATE, MA_NOACTIVATE);
15890 TEST_MOUSEACTIVATE(HTSYSMENU, MA_ACTIVATE, MA_ACTIVATE);
15891 TEST_MOUSEACTIVATE(HTSIZE, MA_ACTIVATE, MA_ACTIVATE);
15892 TEST_MOUSEACTIVATE(HTMENU, MA_ACTIVATE, MA_ACTIVATE);
15893 TEST_MOUSEACTIVATE(HTHSCROLL, MA_ACTIVATE, MA_ACTIVATE);
15894 TEST_MOUSEACTIVATE(HTVSCROLL, MA_ACTIVATE, MA_ACTIVATE);
15895 TEST_MOUSEACTIVATE(HTMINBUTTON, MA_ACTIVATE, MA_ACTIVATE);
15896 TEST_MOUSEACTIVATE(HTMAXBUTTON, MA_ACTIVATE, MA_ACTIVATE);
15897 TEST_MOUSEACTIVATE(HTLEFT, MA_ACTIVATE, MA_ACTIVATE);
15898 TEST_MOUSEACTIVATE(HTRIGHT, MA_ACTIVATE, MA_ACTIVATE);
15899 TEST_MOUSEACTIVATE(HTTOP, MA_ACTIVATE, MA_ACTIVATE);
15900 TEST_MOUSEACTIVATE(HTTOPLEFT, MA_ACTIVATE, MA_ACTIVATE);
15901 TEST_MOUSEACTIVATE(HTTOPRIGHT, MA_ACTIVATE, MA_ACTIVATE);
15902 TEST_MOUSEACTIVATE(HTBOTTOM, MA_ACTIVATE, MA_ACTIVATE);
15903 TEST_MOUSEACTIVATE(HTBOTTOMLEFT, MA_ACTIVATE, MA_ACTIVATE);
15904 TEST_MOUSEACTIVATE(HTBOTTOMRIGHT, MA_ACTIVATE, MA_ACTIVATE);
15905 TEST_MOUSEACTIVATE(HTBORDER, MA_ACTIVATE, MA_ACTIVATE);
15906 TEST_MOUSEACTIVATE(HTOBJECT, MA_ACTIVATE, MA_ACTIVATE);
15907 TEST_MOUSEACTIVATE(HTCLOSE, MA_ACTIVATE, MA_ACTIVATE);
15908 TEST_MOUSEACTIVATE(HTHELP, MA_ACTIVATE, MA_ACTIVATE);
15910 SetEvent( data.wndproc_finished );
15911 WaitForSingleObject( thread, 1000 );
15912 CloseHandle( data.wndproc_finished );
15913 CloseHandle( thread );
15915 SetCursorPos(pos.x, pos.y);
15917 DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0);
15918 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) {
15919 if( msg.message == WM_QUIT) gotwmquit = TRUE;
15920 DispatchMessageA( &msg );
15922 ok(!gotwmquit, "Unexpected WM_QUIT message!\n");
15923 DestroyWindow( hwnd);
15926 static void test_desktop_winproc(void)
15928 HINSTANCE instance = GetModuleHandleA(NULL);
15929 RECT rect, default_rect;
15930 WNDPROC desktop_proc;
15931 char buffer[256];
15932 WNDCLASSA cls;
15933 LRESULT res;
15934 HWND hwnd;
15935 BOOL ret;
15937 ret = GetClassInfoA(instance, (const CHAR *)MAKEINTATOM(32769), &cls);
15938 ok(ret, "Failed to get desktop class.\n");
15939 desktop_proc = cls.lpfnWndProc;
15941 memset(&cls, 0, sizeof(cls));
15942 cls.lpfnWndProc = desktop_proc;
15943 cls.hInstance = instance;
15944 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
15945 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
15946 cls.lpszClassName = "TestDesktopClass";
15947 ret = !!RegisterClassA(&cls);
15948 ok(ret, "Failed to register class.\n");
15950 hwnd = CreateWindowExA(0, cls.lpszClassName, "test_desktop_wndproc",
15951 WS_VISIBLE | WS_CAPTION | WS_OVERLAPPEDWINDOW, 0, 0, 500, 100, 0, 0, 0, NULL);
15952 if (!hwnd) /* win2003 */
15954 skip("Failed to create window with desktop window procedure.\n");
15955 goto out_unregister;
15958 memset(&cls, 0, sizeof(cls));
15959 ret = GetClassInfoA(instance, "TestDesktopClass", &cls);
15960 ok(ret, "Failed to get class info.\n");
15961 ok(cls.lpfnWndProc == desktop_proc, "Got %p, expected %p.\n", cls.lpfnWndProc, desktop_proc);
15963 GetWindowTextA(hwnd, buffer, ARRAY_SIZE(buffer));
15964 todo_wine ok(!strcmp(buffer, "test_desktop_wndproc"), "Got unexpected window text: %s.\n", buffer);
15966 res = CallWindowProcA(desktop_proc, hwnd, WM_SETTEXT, 0, (LPARAM)"test");
15967 ok(res == TRUE, "Failed to set text, %ld.\n", res);
15968 GetWindowTextA(hwnd, buffer, ARRAY_SIZE(buffer));
15969 ok(!strcmp(buffer, "test"), "Got unexpected window text: %s.\n", buffer);
15971 SetRect(&default_rect, 0, 0, 100, 100);
15972 res = DefWindowProcW(hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&default_rect);
15973 ok(!res, "Got unexpected result %ld.\n", res);
15975 SetRect(&rect, 0, 0, 100, 100);
15976 res = CallWindowProcA(desktop_proc, hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rect);
15977 ok(!res, "Got unexpected result %ld.\n", res);
15978 todo_wine ok(EqualRect(&rect, &default_rect), "rect Got %s, expected %s.\n",
15979 wine_dbgstr_rect(&rect), wine_dbgstr_rect(&default_rect));
15981 DestroyWindow(hwnd);
15983 out_unregister:
15984 UnregisterClassA("TestDesktopClass", instance);
15987 #define clear_clipboard(hwnd) clear_clipboard_(__LINE__, (hwnd))
15988 static void clear_clipboard_(int line, HWND hWnd)
15990 BOOL succ;
15991 succ = OpenClipboard(hWnd);
15992 ok_(__FILE__, line)(succ, "OpenClipboard failed, err=%u\n", GetLastError());
15993 succ = EmptyClipboard();
15994 ok_(__FILE__, line)(succ, "EmptyClipboard failed, err=%u\n", GetLastError());
15995 succ = CloseClipboard();
15996 ok_(__FILE__, line)(succ, "CloseClipboard failed, err=%u\n", GetLastError());
15999 #define expect_HWND(expected, got) expect_HWND_(__LINE__, (expected), (got))
16000 static void expect_HWND_(int line, HWND expected, HWND got)
16002 ok_(__FILE__, line)(got==expected, "Expected %p, got %p\n", expected, got);
16005 static WNDPROC pOldViewerProc;
16007 static LRESULT CALLBACK recursive_viewer_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
16009 static BOOL recursion_guard;
16011 if (message == WM_DRAWCLIPBOARD && !recursion_guard)
16013 recursion_guard = TRUE;
16014 clear_clipboard(hWnd);
16015 recursion_guard = FALSE;
16017 return CallWindowProcA(pOldViewerProc, hWnd, message, wParam, lParam);
16020 static void test_clipboard_viewers(void)
16022 static struct message wm_change_cb_chain[] =
16024 { WM_CHANGECBCHAIN, sent|wparam|lparam, 0, 0 },
16025 { 0 }
16027 static const struct message wm_clipboard_destroyed[] =
16029 { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
16030 { 0 }
16032 static struct message wm_clipboard_changed[] =
16034 { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
16035 { 0 }
16037 static struct message wm_clipboard_changed_and_owned[] =
16039 { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
16040 { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
16041 { 0 }
16044 HINSTANCE hInst = GetModuleHandleA(NULL);
16045 HWND hWnd1, hWnd2, hWnd3;
16046 HWND hOrigViewer;
16047 HWND hRet;
16049 hWnd1 = CreateWindowExA(0, "TestWindowClass", "Clipboard viewer test wnd 1",
16050 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
16051 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
16052 GetDesktopWindow(), NULL, hInst, NULL);
16053 hWnd2 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 2",
16054 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
16055 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
16056 GetDesktopWindow(), NULL, hInst, NULL);
16057 hWnd3 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 3",
16058 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
16059 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
16060 GetDesktopWindow(), NULL, hInst, NULL);
16061 trace("clipbd viewers: hWnd1=%p, hWnd2=%p, hWnd3=%p\n", hWnd1, hWnd2, hWnd3);
16062 assert(hWnd1 && hWnd2 && hWnd3);
16064 CountClipboardFormats(); /* Ensure that we do not have an X11 update to the clipboard */
16065 flush_sequence();
16067 /* Test getting the clipboard viewer and setting the viewer to NULL. */
16068 hOrigViewer = GetClipboardViewer();
16069 hRet = SetClipboardViewer(NULL);
16070 ok_sequence(WmEmptySeq, "set viewer to NULL", FALSE);
16071 expect_HWND(hOrigViewer, hRet);
16072 expect_HWND(NULL, GetClipboardViewer());
16074 /* Test registering hWnd1 as a viewer. */
16075 hRet = SetClipboardViewer(hWnd1);
16076 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
16077 ok_sequence(wm_clipboard_changed, "set viewer NULL->1", FALSE);
16078 expect_HWND(NULL, hRet);
16079 expect_HWND(hWnd1, GetClipboardViewer());
16081 /* Test that changing the clipboard actually refreshes the registered viewer. */
16082 clear_clipboard(hWnd1);
16083 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
16084 ok_sequence(wm_clipboard_changed, "clear clipbd (viewer=owner=1)", FALSE);
16086 /* Again, but with different owner. */
16087 clear_clipboard(hWnd2);
16088 wm_clipboard_changed_and_owned[1].wParam = (WPARAM) GetClipboardOwner();
16089 ok_sequence(wm_clipboard_changed_and_owned, "clear clipbd (viewer=1, owner=2)", FALSE);
16091 /* Test re-registering same window. */
16092 hRet = SetClipboardViewer(hWnd1);
16093 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
16094 ok_sequence(wm_clipboard_changed, "set viewer 1->1", FALSE);
16095 expect_HWND(hWnd1, hRet);
16096 expect_HWND(hWnd1, GetClipboardViewer());
16098 /* Test ChangeClipboardChain. */
16099 ChangeClipboardChain(hWnd2, hWnd3);
16100 wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
16101 wm_change_cb_chain[0].lParam = (LPARAM) hWnd3;
16102 ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=3)", FALSE);
16103 expect_HWND(hWnd1, GetClipboardViewer());
16105 ChangeClipboardChain(hWnd2, NULL);
16106 wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
16107 wm_change_cb_chain[0].lParam = 0;
16108 ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=NULL)", FALSE);
16109 expect_HWND(hWnd1, GetClipboardViewer());
16111 ChangeClipboardChain(NULL, hWnd2);
16112 ok_sequence(WmEmptySeq, "change chain (viewer=1, remove=NULL, next=2)", FALSE);
16113 expect_HWND(hWnd1, GetClipboardViewer());
16115 /* Actually change clipboard viewer with ChangeClipboardChain. */
16116 ChangeClipboardChain(hWnd1, hWnd2);
16117 ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=2)", FALSE);
16118 expect_HWND(hWnd2, GetClipboardViewer());
16120 /* Test that no refresh messages are sent when viewer has unregistered. */
16121 clear_clipboard(hWnd2);
16122 ok_sequence(WmEmptySeq, "clear clipd (viewer=2, owner=1)", FALSE);
16124 /* Register hWnd1 again. */
16125 ChangeClipboardChain(hWnd2, hWnd1);
16126 ok_sequence(WmEmptySeq, "change chain (viewer=remove=2, next=1)", FALSE);
16127 expect_HWND(hWnd1, GetClipboardViewer());
16129 /* Subclass hWnd1 so that when it receives a WM_DRAWCLIPBOARD message, it
16130 * changes the clipboard. When this happens, the system shouldn't send
16131 * another WM_DRAWCLIPBOARD (as this could cause an infinite loop).
16133 pOldViewerProc = (WNDPROC) SetWindowLongPtrA(hWnd1, GWLP_WNDPROC, (LONG_PTR) recursive_viewer_proc);
16134 clear_clipboard(hWnd2);
16135 /* The clipboard owner is changed in recursive_viewer_proc: */
16136 wm_clipboard_changed[0].wParam = (WPARAM) hWnd2;
16137 ok_sequence(wm_clipboard_changed, "recursive clear clipbd (viewer=1, owner=2)", TRUE);
16139 /* Test unregistering. */
16140 ChangeClipboardChain(hWnd1, NULL);
16141 ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=NULL)", FALSE);
16142 expect_HWND(NULL, GetClipboardViewer());
16144 clear_clipboard(hWnd1);
16145 ok_sequence(wm_clipboard_destroyed, "clear clipbd (no viewer, owner=1)", FALSE);
16147 DestroyWindow(hWnd1);
16148 DestroyWindow(hWnd2);
16149 DestroyWindow(hWnd3);
16150 SetClipboardViewer(hOrigViewer);
16153 static void test_PostMessage(void)
16155 static const struct
16157 HWND hwnd;
16158 BOOL ret;
16159 } data[] =
16161 { HWND_TOP /* 0 */, TRUE },
16162 { HWND_BROADCAST, TRUE },
16163 { HWND_BOTTOM, TRUE },
16164 { HWND_TOPMOST, TRUE },
16165 { HWND_NOTOPMOST, FALSE },
16166 { HWND_MESSAGE, FALSE },
16167 { (HWND)0xdeadbeef, FALSE }
16169 int i;
16170 HWND hwnd;
16171 BOOL ret;
16172 MSG msg;
16173 static const WCHAR staticW[] = {'s','t','a','t','i','c',0};
16175 SetLastError(0xdeadbeef);
16176 hwnd = CreateWindowExW(0, staticW, NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
16177 if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
16179 win_skip("Skipping some PostMessage tests on Win9x/WinMe\n");
16180 return;
16182 assert(hwnd);
16184 flush_events();
16186 PostMessageA(hwnd, WM_USER+1, 0x1234, 0x5678);
16187 PostMessageA(0, WM_USER+2, 0x5678, 0x1234);
16189 for (i = 0; i < ARRAY_SIZE(data); i++)
16191 memset(&msg, 0xab, sizeof(msg));
16192 ret = PeekMessageA(&msg, data[i].hwnd, 0, 0, PM_NOREMOVE);
16193 ok(ret == data[i].ret, "%d: hwnd %p expected %d, got %d\n", i, data[i].hwnd, data[i].ret, ret);
16194 if (data[i].ret)
16196 if (data[i].hwnd)
16197 ok(ret && msg.hwnd == 0 && msg.message == WM_USER+2 &&
16198 msg.wParam == 0x5678 && msg.lParam == 0x1234,
16199 "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/0/WM_USER+2/0x5678/0x1234\n",
16200 i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam);
16201 else
16202 ok(ret && msg.hwnd == hwnd && msg.message == WM_USER+1 &&
16203 msg.wParam == 0x1234 && msg.lParam == 0x5678,
16204 "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/%p/WM_USER+1/0x1234/0x5678\n",
16205 i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam, msg.hwnd);
16209 DestroyWindow(hwnd);
16210 flush_events();
16213 static WPARAM g_broadcast_wparam;
16214 static LRESULT WINAPI broadcast_test_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
16216 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
16218 if (wParam == 0xbaadbeef)
16219 g_broadcast_wparam = wParam;
16220 else
16221 g_broadcast_wparam = 0;
16223 return CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
16225 static WNDPROC *g_oldproc_sub;
16226 static WPARAM *g_broadcast_sub_wparam;
16227 static LRESULT WINAPI broadcast_test_sub_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
16229 int sub_index = GetWindowLongPtrA(hwnd, GWLP_USERDATA);
16231 g_broadcast_sub_wparam[sub_index] = (wParam == 0xbaadbeef) ? wParam : 0;
16233 return CallWindowProcA(g_oldproc_sub[sub_index], hwnd, message, wParam, lParam);
16236 static void test_broadcast(void)
16238 static const UINT messages[] =
16240 WM_USER-1,
16241 WM_USER,
16242 WM_USER+1,
16243 0xc000-1,
16244 0xc000, /* lowest possible atom returned by RegisterWindowMessage */
16245 0xffff,
16247 static const struct
16249 LONG style;
16250 BOOL receive;
16251 } bcast_expect[] =
16253 {WS_OVERLAPPED, TRUE},
16254 {WS_OVERLAPPED|WS_DLGFRAME, TRUE},
16255 {WS_OVERLAPPED|WS_BORDER, TRUE},
16256 {WS_OVERLAPPED|WS_CAPTION, TRUE},
16257 {WS_CHILD, FALSE},
16258 {WS_CHILD|WS_DLGFRAME, FALSE},
16259 {WS_CHILD|WS_BORDER, FALSE},
16260 {WS_CHILD|WS_CAPTION, FALSE},
16261 {WS_CHILD|WS_POPUP, TRUE},
16262 {WS_POPUP, TRUE},
16263 {WS_POPUP|WS_DLGFRAME, TRUE},
16264 {WS_POPUP|WS_BORDER, TRUE},
16265 {WS_POPUP|WS_CAPTION, TRUE},
16267 WNDPROC oldproc;
16268 unsigned int i, j;
16269 HWND hwnd;
16270 HWND *hwnd_sub;
16272 hwnd_sub = HeapAlloc( GetProcessHeap(), 0, ARRAY_SIZE(bcast_expect) * sizeof(*hwnd_sub) );
16273 g_oldproc_sub = HeapAlloc( GetProcessHeap(), 0, ARRAY_SIZE(bcast_expect) * sizeof(*g_oldproc_sub) );
16274 g_broadcast_sub_wparam = HeapAlloc( GetProcessHeap(), 0, ARRAY_SIZE(bcast_expect) * sizeof(*g_broadcast_sub_wparam) );
16276 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, NULL);
16277 ok(hwnd != NULL, "got %p\n", hwnd);
16279 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)broadcast_test_proc);
16280 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
16282 for (i = 0; i < ARRAY_SIZE(messages); i++)
16284 BOOL ret;
16285 BOOL msg_expected = (messages[i] < WM_USER || messages[i] >= 0xc000);
16286 MSG msg;
16288 flush_events();
16289 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
16292 /* post, broadcast */
16293 ret = PostMessageA(HWND_BROADCAST, messages[i], 0, 0);
16294 ok(ret, "%d: got %d, error %d\n", i, ret, GetLastError());
16296 memset(&msg, 0xab, sizeof(msg));
16297 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
16298 ok(ret == msg_expected, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
16299 if (msg_expected)
16300 ok(msg.hwnd == hwnd, "%d: got %p\n", i, msg.hwnd);
16302 /* post, topmost */
16303 ret = PostMessageA(HWND_TOPMOST, messages[i], 0, 0);
16304 ok(ret, "%d: got %d, error %d\n", i, ret, GetLastError());
16306 memset(&msg, 0xab, sizeof(msg));
16307 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
16308 ok(ret == msg_expected, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
16309 if (msg_expected)
16310 ok(msg.hwnd == hwnd, "%d: got %p\n", i, msg.hwnd);
16313 for (j = 0; j < ARRAY_SIZE(bcast_expect); j++)
16315 hwnd_sub[j] = CreateWindowA("static", NULL, bcast_expect[j].style, 0, 0, 0, 0, hwnd, 0, 0, NULL);
16316 ok(hwnd_sub[j] != NULL, "got %p\n", hwnd_sub[j]);
16317 /* CreateWindow adds extra style flags, so call SetWindowLong to clear some of those. */
16318 SetWindowLongA(hwnd_sub[j], GWL_STYLE, bcast_expect[j].style);
16320 g_oldproc_sub[j] = (WNDPROC)SetWindowLongPtrA(hwnd_sub[j], GWLP_WNDPROC, (LONG_PTR)broadcast_test_sub_proc);
16321 SetWindowLongPtrA(hwnd_sub[j], GWLP_USERDATA, (LONG_PTR)j);
16324 for (i = 0; i < ARRAY_SIZE(messages); i++)
16326 BOOL ret;
16327 BOOL msg_expected = (messages[i] < WM_USER || messages[i] >= 0xc000);
16329 /* send, broadcast */
16330 g_broadcast_wparam = 0xdead;
16331 for (j = 0; j < ARRAY_SIZE(bcast_expect); j++)
16332 g_broadcast_sub_wparam[j] = 0xdead;
16333 ret = SendMessageTimeoutA(HWND_BROADCAST, messages[i], 0xbaadbeef, 0, SMTO_NORMAL, 2000, NULL);
16334 if (!ret && GetLastError() == ERROR_TIMEOUT)
16335 win_skip("broadcasting test %d, timeout\n", i);
16336 else
16338 WPARAM wparam_expected = msg_expected ? 0xbaadbeef : 0xdead;
16339 ok(g_broadcast_wparam == wparam_expected, "%d: message %04x, got %#lx, error %d\n",
16340 i, messages[i], g_broadcast_wparam, GetLastError());
16341 for (j = 0; j < ARRAY_SIZE(bcast_expect); j++)
16343 wparam_expected = (msg_expected && bcast_expect[j].receive) ? 0xbaadbeef : 0xdead;
16344 ok(g_broadcast_sub_wparam[j] == wparam_expected,
16345 "%d,%d: message %04x, got %#lx, error %d\n", i, j, messages[i],
16346 g_broadcast_sub_wparam[j], GetLastError());
16350 /* send, topmost */
16351 g_broadcast_wparam = 0xdead;
16352 for (j = 0; j < ARRAY_SIZE(bcast_expect); j++)
16353 g_broadcast_sub_wparam[j] = 0xdead;
16354 ret = SendMessageTimeoutA(HWND_TOPMOST, messages[i], 0xbaadbeef, 0, SMTO_NORMAL, 2000, NULL);
16355 if (!ret && GetLastError() == ERROR_TIMEOUT)
16356 win_skip("broadcasting test %d, timeout\n", i);
16357 else
16359 WPARAM wparam_expected = msg_expected ? 0xbaadbeef : 0xdead;
16360 ok(g_broadcast_wparam == wparam_expected, "%d: message %04x, got %#lx, error %d\n",
16361 i, messages[i], g_broadcast_wparam, GetLastError());
16362 for (j = 0; j < ARRAY_SIZE(bcast_expect); j++)
16364 wparam_expected = (msg_expected && bcast_expect[j].receive) ? 0xbaadbeef : 0xdead;
16365 ok(g_broadcast_sub_wparam[j] == wparam_expected,
16366 "%d,%d: message %04x, got %#lx, error %d\n", i, j, messages[i],
16367 g_broadcast_sub_wparam[j], GetLastError());
16372 for (j = 0; j < ARRAY_SIZE(bcast_expect); j++)
16373 DestroyWindow(hwnd_sub[j]);
16375 HeapFree(GetProcessHeap(), 0, g_broadcast_sub_wparam);
16376 HeapFree(GetProcessHeap(), 0, g_oldproc_sub);
16377 HeapFree(GetProcessHeap(), 0, hwnd_sub);
16379 DestroyWindow(hwnd);
16382 static const struct
16384 DWORD exp, broken;
16385 BOOL todo;
16386 } wait_idle_expect[] =
16388 /* 0 */ { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
16389 { WAIT_TIMEOUT, 0, FALSE },
16390 { WAIT_TIMEOUT, 0, FALSE },
16391 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
16392 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
16393 /* 5 */ { WAIT_TIMEOUT, 0, FALSE },
16394 { WAIT_TIMEOUT, 0, FALSE },
16395 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
16396 { 0, 0, FALSE },
16397 { 0, 0, FALSE },
16398 /* 10 */ { 0, 0, FALSE },
16399 { 0, 0, FALSE },
16400 { 0, WAIT_TIMEOUT, FALSE },
16401 { 0, 0, FALSE },
16402 { 0, 0, FALSE },
16403 /* 15 */ { 0, 0, FALSE },
16404 { WAIT_TIMEOUT, 0, FALSE },
16405 { WAIT_TIMEOUT, 0, FALSE },
16406 { WAIT_TIMEOUT, 0, FALSE },
16407 { WAIT_TIMEOUT, 0, FALSE },
16408 /* 20 */ { WAIT_TIMEOUT, 0, FALSE },
16411 static DWORD CALLBACK do_wait_idle_child_thread( void *arg )
16413 MSG msg;
16415 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
16416 Sleep( 200 );
16417 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
16418 return 0;
16421 static void do_wait_idle_child( int arg )
16423 WNDCLASSA cls;
16424 MSG msg;
16425 HWND hwnd = 0;
16426 HANDLE thread;
16427 DWORD id;
16428 HANDLE start_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_start" );
16429 HANDLE end_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_end" );
16431 memset( &cls, 0, sizeof(cls) );
16432 cls.lpfnWndProc = DefWindowProcA;
16433 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
16434 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
16435 cls.lpszClassName = "TestClass";
16436 RegisterClassA( &cls );
16438 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ); /* create the msg queue */
16440 ok( start_event != 0, "failed to create start event, error %u\n", GetLastError() );
16441 ok( end_event != 0, "failed to create end event, error %u\n", GetLastError() );
16443 switch (arg)
16445 case 0:
16446 SetEvent( start_event );
16447 break;
16448 case 1:
16449 SetEvent( start_event );
16450 Sleep( 200 );
16451 PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
16452 break;
16453 case 2:
16454 SetEvent( start_event );
16455 Sleep( 200 );
16456 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
16457 PostThreadMessageA( GetCurrentThreadId(), WM_COMMAND, 0x1234, 0xabcd );
16458 PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
16459 break;
16460 case 3:
16461 SetEvent( start_event );
16462 Sleep( 200 );
16463 SendMessageA( HWND_BROADCAST, WM_WININICHANGE, 0, 0 );
16464 break;
16465 case 4:
16466 SetEvent( start_event );
16467 Sleep( 200 );
16468 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
16469 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
16470 break;
16471 case 5:
16472 SetEvent( start_event );
16473 Sleep( 200 );
16474 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
16475 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
16476 break;
16477 case 6:
16478 SetEvent( start_event );
16479 Sleep( 200 );
16480 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
16481 while (PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ))
16483 GetMessageA( &msg, 0, 0, 0 );
16484 DispatchMessageA( &msg );
16486 break;
16487 case 7:
16488 SetEvent( start_event );
16489 Sleep( 200 );
16490 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
16491 SetTimer( hwnd, 3, 1, NULL );
16492 Sleep( 200 );
16493 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
16494 break;
16495 case 8:
16496 SetEvent( start_event );
16497 Sleep( 200 );
16498 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
16499 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
16500 break;
16501 case 9:
16502 SetEvent( start_event );
16503 Sleep( 200 );
16504 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
16505 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
16506 for (;;) GetMessageA( &msg, 0, 0, 0 );
16507 break;
16508 case 10:
16509 SetEvent( start_event );
16510 Sleep( 200 );
16511 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
16512 SetTimer( hwnd, 3, 1, NULL );
16513 Sleep( 200 );
16514 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
16515 break;
16516 case 11:
16517 SetEvent( start_event );
16518 Sleep( 200 );
16519 return; /* exiting the process makes WaitForInputIdle return success too */
16520 case 12:
16521 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
16522 Sleep( 200 );
16523 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
16524 SetEvent( start_event );
16525 break;
16526 case 13:
16527 SetEvent( start_event );
16528 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
16529 Sleep( 200 );
16530 thread = CreateThread( NULL, 0, do_wait_idle_child_thread, NULL, 0, &id );
16531 WaitForSingleObject( thread, 10000 );
16532 CloseHandle( thread );
16533 break;
16534 case 14:
16535 SetEvent( start_event );
16536 Sleep( 200 );
16537 PeekMessageA( &msg, HWND_TOPMOST, 0, 0, PM_NOREMOVE );
16538 break;
16539 case 15:
16540 SetEvent( start_event );
16541 Sleep( 200 );
16542 PeekMessageA( &msg, HWND_BROADCAST, 0, 0, PM_NOREMOVE );
16543 break;
16544 case 16:
16545 SetEvent( start_event );
16546 Sleep( 200 );
16547 PeekMessageA( &msg, HWND_BOTTOM, 0, 0, PM_NOREMOVE );
16548 break;
16549 case 17:
16550 SetEvent( start_event );
16551 Sleep( 200 );
16552 PeekMessageA( &msg, (HWND)0xdeadbeef, 0, 0, PM_NOREMOVE );
16553 break;
16554 case 18:
16555 SetEvent( start_event );
16556 Sleep( 200 );
16557 PeekMessageA( &msg, HWND_NOTOPMOST, 0, 0, PM_NOREMOVE );
16558 break;
16559 case 19:
16560 SetEvent( start_event );
16561 Sleep( 200 );
16562 PeekMessageA( &msg, HWND_MESSAGE, 0, 0, PM_NOREMOVE );
16563 break;
16564 case 20:
16565 SetEvent( start_event );
16566 Sleep( 200 );
16567 PeekMessageA( &msg, GetDesktopWindow(), 0, 0, PM_NOREMOVE );
16568 break;
16570 WaitForSingleObject( end_event, 2000 );
16571 CloseHandle( start_event );
16572 CloseHandle( end_event );
16573 if (hwnd) DestroyWindow( hwnd );
16576 static LRESULT CALLBACK wait_idle_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
16578 if (msg == WM_WININICHANGE) Sleep( 200 ); /* make sure the child waits */
16579 return DefWindowProcA( hwnd, msg, wp, lp );
16582 static DWORD CALLBACK wait_idle_thread( void *arg )
16584 WNDCLASSA cls;
16585 MSG msg;
16586 HWND hwnd;
16588 memset( &cls, 0, sizeof(cls) );
16589 cls.lpfnWndProc = wait_idle_proc;
16590 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
16591 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
16592 cls.lpszClassName = "TestClass";
16593 RegisterClassA( &cls );
16595 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL);
16596 while (GetMessageA( &msg, 0, 0, 0 )) DispatchMessageA( &msg );
16597 DestroyWindow(hwnd);
16598 return 0;
16601 static void test_WaitForInputIdle( char *argv0 )
16603 char path[MAX_PATH];
16604 PROCESS_INFORMATION pi;
16605 STARTUPINFOA startup;
16606 BOOL ret;
16607 HANDLE start_event, end_event, thread;
16608 unsigned int i;
16609 DWORD id;
16610 const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)GetModuleHandleA(0);
16611 const IMAGE_NT_HEADERS *nt = (const IMAGE_NT_HEADERS *)((const char *)dos + dos->e_lfanew);
16612 BOOL console_app = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI);
16614 if (console_app) /* build the test with -mwindows for better coverage */
16615 trace( "not built as a GUI app, WaitForInputIdle may not be fully tested\n" );
16617 start_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_start");
16618 end_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_end");
16619 ok(start_event != 0, "failed to create start event, error %u\n", GetLastError());
16620 ok(end_event != 0, "failed to create end event, error %u\n", GetLastError());
16622 memset( &startup, 0, sizeof(startup) );
16623 startup.cb = sizeof(startup);
16624 startup.dwFlags = STARTF_USESHOWWINDOW;
16625 startup.wShowWindow = SW_SHOWNORMAL;
16627 thread = CreateThread( NULL, 0, wait_idle_thread, NULL, 0, &id );
16629 for (i = 0; i < ARRAY_SIZE(wait_idle_expect); i++)
16631 ResetEvent( start_event );
16632 ResetEvent( end_event );
16633 sprintf( path, "%s msg %u", argv0, i );
16634 ret = CreateProcessA( NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &pi );
16635 ok( ret, "CreateProcess '%s' failed err %u.\n", path, GetLastError() );
16636 if (ret)
16638 ret = WaitForSingleObject( start_event, 5000 );
16639 ok( ret == WAIT_OBJECT_0, "%u: WaitForSingleObject failed\n", i );
16640 if (ret == WAIT_OBJECT_0)
16642 ret = WaitForInputIdle( pi.hProcess, 1000 );
16643 if (ret == WAIT_FAILED)
16644 ok( console_app ||
16645 ret == wait_idle_expect[i].exp ||
16646 broken(ret == wait_idle_expect[i].broken),
16647 "%u: WaitForInputIdle error %08x expected %08x\n",
16648 i, ret, wait_idle_expect[i].exp );
16649 else todo_wine_if (wait_idle_expect[i].todo)
16650 ok( ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken),
16651 "%u: WaitForInputIdle error %08x expected %08x\n",
16652 i, ret, wait_idle_expect[i].exp );
16653 SetEvent( end_event );
16654 WaitForSingleObject( pi.hProcess, 1000 ); /* give it a chance to exit on its own */
16656 TerminateProcess( pi.hProcess, 0 ); /* just in case */
16657 wait_child_process( pi.hProcess );
16658 ret = WaitForInputIdle( pi.hProcess, 100 );
16659 ok( ret == WAIT_FAILED, "%u: WaitForInputIdle after exit error %08x\n", i, ret );
16660 CloseHandle( pi.hProcess );
16661 CloseHandle( pi.hThread );
16664 CloseHandle( end_event );
16665 CloseHandle( start_event );
16666 PostThreadMessageA( id, WM_QUIT, 0, 0 );
16667 WaitForSingleObject( thread, 10000 );
16668 CloseHandle( thread );
16671 static const struct message WmSetParentSeq_1[] = {
16672 { WM_SHOWWINDOW, sent|wparam, 0 },
16673 { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
16674 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
16675 { WM_CHILDACTIVATE, sent },
16676 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE },
16677 { WM_MOVE, sent|defwinproc|wparam, 0 },
16678 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
16679 { WM_SHOWWINDOW, sent|wparam, 1 },
16680 { 0 }
16683 static const struct message WmSetParentSeq_2[] = {
16684 { WM_SHOWWINDOW, sent|wparam, 0 },
16685 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
16686 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
16687 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
16688 { HCBT_SETFOCUS, hook|optional },
16689 { WM_NCACTIVATE, sent|wparam|optional, 0 },
16690 { WM_ACTIVATE, sent|wparam|optional, 0 },
16691 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
16692 { WM_KILLFOCUS, sent|wparam, 0 },
16693 { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
16694 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
16695 { HCBT_ACTIVATE, hook|optional },
16696 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
16697 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
16698 { WM_NCACTIVATE, sent|wparam|optional, 1 },
16699 { WM_ACTIVATE, sent|wparam|optional, 1 },
16700 { HCBT_SETFOCUS, hook|optional },
16701 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
16702 { WM_SETFOCUS, sent|optional|defwinproc },
16703 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOCLIENTSIZE },
16704 { WM_MOVE, sent|defwinproc|wparam, 0 },
16705 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
16706 { WM_SHOWWINDOW, sent|wparam, 1 },
16707 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
16708 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
16709 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
16710 { 0 }
16714 static void test_SetParent(void)
16716 HWND parent1, parent2, child, popup;
16717 RECT rc, rc_old;
16719 parent1 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
16720 100, 100, 200, 200, 0, 0, 0, NULL);
16721 ok(parent1 != 0, "Failed to create parent1 window\n");
16723 parent2 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
16724 400, 100, 200, 200, 0, 0, 0, NULL);
16725 ok(parent2 != 0, "Failed to create parent2 window\n");
16727 /* WS_CHILD window */
16728 child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD | WS_VISIBLE,
16729 10, 10, 150, 150, parent1, 0, 0, NULL);
16730 ok(child != 0, "Failed to create child window\n");
16732 GetWindowRect(parent1, &rc);
16733 trace("parent1 %s\n", wine_dbgstr_rect(&rc));
16734 GetWindowRect(child, &rc_old);
16735 MapWindowPoints(0, parent1, (POINT *)&rc_old, 2);
16736 trace("child %s\n", wine_dbgstr_rect(&rc_old));
16738 flush_sequence();
16740 SetParent(child, parent2);
16741 flush_events();
16742 ok_sequence(WmSetParentSeq_1, "SetParent() visible WS_CHILD", FALSE);
16744 ok(GetWindowLongA(child, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
16745 ok(!IsWindowVisible(child), "IsWindowVisible() should return FALSE\n");
16747 GetWindowRect(parent2, &rc);
16748 trace("parent2 %s\n", wine_dbgstr_rect(&rc));
16749 GetWindowRect(child, &rc);
16750 MapWindowPoints(0, parent2, (POINT *)&rc, 2);
16751 trace("child %s\n", wine_dbgstr_rect(&rc));
16753 ok(EqualRect(&rc_old, &rc), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc_old),
16754 wine_dbgstr_rect(&rc));
16756 /* WS_POPUP window */
16757 popup = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP | WS_VISIBLE,
16758 20, 20, 100, 100, 0, 0, 0, NULL);
16759 ok(popup != 0, "Failed to create popup window\n");
16761 GetWindowRect(popup, &rc_old);
16762 trace("popup %s\n", wine_dbgstr_rect(&rc_old));
16764 flush_sequence();
16766 SetParent(popup, child);
16767 flush_events();
16768 ok_sequence(WmSetParentSeq_2, "SetParent() visible WS_POPUP", TRUE);
16770 ok(GetWindowLongA(popup, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
16771 ok(!IsWindowVisible(popup), "IsWindowVisible() should return FALSE\n");
16773 GetWindowRect(child, &rc);
16774 trace("parent2 %s\n", wine_dbgstr_rect(&rc));
16775 GetWindowRect(popup, &rc);
16776 MapWindowPoints(0, child, (POINT *)&rc, 2);
16777 trace("popup %s\n", wine_dbgstr_rect(&rc));
16779 ok(EqualRect(&rc_old, &rc), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc_old),
16780 wine_dbgstr_rect(&rc));
16782 DestroyWindow(popup);
16783 DestroyWindow(child);
16784 DestroyWindow(parent1);
16785 DestroyWindow(parent2);
16787 flush_sequence();
16790 static const struct message WmKeyReleaseOnly[] = {
16791 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x80000001 },
16792 { WM_KEYUP, sent|wparam|lparam, 0x41, 0x80000001 },
16793 { 0 }
16795 static const struct message WmKeyPressNormal[] = {
16796 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x1 },
16797 { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x1 },
16798 { 0 }
16800 static const struct message WmKeyPressRepeat[] = {
16801 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x40000001 },
16802 { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x40000001 },
16803 { 0 }
16805 static const struct message WmKeyReleaseNormal[] = {
16806 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0xc0000001 },
16807 { WM_KEYUP, sent|wparam|lparam, 0x41, 0xc0000001 },
16808 { 0 }
16811 static void test_keyflags(void)
16813 HWND test_window;
16814 SHORT key_state;
16815 BYTE keyboard_state[256];
16816 MSG msg;
16818 test_window = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
16819 100, 100, 200, 200, 0, 0, 0, NULL);
16821 flush_events();
16822 flush_sequence();
16824 /* keyup without a keydown */
16825 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
16826 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16827 DispatchMessageA(&msg);
16828 ok_sequence(WmKeyReleaseOnly, "key release only", TRUE);
16830 key_state = GetAsyncKeyState(0x41);
16831 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16833 key_state = GetKeyState(0x41);
16834 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16836 /* keydown */
16837 keybd_event(0x41, 0, 0, 0);
16838 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16839 DispatchMessageA(&msg);
16840 ok_sequence(WmKeyPressNormal, "key press only", FALSE);
16842 key_state = GetAsyncKeyState(0x41);
16843 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16845 key_state = GetKeyState(0x41);
16846 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16848 /* keydown repeat */
16849 keybd_event(0x41, 0, 0, 0);
16850 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16851 DispatchMessageA(&msg);
16852 ok_sequence(WmKeyPressRepeat, "key press repeat", FALSE);
16854 key_state = GetAsyncKeyState(0x41);
16855 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16857 key_state = GetKeyState(0x41);
16858 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16860 /* keyup */
16861 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
16862 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16863 DispatchMessageA(&msg);
16864 ok_sequence(WmKeyReleaseNormal, "key release repeat", FALSE);
16866 key_state = GetAsyncKeyState(0x41);
16867 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16869 key_state = GetKeyState(0x41);
16870 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16872 /* set the key state in this thread */
16873 GetKeyboardState(keyboard_state);
16874 keyboard_state[0x41] = 0x80;
16875 SetKeyboardState(keyboard_state);
16877 key_state = GetAsyncKeyState(0x41);
16878 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16880 /* keydown */
16881 keybd_event(0x41, 0, 0, 0);
16882 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16883 DispatchMessageA(&msg);
16884 ok_sequence(WmKeyPressRepeat, "key press after setkeyboardstate", TRUE);
16886 key_state = GetAsyncKeyState(0x41);
16887 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16889 key_state = GetKeyState(0x41);
16890 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16892 /* clear the key state in this thread */
16893 GetKeyboardState(keyboard_state);
16894 keyboard_state[0x41] = 0;
16895 SetKeyboardState(keyboard_state);
16897 key_state = GetAsyncKeyState(0x41);
16898 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16900 /* keyup */
16901 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
16902 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16903 DispatchMessageA(&msg);
16904 ok_sequence(WmKeyReleaseOnly, "key release after setkeyboardstate", TRUE);
16906 key_state = GetAsyncKeyState(0x41);
16907 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16909 key_state = GetKeyState(0x41);
16910 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16912 DestroyWindow(test_window);
16913 flush_sequence();
16916 static const struct message WmHotkeyPressLWIN[] = {
16917 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
16918 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
16919 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
16920 { 0 }
16922 static const struct message WmHotkeyPress[] = {
16923 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16924 { WM_HOTKEY, sent|wparam, 5 },
16925 { 0 }
16927 static const struct message WmHotkeyRelease[] = {
16928 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16929 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 0x80000001 },
16930 { WM_KEYUP, sent|lparam, 0, 0x80000001 },
16931 { 0 }
16933 static const struct message WmHotkeyReleaseLWIN[] = {
16934 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
16935 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
16936 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
16937 { 0 }
16939 static const struct message WmHotkeyCombined[] = {
16940 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
16941 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16942 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16943 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
16944 { WM_APP, sent, 0, 0 },
16945 { WM_HOTKEY, sent|wparam, 5 },
16946 { WM_APP+1, sent, 0, 0 },
16947 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
16948 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
16949 { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
16950 { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
16951 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
16952 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
16953 { 0 }
16955 static const struct message WmHotkeyPrevious[] = {
16956 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
16957 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16958 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16959 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
16960 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
16961 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
16962 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 1 },
16963 { WM_KEYDOWN, sent|lparam, 0, 1 },
16964 { HCBT_KEYSKIPPED, hook|optional|lparam, 0, 0xc0000001 },
16965 { WM_KEYUP, sent|lparam, 0, 0xc0000001 },
16966 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
16967 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
16968 { 0 }
16970 static const struct message WmHotkeyNew[] = {
16971 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16972 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16973 { WM_HOTKEY, sent|wparam, 5 },
16974 { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
16975 { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
16976 { 0 }
16979 static int hotkey_letter;
16981 static LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
16983 struct recvd_message msg;
16985 if (nCode == HC_ACTION)
16987 KBDLLHOOKSTRUCT *kdbhookstruct = (KBDLLHOOKSTRUCT*)lParam;
16989 msg.hwnd = 0;
16990 msg.message = wParam;
16991 msg.flags = kbd_hook|wparam|lparam;
16992 msg.wParam = kdbhookstruct->vkCode;
16993 msg.lParam = kdbhookstruct->flags;
16994 msg.descr = "KeyboardHookProc";
16995 add_message(&msg);
16997 if (wParam == WM_KEYUP || wParam == WM_KEYDOWN)
16999 ok(kdbhookstruct->vkCode == VK_LWIN || kdbhookstruct->vkCode == hotkey_letter,
17000 "unexpected keycode %x\n", kdbhookstruct->vkCode);
17004 return CallNextHookEx(hKBD_hook, nCode, wParam, lParam);
17007 static void test_hotkey(void)
17009 HWND test_window, taskbar_window;
17010 BOOL ret;
17011 MSG msg;
17012 DWORD queue_status;
17013 SHORT key_state;
17015 SetLastError(0xdeadbeef);
17016 ret = UnregisterHotKey(NULL, 0);
17017 if (ret == TRUE)
17019 skip("hotkeys not supported\n");
17020 return;
17023 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
17024 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
17025 "unexpected error %d\n", GetLastError());
17027 test_window = CreateWindowExA(0, "HotkeyWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
17028 100, 100, 200, 200, 0, 0, 0, NULL);
17030 flush_sequence();
17032 SetLastError(0xdeadbeef);
17033 ret = UnregisterHotKey(test_window, 0);
17034 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
17035 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
17036 "unexpected error %d\n", GetLastError());
17038 /* Search for a Windows Key + letter combination that hasn't been registered */
17039 for (hotkey_letter = 0x41; hotkey_letter <= 0x51; hotkey_letter ++)
17041 SetLastError(0xdeadbeef);
17042 ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
17044 if (ret == TRUE)
17046 break;
17048 else
17050 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
17051 "unexpected error %d\n", GetLastError());
17055 if (hotkey_letter == 0x52)
17057 ok(0, "Couldn't find any free Windows Key + letter combination\n");
17058 goto end;
17061 hKBD_hook = SetWindowsHookExA(WH_KEYBOARD_LL, KeyboardHookProc, GetModuleHandleA(NULL), 0);
17062 if (!hKBD_hook) win_skip("WH_KEYBOARD_LL is not supported\n");
17064 /* Same key combination, different id */
17065 SetLastError(0xdeadbeef);
17066 ret = RegisterHotKey(test_window, 4, MOD_WIN, hotkey_letter);
17067 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
17068 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
17069 "unexpected error %d\n", GetLastError());
17071 /* Same key combination, different window */
17072 SetLastError(0xdeadbeef);
17073 ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
17074 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
17075 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
17076 "unexpected error %d\n", GetLastError());
17078 /* Register the same hotkey twice */
17079 SetLastError(0xdeadbeef);
17080 ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
17081 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
17082 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
17083 "unexpected error %d\n", GetLastError());
17085 /* Window on another thread */
17086 taskbar_window = FindWindowA("Shell_TrayWnd", NULL);
17087 if (!taskbar_window)
17089 skip("no taskbar?\n");
17091 else
17093 SetLastError(0xdeadbeef);
17094 ret = RegisterHotKey(taskbar_window, 5, 0, hotkey_letter);
17095 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
17096 ok(GetLastError() == ERROR_WINDOW_OF_OTHER_THREAD || broken(GetLastError() == 0xdeadbeef),
17097 "unexpected error %d\n", GetLastError());
17100 /* Inject the appropriate key sequence */
17101 keybd_event(VK_LWIN, 0, 0, 0);
17102 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
17103 DispatchMessageA(&msg);
17104 ok_sequence(WmHotkeyPressLWIN, "window hotkey press LWIN", FALSE);
17106 keybd_event(hotkey_letter, 0, 0, 0);
17107 queue_status = GetQueueStatus(QS_HOTKEY);
17108 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
17109 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
17111 if (msg.message == WM_HOTKEY)
17113 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
17114 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
17116 DispatchMessageA(&msg);
17118 ok_sequence(WmHotkeyPress, "window hotkey press", FALSE);
17120 queue_status = GetQueueStatus(QS_HOTKEY);
17121 ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
17123 key_state = GetAsyncKeyState(hotkey_letter);
17124 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
17126 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
17127 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
17128 DispatchMessageA(&msg);
17129 ok_sequence(WmHotkeyRelease, "window hotkey release", TRUE);
17131 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
17132 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
17133 DispatchMessageA(&msg);
17134 ok_sequence(WmHotkeyReleaseLWIN, "window hotkey release LWIN", FALSE);
17136 /* normal posted WM_HOTKEY messages set QS_HOTKEY */
17137 PostMessageA(test_window, WM_HOTKEY, 0, 0);
17138 queue_status = GetQueueStatus(QS_HOTKEY);
17139 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
17140 queue_status = GetQueueStatus(QS_POSTMESSAGE);
17141 ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
17142 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
17143 DispatchMessageA(&msg);
17144 flush_sequence();
17146 /* Send and process all messages at once */
17147 PostMessageA(test_window, WM_APP, 0, 0);
17148 keybd_event(VK_LWIN, 0, 0, 0);
17149 keybd_event(hotkey_letter, 0, 0, 0);
17150 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
17151 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
17153 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
17155 if (msg.message == WM_HOTKEY)
17157 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
17158 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
17160 DispatchMessageA(&msg);
17162 ok_sequence(WmHotkeyCombined, "window hotkey combined", FALSE);
17164 /* Register same hwnd/id with different key combination */
17165 ret = RegisterHotKey(test_window, 5, 0, hotkey_letter);
17166 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
17168 /* Previous key combination does not work */
17169 keybd_event(VK_LWIN, 0, 0, 0);
17170 keybd_event(hotkey_letter, 0, 0, 0);
17171 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
17172 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
17174 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
17175 DispatchMessageA(&msg);
17176 ok_sequence(WmHotkeyPrevious, "window hotkey previous", FALSE);
17178 /* New key combination works */
17179 keybd_event(hotkey_letter, 0, 0, 0);
17180 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
17182 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
17184 if (msg.message == WM_HOTKEY)
17186 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
17187 ok(msg.lParam == MAKELPARAM(0, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
17189 DispatchMessageA(&msg);
17191 ok_sequence(WmHotkeyNew, "window hotkey new", FALSE);
17193 /* Unregister hotkey properly */
17194 ret = UnregisterHotKey(test_window, 5);
17195 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
17197 /* Unregister hotkey again */
17198 SetLastError(0xdeadbeef);
17199 ret = UnregisterHotKey(test_window, 5);
17200 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
17201 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
17202 "unexpected error %d\n", GetLastError());
17204 /* Register thread hotkey */
17205 ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
17206 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
17208 /* Inject the appropriate key sequence */
17209 keybd_event(VK_LWIN, 0, 0, 0);
17210 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
17212 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
17213 DispatchMessageA(&msg);
17215 ok_sequence(WmHotkeyPressLWIN, "thread hotkey press LWIN", FALSE);
17217 keybd_event(hotkey_letter, 0, 0, 0);
17218 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
17220 if (msg.message == WM_HOTKEY)
17222 struct recvd_message message;
17223 ok(msg.hwnd == NULL, "unexpected hwnd %p\n", msg.hwnd);
17224 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
17225 message.message = msg.message;
17226 message.flags = sent|wparam|lparam;
17227 message.wParam = msg.wParam;
17228 message.lParam = msg.lParam;
17229 message.descr = "test_hotkey thread message";
17230 add_message(&message);
17232 else
17233 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
17234 DispatchMessageA(&msg);
17236 ok_sequence(WmHotkeyPress, "thread hotkey press", FALSE);
17238 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
17239 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
17241 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
17242 DispatchMessageA(&msg);
17244 ok_sequence(WmHotkeyRelease, "thread hotkey release", TRUE);
17246 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
17247 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
17249 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
17250 DispatchMessageA(&msg);
17252 ok_sequence(WmHotkeyReleaseLWIN, "thread hotkey release LWIN", FALSE);
17254 /* Unregister thread hotkey */
17255 ret = UnregisterHotKey(NULL, 5);
17256 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
17258 if (hKBD_hook) UnhookWindowsHookEx(hKBD_hook);
17259 hKBD_hook = NULL;
17261 end:
17262 UnregisterHotKey(NULL, 5);
17263 UnregisterHotKey(test_window, 5);
17264 DestroyWindow(test_window);
17265 flush_sequence();
17269 static const struct message WmSetFocus_1[] = {
17270 { HCBT_SETFOCUS, hook }, /* child */
17271 { HCBT_ACTIVATE, hook }, /* parent */
17272 { WM_QUERYNEWPALETTE, sent|wparam|lparam|parent|optional, 0, 0 },
17273 { WM_WINDOWPOSCHANGING, sent|parent, 0, SWP_NOSIZE|SWP_NOMOVE },
17274 { WM_ACTIVATEAPP, sent|wparam|parent, 1 },
17275 { WM_NCACTIVATE, sent|parent },
17276 { WM_GETTEXT, sent|defwinproc|parent|optional },
17277 { WM_GETTEXT, sent|defwinproc|parent|optional },
17278 { WM_ACTIVATE, sent|wparam|parent, 1 },
17279 { HCBT_SETFOCUS, hook }, /* parent */
17280 { WM_SETFOCUS, sent|defwinproc|parent },
17281 { WM_KILLFOCUS, sent|parent },
17282 { WM_SETFOCUS, sent },
17283 { 0 }
17285 static const struct message WmSetFocus_2[] = {
17286 { HCBT_SETFOCUS, hook }, /* parent */
17287 { WM_KILLFOCUS, sent },
17288 { WM_SETFOCUS, sent|parent },
17289 { 0 }
17291 static const struct message WmSetFocus_3[] = {
17292 { HCBT_SETFOCUS, hook }, /* child */
17293 { 0 }
17296 static void test_SetFocus(void)
17298 HWND parent, old_parent, child, old_focus, old_active;
17299 MSG msg;
17300 struct wnd_event wnd_event;
17301 HANDLE hthread;
17302 DWORD ret, tid;
17304 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
17305 ok(wnd_event.start_event != 0, "CreateEvent error %d\n", GetLastError());
17306 hthread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
17307 ok(hthread != 0, "CreateThread error %d\n", GetLastError());
17308 ret = WaitForSingleObject(wnd_event.start_event, INFINITE);
17309 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
17310 CloseHandle(wnd_event.start_event);
17312 parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
17313 0, 0, 0, 0, 0, 0, 0, NULL);
17314 ok(parent != 0, "failed to create parent window\n");
17315 child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
17316 0, 0, 0, 0, parent, 0, 0, NULL);
17317 ok(child != 0, "failed to create child window\n");
17319 trace("parent %p, child %p, thread window %p\n", parent, child, wnd_event.hwnd);
17321 SetFocus(0);
17322 SetActiveWindow(0);
17324 flush_events();
17325 flush_sequence();
17327 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
17328 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
17330 log_all_parent_messages++;
17332 old_focus = SetFocus(child);
17333 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17334 ok_sequence(WmSetFocus_1, "SetFocus on a child window", TRUE);
17335 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
17336 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17337 ok(GetFocus() == child, "expected focus %p, got %p\n", child, GetFocus());
17339 old_focus = SetFocus(parent);
17340 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17341 ok_sequence(WmSetFocus_2, "SetFocus on a parent window", FALSE);
17342 ok(old_focus == child, "expected old focus %p, got %p\n", child, old_focus);
17343 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17344 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17346 SetLastError(0xdeadbeef);
17347 old_focus = SetFocus((HWND)0xdeadbeef);
17348 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
17349 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
17350 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17351 ok_sequence(WmEmptySeq, "SetFocus on an invalid window", FALSE);
17352 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
17353 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17354 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17356 SetLastError(0xdeadbeef);
17357 old_focus = SetFocus(GetDesktopWindow());
17358 ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
17359 broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
17360 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17361 ok_sequence(WmEmptySeq, "SetFocus on a desktop window", TRUE);
17362 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
17363 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17364 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17366 SetLastError(0xdeadbeef);
17367 old_focus = SetFocus(wnd_event.hwnd);
17368 ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
17369 broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
17370 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17371 ok_sequence(WmEmptySeq, "SetFocus on another thread window", TRUE);
17372 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
17373 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17374 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17376 SetLastError(0xdeadbeef);
17377 old_active = SetActiveWindow((HWND)0xdeadbeef);
17378 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
17379 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
17380 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17381 ok_sequence(WmEmptySeq, "SetActiveWindow on an invalid window", FALSE);
17382 ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
17383 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17384 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17386 SetLastError(0xdeadbeef);
17387 old_active = SetActiveWindow(GetDesktopWindow());
17388 todo_wine
17389 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
17390 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17391 ok_sequence(WmEmptySeq, "SetActiveWindow on a desktop window", TRUE);
17392 ok(old_active == 0, "expected old focus 0, got %p\n", old_focus);
17393 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17394 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17396 SetLastError(0xdeadbeef);
17397 old_active = SetActiveWindow(wnd_event.hwnd);
17398 todo_wine
17399 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
17400 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17401 ok_sequence(WmEmptySeq, "SetActiveWindow on another thread window", TRUE);
17402 ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
17403 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17404 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17406 SetLastError(0xdeadbeef);
17407 ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE);
17408 ok(ret, "AttachThreadInput error %d\n", GetLastError());
17410 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17411 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17413 flush_events();
17414 flush_sequence();
17416 old_focus = SetFocus(wnd_event.hwnd);
17417 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17418 ok(old_focus == wnd_event.hwnd, "expected old focus %p, got %p\n", wnd_event.hwnd, old_focus);
17419 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
17420 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
17422 old_focus = SetFocus(parent);
17423 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17424 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
17425 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17426 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17428 flush_events();
17429 flush_sequence();
17431 old_active = SetActiveWindow(wnd_event.hwnd);
17432 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17433 ok(old_active == parent, "expected old focus %p, got %p\n", parent, old_active);
17434 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
17435 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
17437 SetLastError(0xdeadbeef);
17438 ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE);
17439 ok(ret, "AttachThreadInput error %d\n", GetLastError());
17441 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
17442 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
17444 old_parent = SetParent(child, GetDesktopWindow());
17445 ok(old_parent == parent, "expected old parent %p, got %p\n", parent, old_parent);
17447 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
17448 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
17450 old_focus = SetFocus(parent);
17451 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17452 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
17453 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17454 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17456 flush_events();
17457 flush_sequence();
17459 SetLastError(0xdeadbeef);
17460 old_focus = SetFocus(child);
17461 todo_wine
17462 ok(GetLastError() == ERROR_INVALID_PARAMETER /* Vista+ */ ||
17463 broken(GetLastError() == 0) /* XP */ ||
17464 broken(GetLastError() == 0xdeadbeef), "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
17465 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17466 ok_sequence(WmSetFocus_3, "SetFocus on a child window", TRUE);
17467 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
17468 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17469 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17471 SetLastError(0xdeadbeef);
17472 old_active = SetActiveWindow(child);
17473 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
17474 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
17475 ok_sequence(WmEmptySeq, "SetActiveWindow on a child window", FALSE);
17476 ok(old_active == parent, "expected old active %p, got %p\n", parent, old_active);
17477 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
17478 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
17480 log_all_parent_messages--;
17482 DestroyWindow(child);
17483 DestroyWindow(parent);
17485 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
17486 ok(ret, "PostMessage(WM_QUIT) error %d\n", GetLastError());
17487 ret = WaitForSingleObject(hthread, INFINITE);
17488 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
17489 CloseHandle(hthread);
17492 static const struct message WmSetLayeredStyle[] = {
17493 { WM_STYLECHANGING, sent },
17494 { WM_STYLECHANGED, sent },
17495 { WM_GETTEXT, sent|defwinproc|optional },
17496 { 0 }
17499 static const struct message WmSetLayeredStyle2[] = {
17500 { WM_STYLECHANGING, sent },
17501 { WM_STYLECHANGED, sent },
17502 { WM_WINDOWPOSCHANGING, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
17503 { WM_NCCALCSIZE, sent|optional|wparam|defwinproc, 1 },
17504 { WM_WINDOWPOSCHANGED, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
17505 { WM_MOVE, sent|optional|defwinproc|wparam, 0 },
17506 { WM_SIZE, sent|optional|defwinproc|wparam, SIZE_RESTORED },
17507 { 0 }
17510 struct layered_window_info
17512 HWND hwnd;
17513 HDC hdc;
17514 SIZE size;
17515 HANDLE event;
17516 BOOL ret;
17519 static DWORD CALLBACK update_layered_proc( void *param )
17521 struct layered_window_info *info = param;
17522 POINT src = { 0, 0 };
17524 info->ret = pUpdateLayeredWindow( info->hwnd, 0, NULL, &info->size,
17525 info->hdc, &src, 0, NULL, ULW_OPAQUE );
17526 ok( info->ret, "failed\n");
17527 SetEvent( info->event );
17528 return 0;
17531 static void test_layered_window(void)
17533 HWND hwnd;
17534 HDC hdc;
17535 HBITMAP bmp;
17536 BOOL ret;
17537 SIZE size;
17538 POINT pos, src;
17539 RECT rect, client;
17540 HANDLE thread;
17541 DWORD tid;
17542 struct layered_window_info info;
17544 if (!pUpdateLayeredWindow)
17546 win_skip( "UpdateLayeredWindow not supported\n" );
17547 return;
17550 hdc = CreateCompatibleDC( 0 );
17551 bmp = CreateCompatibleBitmap( hdc, 300, 300 );
17552 SelectObject( hdc, bmp );
17554 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_CAPTION | WS_THICKFRAME | WS_SYSMENU,
17555 100, 100, 300, 300, 0, 0, 0, NULL);
17556 ok( hwnd != 0, "failed to create window\n" );
17557 ShowWindow( hwnd, SW_SHOWNORMAL );
17558 UpdateWindow( hwnd );
17559 flush_events();
17560 flush_sequence();
17562 GetWindowRect( hwnd, &rect );
17563 GetClientRect( hwnd, &client );
17564 ok( client.right < rect.right - rect.left, "wrong client area\n" );
17565 ok( client.bottom < rect.bottom - rect.top, "wrong client area\n" );
17567 src.x = src.y = 0;
17568 pos.x = pos.y = 300;
17569 size.cx = size.cy = 250;
17570 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
17571 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
17572 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
17573 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
17574 ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
17576 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
17577 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
17578 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
17579 GetWindowRect( hwnd, &rect );
17580 ok( rect.left == 300 && rect.top == 300 && rect.right == 550 && rect.bottom == 550,
17581 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
17582 GetClientRect( hwnd, &rect );
17583 ok( rect.right == client.right - 50 && rect.bottom == client.bottom - 50,
17584 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
17586 size.cx = 150;
17587 pos.y = 200;
17588 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
17589 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
17590 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
17591 GetWindowRect( hwnd, &rect );
17592 ok( rect.left == 300 && rect.top == 200 && rect.right == 450 && rect.bottom == 450,
17593 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
17594 GetClientRect( hwnd, &rect );
17595 ok( rect.right == client.right - 150 && rect.bottom == client.bottom - 50,
17596 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
17598 SetWindowLongA( hwnd, GWL_STYLE,
17599 GetWindowLongA(hwnd, GWL_STYLE) & ~(WS_CAPTION | WS_THICKFRAME | WS_SYSMENU) );
17600 ok_sequence( WmSetLayeredStyle2, "WmSetLayeredStyle2", FALSE );
17602 size.cx = 200;
17603 pos.x = 200;
17604 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
17605 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
17606 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
17607 GetWindowRect( hwnd, &rect );
17608 ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
17609 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
17610 GetClientRect( hwnd, &rect );
17611 ok( (rect.right == 200 && rect.bottom == 250) ||
17612 broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
17613 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
17615 size.cx = 0;
17616 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
17617 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
17618 ok( GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == ERROR_MR_MID_NOT_FOUND) ||
17619 broken(GetLastError() == ERROR_GEN_FAILURE) /* win7 */, "wrong error %u\n", GetLastError() );
17620 size.cx = 1;
17621 size.cy = -1;
17622 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
17623 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
17624 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
17626 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED );
17627 ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
17628 GetWindowRect( hwnd, &rect );
17629 ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
17630 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
17631 GetClientRect( hwnd, &rect );
17632 ok( (rect.right == 200 && rect.bottom == 250) ||
17633 broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
17634 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
17636 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
17637 info.hwnd = hwnd;
17638 info.hdc = hdc;
17639 info.size.cx = 250;
17640 info.size.cy = 300;
17641 info.event = CreateEventA( NULL, TRUE, FALSE, NULL );
17642 info.ret = FALSE;
17643 thread = CreateThread( NULL, 0, update_layered_proc, &info, 0, &tid );
17644 ok( WaitForSingleObject( info.event, 1000 ) == 0, "wait failed\n" );
17645 ok( info.ret, "UpdateLayeredWindow failed in other thread\n" );
17646 WaitForSingleObject( thread, 1000 );
17647 CloseHandle( thread );
17648 GetWindowRect( hwnd, &rect );
17649 ok( rect.left == 200 && rect.top == 200 && rect.right == 450 && rect.bottom == 500,
17650 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
17651 GetClientRect( hwnd, &rect );
17652 ok( (rect.right == 250 && rect.bottom == 300) ||
17653 broken(rect.right == client.right - 50 && rect.bottom == client.bottom),
17654 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
17656 DestroyWindow( hwnd );
17657 DeleteDC( hdc );
17658 DeleteObject( bmp );
17661 static HMENU hpopupmenu;
17663 static LRESULT WINAPI minimize_popup_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
17665 LRESULT ret;
17667 if (ignore_message( message )) return 0;
17668 ret = MsgCheckProc( FALSE, hwnd, message, wParam, lParam );
17670 switch (message) {
17671 case WM_ENTERIDLE:
17672 ShowWindow(hwnd, SW_MINIMIZE);
17673 break;
17674 case WM_TIMER:
17675 EndMenu();
17676 break;
17679 return ret;
17682 static LRESULT WINAPI cancel_popup_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
17684 if (ignore_message( message )) return 0;
17686 switch (message) {
17687 case WM_ENTERIDLE:
17688 todo_wine ok(GetCapture() == hwnd, "expected %p, got %p\n", hwnd, GetCapture());
17689 EndMenu();
17690 break;
17691 case WM_INITMENU:
17692 case WM_INITMENUPOPUP:
17693 case WM_UNINITMENUPOPUP:
17694 ok((HMENU)wParam == hpopupmenu, "expected %p, got %lx\n", hpopupmenu, wParam);
17695 break;
17696 case WM_CAPTURECHANGED:
17697 todo_wine ok(!lParam || (HWND)lParam == hwnd, "lost capture to %lx\n", lParam);
17698 break;
17701 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
17704 static LRESULT WINAPI cancel_init_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
17706 if (ignore_message( message )) return 0;
17708 switch (message) {
17709 case WM_ENTERMENULOOP:
17710 ok(EndMenu() == TRUE, "EndMenu() failed\n");
17711 break;
17714 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
17717 static void test_TrackPopupMenu(void)
17719 MSG msg;
17720 HWND hwnd;
17721 BOOL ret;
17723 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
17724 0, 0, 1, 1, 0,
17725 NULL, NULL, 0);
17726 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
17728 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
17730 hpopupmenu = CreatePopupMenu();
17731 ok(hpopupmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
17733 AppendMenuA(hpopupmenu, MF_STRING, 100, "item 1");
17734 AppendMenuA(hpopupmenu, MF_STRING, 100, "item 2");
17736 flush_events();
17737 flush_sequence();
17738 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17739 ok_sequence(WmTrackPopupMenu, "TrackPopupMenu", TRUE);
17740 ok(ret == 1, "TrackPopupMenu failed with error %i\n", GetLastError());
17742 /* Test popup closing with an ESC-press */
17743 flush_events();
17744 PostMessageW(hwnd, WM_KEYDOWN, VK_ESCAPE, 0);
17745 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17746 ok(ret == 1, "TrackPopupMenu failed with error %i\n", GetLastError());
17747 PostQuitMessage(0);
17748 flush_sequence();
17749 while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
17751 TranslateMessage(&msg);
17752 DispatchMessageA(&msg);
17754 ok_sequence(WmTrackPopupMenuEsc, "TrackPopupMenuEsc", FALSE); /* Shouldn't get any message */
17756 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_init_proc);
17758 flush_events();
17759 flush_sequence();
17760 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17761 ok_sequence(WmTrackPopupMenuAbort, "WmTrackPopupMenuAbort", TRUE);
17762 ok(ret == TRUE, "TrackPopupMenu failed\n");
17764 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)minimize_popup_proc);
17766 /* set cursor over the window, otherwise the WM_CANCELMODE message may not always be sent */
17767 SetCursorPos( 0, 0 );
17768 ShowWindow( hwnd, SW_SHOW );
17770 flush_events();
17771 flush_sequence();
17772 SetTimer( hwnd, TIMER_ID, 500, NULL );
17773 ret = TrackPopupMenu( hpopupmenu, 0, 100,100, 0, hwnd, NULL );
17774 ok_sequence( WmTrackPopupMenuMinimizeWindow, "TrackPopupMenuMinimizeWindow", TRUE );
17775 ok( ret == 1, "TrackPopupMenu failed with error %i\n", GetLastError() );
17776 KillTimer( hwnd, TIMER_ID );
17777 ShowWindow( hwnd, SW_RESTORE );
17779 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
17781 SetCapture(hwnd);
17783 flush_events();
17784 flush_sequence();
17785 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17786 ok_sequence(WmTrackPopupMenuCapture, "TrackPopupMenuCapture", TRUE);
17787 ok(ret == 1, "TrackPopupMenuCapture failed with error %i\n", GetLastError());
17789 DestroyMenu(hpopupmenu);
17790 DestroyWindow(hwnd);
17793 static void test_TrackPopupMenuEmpty(void)
17795 HWND hwnd;
17796 BOOL ret;
17798 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
17799 0, 0, 1, 1, 0,
17800 NULL, NULL, 0);
17801 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
17803 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
17805 hpopupmenu = CreatePopupMenu();
17806 ok(hpopupmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
17808 flush_events();
17809 flush_sequence();
17810 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
17811 ok_sequence(WmTrackPopupMenuEmpty, "TrackPopupMenuEmpty", TRUE);
17812 ok(ret == 0, "TrackPopupMenu succeeded\n");
17814 DestroyMenu(hpopupmenu);
17815 DestroyWindow(hwnd);
17818 static const struct message send_message_1[] = {
17819 { WM_USER+2, sent|wparam|lparam, 0, 0 },
17820 { WM_USER, sent|wparam|lparam, 0, 0 },
17821 { 0 }
17823 static const struct message send_message_2[] = {
17824 { WM_USER+4, sent|wparam|lparam, 0, 0 },
17825 { 0 }
17827 static const struct message send_message_3[] = {
17828 { WM_USER+3, sent|wparam|lparam, 0, 0 },
17829 { WM_USER+1, sent|wparam|lparam, 0, 0 },
17830 { 0 }
17833 static DWORD WINAPI SendMessage_thread_1(void *param)
17835 struct wnd_event *wnd_event = param;
17837 trace("thread: starting\n");
17838 WaitForSingleObject(wnd_event->start_event, INFINITE);
17840 trace("thread: call PostMessage\n");
17841 PostMessageA(wnd_event->hwnd, WM_USER, 0, 0);
17843 trace("thread: call PostMessage\n");
17844 PostMessageA(wnd_event->hwnd, WM_USER+1, 0, 0);
17846 trace("thread: call SendMessage\n");
17847 SendMessageA(wnd_event->hwnd, WM_USER+2, 0, 0);
17848 SetEvent(wnd_event->stop_event);
17850 trace("thread: call SendMessage\n");
17851 SendMessageA(wnd_event->hwnd, WM_USER+3, 0, 0);
17853 return 0;
17856 static DWORD WINAPI SendMessage_thread_2(void *param)
17858 struct wnd_event *wnd_event = param;
17860 trace("thread: starting\n");
17861 WaitForSingleObject(wnd_event->start_event, INFINITE);
17863 trace("thread: call PostMessage\n");
17864 PostMessageA(wnd_event->hwnd, WM_USER, 0, 0);
17866 trace("thread: call PostMessage\n");
17867 PostMessageA(wnd_event->hwnd, WM_USER+1, 0, 0);
17869 /* this leads to sending an internal message under Wine */
17870 trace("thread: call SetParent\n");
17871 SetParent(wnd_event->hwnd, wnd_event->hwnd);
17873 trace("thread: call SendMessage\n");
17874 SendMessageA(wnd_event->hwnd, WM_USER+2, 0, 0);
17875 SetEvent(wnd_event->stop_event);
17877 trace("thread: call SendMessage\n");
17878 SendMessageA(wnd_event->hwnd, WM_USER+3, 0, 0);
17880 return 0;
17883 static void test_SendMessage_other_thread(int thread_n)
17885 DWORD qs_all_input = QS_ALLINPUT & ~QS_RAWINPUT;
17886 HANDLE hthread;
17887 struct wnd_event wnd_event;
17888 DWORD tid, ret;
17889 MSG msg;
17891 wnd_event.start_event = CreateEventA(NULL, 0, 0, NULL);
17892 wnd_event.stop_event = CreateEventA(NULL, 0, 0, NULL);
17894 wnd_event.hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
17895 100, 100, 200, 200, 0, 0, 0, NULL);
17896 ok(wnd_event.hwnd != 0, "CreateWindowEx failed\n");
17898 hthread = CreateThread(NULL, 0, thread_n == 1 ? SendMessage_thread_1 : SendMessage_thread_2, &wnd_event, 0, &tid);
17899 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
17900 CloseHandle(hthread);
17902 flush_events();
17903 flush_sequence();
17905 ret = GetQueueStatus(QS_SENDMESSAGE);
17906 ok(ret == 0, "wrong status %08x\n", ret);
17908 SetEvent(wnd_event.start_event);
17910 /* wait for other thread's SendMessage */
17911 for (;;)
17913 ret = GetQueueStatus(QS_SENDMESSAGE);
17914 if (ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE)) break;
17915 Sleep(50);
17918 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17919 ok(ret == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08x\n", ret);
17921 trace("main: call GetMessage\n");
17922 GetMessageA(&msg, 0, 0, 0);
17923 ok(msg.message == WM_USER, "expected WM_USER, got %04x\n", msg.message);
17924 DispatchMessageA(&msg);
17925 ok_sequence(send_message_1, "SendMessage from other thread 1", thread_n == 2);
17927 ret = WaitForSingleObject(wnd_event.stop_event, 100);
17928 todo_wine_if (thread_n == 2)
17929 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed, ret:%x\n", ret);
17931 /* intentionally yield */
17932 MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input);
17934 trace("main: call SendMessage\n");
17935 SendMessageA(wnd_event.hwnd, WM_USER+4, 0, 0);
17936 ok_sequence(send_message_2, "SendMessage from other thread 2", FALSE);
17938 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17939 ok(ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08x\n", ret);
17941 trace("main: call PeekMessage\n");
17942 ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should not fail\n");
17943 ok(msg.message == WM_USER+1, "expected WM_USER+1, got %04x\n", msg.message);
17944 DispatchMessageA(&msg);
17945 ok_sequence(send_message_3, "SendMessage from other thread 3", thread_n == 2);
17947 /* intentionally yield */
17948 MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input);
17950 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17951 /* FIXME: remove once Wine is fixed */
17952 todo_wine_if (thread_n == 2)
17953 ok(ret == 0, "wrong status %08x\n", ret);
17955 trace("main: call PeekMessage\n");
17956 ok(!PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should fail\n");
17957 ok_sequence(WmEmptySeq, "SendMessage from other thread 5", thread_n == 2);
17959 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17960 ok(ret == 0, "wrong status %08x\n", ret);
17962 trace("main: call DestroyWindow\n");
17963 DestroyWindow(msg.hwnd);
17965 flush_events();
17966 flush_sequence();
17968 CloseHandle(wnd_event.start_event);
17969 CloseHandle(wnd_event.stop_event);
17972 static LRESULT CALLBACK insendmessage_wnd_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
17974 DWORD flags = InSendMessageEx( NULL );
17975 BOOL ret;
17977 switch (msg)
17979 case WM_USER:
17980 ok( flags == ISMEX_SEND, "wrong flags %x\n", flags );
17981 ok( InSendMessage(), "InSendMessage returned false\n" );
17982 ret = ReplyMessage( msg );
17983 ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
17984 flags = InSendMessageEx( NULL );
17985 ok( flags == (ISMEX_SEND | ISMEX_REPLIED), "wrong flags %x\n", flags );
17986 ok( InSendMessage(), "InSendMessage returned false\n" );
17987 break;
17988 case WM_USER + 1:
17989 ok( flags == ISMEX_NOTIFY, "wrong flags %x\n", flags );
17990 ok( InSendMessage(), "InSendMessage returned false\n" );
17991 ret = ReplyMessage( msg );
17992 ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
17993 flags = InSendMessageEx( NULL );
17994 ok( flags == ISMEX_NOTIFY, "wrong flags %x\n", flags );
17995 ok( InSendMessage(), "InSendMessage returned false\n" );
17996 break;
17997 case WM_USER + 2:
17998 ok( flags == ISMEX_CALLBACK, "wrong flags %x\n", flags );
17999 ok( InSendMessage(), "InSendMessage returned false\n" );
18000 ret = ReplyMessage( msg );
18001 ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
18002 flags = InSendMessageEx( NULL );
18003 ok( flags == (ISMEX_CALLBACK | ISMEX_REPLIED) || flags == ISMEX_SEND, "wrong flags %x\n", flags );
18004 ok( InSendMessage(), "InSendMessage returned false\n" );
18005 break;
18006 case WM_USER + 3:
18007 ok( flags == ISMEX_NOSEND, "wrong flags %x\n", flags );
18008 ok( !InSendMessage(), "InSendMessage returned true\n" );
18009 ret = ReplyMessage( msg );
18010 ok( !ret, "ReplyMessage succeeded\n" );
18011 break;
18014 return DefWindowProcA( hwnd, msg, wp, lp );
18017 static void CALLBACK msg_callback( HWND hwnd, UINT msg, ULONG_PTR arg, LRESULT result )
18019 ok( msg == WM_USER + 2, "wrong msg %x\n", msg );
18020 ok( result == WM_USER + 2, "wrong result %lx\n", result );
18023 static DWORD WINAPI send_message_thread( void *arg )
18025 HWND win = arg;
18027 SendMessageA( win, WM_USER, 0, 0 );
18028 SendNotifyMessageA( win, WM_USER + 1, 0, 0 );
18029 SendMessageCallbackA( win, WM_USER + 2, 0, 0, msg_callback, 0 );
18030 PostMessageA( win, WM_USER + 3, 0, 0 );
18031 PostMessageA( win, WM_QUIT, 0, 0 );
18032 return 0;
18035 static void test_InSendMessage(void)
18037 WNDCLASSA cls;
18038 HWND win;
18039 MSG msg;
18040 HANDLE thread;
18041 DWORD tid;
18043 memset(&cls, 0, sizeof(cls));
18044 cls.lpfnWndProc = insendmessage_wnd_proc;
18045 cls.hInstance = GetModuleHandleA(NULL);
18046 cls.lpszClassName = "InSendMessage_test";
18047 RegisterClassA(&cls);
18049 win = CreateWindowA( "InSendMessage_test", NULL, 0, 0, 0, 0, 0, NULL, 0, NULL, 0 );
18050 ok( win != NULL, "CreateWindow failed: %d\n", GetLastError() );
18052 thread = CreateThread( NULL, 0, send_message_thread, win, 0, &tid );
18053 ok( thread != NULL, "CreateThread failed: %d\n", GetLastError() );
18055 while (GetMessageA(&msg, NULL, 0, 0)) DispatchMessageA( &msg );
18057 ok( WaitForSingleObject( thread, 30000 ) == WAIT_OBJECT_0, "WaitForSingleObject failed\n" );
18058 CloseHandle( thread );
18060 DestroyWindow( win );
18061 UnregisterClassA( "InSendMessage_test", GetModuleHandleA(NULL) );
18064 static const struct message DoubleSetCaptureSeq[] =
18066 { WM_CAPTURECHANGED, sent },
18067 { 0 }
18070 static void test_DoubleSetCapture(void)
18072 HWND hwnd;
18074 hwnd = CreateWindowExA(0, "TestWindowClass", "Test DoubleSetCapture",
18075 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
18076 100, 100, 200, 200, 0, 0, 0, NULL);
18077 ok (hwnd != 0, "Failed to create overlapped window\n");
18079 ShowWindow( hwnd, SW_SHOW );
18080 UpdateWindow( hwnd );
18081 flush_events();
18082 flush_sequence();
18084 SetCapture( hwnd );
18085 SetCapture( hwnd );
18086 ok_sequence(DoubleSetCaptureSeq, "SetCapture( hwnd ) twice", FALSE);
18088 DestroyWindow(hwnd);
18091 static const struct message WmRestoreMinimizedSeq[] =
18093 { HCBT_ACTIVATE, hook },
18094 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
18095 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
18096 { WM_ACTIVATEAPP, sent|wparam, 1 },
18097 { WM_NCACTIVATE, sent|wparam, 0x200001 },
18098 { WM_GETTEXT, sent|defwinproc|optional },
18099 { WM_ACTIVATE, sent|wparam, 0x200001 }, /* Note that activate messages are after WM_WINDOWPOSCHANGED and before WM_SYSCOMMAND */
18100 { HCBT_KEYSKIPPED, hook|optional },
18101 { WM_SYSKEYUP, sent|optional },
18102 { WM_SYSCOMMAND, sent|wparam, SC_RESTORE },
18103 { HCBT_SYSCOMMAND, hook|wparam, SC_RESTORE },
18104 { HCBT_SYSCOMMAND, hook|wparam|optional, SC_RESTORE },
18105 { HCBT_MINMAX, hook },
18106 { HCBT_MINMAX, hook|optional },
18107 { WM_QUERYOPEN, sent|defwinproc },
18108 { WM_QUERYOPEN, sent|optional },
18109 { WM_GETTEXT, sent|defwinproc|optional },
18110 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
18111 { WM_GETMINMAXINFO, sent|defwinproc },
18112 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
18113 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
18114 { WM_GETTEXT, sent|defwinproc|optional },
18115 { WM_ERASEBKGND, sent|defwinproc },
18116 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
18117 { WM_MOVE, sent|defwinproc },
18118 { WM_SIZE, sent|defwinproc },
18119 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
18120 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
18121 { WM_ERASEBKGND, sent|defwinproc|optional },
18122 { HCBT_SETFOCUS, hook },
18123 { WM_SETFOCUS, sent|defwinproc },
18124 { WM_ACTIVATE, sent|wparam|defwinproc, 1 },
18125 { WM_PAINT, sent| optional },
18126 { WM_SETFOCUS, sent|defwinproc|optional },
18127 { HCBT_KEYSKIPPED, hook|optional },
18128 { WM_KEYUP, sent|optional },
18129 { HCBT_KEYSKIPPED, hook|optional },
18130 { WM_SYSKEYUP, sent|optional },
18131 { HCBT_KEYSKIPPED, hook|optional },
18132 { WM_KEYUP, sent|optional },
18133 { HCBT_KEYSKIPPED, hook|optional },
18134 { WM_SYSKEYUP, sent|optional },
18135 { HCBT_KEYSKIPPED, hook|optional },
18136 { WM_KEYUP, sent|optional },
18137 { WM_PAINT, sent| optional },
18138 { 0 }
18141 static void test_restore_messages(void)
18143 INPUT ip = {0};
18144 HWND hwnd;
18145 INT i;
18147 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100,
18148 100, 200, 200, 0, 0, 0, NULL);
18149 ok (hwnd != 0, "Failed to create overlapped window\n");
18150 SetForegroundWindow(hwnd);
18151 ShowWindow(hwnd, SW_MINIMIZE);
18152 flush_events();
18153 flush_sequence();
18155 for (i = 0; i < 5; i++)
18157 /* Send Alt+Tab to restore test window from minimized state */
18158 ip.type = INPUT_KEYBOARD;
18159 ip.ki.wVk = VK_MENU;
18160 SendInput(1, &ip, sizeof(INPUT));
18161 ip.ki.wVk = VK_TAB;
18162 SendInput(1, &ip, sizeof(INPUT));
18163 ip.ki.wVk = VK_MENU;
18164 ip.ki.dwFlags = KEYEVENTF_KEYUP;
18165 SendInput(1, &ip, sizeof(INPUT));
18166 ip.ki.wVk = VK_TAB;
18167 ip.ki.dwFlags = KEYEVENTF_KEYUP;
18168 SendInput(1, &ip, sizeof(INPUT));
18169 flush_events();
18170 if (!IsIconic(hwnd))
18171 break;
18174 if (IsIconic(hwnd))
18176 skip("Alt+Tab failed to bring up test window.\n");
18177 goto done;
18179 ok_sequence(WmRestoreMinimizedSeq, "Restore minimized window", TRUE);
18181 done:
18182 DestroyWindow(hwnd);
18185 static void test_invalid_window(void)
18187 MSG msg;
18188 BOOL ret;
18190 SetLastError(0xdeadbeef);
18191 ret = GetMessageA(&msg, (HWND)0xdeadbeef, 0, 0);
18192 ok(ret == -1, "wrong ret %d\n", ret);
18193 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError());
18195 SetLastError(0xdeadbeef);
18196 ret = PeekMessageA(&msg, (HWND)0xdeadbeef, 0, 0, PM_REMOVE);
18197 ok(!ret, "wrong ret %d\n", ret);
18198 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError());
18201 static void test_button_style(void)
18203 DWORD type, expected_type;
18204 HWND button;
18205 LRESULT ret;
18206 DWORD i, j;
18208 for (i = BS_PUSHBUTTON; i <= BS_DEFCOMMANDLINK; ++i)
18210 button = CreateWindowA(WC_BUTTONA, "test", i, 0, 0, 50, 50, NULL, 0, 0, NULL);
18211 ok(button != NULL, "Expected button not null.\n");
18213 type = GetWindowLongW(button, GWL_STYLE) & BS_TYPEMASK;
18214 expected_type = (i == BS_USERBUTTON ? BS_PUSHBUTTON : i);
18215 ok(type == expected_type, "Expected type %#x, got %#x.\n", expected_type, type);
18217 for (j = BS_PUSHBUTTON; j <= BS_DEFCOMMANDLINK; ++j)
18219 ret = SendMessageA(button, BM_SETSTYLE, j, FALSE);
18220 ok(ret == 0, "Expected %#x, got %#lx.\n", 0, ret);
18222 type = GetWindowLongW(button, GWL_STYLE) & BS_TYPEMASK;
18223 expected_type = j;
18225 ok(type == expected_type, "Original type %#x, expected new type %#x, got %#x.\n", i,
18226 expected_type, type);
18228 DestroyWindow(button);
18232 START_TEST(msg)
18234 char **test_argv;
18235 BOOL ret;
18236 BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
18237 HMODULE hModuleImm32;
18238 BOOL (WINAPI *pImmDisableIME)(DWORD);
18239 int argc;
18241 argc = winetest_get_mainargs( &test_argv );
18242 if (argc >= 3)
18244 unsigned int arg;
18245 /* Child process. */
18246 sscanf (test_argv[2], "%d", (unsigned int *) &arg);
18247 do_wait_idle_child( arg );
18248 return;
18251 InitializeCriticalSection( &sequence_cs );
18252 init_procs();
18254 hModuleImm32 = LoadLibraryA("imm32.dll");
18255 if (hModuleImm32) {
18256 pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME");
18257 if (pImmDisableIME)
18258 pImmDisableIME(0);
18260 pImmDisableIME = NULL;
18261 FreeLibrary(hModuleImm32);
18263 if (!RegisterWindowClasses()) assert(0);
18265 if (pSetWinEventHook)
18267 hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
18268 GetModuleHandleA(0), win_event_proc,
18269 0, GetCurrentThreadId(),
18270 WINEVENT_INCONTEXT);
18271 if (pIsWinEventHookInstalled && hEvent_hook)
18273 UINT event;
18274 for (event = EVENT_MIN; event <= EVENT_MAX; event++)
18275 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
18278 if (!hEvent_hook) win_skip( "no win event hook support\n" );
18280 cbt_hook_thread_id = GetCurrentThreadId();
18281 hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
18282 if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
18284 test_winevents();
18286 /* Fix message sequences before removing 4 lines below */
18287 if (pUnhookWinEvent && hEvent_hook)
18289 ret = pUnhookWinEvent(hEvent_hook);
18290 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
18291 pUnhookWinEvent = 0;
18293 hEvent_hook = 0;
18295 test_SendMessage_other_thread(1);
18296 test_SendMessage_other_thread(2);
18297 test_InSendMessage();
18298 test_SetFocus();
18299 test_SetParent();
18300 test_PostMessage();
18301 test_broadcast();
18302 test_ShowWindow();
18303 test_PeekMessage();
18304 test_PeekMessage2();
18305 test_PeekMessage3();
18306 test_WaitForInputIdle( test_argv[0] );
18307 test_scrollwindowex();
18308 test_messages();
18309 test_setwindowpos();
18310 test_showwindow();
18311 invisible_parent_tests();
18312 test_mdi_messages();
18313 test_button_messages();
18314 test_button_bm_get_set_image();
18315 test_button_style();
18316 test_autoradio_BM_CLICK();
18317 test_autoradio_kbd_move();
18318 test_static_messages();
18319 test_listbox_messages();
18320 test_combobox_messages();
18321 test_wmime_keydown_message();
18322 test_paint_messages();
18323 test_interthread_messages();
18324 test_message_conversion();
18325 test_accelerators();
18326 test_timers();
18327 test_timers_no_wnd();
18328 test_timers_exceptions();
18329 if (hCBT_hook)
18331 test_set_hook();
18332 test_recursive_hook();
18334 test_DestroyWindow();
18335 test_DispatchMessage();
18336 test_SendMessageTimeout();
18337 test_edit_messages();
18338 test_quit_message();
18339 test_notify_message();
18340 test_SetActiveWindow();
18341 test_restore_messages();
18342 test_invalid_window();
18344 if (!pTrackMouseEvent)
18345 win_skip("TrackMouseEvent is not available\n");
18346 else
18347 test_TrackMouseEvent();
18349 test_SetWindowRgn();
18350 test_sys_menu();
18351 test_dialog_messages();
18352 test_EndDialog();
18353 test_nullCallback();
18354 test_dbcs_wm_char();
18355 test_unicode_wm_char();
18356 test_menu_messages();
18357 test_paintingloop();
18358 test_defwinproc();
18359 test_desktop_winproc();
18360 test_clipboard_viewers();
18361 test_keyflags();
18362 test_hotkey();
18363 test_layered_window();
18364 test_TrackPopupMenu();
18365 test_TrackPopupMenuEmpty();
18366 test_DoubleSetCapture();
18367 /* keep it the last test, under Windows it tends to break the tests
18368 * which rely on active/foreground windows being correct.
18370 test_SetForegroundWindow();
18372 UnhookWindowsHookEx(hCBT_hook);
18373 if (pUnhookWinEvent && hEvent_hook)
18375 ret = pUnhookWinEvent(hEvent_hook);
18376 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
18377 SetLastError(0xdeadbeef);
18378 ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
18379 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
18380 GetLastError() == 0xdeadbeef, /* Win9x */
18381 "unexpected error %d\n", GetLastError());
18383 DeleteCriticalSection( &sequence_cs );