user32/tests: Add tests for disabled buttons receiving WM_LBUTTONUP.
[wine.git] / dlls / user32 / tests / msg.c
blobe95d435766af576d4a2055075542ffc7e6d103b1
1 /*
2 * Unit tests for window message handling
4 * Copyright 1999 Ove Kaaven
5 * Copyright 2003 Dimitrie O. Paun
6 * Copyright 2004, 2005 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 #define _WIN32_WINNT 0x0600 /* For WM_CHANGEUISTATE,QS_RAWINPUT,WM_DWMxxxx */
24 #define WINVER 0x0600 /* for WM_GETTITLEBARINFOEX */
26 #include <assert.h>
27 #include <limits.h>
28 #include <stdarg.h>
29 #include <stdio.h>
31 #include "windef.h"
32 #include "winbase.h"
33 #include "wingdi.h"
34 #include "winuser.h"
35 #include "winnls.h"
36 #include "dbt.h"
38 #include "wine/test.h"
40 #define MDI_FIRST_CHILD_ID 2004
42 /* undocumented SWP flags - from SDK 3.1 */
43 #define SWP_NOCLIENTSIZE 0x0800
44 #define SWP_NOCLIENTMOVE 0x1000
45 #define SWP_STATECHANGED 0x8000
47 #define SW_NORMALNA 0xCC /* undoc. flag in MinMaximize */
49 #ifndef WM_KEYF1
50 #define WM_KEYF1 0x004d
51 #endif
53 #ifndef WM_SYSTIMER
54 #define WM_SYSTIMER 0x0118
55 #endif
57 #define WND_PARENT_ID 1
58 #define WND_POPUP_ID 2
59 #define WND_CHILD_ID 3
61 #ifndef WM_LBTRACKPOINT
62 #define WM_LBTRACKPOINT 0x0131
63 #endif
65 #ifdef __i386__
66 #define ARCH "x86"
67 #elif defined __x86_64__
68 #define ARCH "amd64"
69 #elif defined __arm__
70 #define ARCH "arm"
71 #elif defined __aarch64__
72 #define ARCH "arm64"
73 #else
74 #define ARCH "none"
75 #endif
77 static BOOL (WINAPI *pActivateActCtx)(HANDLE,ULONG_PTR*);
78 static HANDLE (WINAPI *pCreateActCtxW)(PCACTCTXW);
79 static BOOL (WINAPI *pDeactivateActCtx)(DWORD,ULONG_PTR);
80 static BOOL (WINAPI *pGetCurrentActCtx)(HANDLE *);
81 static BOOL (WINAPI *pQueryActCtxW)(DWORD,HANDLE,void*,ULONG,void*,SIZE_T,SIZE_T*);
82 static void (WINAPI *pReleaseActCtx)(HANDLE);
84 /* encoded DRAWITEMSTRUCT into an LPARAM */
85 typedef struct
87 union
89 struct
91 UINT type : 4; /* ODT_* flags */
92 UINT ctl_id : 4; /* Control ID */
93 UINT item_id : 4; /* Menu item ID */
94 UINT action : 4; /* ODA_* flags */
95 UINT state : 16; /* ODS_* flags */
96 } item;
97 LPARAM lp;
98 } u;
99 } DRAW_ITEM_STRUCT;
101 static BOOL test_DestroyWindow_flag;
102 static HWINEVENTHOOK hEvent_hook;
103 static HHOOK hKBD_hook;
104 static HHOOK hCBT_hook;
105 static DWORD cbt_hook_thread_id;
107 static const WCHAR testWindowClassW[] =
108 { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 };
111 FIXME: add tests for these
112 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
113 WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
114 WS_THICKFRAME: thick border
115 WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
116 WS_BORDER (default for overlapped windows): single black border
117 none (default for child (and popup?) windows): no border
120 typedef enum {
121 sent=0x1,
122 posted=0x2,
123 parent=0x4,
124 wparam=0x8,
125 lparam=0x10,
126 defwinproc=0x20,
127 beginpaint=0x40,
128 optional=0x80,
129 hook=0x100,
130 winevent_hook=0x200,
131 kbd_hook=0x400
132 } msg_flags_t;
134 struct message {
135 UINT message; /* the WM_* code */
136 msg_flags_t flags; /* message props */
137 WPARAM wParam; /* expected value of wParam */
138 LPARAM lParam; /* expected value of lParam */
139 WPARAM wp_mask; /* mask for wParam checks */
140 LPARAM lp_mask; /* mask for lParam checks */
143 struct recvd_message {
144 UINT message; /* the WM_* code */
145 msg_flags_t flags; /* message props */
146 HWND hwnd; /* window that received the message */
147 WPARAM wParam; /* expected value of wParam */
148 LPARAM lParam; /* expected value of lParam */
149 int line; /* source line where logged */
150 const char *descr; /* description for trace output */
151 char output[512]; /* trace output */
154 /* Empty message sequence */
155 static const struct message WmEmptySeq[] =
157 { 0 }
159 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
160 static const struct message WmCreateOverlappedSeq[] = {
161 { HCBT_CREATEWND, hook },
162 { WM_GETMINMAXINFO, sent },
163 { WM_NCCREATE, sent },
164 { WM_NCCALCSIZE, sent|wparam, 0 },
165 { 0x0093, sent|defwinproc|optional },
166 { 0x0094, sent|defwinproc|optional },
167 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
168 { WM_CREATE, sent },
169 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
170 { 0 }
172 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
173 * for a not visible overlapped window.
175 static const struct message WmSWP_ShowOverlappedSeq[] = {
176 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
177 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
178 { WM_NCPAINT, sent|wparam|optional, 1 },
179 { WM_GETTEXT, sent|defwinproc|optional },
180 { WM_ERASEBKGND, sent|optional },
181 { HCBT_ACTIVATE, hook },
182 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
183 { WM_NOTIFYFORMAT, sent|optional },
184 { WM_QUERYUISTATE, sent|optional },
185 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
186 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
187 { WM_ACTIVATEAPP, sent|wparam, 1 },
188 { WM_NCACTIVATE, sent },
189 { WM_GETTEXT, sent|defwinproc|optional },
190 { WM_ACTIVATE, sent|wparam, 1 },
191 { HCBT_SETFOCUS, hook },
192 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
193 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
194 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
195 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
196 { WM_GETTEXT, sent|optional },
197 { WM_NCPAINT, sent|wparam|optional, 1 },
198 { WM_GETTEXT, sent|defwinproc|optional },
199 { WM_ERASEBKGND, sent|optional },
200 /* Win9x adds SWP_NOZORDER below */
201 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
202 { WM_GETTEXT, sent|optional },
203 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
204 { WM_NCPAINT, sent|wparam|optional, 1 },
205 { WM_ERASEBKGND, sent|optional },
206 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
207 { WM_SYNCPAINT, sent|optional },
208 { WM_GETTITLEBARINFOEX, sent|optional },
209 { WM_PAINT, sent|optional },
210 { WM_NCPAINT, sent|beginpaint|optional },
211 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
212 { WM_ERASEBKGND, sent|beginpaint|optional },
213 { 0 }
215 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
216 * for a visible overlapped window.
218 static const struct message WmSWP_HideOverlappedSeq[] = {
219 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
220 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
221 { HCBT_ACTIVATE, hook|optional },
222 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
223 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
224 { WM_NCACTIVATE, sent|optional },
225 { WM_ACTIVATE, sent|optional },
226 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
227 { 0 }
230 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
231 * for a visible overlapped window.
233 static const struct message WmSWP_ResizeSeq[] = {
234 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
235 { WM_GETMINMAXINFO, sent|defwinproc },
236 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
237 { WM_NCPAINT, sent|optional },
238 { WM_GETTEXT, sent|defwinproc|optional },
239 { WM_ERASEBKGND, sent|optional },
240 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
241 { WM_SIZE, sent|defwinproc|optional },
242 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
243 { WM_NCPAINT, sent|optional },
244 { WM_GETTEXT, sent|defwinproc|optional },
245 { WM_ERASEBKGND, sent|optional },
246 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
247 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
248 { 0 }
251 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
252 * for a visible popup window.
254 static const struct message WmSWP_ResizePopupSeq[] = {
255 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
256 { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */
257 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
258 { WM_NCPAINT, sent|optional },
259 { WM_GETTEXT, sent|defwinproc|optional },
260 { WM_ERASEBKGND, sent|optional },
261 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
262 { WM_SIZE, sent|defwinproc|wparam|optional, SIZE_RESTORED },
263 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
264 { WM_NCPAINT, sent|optional },
265 { WM_GETTEXT, sent|defwinproc|optional },
266 { WM_ERASEBKGND, sent|optional },
267 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
268 { 0 }
271 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
272 * for a visible overlapped window.
274 static const struct message WmSWP_MoveSeq[] = {
275 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
276 { WM_NCPAINT, sent|optional },
277 { WM_GETTEXT, sent|defwinproc|optional },
278 { WM_ERASEBKGND, sent|optional },
279 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
280 { WM_MOVE, sent|defwinproc|wparam, 0 },
281 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
282 { 0 }
284 /* Resize with SetWindowPos(SWP_NOZORDER)
285 * for a visible overlapped window
286 * SWP_NOZORDER is stripped by the logging code
288 static const struct message WmSWP_ResizeNoZOrder[] = {
289 { WM_WINDOWPOSCHANGING, sent|wparam, /*SWP_NOZORDER|*/SWP_NOACTIVATE },
290 { WM_GETMINMAXINFO, sent|defwinproc },
291 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
292 { WM_NCPAINT, sent|optional },
293 { WM_GETTEXT, sent|defwinproc|optional },
294 { WM_ERASEBKGND, sent|optional },
295 { WM_WINDOWPOSCHANGED, sent|wparam|optional, /*SWP_NOZORDER|*/SWP_NOACTIVATE, 0,
296 SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
297 { WM_MOVE, sent|defwinproc|optional },
298 { WM_SIZE, sent|defwinproc|optional },
299 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
300 { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
301 { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */
302 { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */
303 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
304 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
305 { 0 }
308 /* Switch visible mdi children */
309 static const struct message WmSwitchChild[] = {
310 /* Switch MDI child */
311 { WM_MDIACTIVATE, sent },/* in the MDI client */
312 { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 1st MDI child */
313 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
314 { WM_CHILDACTIVATE, sent },/* in the 1st MDI child */
315 /* Deactivate 2nd MDI child */
316 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
317 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
318 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
319 /* Preparing for maximize and maximize the 1st MDI child */
320 { WM_GETMINMAXINFO, sent|defwinproc }, /* in the 1st MDI child */
321 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED }, /* in the 1st MDI child */
322 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
323 { WM_CHILDACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
324 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 1st MDI child */
325 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, /* in the 1st MDI child */
326 /* Lock redraw 2nd MDI child */
327 { WM_SETREDRAW, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
328 { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
329 /* Restore 2nd MDI child */
330 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },/* in the 2nd MDI child */
331 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
332 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
333 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 2nd MDI child */
334 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, /* in the 2nd MDI child */
335 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
336 /* Redraw 2nd MDI child */
337 { WM_SETREDRAW, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
338 /* Redraw MDI frame */
339 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },/* in MDI frame */
340 { WM_NCCALCSIZE, sent|wparam, 1 },/* in MDI frame */
341 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in MDI frame */
342 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in MDI frame */
343 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
344 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
345 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
346 { HCBT_SETFOCUS, hook },
347 { WM_KILLFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
348 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },/* in the 1st MDI child */
349 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
350 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
351 { WM_SETFOCUS, sent },/* in the MDI client */
352 { HCBT_SETFOCUS, hook },
353 { WM_KILLFOCUS, sent },/* in the MDI client */
354 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
355 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, /* in the 1st MDI child */
356 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
357 { WM_SETFOCUS, sent|defwinproc }, /* in the 1st MDI child */
358 { WM_MDIACTIVATE, sent|defwinproc },/* in the 1st MDI child */
359 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* in the 1st MDI child */
360 { 0 }
363 /* Switch visible not maximized mdi children */
364 static const struct message WmSwitchNotMaximizedChild[] = {
365 /* Switch not maximized MDI child */
366 { WM_MDIACTIVATE, sent },/* in the MDI client */
367 { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 2nd MDI child */
368 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
369 { WM_CHILDACTIVATE, sent },/* in the 2nd MDI child */
370 /* Deactivate 1st MDI child */
371 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
372 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
373 /* Activate 2nd MDI child */
374 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE}, /* in the 2nd MDI child */
375 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 2nd MDI child */
376 { HCBT_SETFOCUS, hook }, /* in the 1st MDI child */
377 { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
378 { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
379 { WM_IME_SETCONTEXT, sent|optional }, /* in the MDI client */
380 { WM_SETFOCUS, sent, 0 }, /* in the MDI client */
381 { HCBT_SETFOCUS, hook },
382 { WM_KILLFOCUS, sent }, /* in the MDI client */
383 { WM_IME_SETCONTEXT, sent|optional }, /* in the MDI client */
384 { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
385 { WM_SETFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
386 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
387 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in the 2nd MDI child */
388 { 0 }
392 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
393 SWP_NOZORDER|SWP_FRAMECHANGED)
394 * for a visible overlapped window with WS_CLIPCHILDREN style set.
396 static const struct message WmSWP_FrameChanged_clip[] = {
397 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
398 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
399 { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
400 { WM_GETTEXT, sent|parent|defwinproc|optional },
401 { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
402 { WM_NCPAINT, sent }, /* wparam != 1 */
403 { WM_ERASEBKGND, sent },
404 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
405 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
406 { WM_PAINT, sent },
407 { 0 }
409 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
410 SWP_NOZORDER|SWP_FRAMECHANGED)
411 * for a visible overlapped window.
413 static const struct message WmSWP_FrameChangedDeferErase[] = {
414 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
415 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
416 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
417 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
418 { WM_PAINT, sent|parent|optional },
419 { WM_NCPAINT, sent|beginpaint|parent|optional }, /* wparam != 1 */
420 { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
421 { WM_PAINT, sent },
422 { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
423 { WM_ERASEBKGND, sent|beginpaint|optional },
424 { 0 }
427 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
428 SWP_NOZORDER|SWP_FRAMECHANGED)
429 * for a visible overlapped window without WS_CLIPCHILDREN style set.
431 static const struct message WmSWP_FrameChanged_noclip[] = {
432 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
433 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
434 { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
435 { WM_GETTEXT, sent|parent|defwinproc|optional },
436 { WM_ERASEBKGND, sent|parent|optional },
437 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
438 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
439 { WM_PAINT, sent },
440 { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
441 { WM_ERASEBKGND, sent|beginpaint|optional },
442 { 0 }
445 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
446 static const struct message WmShowOverlappedSeq[] = {
447 { WM_SHOWWINDOW, sent|wparam, 1 },
448 { WM_NCPAINT, sent|wparam|optional, 1 },
449 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
450 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
451 { WM_NCPAINT, sent|wparam|optional, 1 },
452 { WM_GETTEXT, sent|defwinproc|optional },
453 { WM_ERASEBKGND, sent|optional },
454 { HCBT_ACTIVATE, hook|optional },
455 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
456 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
457 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
458 { WM_NCPAINT, sent|wparam|optional, 1 },
459 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
460 { WM_NCACTIVATE, sent|wparam|optional, 1 },
461 { WM_GETTEXT, sent|defwinproc|optional },
462 { WM_ACTIVATE, sent|wparam|optional, 1 },
463 { HCBT_SETFOCUS, hook|optional },
464 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
465 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
466 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
467 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
468 { WM_GETTEXT, sent|optional },
469 { WM_NCPAINT, sent|wparam|optional, 1 },
470 { WM_GETTEXT, sent|defwinproc|optional },
471 { WM_ERASEBKGND, sent|optional },
472 /* Win9x adds SWP_NOZORDER below */
473 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
474 { WM_NCCALCSIZE, sent|optional },
475 { WM_GETTEXT, sent|optional },
476 { WM_NCPAINT, sent|optional },
477 { WM_ERASEBKGND, sent|optional },
478 { WM_SYNCPAINT, sent|optional },
479 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
480 * messages. Does that mean that CreateWindow doesn't set initial
481 * window dimensions for overlapped windows?
483 { WM_SIZE, sent },
484 { WM_MOVE, sent },
485 #endif
486 { WM_PAINT, sent|optional },
487 { WM_NCPAINT, sent|beginpaint|optional },
488 { 0 }
490 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
491 static const struct message WmShowMaxOverlappedSeq[] = {
492 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
493 { WM_GETMINMAXINFO, sent },
494 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
495 { WM_GETMINMAXINFO, sent|defwinproc },
496 { WM_NCCALCSIZE, sent|wparam, TRUE },
497 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
498 { HCBT_ACTIVATE, hook|optional },
499 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
500 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
501 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
502 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
503 { WM_NCACTIVATE, sent|wparam|optional, 1 },
504 { WM_GETTEXT, sent|defwinproc|optional },
505 { WM_ACTIVATE, sent|wparam|optional, 1 },
506 { HCBT_SETFOCUS, hook|optional },
507 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
508 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
509 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
510 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
511 { WM_GETTEXT, sent|optional },
512 { WM_NCPAINT, sent|wparam|optional, 1 },
513 { WM_GETTEXT, sent|defwinproc|optional },
514 { WM_ERASEBKGND, sent|optional },
515 /* Win9x adds SWP_NOZORDER below */
516 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
517 { WM_MOVE, sent|defwinproc },
518 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
519 { WM_GETTEXT, sent|optional },
520 { WM_NCCALCSIZE, sent|optional },
521 { WM_NCPAINT, sent|optional },
522 { WM_ERASEBKGND, sent|optional },
523 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
524 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
525 { WM_SYNCPAINT, sent|optional },
526 { WM_GETTITLEBARINFOEX, sent|optional },
527 { WM_PAINT, sent|optional },
528 { WM_NCPAINT, sent|beginpaint|optional },
529 { WM_ERASEBKGND, sent|beginpaint|optional },
530 { 0 }
532 /* ShowWindow(SW_RESTORE) for a not visible maximized overlapped window */
533 static const struct message WmShowRestoreMaxOverlappedSeq[] = {
534 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
535 { WM_GETTEXT, sent|optional },
536 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
537 { WM_GETMINMAXINFO, sent|defwinproc },
538 { WM_NCCALCSIZE, sent|wparam, TRUE },
539 { WM_NCPAINT, sent|optional },
540 { WM_GETTEXT, sent|defwinproc|optional },
541 { WM_ERASEBKGND, sent|optional },
542 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
543 { WM_MOVE, sent|defwinproc|optional },
544 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
545 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
546 { WM_NCPAINT, sent|optional },
547 { WM_ERASEBKGND, sent|optional },
548 { WM_PAINT, sent|optional },
549 { WM_GETTITLEBARINFOEX, sent|optional },
550 { WM_NCPAINT, sent|beginpaint|optional },
551 { WM_ERASEBKGND, sent|beginpaint|optional },
552 { 0 }
554 /* ShowWindow(SW_RESTORE) for a not visible minimized overlapped window */
555 static const struct message WmShowRestoreMinOverlappedSeq[] = {
556 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
557 { WM_QUERYOPEN, sent|optional },
558 { WM_GETTEXT, sent|optional },
559 { WM_NCACTIVATE, sent|wparam|optional, 1 },
560 { WM_WINDOWPOSCHANGING, sent|optional }, /* SWP_NOSIZE|SWP_NOMOVE */
561 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
562 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
563 { WM_MOVE, sent|optional },
564 { WM_SIZE, sent|wparam|optional, SIZE_RESTORED },
565 { WM_GETTEXT, sent|optional },
566 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED|SWP_NOCOPYBITS },
567 { WM_GETMINMAXINFO, sent|defwinproc|optional },
568 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
569 { HCBT_ACTIVATE, hook|optional },
570 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
571 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
572 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
573 { WM_NCACTIVATE, sent|wparam|optional, 1 },
574 { WM_GETTEXT, sent|defwinproc|optional },
575 { WM_ACTIVATE, sent|wparam|optional, 1 },
576 { HCBT_SETFOCUS, hook|optional },
577 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
578 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
579 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
580 { WM_GETTEXT, sent|optional },
581 { WM_NCPAINT, sent|wparam|optional, 1 },
582 { WM_GETTEXT, sent|defwinproc|optional },
583 { WM_ERASEBKGND, sent },
584 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_STATECHANGED|SWP_FRAMECHANGED|SWP_NOCOPYBITS },
585 { WM_MOVE, sent|defwinproc },
586 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
587 { HCBT_SETFOCUS, hook|optional },
588 { WM_SETFOCUS, sent|wparam|optional, 0 },
589 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
590 { WM_NCPAINT, sent|wparam|optional, 1 },
591 { WM_ERASEBKGND, sent|optional },
592 { HCBT_SETFOCUS, hook|optional },
593 { WM_SETFOCUS, sent|wparam|optional, 0 },
594 { WM_ACTIVATE, sent|wparam, 1 },
595 { WM_GETTEXT, sent|optional },
596 { WM_PAINT, sent|optional },
597 { WM_GETTITLEBARINFOEX, sent|optional },
598 { WM_NCPAINT, sent|beginpaint|optional },
599 { WM_ERASEBKGND, sent|beginpaint|optional },
600 { 0 }
602 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
603 static const struct message WmShowMinOverlappedSeq[] = {
604 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
605 { HCBT_SETFOCUS, hook|optional },
606 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
607 { WM_KILLFOCUS, sent|optional },
608 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
609 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
610 { WM_GETTEXT, sent|optional },
611 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
612 { WM_GETMINMAXINFO, sent|defwinproc },
613 { WM_NCCALCSIZE, sent|wparam, TRUE },
614 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
615 { WM_NCPAINT, sent|optional },
616 { WM_GETTEXT, sent|defwinproc|optional },
617 { WM_WINDOWPOSCHANGED, sent },
618 { WM_MOVE, sent|defwinproc },
619 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
620 { WM_NCCALCSIZE, sent|optional },
621 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
622 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
623 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
624 { WM_NCACTIVATE, sent|wparam|optional, 0 },
625 { WM_GETTEXT, sent|defwinproc|optional },
626 { WM_ACTIVATE, sent|optional },
627 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
629 /* Vista sometimes restores the window right away... */
630 { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
631 { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
632 { HCBT_MINMAX, hook|optional|lparam, 0, SW_RESTORE },
633 { WM_QUERYOPEN, sent|optional },
634 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
635 { WM_GETMINMAXINFO, sent|optional|defwinproc },
636 { WM_NCCALCSIZE, sent|optional|wparam, TRUE },
637 { HCBT_ACTIVATE, hook|optional },
638 { WM_ACTIVATEAPP, sent|optional|wparam, 1 },
639 { WM_NCACTIVATE, sent|optional },
640 { WM_GETTEXT, sent|optional },
641 { WM_ACTIVATE, sent|optional|wparam, 1 },
642 { HCBT_SETFOCUS, hook|optional },
643 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
644 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
645 { WM_SETFOCUS, sent|optional },
646 { WM_NCPAINT, sent|optional },
647 { WM_GETTEXT, sent|defwinproc|optional },
648 { WM_ERASEBKGND, sent|optional },
649 { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
650 { WM_MOVE, sent|defwinproc|optional },
651 { WM_SIZE, sent|defwinproc|optional|wparam, SIZE_RESTORED },
652 { WM_ACTIVATE, sent|optional|wparam, 1 },
653 { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
654 { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
656 { WM_PAINT, sent|optional },
657 { WM_NCPAINT, sent|beginpaint|optional },
658 { WM_ERASEBKGND, sent|beginpaint|optional },
659 { 0 }
661 /* ShowWindow(SW_HIDE) for a visible overlapped window */
662 static const struct message WmHideOverlappedSeq[] = {
663 { WM_SHOWWINDOW, sent|wparam, 0 },
664 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
665 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
666 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
667 { WM_SIZE, sent|optional }, /* XP doesn't send it */
668 { WM_MOVE, sent|optional }, /* XP doesn't send it */
669 { WM_NCACTIVATE, sent|wparam|optional, 0 },
670 { WM_ACTIVATE, sent|wparam|optional, 0 },
671 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
672 { HCBT_SETFOCUS, hook|optional },
673 { WM_KILLFOCUS, sent|wparam|optional, 0 },
674 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
675 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
676 { 0 }
678 /* DestroyWindow for a visible overlapped window */
679 static const struct message WmDestroyOverlappedSeq[] = {
680 { HCBT_DESTROYWND, hook },
681 { 0x0090, sent|optional },
682 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
683 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
684 { 0x0090, sent|optional },
685 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
686 { WM_NCACTIVATE, sent|optional|wparam, 0 },
687 { WM_ACTIVATE, sent|optional },
688 { WM_ACTIVATEAPP, sent|optional|wparam, 0 },
689 { WM_KILLFOCUS, sent|optional|wparam, 0 },
690 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
691 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
692 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
693 { WM_DESTROY, sent },
694 { WM_NCDESTROY, sent },
695 { 0 }
697 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
698 static const struct message WmCreateMaxPopupSeq[] = {
699 { HCBT_CREATEWND, hook },
700 { WM_NCCREATE, sent },
701 { WM_NCCALCSIZE, sent|wparam, 0 },
702 { WM_CREATE, sent },
703 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
704 { WM_SIZE, sent|wparam, SIZE_RESTORED },
705 { WM_MOVE, sent },
706 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
707 { WM_GETMINMAXINFO, sent },
708 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
709 { WM_NCCALCSIZE, sent|wparam, TRUE },
710 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
711 { WM_MOVE, sent|defwinproc },
712 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
713 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
714 { WM_SHOWWINDOW, sent|wparam, 1 },
715 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
716 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
717 { HCBT_ACTIVATE, hook },
718 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
719 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
720 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
721 { WM_NCPAINT, sent|wparam|optional, 1 },
722 { WM_ERASEBKGND, sent|optional },
723 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_NOMOVE|SWP_NOSIZE },
724 { WM_ACTIVATEAPP, sent|wparam, 1 },
725 { WM_NCACTIVATE, sent },
726 { WM_ACTIVATE, sent|wparam, 1 },
727 { HCBT_SETFOCUS, hook },
728 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
729 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
730 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
731 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
732 { WM_GETTEXT, sent|optional },
733 { WM_SYNCPAINT, sent|wparam|optional, 4 },
734 { WM_NCPAINT, sent|wparam|optional, 1 },
735 { WM_ERASEBKGND, sent|optional },
736 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
737 { WM_ERASEBKGND, sent|defwinproc|optional },
738 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
739 { 0 }
741 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
742 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
743 { HCBT_CREATEWND, hook },
744 { WM_NCCREATE, sent },
745 { WM_NCCALCSIZE, sent|wparam, 0 },
746 { WM_CREATE, sent },
747 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
748 { WM_SIZE, sent|wparam, SIZE_RESTORED },
749 { WM_MOVE, sent },
750 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
751 { WM_GETMINMAXINFO, sent },
752 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
753 { WM_NCCALCSIZE, sent|wparam, TRUE },
754 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
755 { WM_MOVE, sent|defwinproc },
756 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
757 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
758 { 0 }
760 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
761 static const struct message WmShowMaxPopupResizedSeq_todo[] = {
762 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
763 { WM_GETMINMAXINFO, sent },
764 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
765 { WM_NCCALCSIZE, sent|wparam, TRUE },
766 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
767 { HCBT_ACTIVATE, hook },
768 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
769 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
770 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
771 { WM_NCPAINT, sent|wparam|optional, 1 },
772 { WM_ERASEBKGND, sent|optional },
773 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
774 { WM_ACTIVATEAPP, sent|wparam, 1 },
775 { WM_NCACTIVATE, sent },
776 { WM_ACTIVATE, sent|wparam, 1 },
777 { HCBT_SETFOCUS, hook },
778 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
779 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
780 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
781 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
782 { WM_GETTEXT, sent|optional },
783 { WM_NCPAINT, sent|wparam|optional, 1 },
784 { WM_ERASEBKGND, sent|optional },
785 { WM_WINDOWPOSCHANGED, sent },
786 /* WinNT4.0 sends WM_MOVE */
787 { WM_MOVE, sent|defwinproc|optional },
788 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
789 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
790 { 0 }
792 static const struct message WmShowMaxPopupResizedSeq[] = {
793 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
794 { WM_GETMINMAXINFO, sent },
795 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
796 { WM_NCCALCSIZE, sent|wparam, TRUE },
797 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
798 { HCBT_ACTIVATE, hook },
799 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
800 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
801 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
802 { WM_NCPAINT, sent|wparam|optional, 1 },
803 { WM_ERASEBKGND, sent|optional },
804 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
805 { WM_ACTIVATEAPP, sent|wparam, 1 },
806 { WM_NCACTIVATE, sent },
807 { WM_ACTIVATE, sent|wparam, 1 },
808 { HCBT_SETFOCUS, hook },
809 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
810 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
811 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
812 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
813 { WM_GETTEXT, sent|optional },
814 { WM_NCPAINT, sent|optional }, /* We'll check WM_NCPAINT behaviour in another test */
815 { WM_ERASEBKGND, sent|optional },
816 { WM_WINDOWPOSCHANGED, sent },
817 /* WinNT4.0 sends WM_MOVE */
818 { WM_MOVE, sent|defwinproc|optional },
819 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
820 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
821 { 0 }
823 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
824 static const struct message WmShowMaxPopupSeq[] = {
825 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
826 { WM_GETMINMAXINFO, sent },
827 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
828 { WM_NCCALCSIZE, sent|wparam, TRUE },
829 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
830 { HCBT_ACTIVATE, hook },
831 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
832 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
833 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
834 { WM_NCPAINT, sent|wparam|optional, 1 },
835 { WM_ERASEBKGND, sent|optional },
836 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOMOVE|SWP_NOSIZE },
837 { WM_ACTIVATEAPP, sent|wparam, 1 },
838 { WM_NCACTIVATE, sent },
839 { WM_ACTIVATE, sent|wparam, 1 },
840 { HCBT_SETFOCUS, hook },
841 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
842 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
843 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
844 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
845 { WM_GETTEXT, sent|optional },
846 { WM_SYNCPAINT, sent|wparam|optional, 4 },
847 { WM_NCPAINT, sent|wparam|optional, 1 },
848 { WM_ERASEBKGND, sent|optional },
849 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
850 { WM_ERASEBKGND, sent|defwinproc|optional },
851 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE },
852 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
853 { 0 }
855 /* CreateWindow(WS_VISIBLE) for popup window */
856 static const struct message WmCreatePopupSeq[] = {
857 { HCBT_CREATEWND, hook },
858 { WM_NCCREATE, sent },
859 { WM_NCCALCSIZE, sent|wparam, 0 },
860 { WM_CREATE, sent },
861 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
862 { WM_SIZE, sent|wparam, SIZE_RESTORED },
863 { WM_MOVE, sent },
864 { WM_SHOWWINDOW, sent|wparam, 1 },
865 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
866 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
867 { HCBT_ACTIVATE, hook },
868 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
869 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
870 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
871 { WM_NCPAINT, sent|wparam|optional, 1 },
872 { WM_ERASEBKGND, sent|optional },
873 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
874 { WM_ACTIVATEAPP, sent|wparam, 1 },
875 { WM_NCACTIVATE, sent },
876 { WM_ACTIVATE, sent|wparam, 1 },
877 { HCBT_SETFOCUS, hook },
878 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
879 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
880 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
881 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
882 { WM_GETTEXT, sent|optional },
883 { WM_SYNCPAINT, sent|wparam|optional, 4 },
884 { WM_NCPAINT, sent|wparam|optional, 1 },
885 { WM_ERASEBKGND, sent|optional },
886 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
887 { 0 }
889 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
890 static const struct message WmShowVisMaxPopupSeq[] = {
891 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
892 { WM_GETMINMAXINFO, sent },
893 { WM_GETTEXT, sent|optional },
894 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
895 { WM_GETTEXT, sent|optional },
896 { WM_NCCALCSIZE, sent|wparam, TRUE },
897 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
898 { WM_NCPAINT, sent|wparam|optional, 1 },
899 { WM_ERASEBKGND, sent|optional },
900 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
901 { WM_MOVE, sent|defwinproc },
902 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
903 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
904 { 0 }
906 /* CreateWindow (for a child popup window, not initially visible) */
907 static const struct message WmCreateChildPopupSeq[] = {
908 { HCBT_CREATEWND, hook },
909 { WM_NCCREATE, sent },
910 { WM_NCCALCSIZE, sent|wparam, 0 },
911 { WM_CREATE, sent },
912 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
913 { WM_SIZE, sent|wparam, SIZE_RESTORED },
914 { WM_MOVE, sent },
915 { 0 }
917 /* CreateWindow (for a popup window, not initially visible,
918 * which sets WS_VISIBLE in WM_CREATE handler)
920 static const struct message WmCreateInvisiblePopupSeq[] = {
921 { HCBT_CREATEWND, hook },
922 { WM_NCCREATE, sent },
923 { WM_NCCALCSIZE, sent|wparam, 0 },
924 { WM_CREATE, sent },
925 { WM_STYLECHANGING, sent },
926 { WM_STYLECHANGED, sent },
927 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
928 { WM_SIZE, sent|wparam, SIZE_RESTORED },
929 { WM_MOVE, sent },
930 { 0 }
932 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
933 * for a popup window with WS_VISIBLE style set
935 static const struct message WmShowVisiblePopupSeq_2[] = {
936 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
937 { 0 }
939 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
940 * for a popup window with WS_VISIBLE style set
942 static const struct message WmShowVisiblePopupSeq_3[] = {
943 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
944 { HCBT_ACTIVATE, hook },
945 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
946 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
947 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
948 { WM_NCACTIVATE, sent },
949 { WM_ACTIVATE, sent|wparam, 1 },
950 { HCBT_SETFOCUS, hook },
951 { WM_KILLFOCUS, sent|parent },
952 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
953 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
954 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
955 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
956 { WM_SETFOCUS, sent|defwinproc },
957 { WM_GETTEXT, sent|optional },
958 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_SHOWWINDOW },
959 { 0 }
961 /* CreateWindow (for a popup window with WS_VISIBLE style set and extreme location)
963 static const struct message WmShowPopupExtremeLocationSeq[] = {
964 { HCBT_CREATEWND, hook },
965 { WM_NCCREATE, sent },
966 { WM_NCCALCSIZE, sent|wparam, 0 },
967 { WM_CREATE, sent },
968 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
969 { WM_SIZE, sent|wparam, SIZE_RESTORED },
970 { WM_MOVE, sent },
971 { WM_SHOWWINDOW, sent|wparam, 1 },
972 { WM_WINDOWPOSCHANGING, sent },
973 { HCBT_ACTIVATE, hook },
974 { WM_WINDOWPOSCHANGING, sent|optional },
975 { WM_QUERYNEWPALETTE, sent|optional },
976 { WM_ACTIVATEAPP, sent },
977 { WM_NCACTIVATE, sent },
978 { WM_ACTIVATE, sent },
979 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
980 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
981 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
982 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
983 { HCBT_SETFOCUS, hook },
984 { WM_SETFOCUS, sent|defwinproc },
985 { WM_NCPAINT, sent|wparam, 1 },
986 { WM_ERASEBKGND, sent },
987 { WM_WINDOWPOSCHANGED, sent },
988 /* ocasionally received on test machines */
989 { WM_NCPAINT, sent|optional },
990 { WM_ERASEBKGND, sent|optional },
991 { 0 }
993 /* CreateWindow (for a popup window with WS_VISIBLE style set)
995 static const struct message WmShowPopupFirstDrawSeq_1[] = {
996 { HCBT_CREATEWND, hook },
997 { WM_NCCREATE, sent },
998 { WM_NCCALCSIZE, sent|wparam, 0 },
999 { WM_CREATE, sent },
1000 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1001 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1002 { WM_MOVE, sent },
1003 { WM_SHOWWINDOW, sent|wparam, 1 },
1004 { WM_WINDOWPOSCHANGING, sent },
1005 { HCBT_ACTIVATE, hook },
1006 { WM_WINDOWPOSCHANGING, sent|optional },
1007 { WM_QUERYNEWPALETTE, sent|optional },
1008 { WM_ACTIVATEAPP, sent },
1009 { WM_NCACTIVATE, sent },
1010 { WM_ACTIVATE, sent },
1011 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1012 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1013 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1014 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1015 { HCBT_SETFOCUS, hook },
1016 { WM_SETFOCUS, sent|defwinproc },
1017 { WM_NCPAINT, sent|wparam, 1 },
1018 { WM_ERASEBKGND, sent },
1019 { WM_WINDOWPOSCHANGED, sent },
1020 { WM_PAINT, sent },
1021 /* ocasionally received on test machines */
1022 { WM_NCPAINT, sent|beginpaint|optional },
1023 { WM_ERASEBKGND, sent|beginpaint|optional },
1024 { 0 }
1026 /* CreateWindow (for a popup window that is shown with ShowWindow(SW_SHOWMAXIMIZED))
1028 static const struct message WmShowPopupFirstDrawSeq_2[] = {
1029 { HCBT_CREATEWND, hook },
1030 { WM_NCCREATE, sent },
1031 { WM_NCCALCSIZE, sent|wparam, 0 },
1032 { WM_CREATE, sent },
1033 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1034 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1035 { WM_MOVE, sent },
1036 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1037 { WM_GETMINMAXINFO, sent },
1038 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_STATECHANGED|SWP_SHOWWINDOW|SWP_FRAMECHANGED },
1039 { WM_NCCALCSIZE, sent|wparam, TRUE },
1040 { HCBT_ACTIVATE, hook },
1041 { WM_WINDOWPOSCHANGING, sent|optional },
1042 { WM_NCPAINT, sent|optional|wparam, 1 },
1043 { WM_ERASEBKGND, sent|optional },
1044 { WM_WINDOWPOSCHANGED, sent|optional },
1045 { WM_QUERYNEWPALETTE, sent|optional },
1046 { WM_ACTIVATEAPP, sent },
1047 { WM_NCACTIVATE, sent },
1048 { WM_ACTIVATE, sent },
1049 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1050 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1051 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1052 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1053 { HCBT_SETFOCUS, hook },
1054 { WM_SETFOCUS, sent|defwinproc },
1055 { WM_NCPAINT, sent|wparam, 1 },
1056 { WM_ERASEBKGND, sent },
1057 { WM_WINDOWPOSCHANGED, sent|optional },
1058 { WM_MOVE, sent|defwinproc },
1059 { WM_SIZE, sent|defwinproc, 0 },
1060 { WM_PAINT, sent},
1061 /* ocasionally received on test machines */
1062 { WM_NCPAINT, sent|beginpaint|optional },
1063 { WM_ERASEBKGND, sent|beginpaint|optional },
1064 { 0 }
1066 static const struct message WmFirstDrawSetWindowPosSeq1[] = {
1067 { HCBT_CREATEWND, hook },
1068 { WM_NCCREATE, sent },
1069 { WM_NCCALCSIZE, sent|wparam, 0 },
1070 { WM_CREATE, sent },
1071 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1072 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1073 { WM_MOVE, sent },
1074 { WM_WINDOWPOSCHANGING, sent },
1075 { HCBT_ACTIVATE, hook },
1076 { WM_WINDOWPOSCHANGING, sent|optional },
1077 { WM_QUERYNEWPALETTE, sent|optional },
1078 { WM_ACTIVATEAPP, sent },
1079 { WM_NCACTIVATE, sent },
1080 { WM_ACTIVATE, sent },
1081 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1082 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1083 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1084 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1085 { HCBT_SETFOCUS, hook },
1086 { WM_SETFOCUS, sent|defwinproc },
1087 { WM_NCPAINT, sent|wparam, 1 },
1088 { WM_ERASEBKGND, sent },
1089 { WM_WINDOWPOSCHANGED, sent },
1090 { WM_MOVE, sent|defwinproc },
1091 { 0 }
1093 static const struct message WmFirstDrawSetWindowPosSeq2[] = {
1094 { HCBT_CREATEWND, hook },
1095 { WM_NCCREATE, sent },
1096 { WM_NCCALCSIZE, sent|wparam, 0 },
1097 { WM_CREATE, sent },
1098 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1099 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1100 { WM_MOVE, sent },
1101 { WM_WINDOWPOSCHANGING, sent },
1102 { HCBT_ACTIVATE, hook },
1103 { WM_QUERYNEWPALETTE, sent|optional },
1104 { WM_WINDOWPOSCHANGING, sent|optional },
1105 { WM_ACTIVATEAPP, sent },
1106 { WM_NCACTIVATE, sent },
1107 { WM_ACTIVATE, sent },
1108 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1109 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1110 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1111 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1112 { HCBT_SETFOCUS, hook },
1113 { WM_SETFOCUS, sent|defwinproc },
1114 { WM_WINDOWPOSCHANGED, sent },
1115 { WM_MOVE, sent|defwinproc },
1116 { 0 }
1118 static const struct message WmFirstDrawSetWindowPosSeq3[] = {
1119 { HCBT_CREATEWND, hook },
1120 { WM_NCCREATE, sent },
1121 { WM_NCCALCSIZE, sent|wparam, 0 },
1122 { WM_CREATE, sent },
1123 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1124 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1125 { WM_MOVE, sent },
1126 { HCBT_ACTIVATE, hook|optional },
1127 /* Probably shouldn't happen, but not part of this test */
1128 { WM_QUERYNEWPALETTE, sent|optional },
1129 { WM_ACTIVATEAPP, sent|optional },
1130 { WM_NCACTIVATE, sent|optional },
1131 { WM_ACTIVATE, sent|optional },
1132 { HCBT_SETFOCUS, hook|optional },
1133 { WM_SETFOCUS, sent|defwinproc|optional },
1134 { 0 }
1136 static const struct message WmFirstDrawSetWindowPosSeq4[] = {
1137 { HCBT_CREATEWND, hook },
1138 { WM_NCCREATE, sent },
1139 { WM_NCCALCSIZE, sent|wparam, 0 },
1140 { WM_CREATE, sent },
1141 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1142 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1143 { WM_MOVE, sent },
1144 { WM_WINDOWPOSCHANGING, sent },
1145 { HCBT_ACTIVATE, hook },
1146 { WM_WINDOWPOSCHANGING, sent|optional },
1147 { WM_QUERYNEWPALETTE, sent|optional },
1148 { WM_ACTIVATEAPP, sent },
1149 { WM_NCACTIVATE, sent },
1150 { WM_ACTIVATE, sent },
1151 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1152 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1153 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1154 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1155 { HCBT_SETFOCUS, hook },
1156 { WM_SETFOCUS, sent|defwinproc },
1157 { WM_NCPAINT, sent|wparam, 1 },
1158 { WM_ERASEBKGND, sent },
1159 { WM_WINDOWPOSCHANGED, sent },
1160 { 0 }
1162 static const struct message WmFirstDrawSetWindowPosSeq5[] = {
1163 { HCBT_CREATEWND, hook },
1164 { WM_NCCREATE, sent },
1165 { WM_NCCALCSIZE, sent|wparam, 0 },
1166 { WM_CREATE, sent },
1167 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1168 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1169 { WM_MOVE, sent },
1170 { WM_WINDOWPOSCHANGING, sent },
1171 { HCBT_ACTIVATE, hook },
1172 { WM_WINDOWPOSCHANGING, sent|optional },
1173 { WM_QUERYNEWPALETTE, sent|optional },
1174 { WM_ACTIVATEAPP, sent },
1175 { WM_NCACTIVATE, sent },
1176 { WM_ACTIVATE, sent },
1177 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1178 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1179 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1180 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1181 { HCBT_SETFOCUS, hook },
1182 { WM_SETFOCUS, sent|defwinproc },
1183 { WM_WINDOWPOSCHANGED, sent },
1184 { 0 }
1186 static const struct message WmFirstDrawChildSeq1[] = {
1187 { 0 }
1189 static const struct message WmFirstDrawChildSeq2[] = {
1190 { WM_NCPAINT, sent|wparam, 1 },
1191 { WM_ERASEBKGND, sent },
1192 /* ocasionally received on test machines */
1193 { WM_NCPAINT, sent|optional },
1194 { WM_ERASEBKGND, sent|optional },
1195 { 0 }
1197 /* CreateWindow (for child window, not initially visible) */
1198 static const struct message WmCreateChildSeq[] = {
1199 { HCBT_CREATEWND, hook },
1200 { WM_NCCREATE, sent },
1201 /* child is inserted into parent's child list after WM_NCCREATE returns */
1202 { WM_NCCALCSIZE, sent|wparam, 0 },
1203 { WM_CREATE, sent },
1204 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1205 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1206 { WM_MOVE, sent },
1207 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1208 { 0 }
1210 /* CreateWindow (for maximized child window, not initially visible) */
1211 static const struct message WmCreateMaximizedChildSeq[] = {
1212 { HCBT_CREATEWND, hook },
1213 { WM_NCCREATE, sent },
1214 { WM_NCCALCSIZE, sent|wparam, 0 },
1215 { WM_CREATE, sent },
1216 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1217 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1218 { WM_MOVE, sent },
1219 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1220 { WM_GETMINMAXINFO, sent },
1221 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
1222 { WM_NCCALCSIZE, sent|wparam, 1 },
1223 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1224 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1225 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1226 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1227 { 0 }
1229 /* CreateWindow (for a child window, initially visible) */
1230 static const struct message WmCreateVisibleChildSeq[] = {
1231 { HCBT_CREATEWND, hook },
1232 { WM_NCCREATE, sent },
1233 /* child is inserted into parent's child list after WM_NCCREATE returns */
1234 { WM_NCCALCSIZE, sent|wparam, 0 },
1235 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1236 { WM_CREATE, sent },
1237 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1238 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1239 { WM_MOVE, sent },
1240 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1241 { WM_SHOWWINDOW, sent|wparam, 1 },
1242 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1243 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1244 { WM_ERASEBKGND, sent|parent|optional },
1245 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1246 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
1247 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1248 { 0 }
1250 /* ShowWindow(SW_SHOW) for a not visible child window */
1251 static const struct message WmShowChildSeq[] = {
1252 { WM_SHOWWINDOW, sent|wparam, 1 },
1253 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1254 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1255 { WM_ERASEBKGND, sent|parent|optional },
1256 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1257 { 0 }
1259 /* ShowWindow(SW_HIDE) for a visible child window */
1260 static const struct message WmHideChildSeq[] = {
1261 { WM_SHOWWINDOW, sent|wparam, 0 },
1262 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1263 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1264 { WM_ERASEBKGND, sent|parent|optional },
1265 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1266 { 0 }
1268 /* ShowWindow(SW_HIDE) for a visible child window checking all parent events*/
1269 static const struct message WmHideChildSeq2[] = {
1270 { WM_SHOWWINDOW, sent|wparam, 0 },
1271 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1272 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1273 { WM_ERASEBKGND, sent|parent|optional },
1274 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1275 { 0 }
1277 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1278 * for a not visible child window
1280 static const struct message WmShowChildSeq_2[] = {
1281 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1282 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1283 { WM_CHILDACTIVATE, sent },
1284 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1285 { 0 }
1287 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
1288 * for a not visible child window
1290 static const struct message WmShowChildSeq_3[] = {
1291 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1292 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1293 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1294 { 0 }
1296 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1297 * for a visible child window with a caption
1299 static const struct message WmShowChildSeq_4[] = {
1300 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1301 { WM_CHILDACTIVATE, sent },
1302 { 0 }
1304 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
1305 static const struct message WmShowChildInvisibleParentSeq_1[] = {
1306 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1307 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1308 { WM_NCCALCSIZE, sent|wparam, 1 },
1309 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1310 { WM_CHILDACTIVATE, sent|optional },
1311 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1312 { WM_MOVE, sent|defwinproc },
1313 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1314 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1315 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1316 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1317 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1318 { WM_GETTEXT, sent|optional },
1319 { 0 }
1321 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
1322 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
1323 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1324 { 0 }
1326 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1327 static const struct message WmShowChildInvisibleParentSeq_2[] = {
1328 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1329 { WM_GETMINMAXINFO, sent },
1330 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
1331 { WM_NCCALCSIZE, sent|wparam, 1 },
1332 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1333 { WM_CHILDACTIVATE, sent },
1334 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1335 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1336 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1337 { 0 }
1339 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1340 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
1341 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1342 { 0 }
1344 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1345 static const struct message WmShowChildInvisibleParentSeq_3[] = {
1346 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1347 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1348 { WM_NCCALCSIZE, sent|wparam, 1 },
1349 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1350 { WM_CHILDACTIVATE, sent },
1351 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1352 { WM_MOVE, sent|defwinproc },
1353 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1354 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1355 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1356 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1357 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1358 { WM_GETTEXT, sent|optional },
1359 { 0 }
1361 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1362 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
1363 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1364 { 0 }
1366 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1367 static const struct message WmShowChildInvisibleParentSeq_4[] = {
1368 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1369 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
1370 { WM_NCCALCSIZE, sent|wparam, 1 },
1371 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1372 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1373 { WM_MOVE, sent|defwinproc },
1374 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1375 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1376 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1377 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1378 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1379 { WM_GETTEXT, sent|optional },
1380 { 0 }
1382 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1383 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
1384 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1385 { 0 }
1387 /* ShowWindow(SW_SHOW) for child with invisible parent */
1388 static const struct message WmShowChildInvisibleParentSeq_5[] = {
1389 { WM_SHOWWINDOW, sent|wparam, 1 },
1390 { 0 }
1392 /* ShowWindow(SW_HIDE) for child with invisible parent */
1393 static const struct message WmHideChildInvisibleParentSeq[] = {
1394 { WM_SHOWWINDOW, sent|wparam, 0 },
1395 { 0 }
1397 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
1398 static const struct message WmShowChildInvisibleParentSeq_6[] = {
1399 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1400 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1401 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1402 { 0 }
1404 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
1405 static const struct message WmHideChildInvisibleParentSeq_2[] = {
1406 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1407 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1408 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1409 { 0 }
1411 /* DestroyWindow for a visible child window */
1412 static const struct message WmDestroyChildSeq[] = {
1413 { HCBT_DESTROYWND, hook },
1414 { 0x0090, sent|optional },
1415 { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1416 { WM_SHOWWINDOW, sent|wparam, 0 },
1417 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1418 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1419 { WM_ERASEBKGND, sent|parent|optional },
1420 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1421 { HCBT_SETFOCUS, hook }, /* set focus to a parent */
1422 { WM_KILLFOCUS, sent },
1423 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1424 { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
1425 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1426 { WM_SETFOCUS, sent|parent },
1427 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1428 { WM_DESTROY, sent },
1429 { WM_DESTROY, sent|optional }, /* some other (IME?) window */
1430 { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
1431 { WM_NCDESTROY, sent },
1432 { 0 }
1434 /* visible child window destroyed by thread exit */
1435 static const struct message WmExitThreadSeq[] = {
1436 { WM_NCDESTROY, sent }, /* actually in grandchild */
1437 { WM_PAINT, sent|parent },
1438 { WM_ERASEBKGND, sent|parent|beginpaint },
1439 { 0 }
1441 /* DestroyWindow for a visible child window with invisible parent */
1442 static const struct message WmDestroyInvisibleChildSeq[] = {
1443 { HCBT_DESTROYWND, hook },
1444 { 0x0090, sent|optional },
1445 { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1446 { WM_SHOWWINDOW, sent|wparam, 0 },
1447 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1448 { WM_DESTROY, sent },
1449 { WM_NCDESTROY, sent },
1450 { 0 }
1452 /* Resizing child window with MoveWindow (32) */
1453 static const struct message WmResizingChildWithMoveWindowSeq[] = {
1454 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
1455 { WM_NCCALCSIZE, sent|wparam, 1 },
1456 { WM_ERASEBKGND, sent|parent|optional },
1457 { WM_ERASEBKGND, sent|optional },
1458 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
1459 { WM_MOVE, sent|defwinproc },
1460 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1461 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1462 { 0 }
1464 /* Creation of a custom dialog (32) */
1465 static const struct message WmCreateCustomDialogSeq[] = {
1466 { HCBT_CREATEWND, hook },
1467 { WM_GETMINMAXINFO, sent },
1468 { WM_NCCREATE, sent },
1469 { WM_NCCALCSIZE, sent|wparam, 0 },
1470 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1471 { WM_CREATE, sent },
1472 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1473 { WM_NOTIFYFORMAT, sent|optional },
1474 { WM_QUERYUISTATE, sent|optional },
1475 { WM_WINDOWPOSCHANGING, sent|optional },
1476 { WM_GETMINMAXINFO, sent|optional },
1477 { WM_NCCALCSIZE, sent|optional },
1478 { WM_WINDOWPOSCHANGED, sent|optional },
1479 { WM_SHOWWINDOW, sent|wparam, 1 },
1480 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1481 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1482 { HCBT_ACTIVATE, hook },
1483 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1486 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1488 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1490 { WM_NCACTIVATE, sent },
1491 { WM_GETTEXT, sent|optional|defwinproc },
1492 { WM_GETTEXT, sent|optional|defwinproc },
1493 { WM_GETTEXT, sent|optional|defwinproc },
1494 { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1495 { WM_ACTIVATE, sent|wparam, 1 },
1496 { WM_GETTEXT, sent|optional },
1497 { WM_KILLFOCUS, sent|parent },
1498 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1499 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1500 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1501 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1502 { WM_SETFOCUS, sent },
1503 { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1504 { WM_NCPAINT, sent|wparam, 1 },
1505 { WM_GETTEXT, sent|optional|defwinproc },
1506 { WM_GETTEXT, sent|optional|defwinproc },
1507 { WM_ERASEBKGND, sent },
1508 { WM_CTLCOLORDLG, sent|optional|defwinproc },
1509 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1510 { WM_GETTEXT, sent|optional },
1511 { WM_GETTEXT, sent|optional },
1512 { WM_NCCALCSIZE, sent|optional },
1513 { WM_NCPAINT, sent|optional },
1514 { WM_GETTEXT, sent|optional|defwinproc },
1515 { WM_GETTEXT, sent|optional|defwinproc },
1516 { WM_ERASEBKGND, sent|optional },
1517 { WM_CTLCOLORDLG, sent|optional|defwinproc },
1518 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1519 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1520 { WM_MOVE, sent },
1521 { 0 }
1523 /* Calling EndDialog for a custom dialog (32) */
1524 static const struct message WmEndCustomDialogSeq[] = {
1525 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1526 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1527 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1528 { WM_GETTEXT, sent|optional },
1529 { HCBT_ACTIVATE, hook },
1530 { WM_NCACTIVATE, sent|wparam, 0 },
1531 { WM_GETTEXT, sent|optional|defwinproc },
1532 { WM_GETTEXT, sent|optional|defwinproc },
1533 { WM_ACTIVATE, sent|wparam, 0 },
1534 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1535 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1536 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1537 { WM_GETTEXT, sent|optional|defwinproc },
1538 { WM_GETTEXT, sent|optional|defwinproc },
1539 { HCBT_SETFOCUS, hook },
1540 { WM_KILLFOCUS, sent },
1541 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1542 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1543 { WM_IME_NOTIFY, sent|wparam|optional, 1 },
1544 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1545 { WM_SETFOCUS, sent|parent|defwinproc },
1546 { 0 }
1548 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
1549 static const struct message WmShowCustomDialogSeq[] = {
1550 { WM_SHOWWINDOW, sent|wparam, 1 },
1551 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1552 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1553 { HCBT_ACTIVATE, hook },
1554 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1556 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1558 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1559 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1560 { WM_NCACTIVATE, sent },
1561 { WM_ACTIVATE, sent|wparam, 1 },
1562 { WM_GETTEXT, sent|optional },
1564 { WM_KILLFOCUS, sent|parent },
1565 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1566 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1567 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1568 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1569 { WM_SETFOCUS, sent },
1570 { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1571 { WM_NCPAINT, sent|wparam, 1 },
1572 { WM_ERASEBKGND, sent },
1573 { WM_CTLCOLORDLG, sent|defwinproc },
1574 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1575 { 0 }
1577 /* Creation and destruction of a modal dialog (32) */
1578 static const struct message WmModalDialogSeq[] = {
1579 { WM_CANCELMODE, sent|parent },
1580 { HCBT_SETFOCUS, hook },
1581 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1582 { WM_KILLFOCUS, sent|parent },
1583 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1584 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1585 { WM_ENABLE, sent|parent|wparam, 0 },
1586 { HCBT_CREATEWND, hook },
1587 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1588 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1589 { WM_SETFONT, sent },
1590 { WM_INITDIALOG, sent },
1591 { WM_CHANGEUISTATE, sent|optional },
1592 { WM_UPDATEUISTATE, sent|optional },
1593 { WM_SHOWWINDOW, sent },
1594 { HCBT_ACTIVATE, hook },
1595 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1596 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1597 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1598 { WM_NCACTIVATE, sent },
1599 { WM_GETTEXT, sent|optional },
1600 { WM_ACTIVATE, sent|wparam, 1 },
1601 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1602 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1603 { WM_NCPAINT, sent|optional },
1604 { WM_GETTEXT, sent|optional },
1605 { WM_ERASEBKGND, sent|optional },
1606 { WM_CTLCOLORDLG, sent|optional },
1607 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1608 { WM_GETTEXT, sent|optional },
1609 { WM_NCCALCSIZE, sent|optional },
1610 { WM_NCPAINT, sent|optional },
1611 { WM_GETTEXT, sent|optional },
1612 { WM_ERASEBKGND, sent|optional },
1613 { WM_CTLCOLORDLG, sent|optional },
1614 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1615 { WM_PAINT, sent|optional },
1616 { WM_CTLCOLORBTN, sent|optional },
1617 { WM_GETTITLEBARINFOEX, sent|optional },
1618 { WM_ENTERIDLE, sent|parent|optional },
1619 { WM_ENTERIDLE, sent|parent|optional },
1620 { WM_ENTERIDLE, sent|parent|optional },
1621 { WM_ENTERIDLE, sent|parent|optional },
1622 { WM_ENTERIDLE, sent|parent|optional },
1623 { WM_ENTERIDLE, sent|parent|optional },
1624 { WM_ENTERIDLE, sent|parent|optional },
1625 { WM_ENTERIDLE, sent|parent|optional },
1626 { WM_ENTERIDLE, sent|parent|optional },
1627 { WM_ENTERIDLE, sent|parent|optional },
1628 { WM_ENTERIDLE, sent|parent|optional },
1629 { WM_ENTERIDLE, sent|parent|optional },
1630 { WM_ENTERIDLE, sent|parent|optional },
1631 { WM_ENTERIDLE, sent|parent|optional },
1632 { WM_ENTERIDLE, sent|parent|optional },
1633 { WM_ENTERIDLE, sent|parent|optional },
1634 { WM_ENTERIDLE, sent|parent|optional },
1635 { WM_ENTERIDLE, sent|parent|optional },
1636 { WM_ENTERIDLE, sent|parent|optional },
1637 { WM_ENTERIDLE, sent|parent|optional },
1638 { WM_TIMER, sent },
1639 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1640 { WM_ENABLE, sent|parent|wparam, 1 },
1641 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1642 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1643 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1644 { WM_GETTEXT, sent|optional },
1645 { HCBT_ACTIVATE, hook },
1646 { WM_NCACTIVATE, sent|wparam, 0 },
1647 { WM_GETTEXT, sent|optional },
1648 { WM_ACTIVATE, sent|wparam, 0 },
1649 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1650 { WM_WINDOWPOSCHANGING, sent|optional },
1651 { WM_WINDOWPOSCHANGED, sent|optional },
1652 { HCBT_SETFOCUS, hook },
1653 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1654 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1655 { WM_SETFOCUS, sent|parent|defwinproc },
1656 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
1657 { HCBT_DESTROYWND, hook },
1658 { 0x0090, sent|optional },
1659 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1660 { WM_DESTROY, sent },
1661 { WM_NCDESTROY, sent },
1662 { 0 }
1664 static const struct message WmModalDialogSeq_2[] = {
1665 { WM_CANCELMODE, sent },
1666 { HCBT_SETFOCUS, hook },
1667 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1668 { WM_KILLFOCUS, sent },
1669 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1670 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1671 { WM_ENABLE, sent|wparam, 0 },
1672 { HCBT_CREATEWND, hook },
1673 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1674 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1675 { WM_SETFONT, sent },
1676 { WM_INITDIALOG, sent },
1677 { WM_CHANGEUISTATE, sent|optional },
1678 { WM_UPDATEUISTATE, sent|optional },
1679 { WM_ENABLE, sent|wparam, 1 },
1680 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1681 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1682 { WM_CHANGEUISTATE, sent|optional },
1683 { WM_UPDATEUISTATE, sent|optional },
1684 { HCBT_DESTROYWND, hook },
1685 { 0x0090, sent|optional },
1686 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1687 { WM_DESTROY, sent },
1688 { WM_NCDESTROY, sent },
1689 { 0 }
1691 /* SetMenu for NonVisible windows with size change*/
1692 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1693 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1694 { WM_NCCALCSIZE, sent|wparam, 1 },
1695 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1696 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1697 { WM_MOVE, sent|defwinproc },
1698 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1699 { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1700 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1701 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1702 { WM_GETTEXT, sent|optional },
1703 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1704 { 0 }
1706 /* SetMenu for NonVisible windows with no size change */
1707 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1708 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1709 { WM_NCCALCSIZE, sent|wparam, 1 },
1710 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1711 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1712 { 0 }
1714 /* SetMenu for Visible windows with size change */
1715 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1716 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1717 { WM_NCCALCSIZE, sent|wparam, 1 },
1718 { 0x0093, sent|defwinproc|optional },
1719 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1720 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1721 { 0x0093, sent|defwinproc|optional },
1722 { 0x0093, sent|defwinproc|optional },
1723 { 0x0091, sent|defwinproc|optional },
1724 { 0x0092, sent|defwinproc|optional },
1725 { WM_GETTEXT, sent|defwinproc|optional },
1726 { WM_ERASEBKGND, sent|optional },
1727 { WM_ACTIVATE, sent|optional },
1728 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1729 { WM_MOVE, sent|defwinproc },
1730 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1731 { 0x0093, sent|optional },
1732 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1733 { 0x0093, sent|defwinproc|optional },
1734 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1735 { 0x0093, sent|defwinproc|optional },
1736 { 0x0093, sent|defwinproc|optional },
1737 { 0x0091, sent|defwinproc|optional },
1738 { 0x0092, sent|defwinproc|optional },
1739 { WM_ERASEBKGND, sent|optional },
1740 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1741 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1742 { 0 }
1744 /* SetMenu for Visible windows with no size change */
1745 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1746 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1747 { WM_NCCALCSIZE, sent|wparam, 1 },
1748 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1749 { WM_GETTEXT, sent|defwinproc|optional },
1750 { WM_ERASEBKGND, sent|optional },
1751 { WM_ACTIVATE, sent|optional },
1752 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1753 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1754 { 0 }
1756 /* DrawMenuBar for a visible window */
1757 static const struct message WmDrawMenuBarSeq[] =
1759 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1760 { WM_NCCALCSIZE, sent|wparam, 1 },
1761 { 0x0093, sent|defwinproc|optional },
1762 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1763 { 0x0093, sent|defwinproc|optional },
1764 { 0x0093, sent|defwinproc|optional },
1765 { 0x0091, sent|defwinproc|optional },
1766 { 0x0092, sent|defwinproc|optional },
1767 { WM_GETTEXT, sent|defwinproc|optional },
1768 { WM_ERASEBKGND, sent|optional },
1769 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1770 { 0x0093, sent|optional },
1771 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1772 { 0 }
1775 static const struct message WmSetRedrawFalseSeq[] =
1777 { WM_SETREDRAW, sent|wparam, 0 },
1778 { 0 }
1781 static const struct message WmSetRedrawTrueSeq[] =
1783 { WM_SETREDRAW, sent|wparam, 1 },
1784 { 0 }
1787 static const struct message WmEnableWindowSeq_1[] =
1789 { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1790 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1791 { HCBT_SETFOCUS, hook|optional },
1792 { WM_KILLFOCUS, sent|optional },
1793 { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1794 { 0 }
1797 static const struct message WmEnableWindowSeq_2[] =
1799 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1800 { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
1801 { 0 }
1804 static const struct message WmGetScrollRangeSeq[] =
1806 { SBM_GETRANGE, sent },
1807 { 0 }
1809 static const struct message WmGetScrollInfoSeq[] =
1811 { SBM_GETSCROLLINFO, sent },
1812 { 0 }
1814 static const struct message WmSetScrollRangeSeq[] =
1816 /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
1817 sends SBM_SETSCROLLINFO.
1819 { SBM_SETSCROLLINFO, sent },
1820 { 0 }
1822 /* SetScrollRange for a window without a non-client area */
1823 static const struct message WmSetScrollRangeHSeq_empty[] =
1825 { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
1826 { 0 }
1828 static const struct message WmSetScrollRangeVSeq_empty[] =
1830 { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
1831 { 0 }
1833 static const struct message WmSetScrollRangeHVSeq[] =
1835 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1836 { WM_NCCALCSIZE, sent|wparam, 1 },
1837 { WM_GETTEXT, sent|defwinproc|optional },
1838 { WM_ERASEBKGND, sent|optional },
1839 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1840 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1841 { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1842 { 0 }
1844 /* SetScrollRange for a window with a non-client area */
1845 static const struct message WmSetScrollRangeHV_NC_Seq[] =
1847 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1848 { WM_NCCALCSIZE, sent|wparam, 1 },
1849 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1850 { WM_NCPAINT, sent|optional },
1851 { WM_STYLECHANGING, sent|defwinproc|optional },
1852 { WM_STYLECHANGED, sent|defwinproc|optional },
1853 { WM_STYLECHANGING, sent|defwinproc|optional },
1854 { WM_STYLECHANGED, sent|defwinproc|optional },
1855 { WM_STYLECHANGING, sent|defwinproc|optional },
1856 { WM_STYLECHANGED, sent|defwinproc|optional },
1857 { WM_STYLECHANGING, sent|defwinproc|optional },
1858 { WM_STYLECHANGED, sent|defwinproc|optional },
1859 { WM_GETTEXT, sent|defwinproc|optional },
1860 { WM_GETTEXT, sent|defwinproc|optional },
1861 { WM_ERASEBKGND, sent|optional },
1862 { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
1863 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOCLIENTSIZE },
1864 { WM_SIZE, sent|defwinproc|optional },
1865 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1866 { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1867 { WM_GETTEXT, sent|optional },
1868 { WM_GETTEXT, sent|optional },
1869 { WM_GETTEXT, sent|optional },
1870 { WM_GETTEXT, sent|optional },
1871 { 0 }
1873 /* test if we receive the right sequence of messages */
1874 /* after calling ShowWindow( SW_SHOWNA) */
1875 static const struct message WmSHOWNAChildInvisParInvis[] = {
1876 { WM_SHOWWINDOW, sent|wparam, 1 },
1877 { 0 }
1879 static const struct message WmSHOWNAChildVisParInvis[] = {
1880 { WM_SHOWWINDOW, sent|wparam, 1 },
1881 { 0 }
1883 static const struct message WmSHOWNAChildVisParVis[] = {
1884 { WM_SHOWWINDOW, sent|wparam, 1 },
1885 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1886 { 0 }
1888 static const struct message WmSHOWNAChildInvisParVis[] = {
1889 { WM_SHOWWINDOW, sent|wparam, 1 },
1890 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1891 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1892 { WM_ERASEBKGND, sent|optional },
1893 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
1894 { 0 }
1896 static const struct message WmSHOWNATopVisible[] = {
1897 { WM_SHOWWINDOW, sent|wparam, 1 },
1898 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1899 { WM_NCPAINT, sent|wparam|optional, 1 },
1900 { WM_GETTEXT, sent|defwinproc|optional },
1901 { WM_ERASEBKGND, sent|optional },
1902 { WM_WINDOWPOSCHANGED, sent|optional },
1903 { 0 }
1905 static const struct message WmSHOWNATopInvisible[] = {
1906 { WM_NOTIFYFORMAT, sent|optional },
1907 { WM_QUERYUISTATE, sent|optional },
1908 { WM_WINDOWPOSCHANGING, sent|optional },
1909 { WM_GETMINMAXINFO, sent|optional },
1910 { WM_NCCALCSIZE, sent|optional },
1911 { WM_WINDOWPOSCHANGED, sent|optional },
1912 { WM_SHOWWINDOW, sent|wparam, 1 },
1913 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1914 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1915 { WM_NCPAINT, sent|wparam|optional, 1 },
1916 { WM_GETTEXT, sent|defwinproc|optional },
1917 { WM_ERASEBKGND, sent|optional },
1918 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1919 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1920 { WM_NCPAINT, sent|wparam|optional, 1 },
1921 { WM_ERASEBKGND, sent|optional },
1922 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1923 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1924 { WM_MOVE, sent },
1925 { 0 }
1928 static const struct message WmTrackPopupMenu[] = {
1929 { HCBT_CREATEWND, hook },
1930 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1931 { WM_INITMENU, sent|lparam, 0, 0 },
1932 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1933 { 0x0093, sent|optional },
1934 { 0x0094, sent|optional },
1935 { 0x0094, sent|optional },
1936 { WM_ENTERIDLE, sent|wparam, 2 },
1937 { WM_CAPTURECHANGED, sent },
1938 { HCBT_DESTROYWND, hook },
1939 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1940 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
1941 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1942 { 0 }
1945 static const struct message WmTrackPopupMenuEsc[] = {
1946 { 0 }
1949 static const struct message WmTrackPopupMenuCapture[] = {
1950 { HCBT_CREATEWND, hook },
1951 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1952 { WM_CAPTURECHANGED, sent },
1953 { WM_INITMENU, sent|lparam, 0, 0 },
1954 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1955 { 0x0093, sent|optional },
1956 { 0x0094, sent|optional },
1957 { 0x0094, sent|optional },
1958 { WM_ENTERIDLE, sent|wparam, 2 },
1959 { WM_CAPTURECHANGED, sent },
1960 { HCBT_DESTROYWND, hook },
1961 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1962 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
1963 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1964 { 0 }
1967 static const struct message WmTrackPopupMenuEmpty[] = {
1968 { HCBT_CREATEWND, hook },
1969 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1970 { WM_INITMENU, sent|lparam, 0, 0 },
1971 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1972 { 0x0093, sent|optional },
1973 { 0x0094, sent|optional },
1974 { 0x0094, sent|optional },
1975 { WM_CAPTURECHANGED, sent },
1976 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1977 { HCBT_DESTROYWND, hook },
1978 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1979 { 0 }
1982 static const struct message WmTrackPopupMenuAbort[] = {
1983 { HCBT_CREATEWND, hook },
1984 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1985 { WM_INITMENU, sent|lparam, 0, 0 },
1986 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1987 { 0x0093, sent|optional },
1988 { 0x0094, sent|optional },
1989 { 0x0094, sent|optional },
1990 { WM_CAPTURECHANGED, sent },
1991 { HCBT_DESTROYWND, hook },
1992 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1993 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
1994 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1995 { 0 }
1998 static BOOL after_end_dialog, test_def_id, paint_loop_done;
1999 static int sequence_cnt, sequence_size;
2000 static struct recvd_message* sequence;
2001 static int log_all_parent_messages;
2002 static CRITICAL_SECTION sequence_cs;
2004 /* user32 functions */
2005 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
2006 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
2007 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
2008 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
2009 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
2010 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
2011 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
2012 static BOOL (WINAPI *pGetMonitorInfoA)(HMONITOR,LPMONITORINFO);
2013 static HMONITOR (WINAPI *pMonitorFromPoint)(POINT,DWORD);
2014 static BOOL (WINAPI *pUpdateLayeredWindow)(HWND,HDC,POINT*,SIZE*,HDC,POINT*,COLORREF,BLENDFUNCTION*,DWORD);
2015 static UINT_PTR (WINAPI *pSetSystemTimer)(HWND, UINT_PTR, UINT, TIMERPROC);
2016 static UINT_PTR (WINAPI *pKillSystemTimer)(HWND, UINT_PTR);
2017 static UINT_PTR (WINAPI *pSetCoalescableTimer)(HWND, UINT_PTR, UINT, TIMERPROC, ULONG);
2018 /* kernel32 functions */
2019 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
2021 static void init_procs(void)
2023 HMODULE user32 = GetModuleHandleA("user32.dll");
2024 HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
2026 #define GET_PROC(dll, func) \
2027 p ## func = (void*)GetProcAddress(dll, #func); \
2028 if(!p ## func) { \
2029 trace("GetProcAddress(%s) failed\n", #func); \
2032 GET_PROC(user32, GetAncestor)
2033 GET_PROC(user32, GetMenuInfo)
2034 GET_PROC(user32, NotifyWinEvent)
2035 GET_PROC(user32, SetMenuInfo)
2036 GET_PROC(user32, SetWinEventHook)
2037 GET_PROC(user32, TrackMouseEvent)
2038 GET_PROC(user32, UnhookWinEvent)
2039 GET_PROC(user32, GetMonitorInfoA)
2040 GET_PROC(user32, MonitorFromPoint)
2041 GET_PROC(user32, UpdateLayeredWindow)
2042 GET_PROC(user32, SetSystemTimer)
2043 GET_PROC(user32, KillSystemTimer)
2044 GET_PROC(user32, SetCoalescableTimer)
2046 GET_PROC(kernel32, GetCPInfoExA)
2048 #undef GET_PROC
2051 static const char *get_winpos_flags(UINT flags)
2053 static char buffer[300];
2055 buffer[0] = 0;
2056 #define DUMP(flag) do { if (flags & flag) { strcat( buffer, "|" #flag ); flags &= ~flag; } } while(0)
2057 DUMP( SWP_SHOWWINDOW );
2058 DUMP( SWP_HIDEWINDOW );
2059 DUMP( SWP_NOACTIVATE );
2060 DUMP( SWP_FRAMECHANGED );
2061 DUMP( SWP_NOCOPYBITS );
2062 DUMP( SWP_NOOWNERZORDER );
2063 DUMP( SWP_NOSENDCHANGING );
2064 DUMP( SWP_DEFERERASE );
2065 DUMP( SWP_ASYNCWINDOWPOS );
2066 DUMP( SWP_NOZORDER );
2067 DUMP( SWP_NOREDRAW );
2068 DUMP( SWP_NOSIZE );
2069 DUMP( SWP_NOMOVE );
2070 DUMP( SWP_NOCLIENTSIZE );
2071 DUMP( SWP_NOCLIENTMOVE );
2072 if (flags) sprintf(buffer + strlen(buffer),"|0x%04x", flags);
2073 return buffer + 1;
2074 #undef DUMP
2077 static BOOL ignore_message( UINT message )
2079 /* these are always ignored */
2080 return (message >= 0xc000 ||
2081 message == WM_GETICON ||
2082 message == WM_GETOBJECT ||
2083 message == WM_TIMECHANGE ||
2084 message == WM_DISPLAYCHANGE ||
2085 message == WM_DEVICECHANGE ||
2086 message == WM_DWMNCRENDERINGCHANGED);
2090 #define add_message(msg) add_message_(__LINE__,msg);
2091 static void add_message_(int line, const struct recvd_message *msg)
2093 struct recvd_message *seq;
2095 EnterCriticalSection( &sequence_cs );
2096 if (!sequence)
2098 sequence_size = 10;
2099 sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof(*sequence) );
2101 if (sequence_cnt == sequence_size)
2103 sequence_size *= 2;
2104 sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof(*sequence) );
2106 assert(sequence);
2108 seq = &sequence[sequence_cnt++];
2109 seq->hwnd = msg->hwnd;
2110 seq->message = msg->message;
2111 seq->flags = msg->flags;
2112 seq->wParam = msg->wParam;
2113 seq->lParam = msg->lParam;
2114 seq->line = line;
2115 seq->descr = msg->descr;
2116 seq->output[0] = 0;
2117 LeaveCriticalSection( &sequence_cs );
2119 if (msg->descr)
2121 if (msg->flags & hook)
2123 static const char * const CBT_code_name[10] =
2125 "HCBT_MOVESIZE",
2126 "HCBT_MINMAX",
2127 "HCBT_QS",
2128 "HCBT_CREATEWND",
2129 "HCBT_DESTROYWND",
2130 "HCBT_ACTIVATE",
2131 "HCBT_CLICKSKIPPED",
2132 "HCBT_KEYSKIPPED",
2133 "HCBT_SYSCOMMAND",
2134 "HCBT_SETFOCUS"
2136 const char *code_name = (msg->message <= HCBT_SETFOCUS) ? CBT_code_name[msg->message] : "Unknown";
2138 sprintf( seq->output, "%s: hook %d (%s) wp %08lx lp %08lx",
2139 msg->descr, msg->message, code_name, msg->wParam, msg->lParam );
2141 else if (msg->flags & winevent_hook)
2143 sprintf( seq->output, "%s: winevent %p %08x %08lx %08lx",
2144 msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
2146 else
2148 switch (msg->message)
2150 case WM_WINDOWPOSCHANGING:
2151 case WM_WINDOWPOSCHANGED:
2153 WINDOWPOS *winpos = (WINDOWPOS *)msg->lParam;
2155 sprintf( seq->output, "%s: %p WM_WINDOWPOS%s wp %08lx lp %08lx after %p x %d y %d cx %d cy %d flags %s",
2156 msg->descr, msg->hwnd,
2157 (msg->message == WM_WINDOWPOSCHANGING) ? "CHANGING" : "CHANGED",
2158 msg->wParam, msg->lParam, winpos->hwndInsertAfter,
2159 winpos->x, winpos->y, winpos->cx, winpos->cy,
2160 get_winpos_flags(winpos->flags) );
2162 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2163 * in the high word for internal purposes
2165 seq->wParam = winpos->flags & 0xffff;
2166 /* We are not interested in the flags that don't match under XP and Win9x */
2167 seq->wParam &= ~SWP_NOZORDER;
2168 break;
2171 case WM_DRAWITEM:
2173 DRAW_ITEM_STRUCT di;
2174 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)msg->lParam;
2176 sprintf( seq->output, "%s: %p WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x",
2177 msg->descr, msg->hwnd, dis->CtlType, dis->CtlID,
2178 dis->itemID, dis->itemAction, dis->itemState);
2180 di.u.lp = 0;
2181 di.u.item.type = dis->CtlType;
2182 di.u.item.ctl_id = dis->CtlID;
2183 if (dis->CtlType == ODT_LISTBOX ||
2184 dis->CtlType == ODT_COMBOBOX ||
2185 dis->CtlType == ODT_MENU)
2186 di.u.item.item_id = dis->itemID;
2187 di.u.item.action = dis->itemAction;
2188 di.u.item.state = dis->itemState;
2190 seq->lParam = di.u.lp;
2191 break;
2193 default:
2194 if (msg->message >= 0xc000) return; /* ignore registered messages */
2195 sprintf( seq->output, "%s: %p %04x wp %08lx lp %08lx",
2196 msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
2198 if (msg->flags & (sent|posted|parent|defwinproc|beginpaint))
2199 sprintf( seq->output + strlen(seq->output), " (flags %x)", msg->flags );
2204 /* try to make sure pending X events have been processed before continuing */
2205 static void flush_events(void)
2207 MSG msg;
2208 int diff = 200;
2209 int min_timeout = 100;
2210 DWORD time = GetTickCount() + diff;
2212 while (diff > 0)
2214 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
2215 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
2216 diff = time - GetTickCount();
2220 static void flush_sequence(void)
2222 EnterCriticalSection( &sequence_cs );
2223 HeapFree(GetProcessHeap(), 0, sequence);
2224 sequence = 0;
2225 sequence_cnt = sequence_size = 0;
2226 LeaveCriticalSection( &sequence_cs );
2229 static void dump_sequence(const struct message *expected, const char *context, const char *file, int line)
2231 const struct recvd_message *actual = sequence;
2232 unsigned int count = 0;
2234 trace_(file, line)("Failed sequence %s:\n", context );
2235 while (expected->message && actual->message)
2237 if (actual->output[0])
2239 if (expected->flags & hook)
2241 trace_(file, line)( " %u: expected: hook %04x - actual: %s\n",
2242 count, expected->message, actual->output );
2244 else if (expected->flags & winevent_hook)
2246 trace_(file, line)( " %u: expected: winevent %04x - actual: %s\n",
2247 count, expected->message, actual->output );
2249 else if (expected->flags & kbd_hook)
2251 trace_(file, line)( " %u: expected: kbd %04x - actual: %s\n",
2252 count, expected->message, actual->output );
2254 else
2256 trace_(file, line)( " %u: expected: msg %04x - actual: %s\n",
2257 count, expected->message, actual->output );
2261 if (expected->message == actual->message)
2263 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) &&
2264 (expected->flags & optional))
2266 /* don't match messages if their defwinproc status differs */
2267 expected++;
2269 else
2271 expected++;
2272 actual++;
2275 /* silently drop winevent messages if there is no support for them */
2276 else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
2277 expected++;
2278 else
2280 expected++;
2281 actual++;
2283 count++;
2286 /* optional trailing messages */
2287 while (expected->message && ((expected->flags & optional) ||
2288 ((expected->flags & winevent_hook) && !hEvent_hook)))
2290 trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2291 expected++;
2292 count++;
2295 if (expected->message)
2297 trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2298 return;
2301 while (actual->message && actual->output[0])
2303 trace_(file, line)( " %u: expected: nothing - actual: %s\n", count, actual->output );
2304 actual++;
2305 count++;
2309 #define ok_sequence( exp, contx, todo) \
2310 ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
2313 static void ok_sequence_(const struct message *expected_list, const char *context, BOOL todo,
2314 const char *file, int line)
2316 static const struct recvd_message end_of_sequence;
2317 const struct message *expected = expected_list;
2318 const struct recvd_message *actual;
2319 int failcount = 0, dump = 0;
2320 unsigned int count = 0;
2322 add_message(&end_of_sequence);
2324 actual = sequence;
2326 while (expected->message && actual->message)
2328 if (expected->message == actual->message &&
2329 !((expected->flags ^ actual->flags) & (hook|winevent_hook|kbd_hook)))
2331 if (expected->flags & wparam)
2333 if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && todo)
2335 todo_wine {
2336 failcount ++;
2337 if (strcmp(winetest_platform, "wine")) dump++;
2338 ok_( file, line) (FALSE,
2339 "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2340 context, count, expected->message, expected->wParam, actual->wParam);
2343 else
2345 ok_( file, line)( ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) == 0,
2346 "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2347 context, count, expected->message, expected->wParam, actual->wParam);
2348 if ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) dump++;
2352 if (expected->flags & lparam)
2354 if (((expected->lParam ^ actual->lParam) & ~expected->lp_mask) && todo)
2356 todo_wine {
2357 failcount ++;
2358 if (strcmp(winetest_platform, "wine")) dump++;
2359 ok_( file, line) (FALSE,
2360 "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2361 context, count, expected->message, expected->lParam, actual->lParam);
2364 else
2366 ok_( file, line)(((expected->lParam ^ actual->lParam) & ~expected->lp_mask) == 0,
2367 "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2368 context, count, expected->message, expected->lParam, actual->lParam);
2369 if ((expected->lParam ^ actual->lParam) & ~expected->lp_mask) dump++;
2372 if ((expected->flags & optional) &&
2373 ((expected->flags ^ actual->flags) & (defwinproc|parent)))
2375 /* don't match optional messages if their defwinproc or parent status differs */
2376 expected++;
2377 count++;
2378 continue;
2380 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
2382 todo_wine {
2383 failcount ++;
2384 if (strcmp(winetest_platform, "wine")) dump++;
2385 ok_( file, line) (FALSE,
2386 "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2387 context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2390 else
2392 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
2393 "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2394 context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2395 if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++;
2398 ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
2399 "%s: %u: the msg 0x%04x should %shave been sent by BeginPaint\n",
2400 context, count, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
2401 if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++;
2403 ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
2404 "%s: %u: the msg 0x%04x should have been %s\n",
2405 context, count, expected->message, (expected->flags & posted) ? "posted" : "sent");
2406 if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++;
2408 ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
2409 "%s: %u: the msg 0x%04x was expected in %s\n",
2410 context, count, expected->message, (expected->flags & parent) ? "parent" : "child");
2411 if ((expected->flags & parent) != (actual->flags & parent)) dump++;
2413 ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
2414 "%s: %u: the msg 0x%04x should have been sent by a hook\n",
2415 context, count, expected->message);
2416 if ((expected->flags & hook) != (actual->flags & hook)) dump++;
2418 ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
2419 "%s: %u: the msg 0x%04x should have been sent by a winevent hook\n",
2420 context, count, expected->message);
2421 if ((expected->flags & winevent_hook) != (actual->flags & winevent_hook)) dump++;
2423 ok_( file, line) ((expected->flags & kbd_hook) == (actual->flags & kbd_hook),
2424 "%s: %u: the msg 0x%04x should have been sent by a keyboard hook\n",
2425 context, count, expected->message);
2426 if ((expected->flags & kbd_hook) != (actual->flags & kbd_hook)) dump++;
2428 expected++;
2429 actual++;
2431 /* silently drop hook messages if there is no support for them */
2432 else if ((expected->flags & optional) ||
2433 ((expected->flags & hook) && !hCBT_hook) ||
2434 ((expected->flags & winevent_hook) && !hEvent_hook) ||
2435 ((expected->flags & kbd_hook) && !hKBD_hook))
2436 expected++;
2437 else if (todo)
2439 failcount++;
2440 todo_wine {
2441 if (strcmp(winetest_platform, "wine")) dump++;
2442 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2443 context, count, expected->message, actual->message);
2445 goto done;
2447 else
2449 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2450 context, count, expected->message, actual->message);
2451 dump++;
2452 expected++;
2453 actual++;
2455 count++;
2458 /* skip all optional trailing messages */
2459 while (expected->message && ((expected->flags & optional) ||
2460 ((expected->flags & hook) && !hCBT_hook) ||
2461 ((expected->flags & winevent_hook) && !hEvent_hook)))
2462 expected++;
2464 if (todo)
2466 todo_wine {
2467 if (expected->message || actual->message) {
2468 failcount++;
2469 if (strcmp(winetest_platform, "wine")) dump++;
2470 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2471 context, count, expected->message, actual->message);
2475 else
2477 if (expected->message || actual->message)
2479 dump++;
2480 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2481 context, count, expected->message, actual->message);
2484 if( todo && !failcount) /* succeeded yet marked todo */
2485 todo_wine {
2486 if (!strcmp(winetest_platform, "wine")) dump++;
2487 ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
2490 done:
2491 if (dump) dump_sequence(expected_list, context, file, line);
2492 flush_sequence();
2495 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
2497 /******************************** MDI test **********************************/
2499 /* CreateWindow for MDI frame window, initially visible */
2500 static const struct message WmCreateMDIframeSeq[] = {
2501 { HCBT_CREATEWND, hook },
2502 { WM_GETMINMAXINFO, sent },
2503 { WM_NCCREATE, sent },
2504 { WM_NCCALCSIZE, sent|wparam, 0 },
2505 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2506 { WM_CREATE, sent },
2507 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2508 { WM_NOTIFYFORMAT, sent|optional },
2509 { WM_QUERYUISTATE, sent|optional },
2510 { WM_WINDOWPOSCHANGING, sent|optional },
2511 { WM_GETMINMAXINFO, sent|optional },
2512 { WM_NCCALCSIZE, sent|optional },
2513 { WM_WINDOWPOSCHANGED, sent|optional },
2514 { WM_SHOWWINDOW, sent|wparam, 1 },
2515 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2516 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2517 { HCBT_ACTIVATE, hook },
2518 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
2519 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
2520 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
2521 { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
2522 { WM_NCACTIVATE, sent },
2523 { WM_GETTEXT, sent|defwinproc|optional },
2524 { WM_ACTIVATE, sent|wparam, 1 },
2525 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
2526 { HCBT_SETFOCUS, hook },
2527 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2528 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2529 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2530 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
2531 /* Win9x adds SWP_NOZORDER below */
2532 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2533 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2534 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2535 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2536 { WM_MOVE, sent },
2537 { 0 }
2539 /* DestroyWindow for MDI frame window, initially visible */
2540 static const struct message WmDestroyMDIframeSeq[] = {
2541 { HCBT_DESTROYWND, hook },
2542 { 0x0090, sent|optional },
2543 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2544 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2545 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2546 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2547 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
2548 { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2549 { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
2550 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
2551 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2552 { WM_DESTROY, sent },
2553 { WM_NCDESTROY, sent },
2554 { 0 }
2556 /* CreateWindow for MDI client window, initially visible */
2557 static const struct message WmCreateMDIclientSeq[] = {
2558 { HCBT_CREATEWND, hook },
2559 { WM_NCCREATE, sent },
2560 { WM_NCCALCSIZE, sent|wparam, 0 },
2561 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2562 { WM_CREATE, sent },
2563 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2564 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2565 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2566 { WM_MOVE, sent },
2567 { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
2568 { WM_SHOWWINDOW, sent|wparam, 1 },
2569 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2570 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2571 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2572 { 0 }
2574 /* ShowWindow(SW_SHOW) for MDI client window */
2575 static const struct message WmShowMDIclientSeq[] = {
2576 { WM_SHOWWINDOW, sent|wparam, 1 },
2577 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2578 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2579 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2580 { 0 }
2582 /* ShowWindow(SW_HIDE) for MDI client window */
2583 static const struct message WmHideMDIclientSeq[] = {
2584 { WM_SHOWWINDOW, sent|wparam, 0 },
2585 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2586 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
2587 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
2588 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2589 { 0 }
2591 /* DestroyWindow for MDI client window, initially visible */
2592 static const struct message WmDestroyMDIclientSeq[] = {
2593 { HCBT_DESTROYWND, hook },
2594 { 0x0090, sent|optional },
2595 { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
2596 { WM_SHOWWINDOW, sent|wparam, 0 },
2597 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2598 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2599 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2600 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2601 { WM_DESTROY, sent },
2602 { WM_NCDESTROY, sent },
2603 { 0 }
2605 /* CreateWindow for MDI child window, initially visible */
2606 static const struct message WmCreateMDIchildVisibleSeq[] = {
2607 { HCBT_CREATEWND, hook },
2608 { WM_NCCREATE, sent },
2609 { WM_NCCALCSIZE, sent|wparam, 0 },
2610 { WM_CREATE, sent },
2611 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2612 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2613 { WM_MOVE, sent },
2614 /* Win2k sends wparam set to
2615 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2616 * while Win9x doesn't bother to set child window id according to
2617 * CLIENTCREATESTRUCT.idFirstChild
2619 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2620 { WM_SHOWWINDOW, sent|wparam, 1 },
2621 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2622 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2623 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2624 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2625 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2626 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2627 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2629 /* Win9x: message sequence terminates here. */
2631 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2632 { HCBT_SETFOCUS, hook }, /* in MDI client */
2633 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2634 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2635 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2636 { WM_SETFOCUS, sent }, /* in MDI client */
2637 { HCBT_SETFOCUS, hook },
2638 { WM_KILLFOCUS, sent }, /* in MDI client */
2639 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2640 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2641 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2642 { WM_SETFOCUS, sent|defwinproc },
2643 { WM_MDIACTIVATE, sent|defwinproc },
2644 { 0 }
2646 /* WM_CHILDACTIVATE sent to disabled window */
2647 static const struct message WmChildActivateDisabledWindowSeq[] = {
2648 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2649 { 0 }
2651 /* WM_CHILDACTIVATE sent to enabled window */
2652 static const struct message WmChildActivateWindowSeq[] = {
2653 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2654 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 },
2655 { WM_MDIACTIVATE, sent|defwinproc },
2656 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2657 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2658 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2659 { HCBT_SETFOCUS, hook },
2660 { WM_KILLFOCUS, sent|defwinproc },
2661 { WM_SETFOCUS, sent },
2662 { HCBT_SETFOCUS, hook },
2663 { WM_KILLFOCUS, sent },
2664 { WM_SETFOCUS, sent|defwinproc },
2665 { WM_MDIACTIVATE, sent|defwinproc },
2666 { 0 }
2668 /* CreateWindow for MDI child window with invisible parent */
2669 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
2670 { HCBT_CREATEWND, hook },
2671 { WM_GETMINMAXINFO, sent },
2672 { WM_NCCREATE, sent },
2673 { WM_NCCALCSIZE, sent|wparam, 0 },
2674 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2675 { WM_CREATE, sent },
2676 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2677 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2678 { WM_MOVE, sent },
2679 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2680 { WM_SHOWWINDOW, sent|wparam, 1 },
2681 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2682 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2683 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2684 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2686 /* Win9x: message sequence terminates here. */
2688 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2689 { HCBT_SETFOCUS, hook }, /* in MDI client */
2690 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2691 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2692 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2693 { WM_SETFOCUS, sent }, /* in MDI client */
2694 { HCBT_SETFOCUS, hook },
2695 { WM_KILLFOCUS, sent }, /* in MDI client */
2696 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2697 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2698 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2699 { WM_SETFOCUS, sent|defwinproc },
2700 { WM_MDIACTIVATE, sent|defwinproc },
2701 { 0 }
2703 /* DestroyWindow for MDI child window, initially visible */
2704 static const struct message WmDestroyMDIchildVisibleSeq[] = {
2705 { HCBT_DESTROYWND, hook },
2706 /* Win2k sends wparam set to
2707 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2708 * while Win9x doesn't bother to set child window id according to
2709 * CLIENTCREATESTRUCT.idFirstChild
2711 { 0x0090, sent|optional },
2712 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2713 { WM_SHOWWINDOW, sent|wparam, 0 },
2714 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2715 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2716 { WM_ERASEBKGND, sent|parent|optional },
2717 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2719 /* { WM_DESTROY, sent }
2720 * Win9x: message sequence terminates here.
2723 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2724 { WM_KILLFOCUS, sent },
2725 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2726 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2727 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2728 { WM_SETFOCUS, sent }, /* in MDI client */
2730 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2731 { WM_KILLFOCUS, sent }, /* in MDI client */
2732 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2733 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2734 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2735 { WM_SETFOCUS, sent }, /* in MDI client */
2737 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2739 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2740 { WM_KILLFOCUS, sent },
2741 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2742 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2743 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2744 { WM_SETFOCUS, sent }, /* in MDI client */
2746 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2747 { WM_KILLFOCUS, sent }, /* in MDI client */
2748 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2749 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2750 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2751 { WM_SETFOCUS, sent }, /* in MDI client */
2753 { WM_DESTROY, sent },
2755 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2756 { WM_KILLFOCUS, sent },
2757 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2758 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2759 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2760 { WM_SETFOCUS, sent }, /* in MDI client */
2762 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2763 { WM_KILLFOCUS, sent }, /* in MDI client */
2764 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2765 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2766 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2767 { WM_SETFOCUS, sent }, /* in MDI client */
2769 { WM_NCDESTROY, sent },
2770 { 0 }
2772 /* CreateWindow for MDI child window, initially invisible */
2773 static const struct message WmCreateMDIchildInvisibleSeq[] = {
2774 { HCBT_CREATEWND, hook },
2775 { WM_NCCREATE, sent },
2776 { WM_NCCALCSIZE, sent|wparam, 0 },
2777 { WM_CREATE, sent },
2778 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2779 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2780 { WM_MOVE, sent },
2781 /* Win2k sends wparam set to
2782 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2783 * while Win9x doesn't bother to set child window id according to
2784 * CLIENTCREATESTRUCT.idFirstChild
2786 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2787 { 0 }
2789 /* DestroyWindow for MDI child window, initially invisible */
2790 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
2791 { HCBT_DESTROYWND, hook },
2792 /* Win2k sends wparam set to
2793 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2794 * while Win9x doesn't bother to set child window id according to
2795 * CLIENTCREATESTRUCT.idFirstChild
2797 { 0x0090, sent|optional },
2798 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2799 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2800 { WM_DESTROY, sent },
2801 { WM_NCDESTROY, sent },
2802 /* FIXME: Wine destroys an icon/title window while Windows doesn't */
2803 { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
2804 { 0 }
2806 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
2807 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
2808 { HCBT_CREATEWND, hook },
2809 { WM_NCCREATE, sent },
2810 { WM_NCCALCSIZE, sent|wparam, 0 },
2811 { WM_CREATE, sent },
2812 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2813 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2814 { WM_MOVE, sent },
2815 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2816 { WM_GETMINMAXINFO, sent },
2817 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2818 { WM_NCCALCSIZE, sent|wparam, 1 },
2819 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2820 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2821 /* in MDI frame */
2822 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2823 { WM_NCCALCSIZE, sent|wparam, 1 },
2824 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2825 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2826 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2827 /* Win2k sends wparam set to
2828 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2829 * while Win9x doesn't bother to set child window id according to
2830 * CLIENTCREATESTRUCT.idFirstChild
2832 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2833 { WM_SHOWWINDOW, sent|wparam, 1 },
2834 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2835 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2836 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2837 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2838 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2839 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2840 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_FRAMECHANGED },
2842 /* Win9x: message sequence terminates here. */
2844 { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
2845 { HCBT_SETFOCUS, hook|optional }, /* in MDI client */
2846 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2847 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2848 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2849 { WM_SETFOCUS, sent|optional }, /* in MDI client */
2850 { HCBT_SETFOCUS, hook|optional },
2851 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
2852 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2853 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2854 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2855 { WM_SETFOCUS, sent|defwinproc|optional },
2856 { WM_MDIACTIVATE, sent|defwinproc|optional },
2857 /* in MDI frame */
2858 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2859 { WM_NCCALCSIZE, sent|wparam, 1 },
2860 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2861 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2862 { 0 }
2864 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
2865 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
2866 /* restore the 1st MDI child */
2867 { WM_SETREDRAW, sent|wparam, 0 },
2868 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2869 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2870 { WM_NCCALCSIZE, sent|wparam, 1 },
2871 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2872 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2873 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2874 /* in MDI frame */
2875 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2876 { WM_NCCALCSIZE, sent|wparam, 1 },
2877 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2878 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2879 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2880 { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
2881 /* create the 2nd MDI child */
2882 { HCBT_CREATEWND, hook },
2883 { WM_NCCREATE, sent },
2884 { WM_NCCALCSIZE, sent|wparam, 0 },
2885 { WM_CREATE, sent },
2886 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2887 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2888 { WM_MOVE, sent },
2889 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2890 { WM_GETMINMAXINFO, sent },
2891 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2892 { WM_NCCALCSIZE, sent|wparam, 1 },
2893 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2894 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2895 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2896 /* in MDI frame */
2897 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2898 { WM_NCCALCSIZE, sent|wparam, 1 },
2899 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2900 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2901 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2902 /* Win2k sends wparam set to
2903 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2904 * while Win9x doesn't bother to set child window id according to
2905 * CLIENTCREATESTRUCT.idFirstChild
2907 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2908 { WM_SHOWWINDOW, sent|wparam, 1 },
2909 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2910 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2911 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2912 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2913 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2914 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2916 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2917 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2919 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2921 /* Win9x: message sequence terminates here. */
2923 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2924 { HCBT_SETFOCUS, hook },
2925 { WM_KILLFOCUS, sent|defwinproc|optional }, /* in the 1st MDI child */
2926 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
2927 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2928 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2929 { WM_SETFOCUS, sent }, /* in MDI client */
2930 { HCBT_SETFOCUS, hook },
2931 { WM_KILLFOCUS, sent }, /* in MDI client */
2932 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2933 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2934 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2935 { WM_SETFOCUS, sent|defwinproc },
2937 { WM_MDIACTIVATE, sent|defwinproc },
2938 /* in MDI frame */
2939 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2940 { WM_NCCALCSIZE, sent|wparam, 1 },
2941 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2942 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2943 { 0 }
2945 /* WM_MDICREATE MDI child window, initially visible and maximized */
2946 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
2947 { WM_MDICREATE, sent },
2948 { HCBT_CREATEWND, hook },
2949 { WM_NCCREATE, sent },
2950 { WM_NCCALCSIZE, sent|wparam, 0 },
2951 { WM_CREATE, sent },
2952 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2953 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2954 { WM_MOVE, sent },
2955 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2956 { WM_GETMINMAXINFO, sent },
2957 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2958 { WM_NCCALCSIZE, sent|wparam, 1 },
2959 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2960 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2962 /* in MDI frame */
2963 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2964 { WM_NCCALCSIZE, sent|wparam, 1 },
2965 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2966 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2967 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2969 /* Win2k sends wparam set to
2970 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2971 * while Win9x doesn't bother to set child window id according to
2972 * CLIENTCREATESTRUCT.idFirstChild
2974 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2975 { WM_SHOWWINDOW, sent|wparam, 1 },
2976 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2978 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2980 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2981 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2982 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2984 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2985 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2987 /* Win9x: message sequence terminates here. */
2989 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2990 { WM_SETFOCUS, sent|optional }, /* in MDI client */
2991 { HCBT_SETFOCUS, hook }, /* in MDI client */
2992 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2993 { WM_IME_NOTIFY, sent|wparam|optional, 2 },
2994 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
2995 { WM_SETFOCUS, sent|optional }, /* in MDI client */
2996 { HCBT_SETFOCUS, hook|optional },
2997 { WM_KILLFOCUS, sent }, /* in MDI client */
2998 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2999 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3000 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3001 { WM_SETFOCUS, sent|defwinproc },
3003 { WM_MDIACTIVATE, sent|defwinproc },
3005 /* in MDI child */
3006 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3007 { WM_NCCALCSIZE, sent|wparam, 1 },
3008 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3009 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
3011 /* in MDI frame */
3012 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3013 { WM_NCCALCSIZE, sent|wparam, 1 },
3014 { 0x0093, sent|defwinproc|optional },
3015 { 0x0093, sent|defwinproc|optional },
3016 { 0x0093, sent|defwinproc|optional },
3017 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3018 { WM_MOVE, sent|defwinproc },
3019 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3021 /* in MDI client */
3022 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3023 { WM_NCCALCSIZE, sent|wparam, 1 },
3024 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3025 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3027 /* in MDI child */
3028 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3029 { WM_NCCALCSIZE, sent|wparam, 1 },
3030 { 0x0093, sent|optional },
3031 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3032 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3034 { 0x0093, sent|optional },
3035 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3036 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3037 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
3038 { 0x0093, sent|defwinproc|optional },
3039 { 0x0093, sent|defwinproc|optional },
3040 { 0x0093, sent|defwinproc|optional },
3041 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3042 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3044 { 0 }
3046 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
3047 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
3048 { HCBT_CREATEWND, hook },
3049 { WM_GETMINMAXINFO, sent },
3050 { WM_NCCREATE, sent },
3051 { WM_NCCALCSIZE, sent|wparam, 0 },
3052 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
3053 { WM_CREATE, sent },
3054 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3055 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3056 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOZORDER }, /* MDI frame */
3057 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI frame */
3058 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOZORDER }, /* MDI frame */
3059 { WM_MOVE, sent },
3060 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3061 { WM_GETMINMAXINFO, sent },
3062 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3063 { WM_GETMINMAXINFO, sent|defwinproc },
3064 { WM_NCCALCSIZE, sent|wparam, 1 },
3065 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_STATECHANGED },
3066 { WM_MOVE, sent|defwinproc },
3067 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3068 /* in MDI frame */
3069 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3070 { WM_NCCALCSIZE, sent|wparam, 1 },
3071 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3072 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3073 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
3074 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3075 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3076 /* Win2k sends wparam set to
3077 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3078 * while Win9x doesn't bother to set child window id according to
3079 * CLIENTCREATESTRUCT.idFirstChild
3081 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3082 { 0 }
3084 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
3085 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
3086 { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
3087 { HCBT_SYSCOMMAND, hook },
3088 { WM_CLOSE, sent|defwinproc },
3089 { WM_MDIDESTROY, sent }, /* in MDI client */
3091 /* bring the 1st MDI child to top */
3092 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
3093 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
3095 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3097 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
3098 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
3099 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
3101 /* maximize the 1st MDI child */
3102 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3103 { WM_GETMINMAXINFO, sent|defwinproc },
3104 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED },
3105 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
3106 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
3107 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3108 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3110 /* restore the 2nd MDI child */
3111 { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
3112 { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
3113 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
3114 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
3116 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3118 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3119 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3121 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3123 { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
3124 /* in MDI frame */
3125 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3126 { WM_NCCALCSIZE, sent|wparam, 1 },
3127 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3128 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3129 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3131 /* bring the 1st MDI child to top */
3132 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3133 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3134 { HCBT_SETFOCUS, hook },
3135 { WM_KILLFOCUS, sent|defwinproc },
3136 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
3137 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3138 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3139 { WM_SETFOCUS, sent }, /* in MDI client */
3140 { HCBT_SETFOCUS, hook },
3141 { WM_KILLFOCUS, sent }, /* in MDI client */
3142 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3143 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3144 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3145 { WM_SETFOCUS, sent|defwinproc },
3146 { WM_MDIACTIVATE, sent|defwinproc },
3147 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3149 /* apparently ShowWindow(SW_SHOW) on an MDI client */
3150 { WM_SHOWWINDOW, sent|wparam, 1 },
3151 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3152 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3153 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3154 { WM_MDIREFRESHMENU, sent },
3156 { HCBT_DESTROYWND, hook },
3157 /* Win2k sends wparam set to
3158 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3159 * while Win9x doesn't bother to set child window id according to
3160 * CLIENTCREATESTRUCT.idFirstChild
3162 { 0x0090, sent|defwinproc|optional },
3163 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3164 { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
3165 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3166 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3167 { WM_ERASEBKGND, sent|parent|optional },
3168 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3170 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3171 { WM_DESTROY, sent|defwinproc },
3172 { WM_NCDESTROY, sent|defwinproc },
3173 { 0 }
3175 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
3176 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
3177 { WM_MDIDESTROY, sent }, /* in MDI client */
3178 { WM_SHOWWINDOW, sent|wparam, 0 },
3179 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3180 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3181 { WM_ERASEBKGND, sent|parent|optional },
3182 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3184 { HCBT_SETFOCUS, hook },
3185 { WM_KILLFOCUS, sent },
3186 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3187 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3188 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3189 { WM_SETFOCUS, sent }, /* in MDI client */
3190 { HCBT_SETFOCUS, hook },
3191 { WM_KILLFOCUS, sent }, /* in MDI client */
3192 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3193 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3194 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3195 { WM_SETFOCUS, sent },
3197 /* in MDI child */
3198 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3199 { WM_NCCALCSIZE, sent|wparam, 1 },
3200 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3201 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3203 /* in MDI frame */
3204 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3205 { WM_NCCALCSIZE, sent|wparam, 1 },
3206 { 0x0093, sent|defwinproc|optional },
3207 { 0x0093, sent|defwinproc|optional },
3208 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3209 { WM_MOVE, sent|defwinproc },
3210 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3212 /* in MDI client */
3213 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3214 { WM_NCCALCSIZE, sent|wparam, 1 },
3215 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3216 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3218 /* in MDI child */
3219 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3220 { WM_NCCALCSIZE, sent|wparam, 1 },
3221 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3222 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3224 /* in MDI child */
3225 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3226 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3227 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3228 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3230 /* in MDI frame */
3231 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3232 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3233 { 0x0093, sent|defwinproc|optional },
3234 { 0x0093, sent|defwinproc|optional },
3235 { 0x0093, sent|defwinproc|optional },
3236 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3237 { WM_MOVE, sent|defwinproc },
3238 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3240 /* in MDI client */
3241 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3242 { WM_NCCALCSIZE, sent|wparam, 1 },
3243 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3244 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3246 /* in MDI child */
3247 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3248 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3249 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3250 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3251 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3252 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3254 { 0x0093, sent|defwinproc|optional },
3255 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
3256 { 0x0093, sent|defwinproc|optional },
3257 { 0x0093, sent|defwinproc|optional },
3258 { 0x0093, sent|defwinproc|optional },
3259 { 0x0093, sent|optional },
3261 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3262 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3263 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3264 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3265 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3267 /* in MDI frame */
3268 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3269 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3270 { 0x0093, sent|defwinproc|optional },
3271 { 0x0093, sent|defwinproc|optional },
3272 { 0x0093, sent|defwinproc|optional },
3273 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3274 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3275 { 0x0093, sent|optional },
3277 { WM_NCACTIVATE, sent|wparam, 0 },
3278 { WM_MDIACTIVATE, sent },
3280 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
3281 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
3282 { WM_NCCALCSIZE, sent|wparam, 1 },
3284 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3286 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3287 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3288 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3290 /* in MDI child */
3291 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3292 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3293 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3294 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3296 /* in MDI frame */
3297 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3298 { WM_NCCALCSIZE, sent|wparam, 1 },
3299 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3300 { WM_MOVE, sent|defwinproc },
3301 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3303 /* in MDI client */
3304 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3305 { WM_NCCALCSIZE, sent|wparam, 1 },
3306 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3307 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3308 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3309 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
3310 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3311 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3312 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3314 { HCBT_SETFOCUS, hook },
3315 { WM_KILLFOCUS, sent },
3316 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3317 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3318 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3319 { WM_SETFOCUS, sent }, /* in MDI client */
3321 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
3323 { HCBT_DESTROYWND, hook },
3324 /* Win2k sends wparam set to
3325 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3326 * while Win9x doesn't bother to set child window id according to
3327 * CLIENTCREATESTRUCT.idFirstChild
3329 { 0x0090, sent|optional },
3330 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3332 { WM_SHOWWINDOW, sent|wparam, 0 },
3333 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3334 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3335 { WM_ERASEBKGND, sent|parent|optional },
3336 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3338 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3339 { WM_DESTROY, sent },
3340 { WM_NCDESTROY, sent },
3341 { 0 }
3343 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
3344 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
3345 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3346 { WM_GETMINMAXINFO, sent },
3347 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3348 { WM_NCCALCSIZE, sent|wparam, 1 },
3349 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3350 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3352 { WM_WINDOWPOSCHANGING, sent|wparam|optional|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3353 { WM_NCACTIVATE, sent|wparam|optional|defwinproc, 1 },
3354 { HCBT_SETFOCUS, hook|optional },
3355 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3356 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3357 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3358 { HCBT_SETFOCUS, hook|optional },
3359 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3360 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3361 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3362 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3363 { WM_SETFOCUS, sent|optional|defwinproc },
3364 { WM_MDIACTIVATE, sent|optional|defwinproc },
3365 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3366 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3367 /* in MDI frame */
3368 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3369 { WM_NCCALCSIZE, sent|wparam, 1 },
3370 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3371 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3372 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3373 { 0 }
3375 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
3376 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
3377 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3378 { WM_GETMINMAXINFO, sent },
3379 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
3380 { WM_GETMINMAXINFO, sent|defwinproc },
3381 { WM_NCCALCSIZE, sent|wparam, 1 },
3382 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3383 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3385 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3386 { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
3387 { HCBT_SETFOCUS, hook|optional },
3388 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3389 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3390 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3391 { HCBT_SETFOCUS, hook|optional },
3392 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3393 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3394 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3395 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3396 { WM_SETFOCUS, sent|defwinproc|optional },
3397 { WM_MDIACTIVATE, sent|defwinproc|optional },
3398 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3399 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3400 { 0 }
3402 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
3403 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
3404 { WM_MDIMAXIMIZE, sent }, /* in MDI client */
3405 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3406 { WM_GETMINMAXINFO, sent },
3407 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3408 { WM_GETMINMAXINFO, sent|defwinproc },
3409 { WM_NCCALCSIZE, sent|wparam, 1 },
3410 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
3411 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3412 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
3413 { WM_MOVE, sent|defwinproc },
3414 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3416 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3417 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3418 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3419 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3420 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3421 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3422 /* in MDI frame */
3423 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3424 { WM_NCCALCSIZE, sent|wparam, 1 },
3425 { 0x0093, sent|defwinproc|optional },
3426 { 0x0094, sent|defwinproc|optional },
3427 { 0x0094, sent|defwinproc|optional },
3428 { 0x0094, sent|defwinproc|optional },
3429 { 0x0094, sent|defwinproc|optional },
3430 { 0x0093, sent|defwinproc|optional },
3431 { 0x0093, sent|defwinproc|optional },
3432 { 0x0091, sent|defwinproc|optional },
3433 { 0x0092, sent|defwinproc|optional },
3434 { 0x0092, sent|defwinproc|optional },
3435 { 0x0092, sent|defwinproc|optional },
3436 { 0x0092, sent|defwinproc|optional },
3437 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3438 { WM_MOVE, sent|defwinproc },
3439 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3440 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
3441 /* in MDI client */
3442 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3443 { WM_NCCALCSIZE, sent|wparam, 1 },
3444 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3445 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3446 /* in MDI child */
3447 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3448 { WM_GETMINMAXINFO, sent|defwinproc },
3449 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3450 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3451 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3452 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
3453 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3454 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3455 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3456 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3457 /* in MDI frame */
3458 { 0x0093, sent|optional },
3459 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3460 { 0x0093, sent|defwinproc|optional },
3461 { 0x0093, sent|defwinproc|optional },
3462 { 0x0093, sent|defwinproc|optional },
3463 { 0x0091, sent|defwinproc|optional },
3464 { 0x0092, sent|defwinproc|optional },
3465 { 0x0092, sent|defwinproc|optional },
3466 { 0x0092, sent|defwinproc|optional },
3467 { 0x0092, sent|defwinproc|optional },
3468 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3469 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3470 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3471 { 0 }
3473 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
3474 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
3475 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3476 { WM_GETMINMAXINFO, sent },
3477 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3478 { WM_NCCALCSIZE, sent|wparam, 1 },
3479 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3480 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3481 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3482 /* in MDI frame */
3483 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3484 { WM_NCCALCSIZE, sent|wparam, 1 },
3485 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3486 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3487 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3488 { 0 }
3490 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
3491 static const struct message WmRestoreMDIchildVisibleSeq[] = {
3492 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3493 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3494 { WM_NCCALCSIZE, sent|wparam, 1 },
3495 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3496 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3497 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3498 /* in MDI frame */
3499 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3500 { WM_NCCALCSIZE, sent|wparam, 1 },
3501 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3502 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3503 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3504 { 0 }
3506 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
3507 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
3508 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3509 { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
3510 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3511 { WM_NCCALCSIZE, sent|wparam, 1 },
3512 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3513 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3514 { WM_MOVE, sent|defwinproc },
3515 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3516 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3517 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3518 { HCBT_SETFOCUS, hook },
3519 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3520 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
3521 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3522 { WM_SETFOCUS, sent },
3523 { 0 }
3525 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
3526 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
3527 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
3528 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3529 { WM_NCCALCSIZE, sent|wparam, 1 },
3530 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3531 { WM_MOVE, sent|defwinproc },
3532 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
3533 { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
3534 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3535 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3536 /* FIXME: Wine creates an icon/title window while Windows doesn't */
3537 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
3538 { 0 }
3540 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
3541 static const struct message WmRestoreMDIchildInvisibleSeq[] = {
3542 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3543 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3544 { WM_NCCALCSIZE, sent|wparam, 1 },
3545 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3546 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3547 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3548 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3549 /* in MDI frame */
3550 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3551 { WM_NCCALCSIZE, sent|wparam, 1 },
3552 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3553 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3554 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3555 { 0 }
3558 static HWND mdi_client;
3559 static WNDPROC old_mdi_client_proc;
3561 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3563 struct recvd_message msg;
3565 /* do not log painting messages */
3566 if (message != WM_PAINT &&
3567 message != WM_NCPAINT &&
3568 message != WM_SYNCPAINT &&
3569 message != WM_ERASEBKGND &&
3570 message != WM_NCHITTEST &&
3571 message != WM_GETTEXT &&
3572 message != WM_MDIGETACTIVE &&
3573 !ignore_message( message ))
3575 msg.hwnd = hwnd;
3576 msg.message = message;
3577 msg.flags = sent|wparam|lparam;
3578 msg.wParam = wParam;
3579 msg.lParam = lParam;
3580 msg.descr = "mdi client";
3581 add_message(&msg);
3584 return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
3587 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3589 static LONG defwndproc_counter = 0;
3590 LRESULT ret;
3591 struct recvd_message msg;
3593 /* do not log painting messages */
3594 if (message != WM_PAINT &&
3595 message != WM_NCPAINT &&
3596 message != WM_SYNCPAINT &&
3597 message != WM_ERASEBKGND &&
3598 message != WM_NCHITTEST &&
3599 message != WM_GETTEXT &&
3600 !ignore_message( message ))
3602 switch (message)
3604 case WM_MDIACTIVATE:
3606 HWND active, client = GetParent(hwnd);
3608 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
3610 if (hwnd == (HWND)lParam) /* if we are being activated */
3611 ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
3612 else
3613 ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
3614 break;
3618 msg.hwnd = hwnd;
3619 msg.message = message;
3620 msg.flags = sent|wparam|lparam;
3621 if (defwndproc_counter) msg.flags |= defwinproc;
3622 msg.wParam = wParam;
3623 msg.lParam = lParam;
3624 msg.descr = "mdi child";
3625 add_message(&msg);
3628 defwndproc_counter++;
3629 ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
3630 defwndproc_counter--;
3632 return ret;
3635 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3637 static LONG defwndproc_counter = 0;
3638 LRESULT ret;
3639 struct recvd_message msg;
3641 /* do not log painting messages */
3642 if (message != WM_PAINT &&
3643 message != WM_NCPAINT &&
3644 message != WM_SYNCPAINT &&
3645 message != WM_ERASEBKGND &&
3646 message != WM_NCHITTEST &&
3647 message != WM_GETTEXT &&
3648 !ignore_message( message ))
3650 msg.hwnd = hwnd;
3651 msg.message = message;
3652 msg.flags = sent|wparam|lparam;
3653 if (defwndproc_counter) msg.flags |= defwinproc;
3654 msg.wParam = wParam;
3655 msg.lParam = lParam;
3656 msg.descr = "mdi frame";
3657 add_message(&msg);
3660 defwndproc_counter++;
3661 ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
3662 defwndproc_counter--;
3664 return ret;
3667 static BOOL mdi_RegisterWindowClasses(void)
3669 WNDCLASSA cls;
3671 cls.style = 0;
3672 cls.lpfnWndProc = mdi_frame_wnd_proc;
3673 cls.cbClsExtra = 0;
3674 cls.cbWndExtra = 0;
3675 cls.hInstance = GetModuleHandleA(0);
3676 cls.hIcon = 0;
3677 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
3678 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3679 cls.lpszMenuName = NULL;
3680 cls.lpszClassName = "MDI_frame_class";
3681 if (!RegisterClassA(&cls)) return FALSE;
3683 cls.lpfnWndProc = mdi_child_wnd_proc;
3684 cls.lpszClassName = "MDI_child_class";
3685 if (!RegisterClassA(&cls)) return FALSE;
3687 if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
3688 old_mdi_client_proc = cls.lpfnWndProc;
3689 cls.hInstance = GetModuleHandleA(0);
3690 cls.lpfnWndProc = mdi_client_hook_proc;
3691 cls.lpszClassName = "MDI_client_class";
3692 if (!RegisterClassA(&cls)) assert(0);
3694 return TRUE;
3697 static void test_mdi_messages(void)
3699 MDICREATESTRUCTA mdi_cs;
3700 CLIENTCREATESTRUCT client_cs;
3701 HWND mdi_frame, mdi_child, mdi_child2, active_child;
3702 BOOL zoomed;
3703 RECT rc;
3704 HMENU hMenu = CreateMenu();
3705 LONG val;
3707 if (!mdi_RegisterWindowClasses()) assert(0);
3709 flush_sequence();
3711 trace("creating MDI frame window\n");
3712 mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
3713 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
3714 WS_MAXIMIZEBOX | WS_VISIBLE,
3715 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
3716 GetDesktopWindow(), hMenu,
3717 GetModuleHandleA(0), NULL);
3718 assert(mdi_frame);
3719 ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
3721 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3722 ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
3724 trace("creating MDI client window\n");
3725 GetClientRect(mdi_frame, &rc);
3726 client_cs.hWindowMenu = 0;
3727 client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
3728 mdi_client = CreateWindowExA(0, "MDI_client_class",
3729 NULL,
3730 WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
3731 rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
3732 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3733 assert(mdi_client);
3734 SetWindowLongA(mdi_client, 0, 0xdeadbeef);
3736 ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
3737 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3738 ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
3740 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3741 ok(!active_child, "wrong active MDI child %p\n", active_child);
3742 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3744 SetFocus(0);
3745 flush_sequence();
3747 trace("creating invisible MDI child window\n");
3748 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3749 WS_CHILD,
3750 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3751 mdi_client, 0, GetModuleHandleA(0), NULL);
3752 assert(mdi_child);
3754 flush_sequence();
3755 ShowWindow(mdi_child, SW_SHOWNORMAL);
3756 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
3758 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3759 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3761 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3762 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3764 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3765 ok(!active_child, "wrong active MDI child %p\n", active_child);
3766 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3768 ShowWindow(mdi_child, SW_HIDE);
3769 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
3770 flush_sequence();
3772 ShowWindow(mdi_child, SW_SHOW);
3773 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
3775 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3776 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3778 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3779 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3781 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3782 ok(!active_child, "wrong active MDI child %p\n", active_child);
3783 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3785 DestroyWindow(mdi_child);
3786 flush_sequence();
3788 trace("creating visible MDI child window\n");
3789 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3790 WS_CHILD | WS_VISIBLE,
3791 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3792 mdi_client, 0, GetModuleHandleA(0), NULL);
3793 assert(mdi_child);
3794 ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
3796 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3797 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3799 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3800 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3802 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3803 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3804 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3805 flush_sequence();
3807 DestroyWindow(mdi_child);
3808 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3810 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3811 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3813 /* Win2k: MDI client still returns a just destroyed child as active
3814 * Win9x: MDI client returns 0
3816 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3817 ok(active_child == mdi_child || /* win2k */
3818 !active_child, /* win9x */
3819 "wrong active MDI child %p\n", active_child);
3820 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3822 flush_sequence();
3824 trace("creating invisible MDI child window\n");
3825 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3826 WS_CHILD,
3827 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3828 mdi_client, 0, GetModuleHandleA(0), NULL);
3829 assert(mdi_child2);
3830 ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
3832 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
3833 ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
3835 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3836 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3838 /* Win2k: MDI client still returns a just destroyed child as active
3839 * Win9x: MDI client returns mdi_child2
3841 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3842 ok(active_child == mdi_child || /* win2k */
3843 active_child == mdi_child2, /* win9x */
3844 "wrong active MDI child %p\n", active_child);
3845 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3846 flush_sequence();
3848 ShowWindow(mdi_child2, SW_MAXIMIZE);
3849 ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
3851 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3852 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3854 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3855 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3856 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3857 flush_sequence();
3859 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3860 ok(GetFocus() == mdi_child2 || /* win2k */
3861 GetFocus() == 0, /* win9x */
3862 "wrong focus window %p\n", GetFocus());
3864 SetFocus(0);
3865 flush_sequence();
3867 ShowWindow(mdi_child2, SW_HIDE);
3868 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3870 ShowWindow(mdi_child2, SW_RESTORE);
3871 ok_sequence(WmRestoreMDIchildInvisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
3872 flush_sequence();
3874 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3875 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3877 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3878 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3879 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3880 flush_sequence();
3882 SetFocus(0);
3883 flush_sequence();
3885 ShowWindow(mdi_child2, SW_HIDE);
3886 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3888 ShowWindow(mdi_child2, SW_SHOW);
3889 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
3891 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3892 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3894 ShowWindow(mdi_child2, SW_MAXIMIZE);
3895 ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
3897 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3898 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3900 ShowWindow(mdi_child2, SW_RESTORE);
3901 ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
3903 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3904 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3906 ShowWindow(mdi_child2, SW_MINIMIZE);
3907 ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", TRUE);
3909 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3910 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3912 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3913 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3914 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3915 flush_sequence();
3917 ShowWindow(mdi_child2, SW_RESTORE);
3918 ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", FALSE);
3920 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3921 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3923 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3924 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3925 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3926 flush_sequence();
3928 SetFocus(0);
3929 flush_sequence();
3931 ShowWindow(mdi_child2, SW_HIDE);
3932 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3934 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3935 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3937 DestroyWindow(mdi_child2);
3938 ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
3940 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3941 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3943 trace("Testing WM_CHILDACTIVATE\n");
3945 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3946 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_DISABLED,
3947 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3948 mdi_client, 0, GetModuleHandleA(0), NULL);
3950 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3951 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX,
3952 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3953 mdi_client, 0, GetModuleHandleA(0), NULL);
3955 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3956 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3957 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3959 flush_sequence();
3960 SendMessageW(mdi_child, WM_CHILDACTIVATE, 0, 0);
3961 ok_sequence(WmChildActivateDisabledWindowSeq, "WM_CHILDACTIVATE sent to disabled window", FALSE);
3963 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3964 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3965 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3966 flush_sequence();
3968 EnableWindow(mdi_child, TRUE);
3970 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3971 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3972 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3974 flush_sequence();
3975 SendMessageW(mdi_child, WM_CHILDACTIVATE, 0, 0);
3976 ok_sequence(WmChildActivateWindowSeq, "WM_CHILDACTIVATE sent to enabled window", FALSE);
3978 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3979 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3980 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3981 flush_sequence();
3983 DestroyWindow(mdi_child);
3984 DestroyWindow(mdi_child2);
3985 flush_sequence();
3987 /* test for maximized MDI children */
3988 trace("creating maximized visible MDI child window 1\n");
3989 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3990 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3991 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3992 mdi_client, 0, GetModuleHandleA(0), NULL);
3993 assert(mdi_child);
3994 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
3995 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3997 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3998 ok(GetFocus() == mdi_child || /* win2k */
3999 GetFocus() == 0, /* win9x */
4000 "wrong focus window %p\n", GetFocus());
4002 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4003 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4004 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4005 flush_sequence();
4007 trace("creating maximized visible MDI child window 2\n");
4008 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4009 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4010 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4011 mdi_client, 0, GetModuleHandleA(0), NULL);
4012 assert(mdi_child2);
4013 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
4014 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
4015 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4017 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4018 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4020 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4021 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4022 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4023 flush_sequence();
4025 trace("destroying maximized visible MDI child window 2\n");
4026 DestroyWindow(mdi_child2);
4027 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4029 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4031 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4032 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4034 /* Win2k: MDI client still returns a just destroyed child as active
4035 * Win9x: MDI client returns 0
4037 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4038 ok(active_child == mdi_child2 || /* win2k */
4039 !active_child, /* win9x */
4040 "wrong active MDI child %p\n", active_child);
4041 flush_sequence();
4043 ShowWindow(mdi_child, SW_MAXIMIZE);
4044 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4045 flush_sequence();
4047 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4048 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4050 trace("re-creating maximized visible MDI child window 2\n");
4051 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4052 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4053 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4054 mdi_client, 0, GetModuleHandleA(0), NULL);
4055 assert(mdi_child2);
4056 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
4057 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
4058 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4060 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4061 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4063 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4064 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4065 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4066 flush_sequence();
4068 SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
4069 ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
4070 ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
4072 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4073 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4074 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4076 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4077 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4078 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4079 flush_sequence();
4081 DestroyWindow(mdi_child);
4082 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4084 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4085 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4087 /* Win2k: MDI client still returns a just destroyed child as active
4088 * Win9x: MDI client returns 0
4090 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4091 ok(active_child == mdi_child || /* win2k */
4092 !active_child, /* win9x */
4093 "wrong active MDI child %p\n", active_child);
4094 flush_sequence();
4096 trace("creating maximized invisible MDI child window\n");
4097 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4098 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
4099 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4100 mdi_client, 0, GetModuleHandleA(0), NULL);
4101 assert(mdi_child2);
4102 ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE);
4103 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
4104 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
4105 ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
4107 /* Win2k: MDI client still returns a just destroyed child as active
4108 * Win9x: MDI client returns 0
4110 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4111 ok(active_child == mdi_child || /* win2k */
4112 !active_child || active_child == mdi_child2, /* win9x */
4113 "wrong active MDI child %p\n", active_child);
4114 flush_sequence();
4116 trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
4117 ShowWindow(mdi_child2, SW_MAXIMIZE);
4118 ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
4119 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
4120 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4121 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
4123 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4124 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4125 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4126 flush_sequence();
4128 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
4129 flush_sequence();
4131 /* end of test for maximized MDI children */
4132 SetFocus(0);
4133 flush_sequence();
4134 trace("creating maximized visible MDI child window 1(Switch test)\n");
4135 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4136 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4137 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4138 mdi_client, 0, GetModuleHandleA(0), NULL);
4139 assert(mdi_child);
4140 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
4141 ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
4143 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
4144 ok(GetFocus() == mdi_child || /* win2k */
4145 GetFocus() == 0, /* win9x */
4146 "wrong focus window %p(Switch test)\n", GetFocus());
4148 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4149 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
4150 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
4151 flush_sequence();
4153 trace("creating maximized visible MDI child window 2(Switch test)\n");
4154 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4155 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4156 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4157 mdi_client, 0, GetModuleHandleA(0), NULL);
4158 assert(mdi_child2);
4159 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
4161 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
4162 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
4164 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
4165 ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
4167 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4168 ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
4169 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
4170 flush_sequence();
4172 trace("Switch child window.\n");
4173 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
4174 ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
4175 trace("end of test for switch maximized MDI children\n");
4176 flush_sequence();
4178 /* Prepare for switching test of not maximized MDI children */
4179 ShowWindow( mdi_child, SW_NORMAL );
4180 ok(!IsZoomed(mdi_child), "wrong zoomed state for %p(Switch test)\n", mdi_child);
4181 ok(!IsZoomed(mdi_child2), "wrong zoomed state for %p(Switch test)\n", mdi_child2);
4182 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
4183 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
4184 flush_sequence();
4186 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0);
4187 ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE);
4188 trace("end of test for switch not maximized MDI children\n");
4189 flush_sequence();
4191 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
4192 flush_sequence();
4194 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
4195 flush_sequence();
4197 SetFocus(0);
4198 flush_sequence();
4199 /* end of tests for switch maximized/not maximized MDI children */
4201 mdi_cs.szClass = "MDI_child_Class";
4202 mdi_cs.szTitle = "MDI child";
4203 mdi_cs.hOwner = GetModuleHandleA(0);
4204 mdi_cs.x = 0;
4205 mdi_cs.y = 0;
4206 mdi_cs.cx = CW_USEDEFAULT;
4207 mdi_cs.cy = CW_USEDEFAULT;
4208 mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
4209 mdi_cs.lParam = 0;
4210 mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
4211 ok(mdi_child != 0, "MDI child creation failed\n");
4212 ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
4214 ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
4216 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4217 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4219 ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
4220 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4221 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4223 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4224 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4225 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4226 flush_sequence();
4228 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
4229 ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
4231 ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
4232 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4233 ok(!active_child, "wrong active MDI child %p\n", active_child);
4235 SetFocus(0);
4236 flush_sequence();
4238 val = GetWindowLongA(mdi_client, 0);
4239 ok(val == 0xdeadbeef || broken(val == 0) /* >= Win Vista */, "Expected 0xdeadbeef, got 0x%x\n", val);
4240 DestroyWindow(mdi_client);
4241 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
4243 /* test maximization of MDI child with invisible parent */
4244 client_cs.hWindowMenu = 0;
4245 mdi_client = CreateWindowA("MDI_client_class",
4246 NULL,
4247 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
4248 0, 0, 660, 430,
4249 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
4250 ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
4252 ShowWindow(mdi_client, SW_HIDE);
4253 ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
4255 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4256 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
4257 0, 0, 650, 440,
4258 mdi_client, 0, GetModuleHandleA(0), NULL);
4259 ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
4261 SendMessageA(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
4262 ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
4263 zoomed = IsZoomed(mdi_child);
4264 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4266 ShowWindow(mdi_client, SW_SHOW);
4267 ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
4269 DestroyWindow(mdi_child);
4270 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
4272 /* end of test for maximization of MDI child with invisible parent */
4274 DestroyWindow(mdi_client);
4275 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
4277 DestroyWindow(mdi_frame);
4278 ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
4280 /************************* End of MDI test **********************************/
4282 static void test_WM_SETREDRAW(HWND hwnd)
4284 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
4286 flush_events();
4287 flush_sequence();
4289 SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
4290 ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
4292 ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
4293 ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
4295 flush_sequence();
4296 SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
4297 ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
4299 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4300 ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
4302 /* restore original WS_VISIBLE state */
4303 SetWindowLongA(hwnd, GWL_STYLE, style);
4305 flush_events();
4306 flush_sequence();
4309 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4311 struct recvd_message msg;
4313 if (ignore_message( message )) return 0;
4315 switch (message)
4317 /* ignore */
4318 case WM_MOUSEMOVE:
4319 case WM_NCMOUSEMOVE:
4320 case WM_NCMOUSELEAVE:
4321 case WM_SETCURSOR:
4322 return 0;
4323 case WM_NCHITTEST:
4324 return HTCLIENT;
4327 msg.hwnd = hwnd;
4328 msg.message = message;
4329 msg.flags = sent|wparam|lparam;
4330 msg.wParam = wParam;
4331 msg.lParam = lParam;
4332 msg.descr = "dialog";
4333 add_message(&msg);
4335 if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
4336 if (message == WM_TIMER) EndDialog( hwnd, 0 );
4337 return 0;
4340 static INT_PTR CALLBACK TestModalDlgProc2(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4342 struct recvd_message msg;
4344 if (ignore_message( message )) return 0;
4346 switch (message)
4348 /* ignore */
4349 case WM_MOUSEMOVE:
4350 case WM_NCMOUSEMOVE:
4351 case WM_NCMOUSELEAVE:
4352 case WM_SETCURSOR:
4353 return 0;
4354 case WM_NCHITTEST:
4355 return HTCLIENT;
4358 msg.hwnd = hwnd;
4359 msg.message = message;
4360 msg.flags = sent|wparam|lparam;
4361 msg.wParam = wParam;
4362 msg.lParam = lParam;
4363 msg.descr = "dialog";
4364 add_message(&msg);
4366 if (message == WM_INITDIALOG) EndDialog( hwnd, 0 );
4367 return 0;
4370 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4372 DWORD style, exstyle;
4373 INT xmin, xmax;
4374 BOOL ret;
4376 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4377 style = GetWindowLongA(hwnd, GWL_STYLE);
4378 /* do not be confused by WS_DLGFRAME set */
4379 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4381 if (clear) ok(style & clear, "style %08x should be set\n", clear);
4382 if (set) ok(!(style & set), "style %08x should not be set\n", set);
4384 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4385 ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
4386 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4387 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
4388 else
4389 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
4391 style = GetWindowLongA(hwnd, GWL_STYLE);
4392 if (set) ok(style & set, "style %08x should be set\n", set);
4393 if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4395 /* a subsequent call should do nothing */
4396 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4397 ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
4398 ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4400 xmin = 0xdeadbeef;
4401 xmax = 0xdeadbeef;
4402 ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
4403 ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
4404 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4405 ok(xmin == min, "unexpected min scroll value %d\n", xmin);
4406 ok(xmax == max, "unexpected max scroll value %d\n", xmax);
4409 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4411 DWORD style, exstyle;
4412 SCROLLINFO si;
4413 BOOL ret;
4415 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4416 style = GetWindowLongA(hwnd, GWL_STYLE);
4417 /* do not be confused by WS_DLGFRAME set */
4418 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4420 if (clear) ok(style & clear, "style %08x should be set\n", clear);
4421 if (set) ok(!(style & set), "style %08x should not be set\n", set);
4423 si.cbSize = sizeof(si);
4424 si.fMask = SIF_RANGE;
4425 si.nMin = min;
4426 si.nMax = max;
4427 SetScrollInfo(hwnd, ctl, &si, TRUE);
4428 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4429 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
4430 else
4431 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
4433 style = GetWindowLongA(hwnd, GWL_STYLE);
4434 if (set) ok(style & set, "style %08x should be set\n", set);
4435 if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4437 /* a subsequent call should do nothing */
4438 SetScrollInfo(hwnd, ctl, &si, TRUE);
4439 if (style & WS_HSCROLL)
4440 ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4441 else if (style & WS_VSCROLL)
4442 ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4443 else
4444 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4446 si.fMask = SIF_PAGE;
4447 si.nPage = 5;
4448 SetScrollInfo(hwnd, ctl, &si, FALSE);
4449 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4451 si.fMask = SIF_POS;
4452 si.nPos = max - 1;
4453 SetScrollInfo(hwnd, ctl, &si, FALSE);
4454 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4456 si.fMask = SIF_RANGE;
4457 si.nMin = 0xdeadbeef;
4458 si.nMax = 0xdeadbeef;
4459 ret = GetScrollInfo(hwnd, ctl, &si);
4460 ok( ret, "GetScrollInfo error %d\n", GetLastError());
4461 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4462 ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
4463 ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
4466 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
4467 static void test_scroll_messages(HWND hwnd)
4469 SCROLLINFO si;
4470 INT min, max;
4471 BOOL ret;
4473 flush_events();
4474 flush_sequence();
4476 min = 0xdeadbeef;
4477 max = 0xdeadbeef;
4478 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4479 ok( ret, "GetScrollRange error %d\n", GetLastError());
4480 if (sequence->message != WmGetScrollRangeSeq[0].message)
4481 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4482 /* values of min and max are undefined */
4483 flush_sequence();
4485 ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
4486 ok( ret, "SetScrollRange error %d\n", GetLastError());
4487 if (sequence->message != WmSetScrollRangeSeq[0].message)
4488 trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4489 flush_sequence();
4491 min = 0xdeadbeef;
4492 max = 0xdeadbeef;
4493 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4494 ok( ret, "GetScrollRange error %d\n", GetLastError());
4495 if (sequence->message != WmGetScrollRangeSeq[0].message)
4496 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4497 /* values of min and max are undefined */
4498 flush_sequence();
4500 si.cbSize = sizeof(si);
4501 si.fMask = SIF_RANGE;
4502 si.nMin = 20;
4503 si.nMax = 160;
4504 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4505 if (sequence->message != WmSetScrollRangeSeq[0].message)
4506 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4507 flush_sequence();
4509 si.fMask = SIF_PAGE;
4510 si.nPage = 10;
4511 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4512 if (sequence->message != WmSetScrollRangeSeq[0].message)
4513 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4514 flush_sequence();
4516 si.fMask = SIF_POS;
4517 si.nPos = 20;
4518 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4519 if (sequence->message != WmSetScrollRangeSeq[0].message)
4520 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4521 flush_sequence();
4523 si.fMask = SIF_RANGE;
4524 si.nMin = 0xdeadbeef;
4525 si.nMax = 0xdeadbeef;
4526 ret = GetScrollInfo(hwnd, SB_CTL, &si);
4527 ok( ret, "GetScrollInfo error %d\n", GetLastError());
4528 if (sequence->message != WmGetScrollInfoSeq[0].message)
4529 trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4530 /* values of min and max are undefined */
4531 flush_sequence();
4533 /* set WS_HSCROLL */
4534 test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4535 /* clear WS_HSCROLL */
4536 test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4538 /* set WS_HSCROLL */
4539 test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4540 /* clear WS_HSCROLL */
4541 test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4543 /* set WS_VSCROLL */
4544 test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4545 /* clear WS_VSCROLL */
4546 test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4548 /* set WS_VSCROLL */
4549 test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4550 /* clear WS_VSCROLL */
4551 test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4554 static void test_showwindow(void)
4556 HWND hwnd, hchild;
4557 RECT rc;
4559 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4560 100, 100, 200, 200, 0, 0, 0, NULL);
4561 ok (hwnd != 0, "Failed to create overlapped window\n");
4562 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4563 0, 0, 10, 10, hwnd, 0, 0, NULL);
4564 ok (hchild != 0, "Failed to create child\n");
4565 flush_sequence();
4567 /* ShowWindow( SW_SHOWNA) for invisible top level window */
4568 trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
4569 ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4570 ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", FALSE);
4572 /* ShowWindow( SW_SHOWNA) for now visible top level window */
4573 trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
4574 ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4575 ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
4576 /* back to invisible */
4577 ShowWindow(hchild, SW_HIDE);
4578 ShowWindow(hwnd, SW_HIDE);
4579 flush_sequence();
4580 /* ShowWindow(SW_SHOWNA) with child and parent invisible */
4581 trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
4582 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4583 ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
4584 /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */
4585 ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
4586 flush_sequence();
4587 trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
4588 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4589 ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
4590 /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
4591 ShowWindow( hwnd, SW_SHOW);
4592 flush_sequence();
4593 trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
4594 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4595 ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
4597 /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
4598 ShowWindow( hchild, SW_HIDE);
4599 flush_sequence();
4600 trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
4601 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4602 ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
4604 SetCapture(hchild);
4605 ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
4606 DestroyWindow(hchild);
4607 ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
4609 DestroyWindow(hwnd);
4610 flush_sequence();
4612 /* Popup windows */
4613 /* Test 1:
4614 * 1. Create invisible maximized popup window.
4615 * 2. Move and resize it.
4616 * 3. Show it maximized.
4618 trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4619 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4620 100, 100, 200, 200, 0, 0, 0, NULL);
4621 ok (hwnd != 0, "Failed to create popup window\n");
4622 ok(IsZoomed(hwnd), "window should be maximized\n");
4623 ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4625 GetWindowRect(hwnd, &rc);
4626 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4627 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4628 "Invalid maximized size before ShowWindow %s\n", wine_dbgstr_rect( &rc ));
4629 /* Reset window's size & position */
4630 SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
4631 ok(IsZoomed(hwnd), "window should be maximized\n");
4632 flush_sequence();
4634 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4635 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4636 ok(IsZoomed(hwnd), "window should be maximized\n");
4637 ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
4639 GetWindowRect(hwnd, &rc);
4640 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4641 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4642 "Invalid maximized size after ShowWindow %s\n", wine_dbgstr_rect( &rc ));
4643 DestroyWindow(hwnd);
4644 flush_sequence();
4646 /* Test again, this time the NC_PAINT message */
4647 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4648 100, 100, 200, 200, 0, 0, 0, NULL);
4649 ok (hwnd != 0, "Failed to create popup window\n");
4650 SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
4651 flush_sequence();
4652 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4653 ok_sequence(WmShowMaxPopupResizedSeq_todo,
4654 "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup TODO", FALSE);
4655 DestroyWindow(hwnd);
4656 flush_sequence();
4658 /* Test 2:
4659 * 1. Create invisible maximized popup window.
4660 * 2. Show it maximized.
4662 trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4663 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4664 100, 100, 200, 200, 0, 0, 0, NULL);
4665 ok (hwnd != 0, "Failed to create popup window\n");
4666 ok(IsZoomed(hwnd), "window should be maximized\n");
4667 ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4669 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4670 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4671 ok(IsZoomed(hwnd), "window should be maximized\n");
4672 ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
4673 DestroyWindow(hwnd);
4674 flush_sequence();
4676 /* Test 3:
4677 * 1. Create visible maximized popup window.
4679 trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
4680 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
4681 100, 100, 200, 200, 0, 0, 0, NULL);
4682 ok (hwnd != 0, "Failed to create popup window\n");
4683 ok(IsZoomed(hwnd), "window should be maximized\n");
4684 ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4685 DestroyWindow(hwnd);
4686 flush_sequence();
4688 /* Test 4:
4689 * 1. Create visible popup window.
4690 * 2. Maximize it.
4692 trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
4693 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
4694 100, 100, 200, 200, 0, 0, 0, NULL);
4695 ok (hwnd != 0, "Failed to create popup window\n");
4696 ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
4697 ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
4699 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
4700 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4701 ok(IsZoomed(hwnd), "window should be maximized\n");
4702 ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
4703 DestroyWindow(hwnd);
4704 flush_sequence();
4707 static void test_sys_menu(void)
4709 HWND hwnd;
4710 HMENU hmenu;
4711 UINT state;
4713 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4714 100, 100, 200, 200, 0, 0, 0, NULL);
4715 ok (hwnd != 0, "Failed to create overlapped window\n");
4717 flush_sequence();
4719 /* test existing window without CS_NOCLOSE style */
4720 hmenu = GetSystemMenu(hwnd, FALSE);
4721 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4723 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4724 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4725 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4727 EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
4728 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4730 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4731 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4732 ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
4734 EnableMenuItem(hmenu, SC_CLOSE, 0);
4735 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4737 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4738 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4739 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4741 /* test whether removing WS_SYSMENU destroys a system menu */
4742 SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
4743 SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4744 flush_sequence();
4745 hmenu = GetSystemMenu(hwnd, FALSE);
4746 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4748 DestroyWindow(hwnd);
4750 /* test new window with CS_NOCLOSE style */
4751 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4752 100, 100, 200, 200, 0, 0, 0, NULL);
4753 ok (hwnd != 0, "Failed to create overlapped window\n");
4755 hmenu = GetSystemMenu(hwnd, FALSE);
4756 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4758 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4759 ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4761 DestroyWindow(hwnd);
4763 /* test new window without WS_SYSMENU style */
4764 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
4765 100, 100, 200, 200, 0, 0, 0, NULL);
4766 ok(hwnd != 0, "Failed to create overlapped window\n");
4768 hmenu = GetSystemMenu(hwnd, FALSE);
4769 ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
4771 DestroyWindow(hwnd);
4774 /* For shown WS_OVERLAPPEDWINDOW */
4775 static const struct message WmSetIcon_1[] = {
4776 { WM_SETICON, sent },
4777 { 0x00AE, sent|defwinproc|optional }, /* XP */
4778 { WM_GETTEXT, sent|defwinproc|optional },
4779 { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
4780 { 0 }
4783 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
4784 static const struct message WmSetIcon_2[] = {
4785 { WM_SETICON, sent },
4786 { 0 }
4789 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
4790 static const struct message WmInitEndSession[] = {
4791 { 0x003B, sent },
4792 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4793 { 0 }
4796 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
4797 static const struct message WmInitEndSession_2[] = {
4798 { 0x003B, sent },
4799 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4800 { 0 }
4803 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
4804 static const struct message WmInitEndSession_3[] = {
4805 { 0x003B, sent },
4806 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4807 { 0 }
4810 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
4811 static const struct message WmInitEndSession_4[] = {
4812 { 0x003B, sent },
4813 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4814 { 0 }
4817 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
4818 static const struct message WmInitEndSession_5[] = {
4819 { 0x003B, sent },
4820 { WM_ENDSESSION, sent|defwinproc/*|wparam*/|lparam, 1, ENDSESSION_LOGOFF },
4821 { 0 }
4824 static const struct message WmOptionalPaint[] = {
4825 { WM_PAINT, sent|optional },
4826 { WM_NCPAINT, sent|beginpaint|optional },
4827 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4828 { WM_ERASEBKGND, sent|beginpaint|optional },
4829 { 0 }
4832 static const struct message WmZOrder[] = {
4833 { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 },
4834 { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 },
4835 { HCBT_ACTIVATE, hook },
4836 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
4837 { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 },
4838 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 },
4839 { WM_GETTEXT, sent|optional },
4840 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
4841 { WM_ACTIVATEAPP, sent|wparam, 1, 0 },
4842 { WM_NCACTIVATE, sent|lparam, 1, 0 },
4843 { WM_GETTEXT, sent|defwinproc|optional },
4844 { WM_GETTEXT, sent|defwinproc|optional },
4845 { WM_ACTIVATE, sent|wparam|lparam, 1, 0 },
4846 { HCBT_SETFOCUS, hook },
4847 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4848 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4849 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4850 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
4851 { WM_GETTEXT, sent|optional },
4852 { WM_NCCALCSIZE, sent|optional },
4853 { 0 }
4856 static void CALLBACK apc_test_proc(ULONG_PTR param)
4858 /* nothing */
4861 static void test_MsgWaitForMultipleObjects(HWND hwnd)
4863 DWORD ret;
4864 MSG msg;
4866 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4867 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4869 PostMessageA(hwnd, WM_USER, 0, 0);
4871 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4872 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4874 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4875 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4877 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4878 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4880 PostMessageA(hwnd, WM_USER, 0, 0);
4882 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4883 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4885 ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
4886 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4888 /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
4889 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4890 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4892 PostMessageA(hwnd, WM_USER, 0, 0);
4894 /* new incoming message causes it to become signaled again */
4895 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4896 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4898 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4899 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4900 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4901 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4903 /* MWMO_INPUTAVAILABLE should succeed even if the message was already seen */
4904 PostMessageA( hwnd, WM_USER, 0, 0 );
4905 ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
4906 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4908 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_INPUTAVAILABLE );
4909 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
4911 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4912 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4914 /* without MWMO_ALERTABLE the result is never WAIT_IO_COMPLETION */
4915 ret = QueueUserAPC( apc_test_proc, GetCurrentThread(), 0 );
4916 ok(ret, "QueueUserAPC failed %u\n", GetLastError());
4918 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, 0 );
4919 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
4921 /* but even with MWMO_ALERTABLE window events are preferred */
4922 PostMessageA( hwnd, WM_USER, 0, 0 );
4924 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_ALERTABLE );
4925 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
4927 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4928 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4930 /* the APC call is still queued */
4931 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_ALERTABLE );
4932 ok(ret == WAIT_IO_COMPLETION, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
4935 static void test_WM_DEVICECHANGE(HWND hwnd)
4937 DWORD ret;
4938 MSG msg;
4939 int i;
4940 static const WPARAM wparams[] = {0,
4941 DBT_DEVNODES_CHANGED,
4942 DBT_QUERYCHANGECONFIG,
4943 DBT_CONFIGCHANGED,
4944 DBT_CONFIGCHANGECANCELED,
4945 DBT_NO_DISK_SPACE,
4946 DBT_LOW_DISK_SPACE,
4947 DBT_CONFIGMGPRIVATE, /* 0x7fff */
4948 DBT_DEVICEARRIVAL, /* 0x8000 */
4949 DBT_DEVICEQUERYREMOVE,
4950 DBT_DEVICEQUERYREMOVEFAILED,
4951 DBT_DEVICEREMOVEPENDING,
4952 DBT_DEVICEREMOVECOMPLETE,
4953 DBT_DEVICETYPESPECIFIC,
4954 DBT_CUSTOMEVENT};
4956 for (i = 0; i < sizeof(wparams)/sizeof(wparams[0]); i++)
4958 SetLastError(0xdeadbeef);
4959 ret = PostMessageA(hwnd, WM_DEVICECHANGE, wparams[i], 0);
4960 if (wparams[i] & 0x8000)
4962 ok(ret == FALSE, "PostMessage should returned %d\n", ret);
4963 ok(GetLastError() == ERROR_MESSAGE_SYNC_ONLY, "PostMessage error %08x\n", GetLastError());
4965 else
4967 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4968 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4969 memset(&msg, 0, sizeof(msg));
4970 ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should succeed\n");
4971 ok(msg.message == WM_DEVICECHANGE, "got %04x instead of WM_DEVICECHANGE\n", msg.message);
4976 static DWORD CALLBACK show_window_thread(LPVOID arg)
4978 HWND hwnd = arg;
4980 /* function will not return if ShowWindow(SW_HIDE) calls SendMessage() */
4981 ok(ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow(SW_HIDE) expected FALSE\n");
4983 return 0;
4986 /* Helper function to easier test SetWindowPos messages */
4987 #define test_msg_setpos( expected_list, flags, todo ) \
4988 test_msg_setpos_( (expected_list), (flags), (todo), __FILE__, __LINE__)
4989 static void test_msg_setpos_(const struct message *expected_list, UINT flags, BOOL todo, const char *file, int line)
4991 HWND hwnd;
4993 flush_events();
4994 flush_sequence();
4995 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
4996 10, 10, 100, 100, NULL, 0, 0, NULL );
4997 ok (hwnd != 0, "Failed to create popup window\n");
4998 SetWindowPos(hwnd, NULL, 0, 0, 100, 100, flags);
4999 ok_sequence_(expected_list, "SetWindowPos:show_popup_first_show_window", todo, file, line);
5000 DestroyWindow(hwnd);
5003 /* test if we receive the right sequence of messages */
5004 static void test_messages(void)
5006 DWORD tid;
5007 HANDLE hthread;
5008 HWND hwnd, hparent, hchild;
5009 HWND hchild2, hbutton;
5010 HMENU hmenu;
5011 MSG msg;
5012 LRESULT res;
5013 POINT pos;
5014 BOOL ret;
5016 flush_sequence();
5018 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5019 100, 100, 200, 200, 0, 0, 0, NULL);
5020 ok (hwnd != 0, "Failed to create overlapped window\n");
5021 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
5023 /* test ShowWindow(SW_HIDE) on a newly created invisible window */
5024 ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
5025 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
5027 /* test WM_SETREDRAW on a not visible top level window */
5028 test_WM_SETREDRAW(hwnd);
5030 SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5031 flush_events();
5032 ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
5033 ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
5035 ok(GetActiveWindow() == hwnd, "window should be active\n");
5036 ok(GetFocus() == hwnd, "window should have input focus\n");
5037 ShowWindow(hwnd, SW_HIDE);
5038 flush_events();
5039 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5041 /* test ShowWindow(SW_HIDE) on a hidden window - single threaded */
5042 ok(ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow(SW_HIDE) expected FALSE\n");
5043 flush_events();
5044 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5046 /* test ShowWindow(SW_HIDE) on a hidden window - multi-threaded */
5047 hthread = CreateThread(NULL, 0, show_window_thread, hwnd, 0, &tid);
5048 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
5049 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5050 CloseHandle(hthread);
5051 flush_events();
5052 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5054 ShowWindow(hwnd, SW_SHOW);
5055 flush_events();
5056 ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
5058 ShowWindow(hwnd, SW_HIDE);
5059 flush_events();
5060 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5062 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5063 flush_events();
5064 ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
5065 flush_sequence();
5067 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZE)
5069 ShowWindow(hwnd, SW_RESTORE);
5070 flush_events();
5071 ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
5072 flush_sequence();
5075 ShowWindow(hwnd, SW_MINIMIZE);
5076 flush_events();
5077 ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
5078 flush_sequence();
5080 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)
5082 ShowWindow(hwnd, SW_RESTORE);
5083 flush_events();
5084 ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
5085 flush_sequence();
5088 ShowWindow(hwnd, SW_SHOW);
5089 flush_events();
5090 ok_sequence(WmOptionalPaint, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
5092 SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5093 ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
5094 ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
5095 ok(GetActiveWindow() == hwnd, "window should still be active\n");
5097 /* test WM_SETREDRAW on a visible top level window */
5098 ShowWindow(hwnd, SW_SHOW);
5099 flush_events();
5100 test_WM_SETREDRAW(hwnd);
5102 trace("testing scroll APIs on a visible top level window %p\n", hwnd);
5103 test_scroll_messages(hwnd);
5105 /* test resizing and moving */
5106 SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
5107 ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
5108 flush_events();
5109 flush_sequence();
5110 SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
5111 ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
5112 flush_events();
5113 flush_sequence();
5114 SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER|SWP_NOACTIVATE );
5115 ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
5116 flush_events();
5117 flush_sequence();
5119 /* popups don't get WM_GETMINMAXINFO */
5120 SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
5121 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
5122 flush_sequence();
5123 SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
5124 ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
5126 DestroyWindow(hwnd);
5127 ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
5129 /* Test if windows are correctly drawn when first shown */
5131 /* Visible, redraw */
5132 flush_events();
5133 flush_sequence();
5134 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5135 10, 10, 100, 100, NULL, 0, 0, NULL );
5136 ok (hwnd != 0, "Failed to create popup window\n");
5137 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
5138 ok_sequence(WmShowPopupFirstDrawSeq_1, "RedrawWindow:show_popup_first_draw_visible", TRUE);
5139 DestroyWindow(hwnd);
5141 /* Invisible, show, message */
5142 flush_events();
5143 flush_sequence();
5144 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5145 10, 10, 100, 100, NULL, 0, 0, NULL );
5146 ok (hwnd != 0, "Failed to create popup window\n");
5147 ShowWindow(hwnd, SW_SHOW);
5148 SendMessageW(hwnd, WM_PAINT, 0, 0);
5149 ok_sequence(WmShowPopupFirstDrawSeq_1, "RedrawWindow:show_popup_first_draw_show", TRUE);
5150 DestroyWindow(hwnd);
5152 /* Invisible, show maximized, redraw */
5153 flush_events();
5154 flush_sequence();
5155 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5156 10, 10, 100, 100, NULL, 0, 0, NULL );
5157 ok (hwnd != 0, "Failed to create popup window\n");
5158 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5159 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
5160 ok_sequence(WmShowPopupFirstDrawSeq_2, "RedrawWindow:show_popup_first_draw_show_maximized", TRUE);
5161 DestroyWindow(hwnd);
5163 /* Test SetWindowPos */
5164 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW, TRUE);
5165 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, 0, FALSE);
5166 test_msg_setpos(WmFirstDrawSetWindowPosSeq3,
5167 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER, TRUE);
5169 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOSIZE, TRUE);
5170 test_msg_setpos(WmFirstDrawSetWindowPosSeq4, SWP_SHOWWINDOW | SWP_NOMOVE, TRUE);
5171 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCLIENTSIZE, TRUE);
5172 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCLIENTMOVE, TRUE);
5173 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOZORDER, TRUE);
5175 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE, FALSE);
5176 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOCLIENTMOVE, TRUE);
5177 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOCLIENTSIZE, TRUE);
5178 test_msg_setpos(WmFirstDrawSetWindowPosSeq5, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOMOVE, FALSE);
5179 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOSIZE, FALSE);
5180 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOZORDER, FALSE);
5182 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS, TRUE);
5183 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOCLIENTMOVE, TRUE);
5184 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOCLIENTSIZE, TRUE);
5185 test_msg_setpos(WmFirstDrawSetWindowPosSeq4, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOMOVE, TRUE);
5186 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOSIZE, TRUE);
5187 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOZORDER, TRUE);
5189 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW, FALSE);
5190 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCLIENTMOVE, TRUE);
5191 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCLIENTSIZE, TRUE);
5192 test_msg_setpos(WmFirstDrawSetWindowPosSeq5, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOMOVE, FALSE);
5193 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOSIZE, FALSE);
5194 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOZORDER, FALSE);
5196 /* Test SetWindowPos with child windows */
5197 flush_events();
5198 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5199 100, 100, 200, 200, 0, 0, 0, NULL);
5200 ok (hparent != 0, "Failed to create parent window\n");
5202 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5203 0, 0, 10, 10, hparent, 0, 0, NULL);
5204 ok (hchild != 0, "Failed to create child window\n");
5205 flush_sequence();
5206 SetWindowPos(hparent, NULL, 0, 0, 100, 100, SWP_SHOWWINDOW);
5207 ok_sequence(WmFirstDrawChildSeq1, /* Expect no messages for the child */
5208 "SetWindowPos:show_popup_first_show_window_child1", FALSE);
5209 DestroyWindow(hchild);
5210 DestroyWindow(hparent);
5212 flush_events();
5213 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN,
5214 100, 100, 200, 200, 0, 0, 0, NULL);
5215 ok (hparent != 0, "Failed to create parent window\n");
5217 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5218 0, 0, 10, 10, hparent, 0, 0, NULL);
5219 ok (hchild != 0, "Failed to create child window\n");
5220 flush_sequence();
5221 SetWindowPos(hparent, NULL, 0, 0, 100, 100, SWP_SHOWWINDOW);
5222 ok_sequence(WmFirstDrawChildSeq2, /* Expect child to be redrawn */
5223 "SetWindowPos:show_popup_first_show_window_child2", TRUE);
5224 DestroyWindow(hchild);
5225 DestroyWindow(hparent);
5227 /* Test message sequence for extreme position and size */
5229 flush_sequence();
5230 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5231 -10, -10, 10000, 10000, NULL, 0, 0, NULL );
5232 ok (hwnd != 0, "Failed to create popup window\n");
5233 ok_sequence(WmShowPopupExtremeLocationSeq, "RedrawWindow:show_popup_extreme_location", TRUE);
5234 DestroyWindow(hwnd);
5237 /* Test child windows */
5239 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5240 100, 100, 200, 200, 0, 0, 0, NULL);
5241 ok (hparent != 0, "Failed to create parent window\n");
5242 flush_sequence();
5244 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
5245 0, 0, 10, 10, hparent, 0, 0, NULL);
5246 ok (hchild != 0, "Failed to create child window\n");
5247 ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
5248 DestroyWindow(hchild);
5249 flush_sequence();
5251 /* visible child window with a caption */
5252 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
5253 WS_CHILD | WS_VISIBLE | WS_CAPTION,
5254 0, 0, 10, 10, hparent, 0, 0, NULL);
5255 ok (hchild != 0, "Failed to create child window\n");
5256 ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
5258 trace("testing scroll APIs on a visible child window %p\n", hchild);
5259 test_scroll_messages(hchild);
5261 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5262 ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
5264 DestroyWindow(hchild);
5265 flush_sequence();
5267 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5268 0, 0, 10, 10, hparent, 0, 0, NULL);
5269 ok (hchild != 0, "Failed to create child window\n");
5270 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
5272 hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
5273 100, 100, 50, 50, hparent, 0, 0, NULL);
5274 ok (hchild2 != 0, "Failed to create child2 window\n");
5275 flush_sequence();
5277 hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
5278 0, 100, 50, 50, hchild, 0, 0, NULL);
5279 ok (hbutton != 0, "Failed to create button window\n");
5281 /* test WM_SETREDRAW on a not visible child window */
5282 test_WM_SETREDRAW(hchild);
5284 ShowWindow(hchild, SW_SHOW);
5285 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5287 /* check parent messages too */
5288 log_all_parent_messages++;
5289 ShowWindow(hchild, SW_HIDE);
5290 ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
5291 log_all_parent_messages--;
5293 ShowWindow(hchild, SW_SHOW);
5294 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5296 ShowWindow(hchild, SW_HIDE);
5297 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
5299 ShowWindow(hchild, SW_SHOW);
5300 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5302 /* test WM_SETREDRAW on a visible child window */
5303 test_WM_SETREDRAW(hchild);
5305 log_all_parent_messages++;
5306 MoveWindow(hchild, 10, 10, 20, 20, TRUE);
5307 ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
5308 log_all_parent_messages--;
5310 ShowWindow(hchild, SW_HIDE);
5311 flush_sequence();
5312 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5313 ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
5315 ShowWindow(hchild, SW_HIDE);
5316 flush_sequence();
5317 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
5318 ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
5320 /* DestroyWindow sequence below expects that a child has focus */
5321 SetFocus(hchild);
5322 flush_sequence();
5324 DestroyWindow(hchild);
5325 ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
5326 DestroyWindow(hchild2);
5327 DestroyWindow(hbutton);
5329 flush_sequence();
5330 hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
5331 0, 0, 100, 100, hparent, 0, 0, NULL);
5332 ok (hchild != 0, "Failed to create child popup window\n");
5333 ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
5334 DestroyWindow(hchild);
5336 /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
5337 flush_sequence();
5338 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
5339 0, 0, 100, 100, hparent, 0, 0, NULL);
5340 ok (hchild != 0, "Failed to create popup window\n");
5341 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
5342 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5343 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
5344 flush_sequence();
5345 ShowWindow(hchild, SW_SHOW);
5346 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
5347 flush_sequence();
5348 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5349 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
5350 flush_sequence();
5351 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5352 ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
5353 DestroyWindow(hchild);
5355 /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
5356 * changes nothing in message sequences.
5358 flush_sequence();
5359 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5360 0, 0, 100, 100, hparent, 0, 0, NULL);
5361 ok (hchild != 0, "Failed to create popup window\n");
5362 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
5363 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5364 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
5365 flush_sequence();
5366 ShowWindow(hchild, SW_SHOW);
5367 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
5368 flush_sequence();
5369 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5370 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
5371 DestroyWindow(hchild);
5373 flush_sequence();
5374 hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
5375 0, 0, 100, 100, hparent, 0, 0, NULL);
5376 ok(hwnd != 0, "Failed to create custom dialog window\n");
5377 ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
5379 if(0) {
5380 trace("testing scroll APIs on a visible dialog %p\n", hwnd);
5381 test_scroll_messages(hwnd);
5384 flush_sequence();
5386 test_def_id = TRUE;
5387 SendMessageA(hwnd, WM_NULL, 0, 0);
5389 flush_sequence();
5390 after_end_dialog = TRUE;
5391 EndDialog( hwnd, 0 );
5392 ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
5394 DestroyWindow(hwnd);
5395 after_end_dialog = FALSE;
5396 test_def_id = FALSE;
5398 ok(GetCursorPos(&pos), "GetCursorPos failed\n");
5399 ok(SetCursorPos(109, 109), "SetCursorPos failed\n");
5401 hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP|WS_CHILD,
5402 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
5403 ok(hwnd != 0, "Failed to create custom dialog window\n");
5404 flush_sequence();
5405 trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
5406 ShowWindow(hwnd, SW_SHOW);
5407 ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
5409 flush_events();
5410 flush_sequence();
5411 ret = DrawMenuBar(hwnd);
5412 ok(ret, "DrawMenuBar failed: %d\n", GetLastError());
5413 flush_events();
5414 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
5415 ok(SetCursorPos(pos.x, pos.y), "SetCursorPos failed\n");
5417 DestroyWindow(hwnd);
5419 hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_CHILD|WS_VISIBLE,
5420 0, 0, 100, 100, hparent, 0, GetModuleHandleA(0), NULL);
5421 ok(hwnd != 0, "Failed to create custom dialog window\n");
5422 flush_events();
5423 flush_sequence();
5424 ret = DrawMenuBar(hwnd);
5425 ok(ret, "DrawMenuBar failed: %d\n", GetLastError());
5426 flush_events();
5427 ok_sequence(WmEmptySeq, "DrawMenuBar for a child window", FALSE);
5429 DestroyWindow(hwnd);
5431 flush_sequence();
5432 DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
5433 ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
5435 DestroyWindow(hparent);
5436 flush_sequence();
5438 /* Message sequence for SetMenu */
5439 ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a destroyed window\n");
5440 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "last error is %d\n", GetLastError());
5441 ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
5443 hmenu = CreateMenu();
5444 ok (hmenu != 0, "Failed to create menu\n");
5445 ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
5446 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5447 100, 100, 200, 200, 0, hmenu, 0, NULL);
5448 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
5449 ok (SetMenu(hwnd, 0), "SetMenu\n");
5450 ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
5451 ok (SetMenu(hwnd, 0), "SetMenu\n");
5452 ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
5453 ShowWindow(hwnd, SW_SHOW);
5454 UpdateWindow( hwnd );
5455 flush_events();
5456 flush_sequence();
5457 ok (SetMenu(hwnd, 0), "SetMenu\n");
5458 ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
5459 ok (SetMenu(hwnd, hmenu), "SetMenu\n");
5460 ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
5462 UpdateWindow( hwnd );
5463 flush_events();
5464 flush_sequence();
5465 ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
5466 flush_events();
5467 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
5469 DestroyWindow(hwnd);
5470 flush_sequence();
5472 /* Message sequence for EnableWindow */
5473 hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5474 100, 100, 200, 200, 0, 0, 0, NULL);
5475 ok (hparent != 0, "Failed to create parent window\n");
5476 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5477 0, 0, 10, 10, hparent, 0, 0, NULL);
5478 ok (hchild != 0, "Failed to create child window\n");
5480 SetFocus(hchild);
5481 flush_events();
5482 flush_sequence();
5484 EnableWindow(hparent, FALSE);
5485 ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
5487 EnableWindow(hparent, TRUE);
5488 ok_sequence(WmEnableWindowSeq_2, "EnableWindow(TRUE)", FALSE);
5490 flush_events();
5491 flush_sequence();
5493 test_MsgWaitForMultipleObjects(hparent);
5494 test_WM_DEVICECHANGE(hparent);
5496 /* the following test causes an exception in user.exe under win9x */
5497 if (!PostMessageW( hparent, WM_USER, 0, 0 ))
5499 DestroyWindow(hparent);
5500 flush_sequence();
5501 return;
5503 PostMessageW( hparent, WM_USER+1, 0, 0 );
5504 /* PeekMessage(NULL) fails, but still removes the message */
5505 SetLastError(0xdeadbeef);
5506 ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
5507 ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
5508 GetLastError() == 0xdeadbeef, /* NT4 */
5509 "last error is %d\n", GetLastError() );
5510 ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
5511 ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
5513 DestroyWindow(hchild);
5514 DestroyWindow(hparent);
5515 flush_sequence();
5517 /* Message sequences for WM_SETICON */
5518 trace("testing WM_SETICON\n");
5519 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
5520 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5521 NULL, NULL, 0);
5522 ShowWindow(hwnd, SW_SHOW);
5523 UpdateWindow(hwnd);
5524 flush_events();
5525 flush_sequence();
5526 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5527 ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
5529 ShowWindow(hwnd, SW_HIDE);
5530 flush_events();
5531 flush_sequence();
5532 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5533 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
5534 DestroyWindow(hwnd);
5535 flush_sequence();
5537 hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
5538 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5539 NULL, NULL, 0);
5540 ShowWindow(hwnd, SW_SHOW);
5541 UpdateWindow(hwnd);
5542 flush_events();
5543 flush_sequence();
5544 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5545 ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
5547 ShowWindow(hwnd, SW_HIDE);
5548 flush_events();
5549 flush_sequence();
5550 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5551 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
5553 flush_sequence();
5554 res = SendMessageA(hwnd, 0x3B, 0x8000000b, 0);
5555 if (!res)
5557 todo_wine win_skip( "Message 0x3b not supported\n" );
5558 goto done;
5560 ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
5561 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res);
5562 res = SendMessageA(hwnd, 0x3B, 0x0000000b, 0);
5563 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
5564 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res);
5565 res = SendMessageA(hwnd, 0x3B, 0x0000000f, 0);
5566 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
5567 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res);
5569 flush_sequence();
5570 res = SendMessageA(hwnd, 0x3B, 0x80000008, 0);
5571 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
5572 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res);
5573 res = SendMessageA(hwnd, 0x3B, 0x00000008, 0);
5574 ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
5575 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res);
5577 res = SendMessageA(hwnd, 0x3B, 0x80000004, 0);
5578 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
5579 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res);
5581 res = SendMessageA(hwnd, 0x3B, 0x80000001, 0);
5582 ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
5583 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res);
5585 done:
5586 DestroyWindow(hwnd);
5587 flush_sequence();
5590 static void test_setwindowpos(void)
5592 HWND hwnd;
5593 RECT rc;
5594 LRESULT res;
5595 const INT winX = 100;
5596 const INT winY = 100;
5597 const INT sysX = GetSystemMetrics(SM_CXMINTRACK);
5599 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
5600 0, 0, winX, winY, 0,
5601 NULL, NULL, 0);
5603 GetWindowRect(hwnd, &rc);
5604 expect(sysX, rc.right);
5605 expect(winY, rc.bottom);
5607 flush_events();
5608 flush_sequence();
5609 res = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, winX, winY, 0);
5610 ok_sequence(WmZOrder, "Z-Order", TRUE);
5611 ok(res == TRUE, "SetWindowPos expected TRUE, got %ld\n", res);
5613 GetWindowRect(hwnd, &rc);
5614 expect(sysX, rc.right);
5615 expect(winY, rc.bottom);
5616 DestroyWindow(hwnd);
5619 static void invisible_parent_tests(void)
5621 HWND hparent, hchild;
5623 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
5624 100, 100, 200, 200, 0, 0, 0, NULL);
5625 ok (hparent != 0, "Failed to create parent window\n");
5626 flush_sequence();
5628 /* test showing child with hidden parent */
5630 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5631 0, 0, 10, 10, hparent, 0, 0, NULL);
5632 ok (hchild != 0, "Failed to create child window\n");
5633 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
5635 ShowWindow( hchild, SW_MINIMIZE );
5636 ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
5637 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5638 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5640 /* repeat */
5641 flush_events();
5642 flush_sequence();
5643 ShowWindow( hchild, SW_MINIMIZE );
5644 ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
5646 DestroyWindow(hchild);
5647 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5648 0, 0, 10, 10, hparent, 0, 0, NULL);
5649 flush_sequence();
5651 ShowWindow( hchild, SW_MAXIMIZE );
5652 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
5653 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5654 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5656 /* repeat */
5657 flush_events();
5658 flush_sequence();
5659 ShowWindow( hchild, SW_MAXIMIZE );
5660 ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
5662 DestroyWindow(hchild);
5663 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5664 0, 0, 10, 10, hparent, 0, 0, NULL);
5665 flush_sequence();
5667 ShowWindow( hchild, SW_RESTORE );
5668 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
5669 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5670 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5672 DestroyWindow(hchild);
5673 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5674 0, 0, 10, 10, hparent, 0, 0, NULL);
5675 flush_sequence();
5677 ShowWindow( hchild, SW_SHOWMINIMIZED );
5678 ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5679 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5680 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5682 /* repeat */
5683 flush_events();
5684 flush_sequence();
5685 ShowWindow( hchild, SW_SHOWMINIMIZED );
5686 ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5688 DestroyWindow(hchild);
5689 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5690 0, 0, 10, 10, hparent, 0, 0, NULL);
5691 flush_sequence();
5693 /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
5694 ShowWindow( hchild, SW_SHOWMAXIMIZED );
5695 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
5696 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5697 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5699 DestroyWindow(hchild);
5700 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5701 0, 0, 10, 10, hparent, 0, 0, NULL);
5702 flush_sequence();
5704 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5705 ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5706 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5707 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5709 /* repeat */
5710 flush_events();
5711 flush_sequence();
5712 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5713 ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5715 DestroyWindow(hchild);
5716 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5717 0, 0, 10, 10, hparent, 0, 0, NULL);
5718 flush_sequence();
5720 /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
5721 ShowWindow( hchild, SW_FORCEMINIMIZE );
5722 ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
5723 todo_wine {
5724 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5726 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5728 DestroyWindow(hchild);
5729 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5730 0, 0, 10, 10, hparent, 0, 0, NULL);
5731 flush_sequence();
5733 ShowWindow( hchild, SW_SHOWNA );
5734 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5735 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5736 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5738 /* repeat */
5739 flush_events();
5740 flush_sequence();
5741 ShowWindow( hchild, SW_SHOWNA );
5742 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5744 DestroyWindow(hchild);
5745 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5746 0, 0, 10, 10, hparent, 0, 0, NULL);
5747 flush_sequence();
5749 ShowWindow( hchild, SW_SHOW );
5750 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5751 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5752 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5754 /* repeat */
5755 flush_events();
5756 flush_sequence();
5757 ShowWindow( hchild, SW_SHOW );
5758 ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5760 ShowWindow( hchild, SW_HIDE );
5761 ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
5762 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5763 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5765 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5766 ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
5767 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5768 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5770 SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5771 ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
5772 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
5773 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5775 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5776 flush_sequence();
5777 DestroyWindow(hchild);
5778 ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
5780 DestroyWindow(hparent);
5781 flush_sequence();
5784 /****************** button message test *************************/
5785 #define ID_BUTTON 0x000e
5787 static const struct message WmSetFocusButtonSeq[] =
5789 { HCBT_SETFOCUS, hook },
5790 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5791 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5792 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5793 { WM_SETFOCUS, sent|wparam, 0 },
5794 { WM_CTLCOLORBTN, sent|parent },
5795 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5796 { WM_APP, sent|wparam|lparam, 0, 0 },
5797 { 0 }
5799 static const struct message WmKillFocusButtonSeq[] =
5801 { HCBT_SETFOCUS, hook },
5802 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5803 { WM_KILLFOCUS, sent|wparam, 0 },
5804 { WM_CTLCOLORBTN, sent|parent },
5805 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5806 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5807 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5808 { WM_APP, sent|wparam|lparam, 0, 0 },
5809 { WM_PAINT, sent },
5810 { WM_CTLCOLORBTN, sent|parent },
5811 { 0 }
5813 static const struct message WmSetFocusStaticSeq[] =
5815 { HCBT_SETFOCUS, hook },
5816 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5817 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5818 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5819 { WM_SETFOCUS, sent|wparam, 0 },
5820 { WM_CTLCOLORSTATIC, sent|parent },
5821 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5822 { WM_COMMAND, sent|wparam|parent|optional, MAKEWPARAM(ID_BUTTON, BN_CLICKED) }, /* radio button */
5823 { WM_APP, sent|wparam|lparam, 0, 0 },
5824 { 0 }
5826 static const struct message WmKillFocusStaticSeq[] =
5828 { HCBT_SETFOCUS, hook },
5829 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5830 { WM_KILLFOCUS, sent|wparam, 0 },
5831 { WM_CTLCOLORSTATIC, sent|parent },
5832 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5833 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5834 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5835 { WM_APP, sent|wparam|lparam, 0, 0 },
5836 { WM_PAINT, sent },
5837 { WM_CTLCOLORSTATIC, sent|parent },
5838 { 0 }
5840 static const struct message WmSetFocusOwnerdrawSeq[] =
5842 { HCBT_SETFOCUS, hook },
5843 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5844 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5845 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5846 { WM_SETFOCUS, sent|wparam, 0 },
5847 { WM_CTLCOLORBTN, sent|parent },
5848 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x001040e4 },
5849 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5850 { WM_APP, sent|wparam|lparam, 0, 0 },
5851 { 0 }
5853 static const struct message WmKillFocusOwnerdrawSeq[] =
5855 { HCBT_SETFOCUS, hook },
5856 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5857 { WM_KILLFOCUS, sent|wparam, 0 },
5858 { WM_CTLCOLORBTN, sent|parent },
5859 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000040e4 },
5860 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5861 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5862 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5863 { WM_APP, sent|wparam|lparam, 0, 0 },
5864 { WM_PAINT, sent },
5865 { WM_CTLCOLORBTN, sent|parent },
5866 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
5867 { 0 }
5869 static const struct message WmLButtonDownSeq[] =
5871 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
5872 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5873 { HCBT_SETFOCUS, hook },
5874 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5875 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5876 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5877 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
5878 { WM_CTLCOLORBTN, sent|defwinproc },
5879 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
5880 { WM_CTLCOLORBTN, sent|defwinproc },
5881 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5882 { 0 }
5884 static const struct message WmLButtonDownStaticSeq[] =
5886 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
5887 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5888 { HCBT_SETFOCUS, hook },
5889 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5890 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5891 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5892 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
5893 { WM_CTLCOLORSTATIC, sent|defwinproc },
5894 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
5895 { WM_CTLCOLORSTATIC, sent|defwinproc },
5896 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5897 { 0 }
5899 static const struct message WmLButtonUpSeq[] =
5901 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
5902 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
5903 { WM_CTLCOLORBTN, sent|defwinproc },
5904 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5905 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
5906 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
5907 { 0 }
5909 static const struct message WmLButtonUpStaticSeq[] =
5911 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
5912 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
5913 { WM_CTLCOLORSTATIC, sent|defwinproc },
5914 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5915 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
5916 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
5917 { 0 }
5919 static const struct message WmLButtonUpAutoSeq[] =
5921 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
5922 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
5923 { WM_CTLCOLORSTATIC, sent|defwinproc },
5924 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5925 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
5926 { BM_SETCHECK, sent|defwinproc },
5927 { WM_CTLCOLORSTATIC, sent|defwinproc, 0, 0 },
5928 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
5929 { 0 }
5931 static const struct message WmLButtonUpBrokenSeq[] =
5933 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
5934 { 0 }
5936 static const struct message WmSetFontButtonSeq[] =
5938 { WM_SETFONT, sent },
5939 { WM_PAINT, sent },
5940 { WM_ERASEBKGND, sent|defwinproc|optional },
5941 { WM_CTLCOLORBTN, sent|defwinproc },
5942 { WM_CTLCOLORBTN, sent|defwinproc|optional }, /* FIXME: Wine sends it twice for BS_OWNERDRAW */
5943 { 0 }
5945 static const struct message WmSetFontStaticSeq[] =
5947 { WM_SETFONT, sent },
5948 { WM_PAINT, sent },
5949 { WM_ERASEBKGND, sent|defwinproc|optional },
5950 { WM_CTLCOLORSTATIC, sent|defwinproc },
5951 { 0 }
5953 static const struct message WmSetTextButtonSeq[] =
5955 { WM_SETTEXT, sent },
5956 { WM_CTLCOLORBTN, sent|parent },
5957 { WM_CTLCOLORBTN, sent|parent },
5958 { WM_COMMAND, sent|parent|optional },
5959 { WM_DRAWITEM, sent|parent|optional },
5960 { 0 }
5962 static const struct message WmSetTextStaticSeq[] =
5964 { WM_SETTEXT, sent },
5965 { WM_CTLCOLORSTATIC, sent|parent },
5966 { WM_CTLCOLORSTATIC, sent|parent },
5967 { 0 }
5969 static const struct message WmSetTextGroupSeq[] =
5971 { WM_SETTEXT, sent },
5972 { WM_CTLCOLORSTATIC, sent|parent },
5973 { WM_CTLCOLORSTATIC, sent|parent|optional }, /* FIXME: Missing in Wine */
5974 { WM_CTLCOLORSTATIC, sent|parent|optional }, /* FIXME: Missing in Wine */
5975 { 0 }
5977 static const struct message WmSetTextInvisibleSeq[] =
5979 { WM_SETTEXT, sent },
5980 { 0 }
5982 static const struct message WmSetStyleButtonSeq[] =
5984 { BM_SETSTYLE, sent },
5985 { WM_APP, sent|wparam|lparam, 0, 0 },
5986 { WM_PAINT, sent },
5987 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
5988 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5989 { WM_CTLCOLORBTN, sent|parent },
5990 { 0 }
5992 static const struct message WmSetStyleStaticSeq[] =
5994 { BM_SETSTYLE, sent },
5995 { WM_APP, sent|wparam|lparam, 0, 0 },
5996 { WM_PAINT, sent },
5997 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
5998 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5999 { WM_CTLCOLORSTATIC, sent|parent },
6000 { 0 }
6002 static const struct message WmSetStyleUserSeq[] =
6004 { BM_SETSTYLE, sent },
6005 { WM_APP, sent|wparam|lparam, 0, 0 },
6006 { WM_PAINT, sent },
6007 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6008 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6009 { WM_CTLCOLORBTN, sent|parent },
6010 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_PAINT) },
6011 { 0 }
6013 static const struct message WmSetStyleOwnerdrawSeq[] =
6015 { BM_SETSTYLE, sent },
6016 { WM_APP, sent|wparam|lparam, 0, 0 },
6017 { WM_PAINT, sent },
6018 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
6019 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6020 { WM_CTLCOLORBTN, sent|parent },
6021 { WM_CTLCOLORBTN, sent|parent|optional }, /* Win9x doesn't send it */
6022 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
6023 { 0 }
6025 static const struct message WmSetStateButtonSeq[] =
6027 { BM_SETSTATE, sent },
6028 { WM_CTLCOLORBTN, sent|parent },
6029 { WM_APP, sent|wparam|lparam, 0, 0 },
6030 { 0 }
6032 static const struct message WmSetStateStaticSeq[] =
6034 { BM_SETSTATE, sent },
6035 { WM_CTLCOLORSTATIC, sent|parent },
6036 { WM_APP, sent|wparam|lparam, 0, 0 },
6037 { 0 }
6039 static const struct message WmSetStateUserSeq[] =
6041 { BM_SETSTATE, sent },
6042 { WM_CTLCOLORBTN, sent|parent },
6043 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_HILITE) },
6044 { WM_APP, sent|wparam|lparam, 0, 0 },
6045 { 0 }
6047 static const struct message WmSetStateOwnerdrawSeq[] =
6049 { BM_SETSTATE, sent },
6050 { WM_CTLCOLORBTN, sent|parent },
6051 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000120e4 },
6052 { WM_APP, sent|wparam|lparam, 0, 0 },
6053 { 0 }
6055 static const struct message WmClearStateButtonSeq[] =
6057 { BM_SETSTATE, sent },
6058 { WM_CTLCOLORBTN, sent|parent },
6059 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_UNHILITE) },
6060 { WM_APP, sent|wparam|lparam, 0, 0 },
6061 { 0 }
6063 static const struct message WmDisableButtonSeq[] =
6065 { WM_LBUTTONDOWN, sent },
6066 { BM_SETSTATE, sent|defwinproc },
6067 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6068 { WM_CTLCOLORBTN, sent|optional },
6069 { WM_LBUTTONUP, sent },
6070 { BM_SETSTATE, sent|defwinproc },
6071 { WM_CTLCOLORBTN, sent|defwinproc|optional },
6072 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6073 { BM_SETCHECK, sent|defwinproc|optional },
6074 { WM_CTLCOLORBTN, sent|optional },
6075 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6076 { WM_CAPTURECHANGED, sent|defwinproc },
6077 { WM_COMMAND, sent },
6078 { 0 }
6080 static const struct message WmClearStateOwnerdrawSeq[] =
6082 { BM_SETSTATE, sent },
6083 { WM_CTLCOLORBTN, sent|parent },
6084 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000020e4 },
6085 { WM_APP, sent|wparam|lparam, 0, 0 },
6086 { 0 }
6088 static const struct message WmSetCheckIgnoredSeq[] =
6090 { BM_SETCHECK, sent },
6091 { WM_APP, sent|wparam|lparam, 0, 0 },
6092 { 0 }
6094 static const struct message WmSetCheckStaticSeq[] =
6096 { BM_SETCHECK, sent },
6097 { WM_CTLCOLORSTATIC, sent|parent },
6098 { WM_APP, sent|wparam|lparam, 0, 0 },
6099 { 0 }
6102 static WNDPROC old_button_proc;
6104 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6106 static LONG defwndproc_counter = 0;
6107 LRESULT ret;
6108 struct recvd_message msg;
6110 if (ignore_message( message )) return 0;
6112 switch (message)
6114 case WM_SYNCPAINT:
6115 break;
6116 case BM_SETSTATE:
6117 if (GetCapture())
6118 ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
6119 /* fall through */
6120 default:
6121 msg.hwnd = hwnd;
6122 msg.message = message;
6123 msg.flags = sent|wparam|lparam;
6124 if (defwndproc_counter) msg.flags |= defwinproc;
6125 msg.wParam = wParam;
6126 msg.lParam = lParam;
6127 msg.descr = "button";
6128 add_message(&msg);
6131 defwndproc_counter++;
6132 ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
6133 defwndproc_counter--;
6135 return ret;
6138 static void subclass_button(void)
6140 WNDCLASSA cls;
6142 if (!GetClassInfoA(0, "button", &cls)) assert(0);
6144 old_button_proc = cls.lpfnWndProc;
6146 cls.hInstance = GetModuleHandleA(NULL);
6147 cls.lpfnWndProc = button_hook_proc;
6148 cls.lpszClassName = "my_button_class";
6149 UnregisterClassA(cls.lpszClassName, cls.hInstance);
6150 if (!RegisterClassA(&cls)) assert(0);
6153 static void test_button_messages(void)
6155 static const struct
6157 DWORD style;
6158 DWORD dlg_code;
6159 const struct message *setfocus;
6160 const struct message *killfocus;
6161 const struct message *setstyle;
6162 const struct message *setstate;
6163 const struct message *clearstate;
6164 const struct message *setcheck;
6165 const struct message *lbuttondown;
6166 const struct message *lbuttonup;
6167 const struct message *setfont;
6168 const struct message *settext;
6169 } button[] = {
6170 { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
6171 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
6172 WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq,
6173 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6174 WmSetTextButtonSeq },
6175 { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
6176 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
6177 WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq,
6178 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6179 WmSetTextButtonSeq },
6180 { BS_CHECKBOX, DLGC_BUTTON,
6181 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6182 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6183 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6184 WmSetTextStaticSeq },
6185 { BS_AUTOCHECKBOX, DLGC_BUTTON,
6186 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6187 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6188 WmLButtonDownStaticSeq, WmLButtonUpAutoSeq, WmSetFontStaticSeq,
6189 WmSetTextStaticSeq },
6190 { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
6191 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6192 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6193 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6194 WmSetTextStaticSeq },
6195 { BS_3STATE, DLGC_BUTTON,
6196 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6197 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6198 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6199 WmSetTextStaticSeq },
6200 { BS_AUTO3STATE, DLGC_BUTTON,
6201 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6202 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6203 WmLButtonDownStaticSeq, WmLButtonUpAutoSeq, WmSetFontStaticSeq,
6204 WmSetTextStaticSeq },
6205 { BS_GROUPBOX, DLGC_STATIC,
6206 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6207 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckIgnoredSeq,
6208 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6209 WmSetTextGroupSeq },
6210 { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
6211 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleUserSeq,
6212 WmSetStateUserSeq, WmClearStateButtonSeq, WmSetCheckIgnoredSeq,
6213 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6214 WmSetTextButtonSeq },
6215 { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
6216 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6217 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6218 NULL /* avoid infinite loop */, WmLButtonUpBrokenSeq, WmSetFontStaticSeq,
6219 WmSetTextStaticSeq },
6220 { BS_OWNERDRAW, DLGC_BUTTON,
6221 WmSetFocusOwnerdrawSeq, WmKillFocusOwnerdrawSeq, WmSetStyleOwnerdrawSeq,
6222 WmSetStateOwnerdrawSeq, WmClearStateOwnerdrawSeq, WmSetCheckIgnoredSeq,
6223 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6224 WmSetTextButtonSeq },
6226 LOGFONTA logfont = { 0 };
6227 HFONT zfont, hfont2;
6228 unsigned int i;
6229 HWND hwnd, parent;
6230 DWORD dlg_code;
6232 /* selection with VK_SPACE should capture button window */
6233 hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
6234 0, 0, 50, 14, 0, 0, 0, NULL);
6235 ok(hwnd != 0, "Failed to create button window\n");
6236 ReleaseCapture();
6237 SetFocus(hwnd);
6238 SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
6239 ok(GetCapture() == hwnd, "Should be captured on VK_SPACE WM_KEYDOWN\n");
6240 SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
6241 DestroyWindow(hwnd);
6243 subclass_button();
6245 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6246 100, 100, 200, 200, 0, 0, 0, NULL);
6247 ok(parent != 0, "Failed to create parent window\n");
6249 memset(&logfont, 0, sizeof(logfont));
6250 logfont.lfHeight = -12;
6251 logfont.lfWeight = FW_NORMAL;
6252 strcpy(logfont.lfFaceName, "Tahoma");
6254 hfont2 = CreateFontIndirectA(&logfont);
6255 ok(hfont2 != NULL, "Failed to create Tahoma font\n");
6257 for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
6259 MSG msg;
6260 DWORD style, state;
6261 HFONT prevfont;
6262 char desc[64];
6263 HDC hdc;
6265 trace("button style %08x\n", button[i].style);
6267 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_CHILD | BS_NOTIFY,
6268 0, 0, 50, 14, parent, (HMENU)ID_BUTTON, 0, NULL);
6269 ok(hwnd != 0, "Failed to create button window\n");
6271 style = GetWindowLongA(hwnd, GWL_STYLE);
6272 style &= ~(WS_CHILD | BS_NOTIFY);
6273 /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
6274 if (button[i].style == BS_USERBUTTON)
6275 ok(style == BS_PUSHBUTTON, "expected style BS_PUSHBUTTON got %x\n", style);
6276 else
6277 ok(style == button[i].style, "expected style %x got %x\n", button[i].style, style);
6279 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
6280 ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
6282 ShowWindow(hwnd, SW_SHOW);
6283 UpdateWindow(hwnd);
6284 SetFocus(0);
6285 flush_events();
6286 SetFocus(0);
6287 flush_sequence();
6289 log_all_parent_messages++;
6291 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
6292 SetFocus(hwnd);
6293 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6294 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6295 ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
6297 SetFocus(0);
6298 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6299 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6300 ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
6302 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
6304 SendMessageA(hwnd, BM_SETSTYLE, button[i].style | BS_BOTTOM, TRUE);
6305 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6306 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6307 ok_sequence(button[i].setstyle, "BM_SETSTYLE on a button", FALSE);
6309 style = GetWindowLongA(hwnd, GWL_STYLE);
6310 style &= ~(WS_VISIBLE | WS_CHILD | BS_NOTIFY);
6311 /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */
6312 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6314 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6315 ok(state == 0, "expected state 0, got %04x\n", state);
6317 flush_sequence();
6319 SendMessageA(hwnd, BM_SETSTATE, TRUE, 0);
6320 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6321 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6322 ok_sequence(button[i].setstate, "BM_SETSTATE/TRUE on a button", FALSE);
6324 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6325 ok(state == 0x0004, "expected state 0x0004, got %04x\n", state);
6327 style = GetWindowLongA(hwnd, GWL_STYLE);
6328 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6329 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6331 flush_sequence();
6333 SendMessageA(hwnd, BM_SETSTATE, FALSE, 0);
6334 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6335 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6336 ok_sequence(button[i].clearstate, "BM_SETSTATE/FALSE on a button", FALSE);
6338 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6339 ok(state == 0, "expected state 0, got %04x\n", state);
6341 style = GetWindowLongA(hwnd, GWL_STYLE);
6342 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6343 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6345 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6346 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
6348 flush_sequence();
6350 SendMessageA(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
6351 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6352 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6353 ok_sequence(WmSetCheckIgnoredSeq, "BM_SETCHECK on a button", FALSE);
6355 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6356 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
6358 style = GetWindowLongA(hwnd, GWL_STYLE);
6359 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6360 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6362 flush_sequence();
6364 SendMessageA(hwnd, BM_SETCHECK, BST_CHECKED, 0);
6365 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6366 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6367 ok_sequence(button[i].setcheck, "BM_SETCHECK on a button", FALSE);
6369 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 1");
6370 sprintf(desc, "button[%i]: WM_SETTEXT on a visible button", i);
6371 ok_sequence(button[i].settext, desc, FALSE);
6373 ShowWindow(hwnd, SW_HIDE);
6374 flush_events();
6375 flush_sequence();
6377 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 2");
6378 sprintf(desc, "button[%i]: WM_SETTEXT on an invisible button", i);
6379 ok_sequence(WmSetTextInvisibleSeq, desc, FALSE);
6381 ShowWindow(hwnd, SW_SHOW);
6382 ShowWindow(parent, SW_HIDE);
6383 flush_events();
6384 flush_sequence();
6386 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 3");
6387 sprintf(desc, "button[%i]: WM_SETTEXT on an invisible button", i);
6388 ok_sequence(WmSetTextInvisibleSeq, desc, FALSE);
6390 ShowWindow(parent, SW_SHOW);
6391 flush_events();
6393 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6394 if (button[i].style == BS_PUSHBUTTON ||
6395 button[i].style == BS_DEFPUSHBUTTON ||
6396 button[i].style == BS_GROUPBOX ||
6397 button[i].style == BS_USERBUTTON ||
6398 button[i].style == BS_OWNERDRAW)
6399 ok(state == BST_UNCHECKED, "expected check 0, got %04x\n", state);
6400 else
6401 ok(state == BST_CHECKED, "expected check 1, got %04x\n", state);
6403 style = GetWindowLongA(hwnd, GWL_STYLE);
6404 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6405 if (button[i].style == BS_RADIOBUTTON ||
6406 button[i].style == BS_AUTORADIOBUTTON)
6407 ok(style == (button[i].style | WS_TABSTOP), "expected style %04x | WS_TABSTOP got %04x\n", button[i].style, style);
6408 else
6409 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6411 log_all_parent_messages--;
6413 DestroyWindow(hwnd);
6415 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP | WS_VISIBLE,
6416 0, 0, 50, 14, 0, 0, 0, NULL);
6417 ok(hwnd != 0, "Failed to create button window\n");
6419 SetForegroundWindow(hwnd);
6420 flush_events();
6422 SetActiveWindow(hwnd);
6423 SetFocus(0);
6424 flush_sequence();
6426 if (button[i].lbuttondown)
6428 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
6429 sprintf(desc, "button[%i]: WM_LBUTTONDOWN on a button", i);
6430 ok_sequence(button[i].lbuttondown, desc, FALSE);
6433 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
6434 sprintf(desc, "button[%i]: WM_LBUTTONUP on a button", i);
6435 ok_sequence(button[i].lbuttonup, desc, FALSE);
6437 flush_sequence();
6438 zfont = GetStockObject(DEFAULT_GUI_FONT);
6439 SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
6440 UpdateWindow(hwnd);
6441 sprintf(desc, "button[%i]: WM_SETFONT on a button", i);
6442 ok_sequence(button[i].setfont, desc, FALSE);
6444 /* Test that original font is not selected back after painting */
6445 hdc = CreateCompatibleDC(0);
6447 prevfont = SelectObject(hdc, hfont2);
6448 ok(prevfont == GetStockObject(SYSTEM_FONT), "Unexpected default font\n");
6449 SendMessageA(hwnd, WM_PRINTCLIENT, (WPARAM)hdc, 0);
6450 todo_wine
6451 ok(GetStockObject(SYSTEM_FONT) == GetCurrentObject(hdc, OBJ_FONT), "button[%u]: unexpected font selected after WM_PRINTCLIENT\n", i);
6452 SelectObject(hdc, prevfont);
6454 prevfont = SelectObject(hdc, hfont2);
6455 ok(prevfont == GetStockObject(SYSTEM_FONT), "Unexpected default font\n");
6456 SendMessageA(hwnd, WM_PAINT, (WPARAM)hdc, 0);
6457 todo_wine
6458 ok(GetStockObject(SYSTEM_FONT) == GetCurrentObject(hdc, OBJ_FONT), "button[%u]: unexpected font selected after WM_PAINT\n", i);
6459 SelectObject(hdc, prevfont);
6461 DeleteDC(hdc);
6463 DestroyWindow(hwnd);
6466 DeleteObject(hfont2);
6467 DestroyWindow(parent);
6469 /* Test if WM_LBUTTONDOWN and WM_LBUTTONUP to a disabled button leads to a WM_COMMAND for the parent */
6471 parent = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6472 100, 100, 200, 200, 0, 0, 0, NULL);
6473 ok (hwnd != 0, "Failed to create overlapped window\n");
6475 hwnd = CreateWindowExA(0, "my_button_class", "test", BS_DEFPUSHBUTTON | WS_VISIBLE | WS_CHILD,
6476 0, 0, 50, 14, parent, 0, 0, NULL);
6478 EnableWindow(hwnd, FALSE);
6479 flush_sequence();
6480 SendMessageA(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, 0);
6481 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
6482 ok_sequence(WmDisableButtonSeq, "Mouseclick on a disabled button", FALSE);
6484 DestroyWindow(hwnd);
6485 DestroyWindow(parent);
6488 /****************** static message test *************************/
6489 static const struct message WmSetFontStaticSeq2[] =
6491 { WM_SETFONT, sent },
6492 { WM_PAINT, sent|defwinproc|optional },
6493 { WM_ERASEBKGND, sent|defwinproc|optional },
6494 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6495 { 0 }
6498 static WNDPROC old_static_proc;
6500 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6502 static LONG defwndproc_counter = 0;
6503 LRESULT ret;
6504 struct recvd_message msg;
6506 if (ignore_message( message )) return 0;
6508 msg.hwnd = hwnd;
6509 msg.message = message;
6510 msg.flags = sent|wparam|lparam;
6511 if (defwndproc_counter) msg.flags |= defwinproc;
6512 msg.wParam = wParam;
6513 msg.lParam = lParam;
6514 msg.descr = "static";
6515 add_message(&msg);
6517 defwndproc_counter++;
6518 ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
6519 defwndproc_counter--;
6521 return ret;
6524 static void subclass_static(void)
6526 WNDCLASSA cls;
6528 if (!GetClassInfoA(0, "static", &cls)) assert(0);
6530 old_static_proc = cls.lpfnWndProc;
6532 cls.hInstance = GetModuleHandleA(NULL);
6533 cls.lpfnWndProc = static_hook_proc;
6534 cls.lpszClassName = "my_static_class";
6535 UnregisterClassA(cls.lpszClassName, cls.hInstance);
6536 if (!RegisterClassA(&cls)) assert(0);
6539 static void test_static_messages(void)
6541 /* FIXME: make as comprehensive as the button message test */
6542 static const struct
6544 DWORD style;
6545 DWORD dlg_code;
6546 const struct message *setfont;
6547 } static_ctrl[] = {
6548 { SS_LEFT, DLGC_STATIC,
6549 WmSetFontStaticSeq2 }
6551 unsigned int i;
6552 HWND hwnd;
6553 DWORD dlg_code;
6555 subclass_static();
6557 for (i = 0; i < sizeof(static_ctrl)/sizeof(static_ctrl[0]); i++)
6559 hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
6560 0, 0, 50, 14, 0, 0, 0, NULL);
6561 ok(hwnd != 0, "Failed to create static window\n");
6563 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
6564 ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
6566 ShowWindow(hwnd, SW_SHOW);
6567 UpdateWindow(hwnd);
6568 SetFocus(0);
6569 flush_sequence();
6571 trace("static style %08x\n", static_ctrl[i].style);
6572 SendMessageA(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
6573 ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
6575 DestroyWindow(hwnd);
6579 /****************** ComboBox message test *************************/
6580 #define ID_COMBOBOX 0x000f
6582 static const struct message WmKeyDownComboSeq[] =
6584 { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
6585 { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
6586 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
6587 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
6588 { WM_CTLCOLOREDIT, sent|parent },
6589 { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
6590 { 0 }
6593 static const struct message WmSetPosComboSeq[] =
6595 { WM_WINDOWPOSCHANGING, sent },
6596 { WM_NCCALCSIZE, sent|wparam, TRUE },
6597 { WM_CHILDACTIVATE, sent },
6598 { WM_WINDOWPOSCHANGED, sent },
6599 { WM_MOVE, sent|defwinproc },
6600 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
6601 { WM_WINDOWPOSCHANGING, sent|defwinproc },
6602 { WM_NCCALCSIZE, sent|defwinproc|wparam, TRUE },
6603 { WM_WINDOWPOSCHANGED, sent|defwinproc },
6604 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
6605 { 0 }
6608 static const struct message WMSetFocusComboBoxSeq[] =
6610 { WM_SETFOCUS, sent },
6611 { WM_KILLFOCUS, sent|parent },
6612 { WM_SETFOCUS, sent },
6613 { WM_COMMAND, sent|defwinproc|wparam, MAKEWPARAM(1001, EN_SETFOCUS) },
6614 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, INT_MAX },
6615 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
6616 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
6617 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SETFOCUS) },
6618 { 0 }
6621 static const struct message SetFocusButtonSeq[] =
6623 { WM_KILLFOCUS, sent },
6624 { CB_GETCOMBOBOXINFO, sent|optional },/* Windows 2000 */
6625 { 0x0167, sent|optional },/* Undocumented message. Sent on all versions except Windows 2000 */
6626 { WM_LBUTTONUP, sent|defwinproc },
6627 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDCANCEL) },
6628 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, 0 },
6629 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
6630 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
6631 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_KILLFOCUS) },
6632 { WM_CTLCOLORBTN, sent|parent },
6633 { 0 }
6636 static const struct message SetFocusComboBoxSeq[] =
6638 { WM_CTLCOLORBTN, sent|parent },
6639 { WM_SETFOCUS, sent },
6640 { WM_KILLFOCUS, sent|defwinproc },
6641 { WM_SETFOCUS, sent },
6642 { WM_COMMAND, sent|defwinproc|wparam, MAKEWPARAM(1001, EN_SETFOCUS) },
6643 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, INT_MAX },
6644 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
6645 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
6646 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SETFOCUS) },
6647 { 0 }
6650 static const struct message SetFocusButtonSeq2[] =
6652 { WM_KILLFOCUS, sent },
6653 { CB_GETCOMBOBOXINFO, sent|optional },/* Windows 2000 */
6654 { 0x0167, sent|optional },/* Undocumented message. Sent on all versions except Windows 2000 */
6655 { WM_LBUTTONUP, sent|defwinproc },
6656 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDCANCEL) },
6657 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, 0 },
6658 { WM_CTLCOLOREDIT, sent|defwinproc },
6659 { WM_CTLCOLOREDIT, sent|parent },
6660 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_KILLFOCUS) },
6661 { WM_CTLCOLORBTN, sent|parent },
6662 { 0 }
6665 static WNDPROC old_combobox_proc, edit_window_proc;
6667 static LRESULT CALLBACK combobox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6669 static LONG defwndproc_counter = 0;
6670 LRESULT ret;
6671 struct recvd_message msg;
6673 /* do not log painting messages */
6674 if (message != WM_PAINT &&
6675 message != WM_NCPAINT &&
6676 message != WM_SYNCPAINT &&
6677 message != WM_ERASEBKGND &&
6678 message != WM_NCHITTEST &&
6679 message != WM_GETTEXT &&
6680 !ignore_message( message ))
6682 msg.hwnd = hwnd;
6683 msg.message = message;
6684 msg.flags = sent|wparam|lparam;
6685 if (defwndproc_counter) msg.flags |= defwinproc;
6686 msg.wParam = wParam;
6687 msg.lParam = lParam;
6688 msg.descr = "combo";
6689 add_message(&msg);
6692 defwndproc_counter++;
6693 ret = CallWindowProcA(edit_window_proc, hwnd, message, wParam, lParam);
6694 defwndproc_counter--;
6696 return ret;
6699 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6701 static LONG defwndproc_counter = 0;
6702 LRESULT ret;
6703 struct recvd_message msg;
6705 /* do not log painting messages */
6706 if (message != WM_PAINT &&
6707 message != WM_NCPAINT &&
6708 message != WM_SYNCPAINT &&
6709 message != WM_ERASEBKGND &&
6710 message != WM_NCHITTEST &&
6711 message != WM_GETTEXT &&
6712 !ignore_message( message ))
6714 msg.hwnd = hwnd;
6715 msg.message = message;
6716 msg.flags = sent|wparam|lparam;
6717 if (defwndproc_counter) msg.flags |= defwinproc;
6718 msg.wParam = wParam;
6719 msg.lParam = lParam;
6720 msg.descr = "combo";
6721 add_message(&msg);
6724 defwndproc_counter++;
6725 ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
6726 defwndproc_counter--;
6728 return ret;
6731 static void subclass_combobox(void)
6733 WNDCLASSA cls;
6735 if (!GetClassInfoA(0, "ComboBox", &cls)) assert(0);
6737 old_combobox_proc = cls.lpfnWndProc;
6739 cls.hInstance = GetModuleHandleA(NULL);
6740 cls.lpfnWndProc = combobox_hook_proc;
6741 cls.lpszClassName = "my_combobox_class";
6742 UnregisterClassA(cls.lpszClassName, cls.hInstance);
6743 if (!RegisterClassA(&cls)) assert(0);
6746 static void test_combobox_messages(void)
6748 HWND parent, combo, button, edit;
6749 LRESULT ret;
6750 BOOL (WINAPI *pGetComboBoxInfo)(HWND, PCOMBOBOXINFO);
6751 COMBOBOXINFO cbInfo;
6752 BOOL res;
6754 subclass_combobox();
6756 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6757 100, 100, 200, 200, 0, 0, 0, NULL);
6758 ok(parent != 0, "Failed to create parent window\n");
6759 flush_sequence();
6761 combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
6762 0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
6763 ok(combo != 0, "Failed to create combobox window\n");
6765 UpdateWindow(combo);
6767 ret = SendMessageA(combo, WM_GETDLGCODE, 0, 0);
6768 ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08lx\n", ret);
6770 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
6771 ok(ret == 0, "expected 0, got %ld\n", ret);
6772 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
6773 ok(ret == 1, "expected 1, got %ld\n", ret);
6774 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
6775 ok(ret == 2, "expected 2, got %ld\n", ret);
6777 SendMessageA(combo, CB_SETCURSEL, 0, 0);
6778 SetFocus(combo);
6779 flush_sequence();
6781 log_all_parent_messages++;
6782 SendMessageA(combo, WM_KEYDOWN, VK_DOWN, 0);
6783 SendMessageA(combo, WM_KEYUP, VK_DOWN, 0);
6784 log_all_parent_messages--;
6785 ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
6787 flush_sequence();
6788 SetWindowPos(combo, 0, 10, 10, 120, 130, SWP_NOZORDER);
6789 ok_sequence(WmSetPosComboSeq, "repositioning messages on a ComboBox", FALSE);
6791 DestroyWindow(combo);
6792 DestroyWindow(parent);
6794 /* Start again. Test combobox text selection when getting and losing focus */
6795 pGetComboBoxInfo = (void *)GetProcAddress(GetModuleHandleA("user32.dll"), "GetComboBoxInfo");
6796 if (!pGetComboBoxInfo)
6798 win_skip("GetComboBoxInfo is not available\n");
6799 return;
6802 parent = CreateWindowExA(0, "TestParentClass", "Parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6803 10, 10, 300, 300, NULL, NULL, NULL, NULL);
6804 ok(parent != 0, "Failed to create parent window\n");
6806 combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWN,
6807 5, 5, 100, 100, parent, (HMENU)ID_COMBOBOX, NULL, NULL);
6808 ok(combo != 0, "Failed to create combobox window\n");
6810 cbInfo.cbSize = sizeof(COMBOBOXINFO);
6811 SetLastError(0xdeadbeef);
6812 res = pGetComboBoxInfo(combo, &cbInfo);
6813 ok(res, "Failed to get COMBOBOXINFO structure; LastError: %u\n", GetLastError());
6814 edit = cbInfo.hwndItem;
6816 edit_window_proc = (WNDPROC)SetWindowLongPtrA(edit, GWLP_WNDPROC, (ULONG_PTR)combobox_subclass_proc);
6818 button = CreateWindowExA(0, "Button", "OK", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
6819 5, 50, 100, 20, parent, NULL,
6820 (HINSTANCE)GetWindowLongPtrA(parent, GWLP_HINSTANCE), NULL);
6821 ok(button != 0, "Failed to create button window\n");
6823 flush_sequence();
6824 log_all_parent_messages++;
6825 SendMessageA(combo, WM_SETFOCUS, 0, (LPARAM)edit);
6826 log_all_parent_messages--;
6827 ok_sequence(WMSetFocusComboBoxSeq, "WM_SETFOCUS on a ComboBox", TRUE);
6829 flush_sequence();
6830 log_all_parent_messages++;
6831 SetFocus(button);
6832 log_all_parent_messages--;
6833 ok_sequence(SetFocusButtonSeq, "SetFocus on a Button", TRUE);
6835 SendMessageA(combo, WM_SETTEXT, 0, (LPARAM)"Wine Test");
6837 flush_sequence();
6838 log_all_parent_messages++;
6839 SetFocus(combo);
6840 log_all_parent_messages--;
6841 ok_sequence(SetFocusComboBoxSeq, "SetFocus on a ComboBox", TRUE);
6843 flush_sequence();
6844 log_all_parent_messages++;
6845 SetFocus(button);
6846 log_all_parent_messages--;
6847 ok_sequence(SetFocusButtonSeq2, "SetFocus on a Button (2)", TRUE);
6849 DestroyWindow(button);
6850 DestroyWindow(combo);
6851 DestroyWindow(parent);
6854 /****************** WM_IME_KEYDOWN message test *******************/
6856 static const struct message WmImeKeydownMsgSeq_0[] =
6858 { WM_IME_KEYDOWN, wparam, VK_RETURN },
6859 { WM_CHAR, wparam, 'A' },
6860 { 0 }
6863 static const struct message WmImeKeydownMsgSeq_1[] =
6865 { WM_KEYDOWN, optional|wparam, VK_RETURN },
6866 { WM_CHAR, optional|wparam, VK_RETURN },
6867 { 0 }
6870 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6872 struct recvd_message msg;
6874 msg.hwnd = hwnd;
6875 msg.message = message;
6876 msg.flags = wparam|lparam;
6877 msg.wParam = wParam;
6878 msg.lParam = lParam;
6879 msg.descr = "wmime_keydown";
6880 add_message(&msg);
6882 return DefWindowProcA(hwnd, message, wParam, lParam);
6885 static void register_wmime_keydown_class(void)
6887 WNDCLASSA cls;
6889 ZeroMemory(&cls, sizeof(WNDCLASSA));
6890 cls.lpfnWndProc = wmime_keydown_procA;
6891 cls.hInstance = GetModuleHandleA(0);
6892 cls.lpszClassName = "wmime_keydown_class";
6893 if (!RegisterClassA(&cls)) assert(0);
6896 static void test_wmime_keydown_message(void)
6898 HWND hwnd;
6899 MSG msg;
6901 trace("Message sequences by WM_IME_KEYDOWN\n");
6903 register_wmime_keydown_class();
6904 hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
6905 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
6906 NULL, NULL, 0);
6907 flush_events();
6908 flush_sequence();
6910 SendMessageA(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
6911 SendMessageA(hwnd, WM_CHAR, 'A', 1);
6912 ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
6914 while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
6916 TranslateMessage(&msg);
6917 DispatchMessageA(&msg);
6919 ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
6921 DestroyWindow(hwnd);
6924 /************* painting message test ********************/
6926 void dump_region(HRGN hrgn)
6928 DWORD i, size;
6929 RGNDATA *data = NULL;
6930 RECT *rect;
6932 if (!hrgn)
6934 printf( "null region\n" );
6935 return;
6937 if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
6938 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
6939 GetRegionData( hrgn, size, data );
6940 printf("%d rects:", data->rdh.nCount );
6941 for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
6942 printf( " %s", wine_dbgstr_rect( rect ));
6943 printf("\n");
6944 HeapFree( GetProcessHeap(), 0, data );
6947 static void check_update_rgn( HWND hwnd, HRGN hrgn )
6949 INT ret;
6950 RECT r1, r2;
6951 HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
6952 HRGN update = CreateRectRgn( 0, 0, 0, 0 );
6954 ret = GetUpdateRgn( hwnd, update, FALSE );
6955 ok( ret != ERROR, "GetUpdateRgn failed\n" );
6956 if (ret == NULLREGION)
6958 ok( !hrgn, "Update region shouldn't be empty\n" );
6960 else
6962 if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
6964 ok( 0, "Regions are different\n" );
6965 if (winetest_debug > 0)
6967 printf( "Update region: " );
6968 dump_region( update );
6969 printf( "Wanted region: " );
6970 dump_region( hrgn );
6974 GetRgnBox( update, &r1 );
6975 GetUpdateRect( hwnd, &r2, FALSE );
6976 ok( EqualRect( &r1, &r2 ), "Rectangles are different: %s / %s\n", wine_dbgstr_rect( &r1 ),
6977 wine_dbgstr_rect( &r2 ));
6979 DeleteObject( tmp );
6980 DeleteObject( update );
6983 static const struct message WmInvalidateRgn[] = {
6984 { WM_NCPAINT, sent },
6985 { WM_GETTEXT, sent|defwinproc|optional },
6986 { 0 }
6989 static const struct message WmGetUpdateRect[] = {
6990 { WM_NCPAINT, sent },
6991 { WM_GETTEXT, sent|defwinproc|optional },
6992 { WM_PAINT, sent },
6993 { 0 }
6996 static const struct message WmInvalidateFull[] = {
6997 { WM_NCPAINT, sent|wparam, 1 },
6998 { WM_GETTEXT, sent|defwinproc|optional },
6999 { 0 }
7002 static const struct message WmInvalidateErase[] = {
7003 { WM_NCPAINT, sent|wparam, 1 },
7004 { WM_GETTEXT, sent|defwinproc|optional },
7005 { WM_ERASEBKGND, sent },
7006 { 0 }
7009 static const struct message WmInvalidatePaint[] = {
7010 { WM_PAINT, sent },
7011 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
7012 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7013 { 0 }
7016 static const struct message WmInvalidateErasePaint[] = {
7017 { WM_PAINT, sent },
7018 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
7019 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7020 { WM_ERASEBKGND, sent|beginpaint|optional },
7021 { 0 }
7024 static const struct message WmInvalidateErasePaint2[] = {
7025 { WM_PAINT, sent },
7026 { WM_NCPAINT, sent|beginpaint },
7027 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7028 { WM_ERASEBKGND, sent|beginpaint|optional },
7029 { 0 }
7032 static const struct message WmErase[] = {
7033 { WM_ERASEBKGND, sent },
7034 { 0 }
7037 static const struct message WmPaint[] = {
7038 { WM_PAINT, sent },
7039 { 0 }
7042 static const struct message WmParentOnlyPaint[] = {
7043 { WM_PAINT, sent|parent },
7044 { 0 }
7047 static const struct message WmInvalidateParent[] = {
7048 { WM_NCPAINT, sent|parent },
7049 { WM_GETTEXT, sent|defwinproc|parent|optional },
7050 { WM_ERASEBKGND, sent|parent },
7051 { 0 }
7054 static const struct message WmInvalidateParentChild[] = {
7055 { WM_NCPAINT, sent|parent },
7056 { WM_GETTEXT, sent|defwinproc|parent|optional },
7057 { WM_ERASEBKGND, sent|parent },
7058 { WM_NCPAINT, sent },
7059 { WM_GETTEXT, sent|defwinproc|optional },
7060 { WM_ERASEBKGND, sent },
7061 { 0 }
7064 static const struct message WmInvalidateParentChild2[] = {
7065 { WM_ERASEBKGND, sent|parent },
7066 { WM_NCPAINT, sent },
7067 { WM_GETTEXT, sent|defwinproc|optional },
7068 { WM_ERASEBKGND, sent },
7069 { 0 }
7072 static const struct message WmParentPaint[] = {
7073 { WM_PAINT, sent|parent },
7074 { WM_PAINT, sent },
7075 { 0 }
7078 static const struct message WmParentPaintNc[] = {
7079 { WM_PAINT, sent|parent },
7080 { WM_PAINT, sent },
7081 { WM_NCPAINT, sent|beginpaint },
7082 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7083 { WM_ERASEBKGND, sent|beginpaint|optional },
7084 { 0 }
7087 static const struct message WmChildPaintNc[] = {
7088 { WM_PAINT, sent },
7089 { WM_NCPAINT, sent|beginpaint },
7090 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7091 { WM_ERASEBKGND, sent|beginpaint|optional },
7092 { 0 }
7095 static const struct message WmParentErasePaint[] = {
7096 { WM_PAINT, sent|parent },
7097 { WM_NCPAINT, sent|parent|beginpaint },
7098 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
7099 { WM_ERASEBKGND, sent|parent|beginpaint|optional },
7100 { WM_PAINT, sent },
7101 { WM_NCPAINT, sent|beginpaint },
7102 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7103 { WM_ERASEBKGND, sent|beginpaint|optional },
7104 { 0 }
7107 static const struct message WmParentOnlyNcPaint[] = {
7108 { WM_PAINT, sent|parent },
7109 { WM_NCPAINT, sent|parent|beginpaint },
7110 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
7111 { 0 }
7114 static const struct message WmSetParentStyle[] = {
7115 { WM_STYLECHANGING, sent|parent },
7116 { WM_STYLECHANGED, sent|parent },
7117 { 0 }
7120 static void test_paint_messages(void)
7122 BOOL ret;
7123 RECT rect, rect2;
7124 POINT pt;
7125 MSG msg;
7126 HWND hparent, hchild;
7127 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
7128 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
7129 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
7130 100, 100, 200, 200, 0, 0, 0, NULL);
7131 ok (hwnd != 0, "Failed to create overlapped window\n");
7133 ShowWindow( hwnd, SW_SHOW );
7134 UpdateWindow( hwnd );
7135 flush_events();
7136 flush_sequence();
7138 check_update_rgn( hwnd, 0 );
7139 SetRectRgn( hrgn, 10, 10, 20, 20 );
7140 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
7141 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7142 check_update_rgn( hwnd, hrgn );
7143 SetRectRgn( hrgn2, 20, 20, 30, 30 );
7144 ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
7145 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7146 CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
7147 check_update_rgn( hwnd, hrgn );
7148 /* validate everything */
7149 ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7150 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7151 check_update_rgn( hwnd, 0 );
7153 /* test empty region */
7154 SetRectRgn( hrgn, 10, 10, 10, 15 );
7155 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
7156 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7157 check_update_rgn( hwnd, 0 );
7158 /* test empty rect */
7159 SetRect( &rect, 10, 10, 10, 15 );
7160 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
7161 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7162 check_update_rgn( hwnd, 0 );
7164 /* flush pending messages */
7165 flush_events();
7166 flush_sequence();
7168 GetClientRect( hwnd, &rect );
7169 SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
7170 /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
7171 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
7173 trace("testing InvalidateRect(0, NULL, FALSE)\n");
7174 SetRectEmpty( &rect );
7175 ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) should fail\n");
7176 check_update_rgn( hwnd, hrgn );
7177 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7178 flush_events();
7179 ok_sequence( WmPaint, "Paint", FALSE );
7180 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7181 check_update_rgn( hwnd, 0 );
7183 /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
7184 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
7186 trace("testing ValidateRect(0, NULL)\n");
7187 SetRectEmpty( &rect );
7188 if (ValidateRect(0, &rect) && /* not supported on Win9x */
7189 GetUpdateRect(hwnd, NULL, FALSE)) /* or >= Win 8 */
7191 check_update_rgn( hwnd, hrgn );
7192 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7193 flush_events();
7194 ok_sequence( WmPaint, "Paint", FALSE );
7195 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7196 check_update_rgn( hwnd, 0 );
7199 trace("testing InvalidateRgn(0, NULL, FALSE)\n");
7200 SetLastError(0xdeadbeef);
7201 ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
7202 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
7203 "wrong error code %d\n", GetLastError());
7204 check_update_rgn( hwnd, 0 );
7205 flush_events();
7206 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
7208 trace("testing ValidateRgn(0, NULL)\n");
7209 SetLastError(0xdeadbeef);
7210 ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
7211 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
7212 broken( GetLastError() == 0xdeadbeef ) /* win9x */,
7213 "wrong error code %d\n", GetLastError());
7214 check_update_rgn( hwnd, 0 );
7215 flush_events();
7216 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
7218 trace("testing UpdateWindow(NULL)\n");
7219 SetLastError(0xdeadbeef);
7220 ok(!UpdateWindow(NULL), "UpdateWindow(NULL) should fail\n");
7221 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
7222 broken( GetLastError() == 0xdeadbeef ) /* win9x */,
7223 "wrong error code %d\n", GetLastError());
7224 check_update_rgn( hwnd, 0 );
7225 flush_events();
7226 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
7228 /* now with frame */
7229 SetRectRgn( hrgn, -5, -5, 20, 20 );
7231 /* flush pending messages */
7232 flush_events();
7233 flush_sequence();
7234 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7235 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
7237 SetRectRgn( hrgn, 0, 0, 20, 20 ); /* GetUpdateRgn clips to client area */
7238 check_update_rgn( hwnd, hrgn );
7240 flush_sequence();
7241 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
7242 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
7244 flush_sequence();
7245 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
7246 ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
7248 GetClientRect( hwnd, &rect );
7249 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
7250 check_update_rgn( hwnd, hrgn );
7252 flush_sequence();
7253 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
7254 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7256 flush_sequence();
7257 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
7258 ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
7259 check_update_rgn( hwnd, 0 );
7261 flush_sequence();
7262 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
7263 ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
7264 check_update_rgn( hwnd, 0 );
7266 flush_sequence();
7267 SetRectRgn( hrgn, 0, 0, 100, 100 );
7268 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
7269 SetRectRgn( hrgn, 0, 0, 50, 100 );
7270 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
7271 SetRectRgn( hrgn, 50, 0, 100, 100 );
7272 check_update_rgn( hwnd, hrgn );
7273 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
7274 ok_sequence( WmEmptySeq, "EmptySeq", FALSE ); /* must not generate messages, everything is valid */
7275 check_update_rgn( hwnd, 0 );
7277 flush_sequence();
7278 SetRectRgn( hrgn, 0, 0, 100, 100 );
7279 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
7280 SetRectRgn( hrgn, 0, 0, 100, 50 );
7281 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
7282 ok_sequence( WmErase, "Erase", FALSE );
7283 SetRectRgn( hrgn, 0, 50, 100, 100 );
7284 check_update_rgn( hwnd, hrgn );
7286 flush_sequence();
7287 SetRectRgn( hrgn, 0, 0, 100, 100 );
7288 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
7289 SetRectRgn( hrgn, 0, 0, 50, 50 );
7290 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
7291 ok_sequence( WmPaint, "Paint", FALSE );
7293 flush_sequence();
7294 SetRectRgn( hrgn, -4, -4, -2, -2 );
7295 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7296 SetRectRgn( hrgn, -200, -200, -198, -198 );
7297 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
7298 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
7300 flush_sequence();
7301 SetRectRgn( hrgn, -4, -4, -2, -2 );
7302 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7303 SetRectRgn( hrgn, -4, -4, -3, -3 );
7304 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
7305 SetRectRgn( hrgn, 0, 0, 1, 1 );
7306 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
7307 ok_sequence( WmPaint, "Paint", FALSE );
7309 flush_sequence();
7310 SetRectRgn( hrgn, -4, -4, -1, -1 );
7311 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7312 RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
7313 /* make sure no WM_PAINT was generated */
7314 flush_events();
7315 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
7317 flush_sequence();
7318 SetRectRgn( hrgn, -4, -4, -1, -1 );
7319 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7320 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
7322 if (msg.hwnd == hwnd && msg.message == WM_PAINT)
7324 /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
7325 INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
7326 ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
7327 ret = GetUpdateRect( hwnd, &rect, FALSE );
7328 ok( ret, "Invalid GetUpdateRect result %d\n", ret );
7329 /* this will send WM_NCPAINT and validate the non client area */
7330 ret = GetUpdateRect( hwnd, &rect, TRUE );
7331 ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
7333 DispatchMessageA( &msg );
7335 ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
7337 DestroyWindow( hwnd );
7339 /* now test with a child window */
7341 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
7342 100, 100, 200, 200, 0, 0, 0, NULL);
7343 ok (hparent != 0, "Failed to create parent window\n");
7345 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
7346 10, 10, 100, 100, hparent, 0, 0, NULL);
7347 ok (hchild != 0, "Failed to create child window\n");
7349 ShowWindow( hparent, SW_SHOW );
7350 UpdateWindow( hparent );
7351 UpdateWindow( hchild );
7352 flush_events();
7353 flush_sequence();
7354 log_all_parent_messages++;
7356 SetRect( &rect, 0, 0, 50, 50 );
7357 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7358 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
7359 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
7361 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7362 pt.x = pt.y = 0;
7363 MapWindowPoints( hchild, hparent, &pt, 1 );
7364 SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
7365 check_update_rgn( hchild, hrgn );
7366 SetRectRgn( hrgn, 0, 0, 50, 50 );
7367 check_update_rgn( hparent, hrgn );
7368 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
7369 ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
7370 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
7371 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
7373 flush_events();
7374 ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
7376 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
7377 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
7378 ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
7379 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
7380 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
7382 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
7383 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
7384 ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
7386 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
7387 flush_sequence();
7388 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
7389 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
7390 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
7392 /* flush all paint messages */
7393 flush_events();
7394 flush_sequence();
7396 /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
7397 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
7398 SetRectRgn( hrgn, 0, 0, 50, 50 );
7399 check_update_rgn( hparent, hrgn );
7400 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
7401 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
7402 SetRectRgn( hrgn, 0, 0, 50, 50 );
7403 check_update_rgn( hparent, hrgn );
7405 /* flush all paint messages */
7406 flush_events();
7407 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
7408 flush_sequence();
7410 /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
7411 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7412 SetRectRgn( hrgn, 0, 0, 50, 50 );
7413 check_update_rgn( hparent, hrgn );
7414 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
7415 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
7416 SetRectRgn( hrgn2, 10, 10, 50, 50 );
7417 CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
7418 check_update_rgn( hparent, hrgn );
7419 /* flush all paint messages */
7420 flush_events();
7421 flush_sequence();
7423 /* same as above but parent gets completely validated */
7424 SetRect( &rect, 20, 20, 30, 30 );
7425 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7426 SetRectRgn( hrgn, 20, 20, 30, 30 );
7427 check_update_rgn( hparent, hrgn );
7428 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
7429 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
7430 check_update_rgn( hparent, 0 ); /* no update region */
7431 flush_events();
7432 ok_sequence( WmEmptySeq, "WmEmpty", FALSE ); /* and no paint messages */
7434 /* make sure RDW_VALIDATE on child doesn't have the same effect */
7435 flush_sequence();
7436 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7437 SetRectRgn( hrgn, 20, 20, 30, 30 );
7438 check_update_rgn( hparent, hrgn );
7439 RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
7440 SetRectRgn( hrgn, 20, 20, 30, 30 );
7441 check_update_rgn( hparent, hrgn );
7443 /* same as above but normal WM_PAINT doesn't validate parent */
7444 flush_sequence();
7445 SetRect( &rect, 20, 20, 30, 30 );
7446 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7447 SetRectRgn( hrgn, 20, 20, 30, 30 );
7448 check_update_rgn( hparent, hrgn );
7449 /* no WM_PAINT in child while parent still pending */
7450 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
7451 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
7452 while (PeekMessageA( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
7453 ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
7455 flush_sequence();
7456 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7457 /* no WM_PAINT in child while parent still pending */
7458 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
7459 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
7460 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
7461 /* now that parent is valid child should get WM_PAINT */
7462 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
7463 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
7464 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
7465 ok_sequence( WmEmptySeq, "No other message", FALSE );
7467 /* same thing with WS_CLIPCHILDREN in parent */
7468 flush_sequence();
7469 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
7470 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
7471 /* changing style invalidates non client area, but we need to invalidate something else to see it */
7472 RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
7473 ok_sequence( WmEmptySeq, "No message", FALSE );
7474 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
7475 ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
7477 flush_sequence();
7478 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
7479 SetRectRgn( hrgn, 20, 20, 30, 30 );
7480 check_update_rgn( hparent, hrgn );
7481 /* no WM_PAINT in child while parent still pending */
7482 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
7483 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
7484 /* WM_PAINT in parent first */
7485 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
7486 ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
7488 /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
7489 flush_sequence();
7490 SetRect( &rect, 0, 0, 30, 30 );
7491 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
7492 SetRectRgn( hrgn, 0, 0, 30, 30 );
7493 check_update_rgn( hparent, hrgn );
7494 flush_events();
7495 ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
7497 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
7498 flush_sequence();
7499 SetRect( &rect, -10, 0, 30, 30 );
7500 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
7501 SetRect( &rect, 0, 0, 20, 20 );
7502 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
7503 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
7504 ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
7506 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
7507 flush_sequence();
7508 SetRect( &rect, -10, 0, 30, 30 );
7509 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
7510 SetRect( &rect, 0, 0, 100, 100 );
7511 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
7512 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
7513 ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
7514 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
7515 ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
7517 /* WS_CLIPCHILDREN doesn't exclude children from update region */
7518 flush_sequence();
7519 RedrawWindow( hparent, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
7520 GetClientRect( hparent, &rect );
7521 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
7522 check_update_rgn( hparent, hrgn );
7523 flush_events();
7525 RedrawWindow( hparent, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
7526 GetClientRect( hparent, &rect );
7527 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
7528 check_update_rgn( hparent, hrgn );
7529 flush_events();
7531 /* test RDW_INTERNALPAINT behavior */
7533 flush_sequence();
7534 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
7535 flush_events();
7536 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
7538 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
7539 flush_events();
7540 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
7542 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
7543 flush_events();
7544 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
7546 assert( GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
7547 UpdateWindow( hparent );
7548 flush_events();
7549 flush_sequence();
7550 trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
7551 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7552 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
7553 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
7554 flush_events();
7555 ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
7557 UpdateWindow( hparent );
7558 flush_events();
7559 flush_sequence();
7560 trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
7561 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7562 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
7563 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
7564 flush_events();
7565 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
7567 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
7568 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
7569 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
7570 flush_events();
7571 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
7573 assert( !(GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
7574 UpdateWindow( hparent );
7575 flush_events();
7576 flush_sequence();
7577 trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
7578 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7579 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
7580 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
7581 flush_events();
7582 ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
7584 UpdateWindow( hparent );
7585 flush_events();
7586 flush_sequence();
7587 trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
7588 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7589 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
7590 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
7591 flush_events();
7592 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
7594 ok(GetWindowLongA( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
7595 ok(GetWindowLongA( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
7597 UpdateWindow( hparent );
7598 flush_events();
7599 flush_sequence();
7600 trace("testing SetWindowPos(-10000, -10000) on child\n");
7601 SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
7602 check_update_rgn( hchild, 0 );
7603 flush_events();
7605 #if 0 /* this one doesn't pass under Wine yet */
7606 UpdateWindow( hparent );
7607 flush_events();
7608 flush_sequence();
7609 trace("testing ShowWindow(SW_MINIMIZE) on child\n");
7610 ShowWindow( hchild, SW_MINIMIZE );
7611 check_update_rgn( hchild, 0 );
7612 flush_events();
7613 #endif
7615 UpdateWindow( hparent );
7616 flush_events();
7617 flush_sequence();
7618 trace("testing SetWindowPos(-10000, -10000) on parent\n");
7619 SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
7620 check_update_rgn( hparent, 0 );
7621 flush_events();
7623 log_all_parent_messages--;
7624 DestroyWindow( hparent );
7625 ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
7627 /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
7629 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
7630 100, 100, 200, 200, 0, 0, 0, NULL);
7631 ok (hparent != 0, "Failed to create parent window\n");
7633 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
7634 10, 10, 100, 100, hparent, 0, 0, NULL);
7635 ok (hchild != 0, "Failed to create child window\n");
7637 ShowWindow( hparent, SW_SHOW );
7638 UpdateWindow( hparent );
7639 UpdateWindow( hchild );
7640 flush_events();
7641 flush_sequence();
7643 /* moving child outside of parent boundaries changes update region */
7644 SetRect( &rect, 0, 0, 40, 40 );
7645 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
7646 SetRectRgn( hrgn, 0, 0, 40, 40 );
7647 check_update_rgn( hchild, hrgn );
7648 MoveWindow( hchild, -10, 10, 100, 100, FALSE );
7649 SetRectRgn( hrgn, 10, 0, 40, 40 );
7650 check_update_rgn( hchild, hrgn );
7651 MoveWindow( hchild, -10, -10, 100, 100, FALSE );
7652 SetRectRgn( hrgn, 10, 10, 40, 40 );
7653 check_update_rgn( hchild, hrgn );
7655 /* moving parent off-screen does too */
7656 SetRect( &rect, 0, 0, 100, 100 );
7657 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
7658 SetRectRgn( hrgn, 0, 0, 100, 100 );
7659 check_update_rgn( hparent, hrgn );
7660 SetRectRgn( hrgn, 10, 10, 40, 40 );
7661 check_update_rgn( hchild, hrgn );
7662 MoveWindow( hparent, -20, -20, 200, 200, FALSE );
7663 GetUpdateRect( hparent, &rect2, FALSE );
7664 if (!EqualRect( &rect2, &rect )) /* Win 8 and later don't crop update to screen */
7666 rect.left += 20;
7667 rect.top += 20;
7669 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
7670 check_update_rgn( hparent, hrgn );
7671 SetRectRgn( hrgn, rect.left + 10, rect.top + 10, 40, 40 );
7672 check_update_rgn( hchild, hrgn );
7674 /* invalidated region is cropped by the parent rects */
7675 SetRect( &rect, 0, 0, 50, 50 );
7676 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
7677 SetRectRgn( hrgn, rect2.left + 10, rect2.top + 10, 50, 50 );
7678 check_update_rgn( hchild, hrgn );
7680 DestroyWindow( hparent );
7681 ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
7682 flush_sequence();
7684 DeleteObject( hrgn );
7685 DeleteObject( hrgn2 );
7688 struct wnd_event
7690 HWND hwnd;
7691 HANDLE grand_child;
7692 HANDLE start_event;
7693 HANDLE stop_event;
7696 static DWORD WINAPI thread_proc(void *param)
7698 MSG msg;
7699 struct wnd_event *wnd_event = param;
7701 wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
7702 100, 100, 200, 200, 0, 0, 0, NULL);
7703 ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
7705 SetEvent(wnd_event->start_event);
7707 while (GetMessageA(&msg, 0, 0, 0))
7709 TranslateMessage(&msg);
7710 DispatchMessageA(&msg);
7713 ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
7715 return 0;
7718 static DWORD CALLBACK create_grand_child_thread( void *param )
7720 struct wnd_event *wnd_event = param;
7721 HWND hchild;
7722 MSG msg;
7724 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
7725 WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
7726 ok (hchild != 0, "Failed to create child window\n");
7727 flush_events();
7728 flush_sequence();
7729 SetEvent( wnd_event->start_event );
7731 for (;;)
7733 MsgWaitForMultipleObjects(0, NULL, FALSE, 1000, QS_ALLINPUT);
7734 if (!IsWindow( hchild )) break; /* will be destroyed when parent thread exits */
7735 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7737 return 0;
7740 static DWORD CALLBACK create_child_thread( void *param )
7742 struct wnd_event *wnd_event = param;
7743 struct wnd_event child_event;
7744 DWORD ret, tid;
7745 MSG msg;
7747 child_event.hwnd = CreateWindowExA(0, "TestWindowClass", "Test child",
7748 WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
7749 ok (child_event.hwnd != 0, "Failed to create child window\n");
7750 SetFocus( child_event.hwnd );
7751 flush_events();
7752 flush_sequence();
7753 child_event.start_event = wnd_event->start_event;
7754 wnd_event->grand_child = CreateThread(NULL, 0, create_grand_child_thread, &child_event, 0, &tid);
7755 for (;;)
7757 DWORD ret = MsgWaitForMultipleObjects(1, &child_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
7758 if (ret != 1) break;
7759 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7761 ret = WaitForSingleObject( wnd_event->stop_event, 5000 );
7762 ok( !ret, "WaitForSingleObject failed %x\n", ret );
7763 return 0;
7766 static const char manifest_dep[] =
7767 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
7768 "<assemblyIdentity version=\"1.2.3.4\" name=\"testdep1\" type=\"win32\" processorArchitecture=\"" ARCH "\"/>"
7769 " <file name=\"testdep.dll\" />"
7770 "</assembly>";
7772 static const char manifest_main[] =
7773 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
7774 "<assemblyIdentity version=\"1.2.3.4\" name=\"Wine.Test\" type=\"win32\" />"
7775 "<dependency>"
7776 " <dependentAssembly>"
7777 " <assemblyIdentity type=\"win32\" name=\"testdep1\" version=\"1.2.3.4\" processorArchitecture=\"" ARCH "\" />"
7778 " </dependentAssembly>"
7779 "</dependency>"
7780 "</assembly>";
7782 static void create_manifest_file(const char *filename, const char *manifest)
7784 WCHAR path[MAX_PATH];
7785 HANDLE file;
7786 DWORD size;
7788 MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH );
7789 file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7790 ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
7791 WriteFile(file, manifest, strlen(manifest), &size, NULL);
7792 CloseHandle(file);
7795 static HANDLE test_create(const char *file)
7797 WCHAR path[MAX_PATH];
7798 ACTCTXW actctx;
7799 HANDLE handle;
7801 MultiByteToWideChar(CP_ACP, 0, file, -1, path, MAX_PATH);
7802 memset(&actctx, 0, sizeof(ACTCTXW));
7803 actctx.cbSize = sizeof(ACTCTXW);
7804 actctx.lpSource = path;
7806 handle = pCreateActCtxW(&actctx);
7807 ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %u\n", GetLastError());
7809 ok(actctx.cbSize == sizeof(actctx), "cbSize=%d\n", actctx.cbSize);
7810 ok(actctx.dwFlags == 0, "dwFlags=%d\n", actctx.dwFlags);
7811 ok(actctx.lpSource == path, "lpSource=%p\n", actctx.lpSource);
7812 ok(actctx.wProcessorArchitecture == 0, "wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture);
7813 ok(actctx.wLangId == 0, "wLangId=%d\n", actctx.wLangId);
7814 ok(actctx.lpAssemblyDirectory == NULL, "lpAssemblyDirectory=%p\n", actctx.lpAssemblyDirectory);
7815 ok(actctx.lpResourceName == NULL, "lpResourceName=%p\n", actctx.lpResourceName);
7816 ok(actctx.lpApplicationName == NULL, "lpApplicationName=%p\n", actctx.lpApplicationName);
7817 ok(actctx.hModule == NULL, "hModule=%p\n", actctx.hModule);
7819 return handle;
7822 static void test_interthread_messages(void)
7824 HANDLE hThread, context, handle, event;
7825 ULONG_PTR cookie;
7826 DWORD tid;
7827 WNDPROC proc;
7828 MSG msg;
7829 char buf[256];
7830 int len, expected_len;
7831 struct wnd_event wnd_event;
7832 BOOL ret;
7834 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
7835 if (!wnd_event.start_event)
7837 win_skip("skipping interthread message test under win9x\n");
7838 return;
7841 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
7842 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
7844 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7846 CloseHandle(wnd_event.start_event);
7848 SetLastError(0xdeadbeef);
7849 ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeeded\n");
7850 ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
7851 "wrong error code %d\n", GetLastError());
7853 proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
7854 ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
7856 expected_len = lstrlenA("window caption text");
7857 memset(buf, 0, sizeof(buf));
7858 SetLastError(0xdeadbeef);
7859 len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
7860 ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
7861 ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
7863 msg.hwnd = wnd_event.hwnd;
7864 msg.message = WM_GETTEXT;
7865 msg.wParam = sizeof(buf);
7866 msg.lParam = (LPARAM)buf;
7867 memset(buf, 0, sizeof(buf));
7868 SetLastError(0xdeadbeef);
7869 len = DispatchMessageA(&msg);
7870 ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */
7871 "DispatchMessageA(WM_GETTEXT) succeeded on another thread window: ret %d, error %d\n", len, GetLastError());
7873 /* the following test causes an exception in user.exe under win9x */
7874 msg.hwnd = wnd_event.hwnd;
7875 msg.message = WM_TIMER;
7876 msg.wParam = 0;
7877 msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
7878 SetLastError(0xdeadbeef);
7879 len = DispatchMessageA(&msg);
7880 ok(!len && GetLastError() == 0xdeadbeef,
7881 "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
7883 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
7884 ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
7886 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7887 CloseHandle(hThread);
7889 ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
7891 wnd_event.hwnd = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7892 100, 100, 200, 200, 0, 0, 0, NULL);
7893 ok (wnd_event.hwnd != 0, "Failed to create parent window\n");
7894 flush_events();
7895 flush_sequence();
7896 log_all_parent_messages++;
7897 wnd_event.start_event = CreateEventA( NULL, TRUE, FALSE, NULL );
7898 wnd_event.stop_event = CreateEventA( NULL, TRUE, FALSE, NULL );
7899 hThread = CreateThread( NULL, 0, create_child_thread, &wnd_event, 0, &tid );
7900 for (;;)
7902 ret = MsgWaitForMultipleObjects(1, &wnd_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
7903 if (ret != 1) break;
7904 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7906 ok( !ret, "MsgWaitForMultipleObjects failed %x\n", ret );
7907 /* now wait for the thread without processing messages; this shouldn't deadlock */
7908 SetEvent( wnd_event.stop_event );
7909 ret = WaitForSingleObject( hThread, 5000 );
7910 ok( !ret, "WaitForSingleObject failed %x\n", ret );
7911 CloseHandle( hThread );
7913 ret = WaitForSingleObject( wnd_event.grand_child, 5000 );
7914 ok( !ret, "WaitForSingleObject failed %x\n", ret );
7915 CloseHandle( wnd_event.grand_child );
7917 CloseHandle( wnd_event.start_event );
7918 CloseHandle( wnd_event.stop_event );
7919 flush_events();
7920 ok_sequence(WmExitThreadSeq, "destroy child on thread exit", FALSE);
7921 log_all_parent_messages--;
7922 DestroyWindow( wnd_event.hwnd );
7924 /* activation context tests */
7925 if (!pActivateActCtx)
7927 win_skip("Activation contexts are not supported, skipping\n");
7928 return;
7931 create_manifest_file("testdep1.manifest", manifest_dep);
7932 create_manifest_file("main.manifest", manifest_main);
7934 context = test_create("main.manifest");
7935 DeleteFileA("testdep1.manifest");
7936 DeleteFileA("main.manifest");
7938 handle = (void*)0xdeadbeef;
7939 ret = pGetCurrentActCtx(&handle);
7940 ok(ret, "GetCurrentActCtx failed: %u\n", GetLastError());
7941 ok(handle == 0, "active context %p\n", handle);
7943 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
7944 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
7945 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
7946 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7947 CloseHandle(wnd_event.start_event);
7949 /* context is activated after thread creation, so it doesn't inherit it by default */
7950 ret = pActivateActCtx(context, &cookie);
7951 ok(ret, "activation failed: %u\n", GetLastError());
7953 handle = 0;
7954 ret = pGetCurrentActCtx(&handle);
7955 ok(ret, "GetCurrentActCtx failed: %u\n", GetLastError());
7956 ok(handle != 0, "active context %p\n", handle);
7957 pReleaseActCtx(handle);
7959 /* destination window will test for active context */
7960 ret = SendMessageA(wnd_event.hwnd, WM_USER+10, 0, 0);
7961 ok(ret, "thread window returned %d\n", ret);
7963 event = CreateEventW(NULL, 0, 0, NULL);
7964 ret = PostMessageA(wnd_event.hwnd, WM_USER+10, 0, (LPARAM)event);
7965 ok(ret, "thread window returned %d\n", ret);
7966 ok(WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7967 CloseHandle(event);
7969 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
7970 ok(ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
7972 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7973 CloseHandle(hThread);
7975 ret = pDeactivateActCtx(0, cookie);
7976 ok(ret, "DeactivateActCtx failed: %u\n", GetLastError());
7977 pReleaseActCtx(context);
7981 static const struct message WmVkN[] = {
7982 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
7983 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
7984 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
7985 { WM_CHAR, wparam|lparam, 'n', 1 },
7986 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
7987 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
7988 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
7989 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
7990 { 0 }
7992 static const struct message WmShiftVkN[] = {
7993 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
7994 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
7995 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
7996 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
7997 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
7998 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
7999 { WM_CHAR, wparam|lparam, 'N', 1 },
8000 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
8001 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8002 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8003 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8004 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
8005 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
8006 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
8007 { 0 }
8009 static const struct message WmCtrlVkN[] = {
8010 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8011 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8012 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8013 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8014 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8015 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
8016 { WM_CHAR, wparam|lparam, 0x000e, 1 },
8017 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
8018 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8019 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8020 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8021 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8022 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8023 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8024 { 0 }
8026 static const struct message WmCtrlVkN_2[] = {
8027 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8028 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8029 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8030 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8031 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8032 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
8033 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8034 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8035 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8036 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8037 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8038 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8039 { 0 }
8041 static const struct message WmAltVkN[] = {
8042 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8043 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8044 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8045 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8046 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
8047 { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
8048 { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
8049 { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
8050 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
8051 { HCBT_SYSCOMMAND, hook },
8052 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8053 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8054 { 0x00AE, sent|defwinproc|optional }, /* XP */
8055 { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
8056 { WM_INITMENU, sent|defwinproc },
8057 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8058 { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
8059 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8060 { WM_CAPTURECHANGED, sent|defwinproc },
8061 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
8062 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8063 { WM_EXITMENULOOP, sent|defwinproc },
8064 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
8065 { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
8066 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8067 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
8068 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8069 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8070 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8071 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8072 { 0 }
8074 static const struct message WmAltVkN_2[] = {
8075 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8076 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8077 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8078 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8079 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
8080 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
8081 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8082 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
8083 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8084 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8085 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8086 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8087 { 0 }
8089 static const struct message WmCtrlAltVkN[] = {
8090 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8091 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8092 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8093 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8094 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8095 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8096 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8097 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
8098 { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
8099 { WM_CHAR, optional },
8100 { WM_CHAR, sent|optional },
8101 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8102 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
8103 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8104 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8105 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8106 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8107 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8108 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8109 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8110 { 0 }
8112 static const struct message WmCtrlShiftVkN[] = {
8113 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8114 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8115 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8116 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8117 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8118 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
8119 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8120 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8121 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
8122 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8123 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8124 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8125 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
8126 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
8127 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
8128 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8129 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8130 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8131 { 0 }
8133 static const struct message WmCtrlAltShiftVkN[] = {
8134 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8135 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8136 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8137 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8138 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8139 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8140 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
8141 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
8142 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
8143 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8144 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
8145 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
8146 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8147 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
8148 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8149 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
8150 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
8151 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
8152 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8153 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8154 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8155 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8156 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8157 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8158 { 0 }
8160 static const struct message WmAltPressRelease[] = {
8161 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8162 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8163 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8164 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8165 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8166 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8167 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
8168 { HCBT_SYSCOMMAND, hook },
8169 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8170 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8171 { WM_INITMENU, sent|defwinproc },
8172 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8173 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
8174 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
8176 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
8178 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8179 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
8180 { WM_CAPTURECHANGED, sent|defwinproc },
8181 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
8182 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8183 { WM_EXITMENULOOP, sent|defwinproc },
8184 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8185 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8186 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8187 { 0 }
8189 static const struct message WmShiftMouseButton[] = {
8190 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8191 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8192 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
8193 { WM_MOUSEMOVE, wparam|optional, 0, 0 },
8194 { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
8195 { WM_LBUTTONDOWN, wparam, MK_LBUTTON|MK_SHIFT, 0 },
8196 { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON|MK_SHIFT, 0 },
8197 { WM_LBUTTONUP, wparam, MK_SHIFT, 0 },
8198 { WM_LBUTTONUP, sent|wparam, MK_SHIFT, 0 },
8199 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
8200 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
8201 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
8202 { 0 }
8204 static const struct message WmF1Seq[] = {
8205 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
8206 { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
8207 { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
8208 { WM_KEYF1, wparam|lparam, 0, 0 },
8209 { WM_KEYF1, sent|wparam|lparam, 0, 0 },
8210 { WM_HELP, sent|defwinproc },
8211 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
8212 { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
8213 { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
8214 { 0 }
8216 static const struct message WmVkAppsSeq[] = {
8217 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
8218 { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
8219 { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
8220 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
8221 { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
8222 { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
8223 { WM_CONTEXTMENU, lparam, /*hwnd*/0, -1 },
8224 { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, -1 },
8225 { 0 }
8227 static const struct message WmVkF10Seq[] = {
8228 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
8229 { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
8230 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
8231 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
8232 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
8233 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
8234 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
8235 { HCBT_SYSCOMMAND, hook },
8236 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8237 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8238 { WM_INITMENU, sent|defwinproc },
8239 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8240 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
8241 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
8243 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0x10000001 }, /* XP */
8245 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
8246 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8247 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
8248 { WM_CAPTURECHANGED, sent|defwinproc },
8249 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
8250 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8251 { WM_EXITMENULOOP, sent|defwinproc },
8252 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
8253 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
8254 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
8255 { 0 }
8257 static const struct message WmShiftF10Seq[] = {
8258 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8259 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8260 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x00000001 },
8261 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
8262 { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
8263 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
8264 { WM_CONTEXTMENU, sent|defwinproc|lparam, /*hwnd*/0, -1 },
8265 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
8266 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
8267 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
8268 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
8269 { HCBT_SYSCOMMAND, hook },
8270 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8271 { WM_INITMENU, sent|defwinproc },
8272 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
8273 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xd0000001 }, /* XP */
8274 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0x10000001 }, /* XP */
8275 { WM_CAPTURECHANGED, sent|defwinproc|wparam|lparam, 0, 0 },
8276 { WM_MENUSELECT, sent|defwinproc|wparam|lparam, 0xffff0000, 0 },
8277 { WM_EXITMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8278 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 }, /* XP */
8279 { WM_KEYUP, wparam|lparam, VK_ESCAPE, 0xc0000001 },
8280 { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
8281 { 0 }
8284 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
8286 MSG msg;
8288 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
8290 struct recvd_message log_msg;
8292 /* ignore some unwanted messages */
8293 if (msg.message == WM_MOUSEMOVE ||
8294 msg.message == WM_TIMER ||
8295 ignore_message( msg.message ))
8296 continue;
8298 log_msg.hwnd = msg.hwnd;
8299 log_msg.message = msg.message;
8300 log_msg.flags = wparam|lparam;
8301 log_msg.wParam = msg.wParam;
8302 log_msg.lParam = msg.lParam;
8303 log_msg.descr = "accel";
8304 add_message(&log_msg);
8306 if (!hAccel || !TranslateAcceleratorA(hwnd, hAccel, &msg))
8308 TranslateMessage(&msg);
8309 DispatchMessageA(&msg);
8314 static void test_accelerators(void)
8316 RECT rc;
8317 POINT pt;
8318 SHORT state;
8319 HACCEL hAccel;
8320 HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8321 100, 100, 200, 200, 0, 0, 0, NULL);
8322 BOOL ret;
8324 assert(hwnd != 0);
8325 UpdateWindow(hwnd);
8326 flush_events();
8327 flush_sequence();
8329 SetFocus(hwnd);
8330 ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
8332 state = GetKeyState(VK_SHIFT);
8333 ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
8334 state = GetKeyState(VK_CAPITAL);
8335 ok(state == 0, "wrong CapsLock state %04x\n", state);
8337 hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
8338 assert(hAccel != 0);
8340 flush_events();
8341 pump_msg_loop(hwnd, 0);
8342 flush_sequence();
8344 trace("testing VK_N press/release\n");
8345 flush_sequence();
8346 keybd_event('N', 0, 0, 0);
8347 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8348 pump_msg_loop(hwnd, hAccel);
8349 if (!sequence_cnt) /* we didn't get any message */
8351 skip( "queuing key events not supported\n" );
8352 goto done;
8354 ok_sequence(WmVkN, "VK_N press/release", FALSE);
8356 trace("testing Shift+VK_N press/release\n");
8357 flush_sequence();
8358 keybd_event(VK_SHIFT, 0, 0, 0);
8359 keybd_event('N', 0, 0, 0);
8360 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8361 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
8362 pump_msg_loop(hwnd, hAccel);
8363 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
8365 trace("testing Ctrl+VK_N press/release\n");
8366 flush_sequence();
8367 keybd_event(VK_CONTROL, 0, 0, 0);
8368 keybd_event('N', 0, 0, 0);
8369 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8370 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
8371 pump_msg_loop(hwnd, hAccel);
8372 ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
8374 trace("testing Alt+VK_N press/release\n");
8375 flush_sequence();
8376 keybd_event(VK_MENU, 0, 0, 0);
8377 keybd_event('N', 0, 0, 0);
8378 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8379 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
8380 pump_msg_loop(hwnd, hAccel);
8381 ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
8383 trace("testing Ctrl+Alt+VK_N press/release 1\n");
8384 flush_sequence();
8385 keybd_event(VK_CONTROL, 0, 0, 0);
8386 keybd_event(VK_MENU, 0, 0, 0);
8387 keybd_event('N', 0, 0, 0);
8388 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8389 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
8390 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
8391 pump_msg_loop(hwnd, hAccel);
8392 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
8394 ret = DestroyAcceleratorTable(hAccel);
8395 ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
8397 hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(2));
8398 assert(hAccel != 0);
8400 trace("testing VK_N press/release\n");
8401 flush_sequence();
8402 keybd_event('N', 0, 0, 0);
8403 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8404 pump_msg_loop(hwnd, hAccel);
8405 ok_sequence(WmVkN, "VK_N press/release", FALSE);
8407 trace("testing Shift+VK_N press/release\n");
8408 flush_sequence();
8409 keybd_event(VK_SHIFT, 0, 0, 0);
8410 keybd_event('N', 0, 0, 0);
8411 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8412 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
8413 pump_msg_loop(hwnd, hAccel);
8414 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
8416 trace("testing Ctrl+VK_N press/release 2\n");
8417 flush_sequence();
8418 keybd_event(VK_CONTROL, 0, 0, 0);
8419 keybd_event('N', 0, 0, 0);
8420 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8421 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
8422 pump_msg_loop(hwnd, hAccel);
8423 ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
8425 trace("testing Alt+VK_N press/release 2\n");
8426 flush_sequence();
8427 keybd_event(VK_MENU, 0, 0, 0);
8428 keybd_event('N', 0, 0, 0);
8429 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8430 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
8431 pump_msg_loop(hwnd, hAccel);
8432 ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
8434 trace("testing Ctrl+Alt+VK_N press/release 2\n");
8435 flush_sequence();
8436 keybd_event(VK_CONTROL, 0, 0, 0);
8437 keybd_event(VK_MENU, 0, 0, 0);
8438 keybd_event('N', 0, 0, 0);
8439 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8440 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
8441 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
8442 pump_msg_loop(hwnd, hAccel);
8443 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
8445 trace("testing Ctrl+Shift+VK_N press/release\n");
8446 flush_sequence();
8447 keybd_event(VK_CONTROL, 0, 0, 0);
8448 keybd_event(VK_SHIFT, 0, 0, 0);
8449 keybd_event('N', 0, 0, 0);
8450 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8451 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
8452 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
8453 pump_msg_loop(hwnd, hAccel);
8454 ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
8456 trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
8457 flush_sequence();
8458 keybd_event(VK_CONTROL, 0, 0, 0);
8459 keybd_event(VK_MENU, 0, 0, 0);
8460 keybd_event(VK_SHIFT, 0, 0, 0);
8461 keybd_event('N', 0, 0, 0);
8462 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8463 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
8464 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
8465 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
8466 pump_msg_loop(hwnd, hAccel);
8467 ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
8469 ret = DestroyAcceleratorTable(hAccel);
8470 ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
8471 hAccel = 0;
8473 trace("testing Alt press/release\n");
8474 flush_sequence();
8475 keybd_event(VK_MENU, 0, 0, 0);
8476 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
8477 keybd_event(VK_MENU, 0, 0, 0);
8478 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
8479 pump_msg_loop(hwnd, 0);
8480 /* this test doesn't pass in Wine for managed windows */
8481 ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
8483 trace("testing VK_F1 press/release\n");
8484 keybd_event(VK_F1, 0, 0, 0);
8485 keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
8486 pump_msg_loop(hwnd, 0);
8487 ok_sequence(WmF1Seq, "F1 press/release", FALSE);
8489 trace("testing VK_APPS press/release\n");
8490 keybd_event(VK_APPS, 0, 0, 0);
8491 keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
8492 pump_msg_loop(hwnd, 0);
8493 ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
8495 trace("testing VK_F10 press/release\n");
8496 keybd_event(VK_F10, 0, 0, 0);
8497 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
8498 keybd_event(VK_F10, 0, 0, 0);
8499 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
8500 pump_msg_loop(hwnd, 0);
8501 ok_sequence(WmVkF10Seq, "VK_F10 press/release", TRUE);
8503 trace("testing SHIFT+F10 press/release\n");
8504 keybd_event(VK_SHIFT, 0, 0, 0);
8505 keybd_event(VK_F10, 0, 0, 0);
8506 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
8507 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
8508 keybd_event(VK_ESCAPE, 0, 0, 0);
8509 keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
8510 pump_msg_loop(hwnd, 0);
8511 ok_sequence(WmShiftF10Seq, "SHIFT+F10 press/release", TRUE);
8513 trace("testing Shift+MouseButton press/release\n");
8514 /* first, move mouse pointer inside of the window client area */
8515 GetClientRect(hwnd, &rc);
8516 MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
8517 rc.left += (rc.right - rc.left)/2;
8518 rc.top += (rc.bottom - rc.top)/2;
8519 SetCursorPos(rc.left, rc.top);
8520 SetActiveWindow(hwnd);
8522 flush_events();
8523 flush_sequence();
8524 GetCursorPos(&pt);
8525 if (pt.x == rc.left && pt.y == rc.top)
8527 int i;
8528 keybd_event(VK_SHIFT, 0, 0, 0);
8529 mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
8530 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
8531 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
8532 pump_msg_loop(hwnd, 0);
8533 for (i = 0; i < sequence_cnt; i++) if (sequence[i].message == WM_LBUTTONDOWN) break;
8534 if (i < sequence_cnt)
8535 ok_sequence(WmShiftMouseButton, "Shift+MouseButton press/release", FALSE);
8536 else
8537 skip( "Shift+MouseButton event didn't get to the window\n" );
8540 done:
8541 if (hAccel) DestroyAcceleratorTable(hAccel);
8542 DestroyWindow(hwnd);
8545 /************* window procedures ********************/
8547 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message,
8548 WPARAM wParam, LPARAM lParam)
8550 static LONG defwndproc_counter = 0;
8551 static LONG beginpaint_counter = 0;
8552 LRESULT ret;
8553 struct recvd_message msg;
8555 if (ignore_message( message )) return 0;
8557 switch (message)
8559 case WM_ENABLE:
8561 LONG style = GetWindowLongA(hwnd, GWL_STYLE);
8562 ok((BOOL)wParam == !(style & WS_DISABLED),
8563 "wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
8564 break;
8567 case WM_CAPTURECHANGED:
8568 if (test_DestroyWindow_flag)
8570 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
8571 if (style & WS_CHILD)
8572 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
8573 else if (style & WS_POPUP)
8574 lParam = WND_POPUP_ID;
8575 else
8576 lParam = WND_PARENT_ID;
8578 break;
8580 case WM_NCDESTROY:
8582 HWND capture;
8584 ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
8585 capture = GetCapture();
8586 if (capture)
8588 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
8589 trace("current capture %p, releasing...\n", capture);
8590 ReleaseCapture();
8593 /* fall through */
8594 case WM_DESTROY:
8595 if (pGetAncestor)
8596 ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
8597 if (test_DestroyWindow_flag)
8599 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
8600 if (style & WS_CHILD)
8601 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
8602 else if (style & WS_POPUP)
8603 lParam = WND_POPUP_ID;
8604 else
8605 lParam = WND_PARENT_ID;
8607 break;
8609 /* test_accelerators() depends on this */
8610 case WM_NCHITTEST:
8611 return HTCLIENT;
8613 case WM_USER+10:
8615 ACTIVATION_CONTEXT_BASIC_INFORMATION basicinfo;
8616 HANDLE handle, event = (HANDLE)lParam;
8617 BOOL ret;
8619 handle = (void*)0xdeadbeef;
8620 ret = pGetCurrentActCtx(&handle);
8621 ok(ret, "failed to get current context, %u\n", GetLastError());
8622 ok(handle == 0, "got active context %p\n", handle);
8624 memset(&basicinfo, 0xff, sizeof(basicinfo));
8625 ret = pQueryActCtxW(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX, handle, 0, ActivationContextBasicInformation,
8626 &basicinfo, sizeof(basicinfo), NULL);
8627 ok(ret, "got %d, error %d\n", ret, GetLastError());
8628 ok(basicinfo.hActCtx == NULL, "got %p\n", basicinfo.hActCtx);
8629 ok(basicinfo.dwFlags == 0, "got %x\n", basicinfo.dwFlags);
8631 if (event) SetEvent(event);
8632 return 1;
8635 /* ignore */
8636 case WM_MOUSEMOVE:
8637 case WM_MOUSEACTIVATE:
8638 case WM_NCMOUSEMOVE:
8639 case WM_SETCURSOR:
8640 case WM_IME_SELECT:
8641 return 0;
8644 msg.hwnd = hwnd;
8645 msg.message = message;
8646 msg.flags = sent|wparam|lparam;
8647 if (defwndproc_counter) msg.flags |= defwinproc;
8648 if (beginpaint_counter) msg.flags |= beginpaint;
8649 msg.wParam = wParam;
8650 msg.lParam = lParam;
8651 msg.descr = "MsgCheckProc";
8652 add_message(&msg);
8654 if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
8656 HWND parent = GetParent(hwnd);
8657 RECT rc;
8658 MINMAXINFO *minmax = (MINMAXINFO *)lParam;
8660 GetClientRect(parent, &rc);
8661 trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
8662 trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n",
8663 minmax->ptReserved.x, minmax->ptReserved.y,
8664 minmax->ptMaxSize.x, minmax->ptMaxSize.y,
8665 minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
8666 minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
8667 minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
8669 ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
8670 minmax->ptMaxSize.x, rc.right);
8671 ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
8672 minmax->ptMaxSize.y, rc.bottom);
8675 if (message == WM_PAINT)
8677 PAINTSTRUCT ps;
8678 beginpaint_counter++;
8679 BeginPaint( hwnd, &ps );
8680 beginpaint_counter--;
8681 EndPaint( hwnd, &ps );
8682 return 0;
8685 if (message == WM_CONTEXTMENU)
8687 /* don't create context menu */
8688 return 0;
8691 defwndproc_counter++;
8692 ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam)
8693 : DefWindowProcA(hwnd, message, wParam, lParam);
8694 defwndproc_counter--;
8696 return ret;
8699 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8701 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
8704 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8706 return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
8709 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8711 static LONG defwndproc_counter = 0;
8712 LRESULT ret;
8713 struct recvd_message msg;
8715 if (ignore_message( message )) return 0;
8717 switch (message)
8719 case WM_QUERYENDSESSION:
8720 case WM_ENDSESSION:
8721 lParam &= ~0x01; /* Vista adds a 0x01 flag */
8722 break;
8725 msg.hwnd = hwnd;
8726 msg.message = message;
8727 msg.flags = sent|wparam|lparam;
8728 if (defwndproc_counter) msg.flags |= defwinproc;
8729 msg.wParam = wParam;
8730 msg.lParam = lParam;
8731 msg.descr = "popup";
8732 add_message(&msg);
8734 if (message == WM_CREATE)
8736 DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
8737 SetWindowLongA(hwnd, GWL_STYLE, style);
8740 defwndproc_counter++;
8741 ret = DefWindowProcA(hwnd, message, wParam, lParam);
8742 defwndproc_counter--;
8744 return ret;
8747 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8749 static LONG defwndproc_counter = 0;
8750 static LONG beginpaint_counter = 0;
8751 LRESULT ret;
8752 struct recvd_message msg;
8754 if (ignore_message( message )) return 0;
8756 if (log_all_parent_messages ||
8757 message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
8758 message == WM_SETFOCUS || message == WM_KILLFOCUS ||
8759 message == WM_ENABLE || message == WM_ENTERIDLE ||
8760 message == WM_DRAWITEM || message == WM_COMMAND ||
8761 message == WM_IME_SETCONTEXT)
8763 switch (message)
8765 /* ignore */
8766 case WM_NCHITTEST:
8767 return HTCLIENT;
8768 case WM_SETCURSOR:
8769 case WM_MOUSEMOVE:
8770 case WM_NCMOUSEMOVE:
8771 return 0;
8773 case WM_ERASEBKGND:
8775 RECT rc;
8776 INT ret = GetClipBox((HDC)wParam, &rc);
8778 trace("WM_ERASEBKGND: GetClipBox()=%d, %s\n", ret, wine_dbgstr_rect(&rc));
8779 break;
8783 msg.hwnd = hwnd;
8784 msg.message = message;
8785 msg.flags = sent|parent|wparam|lparam;
8786 if (defwndproc_counter) msg.flags |= defwinproc;
8787 if (beginpaint_counter) msg.flags |= beginpaint;
8788 msg.wParam = wParam;
8789 msg.lParam = lParam;
8790 msg.descr = "parent";
8791 add_message(&msg);
8794 if (message == WM_PAINT)
8796 PAINTSTRUCT ps;
8797 beginpaint_counter++;
8798 BeginPaint( hwnd, &ps );
8799 beginpaint_counter--;
8800 EndPaint( hwnd, &ps );
8801 return 0;
8804 defwndproc_counter++;
8805 ret = DefWindowProcA(hwnd, message, wParam, lParam);
8806 defwndproc_counter--;
8808 return ret;
8811 static INT_PTR CALLBACK StopQuitMsgCheckProcA(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
8813 if (message == WM_CREATE)
8814 PostMessageA(hwnd, WM_CLOSE, 0, 0);
8815 else if (message == WM_CLOSE)
8817 /* Only the first WM_QUIT will survive the window destruction */
8818 PostMessageA(hwnd, WM_USER, 0x1234, 0x5678);
8819 PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
8820 PostMessageA(hwnd, WM_QUIT, 0x4321, 0x8765);
8823 return DefWindowProcA(hwnd, message, wp, lp);
8826 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8828 static LONG defwndproc_counter = 0;
8829 LRESULT ret;
8830 struct recvd_message msg;
8832 if (ignore_message( message )) return 0;
8834 if (test_def_id)
8836 DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
8837 ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
8838 if (after_end_dialog)
8839 ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
8840 else
8841 ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
8844 msg.hwnd = hwnd;
8845 msg.message = message;
8846 msg.flags = sent|wparam|lparam;
8847 if (defwndproc_counter) msg.flags |= defwinproc;
8848 msg.wParam = wParam;
8849 msg.lParam = lParam;
8850 msg.descr = "dialog";
8851 add_message(&msg);
8853 defwndproc_counter++;
8854 ret = DefDlgProcA(hwnd, message, wParam, lParam);
8855 defwndproc_counter--;
8857 return ret;
8860 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8862 static LONG defwndproc_counter = 0;
8863 LRESULT ret;
8864 struct recvd_message msg;
8866 /* log only specific messages we are interested in */
8867 switch (message)
8869 #if 0 /* probably log these as well */
8870 case WM_ACTIVATE:
8871 case WM_SETFOCUS:
8872 case WM_KILLFOCUS:
8873 #endif
8874 case WM_SHOWWINDOW:
8875 case WM_SIZE:
8876 case WM_MOVE:
8877 case WM_GETMINMAXINFO:
8878 case WM_WINDOWPOSCHANGING:
8879 case WM_WINDOWPOSCHANGED:
8880 break;
8882 default: /* ignore */
8883 /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
8884 return DefWindowProcA(hwnd, message, wParam, lParam);
8887 msg.hwnd = hwnd;
8888 msg.message = message;
8889 msg.flags = sent|wparam|lparam;
8890 if (defwndproc_counter) msg.flags |= defwinproc;
8891 msg.wParam = wParam;
8892 msg.lParam = lParam;
8893 msg.descr = "show";
8894 add_message(&msg);
8896 defwndproc_counter++;
8897 ret = DefWindowProcA(hwnd, message, wParam, lParam);
8898 defwndproc_counter--;
8900 return ret;
8903 static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
8905 switch (msg)
8907 case WM_CREATE: return 0;
8908 case WM_PAINT:
8910 MSG msg2;
8911 static int i = 0;
8913 if (i < 256)
8915 i++;
8916 if (PeekMessageA(&msg2, 0, 0, 0, 1))
8918 TranslateMessage(&msg2);
8919 DispatchMessageA(&msg2);
8921 i--;
8923 else ok(broken(1), "infinite loop\n");
8924 if ( i == 0)
8925 paint_loop_done = TRUE;
8926 return DefWindowProcA(hWnd,msg,wParam,lParam);
8929 return DefWindowProcA(hWnd,msg,wParam,lParam);
8932 static LRESULT WINAPI HotkeyMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8934 static LONG defwndproc_counter = 0;
8935 LRESULT ret;
8936 struct recvd_message msg;
8937 DWORD queue_status;
8939 if (ignore_message( message )) return 0;
8941 if ((message >= WM_KEYFIRST && message <= WM_KEYLAST) ||
8942 message == WM_HOTKEY || message >= WM_APP)
8944 msg.hwnd = hwnd;
8945 msg.message = message;
8946 msg.flags = sent|wparam|lparam;
8947 if (defwndproc_counter) msg.flags |= defwinproc;
8948 msg.wParam = wParam;
8949 msg.lParam = lParam;
8950 msg.descr = "HotkeyMsgCheckProcA";
8951 add_message(&msg);
8954 defwndproc_counter++;
8955 ret = DefWindowProcA(hwnd, message, wParam, lParam);
8956 defwndproc_counter--;
8958 if (message == WM_APP)
8960 queue_status = GetQueueStatus(QS_HOTKEY);
8961 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
8962 queue_status = GetQueueStatus(QS_POSTMESSAGE);
8963 ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
8964 PostMessageA(hwnd, WM_APP+1, 0, 0);
8966 else if (message == WM_APP+1)
8968 queue_status = GetQueueStatus(QS_HOTKEY);
8969 ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
8972 return ret;
8975 static BOOL RegisterWindowClasses(void)
8977 WNDCLASSA cls;
8978 WNDCLASSW clsW;
8980 cls.style = 0;
8981 cls.lpfnWndProc = MsgCheckProcA;
8982 cls.cbClsExtra = 0;
8983 cls.cbWndExtra = 0;
8984 cls.hInstance = GetModuleHandleA(0);
8985 cls.hIcon = 0;
8986 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
8987 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
8988 cls.lpszMenuName = NULL;
8989 cls.lpszClassName = "TestWindowClass";
8990 if(!RegisterClassA(&cls)) return FALSE;
8992 cls.lpfnWndProc = HotkeyMsgCheckProcA;
8993 cls.lpszClassName = "HotkeyWindowClass";
8994 if(!RegisterClassA(&cls)) return FALSE;
8996 cls.lpfnWndProc = ShowWindowProcA;
8997 cls.lpszClassName = "ShowWindowClass";
8998 if(!RegisterClassA(&cls)) return FALSE;
9000 cls.lpfnWndProc = PopupMsgCheckProcA;
9001 cls.lpszClassName = "TestPopupClass";
9002 if(!RegisterClassA(&cls)) return FALSE;
9004 cls.lpfnWndProc = ParentMsgCheckProcA;
9005 cls.lpszClassName = "TestParentClass";
9006 if(!RegisterClassA(&cls)) return FALSE;
9008 cls.lpfnWndProc = StopQuitMsgCheckProcA;
9009 cls.lpszClassName = "StopQuitClass";
9010 if(!RegisterClassA(&cls)) return FALSE;
9012 cls.lpfnWndProc = DefWindowProcA;
9013 cls.lpszClassName = "SimpleWindowClass";
9014 if(!RegisterClassA(&cls)) return FALSE;
9016 cls.lpfnWndProc = PaintLoopProcA;
9017 cls.lpszClassName = "PaintLoopWindowClass";
9018 if(!RegisterClassA(&cls)) return FALSE;
9020 cls.style = CS_NOCLOSE;
9021 cls.lpszClassName = "NoCloseWindowClass";
9022 if(!RegisterClassA(&cls)) return FALSE;
9024 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
9025 cls.style = 0;
9026 cls.hInstance = GetModuleHandleA(0);
9027 cls.hbrBackground = 0;
9028 cls.lpfnWndProc = TestDlgProcA;
9029 cls.lpszClassName = "TestDialogClass";
9030 if(!RegisterClassA(&cls)) return FALSE;
9032 clsW.style = 0;
9033 clsW.lpfnWndProc = MsgCheckProcW;
9034 clsW.cbClsExtra = 0;
9035 clsW.cbWndExtra = 0;
9036 clsW.hInstance = GetModuleHandleW(0);
9037 clsW.hIcon = 0;
9038 clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
9039 clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
9040 clsW.lpszMenuName = NULL;
9041 clsW.lpszClassName = testWindowClassW;
9042 RegisterClassW(&clsW); /* ignore error, this fails on Win9x */
9044 return TRUE;
9047 static BOOL is_our_logged_class(HWND hwnd)
9049 char buf[256];
9051 if (GetClassNameA(hwnd, buf, sizeof(buf)))
9053 if (!lstrcmpiA(buf, "TestWindowClass") ||
9054 !lstrcmpiA(buf, "ShowWindowClass") ||
9055 !lstrcmpiA(buf, "TestParentClass") ||
9056 !lstrcmpiA(buf, "TestPopupClass") ||
9057 !lstrcmpiA(buf, "SimpleWindowClass") ||
9058 !lstrcmpiA(buf, "TestDialogClass") ||
9059 !lstrcmpiA(buf, "MDI_frame_class") ||
9060 !lstrcmpiA(buf, "MDI_client_class") ||
9061 !lstrcmpiA(buf, "MDI_child_class") ||
9062 !lstrcmpiA(buf, "my_button_class") ||
9063 !lstrcmpiA(buf, "my_edit_class") ||
9064 !lstrcmpiA(buf, "static") ||
9065 !lstrcmpiA(buf, "ListBox") ||
9066 !lstrcmpiA(buf, "ComboBox") ||
9067 !lstrcmpiA(buf, "MyDialogClass") ||
9068 !lstrcmpiA(buf, "#32770") ||
9069 !lstrcmpiA(buf, "#32768"))
9070 return TRUE;
9072 return FALSE;
9075 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
9077 HWND hwnd;
9079 ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
9081 if (nCode == HCBT_CLICKSKIPPED)
9083 /* ignore this event, XP sends it a lot when switching focus between windows */
9084 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
9087 if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
9089 struct recvd_message msg;
9091 msg.hwnd = 0;
9092 msg.message = nCode;
9093 msg.flags = hook|wparam|lparam;
9094 msg.wParam = wParam;
9095 msg.lParam = lParam;
9096 msg.descr = "CBT";
9097 add_message(&msg);
9099 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
9102 if (nCode == HCBT_DESTROYWND)
9104 if (test_DestroyWindow_flag)
9106 DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
9107 if (style & WS_CHILD)
9108 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
9109 else if (style & WS_POPUP)
9110 lParam = WND_POPUP_ID;
9111 else
9112 lParam = WND_PARENT_ID;
9116 /* Log also SetFocus(0) calls */
9117 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
9119 if (is_our_logged_class(hwnd))
9121 struct recvd_message msg;
9123 msg.hwnd = hwnd;
9124 msg.message = nCode;
9125 msg.flags = hook|wparam|lparam;
9126 msg.wParam = wParam;
9127 msg.lParam = lParam;
9128 msg.descr = "CBT";
9129 add_message(&msg);
9131 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
9134 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
9135 DWORD event,
9136 HWND hwnd,
9137 LONG object_id,
9138 LONG child_id,
9139 DWORD thread_id,
9140 DWORD event_time)
9142 ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
9144 /* ignore mouse cursor events */
9145 if (object_id == OBJID_CURSOR) return;
9147 if (!hwnd || is_our_logged_class(hwnd))
9149 struct recvd_message msg;
9151 msg.hwnd = hwnd;
9152 msg.message = event;
9153 msg.flags = winevent_hook|wparam|lparam;
9154 msg.wParam = object_id;
9155 msg.lParam = child_id;
9156 msg.descr = "WEH";
9157 add_message(&msg);
9161 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
9162 static const WCHAR wszAnsi[] = {'U',0};
9164 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
9166 switch (uMsg)
9168 case CB_FINDSTRINGEXACT:
9169 trace("String: %p\n", (LPCWSTR)lParam);
9170 if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
9171 return 1;
9172 if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
9173 return 0;
9174 return -1;
9176 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
9179 static const struct message WmGetTextLengthAfromW[] = {
9180 { WM_GETTEXTLENGTH, sent },
9181 { WM_GETTEXT, sent|optional },
9182 { 0 }
9185 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
9187 /* dummy window proc for WM_GETTEXTLENGTH test */
9188 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
9190 switch(msg)
9192 case WM_GETTEXTLENGTH:
9193 return lstrlenW(dummy_window_text) + 37; /* some random length */
9194 case WM_GETTEXT:
9195 lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
9196 return lstrlenW( (LPWSTR)lp );
9197 default:
9198 return DefWindowProcW( hwnd, msg, wp, lp );
9202 static void test_message_conversion(void)
9204 static const WCHAR wszMsgConversionClass[] =
9205 {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
9206 WNDCLASSW cls;
9207 LRESULT lRes;
9208 HWND hwnd;
9209 WNDPROC wndproc, newproc;
9210 BOOL ret;
9212 cls.style = 0;
9213 cls.lpfnWndProc = MsgConversionProcW;
9214 cls.cbClsExtra = 0;
9215 cls.cbWndExtra = 0;
9216 cls.hInstance = GetModuleHandleW(NULL);
9217 cls.hIcon = NULL;
9218 cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
9219 cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
9220 cls.lpszMenuName = NULL;
9221 cls.lpszClassName = wszMsgConversionClass;
9222 /* this call will fail on Win9x, but that doesn't matter as this test is
9223 * meaningless on those platforms */
9224 if(!RegisterClassW(&cls)) return;
9226 hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
9227 100, 100, 200, 200, 0, 0, 0, NULL);
9228 ok(hwnd != NULL, "Window creation failed\n");
9230 /* {W, A} -> A */
9232 wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
9233 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9234 ok(lRes == 0, "String should have been converted\n");
9235 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9236 ok(lRes == 1, "String shouldn't have been converted\n");
9238 /* {W, A} -> W */
9240 wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
9241 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9242 ok(lRes == 1, "String shouldn't have been converted\n");
9243 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9244 ok(lRes == 1, "String shouldn't have been converted\n");
9246 /* Synchronous messages */
9248 lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9249 ok(lRes == 0, "String should have been converted\n");
9250 lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9251 ok(lRes == 1, "String shouldn't have been converted\n");
9253 /* Asynchronous messages */
9255 SetLastError(0);
9256 lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9257 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9258 "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9259 SetLastError(0);
9260 lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9261 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9262 "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9263 SetLastError(0);
9264 lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9265 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9266 "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9267 SetLastError(0);
9268 lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9269 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9270 "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9271 SetLastError(0);
9272 lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9273 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9274 "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9275 SetLastError(0);
9276 lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9277 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9278 "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9279 SetLastError(0);
9280 lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
9281 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9282 "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9283 SetLastError(0);
9284 lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
9285 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9286 "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9288 /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
9290 hwnd = CreateWindowW (testWindowClassW, wszUnicode,
9291 WS_OVERLAPPEDWINDOW,
9292 100, 100, 200, 200, 0, 0, 0, NULL);
9293 assert(hwnd);
9294 flush_sequence();
9295 lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
9296 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
9297 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
9298 "got bad length %ld\n", lRes );
9300 flush_sequence();
9301 lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
9302 hwnd, WM_GETTEXTLENGTH, 0, 0);
9303 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
9304 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
9305 "got bad length %ld\n", lRes );
9307 wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
9308 newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
9309 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
9310 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
9311 NULL, 0, NULL, NULL ) ||
9312 broken(lRes == lstrlenW(dummy_window_text) + 37),
9313 "got bad length %ld\n", lRes );
9315 SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc ); /* restore old wnd proc */
9316 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
9317 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
9318 NULL, 0, NULL, NULL ) ||
9319 broken(lRes == lstrlenW(dummy_window_text) + 37),
9320 "got bad length %ld\n", lRes );
9322 ret = DestroyWindow(hwnd);
9323 ok( ret, "DestroyWindow() error %d\n", GetLastError());
9326 struct timer_info
9328 HWND hWnd;
9329 HANDLE handles[2];
9330 DWORD id;
9333 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
9337 #define TIMER_ID 0x19
9338 #define TIMER_COUNT_EXPECTED 100
9339 #define TIMER_COUNT_TOLERANCE 10
9341 static int count = 0;
9342 static void CALLBACK callback_count(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
9344 count++;
9347 static DWORD exception;
9348 static void CALLBACK callback_exception(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
9350 count++;
9351 RaiseException(exception, 0, 0, NULL);
9354 static DWORD WINAPI timer_thread_proc(LPVOID x)
9356 struct timer_info *info = x;
9357 DWORD r;
9359 r = KillTimer(info->hWnd, 0x19);
9360 ok(r,"KillTimer failed in thread\n");
9361 r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
9362 ok(r,"SetTimer failed in thread\n");
9363 ok(r==TIMER_ID,"SetTimer id different\n");
9364 r = SetEvent(info->handles[0]);
9365 ok(r,"SetEvent failed in thread\n");
9366 return 0;
9369 static void test_timers(void)
9371 struct timer_info info;
9372 DWORD start;
9373 DWORD id;
9374 MSG msg;
9376 info.hWnd = CreateWindowA("TestWindowClass", NULL,
9377 WS_OVERLAPPEDWINDOW ,
9378 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
9379 NULL, NULL, 0);
9381 info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
9382 ok(info.id, "SetTimer failed\n");
9383 ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
9384 info.handles[0] = CreateEventW(NULL,0,0,NULL);
9385 info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
9387 WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
9389 WaitForSingleObject(info.handles[1], INFINITE);
9391 CloseHandle(info.handles[0]);
9392 CloseHandle(info.handles[1]);
9394 ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
9396 /* Check the minimum allowed timeout for a timer. MSDN indicates that it should be 10.0 ms,
9397 * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to
9398 * 15.6 ms. Since there is some measurement error between test runs we are allowing for
9399 * ±9 counts (~4 ms) around the expected value.
9401 count = 0;
9402 id = SetTimer(info.hWnd, TIMER_ID, 0, callback_count);
9403 ok(id != 0, "did not get id from SetTimer.\n");
9404 ok(id==TIMER_ID, "SetTimer timer ID different\n");
9405 start = GetTickCount();
9406 while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
9407 DispatchMessageA(&msg);
9408 ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE /* xp */
9409 || broken(abs(count-64) < TIMER_COUNT_TOLERANCE) /* most common */
9410 || broken(abs(count-43) < TIMER_COUNT_TOLERANCE) /* w2k3, win8 */,
9411 "did not get expected count for minimum timeout (%d != ~%d).\n",
9412 count, TIMER_COUNT_EXPECTED);
9413 ok(KillTimer(info.hWnd, id), "KillTimer failed\n");
9414 /* Perform the same check on SetSystemTimer (only available on w2k3 and older) */
9415 if (pSetSystemTimer)
9417 int syscount = 0;
9419 count = 0;
9420 id = pSetSystemTimer(info.hWnd, TIMER_ID, 0, callback_count);
9421 ok(id != 0, "did not get id from SetSystemTimer.\n");
9422 ok(id==TIMER_ID, "SetTimer timer ID different\n");
9423 start = GetTickCount();
9424 while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
9426 if (msg.message == WM_SYSTIMER)
9427 syscount++;
9428 DispatchMessageA(&msg);
9430 ok(abs(syscount-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE
9431 || broken(abs(syscount-64) < TIMER_COUNT_TOLERANCE) /* most common */
9432 || broken(syscount > 4000 && syscount < 12000) /* win2k3sp0 */,
9433 "did not get expected count for minimum timeout (%d != ~%d).\n",
9434 syscount, TIMER_COUNT_EXPECTED);
9435 todo_wine ok(count == 0, "did not get expected count for callback timeout (%d != 0).\n",
9436 count);
9437 ok(pKillSystemTimer(info.hWnd, id), "KillSystemTimer failed\n");
9440 ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
9443 static void test_timers_no_wnd(void)
9445 static UINT_PTR ids[0xffff];
9446 UINT_PTR id, id2;
9447 DWORD start;
9448 MSG msg;
9449 int i;
9451 count = 0;
9452 id = SetTimer(NULL, 0, 100, callback_count);
9453 ok(id != 0, "did not get id from SetTimer.\n");
9454 id2 = SetTimer(NULL, id, 200, callback_count);
9455 ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
9456 Sleep(150);
9457 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
9458 ok(count == 0, "did not get zero count as expected (%i).\n", count);
9459 Sleep(150);
9460 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
9461 ok(count == 1, "did not get one count as expected (%i).\n", count);
9462 KillTimer(NULL, id);
9463 Sleep(250);
9464 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
9465 ok(count == 1, "killing replaced timer did not work (%i).\n", count);
9467 /* Check the minimum allowed timeout for a timer. MSDN indicates that it should be 10.0 ms,
9468 * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to
9469 * 15.6 ms. Since there is some measurement error between test runs we are allowing for
9470 * ±9 counts (~4 ms) around the expected value.
9472 count = 0;
9473 id = SetTimer(NULL, 0, 0, callback_count);
9474 ok(id != 0, "did not get id from SetTimer.\n");
9475 start = GetTickCount();
9476 while (GetTickCount()-start < 1001 && GetMessageA(&msg, NULL, 0, 0))
9477 DispatchMessageA(&msg);
9478 ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE /* xp */
9479 || broken(abs(count-64) < TIMER_COUNT_TOLERANCE) /* most common */,
9480 "did not get expected count for minimum timeout (%d != ~%d).\n",
9481 count, TIMER_COUNT_EXPECTED);
9482 KillTimer(NULL, id);
9483 /* Note: SetSystemTimer doesn't support a NULL window, see test_timers */
9485 if (pSetCoalescableTimer)
9487 count = 0;
9488 id = pSetCoalescableTimer(NULL, 0, 0, callback_count, 0);
9489 ok(id != 0, "SetCoalescableTimer failed with %u.\n", GetLastError());
9490 start = GetTickCount();
9491 while (GetTickCount()-start < 100 && GetMessageA(&msg, NULL, 0, 0))
9492 DispatchMessageA(&msg);
9493 ok(count > 1, "expected count > 1, got %d.\n", count);
9494 KillTimer(NULL, id);
9496 else
9497 win_skip("SetCoalescableTimer not available.\n");
9499 /* Check what happens when we're running out of timers */
9500 for (i=0; i<sizeof(ids)/sizeof(ids[0]); i++)
9502 SetLastError(0xdeadbeef);
9503 ids[i] = SetTimer(NULL, 0, USER_TIMER_MAXIMUM, tfunc);
9504 if (!ids[i]) break;
9506 ok(i != sizeof(ids)/sizeof(ids[0]), "all timers were created successfully\n");
9507 ok(GetLastError()==ERROR_NO_MORE_USER_HANDLES || broken(GetLastError()==0xdeadbeef),
9508 "GetLastError() = %d\n", GetLastError());
9509 while (i > 0) KillTimer(NULL, ids[--i]);
9512 static void test_timers_exception(DWORD code)
9514 UINT_PTR id;
9515 MSG msg;
9517 exception = code;
9518 id = SetTimer(NULL, 0, 1000, callback_exception);
9519 ok(id != 0, "did not get id from SetTimer.\n");
9521 memset(&msg, 0, sizeof(msg));
9522 msg.message = WM_TIMER;
9523 msg.wParam = id;
9524 msg.lParam = (LPARAM)callback_exception;
9526 count = 0;
9527 DispatchMessageA(&msg);
9528 ok(count == 1, "did not get one count as expected (%i).\n", count);
9530 KillTimer(NULL, id);
9533 static void test_timers_exceptions(void)
9535 test_timers_exception(EXCEPTION_ACCESS_VIOLATION);
9536 test_timers_exception(EXCEPTION_DATATYPE_MISALIGNMENT);
9537 test_timers_exception(EXCEPTION_BREAKPOINT);
9538 test_timers_exception(EXCEPTION_SINGLE_STEP);
9539 test_timers_exception(EXCEPTION_ARRAY_BOUNDS_EXCEEDED);
9540 test_timers_exception(EXCEPTION_FLT_DENORMAL_OPERAND);
9541 test_timers_exception(EXCEPTION_FLT_DIVIDE_BY_ZERO);
9542 test_timers_exception(EXCEPTION_FLT_INEXACT_RESULT);
9543 test_timers_exception(EXCEPTION_ILLEGAL_INSTRUCTION);
9544 test_timers_exception(0xE000BEEF); /* customer exception */
9547 /* Various win events with arbitrary parameters */
9548 static const struct message WmWinEventsSeq[] = {
9549 { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
9550 { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
9551 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
9552 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
9553 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
9554 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
9555 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
9556 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
9557 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
9558 /* our win event hook ignores OBJID_CURSOR events */
9559 /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
9560 { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
9561 { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
9562 { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
9563 { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
9564 { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
9565 { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
9566 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
9567 { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
9568 { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
9569 { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
9570 { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
9571 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
9572 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
9573 { 0 }
9575 static const struct message WmWinEventCaretSeq[] = {
9576 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
9577 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
9578 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
9579 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
9580 { 0 }
9582 static const struct message WmWinEventCaretSeq_2[] = {
9583 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
9584 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
9585 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
9586 { 0 }
9588 static const struct message WmWinEventAlertSeq[] = {
9589 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
9590 { 0 }
9592 static const struct message WmWinEventAlertSeq_2[] = {
9593 /* create window in the thread proc */
9594 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
9595 /* our test event */
9596 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
9597 { 0 }
9599 static const struct message WmGlobalHookSeq_1[] = {
9600 /* create window in the thread proc */
9601 { HCBT_CREATEWND, hook|lparam, 0, 2 },
9602 /* our test events */
9603 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
9604 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
9605 { 0 }
9607 static const struct message WmGlobalHookSeq_2[] = {
9608 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
9609 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
9610 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
9611 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
9612 { 0 }
9615 static const struct message WmMouseLLHookSeq[] = {
9616 { WM_MOUSEMOVE, hook },
9617 { WM_LBUTTONUP, hook },
9618 { WM_MOUSEMOVE, hook },
9619 { 0 }
9622 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
9623 DWORD event,
9624 HWND hwnd,
9625 LONG object_id,
9626 LONG child_id,
9627 DWORD thread_id,
9628 DWORD event_time)
9630 char buf[256];
9632 if (GetClassNameA(hwnd, buf, sizeof(buf)))
9634 if (!lstrcmpiA(buf, "TestWindowClass") ||
9635 !lstrcmpiA(buf, "static"))
9637 struct recvd_message msg;
9639 msg.hwnd = hwnd;
9640 msg.message = event;
9641 msg.flags = winevent_hook|wparam|lparam;
9642 msg.wParam = object_id;
9643 msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
9644 msg.descr = "WEH_2";
9645 add_message(&msg);
9650 static HHOOK hCBT_global_hook;
9651 static DWORD cbt_global_hook_thread_id;
9653 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
9655 HWND hwnd;
9656 char buf[256];
9658 if (nCode == HCBT_SYSCOMMAND)
9660 struct recvd_message msg;
9662 msg.hwnd = 0;
9663 msg.message = nCode;
9664 msg.flags = hook|wparam|lparam;
9665 msg.wParam = wParam;
9666 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
9667 msg.descr = "CBT_2";
9668 add_message(&msg);
9670 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
9672 /* WH_MOUSE_LL hook */
9673 if (nCode == HC_ACTION)
9675 MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
9677 /* we can't test for real mouse events */
9678 if (mhll->flags & LLMHF_INJECTED)
9680 struct recvd_message msg;
9682 memset (&msg, 0, sizeof (msg));
9683 msg.message = wParam;
9684 msg.flags = hook;
9685 msg.descr = "CBT_2";
9686 add_message(&msg);
9688 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
9691 /* Log also SetFocus(0) calls */
9692 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
9694 if (GetClassNameA(hwnd, buf, sizeof(buf)))
9696 if (!lstrcmpiA(buf, "TestWindowClass") ||
9697 !lstrcmpiA(buf, "static"))
9699 struct recvd_message msg;
9701 msg.hwnd = hwnd;
9702 msg.message = nCode;
9703 msg.flags = hook|wparam|lparam;
9704 msg.wParam = wParam;
9705 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
9706 msg.descr = "CBT_2";
9707 add_message(&msg);
9710 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
9713 static DWORD WINAPI win_event_global_thread_proc(void *param)
9715 HWND hwnd;
9716 MSG msg;
9717 HANDLE hevent = *(HANDLE *)param;
9719 assert(pNotifyWinEvent);
9721 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
9722 assert(hwnd);
9723 trace("created thread window %p\n", hwnd);
9725 *(HWND *)param = hwnd;
9727 flush_sequence();
9728 /* this event should be received only by our new hook proc,
9729 * an old one does not expect an event from another thread.
9731 pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
9732 SetEvent(hevent);
9734 while (GetMessageA(&msg, 0, 0, 0))
9736 TranslateMessage(&msg);
9737 DispatchMessageA(&msg);
9739 return 0;
9742 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
9744 HWND hwnd;
9745 MSG msg;
9746 HANDLE hevent = *(HANDLE *)param;
9748 flush_sequence();
9749 /* these events should be received only by our new hook proc,
9750 * an old one does not expect an event from another thread.
9753 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
9754 assert(hwnd);
9755 trace("created thread window %p\n", hwnd);
9757 *(HWND *)param = hwnd;
9759 /* Windows doesn't like when a thread plays games with the focus,
9760 that leads to all kinds of misbehaviours and failures to activate
9761 a window. So, better keep next lines commented out.
9762 SetFocus(0);
9763 SetFocus(hwnd);*/
9765 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
9766 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
9768 SetEvent(hevent);
9770 while (GetMessageA(&msg, 0, 0, 0))
9772 TranslateMessage(&msg);
9773 DispatchMessageA(&msg);
9775 return 0;
9778 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
9780 HWND hwnd;
9781 MSG msg;
9782 HANDLE hevent = *(HANDLE *)param;
9784 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
9785 assert(hwnd);
9786 trace("created thread window %p\n", hwnd);
9788 *(HWND *)param = hwnd;
9790 flush_sequence();
9792 /* Windows doesn't like when a thread plays games with the focus,
9793 * that leads to all kinds of misbehaviours and failures to activate
9794 * a window. So, better don't generate a mouse click message below.
9796 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
9797 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
9798 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
9800 SetEvent(hevent);
9801 while (GetMessageA(&msg, 0, 0, 0))
9803 TranslateMessage(&msg);
9804 DispatchMessageA(&msg);
9806 return 0;
9809 static void test_winevents(void)
9811 BOOL ret;
9812 MSG msg;
9813 HWND hwnd, hwnd2;
9814 UINT i;
9815 HANDLE hthread, hevent;
9816 DWORD tid;
9817 HWINEVENTHOOK hhook;
9818 const struct message *events = WmWinEventsSeq;
9820 hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
9821 WS_OVERLAPPEDWINDOW,
9822 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
9823 NULL, NULL, 0);
9824 assert(hwnd);
9826 /****** start of global hook test *************/
9827 hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
9828 if (!hCBT_global_hook)
9830 ok(DestroyWindow(hwnd), "failed to destroy window\n");
9831 skip( "cannot set global hook\n" );
9832 return;
9835 hevent = CreateEventA(NULL, 0, 0, NULL);
9836 assert(hevent);
9837 hwnd2 = hevent;
9839 hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
9840 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
9842 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
9844 ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
9846 flush_sequence();
9847 /* this one should be received only by old hook proc */
9848 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
9849 /* this one should be received only by old hook proc */
9850 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
9852 ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
9854 ret = UnhookWindowsHookEx(hCBT_global_hook);
9855 ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
9857 PostThreadMessageA(tid, WM_QUIT, 0, 0);
9858 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
9859 CloseHandle(hthread);
9860 CloseHandle(hevent);
9861 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
9862 /****** end of global hook test *************/
9864 if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
9866 ok(DestroyWindow(hwnd), "failed to destroy window\n");
9867 return;
9870 flush_sequence();
9872 if (0)
9874 /* this test doesn't pass under Win9x */
9875 /* win2k ignores events with hwnd == 0 */
9876 SetLastError(0xdeadbeef);
9877 pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
9878 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
9879 GetLastError() == 0xdeadbeef, /* Win9x */
9880 "unexpected error %d\n", GetLastError());
9881 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
9884 for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
9885 pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
9887 ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
9889 /****** start of event filtering test *************/
9890 hhook = pSetWinEventHook(
9891 EVENT_OBJECT_SHOW, /* 0x8002 */
9892 EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
9893 GetModuleHandleA(0), win_event_global_hook_proc,
9894 GetCurrentProcessId(), 0,
9895 WINEVENT_INCONTEXT);
9896 ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
9898 hevent = CreateEventA(NULL, 0, 0, NULL);
9899 assert(hevent);
9900 hwnd2 = hevent;
9902 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
9903 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
9905 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
9907 ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
9909 flush_sequence();
9910 /* this one should be received only by old hook proc */
9911 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
9912 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
9913 /* this one should be received only by old hook proc */
9914 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
9916 ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
9918 ret = pUnhookWinEvent(hhook);
9919 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
9921 PostThreadMessageA(tid, WM_QUIT, 0, 0);
9922 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
9923 CloseHandle(hthread);
9924 CloseHandle(hevent);
9925 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
9926 /****** end of event filtering test *************/
9928 /****** start of out of context event test *************/
9929 hhook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0,
9930 win_event_global_hook_proc, GetCurrentProcessId(), 0,
9931 WINEVENT_OUTOFCONTEXT);
9932 ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
9934 hevent = CreateEventA(NULL, 0, 0, NULL);
9935 assert(hevent);
9936 hwnd2 = hevent;
9938 flush_sequence();
9940 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
9941 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
9943 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
9945 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
9946 /* process pending winevent messages */
9947 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
9948 ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
9950 flush_sequence();
9951 /* this one should be received only by old hook proc */
9952 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
9953 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
9954 /* this one should be received only by old hook proc */
9955 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
9957 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
9958 /* process pending winevent messages */
9959 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
9960 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
9962 ret = pUnhookWinEvent(hhook);
9963 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
9965 PostThreadMessageA(tid, WM_QUIT, 0, 0);
9966 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
9967 CloseHandle(hthread);
9968 CloseHandle(hevent);
9969 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
9970 /****** end of out of context event test *************/
9972 /****** start of MOUSE_LL hook test *************/
9973 hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
9974 /* WH_MOUSE_LL is not supported on Win9x platforms */
9975 if (!hCBT_global_hook)
9977 win_skip("Skipping WH_MOUSE_LL test on this platform\n");
9978 goto skip_mouse_ll_hook_test;
9981 hevent = CreateEventA(NULL, 0, 0, NULL);
9982 assert(hevent);
9983 hwnd2 = hevent;
9985 hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
9986 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
9988 while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
9989 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
9991 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
9992 flush_sequence();
9994 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
9995 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
9996 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
9998 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
10000 ret = UnhookWindowsHookEx(hCBT_global_hook);
10001 ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
10003 PostThreadMessageA(tid, WM_QUIT, 0, 0);
10004 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10005 CloseHandle(hthread);
10006 CloseHandle(hevent);
10007 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10008 /****** end of MOUSE_LL hook test *************/
10009 skip_mouse_ll_hook_test:
10011 ok(DestroyWindow(hwnd), "failed to destroy window\n");
10014 static void test_set_hook(void)
10016 BOOL ret;
10017 HHOOK hhook;
10018 HWINEVENTHOOK hwinevent_hook;
10020 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
10021 ok(hhook != 0, "local hook does not require hModule set to 0\n");
10022 UnhookWindowsHookEx(hhook);
10024 if (0)
10026 /* this test doesn't pass under Win9x: BUG! */
10027 SetLastError(0xdeadbeef);
10028 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
10029 ok(!hhook, "global hook requires hModule != 0\n");
10030 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
10033 SetLastError(0xdeadbeef);
10034 hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
10035 ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
10036 ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
10037 GetLastError() == 0xdeadbeef, /* Win9x */
10038 "unexpected error %d\n", GetLastError());
10040 SetLastError(0xdeadbeef);
10041 ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
10042 ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
10043 GetLastError() == 0xdeadbeef, /* Win9x */
10044 "unexpected error %d\n", GetLastError());
10046 if (!pSetWinEventHook || !pUnhookWinEvent) return;
10048 /* even process local incontext hooks require hmodule */
10049 SetLastError(0xdeadbeef);
10050 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10051 GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
10052 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
10053 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
10054 GetLastError() == 0xdeadbeef, /* Win9x */
10055 "unexpected error %d\n", GetLastError());
10057 /* even thread local incontext hooks require hmodule */
10058 SetLastError(0xdeadbeef);
10059 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10060 GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
10061 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
10062 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
10063 GetLastError() == 0xdeadbeef, /* Win9x */
10064 "unexpected error %d\n", GetLastError());
10066 if (0)
10068 /* these 3 tests don't pass under Win9x */
10069 SetLastError(0xdeadbeef);
10070 hwinevent_hook = pSetWinEventHook(1, 0, 0, win_event_proc,
10071 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
10072 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
10073 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
10075 SetLastError(0xdeadbeef);
10076 hwinevent_hook = pSetWinEventHook(-1, 1, 0, win_event_proc,
10077 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
10078 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
10079 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
10081 SetLastError(0xdeadbeef);
10082 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10083 0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
10084 ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
10085 ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
10088 SetLastError(0xdeadbeef);
10089 hwinevent_hook = pSetWinEventHook(0, 0, 0, win_event_proc,
10090 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
10091 ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
10092 ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
10093 ret = pUnhookWinEvent(hwinevent_hook);
10094 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10096 todo_wine {
10097 /* This call succeeds under win2k SP4, but fails under Wine.
10098 Does win2k test/use passed process id? */
10099 SetLastError(0xdeadbeef);
10100 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10101 0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
10102 ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
10103 ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
10104 ret = pUnhookWinEvent(hwinevent_hook);
10105 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10108 SetLastError(0xdeadbeef);
10109 ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
10110 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
10111 GetLastError() == 0xdeadbeef, /* Win9x */
10112 "unexpected error %d\n", GetLastError());
10115 static HWND hook_hwnd;
10116 static HHOOK recursive_hook;
10117 static int hook_depth, max_hook_depth;
10119 static LRESULT WINAPI rec_get_message_hook(int code, WPARAM w, LPARAM l)
10121 LRESULT res;
10122 MSG msg;
10123 BOOL b;
10125 hook_depth++;
10126 if(hook_depth > max_hook_depth)
10127 max_hook_depth = hook_depth;
10129 b = PeekMessageW(&msg, hook_hwnd, 0, 0, PM_NOREMOVE);
10130 ok(b, "PeekMessage failed\n");
10132 res = CallNextHookEx(recursive_hook, code, w, l);
10134 hook_depth--;
10135 return res;
10138 static void test_recursive_hook(void)
10140 MSG msg;
10141 BOOL b;
10143 hook_hwnd = CreateWindowA("Static", NULL, WS_POPUP, 0, 0, 200, 60, NULL, NULL, NULL, NULL);
10144 ok(hook_hwnd != NULL, "CreateWindow failed\n");
10146 recursive_hook = SetWindowsHookExW(WH_GETMESSAGE, rec_get_message_hook, NULL, GetCurrentThreadId());
10147 ok(recursive_hook != NULL, "SetWindowsHookEx failed\n");
10149 PostMessageW(hook_hwnd, WM_USER, 0, 0);
10150 PostMessageW(hook_hwnd, WM_USER+1, 0, 0);
10152 hook_depth = 0;
10153 GetMessageW(&msg, hook_hwnd, 0, 0);
10154 ok(15 <= max_hook_depth && max_hook_depth < 45, "max_hook_depth = %d\n", max_hook_depth);
10155 trace("max_hook_depth = %d\n", max_hook_depth);
10157 b = UnhookWindowsHookEx(recursive_hook);
10158 ok(b, "UnhokWindowsHookEx failed\n");
10160 DestroyWindow(hook_hwnd);
10163 static const struct message ScrollWindowPaint1[] = {
10164 { WM_PAINT, sent },
10165 { WM_ERASEBKGND, sent|beginpaint },
10166 { WM_GETTEXTLENGTH, sent|optional },
10167 { WM_PAINT, sent|optional },
10168 { WM_NCPAINT, sent|beginpaint|optional },
10169 { WM_GETTEXT, sent|beginpaint|optional },
10170 { WM_GETTEXT, sent|beginpaint|optional },
10171 { WM_GETTEXT, sent|beginpaint|optional },
10172 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
10173 { WM_ERASEBKGND, sent|beginpaint|optional },
10174 { 0 }
10177 static const struct message ScrollWindowPaint2[] = {
10178 { WM_PAINT, sent },
10179 { 0 }
10182 static void test_scrollwindowex(void)
10184 HWND hwnd, hchild;
10185 RECT rect={0,0,130,130};
10187 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
10188 WS_VISIBLE|WS_OVERLAPPEDWINDOW,
10189 100, 100, 200, 200, 0, 0, 0, NULL);
10190 ok (hwnd != 0, "Failed to create overlapped window\n");
10191 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
10192 WS_VISIBLE|WS_CAPTION|WS_CHILD,
10193 10, 10, 150, 150, hwnd, 0, 0, NULL);
10194 ok (hchild != 0, "Failed to create child\n");
10195 UpdateWindow(hwnd);
10196 flush_events();
10197 flush_sequence();
10199 /* scroll without the child window */
10200 trace("start scroll\n");
10201 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
10202 SW_ERASE|SW_INVALIDATE);
10203 ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
10204 trace("end scroll\n");
10205 flush_sequence();
10206 flush_events();
10207 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
10208 flush_events();
10209 flush_sequence();
10211 /* Now without the SW_ERASE flag */
10212 trace("start scroll\n");
10213 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
10214 ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
10215 trace("end scroll\n");
10216 flush_sequence();
10217 flush_events();
10218 ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", FALSE);
10219 flush_events();
10220 flush_sequence();
10222 /* now scroll the child window as well */
10223 trace("start scroll\n");
10224 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
10225 SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
10226 /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
10227 /* windows sometimes a WM_MOVE */
10228 ok_sequence(WmEmptySeq, "ScrollWindowEx", TRUE);
10229 trace("end scroll\n");
10230 flush_sequence();
10231 flush_events();
10232 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
10233 flush_events();
10234 flush_sequence();
10236 /* now scroll with ScrollWindow() */
10237 trace("start scroll with ScrollWindow\n");
10238 ScrollWindow( hwnd, 5, 5, NULL, NULL);
10239 trace("end scroll\n");
10240 flush_sequence();
10241 flush_events();
10242 ok_sequence(ScrollWindowPaint1, "ScrollWindow", FALSE);
10244 ok(DestroyWindow(hchild), "failed to destroy window\n");
10245 ok(DestroyWindow(hwnd), "failed to destroy window\n");
10246 flush_sequence();
10249 static const struct message destroy_window_with_children[] = {
10250 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
10251 { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
10252 { 0x0090, sent|optional },
10253 { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
10254 { 0x0090, sent|optional },
10255 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
10256 { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
10257 { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
10258 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
10259 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
10260 { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
10261 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
10262 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
10263 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
10264 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
10265 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
10266 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
10267 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
10268 { 0 }
10271 static void test_DestroyWindow(void)
10273 BOOL ret;
10274 HWND parent, child1, child2, child3, child4, test;
10275 UINT_PTR child_id = WND_CHILD_ID + 1;
10277 parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
10278 100, 100, 200, 200, 0, 0, 0, NULL);
10279 assert(parent != 0);
10280 child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
10281 0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
10282 assert(child1 != 0);
10283 child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
10284 0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
10285 assert(child2 != 0);
10286 child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
10287 0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
10288 assert(child3 != 0);
10289 child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
10290 0, 0, 50, 50, parent, 0, 0, NULL);
10291 assert(child4 != 0);
10293 /* test owner/parent of child2 */
10294 test = GetParent(child2);
10295 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
10296 ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
10297 if(pGetAncestor) {
10298 test = pGetAncestor(child2, GA_PARENT);
10299 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
10301 test = GetWindow(child2, GW_OWNER);
10302 ok(!test, "wrong owner %p\n", test);
10304 test = SetParent(child2, parent);
10305 ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
10307 /* test owner/parent of the parent */
10308 test = GetParent(parent);
10309 ok(!test, "wrong parent %p\n", test);
10310 ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
10311 if(pGetAncestor) {
10312 test = pGetAncestor(parent, GA_PARENT);
10313 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
10315 test = GetWindow(parent, GW_OWNER);
10316 ok(!test, "wrong owner %p\n", test);
10318 /* test owner/parent of child1 */
10319 test = GetParent(child1);
10320 ok(test == parent, "wrong parent %p\n", test);
10321 ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
10322 if(pGetAncestor) {
10323 test = pGetAncestor(child1, GA_PARENT);
10324 ok(test == parent, "wrong parent %p\n", test);
10326 test = GetWindow(child1, GW_OWNER);
10327 ok(!test, "wrong owner %p\n", test);
10329 /* test owner/parent of child2 */
10330 test = GetParent(child2);
10331 ok(test == parent, "wrong parent %p\n", test);
10332 ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
10333 if(pGetAncestor) {
10334 test = pGetAncestor(child2, GA_PARENT);
10335 ok(test == parent, "wrong parent %p\n", test);
10337 test = GetWindow(child2, GW_OWNER);
10338 ok(!test, "wrong owner %p\n", test);
10340 /* test owner/parent of child3 */
10341 test = GetParent(child3);
10342 ok(test == child1, "wrong parent %p\n", test);
10343 ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
10344 if(pGetAncestor) {
10345 test = pGetAncestor(child3, GA_PARENT);
10346 ok(test == child1, "wrong parent %p\n", test);
10348 test = GetWindow(child3, GW_OWNER);
10349 ok(!test, "wrong owner %p\n", test);
10351 /* test owner/parent of child4 */
10352 test = GetParent(child4);
10353 ok(test == parent, "wrong parent %p\n", test);
10354 ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
10355 if(pGetAncestor) {
10356 test = pGetAncestor(child4, GA_PARENT);
10357 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
10359 test = GetWindow(child4, GW_OWNER);
10360 ok(test == parent, "wrong owner %p\n", test);
10362 flush_sequence();
10364 trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
10365 parent, child1, child2, child3, child4);
10367 SetCapture(child4);
10368 test = GetCapture();
10369 ok(test == child4, "wrong capture window %p\n", test);
10371 test_DestroyWindow_flag = TRUE;
10372 ret = DestroyWindow(parent);
10373 ok( ret, "DestroyWindow() error %d\n", GetLastError());
10374 test_DestroyWindow_flag = FALSE;
10375 ok_sequence(destroy_window_with_children, "destroy window with children", FALSE);
10377 ok(!IsWindow(parent), "parent still exists\n");
10378 ok(!IsWindow(child1), "child1 still exists\n");
10379 ok(!IsWindow(child2), "child2 still exists\n");
10380 ok(!IsWindow(child3), "child3 still exists\n");
10381 ok(!IsWindow(child4), "child4 still exists\n");
10383 test = GetCapture();
10384 ok(!test, "wrong capture window %p\n", test);
10388 static const struct message WmDispatchPaint[] = {
10389 { WM_NCPAINT, sent },
10390 { WM_GETTEXT, sent|defwinproc|optional },
10391 { WM_GETTEXT, sent|defwinproc|optional },
10392 { WM_ERASEBKGND, sent },
10393 { 0 }
10396 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10398 if (message == WM_PAINT) return 0;
10399 return MsgCheckProcA( hwnd, message, wParam, lParam );
10402 static void test_DispatchMessage(void)
10404 RECT rect;
10405 MSG msg;
10406 int count;
10407 HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
10408 100, 100, 200, 200, 0, 0, 0, NULL);
10409 ShowWindow( hwnd, SW_SHOW );
10410 UpdateWindow( hwnd );
10411 flush_events();
10412 flush_sequence();
10413 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
10415 SetRect( &rect, -5, -5, 5, 5 );
10416 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
10417 count = 0;
10418 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
10420 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
10421 else
10423 flush_sequence();
10424 DispatchMessageA( &msg );
10425 /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
10426 if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
10427 else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
10428 if (++count > 10) break;
10431 ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
10433 trace("now without DispatchMessage\n");
10434 flush_sequence();
10435 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
10436 count = 0;
10437 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
10439 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
10440 else
10442 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
10443 flush_sequence();
10444 /* this will send WM_NCCPAINT just like DispatchMessage does */
10445 GetUpdateRgn( hwnd, hrgn, TRUE );
10446 ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
10447 DeleteObject( hrgn );
10448 GetClientRect( hwnd, &rect );
10449 ValidateRect( hwnd, &rect ); /* this will stop WM_PAINTs */
10450 ok( !count, "Got multiple WM_PAINTs\n" );
10451 if (++count > 10) break;
10455 flush_sequence();
10456 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
10457 count = 0;
10458 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
10460 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
10461 else
10463 HDC hdc;
10465 flush_sequence();
10466 hdc = BeginPaint( hwnd, NULL );
10467 ok( !hdc, "got valid hdc %p from BeginPaint\n", hdc );
10468 ok( !EndPaint( hwnd, NULL ), "EndPaint succeeded\n" );
10469 ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
10470 ok( !count, "Got multiple WM_PAINTs\n" );
10471 if (++count > 10) break;
10474 DestroyWindow(hwnd);
10478 static const struct message WmUser[] = {
10479 { WM_USER, sent },
10480 { 0 }
10483 struct sendmsg_info
10485 HWND hwnd;
10486 DWORD timeout;
10487 DWORD ret;
10490 static DWORD CALLBACK send_msg_thread( LPVOID arg )
10492 struct sendmsg_info *info = arg;
10493 SetLastError( 0xdeadbeef );
10494 info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
10495 if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT ||
10496 broken(GetLastError() == 0), /* win9x */
10497 "unexpected error %d\n", GetLastError());
10498 return 0;
10501 static void wait_for_thread( HANDLE thread )
10503 while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
10505 MSG msg;
10506 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA(&msg);
10510 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10512 if (message == WM_USER) Sleep(200);
10513 return MsgCheckProcA( hwnd, message, wParam, lParam );
10516 static void test_SendMessageTimeout(void)
10518 HANDLE thread;
10519 struct sendmsg_info info;
10520 DWORD tid;
10521 BOOL is_win9x;
10523 info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
10524 100, 100, 200, 200, 0, 0, 0, NULL);
10525 flush_events();
10526 flush_sequence();
10528 info.timeout = 1000;
10529 info.ret = 0xdeadbeef;
10530 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
10531 wait_for_thread( thread );
10532 CloseHandle( thread );
10533 ok( info.ret == 1, "SendMessageTimeout failed\n" );
10534 ok_sequence( WmUser, "WmUser", FALSE );
10536 info.timeout = 1;
10537 info.ret = 0xdeadbeef;
10538 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
10539 Sleep(100); /* SendMessageTimeout should time out here */
10540 wait_for_thread( thread );
10541 CloseHandle( thread );
10542 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
10543 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
10545 /* 0 means infinite timeout (but not on win9x) */
10546 info.timeout = 0;
10547 info.ret = 0xdeadbeef;
10548 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
10549 Sleep(100);
10550 wait_for_thread( thread );
10551 CloseHandle( thread );
10552 is_win9x = !info.ret;
10553 if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
10554 else ok_sequence( WmUser, "WmUser", FALSE );
10556 /* timeout is treated as signed despite the prototype (but not on win9x) */
10557 info.timeout = 0x7fffffff;
10558 info.ret = 0xdeadbeef;
10559 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
10560 Sleep(100);
10561 wait_for_thread( thread );
10562 CloseHandle( thread );
10563 ok( info.ret == 1, "SendMessageTimeout failed\n" );
10564 ok_sequence( WmUser, "WmUser", FALSE );
10566 info.timeout = 0x80000000;
10567 info.ret = 0xdeadbeef;
10568 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
10569 Sleep(100);
10570 wait_for_thread( thread );
10571 CloseHandle( thread );
10572 if (is_win9x)
10574 ok( info.ret == 1, "SendMessageTimeout failed\n" );
10575 ok_sequence( WmUser, "WmUser", FALSE );
10577 else
10579 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
10580 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
10583 /* now check for timeout during message processing */
10584 SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
10585 info.timeout = 100;
10586 info.ret = 0xdeadbeef;
10587 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
10588 wait_for_thread( thread );
10589 CloseHandle( thread );
10590 /* we should time out but still get the message */
10591 ok( info.ret == 0, "SendMessageTimeout failed\n" );
10592 ok_sequence( WmUser, "WmUser", FALSE );
10594 DestroyWindow( info.hwnd );
10598 /****************** edit message test *************************/
10599 #define ID_EDIT 0x1234
10600 static const struct message sl_edit_setfocus[] =
10602 { HCBT_SETFOCUS, hook },
10603 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
10604 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10605 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10606 { WM_SETFOCUS, sent|wparam, 0 },
10607 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
10608 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
10609 { WM_CTLCOLOREDIT, sent|parent },
10610 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
10611 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10612 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10613 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
10614 { 0 }
10616 static const struct message sl_edit_invisible[] =
10618 { HCBT_SETFOCUS, hook },
10619 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
10620 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10621 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10622 { WM_KILLFOCUS, sent|parent },
10623 { WM_SETFOCUS, sent },
10624 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
10625 { 0 }
10627 static const struct message ml_edit_setfocus[] =
10629 { HCBT_SETFOCUS, hook },
10630 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
10631 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10632 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10633 { WM_SETFOCUS, sent|wparam, 0 },
10634 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
10635 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
10636 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10637 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10638 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
10639 { 0 }
10641 static const struct message sl_edit_killfocus[] =
10643 { HCBT_SETFOCUS, hook },
10644 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10645 { WM_KILLFOCUS, sent|wparam, 0 },
10646 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10647 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10648 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
10649 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
10650 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10651 { 0 }
10653 static const struct message sl_edit_lbutton_dblclk[] =
10655 { WM_LBUTTONDBLCLK, sent },
10656 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
10657 { 0 }
10659 static const struct message sl_edit_lbutton_down[] =
10661 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
10662 { HCBT_SETFOCUS, hook },
10663 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10664 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10665 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10666 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
10667 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
10668 { WM_CTLCOLOREDIT, sent|parent },
10669 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
10670 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10671 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10672 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10673 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
10674 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
10675 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10676 { WM_CTLCOLOREDIT, sent|parent|optional },
10677 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
10678 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10679 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10680 { 0 }
10682 static const struct message ml_edit_lbutton_down[] =
10684 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
10685 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
10686 { HCBT_SETFOCUS, hook },
10687 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10688 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10689 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10690 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
10691 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
10692 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
10693 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10694 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10695 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
10696 { 0 }
10698 static const struct message sl_edit_lbutton_up[] =
10700 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
10701 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10702 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
10703 { WM_CAPTURECHANGED, sent|defwinproc },
10704 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10705 { 0 }
10707 static const struct message ml_edit_lbutton_up[] =
10709 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
10710 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
10711 { WM_CAPTURECHANGED, sent|defwinproc },
10712 { 0 }
10715 static WNDPROC old_edit_proc;
10717 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10719 static LONG defwndproc_counter = 0;
10720 LRESULT ret;
10721 struct recvd_message msg;
10723 if (ignore_message( message )) return 0;
10725 msg.hwnd = hwnd;
10726 msg.message = message;
10727 msg.flags = sent|wparam|lparam;
10728 if (defwndproc_counter) msg.flags |= defwinproc;
10729 msg.wParam = wParam;
10730 msg.lParam = lParam;
10731 msg.descr = "edit";
10732 add_message(&msg);
10734 defwndproc_counter++;
10735 ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
10736 defwndproc_counter--;
10738 return ret;
10741 static void subclass_edit(void)
10743 WNDCLASSA cls;
10745 if (!GetClassInfoA(0, "edit", &cls)) assert(0);
10747 old_edit_proc = cls.lpfnWndProc;
10749 cls.hInstance = GetModuleHandleA(NULL);
10750 cls.lpfnWndProc = edit_hook_proc;
10751 cls.lpszClassName = "my_edit_class";
10752 UnregisterClassA(cls.lpszClassName, cls.hInstance);
10753 if (!RegisterClassA(&cls)) assert(0);
10756 static void test_edit_messages(void)
10758 HWND hwnd, parent;
10759 DWORD dlg_code;
10761 subclass_edit();
10762 log_all_parent_messages++;
10764 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10765 100, 100, 200, 200, 0, 0, 0, NULL);
10766 ok (parent != 0, "Failed to create parent window\n");
10768 /* test single line edit */
10769 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
10770 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
10771 ok(hwnd != 0, "Failed to create edit window\n");
10773 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
10774 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
10776 flush_sequence();
10777 SetFocus(hwnd);
10778 ok_sequence(sl_edit_invisible, "SetFocus(hwnd) on an invisible edit", FALSE);
10780 ShowWindow(hwnd, SW_SHOW);
10781 UpdateWindow(hwnd);
10782 SetFocus(0);
10783 flush_sequence();
10785 SetFocus(hwnd);
10786 ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
10788 SetFocus(0);
10789 ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
10791 SetFocus(0);
10792 ReleaseCapture();
10793 flush_sequence();
10795 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
10796 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
10798 SetFocus(0);
10799 ReleaseCapture();
10800 flush_sequence();
10802 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
10803 ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
10805 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
10806 ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
10808 DestroyWindow(hwnd);
10810 /* test multiline edit */
10811 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
10812 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
10813 ok(hwnd != 0, "Failed to create edit window\n");
10815 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
10816 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
10817 "wrong dlg_code %08x\n", dlg_code);
10819 ShowWindow(hwnd, SW_SHOW);
10820 UpdateWindow(hwnd);
10821 SetFocus(0);
10822 flush_sequence();
10824 SetFocus(hwnd);
10825 ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
10827 SetFocus(0);
10828 ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
10830 SetFocus(0);
10831 ReleaseCapture();
10832 flush_sequence();
10834 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
10835 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
10837 SetFocus(0);
10838 ReleaseCapture();
10839 flush_sequence();
10841 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
10842 ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
10844 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
10845 ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
10847 DestroyWindow(hwnd);
10848 DestroyWindow(parent);
10850 log_all_parent_messages--;
10853 /**************************** End of Edit test ******************************/
10855 static const struct message WmKeyDownSkippedSeq[] =
10857 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
10858 { 0 }
10860 static const struct message WmKeyDownWasDownSkippedSeq[] =
10862 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x40000001 }, /* XP */
10863 { 0 }
10865 static const struct message WmKeyUpSkippedSeq[] =
10867 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
10868 { 0 }
10870 static const struct message WmUserKeyUpSkippedSeq[] =
10872 { WM_USER, sent },
10873 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
10874 { 0 }
10877 #define EV_STOP 0
10878 #define EV_SENDMSG 1
10879 #define EV_ACK 2
10881 struct peekmsg_info
10883 HWND hwnd;
10884 HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
10887 static DWORD CALLBACK send_msg_thread_2(void *param)
10889 DWORD ret;
10890 struct peekmsg_info *info = param;
10892 trace("thread: looping\n");
10893 SetEvent(info->hevent[EV_ACK]);
10895 while (1)
10897 ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
10899 switch (ret)
10901 case WAIT_OBJECT_0 + EV_STOP:
10902 trace("thread: exiting\n");
10903 return 0;
10905 case WAIT_OBJECT_0 + EV_SENDMSG:
10906 trace("thread: sending message\n");
10907 ret = SendNotifyMessageA(info->hwnd, WM_USER, 0, 0);
10908 ok(ret, "SendNotifyMessageA failed error %u\n", GetLastError());
10909 SetEvent(info->hevent[EV_ACK]);
10910 break;
10912 default:
10913 trace("unexpected return: %04x\n", ret);
10914 assert(0);
10915 break;
10918 return 0;
10921 static void test_PeekMessage(void)
10923 MSG msg;
10924 HANDLE hthread;
10925 DWORD tid, qstatus;
10926 UINT qs_all_input = QS_ALLINPUT;
10927 UINT qs_input = QS_INPUT;
10928 BOOL ret;
10929 struct peekmsg_info info;
10931 info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
10932 100, 100, 200, 200, 0, 0, 0, NULL);
10933 assert(info.hwnd);
10934 ShowWindow(info.hwnd, SW_SHOW);
10935 UpdateWindow(info.hwnd);
10936 SetFocus(info.hwnd);
10938 info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
10939 info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
10940 info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
10942 hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
10943 WaitForSingleObject(info.hevent[EV_ACK], 10000);
10945 flush_events();
10946 flush_sequence();
10948 SetLastError(0xdeadbeef);
10949 qstatus = GetQueueStatus(qs_all_input);
10950 if (GetLastError() == ERROR_INVALID_FLAGS)
10952 trace("QS_RAWINPUT not supported on this platform\n");
10953 qs_all_input &= ~QS_RAWINPUT;
10954 qs_input &= ~QS_RAWINPUT;
10956 if (qstatus & QS_POSTMESSAGE)
10958 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) /* nothing */ ;
10959 qstatus = GetQueueStatus(qs_all_input);
10961 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
10963 trace("signalling to send message\n");
10964 SetEvent(info.hevent[EV_SENDMSG]);
10965 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
10967 /* pass invalid QS_xxxx flags */
10968 SetLastError(0xdeadbeef);
10969 qstatus = GetQueueStatus(0xffffffff);
10970 ok(qstatus == 0 || broken(qstatus) /* win9x */, "GetQueueStatus should fail: %08x\n", qstatus);
10971 if (!qstatus)
10973 ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
10974 qstatus = GetQueueStatus(qs_all_input);
10976 qstatus &= ~MAKELONG( 0x4000, 0x4000 ); /* sometimes set on Win95 */
10977 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
10978 "wrong qstatus %08x\n", qstatus);
10980 msg.message = 0;
10981 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
10982 ok(!ret,
10983 "PeekMessageA should have returned FALSE instead of msg %04x\n",
10984 msg.message);
10985 ok_sequence(WmUser, "WmUser", FALSE);
10987 qstatus = GetQueueStatus(qs_all_input);
10988 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
10990 keybd_event('N', 0, 0, 0);
10991 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
10992 qstatus = GetQueueStatus(qs_all_input);
10993 if (!(qstatus & MAKELONG(QS_KEY, QS_KEY)))
10995 skip( "queuing key events not supported\n" );
10996 goto done;
10998 ok(qstatus == MAKELONG(QS_KEY, QS_KEY) ||
10999 /* keybd_event seems to trigger a sent message on NT4 */
11000 qstatus == MAKELONG(QS_KEY|QS_SENDMESSAGE, QS_KEY|QS_SENDMESSAGE),
11001 "wrong qstatus %08x\n", qstatus);
11003 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11004 qstatus = GetQueueStatus(qs_all_input);
11005 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY) ||
11006 qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
11007 "wrong qstatus %08x\n", qstatus);
11009 InvalidateRect(info.hwnd, NULL, FALSE);
11010 qstatus = GetQueueStatus(qs_all_input);
11011 ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY) ||
11012 qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
11013 "wrong qstatus %08x\n", qstatus);
11015 trace("signalling to send message\n");
11016 SetEvent(info.hevent[EV_SENDMSG]);
11017 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11019 qstatus = GetQueueStatus(qs_all_input);
11020 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11021 "wrong qstatus %08x\n", qstatus);
11023 msg.message = 0;
11024 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
11025 if (ret && msg.message == WM_CHAR)
11027 win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
11028 goto done;
11030 ok(!ret,
11031 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11032 msg.message);
11033 if (!sequence_cnt) /* nt4 doesn't fetch anything with PM_QS_* flags */
11035 win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
11036 goto done;
11038 ok_sequence(WmUser, "WmUser", FALSE);
11040 qstatus = GetQueueStatus(qs_all_input);
11041 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11042 "wrong qstatus %08x\n", qstatus);
11044 trace("signalling to send message\n");
11045 SetEvent(info.hevent[EV_SENDMSG]);
11046 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11048 qstatus = GetQueueStatus(qs_all_input);
11049 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11050 "wrong qstatus %08x\n", qstatus);
11052 msg.message = 0;
11053 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE );
11054 ok(!ret,
11055 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11056 msg.message);
11057 ok_sequence(WmUser, "WmUser", FALSE);
11059 qstatus = GetQueueStatus(qs_all_input);
11060 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11061 "wrong qstatus %08x\n", qstatus);
11063 msg.message = 0;
11064 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
11065 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11066 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11067 ret, msg.message, msg.wParam);
11068 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11070 qstatus = GetQueueStatus(qs_all_input);
11071 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
11072 "wrong qstatus %08x\n", qstatus);
11074 msg.message = 0;
11075 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
11076 ok(!ret,
11077 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11078 msg.message);
11079 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11081 qstatus = GetQueueStatus(qs_all_input);
11082 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
11083 "wrong qstatus %08x\n", qstatus);
11085 msg.message = 0;
11086 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
11087 ok(ret && msg.message == WM_PAINT,
11088 "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
11089 DispatchMessageA(&msg);
11090 ok_sequence(WmPaint, "WmPaint", FALSE);
11092 qstatus = GetQueueStatus(qs_all_input);
11093 ok(qstatus == MAKELONG(0, QS_KEY),
11094 "wrong qstatus %08x\n", qstatus);
11096 msg.message = 0;
11097 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
11098 ok(!ret,
11099 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11100 msg.message);
11101 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11103 qstatus = GetQueueStatus(qs_all_input);
11104 ok(qstatus == MAKELONG(0, QS_KEY),
11105 "wrong qstatus %08x\n", qstatus);
11107 trace("signalling to send message\n");
11108 SetEvent(info.hevent[EV_SENDMSG]);
11109 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11111 qstatus = GetQueueStatus(qs_all_input);
11112 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
11113 "wrong qstatus %08x\n", qstatus);
11115 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11117 qstatus = GetQueueStatus(qs_all_input);
11118 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
11119 "wrong qstatus %08x\n", qstatus);
11121 msg.message = 0;
11122 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
11123 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11124 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11125 ret, msg.message, msg.wParam);
11126 ok_sequence(WmUser, "WmUser", FALSE);
11128 qstatus = GetQueueStatus(qs_all_input);
11129 ok(qstatus == MAKELONG(0, QS_KEY),
11130 "wrong qstatus %08x\n", qstatus);
11132 msg.message = 0;
11133 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
11134 ok(!ret,
11135 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11136 msg.message);
11137 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11139 qstatus = GetQueueStatus(qs_all_input);
11140 ok(qstatus == MAKELONG(0, QS_KEY),
11141 "wrong qstatus %08x\n", qstatus);
11143 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11145 qstatus = GetQueueStatus(qs_all_input);
11146 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
11147 "wrong qstatus %08x\n", qstatus);
11149 trace("signalling to send message\n");
11150 SetEvent(info.hevent[EV_SENDMSG]);
11151 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11153 qstatus = GetQueueStatus(qs_all_input);
11154 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
11155 "wrong qstatus %08x\n", qstatus);
11157 msg.message = 0;
11158 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
11159 ok(!ret,
11160 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11161 msg.message);
11162 ok_sequence(WmUser, "WmUser", FALSE);
11164 qstatus = GetQueueStatus(qs_all_input);
11165 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
11166 "wrong qstatus %08x\n", qstatus);
11168 msg.message = 0;
11169 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
11170 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
11171 else /* workaround for a missing QS_RAWINPUT support */
11172 ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
11173 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
11174 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
11175 ret, msg.message, msg.wParam);
11176 ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
11178 qstatus = GetQueueStatus(qs_all_input);
11179 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
11180 "wrong qstatus %08x\n", qstatus);
11182 msg.message = 0;
11183 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
11184 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
11185 else /* workaround for a missing QS_RAWINPUT support */
11186 ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
11187 ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
11188 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
11189 ret, msg.message, msg.wParam);
11190 ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
11192 qstatus = GetQueueStatus(qs_all_input);
11193 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
11194 "wrong qstatus %08x\n", qstatus);
11196 msg.message = 0;
11197 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
11198 ok(!ret,
11199 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11200 msg.message);
11201 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11203 qstatus = GetQueueStatus(qs_all_input);
11204 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
11205 "wrong qstatus %08x\n", qstatus);
11207 msg.message = 0;
11208 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11209 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11210 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11211 ret, msg.message, msg.wParam);
11212 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11214 qstatus = GetQueueStatus(qs_all_input);
11215 ok(qstatus == 0,
11216 "wrong qstatus %08x\n", qstatus);
11218 msg.message = 0;
11219 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11220 ok(!ret,
11221 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11222 msg.message);
11223 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11225 qstatus = GetQueueStatus(qs_all_input);
11226 ok(qstatus == 0,
11227 "wrong qstatus %08x\n", qstatus);
11229 /* test whether presence of the quit flag in the queue affects
11230 * the queue state
11232 PostQuitMessage(0x1234abcd);
11234 qstatus = GetQueueStatus(qs_all_input);
11235 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
11236 "wrong qstatus %08x\n", qstatus);
11238 PostMessageA(info.hwnd, WM_USER, 0, 0);
11240 qstatus = GetQueueStatus(qs_all_input);
11241 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
11242 "wrong qstatus %08x\n", qstatus);
11244 msg.message = 0;
11245 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11246 ok(ret && msg.message == WM_USER,
11247 "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
11248 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11250 qstatus = GetQueueStatus(qs_all_input);
11251 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
11252 "wrong qstatus %08x\n", qstatus);
11254 msg.message = 0;
11255 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11256 ok(ret && msg.message == WM_QUIT,
11257 "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
11258 ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
11259 ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
11260 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11262 qstatus = GetQueueStatus(qs_all_input);
11263 todo_wine {
11264 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
11265 "wrong qstatus %08x\n", qstatus);
11268 msg.message = 0;
11269 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11270 ok(!ret,
11271 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11272 msg.message);
11273 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11275 qstatus = GetQueueStatus(qs_all_input);
11276 ok(qstatus == 0,
11277 "wrong qstatus %08x\n", qstatus);
11279 /* some GetMessage tests */
11281 keybd_event('N', 0, 0, 0);
11282 qstatus = GetQueueStatus(qs_all_input);
11283 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
11285 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11286 qstatus = GetQueueStatus(qs_all_input);
11287 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
11289 if (qstatus)
11291 ret = GetMessageA( &msg, 0, 0, 0 );
11292 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11293 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11294 ret, msg.message, msg.wParam);
11295 qstatus = GetQueueStatus(qs_all_input);
11296 ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08x\n", qstatus);
11299 if (qstatus)
11301 ret = GetMessageA( &msg, 0, 0, 0 );
11302 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
11303 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
11304 ret, msg.message, msg.wParam);
11305 ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
11306 qstatus = GetQueueStatus(qs_all_input);
11307 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11310 keybd_event('N', 0, 0, 0);
11311 qstatus = GetQueueStatus(qs_all_input);
11312 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
11314 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11315 qstatus = GetQueueStatus(qs_all_input);
11316 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
11318 if (qstatus & (QS_KEY << 16))
11320 ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
11321 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
11322 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
11323 ret, msg.message, msg.wParam);
11324 ok_sequence(WmKeyDownWasDownSkippedSeq, "WmKeyDownWasDownSkippedSeq", FALSE);
11325 qstatus = GetQueueStatus(qs_all_input);
11326 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
11329 if (qstatus)
11331 ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
11332 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11333 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11334 ret, msg.message, msg.wParam);
11335 qstatus = GetQueueStatus(qs_all_input);
11336 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11339 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
11340 qstatus = GetQueueStatus(qs_all_input);
11341 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
11343 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11344 qstatus = GetQueueStatus(qs_all_input);
11345 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
11347 trace("signalling to send message\n");
11348 SetEvent(info.hevent[EV_SENDMSG]);
11349 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11350 qstatus = GetQueueStatus(qs_all_input);
11351 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
11352 "wrong qstatus %08x\n", qstatus);
11354 if (qstatus & (QS_KEY << 16))
11356 ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
11357 ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
11358 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
11359 ret, msg.message, msg.wParam);
11360 ok_sequence(WmUserKeyUpSkippedSeq, "WmUserKeyUpSkippedSeq", FALSE);
11361 qstatus = GetQueueStatus(qs_all_input);
11362 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
11365 if (qstatus)
11367 ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
11368 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11369 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11370 ret, msg.message, msg.wParam);
11371 qstatus = GetQueueStatus(qs_all_input);
11372 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11374 done:
11375 trace("signalling to exit\n");
11376 SetEvent(info.hevent[EV_STOP]);
11378 WaitForSingleObject(hthread, INFINITE);
11380 CloseHandle(hthread);
11381 CloseHandle(info.hevent[0]);
11382 CloseHandle(info.hevent[1]);
11383 CloseHandle(info.hevent[2]);
11385 DestroyWindow(info.hwnd);
11388 static void wait_move_event(HWND hwnd, int x, int y)
11390 MSG msg;
11391 DWORD time;
11392 BOOL ret;
11394 time = GetTickCount();
11395 while (GetTickCount() - time < 200) {
11396 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
11397 if (ret && msg.pt.x > x && msg.pt.y > y) break;
11398 if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, GetTickCount() - time, QS_ALLINPUT );
11399 else Sleep( GetTickCount() - time );
11403 #define STEP 5
11404 static void test_PeekMessage2(void)
11406 HWND hwnd;
11407 BOOL ret;
11408 MSG msg;
11409 UINT message;
11410 DWORD time1, time2, time3;
11411 int x1, y1, x2, y2, x3, y3;
11412 POINT pos;
11414 time1 = time2 = time3 = 0;
11415 x1 = y1 = x2 = y2 = x3 = y3 = 0;
11417 /* Initialise window and make sure it is ready for events */
11418 hwnd = CreateWindowA("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
11419 10, 10, 800, 800, NULL, NULL, NULL, NULL);
11420 assert(hwnd);
11421 trace("Window for test_PeekMessage2 %p\n", hwnd);
11422 ShowWindow(hwnd, SW_SHOW);
11423 UpdateWindow(hwnd);
11424 SetFocus(hwnd);
11425 GetCursorPos(&pos);
11426 SetCursorPos(100, 100);
11427 mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
11428 flush_events();
11430 /* Do initial mousemove, wait until we can see it
11431 and then do our test peek with PM_NOREMOVE. */
11432 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
11433 wait_move_event(hwnd, 100-STEP, 100-STEP);
11435 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
11436 if (!ret)
11438 skip( "queuing mouse events not supported\n" );
11439 goto done;
11441 else
11443 trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
11444 message = msg.message;
11445 time1 = msg.time;
11446 x1 = msg.pt.x;
11447 y1 = msg.pt.y;
11448 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
11451 /* Allow time to advance a bit, and then simulate the user moving their
11452 * mouse around. After that we peek again with PM_NOREMOVE.
11453 * Although the previous mousemove message was never removed, the
11454 * mousemove we now peek should reflect the recent mouse movements
11455 * because the input queue will merge the move events. */
11456 Sleep(100);
11457 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
11458 wait_move_event(hwnd, x1, y1);
11460 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
11461 ok(ret, "no message available\n");
11462 if (ret) {
11463 trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
11464 message = msg.message;
11465 time2 = msg.time;
11466 x2 = msg.pt.x;
11467 y2 = msg.pt.y;
11468 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
11469 ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
11470 ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
11473 /* Have another go, to drive the point home */
11474 Sleep(100);
11475 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
11476 wait_move_event(hwnd, x2, y2);
11478 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
11479 ok(ret, "no message available\n");
11480 if (ret) {
11481 trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
11482 message = msg.message;
11483 time3 = msg.time;
11484 x3 = msg.pt.x;
11485 y3 = msg.pt.y;
11486 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
11487 ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
11488 ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
11491 done:
11492 DestroyWindow(hwnd);
11493 SetCursorPos(pos.x, pos.y);
11494 flush_events();
11497 static void test_PeekMessage3(void)
11499 HWND hwnd;
11500 BOOL ret;
11501 MSG msg;
11503 hwnd = CreateWindowA("TestWindowClass", "PeekMessage3", WS_OVERLAPPEDWINDOW,
11504 10, 10, 800, 800, NULL, NULL, NULL, NULL);
11505 ok(hwnd != NULL, "expected hwnd != NULL\n");
11506 flush_events();
11508 /* GetMessage() and PeekMessage(..., PM_REMOVE) should prefer messages which
11509 * were already seen. */
11511 SetTimer(hwnd, 1, 0, NULL);
11512 while (!PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE));
11513 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11514 PostMessageA(hwnd, WM_USER, 0, 0);
11515 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
11516 todo_wine
11517 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11518 ret = GetMessageA(&msg, NULL, 0, 0);
11519 todo_wine
11520 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11521 ret = GetMessageA(&msg, NULL, 0, 0);
11522 todo_wine
11523 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
11524 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
11525 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
11527 SetTimer(hwnd, 1, 0, NULL);
11528 while (!PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE));
11529 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11530 PostMessageA(hwnd, WM_USER, 0, 0);
11531 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
11532 todo_wine
11533 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11534 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
11535 todo_wine
11536 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
11537 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
11538 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
11540 /* It doesn't matter if a message range is specified or not. */
11542 SetTimer(hwnd, 1, 0, NULL);
11543 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
11544 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11545 PostMessageA(hwnd, WM_USER, 0, 0);
11546 ret = GetMessageA(&msg, NULL, 0, 0);
11547 todo_wine
11548 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11549 ret = GetMessageA(&msg, NULL, 0, 0);
11550 todo_wine
11551 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
11552 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
11553 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
11555 /* But not if the post messages were added before the PeekMessage() call. */
11557 PostMessageA(hwnd, WM_USER, 0, 0);
11558 SetTimer(hwnd, 1, 0, NULL);
11559 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
11560 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11561 ret = GetMessageA(&msg, NULL, 0, 0);
11562 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
11563 ret = GetMessageA(&msg, NULL, 0, 0);
11564 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11565 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
11566 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
11568 /* More complicated test with multiple messages. */
11570 PostMessageA(hwnd, WM_USER, 0, 0);
11571 SetTimer(hwnd, 1, 0, NULL);
11572 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
11573 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11574 PostMessageA(hwnd, WM_USER + 1, 0, 0);
11575 ret = GetMessageA(&msg, NULL, 0, 0);
11576 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
11577 ret = GetMessageA(&msg, NULL, 0, 0);
11578 todo_wine
11579 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11580 ret = GetMessageA(&msg, NULL, 0, 0);
11581 todo_wine
11582 ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message);
11583 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
11584 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
11586 /* Also works for posted messages, but the situation is a bit different,
11587 * because both messages are in the same queue. */
11589 PostMessageA(hwnd, WM_TIMER, 0, 0);
11590 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
11591 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11592 PostMessageA(hwnd, WM_USER, 0, 0);
11593 ret = GetMessageA(&msg, NULL, 0, 0);
11594 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11595 ret = GetMessageA(&msg, NULL, 0, 0);
11596 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
11597 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
11598 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
11600 PostMessageA(hwnd, WM_USER, 0, 0);
11601 PostMessageA(hwnd, WM_TIMER, 0, 0);
11602 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
11603 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11604 ret = GetMessageA(&msg, NULL, 0, 0);
11605 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
11606 ret = GetMessageA(&msg, NULL, 0, 0);
11607 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
11608 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
11609 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
11611 DestroyWindow(hwnd);
11612 flush_events();
11615 static INT_PTR CALLBACK wm_quit_dlg_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
11617 struct recvd_message msg;
11619 if (ignore_message( message )) return 0;
11621 msg.hwnd = hwnd;
11622 msg.message = message;
11623 msg.flags = sent|wparam|lparam;
11624 msg.wParam = wp;
11625 msg.lParam = lp;
11626 msg.descr = "dialog";
11627 add_message(&msg);
11629 switch (message)
11631 case WM_INITDIALOG:
11632 PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
11633 PostMessageA(hwnd, WM_USER, 0xdead, 0xbeef);
11634 return 0;
11636 case WM_GETDLGCODE:
11637 return 0;
11639 case WM_USER:
11640 EndDialog(hwnd, 0);
11641 break;
11644 return 1;
11647 static const struct message WmQuitDialogSeq[] = {
11648 { HCBT_CREATEWND, hook },
11649 { WM_SETFONT, sent },
11650 { WM_INITDIALOG, sent },
11651 { WM_CHANGEUISTATE, sent|optional },
11652 { HCBT_DESTROYWND, hook },
11653 { 0x0090, sent|optional }, /* Vista */
11654 { WM_DESTROY, sent },
11655 { WM_NCDESTROY, sent },
11656 { 0 }
11659 static const struct message WmStopQuitSeq[] = {
11660 { WM_DWMNCRENDERINGCHANGED, posted|optional },
11661 { WM_CLOSE, posted },
11662 { WM_QUIT, posted|wparam|lparam, 0x1234, 0 },
11663 { 0 }
11666 static void test_quit_message(void)
11668 MSG msg;
11669 BOOL ret;
11671 /* test using PostQuitMessage */
11672 flush_events();
11673 PostQuitMessage(0xbeef);
11675 msg.message = 0;
11676 ret = PeekMessageA(&msg, 0, 0, 0, PM_QS_SENDMESSAGE);
11677 ok(!ret, "got %x message\n", msg.message);
11679 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
11680 ok(ret, "PeekMessage failed with error %d\n", GetLastError());
11681 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
11682 ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
11684 ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
11685 ok(ret, "PostMessage failed with error %d\n", GetLastError());
11687 ret = GetMessageA(&msg, NULL, 0, 0);
11688 ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
11689 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
11691 /* note: WM_QUIT message received after WM_USER message */
11692 ret = GetMessageA(&msg, NULL, 0, 0);
11693 ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
11694 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
11695 ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
11697 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
11698 ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
11700 /* now test with PostThreadMessage - different behaviour! */
11701 PostThreadMessageA(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
11703 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
11704 ok(ret, "PeekMessage failed with error %d\n", GetLastError());
11705 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
11706 ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
11708 ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
11709 ok(ret, "PostMessage failed with error %d\n", GetLastError());
11711 /* note: we receive the WM_QUIT message first this time */
11712 ret = GetMessageA(&msg, NULL, 0, 0);
11713 ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
11714 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
11715 ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
11717 ret = GetMessageA(&msg, NULL, 0, 0);
11718 ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
11719 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
11721 flush_events();
11722 flush_sequence();
11723 ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, wm_quit_dlg_proc, 0);
11724 ok(ret == 1, "expected 1, got %d\n", ret);
11725 ok_sequence(WmQuitDialogSeq, "WmQuitDialogSeq", FALSE);
11726 memset(&msg, 0xab, sizeof(msg));
11727 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
11728 ok(ret, "PeekMessage failed\n");
11729 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
11730 ok(msg.wParam == 0x1234, "wParam was 0x%lx instead of 0x1234\n", msg.wParam);
11731 ok(msg.lParam == 0, "lParam was 0x%lx instead of 0\n", msg.lParam);
11733 /* Check what happens to a WM_QUIT message posted to a window that gets
11734 * destroyed.
11736 CreateWindowExA(0, "StopQuitClass", "Stop Quit Test", WS_OVERLAPPEDWINDOW,
11737 0, 0, 100, 100, NULL, NULL, NULL, NULL);
11738 flush_sequence();
11739 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
11741 struct recvd_message rmsg;
11742 rmsg.hwnd = msg.hwnd;
11743 rmsg.message = msg.message;
11744 rmsg.flags = posted|wparam|lparam;
11745 rmsg.wParam = msg.wParam;
11746 rmsg.lParam = msg.lParam;
11747 rmsg.descr = "stop/quit";
11748 if (msg.message == WM_QUIT)
11749 /* The hwnd can only be checked here */
11750 ok(!msg.hwnd, "The WM_QUIT hwnd was %p instead of NULL\n", msg.hwnd);
11751 add_message(&rmsg);
11752 DispatchMessageA(&msg);
11754 ok_sequence(WmStopQuitSeq, "WmStopQuitSeq", FALSE);
11757 static const struct message WmNotifySeq[] = {
11758 { WM_NOTIFY, sent|wparam|lparam, 0x1234, 0xdeadbeef },
11759 { 0 }
11762 static void test_notify_message(void)
11764 HWND hwnd;
11765 BOOL ret;
11766 MSG msg;
11768 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11769 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0, NULL, NULL, 0);
11770 ok(hwnd != 0, "Failed to create window\n");
11771 flush_events();
11772 flush_sequence();
11774 ret = SendNotifyMessageA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
11775 ok(ret == TRUE, "SendNotifyMessageA failed with error %u\n", GetLastError());
11776 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
11778 ret = SendNotifyMessageW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
11779 ok(ret == TRUE, "SendNotifyMessageW failed with error %u\n", GetLastError());
11780 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
11782 ret = SendMessageCallbackA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef, NULL, 0);
11783 ok(ret == TRUE, "SendMessageCallbackA failed with error %u\n", GetLastError());
11784 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
11786 ret = SendMessageCallbackW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef, NULL, 0);
11787 ok(ret == TRUE, "SendMessageCallbackW failed with error %u\n", GetLastError());
11788 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
11790 ret = PostMessageA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
11791 ok(ret == TRUE, "PostMessageA failed with error %u\n", GetLastError());
11792 flush_events();
11793 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
11795 ret = PostMessageW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
11796 ok(ret == TRUE, "PostMessageW failed with error %u\n", GetLastError());
11797 flush_events();
11798 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
11800 ret = PostThreadMessageA(GetCurrentThreadId(), WM_NOTIFY, 0x1234, 0xdeadbeef);
11801 ok(ret == TRUE, "PostThreadMessageA failed with error %u\n", GetLastError());
11802 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
11804 msg.hwnd = hwnd;
11805 DispatchMessageA(&msg);
11807 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
11809 ret = PostThreadMessageW(GetCurrentThreadId(), WM_NOTIFY, 0x1234, 0xdeadbeef);
11810 ok(ret == TRUE, "PostThreadMessageW failed with error %u\n", GetLastError());
11811 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
11813 msg.hwnd = hwnd;
11814 DispatchMessageA(&msg);
11816 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
11818 DestroyWindow(hwnd);
11821 static const struct message WmMouseHoverSeq[] = {
11822 { WM_MOUSEACTIVATE, sent|optional }, /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
11823 { WM_MOUSEACTIVATE, sent|optional },
11824 { WM_TIMER, sent|optional }, /* XP sends it */
11825 { WM_SYSTIMER, sent },
11826 { WM_MOUSEHOVER, sent|wparam, 0 },
11827 { 0 }
11830 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
11832 MSG msg;
11833 DWORD start_ticks, end_ticks;
11835 start_ticks = GetTickCount();
11836 /* add some deviation (50%) to cover not expected delays */
11837 start_ticks += timeout / 2;
11841 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
11843 /* Timer proc messages are not dispatched to the window proc,
11844 * and therefore not logged.
11846 if ((msg.message == WM_TIMER || msg.message == WM_SYSTIMER) && msg.hwnd)
11848 struct recvd_message s_msg;
11850 s_msg.hwnd = msg.hwnd;
11851 s_msg.message = msg.message;
11852 s_msg.flags = sent|wparam|lparam;
11853 s_msg.wParam = msg.wParam;
11854 s_msg.lParam = msg.lParam;
11855 s_msg.descr = "msg_loop";
11856 add_message(&s_msg);
11858 DispatchMessageA(&msg);
11861 end_ticks = GetTickCount();
11863 /* inject WM_MOUSEMOVE to see how it changes tracking */
11864 if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
11866 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
11867 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
11869 inject_mouse_move = FALSE;
11871 } while (start_ticks + timeout >= end_ticks);
11874 static void test_TrackMouseEvent(void)
11876 TRACKMOUSEEVENT tme;
11877 BOOL ret;
11878 HWND hwnd, hchild;
11879 RECT rc_parent, rc_child;
11880 UINT default_hover_time, hover_width = 0, hover_height = 0;
11882 #define track_hover(track_hwnd, track_hover_time) \
11883 tme.cbSize = sizeof(tme); \
11884 tme.dwFlags = TME_HOVER; \
11885 tme.hwndTrack = track_hwnd; \
11886 tme.dwHoverTime = track_hover_time; \
11887 SetLastError(0xdeadbeef); \
11888 ret = pTrackMouseEvent(&tme); \
11889 ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
11891 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
11892 tme.cbSize = sizeof(tme); \
11893 tme.dwFlags = TME_QUERY; \
11894 tme.hwndTrack = (HWND)0xdeadbeef; \
11895 tme.dwHoverTime = 0xdeadbeef; \
11896 SetLastError(0xdeadbeef); \
11897 ret = pTrackMouseEvent(&tme); \
11898 ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
11899 ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
11900 ok(tme.dwFlags == (expected_track_flags), \
11901 "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
11902 ok(tme.hwndTrack == (expected_track_hwnd), \
11903 "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
11904 ok(tme.dwHoverTime == (expected_hover_time), \
11905 "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
11907 #define track_hover_cancel(track_hwnd) \
11908 tme.cbSize = sizeof(tme); \
11909 tme.dwFlags = TME_HOVER | TME_CANCEL; \
11910 tme.hwndTrack = track_hwnd; \
11911 tme.dwHoverTime = 0xdeadbeef; \
11912 SetLastError(0xdeadbeef); \
11913 ret = pTrackMouseEvent(&tme); \
11914 ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
11916 default_hover_time = 0xdeadbeef;
11917 SetLastError(0xdeadbeef);
11918 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
11919 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
11920 "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
11921 if (!ret) default_hover_time = 400;
11922 trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
11924 SetLastError(0xdeadbeef);
11925 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
11926 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
11927 "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
11928 if (!ret) hover_width = 4;
11929 SetLastError(0xdeadbeef);
11930 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
11931 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
11932 "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
11933 if (!ret) hover_height = 4;
11934 trace("hover rect is %u x %d\n", hover_width, hover_height);
11936 hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
11937 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11938 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
11939 NULL, NULL, 0);
11940 assert(hwnd);
11942 hchild = CreateWindowExA(0, "TestWindowClass", NULL,
11943 WS_CHILD | WS_BORDER | WS_VISIBLE,
11944 50, 50, 200, 200, hwnd,
11945 NULL, NULL, 0);
11946 assert(hchild);
11948 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
11949 flush_events();
11950 flush_sequence();
11952 tme.cbSize = 0;
11953 tme.dwFlags = TME_QUERY;
11954 tme.hwndTrack = (HWND)0xdeadbeef;
11955 tme.dwHoverTime = 0xdeadbeef;
11956 SetLastError(0xdeadbeef);
11957 ret = pTrackMouseEvent(&tme);
11958 ok(!ret, "TrackMouseEvent should fail\n");
11959 ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
11960 "not expected error %u\n", GetLastError());
11962 tme.cbSize = sizeof(tme);
11963 tme.dwFlags = TME_HOVER;
11964 tme.hwndTrack = (HWND)0xdeadbeef;
11965 tme.dwHoverTime = 0xdeadbeef;
11966 SetLastError(0xdeadbeef);
11967 ret = pTrackMouseEvent(&tme);
11968 ok(!ret, "TrackMouseEvent should fail\n");
11969 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
11970 "not expected error %u\n", GetLastError());
11972 tme.cbSize = sizeof(tme);
11973 tme.dwFlags = TME_HOVER | TME_CANCEL;
11974 tme.hwndTrack = (HWND)0xdeadbeef;
11975 tme.dwHoverTime = 0xdeadbeef;
11976 SetLastError(0xdeadbeef);
11977 ret = pTrackMouseEvent(&tme);
11978 ok(!ret, "TrackMouseEvent should fail\n");
11979 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
11980 "not expected error %u\n", GetLastError());
11982 GetWindowRect(hwnd, &rc_parent);
11983 GetWindowRect(hchild, &rc_child);
11984 SetCursorPos(rc_child.left - 10, rc_child.top - 10);
11986 /* Process messages so that the system updates its internal current
11987 * window and hittest, otherwise TrackMouseEvent calls don't have any
11988 * effect.
11990 flush_events();
11991 flush_sequence();
11993 track_query(0, NULL, 0);
11994 track_hover(hchild, 0);
11995 track_query(0, NULL, 0);
11997 flush_events();
11998 flush_sequence();
12000 track_hover(hwnd, 0);
12001 tme.cbSize = sizeof(tme);
12002 tme.dwFlags = TME_QUERY;
12003 tme.hwndTrack = (HWND)0xdeadbeef;
12004 tme.dwHoverTime = 0xdeadbeef;
12005 SetLastError(0xdeadbeef);
12006 ret = pTrackMouseEvent(&tme);
12007 ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());
12008 ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize);
12009 if (!tme.dwFlags)
12011 skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" );
12012 DestroyWindow( hwnd );
12013 return;
12015 ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08x, expected TME_HOVER\n", tme.dwFlags);
12016 ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd);
12017 ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %u, expected %u\n",
12018 tme.dwHoverTime, default_hover_time);
12020 pump_msg_loop_timeout(default_hover_time, FALSE);
12021 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
12023 track_query(0, NULL, 0);
12025 track_hover(hwnd, HOVER_DEFAULT);
12026 track_query(TME_HOVER, hwnd, default_hover_time);
12028 Sleep(default_hover_time / 2);
12029 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
12030 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
12032 track_query(TME_HOVER, hwnd, default_hover_time);
12034 pump_msg_loop_timeout(default_hover_time, FALSE);
12035 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
12037 track_query(0, NULL, 0);
12039 track_hover(hwnd, HOVER_DEFAULT);
12040 track_query(TME_HOVER, hwnd, default_hover_time);
12042 pump_msg_loop_timeout(default_hover_time, TRUE);
12043 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
12045 track_query(0, NULL, 0);
12047 track_hover(hwnd, HOVER_DEFAULT);
12048 track_query(TME_HOVER, hwnd, default_hover_time);
12049 track_hover_cancel(hwnd);
12051 DestroyWindow(hwnd);
12053 #undef track_hover
12054 #undef track_query
12055 #undef track_hover_cancel
12059 static const struct message WmSetWindowRgn[] = {
12060 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12061 { WM_NCCALCSIZE, sent|wparam, 1 },
12062 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
12063 { WM_GETTEXT, sent|defwinproc|optional },
12064 { WM_ERASEBKGND, sent|optional },
12065 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12066 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12067 { 0 }
12070 static const struct message WmSetWindowRgn_no_redraw[] = {
12071 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
12072 { WM_NCCALCSIZE, sent|wparam, 1 },
12073 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
12074 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12075 { 0 }
12078 static const struct message WmSetWindowRgn_clear[] = {
12079 { WM_WINDOWPOSCHANGING, sent/*|wparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */ },
12080 { WM_NCCALCSIZE, sent|wparam, 1 },
12081 { WM_NCPAINT, sent|optional },
12082 { WM_GETTEXT, sent|defwinproc|optional },
12083 { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
12084 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12085 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
12086 { WM_NCPAINT, sent|optional },
12087 { WM_GETTEXT, sent|defwinproc|optional },
12088 { WM_ERASEBKGND, sent|optional },
12089 { WM_WINDOWPOSCHANGING, sent|optional },
12090 { WM_NCCALCSIZE, sent|optional|wparam, 1 },
12091 { WM_NCPAINT, sent|optional },
12092 { WM_GETTEXT, sent|defwinproc|optional },
12093 { WM_ERASEBKGND, sent|optional },
12094 { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12095 { WM_NCCALCSIZE, sent|optional|wparam, 1 },
12096 { WM_NCPAINT, sent|optional },
12097 { WM_GETTEXT, sent|defwinproc|optional },
12098 { WM_ERASEBKGND, sent|optional },
12099 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12100 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12101 { 0 }
12104 static void test_SetWindowRgn(void)
12106 HRGN hrgn;
12107 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
12108 100, 100, 200, 200, 0, 0, 0, NULL);
12109 ok( hwnd != 0, "Failed to create overlapped window\n" );
12111 ShowWindow( hwnd, SW_SHOW );
12112 UpdateWindow( hwnd );
12113 flush_events();
12114 flush_sequence();
12116 trace("testing SetWindowRgn\n");
12117 hrgn = CreateRectRgn( 0, 0, 150, 150 );
12118 SetWindowRgn( hwnd, hrgn, TRUE );
12119 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
12121 hrgn = CreateRectRgn( 30, 30, 160, 160 );
12122 SetWindowRgn( hwnd, hrgn, FALSE );
12123 ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
12125 hrgn = CreateRectRgn( 0, 0, 180, 180 );
12126 SetWindowRgn( hwnd, hrgn, TRUE );
12127 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
12129 SetWindowRgn( hwnd, 0, TRUE );
12130 ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
12132 DestroyWindow( hwnd );
12135 /*************************** ShowWindow() test ******************************/
12136 static const struct message WmShowNormal[] = {
12137 { WM_SHOWWINDOW, sent|wparam, 1 },
12138 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12139 { HCBT_ACTIVATE, hook },
12140 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
12141 { HCBT_SETFOCUS, hook },
12142 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12143 { 0 }
12145 static const struct message WmShow[] = {
12146 { WM_SHOWWINDOW, sent|wparam, 1 },
12147 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12148 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12149 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12150 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12151 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12152 { 0 }
12154 static const struct message WmShowNoActivate_1[] = {
12155 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
12156 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12157 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12158 { WM_MOVE, sent|defwinproc|optional },
12159 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
12160 { 0 }
12162 static const struct message WmShowNoActivate_2[] = {
12163 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
12164 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12165 { HCBT_ACTIVATE, hook|optional },
12166 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
12167 { HCBT_SETFOCUS, hook|optional },
12168 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12169 { WM_MOVE, sent|defwinproc },
12170 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
12171 { HCBT_SETFOCUS, hook|optional },
12172 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
12173 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
12174 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12175 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
12176 { 0 }
12178 static const struct message WmShowNA_1[] = {
12179 { WM_SHOWWINDOW, sent|wparam, 1 },
12180 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
12181 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12182 { 0 }
12184 static const struct message WmShowNA_2[] = {
12185 { WM_SHOWWINDOW, sent|wparam, 1 },
12186 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
12187 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12188 { 0 }
12190 static const struct message WmRestore_1[] = {
12191 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
12192 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12193 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12194 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12195 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12196 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12197 { WM_MOVE, sent|defwinproc },
12198 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
12199 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
12200 { 0 }
12202 static const struct message WmRestore_2[] = {
12203 { WM_SHOWWINDOW, sent|wparam, 1 },
12204 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12205 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12206 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12207 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12208 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12209 { 0 }
12211 static const struct message WmRestore_3[] = {
12212 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
12213 { WM_GETMINMAXINFO, sent },
12214 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12215 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
12216 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
12217 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
12218 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12219 { WM_MOVE, sent|defwinproc },
12220 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
12221 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
12222 { 0 }
12224 static const struct message WmRestore_4[] = {
12225 { HCBT_MINMAX, hook|lparam|optional, 0, SW_RESTORE },
12226 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12227 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12228 { WM_MOVE, sent|defwinproc|optional },
12229 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
12230 { 0 }
12232 static const struct message WmRestore_5[] = {
12233 { HCBT_MINMAX, hook|lparam|optional, 0, SW_SHOWNORMAL },
12234 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12235 { HCBT_ACTIVATE, hook|optional },
12236 { HCBT_SETFOCUS, hook|optional },
12237 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12238 { WM_MOVE, sent|defwinproc|optional },
12239 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
12240 { 0 }
12242 static const struct message WmHide_1[] = {
12243 { WM_SHOWWINDOW, sent|wparam, 0 },
12244 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOACTIVATE },
12245 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOACTIVATE },
12246 { HCBT_ACTIVATE, hook|optional },
12247 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
12248 { 0 }
12250 static const struct message WmHide_2[] = {
12251 { WM_SHOWWINDOW, sent|wparam, 0 },
12252 { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
12253 { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
12254 { HCBT_ACTIVATE, hook|optional },
12255 { 0 }
12257 static const struct message WmHide_3[] = {
12258 { WM_SHOWWINDOW, sent|wparam, 0 },
12259 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12260 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12261 { HCBT_SETFOCUS, hook|optional },
12262 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
12263 { 0 }
12265 static const struct message WmShowMinimized_1[] = {
12266 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
12267 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12268 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12269 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12270 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12271 { WM_MOVE, sent|defwinproc },
12272 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
12273 { 0 }
12275 static const struct message WmMinimize_1[] = {
12276 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
12277 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12278 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
12279 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12280 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12281 { WM_MOVE, sent|defwinproc },
12282 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
12283 { 0 }
12285 static const struct message WmMinimize_2[] = {
12286 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
12287 { HCBT_SETFOCUS, hook|optional },
12288 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12289 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12290 { WM_MOVE, sent|defwinproc },
12291 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
12292 { 0 }
12294 static const struct message WmMinimize_3[] = {
12295 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
12296 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12297 { HCBT_ACTIVATE, hook|optional },
12298 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
12299 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12300 { WM_MOVE, sent|defwinproc },
12301 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
12302 { 0 }
12304 static const struct message WmShowMinNoActivate[] = {
12305 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
12306 { WM_WINDOWPOSCHANGING, sent },
12307 { WM_WINDOWPOSCHANGED, sent },
12308 { WM_MOVE, sent|defwinproc|optional },
12309 { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
12310 { 0 }
12312 static const struct message WmMinMax_1[] = {
12313 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
12314 { 0 }
12316 static const struct message WmMinMax_2[] = {
12317 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
12318 { WM_GETMINMAXINFO, sent|optional },
12319 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED },
12320 { HCBT_ACTIVATE, hook|optional },
12321 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
12322 { HCBT_SETFOCUS, hook|optional },
12323 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12324 { WM_MOVE, sent|defwinproc|optional },
12325 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MAXIMIZED },
12326 { HCBT_SETFOCUS, hook|optional },
12327 { 0 }
12329 static const struct message WmMinMax_3[] = {
12330 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
12331 { HCBT_SETFOCUS, hook|optional },
12332 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12333 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12334 { WM_MOVE, sent|defwinproc|optional },
12335 { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
12336 { 0 }
12338 static const struct message WmMinMax_4[] = {
12339 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
12340 { 0 }
12342 static const struct message WmShowMaximized_1[] = {
12343 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
12344 { WM_GETMINMAXINFO, sent },
12345 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12346 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12347 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12348 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12349 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12350 { WM_MOVE, sent|defwinproc },
12351 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
12352 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
12353 { 0 }
12355 static const struct message WmShowMaximized_2[] = {
12356 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
12357 { WM_GETMINMAXINFO, sent },
12358 { WM_WINDOWPOSCHANGING, sent|optional },
12359 { HCBT_ACTIVATE, hook|optional },
12360 { WM_WINDOWPOSCHANGED, sent|optional },
12361 { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
12362 { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
12363 { WM_WINDOWPOSCHANGING, sent|optional },
12364 { HCBT_SETFOCUS, hook|optional },
12365 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12366 { WM_MOVE, sent|defwinproc },
12367 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
12368 { HCBT_SETFOCUS, hook|optional },
12369 { 0 }
12371 static const struct message WmShowMaximized_3[] = {
12372 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
12373 { WM_GETMINMAXINFO, sent|optional },
12374 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12375 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12376 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12377 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12378 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12379 { WM_MOVE, sent|defwinproc|optional },
12380 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
12381 { 0 }
12384 static void test_ShowWindow(void)
12386 /* ShowWindow commands in random order */
12387 static const struct
12389 INT cmd; /* ShowWindow command */
12390 LPARAM ret; /* ShowWindow return value */
12391 DWORD style; /* window style after the command */
12392 const struct message *msg; /* message sequence the command produces */
12393 INT wp_cmd, wp_flags; /* window placement after the command */
12394 POINT wp_min, wp_max; /* window placement after the command */
12395 BOOL todo_msg; /* message sequence doesn't match what Wine does */
12396 } sw[] =
12398 /* 1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal,
12399 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
12400 /* 2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq,
12401 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
12402 /* 3 */ { SW_HIDE, TRUE, 0, WmHide_1,
12403 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
12404 /* 4 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
12405 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
12406 /* 5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1,
12407 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12408 /* 6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1,
12409 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12410 /* 7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1,
12411 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12412 /* 8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
12413 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12414 /* 9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1,
12415 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12416 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
12417 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12418 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1,
12419 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12420 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq,
12421 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12422 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1,
12423 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12424 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
12425 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12426 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2,
12427 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12428 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
12429 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12430 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow,
12431 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12432 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
12433 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12434 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
12435 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12436 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
12437 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12438 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
12439 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12440 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate,
12441 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, TRUE },
12442 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4,
12443 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12444 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
12445 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12446 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
12447 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12448 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1,
12449 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12450 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2,
12451 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12452 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
12453 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12454 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
12455 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12456 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1,
12457 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12458 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
12459 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12460 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3,
12461 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12462 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
12463 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12464 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, /* what does this mean?! */
12465 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12466 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq,
12467 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12468 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
12469 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12470 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2,
12471 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12472 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
12473 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12474 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
12475 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12476 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2,
12477 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12478 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
12479 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12480 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2,
12481 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12482 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
12483 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12484 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
12485 SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12486 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
12487 SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12488 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3,
12489 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12490 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4,
12491 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12492 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3,
12493 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12494 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq,
12495 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12496 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
12497 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12498 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
12499 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12500 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1,
12501 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12502 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
12503 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12504 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3,
12505 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12506 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
12507 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12508 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2,
12509 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12510 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
12511 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE }
12513 HWND hwnd;
12514 DWORD style;
12515 LPARAM ret;
12516 INT i;
12517 WINDOWPLACEMENT wp;
12518 RECT win_rc, work_rc = {0, 0, 0, 0};
12520 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
12521 hwnd = CreateWindowExA(0, "ShowWindowClass", NULL, WS_BASE,
12522 120, 120, 90, 90,
12523 0, 0, 0, NULL);
12524 assert(hwnd);
12526 style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
12527 ok(style == 0, "expected style 0, got %08x\n", style);
12529 flush_events();
12530 flush_sequence();
12532 if (pGetMonitorInfoA && pMonitorFromPoint)
12534 HMONITOR hmon;
12535 MONITORINFO mi;
12536 POINT pt = {0, 0};
12538 SetLastError(0xdeadbeef);
12539 hmon = pMonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
12540 ok(hmon != 0, "MonitorFromPoint error %u\n", GetLastError());
12542 mi.cbSize = sizeof(mi);
12543 SetLastError(0xdeadbeef);
12544 ret = pGetMonitorInfoA(hmon, &mi);
12545 ok(ret, "GetMonitorInfo error %u\n", GetLastError());
12546 trace("monitor %s, work %s\n", wine_dbgstr_rect(&mi.rcMonitor),
12547 wine_dbgstr_rect(&mi.rcWork));
12548 work_rc = mi.rcWork;
12551 GetWindowRect(hwnd, &win_rc);
12552 OffsetRect(&win_rc, -work_rc.left, -work_rc.top);
12554 wp.length = sizeof(wp);
12555 SetLastError(0xdeadbeaf);
12556 ret = GetWindowPlacement(hwnd, &wp);
12557 ok(ret, "GetWindowPlacement error %u\n", GetLastError());
12558 ok(wp.flags == 0, "expected 0, got %#x\n", wp.flags);
12559 ok(wp.showCmd == SW_SHOWNORMAL, "expected SW_SHOWNORMAL, got %d\n", wp.showCmd);
12560 ok(wp.ptMinPosition.x == -1 && wp.ptMinPosition.y == -1,
12561 "expected -1,-1 got %d,%d\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
12562 ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
12563 "expected -1,-1 got %d,%d\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
12564 todo_wine_if (work_rc.left || work_rc.top) /* FIXME: remove once Wine is fixed */
12565 ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n", wine_dbgstr_rect(&win_rc),
12566 wine_dbgstr_rect(&wp.rcNormalPosition));
12568 for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++)
12570 static const char * const sw_cmd_name[13] =
12572 "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
12573 "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
12574 "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
12575 "SW_NORMALNA" /* 0xCC */
12577 char comment[64];
12578 INT idx; /* index into the above array of names */
12580 idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
12582 style = GetWindowLongA(hwnd, GWL_STYLE);
12583 trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
12584 ret = ShowWindow(hwnd, sw[i].cmd);
12585 ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
12586 style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
12587 ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
12589 sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
12590 ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
12592 wp.length = sizeof(wp);
12593 SetLastError(0xdeadbeaf);
12594 ret = GetWindowPlacement(hwnd, &wp);
12595 ok(ret, "GetWindowPlacement error %u\n", GetLastError());
12596 ok(wp.flags == sw[i].wp_flags, "expected %#x, got %#x\n", sw[i].wp_flags, wp.flags);
12597 ok(wp.showCmd == sw[i].wp_cmd, "expected %d, got %d\n", sw[i].wp_cmd, wp.showCmd);
12599 /* NT moves the minimized window to -32000,-32000, win9x to 3000,3000 */
12600 if ((wp.ptMinPosition.x + work_rc.left == -32000 && wp.ptMinPosition.y + work_rc.top == -32000) ||
12601 (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000))
12603 ok((wp.ptMinPosition.x + work_rc.left == sw[i].wp_min.x && wp.ptMinPosition.y + work_rc.top == sw[i].wp_min.y) ||
12604 (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000),
12605 "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
12607 else
12609 ok(wp.ptMinPosition.x == sw[i].wp_min.x && wp.ptMinPosition.y == sw[i].wp_min.y,
12610 "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
12613 todo_wine_if(wp.ptMaxPosition.x != sw[i].wp_max.x || wp.ptMaxPosition.y != sw[i].wp_max.y)
12614 ok(wp.ptMaxPosition.x == sw[i].wp_max.x && wp.ptMaxPosition.y == sw[i].wp_max.y,
12615 "expected %d,%d got %d,%d\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y);
12617 if (0) /* FIXME: Wine behaves completely different here */
12618 ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n",
12619 wine_dbgstr_rect(&win_rc), wine_dbgstr_rect(&wp.rcNormalPosition));
12621 DestroyWindow(hwnd);
12622 flush_events();
12625 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
12627 struct recvd_message msg;
12629 if (ignore_message( message )) return 0;
12631 msg.hwnd = hwnd;
12632 msg.message = message;
12633 msg.flags = sent|wparam|lparam;
12634 msg.wParam = wParam;
12635 msg.lParam = lParam;
12636 msg.descr = "dialog";
12637 add_message(&msg);
12639 /* calling DefDlgProc leads to a recursion under XP */
12641 switch (message)
12643 case WM_INITDIALOG:
12644 case WM_GETDLGCODE:
12645 return 0;
12647 return 1;
12650 static WNDPROC orig_edit_proc;
12651 static LRESULT WINAPI dlg_creation_edit_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
12653 struct recvd_message msg;
12655 if (ignore_message( message )) return 0;
12657 msg.hwnd = hwnd;
12658 msg.message = message;
12659 msg.flags = sent|wparam|lparam;
12660 msg.wParam = wp;
12661 msg.lParam = lp;
12662 msg.descr = "edit";
12663 add_message(&msg);
12665 return CallWindowProcW(orig_edit_proc, hwnd, message, wp, lp);
12668 static INT_PTR WINAPI test_dlg_proc2(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
12670 struct recvd_message msg;
12672 if (ignore_message( message )) return 0;
12674 msg.hwnd = hwnd;
12675 msg.message = message;
12676 msg.flags = sent|wparam|lparam|parent;
12677 msg.wParam = wParam;
12678 msg.lParam = lParam;
12679 msg.descr = "dialog";
12680 add_message(&msg);
12682 if (message == WM_INITDIALOG)
12684 orig_edit_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwnd, 200),
12685 GWLP_WNDPROC, (LONG_PTR)dlg_creation_edit_proc);
12688 return 1;
12691 static INT_PTR WINAPI test_dlg_proc3(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
12693 ok( 0, "should not be called since DefDlgProc is not used\n" );
12694 return 0;
12697 static LRESULT WINAPI test_dlg_proc4(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
12699 struct recvd_message msg;
12701 if (!ignore_message( message ))
12703 msg.hwnd = hwnd;
12704 msg.message = message;
12705 msg.flags = sent|wparam|lparam|parent;
12706 msg.wParam = wParam;
12707 msg.lParam = lParam;
12708 msg.descr = "dialog";
12709 add_message(&msg);
12711 if (message == WM_INITDIALOG)
12713 orig_edit_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwnd, 200),
12714 GWLP_WNDPROC, (LONG_PTR)dlg_creation_edit_proc);
12715 return 1;
12717 return DefWindowProcW( hwnd, message, wParam, lParam );
12720 static const struct message WmDefDlgSetFocus_1[] = {
12721 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
12722 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
12723 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
12724 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
12725 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
12726 { HCBT_SETFOCUS, hook },
12727 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
12728 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
12729 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
12730 { WM_SETFOCUS, sent|wparam, 0 },
12731 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
12732 { WM_CTLCOLOREDIT, sent },
12733 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
12734 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
12735 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
12736 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
12737 { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
12738 { 0 }
12740 static const struct message WmDefDlgSetFocus_2[] = {
12741 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
12742 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
12743 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
12744 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
12745 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
12746 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
12747 { WM_CTLCOLOREDIT, sent|optional }, /* XP */
12748 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
12749 { 0 }
12751 /* Creation of a dialog */
12752 static const struct message WmCreateDialogParamSeq_1[] = {
12753 { HCBT_CREATEWND, hook },
12754 { WM_NCCREATE, sent },
12755 { WM_NCCALCSIZE, sent|wparam, 0 },
12756 { WM_CREATE, sent },
12757 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
12758 { WM_SIZE, sent|wparam, SIZE_RESTORED },
12759 { WM_MOVE, sent },
12760 { WM_SETFONT, sent },
12761 { WM_INITDIALOG, sent },
12762 { WM_CHANGEUISTATE, sent|optional },
12763 { 0 }
12765 /* Creation of a dialog */
12766 static const struct message WmCreateDialogParamSeq_2[] = {
12767 { HCBT_CREATEWND, hook },
12768 { WM_NCCREATE, sent },
12769 { WM_NCCALCSIZE, sent|wparam, 0 },
12770 { WM_CREATE, sent },
12771 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
12772 { WM_SIZE, sent|wparam, SIZE_RESTORED },
12773 { WM_MOVE, sent },
12774 { WM_CHANGEUISTATE, sent|optional },
12775 { 0 }
12778 static const struct message WmCreateDialogParamSeq_3[] = {
12779 { HCBT_CREATEWND, hook },
12780 { WM_SETFONT, sent|parent },
12781 { WM_INITDIALOG, sent|parent },
12782 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
12783 { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
12784 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
12785 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
12786 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
12787 { HCBT_ACTIVATE, hook },
12788 { WM_QUERYNEWPALETTE, sent|parent|optional }, /* TODO: this message should not be sent */
12789 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
12790 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
12791 { WM_ACTIVATEAPP, sent|parent|wparam, 1 },
12792 { WM_NCACTIVATE, sent|parent },
12793 { WM_ACTIVATE, sent|parent|wparam, 1 },
12794 { WM_SETFOCUS, sent },
12795 { WM_COMMAND, sent|parent|wparam, MAKELONG(200, EN_SETFOCUS) },
12796 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
12797 { WM_USER, sent|parent },
12798 { WM_CHANGEUISTATE, sent|parent|optional },
12799 { 0 }
12802 static const struct message WmCreateDialogParamSeq_4[] = {
12803 { HCBT_CREATEWND, hook },
12804 { WM_NCCREATE, sent|parent },
12805 { WM_NCCALCSIZE, sent|parent|wparam, 0 },
12806 { WM_CREATE, sent|parent },
12807 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
12808 { WM_SIZE, sent|parent|wparam, SIZE_RESTORED },
12809 { WM_MOVE, sent|parent },
12810 { WM_SETFONT, sent|parent },
12811 { WM_INITDIALOG, sent|parent },
12812 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
12813 { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
12814 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
12815 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
12816 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
12817 { HCBT_ACTIVATE, hook },
12818 { WM_QUERYNEWPALETTE, sent|parent|optional }, /* TODO: this message should not be sent */
12819 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
12820 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
12821 { WM_ACTIVATEAPP, sent|parent|wparam, 1 },
12822 { WM_NCACTIVATE, sent|parent },
12823 { WM_ACTIVATE, sent|parent|wparam, 1 },
12824 { HCBT_SETFOCUS, hook },
12825 { WM_SETFOCUS, sent|parent },
12826 { WM_KILLFOCUS, sent|parent },
12827 { WM_SETFOCUS, sent },
12828 { WM_COMMAND, sent|parent|wparam, MAKELONG(200, EN_SETFOCUS) },
12829 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
12830 { WM_USER, sent|parent },
12831 { WM_CHANGEUISTATE, sent|parent|optional },
12832 { WM_UPDATEUISTATE, sent|parent|optional },
12833 { WM_UPDATEUISTATE, sent|optional },
12834 { 0 }
12837 static void test_dialog_messages(void)
12839 WNDCLASSA cls;
12840 HWND hdlg, hedit1, hedit2, hfocus, parent, child, child2;
12841 LRESULT ret;
12843 #define set_selection(hctl, start, end) \
12844 ret = SendMessageA(hctl, EM_SETSEL, start, end); \
12845 ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
12847 #define check_selection(hctl, start, end) \
12848 ret = SendMessageA(hctl, EM_GETSEL, 0, 0); \
12849 ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
12851 subclass_edit();
12853 hdlg = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
12854 WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
12855 0, 0, 100, 100, 0, 0, 0, NULL);
12856 ok(hdlg != 0, "Failed to create custom dialog window\n");
12858 hedit1 = CreateWindowExA(0, "my_edit_class", NULL,
12859 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
12860 0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
12861 ok(hedit1 != 0, "Failed to create edit control\n");
12862 hedit2 = CreateWindowExA(0, "my_edit_class", NULL,
12863 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
12864 0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
12865 ok(hedit2 != 0, "Failed to create edit control\n");
12867 SendMessageA(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
12868 SendMessageA(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
12870 hfocus = GetFocus();
12871 ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
12873 SetFocus(hedit2);
12874 hfocus = GetFocus();
12875 ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
12877 check_selection(hedit1, 0, 0);
12878 check_selection(hedit2, 0, 0);
12880 set_selection(hedit2, 0, -1);
12881 check_selection(hedit2, 0, 3);
12883 SetFocus(0);
12884 hfocus = GetFocus();
12885 ok(hfocus == 0, "wrong focus %p\n", hfocus);
12887 flush_sequence();
12888 ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
12889 ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
12890 ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
12892 hfocus = GetFocus();
12893 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
12895 check_selection(hedit1, 0, 5);
12896 check_selection(hedit2, 0, 3);
12898 flush_sequence();
12899 ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
12900 ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
12901 ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
12903 hfocus = GetFocus();
12904 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
12906 check_selection(hedit1, 0, 5);
12907 check_selection(hedit2, 0, 3);
12909 EndDialog(hdlg, 0);
12910 DestroyWindow(hedit1);
12911 DestroyWindow(hedit2);
12912 DestroyWindow(hdlg);
12913 flush_sequence();
12915 #undef set_selection
12916 #undef check_selection
12918 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
12919 cls.lpszClassName = "MyDialogClass";
12920 cls.hInstance = GetModuleHandleA(NULL);
12921 /* need a cast since a dlgproc is used as a wndproc */
12922 cls.lpfnWndProc = test_dlg_proc;
12923 if (!RegisterClassA(&cls)) assert(0);
12925 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
12926 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
12927 ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
12928 EndDialog(hdlg, 0);
12929 DestroyWindow(hdlg);
12930 flush_sequence();
12932 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
12933 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
12934 ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
12935 EndDialog(hdlg, 0);
12936 DestroyWindow(hdlg);
12937 flush_sequence();
12939 hdlg = CreateDialogParamA(0, "FOCUS_TEST_DIALOG_3", 0, test_dlg_proc2, 0);
12940 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
12941 ok_sequence(WmCreateDialogParamSeq_3, "CreateDialogParam_3", TRUE);
12942 EndDialog(hdlg, 0);
12943 DestroyWindow(hdlg);
12944 flush_sequence();
12946 UnregisterClassA( cls.lpszClassName, cls.hInstance );
12947 cls.lpfnWndProc = test_dlg_proc4;
12948 ok( RegisterClassA(&cls), "failed to register class again\n" );
12949 hdlg = CreateDialogParamA(0, "FOCUS_TEST_DIALOG_4", 0, test_dlg_proc3, 0);
12950 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
12951 ok_sequence(WmCreateDialogParamSeq_4, "CreateDialogParam_4", TRUE);
12952 EndDialog(hdlg, 0);
12953 DestroyWindow(hdlg);
12954 flush_sequence();
12956 UnregisterClassA(cls.lpszClassName, cls.hInstance);
12958 parent = CreateWindowExA(0, "TestParentClass", "Test parent",
12959 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
12960 100, 100, 200, 200, 0, 0, 0, NULL);
12961 ok (parent != 0, "Failed to create parent window\n");
12963 /* This child has no parent set. We will later call SetParent on it,
12964 * so that it will have a parent set, but no WS_CHILD style. */
12965 child = CreateWindowExA(0, "TestWindowClass", "Test child",
12966 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
12967 100, 100, 200, 200, 0, 0, 0, NULL);
12968 ok (child != 0, "Failed to create child window\n");
12970 /* This is a regular child window. When used as an owner, the other
12971 * child window will be used. */
12972 child2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2",
12973 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CHILD,
12974 100, 100, 200, 200, child, 0, 0, NULL);
12975 ok (child2 != 0, "Failed to create child window\n");
12977 SetParent(child, parent);
12978 SetFocus(child);
12980 flush_sequence();
12981 DialogBoxA( 0, "TEST_DIALOG", child2, TestModalDlgProc2 );
12982 ok_sequence(WmModalDialogSeq_2, "ModalDialog2", TRUE);
12984 DestroyWindow(child2);
12985 DestroyWindow(child);
12986 DestroyWindow(parent);
12987 flush_sequence();
12990 static void test_enddialog_seq(HWND dialog, HWND owner)
12992 const struct message seq[] = {
12993 { WM_ENABLE, sent },
12994 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
12995 { HCBT_ACTIVATE, hook|wparam, (WPARAM)owner },
12996 { WM_NCACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
12997 { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
12998 /* FIXME: Following two are optional because Wine sends WM_QUERYNEWPALETTE instead of WM_WINDOWPOSCHANGING */
12999 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13000 { WM_QUERYNEWPALETTE, sent|optional },
13001 { WM_NCACTIVATE, sent|wparam|lparam, WA_ACTIVE, (LPARAM)dialog },
13002 { WM_GETTEXT, sent|optional|defwinproc },
13003 { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, (LPARAM)dialog },
13004 { HCBT_SETFOCUS, hook|wparam, (WPARAM)owner },
13005 { WM_KILLFOCUS, sent|wparam, (WPARAM)owner },
13006 { WM_SETFOCUS, sent|defwinproc|wparam, (WPARAM)dialog },
13007 { 0 }
13010 flush_sequence();
13011 EndDialog(dialog, 0);
13012 ok_sequence(seq, "EndDialog", FALSE);
13015 static void test_enddialog_seq2(HWND dialog, HWND owner)
13017 const struct message seq[] = {
13018 { WM_ENABLE, parent|sent },
13019 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13020 { HCBT_ACTIVATE, hook|wparam, (WPARAM)owner },
13021 { WM_NCACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13022 { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13023 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13024 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13025 { HCBT_SETFOCUS, hook|wparam, (WPARAM)owner },
13026 { WM_KILLFOCUS, sent|wparam, (WPARAM)owner },
13027 { WM_SETFOCUS, sent|parent|defwinproc|wparam, (WPARAM)dialog },
13028 { 0 }
13031 flush_sequence();
13032 EndDialog(dialog, 0);
13033 ok_sequence(seq, "EndDialog2", FALSE);
13036 static void test_EndDialog(void)
13038 HWND hparent, hother, hactive, hdlg, hchild;
13039 WNDCLASSA cls;
13041 hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
13042 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
13043 100, 100, 200, 200, 0, 0, 0, NULL);
13044 ok (hparent != 0, "Failed to create parent window\n");
13046 hother = CreateWindowExA(0, "TestParentClass", "Test parent 2",
13047 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13048 200, 100, 200, 200, 0, 0, 0, NULL);
13049 ok (hother != 0, "Failed to create parent window\n");
13051 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
13052 cls.lpszClassName = "MyDialogClass";
13053 cls.hInstance = GetModuleHandleA(NULL);
13054 cls.lpfnWndProc = test_dlg_proc;
13055 if (!RegisterClassA(&cls)) assert(0);
13057 flush_sequence();
13058 SetForegroundWindow(hother);
13059 hactive = GetForegroundWindow();
13060 ok(hother == hactive, "Wrong window has focus (%p != %p)\n", hother, hactive);
13062 /* create a dialog where the parent is disabled, this parent should be
13063 * enabled and receive focus when dialog exits */
13064 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hparent, test_dlg_proc, 0);
13065 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13066 SetForegroundWindow(hdlg);
13067 hactive = GetForegroundWindow();
13068 ok(hdlg == hactive, "Wrong window has focus (%p != %p)\n", hdlg, hactive);
13069 EndDialog(hdlg, 0);
13070 ok(IsWindowEnabled(hparent), "parent is not enabled\n");
13071 hactive = GetForegroundWindow();
13072 ok(hparent == hactive, "Wrong window has focus (parent != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
13073 DestroyWindow(hdlg);
13074 flush_sequence();
13076 /* create a dialog where the parent is disabled and set active window to other window before calling EndDialog */
13077 EnableWindow(hparent, FALSE);
13078 hdlg = CreateWindowExA(0, "TestDialogClass", NULL,
13079 WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
13080 0, 0, 100, 100, hparent, 0, 0, NULL);
13081 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13082 flush_sequence();
13083 SetForegroundWindow(hother);
13084 flush_sequence();
13085 hactive = GetForegroundWindow();
13086 ok(hactive == hother, "Wrong foreground (%p != %p)\n", hactive, hother);
13087 hactive = GetActiveWindow();
13088 ok(hactive == hother, "Wrong active window (%p != %p)\n", hactive, hother);
13089 EndDialog(hdlg, 0);
13090 ok(IsWindowEnabled(hparent), "parent is not enabled\n");
13091 hactive = GetForegroundWindow();
13092 ok(hother == hactive, "Wrong window has focus (other != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
13093 DestroyWindow(hdlg);
13094 flush_sequence();
13096 DestroyWindow( hparent );
13098 hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
13099 WS_POPUP | WS_VISIBLE | WS_DISABLED,
13100 100, 100, 200, 200, 0, 0, 0, NULL);
13101 ok (hparent != 0, "Failed to create parent window\n");
13103 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
13104 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
13105 0, 0, 0, 0, 0, 0, 0, NULL);
13106 ok (hchild != 0, "Failed to create child window\n");
13108 SetParent(hchild, hparent);
13110 flush_sequence();
13111 SetForegroundWindow(hother);
13112 hactive = GetForegroundWindow();
13113 ok(hother == hactive, "Wrong foreground window (%p != %p)\n", hother, hactive);
13115 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hchild, test_dlg_proc, 0);
13116 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13118 SetForegroundWindow(hdlg);
13119 test_enddialog_seq(hdlg, hchild);
13121 hactive = GetForegroundWindow();
13122 ok(hactive == hchild, "Wrong foreground window (active: %p, parent: %p, dlg: %p, other: %p child: %p)\n", hactive, hparent, hdlg, hother, hchild);
13124 DestroyWindow(hdlg);
13126 /* Now set WS_CHILD style flag so that it's a real child and its parent will be dialog's owner. */
13127 SetWindowLongW(hchild, GWL_STYLE, GetWindowLongW(hchild, GWL_STYLE) | WS_CHILD);
13129 SetForegroundWindow(hother);
13130 hactive = GetForegroundWindow();
13131 ok(hother == hactive, "Wrong foreground window (%p != %p)\n", hother, hactive);
13133 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hchild, test_dlg_proc, 0);
13134 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13136 SetForegroundWindow(hdlg);
13137 test_enddialog_seq2(hdlg, hparent);
13139 hactive = GetForegroundWindow();
13140 ok(hactive == hparent, "Wrong foreground window (active: %p, parent: %p, dlg: %p, other: %p child: %p)\n", hactive, hparent, hdlg, hother, hchild);
13141 DestroyWindow(hdlg);
13142 DestroyWindow(hchild);
13143 DestroyWindow(hparent);
13144 DestroyWindow(hother);
13145 flush_sequence();
13147 UnregisterClassA(cls.lpszClassName, cls.hInstance);
13150 static void test_nullCallback(void)
13152 HWND hwnd;
13154 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
13155 100, 100, 200, 200, 0, 0, 0, NULL);
13156 ok (hwnd != 0, "Failed to create overlapped window\n");
13158 SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
13159 flush_events();
13160 DestroyWindow(hwnd);
13163 /* SetActiveWindow( 0 ) hwnd visible */
13164 static const struct message SetActiveWindowSeq0[] =
13166 { HCBT_ACTIVATE, hook|optional },
13167 { WM_NCACTIVATE, sent|wparam, 0 },
13168 { WM_GETTEXT, sent|defwinproc|optional },
13169 { WM_ACTIVATE, sent|wparam, 0 },
13170 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
13171 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
13172 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13173 { WM_KILLFOCUS, sent|optional },
13174 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
13175 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13176 { WM_NCACTIVATE, sent|wparam|optional, 1 },
13177 { WM_GETTEXT, sent|defwinproc|optional },
13178 { WM_ACTIVATE, sent|wparam|optional, 1 },
13179 { HCBT_SETFOCUS, hook|optional },
13180 { WM_KILLFOCUS, sent|defwinproc|optional },
13181 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
13182 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
13183 { WM_IME_SETCONTEXT, sent|optional },
13184 { WM_IME_SETCONTEXT, sent|optional },
13185 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
13186 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13187 { WM_SETFOCUS, sent|defwinproc|optional },
13188 { WM_GETTEXT, sent|optional },
13189 { 0 }
13191 /* SetActiveWindow( hwnd ) hwnd visible */
13192 static const struct message SetActiveWindowSeq1[] =
13194 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13195 { 0 }
13197 /* SetActiveWindow( popup ) hwnd visible, popup visible */
13198 static const struct message SetActiveWindowSeq2[] =
13200 { HCBT_ACTIVATE, hook },
13201 { WM_NCACTIVATE, sent|wparam, 0 },
13202 { WM_GETTEXT, sent|defwinproc|optional },
13203 { WM_ACTIVATE, sent|wparam, 0 },
13204 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13205 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13206 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
13207 { WM_NCPAINT, sent|optional },
13208 { WM_GETTEXT, sent|defwinproc|optional },
13209 { WM_ERASEBKGND, sent|optional },
13210 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13211 { WM_NCACTIVATE, sent|wparam, 1 },
13212 { WM_GETTEXT, sent|defwinproc|optional },
13213 { WM_ACTIVATE, sent|wparam, 1 },
13214 { HCBT_SETFOCUS, hook },
13215 { WM_KILLFOCUS, sent|defwinproc },
13216 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
13217 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
13218 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
13219 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13220 { WM_SETFOCUS, sent|defwinproc },
13221 { WM_GETTEXT, sent|optional },
13222 { 0 }
13225 /* SetActiveWindow( hwnd ) hwnd not visible */
13226 static const struct message SetActiveWindowSeq3[] =
13228 { HCBT_ACTIVATE, hook },
13229 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13230 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
13231 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
13232 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13233 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13234 { WM_ACTIVATEAPP, sent|wparam, 1 },
13235 { WM_ACTIVATEAPP, sent|wparam, 1 },
13236 { WM_NCACTIVATE, sent|wparam, 1 },
13237 { WM_ACTIVATE, sent|wparam, 1 },
13238 { HCBT_SETFOCUS, hook },
13239 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
13240 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13241 { WM_SETFOCUS, sent|defwinproc },
13242 { 0 }
13244 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
13245 static const struct message SetActiveWindowSeq4[] =
13247 { HCBT_ACTIVATE, hook },
13248 { WM_NCACTIVATE, sent|wparam, 0 },
13249 { WM_GETTEXT, sent|defwinproc|optional },
13250 { WM_ACTIVATE, sent|wparam, 0 },
13251 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13252 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
13253 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
13254 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13255 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13256 { WM_NCACTIVATE, sent|wparam, 1 },
13257 { WM_GETTEXT, sent|defwinproc|optional },
13258 { WM_ACTIVATE, sent|wparam, 1 },
13259 { HCBT_SETFOCUS, hook },
13260 { WM_KILLFOCUS, sent|defwinproc },
13261 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
13262 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
13263 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
13264 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13265 { WM_SETFOCUS, sent|defwinproc },
13266 { 0 }
13270 static void test_SetActiveWindow(void)
13272 HWND hwnd, popup, ret;
13274 hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
13275 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13276 100, 100, 200, 200, 0, 0, 0, NULL);
13278 popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
13279 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
13280 100, 100, 200, 200, hwnd, 0, 0, NULL);
13282 ok(hwnd != 0, "Failed to create overlapped window\n");
13283 ok(popup != 0, "Failed to create popup window\n");
13284 SetForegroundWindow( popup );
13285 flush_sequence();
13287 trace("SetActiveWindow(0)\n");
13288 ret = SetActiveWindow(0);
13289 ok( ret == popup, "Failed to SetActiveWindow(0)\n");
13290 ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", FALSE);
13291 flush_sequence();
13293 trace("SetActiveWindow(hwnd), hwnd visible\n");
13294 ret = SetActiveWindow(hwnd);
13295 if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
13296 flush_sequence();
13298 trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
13299 ret = SetActiveWindow(popup);
13300 ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
13301 ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
13302 flush_sequence();
13304 ShowWindow(hwnd, SW_HIDE);
13305 ShowWindow(popup, SW_HIDE);
13306 flush_sequence();
13308 trace("SetActiveWindow(hwnd), hwnd not visible\n");
13309 ret = SetActiveWindow(hwnd);
13310 ok( ret == NULL, "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret );
13311 ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
13312 flush_sequence();
13314 trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
13315 ret = SetActiveWindow(popup);
13316 ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
13317 ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
13318 flush_sequence();
13320 trace("done\n");
13322 DestroyWindow(hwnd);
13325 static const struct message SetForegroundWindowSeq[] =
13327 { WM_NCACTIVATE, sent|wparam, 0 },
13328 { WM_GETTEXT, sent|defwinproc|optional },
13329 { WM_ACTIVATE, sent|wparam, 0 },
13330 { WM_ACTIVATEAPP, sent|wparam, 0 },
13331 { WM_KILLFOCUS, sent },
13332 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
13333 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
13334 { 0 }
13337 static void test_SetForegroundWindow(void)
13339 HWND hwnd;
13341 hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
13342 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13343 100, 100, 200, 200, 0, 0, 0, NULL);
13344 ok (hwnd != 0, "Failed to create overlapped window\n");
13345 SetForegroundWindow( hwnd );
13346 flush_sequence();
13348 trace("SetForegroundWindow( 0 )\n");
13349 SetForegroundWindow( 0 );
13350 ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
13351 trace("SetForegroundWindow( GetDesktopWindow() )\n");
13352 SetForegroundWindow( GetDesktopWindow() );
13353 ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
13354 "foreground top level window", FALSE);
13355 trace("done\n");
13357 DestroyWindow(hwnd);
13360 static DWORD get_input_codepage( void )
13362 DWORD cp;
13363 int ret;
13364 HKL hkl = GetKeyboardLayout( 0 );
13366 ret = GetLocaleInfoW( LOWORD(hkl), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
13367 (WCHAR *)&cp, sizeof(cp) / sizeof(WCHAR) );
13368 if (!ret) cp = CP_ACP;
13369 return cp;
13372 static void test_dbcs_wm_char(void)
13374 BYTE dbch[2];
13375 WCHAR wch, bad_wch;
13376 HWND hwnd, hwnd2;
13377 MSG msg;
13378 DWORD time;
13379 POINT pt;
13380 DWORD_PTR res;
13381 CPINFOEXA cpinfo;
13382 UINT i, j, k;
13383 struct message wmCharSeq[2];
13384 BOOL ret;
13385 DWORD cp = get_input_codepage();
13387 if (!pGetCPInfoExA)
13389 win_skip("GetCPInfoExA is not available\n");
13390 return;
13393 pGetCPInfoExA( cp, 0, &cpinfo );
13394 if (cpinfo.MaxCharSize != 2)
13396 skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
13397 return;
13400 dbch[0] = dbch[1] = 0;
13401 wch = 0;
13402 bad_wch = cpinfo.UnicodeDefaultChar;
13403 for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
13404 for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
13405 for (k = 128; k <= 255; k++)
13407 char str[2];
13408 WCHAR wstr[2];
13409 str[0] = j;
13410 str[1] = k;
13411 if (MultiByteToWideChar( cp, 0, str, 2, wstr, 2 ) == 1 &&
13412 WideCharToMultiByte( cp, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
13413 (BYTE)str[0] == j && (BYTE)str[1] == k &&
13414 HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
13416 dbch[0] = j;
13417 dbch[1] = k;
13418 wch = wstr[0];
13419 break;
13423 if (!wch)
13425 skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
13426 return;
13428 trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
13429 dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
13431 hwnd = CreateWindowExW(0, testWindowClassW, NULL,
13432 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
13433 hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
13434 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
13435 ok (hwnd != 0, "Failed to create overlapped window\n");
13436 ok (hwnd2 != 0, "Failed to create overlapped window\n");
13437 flush_sequence();
13439 memset( wmCharSeq, 0, sizeof(wmCharSeq) );
13440 wmCharSeq[0].message = WM_CHAR;
13441 wmCharSeq[0].flags = sent|wparam;
13442 wmCharSeq[0].wParam = wch;
13444 /* posted message */
13445 PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
13446 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13447 ok( !ret, "got message %x\n", msg.message );
13448 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
13449 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13450 ok( ret, "no message\n" );
13451 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13452 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
13453 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13454 ok( !ret, "got message %x\n", msg.message );
13456 /* posted thread message */
13457 PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
13458 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13459 ok( !ret, "got message %x\n", msg.message );
13460 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
13461 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13462 ok( ret, "no message\n" );
13463 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13464 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
13465 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13466 ok( !ret, "got message %x\n", msg.message );
13468 /* sent message */
13469 flush_sequence();
13470 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
13471 ok_sequence( WmEmptySeq, "no messages", FALSE );
13472 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
13473 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13474 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13475 ok( !ret, "got message %x\n", msg.message );
13477 /* sent message with timeout */
13478 flush_sequence();
13479 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
13480 ok_sequence( WmEmptySeq, "no messages", FALSE );
13481 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
13482 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13483 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13484 ok( !ret, "got message %x\n", msg.message );
13486 /* sent message with timeout and callback */
13487 flush_sequence();
13488 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
13489 ok_sequence( WmEmptySeq, "no messages", FALSE );
13490 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
13491 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13492 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13493 ok( !ret, "got message %x\n", msg.message );
13495 /* sent message with callback */
13496 flush_sequence();
13497 SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
13498 ok_sequence( WmEmptySeq, "no messages", FALSE );
13499 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
13500 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13501 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13502 ok( !ret, "got message %x\n", msg.message );
13504 /* direct window proc call */
13505 flush_sequence();
13506 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
13507 ok_sequence( WmEmptySeq, "no messages", FALSE );
13508 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
13509 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13511 /* dispatch message */
13512 msg.hwnd = hwnd;
13513 msg.message = WM_CHAR;
13514 msg.wParam = dbch[0];
13515 msg.lParam = 0;
13516 DispatchMessageA( &msg );
13517 ok_sequence( WmEmptySeq, "no messages", FALSE );
13518 msg.wParam = dbch[1];
13519 DispatchMessageA( &msg );
13520 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13522 /* window handle is irrelevant */
13523 flush_sequence();
13524 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
13525 ok_sequence( WmEmptySeq, "no messages", FALSE );
13526 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
13527 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13528 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13529 ok( !ret, "got message %x\n", msg.message );
13531 /* interleaved post and send */
13532 flush_sequence();
13533 PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
13534 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
13535 ok_sequence( WmEmptySeq, "no messages", FALSE );
13536 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13537 ok( !ret, "got message %x\n", msg.message );
13538 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
13539 ok_sequence( WmEmptySeq, "no messages", FALSE );
13540 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13541 ok( ret, "no message\n" );
13542 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13543 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
13544 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13545 ok( !ret, "got message %x\n", msg.message );
13546 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
13547 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13548 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13549 ok( !ret, "got message %x\n", msg.message );
13551 /* interleaved sent message and winproc */
13552 flush_sequence();
13553 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
13554 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
13555 ok_sequence( WmEmptySeq, "no messages", FALSE );
13556 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
13557 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13558 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
13559 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13561 /* interleaved winproc and dispatch */
13562 msg.hwnd = hwnd;
13563 msg.message = WM_CHAR;
13564 msg.wParam = dbch[0];
13565 msg.lParam = 0;
13566 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
13567 DispatchMessageA( &msg );
13568 ok_sequence( WmEmptySeq, "no messages", FALSE );
13569 msg.wParam = dbch[1];
13570 DispatchMessageA( &msg );
13571 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13572 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
13573 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13575 /* interleaved sends */
13576 flush_sequence();
13577 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
13578 SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
13579 ok_sequence( WmEmptySeq, "no messages", FALSE );
13580 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
13581 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13582 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
13583 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13585 /* dbcs WM_CHAR */
13586 flush_sequence();
13587 SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
13588 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
13589 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13590 ok( !ret, "got message %x\n", msg.message );
13592 /* other char messages are not magic */
13593 PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
13594 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13595 ok( ret, "no message\n" );
13596 ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
13597 ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
13598 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13599 ok( !ret, "got message %x\n", msg.message );
13600 PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
13601 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13602 ok( ret, "no message\n" );
13603 ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
13604 ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
13605 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
13606 ok( !ret, "got message %x\n", msg.message );
13608 /* test retrieving messages */
13610 PostMessageW( hwnd, WM_CHAR, wch, 0 );
13611 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
13612 ok( ret, "no message\n" );
13613 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
13614 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13615 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
13616 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
13617 ok( ret, "no message\n" );
13618 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
13619 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13620 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
13621 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
13622 ok( !ret, "got message %x\n", msg.message );
13624 /* message filters */
13625 PostMessageW( hwnd, WM_CHAR, wch, 0 );
13626 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
13627 ok( ret, "no message\n" );
13628 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
13629 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13630 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
13631 /* message id is filtered, hwnd is not */
13632 ret = PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE );
13633 ok( !ret, "no message\n" );
13634 ret = PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE );
13635 ok( ret, "no message\n" );
13636 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
13637 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13638 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
13639 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
13640 ok( !ret, "got message %x\n", msg.message );
13642 /* mixing GetMessage and PostMessage */
13643 PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
13644 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
13645 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
13646 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13647 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
13648 ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
13649 time = msg.time;
13650 pt = msg.pt;
13651 ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
13652 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
13653 ok( ret, "no message\n" );
13654 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
13655 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13656 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
13657 ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
13658 ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
13659 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 );
13660 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
13661 ok( !ret, "got message %x\n", msg.message );
13663 /* without PM_REMOVE */
13664 PostMessageW( hwnd, WM_CHAR, wch, 0 );
13665 ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
13666 ok( ret, "no message\n" );
13667 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
13668 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13669 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
13670 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
13671 ok( ret, "no message\n" );
13672 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
13673 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13674 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
13675 ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
13676 ok( ret, "no message\n" );
13677 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
13678 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13679 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
13680 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
13681 ok( ret, "no message\n" );
13682 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
13683 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13684 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
13685 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
13686 ok( !ret, "got message %x\n", msg.message );
13688 DestroyWindow(hwnd);
13689 DestroyWindow(hwnd2);
13692 static void test_unicode_wm_char(void)
13694 HWND hwnd;
13695 MSG msg;
13696 struct message seq[2];
13697 HKL hkl_orig, hkl_greek;
13698 DWORD cp;
13699 LCID thread_locale;
13701 hkl_orig = GetKeyboardLayout( 0 );
13702 GetLocaleInfoW( LOWORD( hkl_orig ), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, (WCHAR*)&cp, sizeof(cp) / sizeof(WCHAR) );
13703 if (cp != 1252)
13705 skip( "Default codepage %d\n", cp );
13706 return;
13709 hkl_greek = LoadKeyboardLayoutA( "00000408", 0 );
13710 if (!hkl_greek || hkl_greek == hkl_orig /* win2k */)
13712 skip( "Unable to load Greek keyboard layout\n" );
13713 return;
13716 hwnd = CreateWindowExW( 0, testWindowClassW, NULL, WS_OVERLAPPEDWINDOW,
13717 100, 100, 200, 200, 0, 0, 0, NULL );
13718 flush_sequence();
13720 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
13722 while (GetMessageW( &msg, hwnd, 0, 0 ))
13724 if (!ignore_message( msg.message )) break;
13727 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
13728 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13729 ok( msg.wParam == 0x3b1, "bad wparam %lx\n", msg.wParam );
13730 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
13732 DispatchMessageW( &msg );
13734 memset( seq, 0, sizeof(seq) );
13735 seq[0].message = WM_CHAR;
13736 seq[0].flags = sent|wparam;
13737 seq[0].wParam = 0x3b1;
13739 ok_sequence( seq, "unicode WM_CHAR", FALSE );
13741 flush_sequence();
13743 /* greek alpha -> 'a' in cp1252 */
13744 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
13746 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
13747 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
13748 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13749 ok( msg.wParam == 0x61, "bad wparam %lx\n", msg.wParam );
13750 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
13752 DispatchMessageA( &msg );
13754 seq[0].wParam = 0x61;
13755 ok_sequence( seq, "unicode WM_CHAR", FALSE );
13757 thread_locale = GetThreadLocale();
13758 ActivateKeyboardLayout( hkl_greek, 0 );
13759 ok( GetThreadLocale() == thread_locale, "locale changed from %08x to %08x\n",
13760 thread_locale, GetThreadLocale() );
13762 flush_sequence();
13764 /* greek alpha -> 0xe1 in cp1253 */
13765 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
13767 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
13768 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
13769 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
13770 ok( msg.wParam == 0xe1, "bad wparam %lx\n", msg.wParam );
13771 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
13773 DispatchMessageA( &msg );
13775 seq[0].wParam = 0x3b1;
13776 ok_sequence( seq, "unicode WM_CHAR", FALSE );
13778 DestroyWindow( hwnd );
13779 ActivateKeyboardLayout( hkl_orig, 0 );
13780 UnloadKeyboardLayout( hkl_greek );
13783 #define ID_LISTBOX 0x000f
13785 static const struct message wm_lb_setcursel_0[] =
13787 { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
13788 { WM_CTLCOLORLISTBOX, sent|parent },
13789 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
13790 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
13791 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
13792 { 0 }
13794 static const struct message wm_lb_setcursel_1[] =
13796 { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
13797 { WM_CTLCOLORLISTBOX, sent|parent },
13798 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
13799 { WM_CTLCOLORLISTBOX, sent|parent },
13800 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
13801 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
13802 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
13803 { 0 }
13805 static const struct message wm_lb_setcursel_2[] =
13807 { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
13808 { WM_CTLCOLORLISTBOX, sent|parent },
13809 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
13810 { WM_CTLCOLORLISTBOX, sent|parent },
13811 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
13812 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
13813 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
13814 { 0 }
13816 static const struct message wm_lb_click_0[] =
13818 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
13819 { HCBT_SETFOCUS, hook },
13820 { WM_KILLFOCUS, sent|parent },
13821 { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
13822 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
13823 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
13824 { WM_SETFOCUS, sent|defwinproc },
13826 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
13827 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
13828 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
13829 { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
13830 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
13832 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
13833 { WM_CTLCOLORLISTBOX, sent|parent },
13834 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
13835 { WM_CTLCOLORLISTBOX, sent|parent },
13836 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
13837 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
13839 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
13840 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
13842 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
13843 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
13844 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
13845 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
13846 { 0 }
13848 static const struct message wm_lb_deletestring[] =
13850 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
13851 { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
13852 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
13853 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
13854 { 0 }
13856 static const struct message wm_lb_deletestring_reset[] =
13858 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
13859 { LB_RESETCONTENT, sent|wparam|lparam|defwinproc|optional, 0, 0 },
13860 { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
13861 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
13862 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
13863 { 0 }
13866 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
13868 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
13870 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
13872 static LONG defwndproc_counter = 0;
13873 LRESULT ret;
13874 struct recvd_message msg;
13876 /* do not log painting messages */
13877 if (message != WM_PAINT &&
13878 message != WM_NCPAINT &&
13879 message != WM_SYNCPAINT &&
13880 message != WM_ERASEBKGND &&
13881 message != WM_NCHITTEST &&
13882 message != WM_GETTEXT &&
13883 !ignore_message( message ))
13885 msg.hwnd = hwnd;
13886 msg.message = message;
13887 msg.flags = sent|wparam|lparam;
13888 if (defwndproc_counter) msg.flags |= defwinproc;
13889 msg.wParam = wp;
13890 msg.lParam = lp;
13891 msg.descr = "listbox";
13892 add_message(&msg);
13895 defwndproc_counter++;
13896 ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
13897 defwndproc_counter--;
13899 return ret;
13902 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
13903 int caret_index, int top_index, int line)
13905 LRESULT ret;
13907 /* calling an orig proc helps to avoid unnecessary message logging */
13908 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
13909 ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
13910 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
13911 ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
13912 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
13913 ok_(__FILE__, line)(ret == caret_index ||
13914 broken(cur_sel == -1 && caret_index == 0 && ret == -1), /* nt4 */
13915 "expected caret index %d, got %ld\n", caret_index, ret);
13916 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
13917 ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
13920 static void test_listbox_messages(void)
13922 HWND parent, listbox;
13923 LRESULT ret;
13925 parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13926 100, 100, 200, 200, 0, 0, 0, NULL);
13927 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
13928 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
13929 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
13930 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
13932 check_lb_state(listbox, 0, LB_ERR, 0, 0);
13934 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
13935 ok(ret == 0, "expected 0, got %ld\n", ret);
13936 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
13937 ok(ret == 1, "expected 1, got %ld\n", ret);
13938 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
13939 ok(ret == 2, "expected 2, got %ld\n", ret);
13941 check_lb_state(listbox, 3, LB_ERR, 0, 0);
13943 flush_sequence();
13945 log_all_parent_messages++;
13947 trace("selecting item 0\n");
13948 ret = SendMessageA(listbox, LB_SETCURSEL, 0, 0);
13949 ok(ret == 0, "expected 0, got %ld\n", ret);
13950 ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
13951 check_lb_state(listbox, 3, 0, 0, 0);
13952 flush_sequence();
13954 trace("selecting item 1\n");
13955 ret = SendMessageA(listbox, LB_SETCURSEL, 1, 0);
13956 ok(ret == 1, "expected 1, got %ld\n", ret);
13957 ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
13958 check_lb_state(listbox, 3, 1, 1, 0);
13960 trace("selecting item 2\n");
13961 ret = SendMessageA(listbox, LB_SETCURSEL, 2, 0);
13962 ok(ret == 2, "expected 2, got %ld\n", ret);
13963 ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
13964 check_lb_state(listbox, 3, 2, 2, 0);
13966 trace("clicking on item 0\n");
13967 ret = SendMessageA(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
13968 ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
13969 ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0);
13970 ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
13971 ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
13972 check_lb_state(listbox, 3, 0, 0, 0);
13973 flush_sequence();
13975 trace("deleting item 0\n");
13976 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
13977 ok(ret == 2, "expected 2, got %ld\n", ret);
13978 ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
13979 check_lb_state(listbox, 2, -1, 0, 0);
13980 flush_sequence();
13982 trace("deleting item 0\n");
13983 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
13984 ok(ret == 1, "expected 1, got %ld\n", ret);
13985 ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
13986 check_lb_state(listbox, 1, -1, 0, 0);
13987 flush_sequence();
13989 trace("deleting item 0\n");
13990 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
13991 ok(ret == 0, "expected 0, got %ld\n", ret);
13992 ok_sequence(wm_lb_deletestring_reset, "LB_DELETESTRING 0", FALSE );
13993 check_lb_state(listbox, 0, -1, 0, 0);
13994 flush_sequence();
13996 trace("deleting item 0\n");
13997 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
13998 ok(ret == LB_ERR, "expected LB_ERR, got %ld\n", ret);
13999 check_lb_state(listbox, 0, -1, 0, 0);
14000 flush_sequence();
14002 log_all_parent_messages--;
14004 DestroyWindow(listbox);
14005 DestroyWindow(parent);
14008 /*************************** Menu test ******************************/
14009 static const struct message wm_popup_menu_1[] =
14011 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
14012 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
14013 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
14014 { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
14015 { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
14016 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
14017 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
14018 { WM_INITMENU, sent|lparam, 0, 0 },
14019 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
14020 { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
14021 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
14022 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
14023 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
14024 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
14025 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001, 0, 0x40000000 },
14026 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
14027 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14028 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
14029 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
14030 { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
14031 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
14032 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
14033 { 0 }
14035 static const struct message wm_popup_menu_2[] =
14037 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
14038 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
14039 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
14040 { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
14041 { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
14042 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
14043 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
14044 { WM_INITMENU, sent|lparam, 0, 0 },
14045 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
14046 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
14047 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
14048 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
14049 { HCBT_CREATEWND, hook },
14050 { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
14051 |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
14052 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
14053 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
14054 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
14055 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
14056 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
14057 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
14058 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
14059 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
14060 { HCBT_DESTROYWND, hook },
14061 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14062 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
14063 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14064 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
14065 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
14066 { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
14067 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
14068 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
14069 { 0 }
14071 static const struct message wm_popup_menu_3[] =
14073 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
14074 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
14075 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
14076 { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
14077 { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
14078 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
14079 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
14080 { WM_INITMENU, sent|lparam, 0, 0 },
14081 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
14082 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
14083 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
14084 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
14085 { HCBT_CREATEWND, hook },
14086 { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
14087 |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
14088 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
14089 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
14090 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
14091 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
14092 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
14093 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
14094 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
14095 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
14096 { HCBT_DESTROYWND, hook },
14097 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14098 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
14099 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14100 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
14101 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
14102 { WM_COMMAND, sent|wparam|lparam, 100, 0 },
14103 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
14104 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
14105 { 0 }
14108 static const struct message wm_single_menu_item[] =
14110 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
14111 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
14112 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0x20000001 },
14113 { WM_SYSKEYDOWN, sent|wparam|lparam, 'Q', 0x20000001 },
14114 { WM_SYSCHAR, sent|wparam|lparam, 'q', 0x20000001 },
14115 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'q' },
14116 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
14117 { WM_INITMENU, sent|lparam, 0, 0 },
14118 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(300,MF_HILITE) },
14119 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
14120 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
14121 { WM_MENUCOMMAND, sent },
14122 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0xe0000001 },
14123 { WM_SYSKEYUP, sent|wparam|lparam, 'Q', 0xe0000001 },
14124 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 },
14125 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
14127 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 1 },
14128 { WM_KEYDOWN, sent|wparam|lparam, VK_ESCAPE, 1 },
14129 { WM_CHAR, sent|wparam|lparam, VK_ESCAPE, 0x00000001 },
14130 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 },
14131 { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
14132 { 0 }
14135 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
14137 if (message == WM_ENTERIDLE ||
14138 message == WM_INITMENU ||
14139 message == WM_INITMENUPOPUP ||
14140 message == WM_MENUSELECT ||
14141 message == WM_PARENTNOTIFY ||
14142 message == WM_ENTERMENULOOP ||
14143 message == WM_EXITMENULOOP ||
14144 message == WM_UNINITMENUPOPUP ||
14145 message == WM_KEYDOWN ||
14146 message == WM_KEYUP ||
14147 message == WM_CHAR ||
14148 message == WM_SYSKEYDOWN ||
14149 message == WM_SYSKEYUP ||
14150 message == WM_SYSCHAR ||
14151 message == WM_COMMAND ||
14152 message == WM_MENUCOMMAND)
14154 struct recvd_message msg;
14156 msg.hwnd = hwnd;
14157 msg.message = message;
14158 msg.flags = sent|wparam|lparam;
14159 msg.wParam = wp;
14160 msg.lParam = lp;
14161 msg.descr = "parent_menu_proc";
14162 add_message(&msg);
14165 return DefWindowProcA(hwnd, message, wp, lp);
14168 static void set_menu_style(HMENU hmenu, DWORD style)
14170 MENUINFO mi;
14171 BOOL ret;
14173 mi.cbSize = sizeof(mi);
14174 mi.fMask = MIM_STYLE;
14175 mi.dwStyle = style;
14176 SetLastError(0xdeadbeef);
14177 ret = pSetMenuInfo(hmenu, &mi);
14178 ok(ret, "SetMenuInfo error %u\n", GetLastError());
14181 static DWORD get_menu_style(HMENU hmenu)
14183 MENUINFO mi;
14184 BOOL ret;
14186 mi.cbSize = sizeof(mi);
14187 mi.fMask = MIM_STYLE;
14188 mi.dwStyle = 0;
14189 SetLastError(0xdeadbeef);
14190 ret = pGetMenuInfo(hmenu, &mi);
14191 ok(ret, "GetMenuInfo error %u\n", GetLastError());
14193 return mi.dwStyle;
14196 static void test_menu_messages(void)
14198 MSG msg;
14199 WNDCLASSA cls;
14200 HMENU hmenu, hmenu_popup;
14201 HWND hwnd;
14202 DWORD style;
14204 if (!pGetMenuInfo || !pSetMenuInfo)
14206 win_skip("GetMenuInfo and/or SetMenuInfo are not available\n");
14207 return;
14209 cls.style = 0;
14210 cls.lpfnWndProc = parent_menu_proc;
14211 cls.cbClsExtra = 0;
14212 cls.cbWndExtra = 0;
14213 cls.hInstance = GetModuleHandleA(0);
14214 cls.hIcon = 0;
14215 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
14216 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
14217 cls.lpszMenuName = NULL;
14218 cls.lpszClassName = "TestMenuClass";
14219 UnregisterClassA(cls.lpszClassName, cls.hInstance);
14220 if (!RegisterClassA(&cls)) assert(0);
14222 SetLastError(0xdeadbeef);
14223 hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14224 100, 100, 200, 200, 0, 0, 0, NULL);
14225 ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError());
14227 SetLastError(0xdeadbeef);
14228 hmenu = LoadMenuA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
14229 ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError());
14231 SetMenu(hwnd, hmenu);
14232 SetForegroundWindow( hwnd );
14233 flush_events();
14235 set_menu_style(hmenu, MNS_NOTIFYBYPOS);
14236 style = get_menu_style(hmenu);
14237 ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
14239 hmenu_popup = GetSubMenu(hmenu, 0);
14240 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
14241 style = get_menu_style(hmenu_popup);
14242 ok(style == 0, "expected 0, got %u\n", style);
14244 hmenu_popup = GetSubMenu(hmenu_popup, 0);
14245 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
14246 style = get_menu_style(hmenu_popup);
14247 ok(style == 0, "expected 0, got %u\n", style);
14249 /* Alt+E, Enter */
14250 trace("testing a popup menu command\n");
14251 flush_sequence();
14252 keybd_event(VK_MENU, 0, 0, 0);
14253 keybd_event('E', 0, 0, 0);
14254 keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
14255 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
14256 keybd_event(VK_RETURN, 0, 0, 0);
14257 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
14258 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
14260 TranslateMessage(&msg);
14261 DispatchMessageA(&msg);
14263 if (!sequence_cnt) /* we didn't get any message */
14265 skip( "queuing key events not supported\n" );
14266 goto done;
14268 /* win98 queues only a WM_KEYUP and doesn't start menu tracking */
14269 if (sequence[0].message == WM_KEYUP && sequence[0].wParam == VK_MENU)
14271 win_skip( "menu tracking through VK_MENU not supported\n" );
14272 goto done;
14274 ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
14276 /* Alt+F, Right, Enter */
14277 trace("testing submenu of a popup menu command\n");
14278 flush_sequence();
14279 keybd_event(VK_MENU, 0, 0, 0);
14280 keybd_event('F', 0, 0, 0);
14281 keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
14282 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
14283 keybd_event(VK_RIGHT, 0, 0, 0);
14284 keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
14285 keybd_event(VK_RETURN, 0, 0, 0);
14286 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
14287 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
14289 TranslateMessage(&msg);
14290 DispatchMessageA(&msg);
14292 ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
14294 trace("testing single menu item command\n");
14295 flush_sequence();
14296 keybd_event(VK_MENU, 0, 0, 0);
14297 keybd_event('Q', 0, 0, 0);
14298 keybd_event('Q', 0, KEYEVENTF_KEYUP, 0);
14299 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
14300 keybd_event(VK_ESCAPE, 0, 0, 0);
14301 keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
14302 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
14304 TranslateMessage(&msg);
14305 DispatchMessageA(&msg);
14307 ok_sequence(wm_single_menu_item, "single menu item command", FALSE);
14309 set_menu_style(hmenu, 0);
14310 style = get_menu_style(hmenu);
14311 ok(style == 0, "expected 0, got %u\n", style);
14313 hmenu_popup = GetSubMenu(hmenu, 0);
14314 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
14315 set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
14316 style = get_menu_style(hmenu_popup);
14317 ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
14319 hmenu_popup = GetSubMenu(hmenu_popup, 0);
14320 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
14321 style = get_menu_style(hmenu_popup);
14322 ok(style == 0, "expected 0, got %u\n", style);
14324 /* Alt+F, Right, Enter */
14325 trace("testing submenu of a popup menu command\n");
14326 flush_sequence();
14327 keybd_event(VK_MENU, 0, 0, 0);
14328 keybd_event('F', 0, 0, 0);
14329 keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
14330 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
14331 keybd_event(VK_RIGHT, 0, 0, 0);
14332 keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
14333 keybd_event(VK_RETURN, 0, 0, 0);
14334 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
14335 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
14337 TranslateMessage(&msg);
14338 DispatchMessageA(&msg);
14340 ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
14342 done:
14343 DestroyWindow(hwnd);
14344 DestroyMenu(hmenu);
14348 static void test_paintingloop(void)
14350 HWND hwnd;
14352 paint_loop_done = FALSE;
14353 hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
14354 "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
14355 100, 100, 100, 100, 0, 0, 0, NULL );
14356 ok(hwnd != 0, "PaintLoop window error %u\n", GetLastError());
14357 ShowWindow(hwnd,SW_NORMAL);
14358 SetFocus(hwnd);
14360 while (!paint_loop_done)
14362 MSG msg;
14363 if (PeekMessageA(&msg, 0, 0, 0, 1))
14365 TranslateMessage(&msg);
14366 DispatchMessageA(&msg);
14369 DestroyWindow(hwnd);
14372 static const struct message NCRBUTTONDOWNSeq[] =
14374 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
14375 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
14376 { WM_CAPTURECHANGED, sent },
14377 { WM_CONTEXTMENU, sent, /*hwnd*/0, -1 },
14378 { 0 }
14381 struct rbuttonup_thread_data
14383 HWND hwnd;
14384 HANDLE wndproc_finished;
14387 static DWORD CALLBACK post_rbuttonup_msg( void *arg )
14389 struct rbuttonup_thread_data *data = arg;
14390 DWORD ret;
14392 ret = WaitForSingleObject( data->wndproc_finished, 500 );
14393 todo_wine ok( ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", ret );
14394 if( ret == WAIT_OBJECT_0 ) return 0;
14396 PostMessageA( data->hwnd, WM_RBUTTONUP, 0, 0 );
14397 return 0;
14400 static void test_defwinproc(void)
14402 HWND hwnd;
14403 MSG msg;
14404 BOOL gotwmquit = FALSE;
14405 POINT pos;
14406 RECT rect;
14407 INT x, y;
14408 LRESULT res;
14409 struct rbuttonup_thread_data data;
14410 HANDLE thread;
14412 hwnd = CreateWindowExA(0, "TestWindowClass", "test_defwndproc",
14413 WS_VISIBLE | WS_CAPTION | WS_OVERLAPPEDWINDOW, 0,0,500,100,0,0,0, NULL);
14414 assert(hwnd);
14415 flush_events();
14417 GetCursorPos(&pos);
14418 GetWindowRect(hwnd, &rect);
14419 x = (rect.left+rect.right) / 2;
14420 y = rect.top + GetSystemMetrics(SM_CYFRAME) + 1;
14421 SetCursorPos(x, y);
14422 flush_events();
14423 res = DefWindowProcA( hwnd, WM_NCHITTEST, 0, MAKELPARAM(x, y));
14424 ok(res == HTCAPTION, "WM_NCHITTEST returned %ld\n", res);
14426 mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 );
14427 mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 );
14428 flush_events();
14430 flush_sequence();
14431 mouse_event( MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0 );
14432 /* workaround for missing support for clicking on window frame */
14433 data.hwnd = hwnd;
14434 data.wndproc_finished = CreateEventA( NULL, FALSE, FALSE, NULL );
14435 thread = CreateThread( NULL, 0, post_rbuttonup_msg, (void*)&data, 0, NULL );
14437 DefWindowProcA( hwnd, WM_NCRBUTTONDOWN, HTCAPTION, MAKELPARAM(x, y));
14438 ok_sequence(NCRBUTTONDOWNSeq, "WM_NCRBUTTONDOWN on caption", FALSE);
14440 SetEvent( data.wndproc_finished );
14441 WaitForSingleObject( thread, 1000 );
14442 CloseHandle( data.wndproc_finished );
14443 CloseHandle( thread );
14445 SetCursorPos(pos.x, pos.y);
14447 DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0);
14448 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) {
14449 if( msg.message == WM_QUIT) gotwmquit = TRUE;
14450 DispatchMessageA( &msg );
14452 ok(!gotwmquit, "Unexpected WM_QUIT message!\n");
14453 DestroyWindow( hwnd);
14456 #define clear_clipboard(hwnd) clear_clipboard_(__LINE__, (hwnd))
14457 static void clear_clipboard_(int line, HWND hWnd)
14459 BOOL succ;
14460 succ = OpenClipboard(hWnd);
14461 ok_(__FILE__, line)(succ, "OpenClipboard failed, err=%u\n", GetLastError());
14462 succ = EmptyClipboard();
14463 ok_(__FILE__, line)(succ, "EmptyClipboard failed, err=%u\n", GetLastError());
14464 succ = CloseClipboard();
14465 ok_(__FILE__, line)(succ, "CloseClipboard failed, err=%u\n", GetLastError());
14468 #define expect_HWND(expected, got) expect_HWND_(__LINE__, (expected), (got))
14469 static void expect_HWND_(int line, HWND expected, HWND got)
14471 ok_(__FILE__, line)(got==expected, "Expected %p, got %p\n", expected, got);
14474 static WNDPROC pOldViewerProc;
14476 static LRESULT CALLBACK recursive_viewer_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
14478 static BOOL recursion_guard;
14480 if (message == WM_DRAWCLIPBOARD && !recursion_guard)
14482 recursion_guard = TRUE;
14483 clear_clipboard(hWnd);
14484 recursion_guard = FALSE;
14486 return CallWindowProcA(pOldViewerProc, hWnd, message, wParam, lParam);
14489 static void test_clipboard_viewers(void)
14491 static struct message wm_change_cb_chain[] =
14493 { WM_CHANGECBCHAIN, sent|wparam|lparam, 0, 0 },
14494 { 0 }
14496 static const struct message wm_clipboard_destroyed[] =
14498 { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
14499 { 0 }
14501 static struct message wm_clipboard_changed[] =
14503 { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
14504 { 0 }
14506 static struct message wm_clipboard_changed_and_owned[] =
14508 { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
14509 { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
14510 { 0 }
14513 HINSTANCE hInst = GetModuleHandleA(NULL);
14514 HWND hWnd1, hWnd2, hWnd3;
14515 HWND hOrigViewer;
14516 HWND hRet;
14518 hWnd1 = CreateWindowExA(0, "TestWindowClass", "Clipboard viewer test wnd 1",
14519 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
14520 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
14521 GetDesktopWindow(), NULL, hInst, NULL);
14522 hWnd2 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 2",
14523 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
14524 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
14525 GetDesktopWindow(), NULL, hInst, NULL);
14526 hWnd3 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 3",
14527 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
14528 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
14529 GetDesktopWindow(), NULL, hInst, NULL);
14530 trace("clipbd viewers: hWnd1=%p, hWnd2=%p, hWnd3=%p\n", hWnd1, hWnd2, hWnd3);
14531 assert(hWnd1 && hWnd2 && hWnd3);
14533 CountClipboardFormats(); /* Ensure that we do not have an X11 update to the clipboard */
14534 flush_sequence();
14536 /* Test getting the clipboard viewer and setting the viewer to NULL. */
14537 hOrigViewer = GetClipboardViewer();
14538 hRet = SetClipboardViewer(NULL);
14539 ok_sequence(WmEmptySeq, "set viewer to NULL", FALSE);
14540 expect_HWND(hOrigViewer, hRet);
14541 expect_HWND(NULL, GetClipboardViewer());
14543 /* Test registering hWnd1 as a viewer. */
14544 hRet = SetClipboardViewer(hWnd1);
14545 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
14546 ok_sequence(wm_clipboard_changed, "set viewer NULL->1", FALSE);
14547 expect_HWND(NULL, hRet);
14548 expect_HWND(hWnd1, GetClipboardViewer());
14550 /* Test that changing the clipboard actually refreshes the registered viewer. */
14551 clear_clipboard(hWnd1);
14552 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
14553 ok_sequence(wm_clipboard_changed, "clear clipbd (viewer=owner=1)", FALSE);
14555 /* Again, but with different owner. */
14556 clear_clipboard(hWnd2);
14557 wm_clipboard_changed_and_owned[1].wParam = (WPARAM) GetClipboardOwner();
14558 ok_sequence(wm_clipboard_changed_and_owned, "clear clipbd (viewer=1, owner=2)", FALSE);
14560 /* Test re-registering same window. */
14561 hRet = SetClipboardViewer(hWnd1);
14562 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
14563 ok_sequence(wm_clipboard_changed, "set viewer 1->1", FALSE);
14564 expect_HWND(hWnd1, hRet);
14565 expect_HWND(hWnd1, GetClipboardViewer());
14567 /* Test ChangeClipboardChain. */
14568 ChangeClipboardChain(hWnd2, hWnd3);
14569 wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
14570 wm_change_cb_chain[0].lParam = (LPARAM) hWnd3;
14571 ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=3)", FALSE);
14572 expect_HWND(hWnd1, GetClipboardViewer());
14574 ChangeClipboardChain(hWnd2, NULL);
14575 wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
14576 wm_change_cb_chain[0].lParam = 0;
14577 ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=NULL)", FALSE);
14578 expect_HWND(hWnd1, GetClipboardViewer());
14580 ChangeClipboardChain(NULL, hWnd2);
14581 ok_sequence(WmEmptySeq, "change chain (viewer=1, remove=NULL, next=2)", FALSE);
14582 expect_HWND(hWnd1, GetClipboardViewer());
14584 /* Actually change clipboard viewer with ChangeClipboardChain. */
14585 ChangeClipboardChain(hWnd1, hWnd2);
14586 ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=2)", FALSE);
14587 expect_HWND(hWnd2, GetClipboardViewer());
14589 /* Test that no refresh messages are sent when viewer has unregistered. */
14590 clear_clipboard(hWnd2);
14591 ok_sequence(WmEmptySeq, "clear clipd (viewer=2, owner=1)", FALSE);
14593 /* Register hWnd1 again. */
14594 ChangeClipboardChain(hWnd2, hWnd1);
14595 ok_sequence(WmEmptySeq, "change chain (viewer=remove=2, next=1)", FALSE);
14596 expect_HWND(hWnd1, GetClipboardViewer());
14598 /* Subclass hWnd1 so that when it receives a WM_DRAWCLIPBOARD message, it
14599 * changes the clipboard. When this happens, the system shouldn't send
14600 * another WM_DRAWCLIPBOARD (as this could cause an infinite loop).
14602 pOldViewerProc = (WNDPROC) SetWindowLongPtrA(hWnd1, GWLP_WNDPROC, (LONG_PTR) recursive_viewer_proc);
14603 clear_clipboard(hWnd2);
14604 /* The clipboard owner is changed in recursive_viewer_proc: */
14605 wm_clipboard_changed[0].wParam = (WPARAM) hWnd2;
14606 ok_sequence(wm_clipboard_changed, "recursive clear clipbd (viewer=1, owner=2)", TRUE);
14608 /* Test unregistering. */
14609 ChangeClipboardChain(hWnd1, NULL);
14610 ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=NULL)", FALSE);
14611 expect_HWND(NULL, GetClipboardViewer());
14613 clear_clipboard(hWnd1);
14614 ok_sequence(wm_clipboard_destroyed, "clear clipbd (no viewer, owner=1)", FALSE);
14616 DestroyWindow(hWnd1);
14617 DestroyWindow(hWnd2);
14618 DestroyWindow(hWnd3);
14619 SetClipboardViewer(hOrigViewer);
14622 static void test_PostMessage(void)
14624 static const struct
14626 HWND hwnd;
14627 BOOL ret;
14628 } data[] =
14630 { HWND_TOP /* 0 */, TRUE },
14631 { HWND_BROADCAST, TRUE },
14632 { HWND_BOTTOM, TRUE },
14633 { HWND_TOPMOST, TRUE },
14634 { HWND_NOTOPMOST, FALSE },
14635 { HWND_MESSAGE, FALSE },
14636 { (HWND)0xdeadbeef, FALSE }
14638 int i;
14639 HWND hwnd;
14640 BOOL ret;
14641 MSG msg;
14642 static const WCHAR staticW[] = {'s','t','a','t','i','c',0};
14644 SetLastError(0xdeadbeef);
14645 hwnd = CreateWindowExW(0, staticW, NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
14646 if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
14648 win_skip("Skipping some PostMessage tests on Win9x/WinMe\n");
14649 return;
14651 assert(hwnd);
14653 flush_events();
14655 PostMessageA(hwnd, WM_USER+1, 0x1234, 0x5678);
14656 PostMessageA(0, WM_USER+2, 0x5678, 0x1234);
14658 for (i = 0; i < sizeof(data)/sizeof(data[0]); i++)
14660 memset(&msg, 0xab, sizeof(msg));
14661 ret = PeekMessageA(&msg, data[i].hwnd, 0, 0, PM_NOREMOVE);
14662 ok(ret == data[i].ret, "%d: hwnd %p expected %d, got %d\n", i, data[i].hwnd, data[i].ret, ret);
14663 if (data[i].ret)
14665 if (data[i].hwnd)
14666 ok(ret && msg.hwnd == 0 && msg.message == WM_USER+2 &&
14667 msg.wParam == 0x5678 && msg.lParam == 0x1234,
14668 "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/0/WM_USER+2/0x5678/0x1234\n",
14669 i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam);
14670 else
14671 ok(ret && msg.hwnd == hwnd && msg.message == WM_USER+1 &&
14672 msg.wParam == 0x1234 && msg.lParam == 0x5678,
14673 "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/%p/WM_USER+1/0x1234/0x5678\n",
14674 i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam, msg.hwnd);
14678 DestroyWindow(hwnd);
14679 flush_events();
14682 static LPARAM g_broadcast_lparam;
14683 static LRESULT WINAPI broadcast_test_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
14685 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
14687 if (wParam == 0xbaadbeef)
14688 g_broadcast_lparam = wParam;
14689 else
14690 g_broadcast_lparam = 0;
14692 return CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
14695 static void test_broadcast(void)
14697 static const UINT messages[] =
14699 WM_USER-1,
14700 WM_USER,
14701 WM_USER+1,
14702 0xc000-1,
14703 0xc000, /* lowest possible atom returned by RegisterWindowMessage */
14704 0xffff,
14706 WNDPROC oldproc;
14707 unsigned int i;
14708 HWND hwnd;
14710 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, NULL);
14711 ok(hwnd != NULL, "got %p\n", hwnd);
14713 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)broadcast_test_proc);
14714 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
14716 for (i = 0; i < sizeof(messages)/sizeof(messages[0]); i++)
14718 BOOL ret;
14719 MSG msg;
14721 flush_events();
14722 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
14725 /* post, broadcast */
14726 ret = PostMessageA(HWND_BROADCAST, messages[i], 0, 0);
14727 ok(ret, "%d: got %d, error %d\n", i, ret, GetLastError());
14729 memset(&msg, 0xab, sizeof(msg));
14730 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
14731 if (messages[i] < WM_USER || messages[i] >= 0xc000)
14733 ok(ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
14734 ok(msg.hwnd == hwnd, "%d: got %p\n", i, msg.hwnd);
14736 else
14738 ok(!ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
14741 /* post, topmost */
14742 ret = PostMessageA(HWND_TOPMOST, messages[i], 0, 0);
14743 ok(ret, "%d: got %d, error %d\n", i, ret, GetLastError());
14745 memset(&msg, 0xab, sizeof(msg));
14746 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
14747 if (messages[i] < WM_USER || messages[i] >= 0xc000)
14749 ok(ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
14750 ok(msg.hwnd == hwnd, "%d: got %p\n", i, msg.hwnd);
14752 else
14754 ok(!ret, "%d: got %d, error %d\n", i, ret, GetLastError());
14757 /* send, broadcast */
14758 g_broadcast_lparam = 0xdead;
14759 ret = SendMessageTimeoutA(HWND_BROADCAST, messages[i], 0xbaadbeef, 0, SMTO_NORMAL, 2000, NULL);
14760 if (!ret && GetLastError() == ERROR_TIMEOUT)
14761 win_skip("broadcasting test %d, timeout\n", i);
14762 else
14764 if (messages[i] < WM_USER || messages[i] >= 0xc000)
14766 ok(g_broadcast_lparam == 0xbaadbeef, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
14767 g_broadcast_lparam, GetLastError());
14769 else
14771 ok(g_broadcast_lparam == 0xdead, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
14772 g_broadcast_lparam, GetLastError());
14776 /* send, topmost */
14777 g_broadcast_lparam = 0xdead;
14778 ret = SendMessageTimeoutA(HWND_TOPMOST, messages[i], 0xbaadbeef, 0, SMTO_NORMAL, 2000, NULL);
14779 if (!ret && GetLastError() == ERROR_TIMEOUT)
14780 win_skip("broadcasting test %d, timeout\n", i);
14781 else
14783 if (messages[i] < WM_USER || messages[i] >= 0xc000)
14785 ok(g_broadcast_lparam == 0xbaadbeef, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
14786 g_broadcast_lparam, GetLastError());
14788 else
14790 ok(g_broadcast_lparam == 0xdead, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
14791 g_broadcast_lparam, GetLastError());
14796 DestroyWindow(hwnd);
14799 static const struct
14801 DWORD exp, broken;
14802 BOOL todo;
14803 } wait_idle_expect[] =
14805 /* 0 */ { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
14806 { WAIT_TIMEOUT, 0, FALSE },
14807 { WAIT_TIMEOUT, 0, FALSE },
14808 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
14809 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
14810 /* 5 */ { WAIT_TIMEOUT, 0, FALSE },
14811 { WAIT_TIMEOUT, 0, FALSE },
14812 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
14813 { 0, 0, FALSE },
14814 { 0, 0, FALSE },
14815 /* 10 */ { 0, 0, FALSE },
14816 { 0, 0, FALSE },
14817 { 0, WAIT_TIMEOUT, FALSE },
14818 { 0, 0, FALSE },
14819 { 0, 0, FALSE },
14820 /* 15 */ { 0, 0, FALSE },
14821 { WAIT_TIMEOUT, 0, FALSE },
14822 { WAIT_TIMEOUT, 0, FALSE },
14823 { WAIT_TIMEOUT, 0, FALSE },
14824 { WAIT_TIMEOUT, 0, FALSE },
14825 /* 20 */ { WAIT_TIMEOUT, 0, FALSE },
14828 static DWORD CALLBACK do_wait_idle_child_thread( void *arg )
14830 MSG msg;
14832 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
14833 Sleep( 200 );
14834 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
14835 return 0;
14838 static void do_wait_idle_child( int arg )
14840 WNDCLASSA cls;
14841 MSG msg;
14842 HWND hwnd = 0;
14843 HANDLE thread;
14844 DWORD id;
14845 HANDLE start_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_start" );
14846 HANDLE end_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_end" );
14848 memset( &cls, 0, sizeof(cls) );
14849 cls.lpfnWndProc = DefWindowProcA;
14850 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
14851 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
14852 cls.lpszClassName = "TestClass";
14853 RegisterClassA( &cls );
14855 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ); /* create the msg queue */
14857 ok( start_event != 0, "failed to create start event, error %u\n", GetLastError() );
14858 ok( end_event != 0, "failed to create end event, error %u\n", GetLastError() );
14860 switch (arg)
14862 case 0:
14863 SetEvent( start_event );
14864 break;
14865 case 1:
14866 SetEvent( start_event );
14867 Sleep( 200 );
14868 PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
14869 break;
14870 case 2:
14871 SetEvent( start_event );
14872 Sleep( 200 );
14873 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
14874 PostThreadMessageA( GetCurrentThreadId(), WM_COMMAND, 0x1234, 0xabcd );
14875 PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
14876 break;
14877 case 3:
14878 SetEvent( start_event );
14879 Sleep( 200 );
14880 SendMessageA( HWND_BROADCAST, WM_WININICHANGE, 0, 0 );
14881 break;
14882 case 4:
14883 SetEvent( start_event );
14884 Sleep( 200 );
14885 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
14886 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
14887 break;
14888 case 5:
14889 SetEvent( start_event );
14890 Sleep( 200 );
14891 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
14892 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
14893 break;
14894 case 6:
14895 SetEvent( start_event );
14896 Sleep( 200 );
14897 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
14898 while (PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ))
14900 GetMessageA( &msg, 0, 0, 0 );
14901 DispatchMessageA( &msg );
14903 break;
14904 case 7:
14905 SetEvent( start_event );
14906 Sleep( 200 );
14907 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
14908 SetTimer( hwnd, 3, 1, NULL );
14909 Sleep( 200 );
14910 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
14911 break;
14912 case 8:
14913 SetEvent( start_event );
14914 Sleep( 200 );
14915 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
14916 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
14917 break;
14918 case 9:
14919 SetEvent( start_event );
14920 Sleep( 200 );
14921 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
14922 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
14923 for (;;) GetMessageA( &msg, 0, 0, 0 );
14924 break;
14925 case 10:
14926 SetEvent( start_event );
14927 Sleep( 200 );
14928 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
14929 SetTimer( hwnd, 3, 1, NULL );
14930 Sleep( 200 );
14931 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
14932 break;
14933 case 11:
14934 SetEvent( start_event );
14935 Sleep( 200 );
14936 return; /* exiting the process makes WaitForInputIdle return success too */
14937 case 12:
14938 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
14939 Sleep( 200 );
14940 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
14941 SetEvent( start_event );
14942 break;
14943 case 13:
14944 SetEvent( start_event );
14945 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
14946 Sleep( 200 );
14947 thread = CreateThread( NULL, 0, do_wait_idle_child_thread, NULL, 0, &id );
14948 WaitForSingleObject( thread, 10000 );
14949 CloseHandle( thread );
14950 break;
14951 case 14:
14952 SetEvent( start_event );
14953 Sleep( 200 );
14954 PeekMessageA( &msg, HWND_TOPMOST, 0, 0, PM_NOREMOVE );
14955 break;
14956 case 15:
14957 SetEvent( start_event );
14958 Sleep( 200 );
14959 PeekMessageA( &msg, HWND_BROADCAST, 0, 0, PM_NOREMOVE );
14960 break;
14961 case 16:
14962 SetEvent( start_event );
14963 Sleep( 200 );
14964 PeekMessageA( &msg, HWND_BOTTOM, 0, 0, PM_NOREMOVE );
14965 break;
14966 case 17:
14967 SetEvent( start_event );
14968 Sleep( 200 );
14969 PeekMessageA( &msg, (HWND)0xdeadbeef, 0, 0, PM_NOREMOVE );
14970 break;
14971 case 18:
14972 SetEvent( start_event );
14973 Sleep( 200 );
14974 PeekMessageA( &msg, HWND_NOTOPMOST, 0, 0, PM_NOREMOVE );
14975 break;
14976 case 19:
14977 SetEvent( start_event );
14978 Sleep( 200 );
14979 PeekMessageA( &msg, HWND_MESSAGE, 0, 0, PM_NOREMOVE );
14980 break;
14981 case 20:
14982 SetEvent( start_event );
14983 Sleep( 200 );
14984 PeekMessageA( &msg, GetDesktopWindow(), 0, 0, PM_NOREMOVE );
14985 break;
14987 WaitForSingleObject( end_event, 2000 );
14988 CloseHandle( start_event );
14989 CloseHandle( end_event );
14990 if (hwnd) DestroyWindow( hwnd );
14993 static LRESULT CALLBACK wait_idle_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
14995 if (msg == WM_WININICHANGE) Sleep( 200 ); /* make sure the child waits */
14996 return DefWindowProcA( hwnd, msg, wp, lp );
14999 static DWORD CALLBACK wait_idle_thread( void *arg )
15001 WNDCLASSA cls;
15002 MSG msg;
15003 HWND hwnd;
15005 memset( &cls, 0, sizeof(cls) );
15006 cls.lpfnWndProc = wait_idle_proc;
15007 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
15008 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
15009 cls.lpszClassName = "TestClass";
15010 RegisterClassA( &cls );
15012 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL);
15013 while (GetMessageA( &msg, 0, 0, 0 )) DispatchMessageA( &msg );
15014 DestroyWindow(hwnd);
15015 return 0;
15018 static void test_WaitForInputIdle( char *argv0 )
15020 char path[MAX_PATH];
15021 PROCESS_INFORMATION pi;
15022 STARTUPINFOA startup;
15023 BOOL ret;
15024 HANDLE start_event, end_event, thread;
15025 unsigned int i;
15026 DWORD id;
15027 const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)GetModuleHandleA(0);
15028 const IMAGE_NT_HEADERS *nt = (const IMAGE_NT_HEADERS *)((const char *)dos + dos->e_lfanew);
15029 BOOL console_app = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI);
15031 if (console_app) /* build the test with -mwindows for better coverage */
15032 trace( "not built as a GUI app, WaitForInputIdle may not be fully tested\n" );
15034 start_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_start");
15035 end_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_end");
15036 ok(start_event != 0, "failed to create start event, error %u\n", GetLastError());
15037 ok(end_event != 0, "failed to create end event, error %u\n", GetLastError());
15039 memset( &startup, 0, sizeof(startup) );
15040 startup.cb = sizeof(startup);
15041 startup.dwFlags = STARTF_USESHOWWINDOW;
15042 startup.wShowWindow = SW_SHOWNORMAL;
15044 thread = CreateThread( NULL, 0, wait_idle_thread, NULL, 0, &id );
15046 for (i = 0; i < sizeof(wait_idle_expect)/sizeof(wait_idle_expect[0]); i++)
15048 ResetEvent( start_event );
15049 ResetEvent( end_event );
15050 sprintf( path, "%s msg %u", argv0, i );
15051 ret = CreateProcessA( NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &pi );
15052 ok( ret, "CreateProcess '%s' failed err %u.\n", path, GetLastError() );
15053 if (ret)
15055 ret = WaitForSingleObject( start_event, 5000 );
15056 ok( ret == WAIT_OBJECT_0, "%u: WaitForSingleObject failed\n", i );
15057 if (ret == WAIT_OBJECT_0)
15059 ret = WaitForInputIdle( pi.hProcess, 1000 );
15060 if (ret == WAIT_FAILED)
15061 ok( console_app ||
15062 ret == wait_idle_expect[i].exp ||
15063 broken(ret == wait_idle_expect[i].broken),
15064 "%u: WaitForInputIdle error %08x expected %08x\n",
15065 i, ret, wait_idle_expect[i].exp );
15066 else todo_wine_if (wait_idle_expect[i].todo)
15067 ok( ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken),
15068 "%u: WaitForInputIdle error %08x expected %08x\n",
15069 i, ret, wait_idle_expect[i].exp );
15070 SetEvent( end_event );
15071 WaitForSingleObject( pi.hProcess, 1000 ); /* give it a chance to exit on its own */
15073 TerminateProcess( pi.hProcess, 0 ); /* just in case */
15074 winetest_wait_child_process( pi.hProcess );
15075 ret = WaitForInputIdle( pi.hProcess, 100 );
15076 ok( ret == WAIT_FAILED, "%u: WaitForInputIdle after exit error %08x\n", i, ret );
15077 CloseHandle( pi.hProcess );
15078 CloseHandle( pi.hThread );
15081 CloseHandle( start_event );
15082 PostThreadMessageA( id, WM_QUIT, 0, 0 );
15083 WaitForSingleObject( thread, 10000 );
15084 CloseHandle( thread );
15087 static const struct message WmSetParentSeq_1[] = {
15088 { WM_SHOWWINDOW, sent|wparam, 0 },
15089 { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15090 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
15091 { WM_CHILDACTIVATE, sent },
15092 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE },
15093 { WM_MOVE, sent|defwinproc|wparam, 0 },
15094 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15095 { WM_SHOWWINDOW, sent|wparam, 1 },
15096 { 0 }
15099 static const struct message WmSetParentSeq_2[] = {
15100 { WM_SHOWWINDOW, sent|wparam, 0 },
15101 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
15102 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
15103 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15104 { HCBT_SETFOCUS, hook|optional },
15105 { WM_NCACTIVATE, sent|wparam|optional, 0 },
15106 { WM_ACTIVATE, sent|wparam|optional, 0 },
15107 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
15108 { WM_KILLFOCUS, sent|wparam, 0 },
15109 { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15110 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
15111 { HCBT_ACTIVATE, hook|optional },
15112 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
15113 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
15114 { WM_NCACTIVATE, sent|wparam|optional, 1 },
15115 { WM_ACTIVATE, sent|wparam|optional, 1 },
15116 { HCBT_SETFOCUS, hook|optional },
15117 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
15118 { WM_SETFOCUS, sent|optional|defwinproc },
15119 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOCLIENTSIZE },
15120 { WM_MOVE, sent|defwinproc|wparam, 0 },
15121 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15122 { WM_SHOWWINDOW, sent|wparam, 1 },
15123 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
15124 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
15125 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15126 { 0 }
15130 static void test_SetParent(void)
15132 HWND parent1, parent2, child, popup;
15133 RECT rc, rc_old;
15135 parent1 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
15136 100, 100, 200, 200, 0, 0, 0, NULL);
15137 ok(parent1 != 0, "Failed to create parent1 window\n");
15139 parent2 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
15140 400, 100, 200, 200, 0, 0, 0, NULL);
15141 ok(parent2 != 0, "Failed to create parent2 window\n");
15143 /* WS_CHILD window */
15144 child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD | WS_VISIBLE,
15145 10, 10, 150, 150, parent1, 0, 0, NULL);
15146 ok(child != 0, "Failed to create child window\n");
15148 GetWindowRect(parent1, &rc);
15149 trace("parent1 %s\n", wine_dbgstr_rect(&rc));
15150 GetWindowRect(child, &rc_old);
15151 MapWindowPoints(0, parent1, (POINT *)&rc_old, 2);
15152 trace("child %s\n", wine_dbgstr_rect(&rc_old));
15154 flush_sequence();
15156 SetParent(child, parent2);
15157 flush_events();
15158 ok_sequence(WmSetParentSeq_1, "SetParent() visible WS_CHILD", TRUE);
15160 ok(GetWindowLongA(child, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
15161 ok(!IsWindowVisible(child), "IsWindowVisible() should return FALSE\n");
15163 GetWindowRect(parent2, &rc);
15164 trace("parent2 %s\n", wine_dbgstr_rect(&rc));
15165 GetWindowRect(child, &rc);
15166 MapWindowPoints(0, parent2, (POINT *)&rc, 2);
15167 trace("child %s\n", wine_dbgstr_rect(&rc));
15169 ok(EqualRect(&rc_old, &rc), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc_old),
15170 wine_dbgstr_rect(&rc));
15172 /* WS_POPUP window */
15173 popup = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP | WS_VISIBLE,
15174 20, 20, 100, 100, 0, 0, 0, NULL);
15175 ok(popup != 0, "Failed to create popup window\n");
15177 GetWindowRect(popup, &rc_old);
15178 trace("popup %s\n", wine_dbgstr_rect(&rc_old));
15180 flush_sequence();
15182 SetParent(popup, child);
15183 flush_events();
15184 ok_sequence(WmSetParentSeq_2, "SetParent() visible WS_POPUP", TRUE);
15186 ok(GetWindowLongA(popup, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
15187 ok(!IsWindowVisible(popup), "IsWindowVisible() should return FALSE\n");
15189 GetWindowRect(child, &rc);
15190 trace("parent2 %s\n", wine_dbgstr_rect(&rc));
15191 GetWindowRect(popup, &rc);
15192 MapWindowPoints(0, child, (POINT *)&rc, 2);
15193 trace("popup %s\n", wine_dbgstr_rect(&rc));
15195 ok(EqualRect(&rc_old, &rc), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc_old),
15196 wine_dbgstr_rect(&rc));
15198 DestroyWindow(popup);
15199 DestroyWindow(child);
15200 DestroyWindow(parent1);
15201 DestroyWindow(parent2);
15203 flush_sequence();
15206 static const struct message WmKeyReleaseOnly[] = {
15207 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x80000001 },
15208 { WM_KEYUP, sent|wparam|lparam, 0x41, 0x80000001 },
15209 { 0 }
15211 static const struct message WmKeyPressNormal[] = {
15212 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x1 },
15213 { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x1 },
15214 { 0 }
15216 static const struct message WmKeyPressRepeat[] = {
15217 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x40000001 },
15218 { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x40000001 },
15219 { 0 }
15221 static const struct message WmKeyReleaseNormal[] = {
15222 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0xc0000001 },
15223 { WM_KEYUP, sent|wparam|lparam, 0x41, 0xc0000001 },
15224 { 0 }
15227 static void test_keyflags(void)
15229 HWND test_window;
15230 SHORT key_state;
15231 BYTE keyboard_state[256];
15232 MSG msg;
15234 test_window = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
15235 100, 100, 200, 200, 0, 0, 0, NULL);
15237 flush_events();
15238 flush_sequence();
15240 /* keyup without a keydown */
15241 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
15242 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
15243 DispatchMessageA(&msg);
15244 ok_sequence(WmKeyReleaseOnly, "key release only", TRUE);
15246 key_state = GetAsyncKeyState(0x41);
15247 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
15249 key_state = GetKeyState(0x41);
15250 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
15252 /* keydown */
15253 keybd_event(0x41, 0, 0, 0);
15254 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
15255 DispatchMessageA(&msg);
15256 ok_sequence(WmKeyPressNormal, "key press only", FALSE);
15258 key_state = GetAsyncKeyState(0x41);
15259 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
15261 key_state = GetKeyState(0x41);
15262 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
15264 /* keydown repeat */
15265 keybd_event(0x41, 0, 0, 0);
15266 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
15267 DispatchMessageA(&msg);
15268 ok_sequence(WmKeyPressRepeat, "key press repeat", FALSE);
15270 key_state = GetAsyncKeyState(0x41);
15271 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
15273 key_state = GetKeyState(0x41);
15274 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
15276 /* keyup */
15277 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
15278 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
15279 DispatchMessageA(&msg);
15280 ok_sequence(WmKeyReleaseNormal, "key release repeat", FALSE);
15282 key_state = GetAsyncKeyState(0x41);
15283 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
15285 key_state = GetKeyState(0x41);
15286 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
15288 /* set the key state in this thread */
15289 GetKeyboardState(keyboard_state);
15290 keyboard_state[0x41] = 0x80;
15291 SetKeyboardState(keyboard_state);
15293 key_state = GetAsyncKeyState(0x41);
15294 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
15296 /* keydown */
15297 keybd_event(0x41, 0, 0, 0);
15298 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
15299 DispatchMessageA(&msg);
15300 ok_sequence(WmKeyPressRepeat, "key press after setkeyboardstate", TRUE);
15302 key_state = GetAsyncKeyState(0x41);
15303 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
15305 key_state = GetKeyState(0x41);
15306 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
15308 /* clear the key state in this thread */
15309 GetKeyboardState(keyboard_state);
15310 keyboard_state[0x41] = 0;
15311 SetKeyboardState(keyboard_state);
15313 key_state = GetAsyncKeyState(0x41);
15314 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
15316 /* keyup */
15317 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
15318 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
15319 DispatchMessageA(&msg);
15320 ok_sequence(WmKeyReleaseOnly, "key release after setkeyboardstate", TRUE);
15322 key_state = GetAsyncKeyState(0x41);
15323 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
15325 key_state = GetKeyState(0x41);
15326 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
15328 DestroyWindow(test_window);
15329 flush_sequence();
15332 static const struct message WmHotkeyPressLWIN[] = {
15333 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
15334 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
15335 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
15336 { 0 }
15338 static const struct message WmHotkeyPress[] = {
15339 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
15340 { WM_HOTKEY, sent|wparam, 5 },
15341 { 0 }
15343 static const struct message WmHotkeyRelease[] = {
15344 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
15345 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 0x80000001 },
15346 { WM_KEYUP, sent|lparam, 0, 0x80000001 },
15347 { 0 }
15349 static const struct message WmHotkeyReleaseLWIN[] = {
15350 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
15351 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
15352 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
15353 { 0 }
15355 static const struct message WmHotkeyCombined[] = {
15356 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
15357 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
15358 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
15359 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
15360 { WM_APP, sent, 0, 0 },
15361 { WM_HOTKEY, sent|wparam, 5 },
15362 { WM_APP+1, sent, 0, 0 },
15363 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
15364 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
15365 { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
15366 { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
15367 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
15368 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
15369 { 0 }
15371 static const struct message WmHotkeyPrevious[] = {
15372 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
15373 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
15374 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
15375 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
15376 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
15377 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
15378 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 1 },
15379 { WM_KEYDOWN, sent|lparam, 0, 1 },
15380 { HCBT_KEYSKIPPED, hook|optional|lparam, 0, 0xc0000001 },
15381 { WM_KEYUP, sent|lparam, 0, 0xc0000001 },
15382 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
15383 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
15384 { 0 }
15386 static const struct message WmHotkeyNew[] = {
15387 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
15388 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
15389 { WM_HOTKEY, sent|wparam, 5 },
15390 { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
15391 { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
15392 { 0 }
15395 static int hotkey_letter;
15397 static LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
15399 struct recvd_message msg;
15401 if (nCode == HC_ACTION)
15403 KBDLLHOOKSTRUCT *kdbhookstruct = (KBDLLHOOKSTRUCT*)lParam;
15405 msg.hwnd = 0;
15406 msg.message = wParam;
15407 msg.flags = kbd_hook|wparam|lparam;
15408 msg.wParam = kdbhookstruct->vkCode;
15409 msg.lParam = kdbhookstruct->flags;
15410 msg.descr = "KeyboardHookProc";
15411 add_message(&msg);
15413 if (wParam == WM_KEYUP || wParam == WM_KEYDOWN)
15415 ok(kdbhookstruct->vkCode == VK_LWIN || kdbhookstruct->vkCode == hotkey_letter,
15416 "unexpected keycode %x\n", kdbhookstruct->vkCode);
15420 return CallNextHookEx(hKBD_hook, nCode, wParam, lParam);
15423 static void test_hotkey(void)
15425 HWND test_window, taskbar_window;
15426 BOOL ret;
15427 MSG msg;
15428 DWORD queue_status;
15429 SHORT key_state;
15431 SetLastError(0xdeadbeef);
15432 ret = UnregisterHotKey(NULL, 0);
15433 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
15434 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
15435 "unexpected error %d\n", GetLastError());
15437 if (ret == TRUE)
15439 skip("hotkeys not supported\n");
15440 return;
15443 test_window = CreateWindowExA(0, "HotkeyWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
15444 100, 100, 200, 200, 0, 0, 0, NULL);
15446 flush_sequence();
15448 SetLastError(0xdeadbeef);
15449 ret = UnregisterHotKey(test_window, 0);
15450 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
15451 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
15452 "unexpected error %d\n", GetLastError());
15454 /* Search for a Windows Key + letter combination that hasn't been registered */
15455 for (hotkey_letter = 0x41; hotkey_letter <= 0x51; hotkey_letter ++)
15457 SetLastError(0xdeadbeef);
15458 ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
15460 if (ret == TRUE)
15462 break;
15464 else
15466 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
15467 "unexpected error %d\n", GetLastError());
15471 if (hotkey_letter == 0x52)
15473 ok(0, "Couldn't find any free Windows Key + letter combination\n");
15474 goto end;
15477 hKBD_hook = SetWindowsHookExA(WH_KEYBOARD_LL, KeyboardHookProc, GetModuleHandleA(NULL), 0);
15478 if (!hKBD_hook) win_skip("WH_KEYBOARD_LL is not supported\n");
15480 /* Same key combination, different id */
15481 SetLastError(0xdeadbeef);
15482 ret = RegisterHotKey(test_window, 4, MOD_WIN, hotkey_letter);
15483 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
15484 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
15485 "unexpected error %d\n", GetLastError());
15487 /* Same key combination, different window */
15488 SetLastError(0xdeadbeef);
15489 ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
15490 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
15491 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
15492 "unexpected error %d\n", GetLastError());
15494 /* Register the same hotkey twice */
15495 SetLastError(0xdeadbeef);
15496 ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
15497 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
15498 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
15499 "unexpected error %d\n", GetLastError());
15501 /* Window on another thread */
15502 taskbar_window = FindWindowA("Shell_TrayWnd", NULL);
15503 if (!taskbar_window)
15505 skip("no taskbar?\n");
15507 else
15509 SetLastError(0xdeadbeef);
15510 ret = RegisterHotKey(taskbar_window, 5, 0, hotkey_letter);
15511 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
15512 ok(GetLastError() == ERROR_WINDOW_OF_OTHER_THREAD || broken(GetLastError() == 0xdeadbeef),
15513 "unexpected error %d\n", GetLastError());
15516 /* Inject the appropriate key sequence */
15517 keybd_event(VK_LWIN, 0, 0, 0);
15518 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
15519 DispatchMessageA(&msg);
15520 ok_sequence(WmHotkeyPressLWIN, "window hotkey press LWIN", FALSE);
15522 keybd_event(hotkey_letter, 0, 0, 0);
15523 queue_status = GetQueueStatus(QS_HOTKEY);
15524 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
15525 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
15527 if (msg.message == WM_HOTKEY)
15529 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
15530 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
15532 DispatchMessageA(&msg);
15534 ok_sequence(WmHotkeyPress, "window hotkey press", FALSE);
15536 queue_status = GetQueueStatus(QS_HOTKEY);
15537 ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
15539 key_state = GetAsyncKeyState(hotkey_letter);
15540 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
15542 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
15543 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
15544 DispatchMessageA(&msg);
15545 ok_sequence(WmHotkeyRelease, "window hotkey release", TRUE);
15547 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
15548 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
15549 DispatchMessageA(&msg);
15550 ok_sequence(WmHotkeyReleaseLWIN, "window hotkey release LWIN", FALSE);
15552 /* normal posted WM_HOTKEY messages set QS_HOTKEY */
15553 PostMessageA(test_window, WM_HOTKEY, 0, 0);
15554 queue_status = GetQueueStatus(QS_HOTKEY);
15555 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
15556 queue_status = GetQueueStatus(QS_POSTMESSAGE);
15557 ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
15558 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
15559 DispatchMessageA(&msg);
15560 flush_sequence();
15562 /* Send and process all messages at once */
15563 PostMessageA(test_window, WM_APP, 0, 0);
15564 keybd_event(VK_LWIN, 0, 0, 0);
15565 keybd_event(hotkey_letter, 0, 0, 0);
15566 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
15567 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
15569 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
15571 if (msg.message == WM_HOTKEY)
15573 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
15574 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
15576 DispatchMessageA(&msg);
15578 ok_sequence(WmHotkeyCombined, "window hotkey combined", FALSE);
15580 /* Register same hwnd/id with different key combination */
15581 ret = RegisterHotKey(test_window, 5, 0, hotkey_letter);
15582 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
15584 /* Previous key combination does not work */
15585 keybd_event(VK_LWIN, 0, 0, 0);
15586 keybd_event(hotkey_letter, 0, 0, 0);
15587 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
15588 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
15590 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
15591 DispatchMessageA(&msg);
15592 ok_sequence(WmHotkeyPrevious, "window hotkey previous", FALSE);
15594 /* New key combination works */
15595 keybd_event(hotkey_letter, 0, 0, 0);
15596 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
15598 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
15600 if (msg.message == WM_HOTKEY)
15602 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
15603 ok(msg.lParam == MAKELPARAM(0, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
15605 DispatchMessageA(&msg);
15607 ok_sequence(WmHotkeyNew, "window hotkey new", FALSE);
15609 /* Unregister hotkey properly */
15610 ret = UnregisterHotKey(test_window, 5);
15611 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
15613 /* Unregister hotkey again */
15614 SetLastError(0xdeadbeef);
15615 ret = UnregisterHotKey(test_window, 5);
15616 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
15617 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
15618 "unexpected error %d\n", GetLastError());
15620 /* Register thread hotkey */
15621 ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
15622 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
15624 /* Inject the appropriate key sequence */
15625 keybd_event(VK_LWIN, 0, 0, 0);
15626 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
15628 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
15629 DispatchMessageA(&msg);
15631 ok_sequence(WmHotkeyPressLWIN, "thread hotkey press LWIN", FALSE);
15633 keybd_event(hotkey_letter, 0, 0, 0);
15634 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
15636 if (msg.message == WM_HOTKEY)
15638 struct recvd_message message;
15639 ok(msg.hwnd == NULL, "unexpected hwnd %p\n", msg.hwnd);
15640 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
15641 message.message = msg.message;
15642 message.flags = sent|wparam|lparam;
15643 message.wParam = msg.wParam;
15644 message.lParam = msg.lParam;
15645 message.descr = "test_hotkey thread message";
15646 add_message(&message);
15648 else
15649 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
15650 DispatchMessageA(&msg);
15652 ok_sequence(WmHotkeyPress, "thread hotkey press", FALSE);
15654 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
15655 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
15657 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
15658 DispatchMessageA(&msg);
15660 ok_sequence(WmHotkeyRelease, "thread hotkey release", TRUE);
15662 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
15663 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
15665 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
15666 DispatchMessageA(&msg);
15668 ok_sequence(WmHotkeyReleaseLWIN, "thread hotkey release LWIN", FALSE);
15670 /* Unregister thread hotkey */
15671 ret = UnregisterHotKey(NULL, 5);
15672 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
15674 if (hKBD_hook) UnhookWindowsHookEx(hKBD_hook);
15675 hKBD_hook = NULL;
15677 end:
15678 UnregisterHotKey(NULL, 5);
15679 UnregisterHotKey(test_window, 5);
15680 DestroyWindow(test_window);
15681 flush_sequence();
15685 static const struct message WmSetFocus_1[] = {
15686 { HCBT_SETFOCUS, hook }, /* child */
15687 { HCBT_ACTIVATE, hook }, /* parent */
15688 { WM_QUERYNEWPALETTE, sent|wparam|lparam|parent|optional, 0, 0 },
15689 { WM_WINDOWPOSCHANGING, sent|parent, 0, SWP_NOSIZE|SWP_NOMOVE },
15690 { WM_ACTIVATEAPP, sent|wparam|parent, 1 },
15691 { WM_NCACTIVATE, sent|parent },
15692 { WM_GETTEXT, sent|defwinproc|parent|optional },
15693 { WM_GETTEXT, sent|defwinproc|parent|optional },
15694 { WM_ACTIVATE, sent|wparam|parent, 1 },
15695 { HCBT_SETFOCUS, hook }, /* parent */
15696 { WM_SETFOCUS, sent|defwinproc|parent },
15697 { WM_KILLFOCUS, sent|parent },
15698 { WM_SETFOCUS, sent },
15699 { 0 }
15701 static const struct message WmSetFocus_2[] = {
15702 { HCBT_SETFOCUS, hook }, /* parent */
15703 { WM_KILLFOCUS, sent },
15704 { WM_SETFOCUS, sent|parent },
15705 { 0 }
15707 static const struct message WmSetFocus_3[] = {
15708 { HCBT_SETFOCUS, hook }, /* child */
15709 { 0 }
15712 static void test_SetFocus(void)
15714 HWND parent, old_parent, child, old_focus, old_active;
15715 MSG msg;
15716 struct wnd_event wnd_event;
15717 HANDLE hthread;
15718 DWORD ret, tid;
15720 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
15721 ok(wnd_event.start_event != 0, "CreateEvent error %d\n", GetLastError());
15722 hthread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
15723 ok(hthread != 0, "CreateThread error %d\n", GetLastError());
15724 ret = WaitForSingleObject(wnd_event.start_event, INFINITE);
15725 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
15726 CloseHandle(wnd_event.start_event);
15728 parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
15729 0, 0, 0, 0, 0, 0, 0, NULL);
15730 ok(parent != 0, "failed to create parent window\n");
15731 child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
15732 0, 0, 0, 0, parent, 0, 0, NULL);
15733 ok(child != 0, "failed to create child window\n");
15735 trace("parent %p, child %p, thread window %p\n", parent, child, wnd_event.hwnd);
15737 SetFocus(0);
15738 SetActiveWindow(0);
15740 flush_events();
15741 flush_sequence();
15743 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
15744 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
15746 log_all_parent_messages++;
15748 old_focus = SetFocus(child);
15749 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
15750 ok_sequence(WmSetFocus_1, "SetFocus on a child window", TRUE);
15751 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
15752 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
15753 ok(GetFocus() == child, "expected focus %p, got %p\n", child, GetFocus());
15755 old_focus = SetFocus(parent);
15756 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
15757 ok_sequence(WmSetFocus_2, "SetFocus on a parent window", FALSE);
15758 ok(old_focus == child, "expected old focus %p, got %p\n", child, old_focus);
15759 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
15760 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
15762 SetLastError(0xdeadbeef);
15763 old_focus = SetFocus((HWND)0xdeadbeef);
15764 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
15765 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
15766 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
15767 ok_sequence(WmEmptySeq, "SetFocus on an invalid window", FALSE);
15768 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
15769 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
15770 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
15772 SetLastError(0xdeadbeef);
15773 old_focus = SetFocus(GetDesktopWindow());
15774 ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
15775 broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
15776 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
15777 ok_sequence(WmEmptySeq, "SetFocus on a desktop window", TRUE);
15778 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
15779 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
15780 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
15782 SetLastError(0xdeadbeef);
15783 old_focus = SetFocus(wnd_event.hwnd);
15784 ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
15785 broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
15786 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
15787 ok_sequence(WmEmptySeq, "SetFocus on another thread window", TRUE);
15788 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
15789 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
15790 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
15792 SetLastError(0xdeadbeef);
15793 old_active = SetActiveWindow((HWND)0xdeadbeef);
15794 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
15795 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
15796 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
15797 ok_sequence(WmEmptySeq, "SetActiveWindow on an invalid window", FALSE);
15798 ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
15799 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
15800 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
15802 SetLastError(0xdeadbeef);
15803 old_active = SetActiveWindow(GetDesktopWindow());
15804 todo_wine
15805 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
15806 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
15807 ok_sequence(WmEmptySeq, "SetActiveWindow on a desktop window", TRUE);
15808 ok(old_active == 0, "expected old focus 0, got %p\n", old_focus);
15809 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
15810 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
15812 SetLastError(0xdeadbeef);
15813 old_active = SetActiveWindow(wnd_event.hwnd);
15814 todo_wine
15815 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
15816 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
15817 ok_sequence(WmEmptySeq, "SetActiveWindow on another thread window", TRUE);
15818 ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
15819 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
15820 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
15822 SetLastError(0xdeadbeef);
15823 ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE);
15824 ok(ret, "AttachThreadInput error %d\n", GetLastError());
15826 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
15827 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
15829 flush_events();
15830 flush_sequence();
15832 old_focus = SetFocus(wnd_event.hwnd);
15833 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
15834 ok(old_focus == wnd_event.hwnd, "expected old focus %p, got %p\n", wnd_event.hwnd, old_focus);
15835 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
15836 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
15838 old_focus = SetFocus(parent);
15839 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
15840 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
15841 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
15842 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
15844 flush_events();
15845 flush_sequence();
15847 old_active = SetActiveWindow(wnd_event.hwnd);
15848 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
15849 ok(old_active == parent, "expected old focus %p, got %p\n", parent, old_active);
15850 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
15851 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
15853 SetLastError(0xdeadbeef);
15854 ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE);
15855 ok(ret, "AttachThreadInput error %d\n", GetLastError());
15857 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
15858 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
15860 old_parent = SetParent(child, GetDesktopWindow());
15861 ok(old_parent == parent, "expected old parent %p, got %p\n", parent, old_parent);
15863 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
15864 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
15866 old_focus = SetFocus(parent);
15867 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
15868 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
15869 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
15870 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
15872 flush_events();
15873 flush_sequence();
15875 SetLastError(0xdeadbeef);
15876 old_focus = SetFocus(child);
15877 todo_wine
15878 ok(GetLastError() == ERROR_INVALID_PARAMETER /* Vista+ */ ||
15879 broken(GetLastError() == 0) /* XP */ ||
15880 broken(GetLastError() == 0xdeadbeef), "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
15881 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
15882 ok_sequence(WmSetFocus_3, "SetFocus on a child window", TRUE);
15883 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
15884 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
15885 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
15887 SetLastError(0xdeadbeef);
15888 old_active = SetActiveWindow(child);
15889 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
15890 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
15891 ok_sequence(WmEmptySeq, "SetActiveWindow on a child window", FALSE);
15892 ok(old_active == parent, "expected old active %p, got %p\n", parent, old_active);
15893 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
15894 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
15896 log_all_parent_messages--;
15898 DestroyWindow(child);
15899 DestroyWindow(parent);
15901 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
15902 ok(ret, "PostMessage(WM_QUIT) error %d\n", GetLastError());
15903 ret = WaitForSingleObject(hthread, INFINITE);
15904 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
15905 CloseHandle(hthread);
15908 static const struct message WmSetLayeredStyle[] = {
15909 { WM_STYLECHANGING, sent },
15910 { WM_STYLECHANGED, sent },
15911 { WM_GETTEXT, sent|defwinproc|optional },
15912 { 0 }
15915 static const struct message WmSetLayeredStyle2[] = {
15916 { WM_STYLECHANGING, sent },
15917 { WM_STYLECHANGED, sent },
15918 { WM_WINDOWPOSCHANGING, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15919 { WM_NCCALCSIZE, sent|optional|wparam|defwinproc, 1 },
15920 { WM_WINDOWPOSCHANGED, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
15921 { WM_MOVE, sent|optional|defwinproc|wparam, 0 },
15922 { WM_SIZE, sent|optional|defwinproc|wparam, SIZE_RESTORED },
15923 { 0 }
15926 struct layered_window_info
15928 HWND hwnd;
15929 HDC hdc;
15930 SIZE size;
15931 HANDLE event;
15932 BOOL ret;
15935 static DWORD CALLBACK update_layered_proc( void *param )
15937 struct layered_window_info *info = param;
15938 POINT src = { 0, 0 };
15940 info->ret = pUpdateLayeredWindow( info->hwnd, 0, NULL, &info->size,
15941 info->hdc, &src, 0, NULL, ULW_OPAQUE );
15942 ok( info->ret, "failed\n");
15943 SetEvent( info->event );
15944 return 0;
15947 static void test_layered_window(void)
15949 HWND hwnd;
15950 HDC hdc;
15951 HBITMAP bmp;
15952 BOOL ret;
15953 SIZE size;
15954 POINT pos, src;
15955 RECT rect, client;
15956 HANDLE thread;
15957 DWORD tid;
15958 struct layered_window_info info;
15960 if (!pUpdateLayeredWindow)
15962 win_skip( "UpdateLayeredWindow not supported\n" );
15963 return;
15966 hdc = CreateCompatibleDC( 0 );
15967 bmp = CreateCompatibleBitmap( hdc, 300, 300 );
15968 SelectObject( hdc, bmp );
15970 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_CAPTION | WS_THICKFRAME | WS_SYSMENU,
15971 100, 100, 300, 300, 0, 0, 0, NULL);
15972 ok( hwnd != 0, "failed to create window\n" );
15973 ShowWindow( hwnd, SW_SHOWNORMAL );
15974 UpdateWindow( hwnd );
15975 flush_events();
15976 flush_sequence();
15978 GetWindowRect( hwnd, &rect );
15979 GetClientRect( hwnd, &client );
15980 ok( client.right < rect.right - rect.left, "wrong client area\n" );
15981 ok( client.bottom < rect.bottom - rect.top, "wrong client area\n" );
15983 src.x = src.y = 0;
15984 pos.x = pos.y = 300;
15985 size.cx = size.cy = 250;
15986 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
15987 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
15988 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
15989 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
15990 ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
15992 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
15993 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
15994 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
15995 GetWindowRect( hwnd, &rect );
15996 ok( rect.left == 300 && rect.top == 300 && rect.right == 550 && rect.bottom == 550,
15997 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
15998 GetClientRect( hwnd, &rect );
15999 ok( rect.right == client.right - 50 && rect.bottom == client.bottom - 50,
16000 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16002 size.cx = 150;
16003 pos.y = 200;
16004 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16005 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
16006 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
16007 GetWindowRect( hwnd, &rect );
16008 ok( rect.left == 300 && rect.top == 200 && rect.right == 450 && rect.bottom == 450,
16009 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16010 GetClientRect( hwnd, &rect );
16011 ok( rect.right == client.right - 150 && rect.bottom == client.bottom - 50,
16012 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16014 SetWindowLongA( hwnd, GWL_STYLE,
16015 GetWindowLongA(hwnd, GWL_STYLE) & ~(WS_CAPTION | WS_THICKFRAME | WS_SYSMENU) );
16016 ok_sequence( WmSetLayeredStyle2, "WmSetLayeredStyle2", FALSE );
16018 size.cx = 200;
16019 pos.x = 200;
16020 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16021 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
16022 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
16023 GetWindowRect( hwnd, &rect );
16024 ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
16025 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16026 GetClientRect( hwnd, &rect );
16027 ok( (rect.right == 200 && rect.bottom == 250) ||
16028 broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
16029 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16031 size.cx = 0;
16032 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16033 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
16034 ok( GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == ERROR_MR_MID_NOT_FOUND) ||
16035 broken(GetLastError() == ERROR_GEN_FAILURE) /* win7 */, "wrong error %u\n", GetLastError() );
16036 size.cx = 1;
16037 size.cy = -1;
16038 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16039 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
16040 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
16042 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED );
16043 ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
16044 GetWindowRect( hwnd, &rect );
16045 ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
16046 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16047 GetClientRect( hwnd, &rect );
16048 ok( (rect.right == 200 && rect.bottom == 250) ||
16049 broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
16050 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16052 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
16053 info.hwnd = hwnd;
16054 info.hdc = hdc;
16055 info.size.cx = 250;
16056 info.size.cy = 300;
16057 info.event = CreateEventA( NULL, TRUE, FALSE, NULL );
16058 info.ret = FALSE;
16059 thread = CreateThread( NULL, 0, update_layered_proc, &info, 0, &tid );
16060 ok( WaitForSingleObject( info.event, 1000 ) == 0, "wait failed\n" );
16061 ok( info.ret, "UpdateLayeredWindow failed in other thread\n" );
16062 WaitForSingleObject( thread, 1000 );
16063 CloseHandle( thread );
16064 GetWindowRect( hwnd, &rect );
16065 ok( rect.left == 200 && rect.top == 200 && rect.right == 450 && rect.bottom == 500,
16066 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16067 GetClientRect( hwnd, &rect );
16068 ok( (rect.right == 250 && rect.bottom == 300) ||
16069 broken(rect.right == client.right - 50 && rect.bottom == client.bottom),
16070 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16072 DestroyWindow( hwnd );
16073 DeleteDC( hdc );
16074 DeleteObject( bmp );
16077 static HMENU hpopupmenu;
16079 static LRESULT WINAPI cancel_popup_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
16081 if (ignore_message( message )) return 0;
16083 switch (message) {
16084 case WM_ENTERIDLE:
16085 todo_wine ok(GetCapture() == hwnd, "expected %p, got %p\n", hwnd, GetCapture());
16086 EndMenu();
16087 break;
16088 case WM_INITMENU:
16089 case WM_INITMENUPOPUP:
16090 case WM_UNINITMENUPOPUP:
16091 ok((HMENU)wParam == hpopupmenu, "expected %p, got %lx\n", hpopupmenu, wParam);
16092 break;
16093 case WM_CAPTURECHANGED:
16094 todo_wine ok(!lParam || (HWND)lParam == hwnd, "lost capture to %lx\n", lParam);
16095 break;
16098 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
16101 static LRESULT WINAPI cancel_init_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
16103 if (ignore_message( message )) return 0;
16105 switch (message) {
16106 case WM_ENTERMENULOOP:
16107 ok(EndMenu() == TRUE, "EndMenu() failed\n");
16108 break;
16111 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
16114 static void test_TrackPopupMenu(void)
16116 MSG msg;
16117 HWND hwnd;
16118 BOOL ret;
16120 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
16121 0, 0, 1, 1, 0,
16122 NULL, NULL, 0);
16123 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
16125 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
16127 hpopupmenu = CreatePopupMenu();
16128 ok(hpopupmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
16130 AppendMenuA(hpopupmenu, MF_STRING, 100, "item 1");
16131 AppendMenuA(hpopupmenu, MF_STRING, 100, "item 2");
16133 flush_events();
16134 flush_sequence();
16135 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
16136 ok_sequence(WmTrackPopupMenu, "TrackPopupMenu", TRUE);
16137 ok(ret == 1, "TrackPopupMenu failed with error %i\n", GetLastError());
16139 /* Test popup closing with an ESC-press */
16140 flush_events();
16141 PostMessageW(hwnd, WM_KEYDOWN, VK_ESCAPE, 0);
16142 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
16143 ok(ret == 1, "TrackPopupMenu failed with error %i\n", GetLastError());
16144 PostQuitMessage(0);
16145 flush_sequence();
16146 while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
16148 TranslateMessage(&msg);
16149 DispatchMessageA(&msg);
16151 ok_sequence(WmTrackPopupMenuEsc, "TrackPopupMenuEsc", FALSE); /* Shouldn't get any message */
16153 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_init_proc);
16155 flush_events();
16156 flush_sequence();
16157 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
16158 ok_sequence(WmTrackPopupMenuAbort, "WmTrackPopupMenuAbort", TRUE);
16159 ok(ret == TRUE, "TrackPopupMenu failed\n");
16161 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
16163 SetCapture(hwnd);
16165 flush_events();
16166 flush_sequence();
16167 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
16168 ok_sequence(WmTrackPopupMenuCapture, "TrackPopupMenuCapture", TRUE);
16169 ok(ret == 1, "TrackPopupMenuCapture failed with error %i\n", GetLastError());
16171 DestroyMenu(hpopupmenu);
16172 DestroyWindow(hwnd);
16175 static void test_TrackPopupMenuEmpty(void)
16177 HWND hwnd;
16178 BOOL ret;
16180 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
16181 0, 0, 1, 1, 0,
16182 NULL, NULL, 0);
16183 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
16185 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
16187 hpopupmenu = CreatePopupMenu();
16188 ok(hpopupmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
16190 flush_events();
16191 flush_sequence();
16192 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
16193 ok_sequence(WmTrackPopupMenuEmpty, "TrackPopupMenuEmpty", TRUE);
16194 ok(ret == 0, "TrackPopupMenu succeeded\n");
16196 DestroyMenu(hpopupmenu);
16197 DestroyWindow(hwnd);
16200 static const struct message send_message_1[] = {
16201 { WM_USER+2, sent|wparam|lparam, 0, 0 },
16202 { WM_USER, sent|wparam|lparam, 0, 0 },
16203 { 0 }
16205 static const struct message send_message_2[] = {
16206 { WM_USER+4, sent|wparam|lparam, 0, 0 },
16207 { 0 }
16209 static const struct message send_message_3[] = {
16210 { WM_USER+3, sent|wparam|lparam, 0, 0 },
16211 { 0 }
16213 static const struct message send_message_4[] = {
16214 { WM_USER+1, sent|wparam|lparam, 0, 0 },
16215 { 0 }
16218 static DWORD WINAPI SendMessage_thread_1(void *param)
16220 struct wnd_event *wnd_event = param;
16222 trace("thread: starting\n");
16223 WaitForSingleObject(wnd_event->start_event, INFINITE);
16225 trace("thread: call PostMessage\n");
16226 PostMessageA(wnd_event->hwnd, WM_USER, 0, 0);
16228 trace("thread: call PostMessage\n");
16229 PostMessageA(wnd_event->hwnd, WM_USER+1, 0, 0);
16231 trace("thread: call SendMessage\n");
16232 SendMessageA(wnd_event->hwnd, WM_USER+2, 0, 0);
16234 trace("thread: call SendMessage\n");
16235 SendMessageA(wnd_event->hwnd, WM_USER+3, 0, 0);
16237 return 0;
16240 static DWORD WINAPI SendMessage_thread_2(void *param)
16242 struct wnd_event *wnd_event = param;
16244 trace("thread: starting\n");
16245 WaitForSingleObject(wnd_event->start_event, INFINITE);
16247 trace("thread: call PostMessage\n");
16248 PostMessageA(wnd_event->hwnd, WM_USER, 0, 0);
16250 trace("thread: call PostMessage\n");
16251 PostMessageA(wnd_event->hwnd, WM_USER+1, 0, 0);
16253 /* this leads to sending an internal message under Wine */
16254 trace("thread: call EnableWindow\n");
16255 EnableWindow(wnd_event->hwnd, TRUE);
16257 trace("thread: call SendMessage\n");
16258 SendMessageA(wnd_event->hwnd, WM_USER+2, 0, 0);
16260 trace("thread: call SendMessage\n");
16261 SendMessageA(wnd_event->hwnd, WM_USER+3, 0, 0);
16263 return 0;
16266 static void test_SendMessage_other_thread(int thread_n)
16268 DWORD qs_all_input = QS_ALLINPUT & ~QS_RAWINPUT;
16269 HANDLE hthread;
16270 struct wnd_event wnd_event;
16271 DWORD tid, ret;
16272 MSG msg;
16274 wnd_event.start_event = CreateEventA(NULL, 0, 0, NULL);
16276 wnd_event.hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
16277 100, 100, 200, 200, 0, 0, 0, NULL);
16278 ok(wnd_event.hwnd != 0, "CreateWindowEx failed\n");
16280 hthread = CreateThread(NULL, 0, thread_n == 1 ? SendMessage_thread_1 : SendMessage_thread_2, &wnd_event, 0, &tid);
16281 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
16282 CloseHandle(hthread);
16284 flush_events();
16285 flush_sequence();
16287 ret = GetQueueStatus(QS_SENDMESSAGE);
16288 ok(ret == 0, "wrong status %08x\n", ret);
16290 SetEvent(wnd_event.start_event);
16292 /* wait for other thread's SendMessage */
16293 for (;;)
16295 ret = GetQueueStatus(QS_SENDMESSAGE);
16296 if (ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE)) break;
16297 Sleep(50);
16300 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
16301 ok(ret == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08x\n", ret);
16303 trace("main: call GetMessage\n");
16304 GetMessageA(&msg, 0, 0, 0);
16305 ok(msg.message == WM_USER, "expected WM_USER, got %04x\n", msg.message);
16306 DispatchMessageA(&msg);
16307 ok_sequence(send_message_1, "SendMessage from other thread 1", thread_n == 2);
16309 /* intentionally yield */
16310 MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input);
16312 trace("main: call SendMessage\n");
16313 SendMessageA(wnd_event.hwnd, WM_USER+4, 0, 0);
16314 ok_sequence(send_message_2, "SendMessage from other thread 2", FALSE);
16316 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
16317 ok(ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08x\n", ret);
16319 trace("main: call PeekMessage\n");
16320 ok(PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "PeekMessage should not fail\n");
16321 ok(msg.message == WM_USER+1, "expected WM_USER+1, got %04x\n", msg.message);
16322 ok_sequence(send_message_3, "SendMessage from other thread 3", thread_n == 2);
16324 trace("main: call PeekMessage\n");
16325 ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should not fail\n");
16326 ok(msg.message == WM_USER+1, "expected WM_USER+1, got %04x\n", msg.message);
16327 DispatchMessageA(&msg);
16328 ok_sequence(send_message_4, "SendMessage from other thread 4", FALSE);
16330 /* intentionally yield */
16331 MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input);
16333 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
16334 /* FIXME: remove once Wine is fixed */
16335 todo_wine_if (thread_n == 2)
16336 ok(ret == 0, "wrong status %08x\n", ret);
16338 trace("main: call PeekMessage\n");
16339 ok(!PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should fail\n");
16340 ok_sequence(WmEmptySeq, "SendMessage from other thread 5", thread_n == 2);
16342 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
16343 ok(ret == 0, "wrong status %08x\n", ret);
16345 trace("main: call DestroyWindow\n");
16346 DestroyWindow(msg.hwnd);
16348 flush_events();
16349 flush_sequence();
16352 static LRESULT CALLBACK insendmessage_wnd_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
16354 DWORD flags = InSendMessageEx( NULL );
16355 BOOL ret;
16357 switch (msg)
16359 case WM_USER:
16360 ok( flags == ISMEX_SEND, "wrong flags %x\n", flags );
16361 ok( InSendMessage(), "InSendMessage returned false\n" );
16362 ret = ReplyMessage( msg );
16363 ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
16364 flags = InSendMessageEx( NULL );
16365 ok( flags == (ISMEX_SEND | ISMEX_REPLIED), "wrong flags %x\n", flags );
16366 ok( InSendMessage(), "InSendMessage returned false\n" );
16367 break;
16368 case WM_USER + 1:
16369 ok( flags == ISMEX_NOTIFY, "wrong flags %x\n", flags );
16370 ok( InSendMessage(), "InSendMessage returned false\n" );
16371 ret = ReplyMessage( msg );
16372 ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
16373 flags = InSendMessageEx( NULL );
16374 ok( flags == ISMEX_NOTIFY, "wrong flags %x\n", flags );
16375 ok( InSendMessage(), "InSendMessage returned false\n" );
16376 break;
16377 case WM_USER + 2:
16378 ok( flags == ISMEX_CALLBACK, "wrong flags %x\n", flags );
16379 ok( InSendMessage(), "InSendMessage returned false\n" );
16380 ret = ReplyMessage( msg );
16381 ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
16382 flags = InSendMessageEx( NULL );
16383 ok( flags == (ISMEX_CALLBACK | ISMEX_REPLIED) || flags == ISMEX_SEND, "wrong flags %x\n", flags );
16384 ok( InSendMessage(), "InSendMessage returned false\n" );
16385 break;
16386 case WM_USER + 3:
16387 ok( flags == ISMEX_NOSEND, "wrong flags %x\n", flags );
16388 ok( !InSendMessage(), "InSendMessage returned true\n" );
16389 ret = ReplyMessage( msg );
16390 ok( !ret, "ReplyMessage succeeded\n" );
16391 break;
16394 return DefWindowProcA( hwnd, msg, wp, lp );
16397 static void CALLBACK msg_callback( HWND hwnd, UINT msg, ULONG_PTR arg, LRESULT result )
16399 ok( msg == WM_USER + 2, "wrong msg %x\n", msg );
16400 ok( result == WM_USER + 2, "wrong result %lx\n", result );
16403 static DWORD WINAPI send_message_thread( void *arg )
16405 HWND win = arg;
16407 SendMessageA( win, WM_USER, 0, 0 );
16408 SendNotifyMessageA( win, WM_USER + 1, 0, 0 );
16409 SendMessageCallbackA( win, WM_USER + 2, 0, 0, msg_callback, 0 );
16410 PostMessageA( win, WM_USER + 3, 0, 0 );
16411 PostMessageA( win, WM_QUIT, 0, 0 );
16412 return 0;
16415 static void test_InSendMessage(void)
16417 WNDCLASSA cls;
16418 HWND win;
16419 MSG msg;
16420 HANDLE thread;
16421 DWORD tid;
16423 memset(&cls, 0, sizeof(cls));
16424 cls.lpfnWndProc = insendmessage_wnd_proc;
16425 cls.hInstance = GetModuleHandleA(NULL);
16426 cls.lpszClassName = "InSendMessage_test";
16427 RegisterClassA(&cls);
16429 win = CreateWindowA( "InSendMessage_test", NULL, 0, 0, 0, 0, 0, NULL, 0, NULL, 0 );
16430 ok( win != NULL, "CreateWindow failed: %d\n", GetLastError() );
16432 thread = CreateThread( NULL, 0, send_message_thread, win, 0, &tid );
16433 ok( thread != NULL, "CreateThread failed: %d\n", GetLastError() );
16435 while (GetMessageA(&msg, NULL, 0, 0)) DispatchMessageA( &msg );
16437 ok( WaitForSingleObject( thread, 30000 ) == WAIT_OBJECT_0, "WaitForSingleObject failed\n" );
16438 CloseHandle( thread );
16440 DestroyWindow( win );
16441 UnregisterClassA( "InSendMessage_test", GetModuleHandleA(NULL) );
16444 static const struct message DoubleSetCaptureSeq[] =
16446 { WM_CAPTURECHANGED, sent },
16447 { 0 }
16450 static void test_DoubleSetCapture(void)
16452 HWND hwnd;
16454 hwnd = CreateWindowExA(0, "TestWindowClass", "Test DoubleSetCapture",
16455 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
16456 100, 100, 200, 200, 0, 0, 0, NULL);
16457 ok (hwnd != 0, "Failed to create overlapped window\n");
16459 ShowWindow( hwnd, SW_SHOW );
16460 UpdateWindow( hwnd );
16461 flush_events();
16462 flush_sequence();
16464 SetCapture( hwnd );
16465 SetCapture( hwnd );
16466 ok_sequence(DoubleSetCaptureSeq, "SetCapture( hwnd ) twice", FALSE);
16468 DestroyWindow(hwnd);
16471 static void init_funcs(void)
16473 HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
16475 #define X(f) p##f = (void*)GetProcAddress(hKernel32, #f)
16476 X(ActivateActCtx);
16477 X(CreateActCtxW);
16478 X(DeactivateActCtx);
16479 X(GetCurrentActCtx);
16480 X(QueryActCtxW);
16481 X(ReleaseActCtx);
16482 #undef X
16485 START_TEST(msg)
16487 char **test_argv;
16488 BOOL ret;
16489 BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
16490 HMODULE hModuleImm32;
16491 BOOL (WINAPI *pImmDisableIME)(DWORD);
16492 int argc;
16494 init_funcs();
16496 argc = winetest_get_mainargs( &test_argv );
16497 if (argc >= 3)
16499 unsigned int arg;
16500 /* Child process. */
16501 sscanf (test_argv[2], "%d", (unsigned int *) &arg);
16502 do_wait_idle_child( arg );
16503 return;
16506 InitializeCriticalSection( &sequence_cs );
16507 init_procs();
16509 hModuleImm32 = LoadLibraryA("imm32.dll");
16510 if (hModuleImm32) {
16511 pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME");
16512 if (pImmDisableIME)
16513 pImmDisableIME(0);
16515 pImmDisableIME = NULL;
16516 FreeLibrary(hModuleImm32);
16518 if (!RegisterWindowClasses()) assert(0);
16520 if (pSetWinEventHook)
16522 hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
16523 GetModuleHandleA(0), win_event_proc,
16524 0, GetCurrentThreadId(),
16525 WINEVENT_INCONTEXT);
16526 if (pIsWinEventHookInstalled && hEvent_hook)
16528 UINT event;
16529 for (event = EVENT_MIN; event <= EVENT_MAX; event++)
16530 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
16533 if (!hEvent_hook) win_skip( "no win event hook support\n" );
16535 cbt_hook_thread_id = GetCurrentThreadId();
16536 hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
16537 if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
16539 test_winevents();
16541 /* Fix message sequences before removing 4 lines below */
16542 if (pUnhookWinEvent && hEvent_hook)
16544 ret = pUnhookWinEvent(hEvent_hook);
16545 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
16546 pUnhookWinEvent = 0;
16548 hEvent_hook = 0;
16550 test_SendMessage_other_thread(1);
16551 test_SendMessage_other_thread(2);
16552 test_InSendMessage();
16553 test_SetFocus();
16554 test_SetParent();
16555 test_PostMessage();
16556 test_broadcast();
16557 test_ShowWindow();
16558 test_PeekMessage();
16559 test_PeekMessage2();
16560 test_PeekMessage3();
16561 test_WaitForInputIdle( test_argv[0] );
16562 test_scrollwindowex();
16563 test_messages();
16564 test_setwindowpos();
16565 test_showwindow();
16566 invisible_parent_tests();
16567 test_mdi_messages();
16568 test_button_messages();
16569 test_static_messages();
16570 test_listbox_messages();
16571 test_combobox_messages();
16572 test_wmime_keydown_message();
16573 test_paint_messages();
16574 test_interthread_messages();
16575 test_message_conversion();
16576 test_accelerators();
16577 test_timers();
16578 test_timers_no_wnd();
16579 test_timers_exceptions();
16580 if (hCBT_hook)
16582 test_set_hook();
16583 test_recursive_hook();
16585 test_DestroyWindow();
16586 test_DispatchMessage();
16587 test_SendMessageTimeout();
16588 test_edit_messages();
16589 test_quit_message();
16590 test_notify_message();
16591 test_SetActiveWindow();
16593 if (!pTrackMouseEvent)
16594 win_skip("TrackMouseEvent is not available\n");
16595 else
16596 test_TrackMouseEvent();
16598 test_SetWindowRgn();
16599 test_sys_menu();
16600 test_dialog_messages();
16601 test_EndDialog();
16602 test_nullCallback();
16603 test_dbcs_wm_char();
16604 test_unicode_wm_char();
16605 test_menu_messages();
16606 test_paintingloop();
16607 test_defwinproc();
16608 test_clipboard_viewers();
16609 test_keyflags();
16610 test_hotkey();
16611 test_layered_window();
16612 test_TrackPopupMenu();
16613 test_TrackPopupMenuEmpty();
16614 test_DoubleSetCapture();
16615 /* keep it the last test, under Windows it tends to break the tests
16616 * which rely on active/foreground windows being correct.
16618 test_SetForegroundWindow();
16620 UnhookWindowsHookEx(hCBT_hook);
16621 if (pUnhookWinEvent && hEvent_hook)
16623 ret = pUnhookWinEvent(hEvent_hook);
16624 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
16625 SetLastError(0xdeadbeef);
16626 ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
16627 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
16628 GetLastError() == 0xdeadbeef, /* Win9x */
16629 "unexpected error %d\n", GetLastError());
16631 DeleteCriticalSection( &sequence_cs );